8 remove all unwrap (#9)

* Remove all unwraps from sending

* Remove unwraps from receiving

* Move Result type to utils
This commit is contained in:
cygnet 2023-07-24 23:15:04 +02:00 committed by GitHub
parent a7001e4a3d
commit ad2c5b0e72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 116 additions and 114 deletions

View File

@ -1,4 +1,4 @@
#![allow(non_snake_case, dead_code)]
#![allow(non_snake_case)]
pub mod receiving;
pub mod sending;
pub mod structs;

View File

@ -5,40 +5,31 @@ use std::{collections::HashMap, str::FromStr};
use crate::{
structs::{OutputWithSignature, ScannedOutput},
utils::ser_uint32,
utils::{ser_uint32, Result},
};
pub fn get_receiving_addresses(
B_scan: PublicKey,
B_spend: PublicKey,
labels: &HashMap<String, String>,
) -> Vec<String> {
) -> Result<Vec<String>> {
let mut receiving_addresses: Vec<String> = vec![];
receiving_addresses.push(encode_silent_payment_address(B_scan, B_spend, None, None));
receiving_addresses.push(encode_silent_payment_address(B_scan, B_spend, None, None)?);
for (_, label) in labels {
receiving_addresses.push(create_labeled_silent_payment_address(
B_scan, B_spend, label, None, None,
));
)?);
}
receiving_addresses
Ok(receiving_addresses)
}
pub fn get_A_sum_public_keys(input: &Vec<String>) -> PublicKey {
let keys: Vec<PublicKey> = input
.iter()
.map(|x| match PublicKey::from_str(&x) {
Ok(key) => key,
Err(_) => {
// we always assume even pairing for input public keys if they are omitted
let x_only_public_key = XOnlyPublicKey::from_str(&x).unwrap();
PublicKey::from_x_only_public_key(x_only_public_key, secp256k1::Parity::Even)
}
})
.collect();
let keys_refs: Vec<&PublicKey> = keys.iter().collect();
pub fn get_A_sum_public_keys(
input: &Vec<PublicKey>,
) -> std::result::Result<PublicKey, secp256k1::Error> {
let keys_refs: &Vec<&PublicKey> = &input.iter().collect();
PublicKey::combine_keys(&keys_refs).unwrap()
PublicKey::combine_keys(keys_refs)
}
fn encode_silent_payment_address(
@ -46,9 +37,9 @@ fn encode_silent_payment_address(
B_m: PublicKey,
hrp: Option<&str>,
version: Option<u8>,
) -> String {
) -> Result<String> {
let hrp = hrp.unwrap_or("sp");
let version = bech32::u5::try_from_u8(version.unwrap_or(0)).unwrap();
let version = bech32::u5::try_from_u8(version.unwrap_or(0))?;
let B_scan_bytes = B_scan.serialize();
let B_m_bytes = B_m.serialize();
@ -57,7 +48,7 @@ fn encode_silent_payment_address(
data.insert(0, version);
bech32::encode(hrp, data, bech32::Variant::Bech32m).unwrap()
Ok(bech32::encode(hrp, data, bech32::Variant::Bech32m)?)
}
fn create_labeled_silent_payment_address(
@ -66,32 +57,26 @@ fn create_labeled_silent_payment_address(
m: &String,
hrp: Option<&str>,
version: Option<u8>,
) -> String {
let bytes = hex::decode(m).unwrap().try_into().unwrap();
) -> Result<String> {
let bytes: [u8; 32] = hex::decode(m)?.as_slice().try_into()?;
let scalar = Scalar::from_be_bytes(bytes).unwrap();
let scalar = Scalar::from_be_bytes(bytes)?;
let secp = Secp256k1::new();
let G: PublicKey = SecretKey::from_slice(&Scalar::ONE.to_be_bytes())
.unwrap()
.public_key(&secp);
let intermediate = G.mul_tweak(&secp, &scalar).unwrap();
let B_m = intermediate.combine(&B_spend).unwrap();
let G: PublicKey = SecretKey::from_slice(&Scalar::ONE.to_be_bytes())?.public_key(&secp);
let intermediate = G.mul_tweak(&secp, &scalar)?;
let B_m = intermediate.combine(&B_spend)?;
encode_silent_payment_address(B_scan, B_m, hrp, version)
}
fn calculate_P_n(B_spend: &PublicKey, t_n: [u8; 32]) -> PublicKey {
fn calculate_P_n(B_spend: &PublicKey, t_n: [u8; 32]) -> Result<PublicKey> {
let secp = Secp256k1::new();
let G: PublicKey = SecretKey::from_slice(&Scalar::ONE.to_be_bytes())
.unwrap()
.public_key(&secp);
let intermediate = G
.mul_tweak(&secp, &Scalar::from_be_bytes(t_n).unwrap())
.unwrap();
let P_n = intermediate.combine(&B_spend).unwrap();
let G: PublicKey = SecretKey::from_slice(&Scalar::ONE.to_be_bytes())?.public_key(&secp);
let intermediate = G.mul_tweak(&secp, &Scalar::from_be_bytes(t_n)?)?;
let P_n = intermediate.combine(&B_spend)?;
P_n
Ok(P_n)
}
fn calculate_t_n(ecdh_shared_secret: &[u8; 33], n: u32) -> [u8; 32] {
@ -105,14 +90,14 @@ fn calculate_ecdh_secret(
A_sum: &PublicKey,
b_scan: SecretKey,
outpoints_hash: [u8; 32],
) -> [u8; 33] {
) -> Result<[u8; 33]> {
let secp = Secp256k1::new();
let intermediate = A_sum.mul_tweak(&secp, &b_scan.into()).unwrap();
let scalar = Scalar::from_be_bytes(outpoints_hash).unwrap();
let ecdh_shared_secret = intermediate.mul_tweak(&secp, &scalar).unwrap().serialize();
let intermediate = A_sum.mul_tweak(&secp, &b_scan.into())?;
let scalar = Scalar::from_be_bytes(outpoints_hash)?;
let ecdh_shared_secret = intermediate.mul_tweak(&secp, &scalar)?.serialize();
ecdh_shared_secret
Ok(ecdh_shared_secret)
}
pub fn scanning(
@ -122,9 +107,9 @@ pub fn scanning(
outpoints_hash: [u8; 32],
outputs_to_check: Vec<XOnlyPublicKey>,
labels: Option<&HashMap<String, String>>,
) -> Vec<ScannedOutput> {
) -> Result<Vec<ScannedOutput>> {
let secp = secp256k1::Secp256k1::new();
let ecdh_shared_secret = calculate_ecdh_secret(&A_sum, b_scan, outpoints_hash);
let ecdh_shared_secret = calculate_ecdh_secret(&A_sum, b_scan, outpoints_hash)?;
let mut n = 0;
let mut wallet: Vec<ScannedOutput> = vec![];
@ -132,7 +117,7 @@ pub fn scanning(
while found {
found = false;
let t_n = calculate_t_n(&ecdh_shared_secret, n);
let P_n = calculate_P_n(&B_spend, t_n);
let P_n = calculate_P_n(&B_spend, t_n)?;
let (P_n_xonly, _) = P_n.x_only_public_key();
if outputs_to_check.iter().any(|&output| output.eq(&P_n_xonly)) {
let pub_key = hex::encode(P_n_xonly.serialize());
@ -149,23 +134,19 @@ pub fn scanning(
let output_even = output.public_key(secp256k1::Parity::Even);
let output_odd = output.public_key(secp256k1::Parity::Odd);
let m_G_sub_even = output_even.combine(&P_n_negated).unwrap();
let m_G_sub_odd = output_odd.combine(&P_n_negated).unwrap();
let m_G_sub_even = output_even.combine(&P_n_negated)?;
let m_G_sub_odd = output_odd.combine(&P_n_negated)?;
let keys: Vec<PublicKey> = vec![m_G_sub_even, m_G_sub_odd];
for labelkeystr in labels.keys() {
let labelkey = PublicKey::from_str(labelkeystr).unwrap();
let labelkey = PublicKey::from_str(labelkeystr)?;
if keys.iter().any(|x| x.eq(&labelkey)) {
let P_nm = hex::encode(output.serialize());
let label = labels.get(labelkeystr).unwrap();
let label_bytes = hex::decode(label).unwrap().try_into().unwrap();
let label_scalar = Scalar::from_be_bytes(label_bytes).unwrap();
let t_n_as_secret_key = SecretKey::from_slice(&t_n).unwrap();
let priv_key_tweak = hex::encode(
t_n_as_secret_key
.add_tweak(&label_scalar)
.unwrap()
.secret_bytes(),
);
let label_bytes = hex::decode(label)?.as_slice().try_into()?;
let label_scalar = Scalar::from_be_bytes(label_bytes)?;
let t_n_as_secret_key = SecretKey::from_slice(&t_n)?;
let priv_key_tweak =
hex::encode(t_n_as_secret_key.add_tweak(&label_scalar)?.secret_bytes());
wallet.push(ScannedOutput {
pub_key: P_nm,
priv_key_tweak,
@ -177,23 +158,23 @@ pub fn scanning(
}
}
}
wallet
Ok(wallet)
}
pub fn verify_and_calculate_signatures(
add_to_wallet: &mut Vec<ScannedOutput>,
b_spend: SecretKey,
) -> Result<Vec<OutputWithSignature>, secp256k1::Error> {
) -> Result<Vec<OutputWithSignature>> {
let secp = secp256k1::Secp256k1::new();
let msg = Message::from_hashed_data::<secp256k1::hashes::sha256::Hash>(b"message");
let aux = secp256k1::hashes::sha256::Hash::hash(b"random auxiliary data").to_byte_array();
let mut res: Vec<OutputWithSignature> = vec![];
for output in add_to_wallet {
let pubkey = XOnlyPublicKey::from_str(&output.pub_key).unwrap();
let tweak = hex::decode(&output.priv_key_tweak).unwrap();
let scalar = Scalar::from_be_bytes(tweak.try_into().unwrap()).unwrap();
let mut full_priv_key = b_spend.add_tweak(&scalar).unwrap();
let pubkey = XOnlyPublicKey::from_str(&output.pub_key)?;
let tweak: [u8; 32] = hex::decode(&output.priv_key_tweak)?.as_slice().try_into()?;
let scalar = Scalar::from_be_bytes(tweak)?;
let mut full_priv_key = b_spend.add_tweak(&scalar)?;
let (_, parity) = full_priv_key.x_only_public_key(&secp);

View File

@ -1,66 +1,64 @@
use bech32::FromBase32;
use secp256k1::{Parity, PublicKey, Scalar, Secp256k1, SecretKey};
use std::{collections::HashMap, str::FromStr};
use std::collections::HashMap;
use crate::utils::{hash_outpoints, ser_uint32, sha256};
use crate::utils::{hash_outpoints, ser_uint32, sha256, Result};
fn get_a_sum_secret_keys(input: &Vec<(String, bool)>) -> SecretKey {
fn get_a_sum_secret_keys(input: &Vec<(SecretKey, bool)>) -> Result<SecretKey> {
let secp = Secp256k1::new();
let mut negated_keys: Vec<SecretKey> = vec![];
for (keystr, is_xonly) in input {
let key = SecretKey::from_str(&keystr).unwrap();
for (key, x_only) in input {
let (_, parity) = key.x_only_public_key(&secp);
if *is_xonly && parity == Parity::Odd {
if *x_only && parity == Parity::Odd {
negated_keys.push(key.negate());
} else {
negated_keys.push(key);
negated_keys.push(*key);
}
}
let (head, tail) = negated_keys.split_first().unwrap();
let (head, tail) = negated_keys.split_first().ok_or("Empty input list")?;
let result: SecretKey = tail
let result: Result<SecretKey> = tail
.iter()
.fold(*head, |acc, &item| acc.add_tweak(&item.into()).unwrap());
.fold(Ok(*head), |acc: Result<SecretKey>, &item| {
Ok(acc?.add_tweak(&item.into())?)
});
result
}
fn decode_silent_payment_address(addr: &str) -> (PublicKey, PublicKey) {
let (_hrp, data, _variant) = bech32::decode(&addr).unwrap();
fn decode_silent_payment_address(addr: &str) -> Result<(PublicKey, PublicKey)> {
let (_hrp, data, _variant) = bech32::decode(&addr)?;
let data = Vec::<u8>::from_base32(&data[1..]).unwrap();
let data = Vec::<u8>::from_base32(&data[1..])?;
let B_scan = PublicKey::from_slice(&data[..33]).unwrap();
let B_spend = PublicKey::from_slice(&data[33..]).unwrap();
let B_scan = PublicKey::from_slice(&data[..33])?;
let B_spend = PublicKey::from_slice(&data[33..])?;
(B_scan, B_spend)
Ok((B_scan, B_spend))
}
pub fn create_outputs(
outpoints: &Vec<(String, u32)>,
input_priv_keys: &Vec<(String, bool)>,
input_priv_keys: &Vec<(SecretKey, bool)>,
recipients: &Vec<(String, f32)>,
) -> Vec<HashMap<String, f32>> {
) -> Result<Vec<HashMap<String, f32>>> {
let secp = Secp256k1::new();
let outpoints_hash = hash_outpoints(outpoints);
let outpoints_hash = hash_outpoints(outpoints)?;
let a_sum = get_a_sum_secret_keys(input_priv_keys);
let a_sum = get_a_sum_secret_keys(input_priv_keys)?;
let mut silent_payment_groups: HashMap<PublicKey, Vec<(PublicKey, f32)>> = HashMap::new();
for (payment_address, amount) in recipients {
let (B_scan, B_m) = decode_silent_payment_address(&payment_address);
let (B_scan, B_m) = decode_silent_payment_address(&payment_address)?;
if silent_payment_groups.contains_key(&B_scan) {
silent_payment_groups
.get_mut(&B_scan)
.unwrap()
.push((B_m, *amount));
if let Some(payments) = silent_payment_groups.get_mut(&B_scan) {
payments.push((B_m, *amount));
} else {
silent_payment_groups.insert(B_scan, vec![(B_m, *amount)]);
}
@ -71,9 +69,9 @@ pub fn create_outputs(
let mut n = 0;
//calculate shared secret
let intermediate = B_scan.mul_tweak(&secp, &a_sum.into()).unwrap();
let scalar = Scalar::from_be_bytes(outpoints_hash).unwrap();
let ecdh_shared_secret = intermediate.mul_tweak(&secp, &scalar).unwrap().serialize();
let intermediate = B_scan.mul_tweak(&secp, &a_sum.into())?;
let scalar = Scalar::from_be_bytes(outpoints_hash)?;
let ecdh_shared_secret = intermediate.mul_tweak(&secp, &scalar)?.serialize();
for (B_m, amount) in B_m_values {
let mut bytes: Vec<u8> = Vec::new();
@ -81,15 +79,10 @@ pub fn create_outputs(
bytes.extend_from_slice(&ser_uint32(n));
let t_n = sha256(&bytes);
// eprintln!("t_n = {:?}", hex::encode(t_n));
let G: PublicKey = SecretKey::from_slice(&Scalar::ONE.to_be_bytes())
.unwrap()
.public_key(&secp);
let res = G
.mul_tweak(&secp, &Scalar::from_be_bytes(t_n).unwrap())
.unwrap();
let reskey = res.combine(&B_m).unwrap();
let G: PublicKey = SecretKey::from_slice(&Scalar::ONE.to_be_bytes())?.public_key(&secp);
let res = G.mul_tweak(&secp, &Scalar::from_be_bytes(t_n)?)?;
let reskey = res.combine(&B_m)?;
let (reskey_xonly, _) = reskey.x_only_public_key();
let mut toAdd: HashMap<String, f32> = HashMap::new();
@ -100,5 +93,5 @@ pub fn create_outputs(
n += 1;
}
}
result
Ok(result)
}

View File

@ -3,6 +3,8 @@ use std::io::Write;
use hex::FromHex;
use secp256k1::hashes::{sha256, Hash};
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
pub fn sha256(message: &[u8]) -> [u8; 32] {
sha256::Hash::hash(message).to_byte_array()
}
@ -11,11 +13,11 @@ pub fn ser_uint32(u: u32) -> Vec<u8> {
u.to_be_bytes().into()
}
pub fn hash_outpoints(sending_data: &Vec<(String, u32)>) -> [u8; 32] {
pub fn hash_outpoints(sending_data: &Vec<(String, u32)>) -> Result<[u8; 32]> {
let mut outpoints: Vec<Vec<u8>> = vec![];
for (txid_str, vout) in sending_data {
let mut txid = Vec::from_hex(txid_str).unwrap();
let mut txid = Vec::from_hex(txid_str)?;
txid.reverse();
let mut vout_bytes = vout.to_le_bytes().to_vec();
txid.append(&mut vout_bytes);
@ -26,8 +28,8 @@ pub fn hash_outpoints(sending_data: &Vec<(String, u32)>) -> [u8; 32] {
let mut engine = sha256::HashEngine::default();
for v in outpoints {
engine.write_all(&v).unwrap();
engine.write_all(&v)?;
}
sha256::Hash::from_engine(engine).to_byte_array()
Ok(sha256::Hash::from_engine(engine).to_byte_array())
}

View File

@ -9,7 +9,7 @@ use silentpayments::utils;
mod tests {
use std::{collections::HashSet, str::FromStr};
use secp256k1::XOnlyPublicKey;
use secp256k1::{PublicKey, SecretKey, XOnlyPublicKey};
use crate::{
common::input::{self, get_testing_silent_payment_key_pair, ComparableHashMap, TestData},
@ -40,8 +40,14 @@ mod tests {
let expected_comparable: HashSet<ComparableHashMap> =
expected.outputs.into_iter().map(|x| x.into()).collect();
let input_priv_keys: Vec<(SecretKey, bool)> = given
.input_priv_keys
.iter()
.map(|(keystr, x_only)| (SecretKey::from_str(&keystr).unwrap(), *x_only))
.collect();
let outputs =
create_outputs(&given.outpoints, &given.input_priv_keys, &given.recipients);
create_outputs(&given.outpoints, &input_priv_keys, &given.recipients).unwrap();
for map in &outputs {
for key in map.keys() {
@ -68,7 +74,8 @@ mod tests {
let (b_scan, b_spend, B_scan, B_spend) =
get_testing_silent_payment_key_pair(&given.bip32_seed);
let receiving_addresses = get_receiving_addresses(B_scan, B_spend, &given.labels);
let receiving_addresses =
get_receiving_addresses(B_scan, B_spend, &given.labels).unwrap();
let set1: HashSet<_> = receiving_addresses.iter().collect();
let set2: HashSet<_> = expected.addresses.iter().collect();
@ -82,8 +89,26 @@ mod tests {
.map(|x| XOnlyPublicKey::from_str(x).unwrap())
.collect();
let outpoints_hash = hash_outpoints(&given.outpoints);
let A_sum = get_A_sum_public_keys(&given.input_pub_keys);
let outpoints_hash = hash_outpoints(&given.outpoints).unwrap();
let input_pub_keys: Vec<PublicKey> = given
.input_pub_keys
.iter()
.map(|x| match PublicKey::from_str(&x) {
Ok(key) => key,
Err(_) => {
// we always assume even pairing for input public keys if they are omitted
let x_only_public_key = XOnlyPublicKey::from_str(&x).unwrap();
PublicKey::from_x_only_public_key(
x_only_public_key,
secp256k1::Parity::Even,
)
}
})
.collect();
let A_sum = get_A_sum_public_keys(&input_pub_keys).unwrap();
let labels = match &given.labels.len() {
0 => None,
_ => Some(&given.labels),
@ -96,7 +121,8 @@ mod tests {
outpoints_hash,
outputs_to_check,
labels,
);
)
.unwrap();
let res = verify_and_calculate_signatures(&mut add_to_wallet, b_spend).unwrap();
assert_eq!(res, expected.outputs);