Skip to content

Commit

Permalink
Sender generates keys with partial secret
Browse files Browse the repository at this point in the history
  • Loading branch information
Sosthene00 authored and cygnet3 committed Sep 17, 2023
1 parent e4e22a8 commit daa411c
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 43 deletions.
41 changes: 16 additions & 25 deletions src/sending.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
Result,
};

#[derive(Copy, Clone, Debug)]
struct SilentPaymentAddress {
version: u8,
scan_pubkey: PublicKey,
Expand Down Expand Up @@ -103,7 +104,7 @@ impl Into<String> for SilentPaymentAddress {
/// # Arguments
///
/// * `recipients` - A `Vec` of silent payment addresses to be paid.
/// * `ecdh_shared_secrets` - A HashMap that maps every scan key (representing a recipient) to a shared secret. This shared secret is created using the scan key, along with the private keys of the outputs to spend. This library has no access to these private keys, so we expect the computed shared secret instead.
/// * `partial_secret` - A `SecretKey` that represents the sum of the private keys of eligible inputs of the transaction multiplied by the hash of its outpoints.
///
/// # Returns
///
Expand All @@ -119,26 +120,22 @@ impl Into<String> for SilentPaymentAddress {
/// * Edge cases are hit during elliptic curve computation (extremely unlikely).
pub fn generate_multiple_recipient_pubkeys(
recipients: Vec<String>,
ecdh_shared_secrets: HashMap<PublicKey, PublicKey>,
partial_secret: SecretKey,
) -> Result<HashMap<String, Vec<XOnlyPublicKey>>> {
let secp = Secp256k1::new();

let mut silent_payment_groups: HashMap<PublicKey, (PublicKey, Vec<SilentPaymentAddress>)> =
HashMap::new();
for recipient in recipients {
let recipient: SilentPaymentAddress = recipient.try_into()?;
let B_scan = recipient.scan_pubkey;
for address in recipients {
let address: SilentPaymentAddress = address.try_into()?;
let B_scan = address.scan_pubkey;

if let Some((_, payments)) = silent_payment_groups.get_mut(&B_scan) {
payments.push(recipient);
payments.push(address);
} else {
let ecdh_shared_secret = ecdh_shared_secrets
.get(&B_scan)
.ok_or(Error::InvalidSharedSecret(
"Shared secret for this B_scan not found".to_owned(),
))?
.to_owned();
silent_payment_groups.insert(B_scan, (ecdh_shared_secret, vec![recipient]));
let ecdh_shared_secret: PublicKey = B_scan.mul_tweak(&secp, &partial_secret.into())?;

silent_payment_groups.insert(B_scan, (ecdh_shared_secret, vec![address]));
}
}

Expand All @@ -148,18 +145,18 @@ pub fn generate_multiple_recipient_pubkeys(

let (ecdh_shared_secret, recipients) = group;

for recipient in recipients {
for addr in recipients {
let mut bytes: Vec<u8> = Vec::new();
bytes.extend_from_slice(&ecdh_shared_secret.serialize());
bytes.extend_from_slice(&ser_uint32(n));

let t_n = sha256(&bytes);

let res = SecretKey::from_slice(&t_n)?.public_key(&secp);
let reskey = res.combine(&recipient.m_pubkey)?;
let reskey = res.combine(&addr.m_pubkey)?;
let (reskey_xonly, _) = reskey.x_only_public_key();

let entry = result.entry(recipient.into()).or_insert_with(Vec::new);
let entry = result.entry(addr.into()).or_insert_with(Vec::new);
entry.push(reskey_xonly);
n += 1;
}
Expand All @@ -175,7 +172,7 @@ pub fn generate_multiple_recipient_pubkeys(
/// # Arguments
///
/// * `recipient` - A `String` of the bech32m-encoded silent payment address to be paid.
/// * `ecdh_shared_secret` - A `PublicKey` representing the shared secret. This shared secret is created using the scan key, along with the private keys of the outputs to spend. This library has no access to these private keys, so we expect the computed shared secret instead.
/// * `partial_secret` - A `SecretKey` representing the private keys of the outputs to spend multiplied by the hash of its outpoints.
///
/// # Returns
///
Expand All @@ -189,15 +186,9 @@ pub fn generate_multiple_recipient_pubkeys(
/// * Edge cases are hit during elliptic curve computation (extremely unlikely).
pub fn generate_recipient_pubkey(
recipient: String,
ecdh_shared_secret: PublicKey,
partial_secret: SecretKey,
) -> Result<XOnlyPublicKey> {
let scan_pubkey = decode_scan_pubkey(&recipient)?;

// re-use generate_recipient_pubkeys function logic
let recipients = vec![recipient];
let mut ecdh_shared_secrets = HashMap::new();
ecdh_shared_secrets.insert(scan_pubkey, ecdh_shared_secret);
let res = generate_multiple_recipient_pubkeys(recipients, ecdh_shared_secrets)?;
let res = generate_multiple_recipient_pubkeys(vec![recipient], partial_secret)?;

let output = res
.into_values()
Expand Down
10 changes: 3 additions & 7 deletions tests/common/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,11 @@ pub fn calculate_tweak_data_for_recipient(
A_sum.mul_tweak(&secp, &outpoints_hash).unwrap()
}

pub fn sender_calculate_shared_secret(
pub fn sender_calculate_partial_secret(
a_sum: SecretKey,
B_scan: PublicKey,
outpoints_hash: Scalar,
) -> PublicKey {
let secp = secp256k1::Secp256k1::new();

let diffie_hellman = B_scan.mul_tweak(&secp, &a_sum.into()).unwrap();
diffie_hellman.mul_tweak(&secp, &outpoints_hash).unwrap()
) -> SecretKey{
a_sum.mul_tweak(&outpoints_hash).unwrap()
}

pub fn receiver_calculate_shared_secret(
Expand Down
18 changes: 7 additions & 11 deletions tests/vector_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ mod tests {
str::FromStr,
};

use secp256k1::{PublicKey, Secp256k1, SecretKey, Scalar};
use secp256k1::{Secp256k1, SecretKey, Scalar};

#[cfg(feature = "receiving")]
use silentpayments::receiving::Receiver;

#[cfg(feature = "sending")]
use silentpayments::sending::{decode_scan_pubkey, generate_multiple_recipient_pubkeys};
use silentpayments::sending::generate_multiple_recipient_pubkeys;

use crate::common::{
structs::TestData,
utils::{
self, calculate_tweak_data_for_recipient, decode_input_pub_keys, decode_outpoints,
decode_outputs_to_check, decode_priv_keys, decode_recipients, get_a_sum_secret_keys,
hash_outpoints, sender_calculate_shared_secret, verify_and_calculate_signatures, receiver_calculate_shared_secret
hash_outpoints, sender_calculate_partial_secret, verify_and_calculate_signatures, receiver_calculate_shared_secret
},
};

Expand Down Expand Up @@ -59,15 +59,11 @@ mod tests {

let a_sum = get_a_sum_secret_keys(&input_priv_keys);

let mut ecdh_shared_secrets: HashMap<PublicKey, PublicKey> = HashMap::new();
for addr in &silent_addresses {
let B_scan = decode_scan_pubkey(&addr).unwrap();
let ecdh_shared_secret =
sender_calculate_shared_secret(a_sum, B_scan, outpoints_hash);
ecdh_shared_secrets.insert(B_scan, ecdh_shared_secret);
}
let partial_secret =
sender_calculate_partial_secret(a_sum, outpoints_hash);

let outputs =
generate_multiple_recipient_pubkeys(silent_addresses, ecdh_shared_secrets).unwrap();
generate_multiple_recipient_pubkeys(silent_addresses, partial_secret).unwrap();

for output_pubkeys in &outputs {
for pubkey in output_pubkeys.1 {
Expand Down

0 comments on commit daa411c

Please sign in to comment.