From 2d55f9fa497e4ad12fbff76361d1d480188941c8 Mon Sep 17 00:00:00 2001 From: cygnet Date: Sun, 23 Jul 2023 14:15:45 +0200 Subject: [PATCH] Add create_labeled_silent_payment_address function --- Cargo.lock | 37 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/input.rs | 22 +++++++++++++--------- src/main.rs | 18 +++++++++++++----- src/receiving.rs | 30 ++++++++++++++++++++++++++++-- 5 files changed, 92 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e6987d6..6444720 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "bech32" version = "0.9.1" @@ -41,6 +47,36 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + [[package]] name = "proc-macro2" version = "1.0.63" @@ -121,6 +157,7 @@ version = "0.1.0" dependencies = [ "bech32", "hex", + "num-bigint", "secp256k1", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 523c5a7..7fde291 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ serde_json = "1.0" hex = "0.4" bech32 = "0.9" # bip32 = { version = "0.5", features = ["alloc"] } +num-bigint = "0.4.0" diff --git a/src/input.rs b/src/input.rs index c1a1459..5090f4c 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,3 +1,4 @@ +use num_bigint::BigUint; use serde::Deserialize; use serde_json::{from_str, Value}; use std::hash::{Hash, Hasher}; @@ -22,11 +23,11 @@ pub struct ReceivingDataGiven { pub input_pub_keys: Vec, pub bip32_seed: String, #[serde(deserialize_with = "empty_array_as_map")] - pub labels: HashMap, + pub labels: HashMap, pub outputs: Vec, } -fn empty_array_as_map<'de, D>(deserializer: D) -> Result, D::Error> +fn empty_array_as_map<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, { @@ -41,22 +42,25 @@ where } } Value::Object(map) => { - let result: HashMap = map + // let len = map.len(); + let result: HashMap = map .into_iter() - .map(|(k, v)| { + .filter_map(|(k, v)| { if let Value::Number(num) = v { num.as_i64() - .and_then(|n| u32::from_str(&n.to_string()).ok()) + .and_then(|n| BigUint::from_str(&n.to_string()).ok()) .map(|n| (k, n)) } else { None } }) - .collect::>() - .ok_or(serde::de::Error::custom( - "Failed to parse map values as u32", - ))?; + .collect(); + // if result.len() != len { + // return Err(serde::de::Error::custom( + // "Failed to parse map values as BigUint", + // )); + // } Ok(result) } _ => Err(serde::de::Error::custom("Expected map or empty array")), diff --git a/src/main.rs b/src/main.rs index 19fef23..a7acc1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,8 +14,9 @@ use std::{collections::HashSet, io::Write}; use crate::{ input::ComparableHashMap, receiving::{ - derive_silent_payment_key_pair, encode_silent_payment_address, get_A_sum_public_keys, - scanning, verify_and_calculate_signatures, + create_labeled_silent_payment_address, derive_silent_payment_key_pair, + encode_silent_payment_address, get_A_sum_public_keys, scanning, + verify_and_calculate_signatures, }, sending::create_outputs, }; @@ -70,6 +71,7 @@ fn main() { } else { eprintln!("sending expected = {:#?}", expected_comparable); eprintln!("sending outputs = {:#?}", outputs_comparable); + std::process::exit(0); } } @@ -88,8 +90,15 @@ fn main() { let mut receiving_addresses: Vec = vec![]; receiving_addresses.push(encode_silent_payment_address(B_scan, B_spend, None, None)); - // todo label support - if !receiving_addresses.eq(&expected.addresses) { + for (_, label) in &given.labels { + receiving_addresses.push(create_labeled_silent_payment_address( + B_scan, B_spend, label, None, None, + )); + } + + let set1: HashSet<_> = receiving_addresses.iter().collect(); + let set2: HashSet<_> = expected.addresses.iter().collect(); + if !set1.eq(&set2) { println!("receiving addressess failed"); eprintln!("receiving_addresses = {:#?}", receiving_addresses); eprintln!("expected.addresses = {:#?}", expected.addresses); @@ -105,7 +114,6 @@ fn main() { let outpoints_hash = hash_outpoints(&given.outpoints); let A_sum = get_A_sum_public_keys(&given.input_pub_keys); let labels = &given.labels; - let mut add_to_wallet = scanning( b_scan, B_spend, diff --git a/src/receiving.rs b/src/receiving.rs index 9f70833..65bfdf3 100644 --- a/src/receiving.rs +++ b/src/receiving.rs @@ -1,5 +1,6 @@ use bech32::ToBase32; +use num_bigint::BigUint; use secp256k1::{hashes::Hash, Message, PublicKey, Scalar, Secp256k1, SecretKey, XOnlyPublicKey}; use std::{collections::HashMap, str::FromStr}; @@ -50,7 +51,7 @@ pub fn get_A_sum_public_keys(input: &Vec) -> PublicKey { .map(|x| match PublicKey::from_str(&x) { Ok(key) => key, Err(_) => { - println!("using x only public key with even pairing"); + // println!("using x only public key with even pairing"); let x_only_public_key = XOnlyPublicKey::from_str(&x).unwrap(); PublicKey::from_x_only_public_key(x_only_public_key, secp256k1::Parity::Even) } @@ -80,6 +81,31 @@ pub fn encode_silent_payment_address( bech32::encode(hrp, data, bech32::Variant::Bech32m).unwrap() } +pub fn create_labeled_silent_payment_address( + B_scan: PublicKey, + B_spend: PublicKey, + m: &BigUint, + hrp: Option<&str>, + version: Option, +) -> String { + let bytes = m.to_bytes_be(); + + let mut array = [0u8; 32]; + let start = array.len() - bytes.len(); + + array[start..].copy_from_slice(&bytes); + + let scalar = Scalar::from_be_bytes(array).unwrap(); + 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(); + + encode_silent_payment_address(B_scan, B_m, hrp, version) +} + fn calculate_P_n(B_spend: &PublicKey, t_n: [u8; 32]) -> XOnlyPublicKey { let secp = Secp256k1::new(); @@ -128,7 +154,7 @@ pub fn scanning( A_sum: PublicKey, outpoints_hash: [u8; 32], outputs_to_check: Vec, - _labels: &HashMap, + _labels: &HashMap, ) -> Vec { let ecdh_shared_secret = calculate_ecdh_secret(&A_sum, b_scan, outpoints_hash); let mut n = 0;