Skip to content

Commit

Permalink
Add example file
Browse files Browse the repository at this point in the history
  • Loading branch information
jlest01 committed Aug 9, 2024
1 parent 0e7e062 commit c217147
Show file tree
Hide file tree
Showing 2 changed files with 308 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ serde = { version = "1.0.103", default-features = false, optional = true }
hashes = { package = "bitcoin_hashes", version = ">= 0.12, <= 0.14", default-features = false, optional = true }
rand = { version = "0.8", default-features = false, optional = true }

# only used in the example of silent payments
libc = { version = "0.2", optional = true }
cc = { version = "1.0", optional = true }

[dev-dependencies]
rand_core = "0.6"
serde_cbor = "0.10.0"
Expand All @@ -66,6 +70,10 @@ required-features = ["hashes", "std"]
name = "generate_keys"
required-features = ["rand", "std"]

[[example]]
name = "silentpayments"
required-features = ["rand", "std", "libc", "cc"]

[workspace]
members = ["secp256k1-sys"]
exclude = ["no_std_test"]
300 changes: 300 additions & 0 deletions examples/silentpayments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
extern crate secp256k1;

use secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey, XOnlyPublicKey};
use secp256k1::silentpayments::{
silentpayments_recipient_create_label_tweak,
silentpayments_sender_create_outputs,
SilentpaymentsRecipient,
silentpayments_recipient_scan_outputs,
SilentpaymentsPublicData,
silentpayments_recipient_create_output_pubkey,
silentpayments_recipient_create_labelled_spend_pubkey
};

use libc::{c_uchar, c_void, size_t};
use std::slice;

#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct LabelCacheEntry {
label: [u8; 33],
label_tweak: [u8; 32],
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
struct LabelsCache {
entries_used: size_t,
entries: [LabelCacheEntry; 5],
}

#[no_mangle]
pub extern "C" fn rust_secp256k1_silentpayments_label_lookup(
label33: *const c_uchar,
cache_ptr: *const c_void,
) -> *const c_uchar {
// Safety checks
if label33.is_null() || cache_ptr.is_null() {
return std::ptr::null();
}

unsafe {
let cache = &*(cache_ptr as *const LabelsCache);
let label33_slice = slice::from_raw_parts(label33, 33);

for i in 0..cache.entries_used {
if cache.entries[i].label == *label33_slice {
return cache.entries[i].label_tweak.as_ptr();
}
}

std::ptr::null()
}
}

fn main() {

let secp = Secp256k1::new();

let sender_secret_keys: [[u8; 32]; 2] = [
[
0x34, 0x18, 0x5f, 0xd2, 0xc0, 0xc3, 0x71, 0x19,
0x73, 0x46, 0x2e, 0xc7, 0x7b, 0x65, 0x69, 0x95,
0x43, 0x20, 0x5a, 0xee, 0x4f, 0x30, 0xf4, 0xee,
0x32, 0x5b, 0xd8, 0x37, 0x6a, 0x1b, 0x36, 0xf3
],
[
0xcf, 0x3e, 0x69, 0x66, 0x58, 0xa9, 0x6e, 0x45,
0x70, 0x96, 0xcb, 0x2e, 0xc9, 0xa9, 0x7c, 0x27,
0x8c, 0x1b, 0xf0, 0xc6, 0x0d, 0x1d, 0xc3, 0x13,
0x92, 0x7d, 0xef, 0xac, 0xc2, 0x86, 0xae, 0x88
]
];

let smallest_outpoint: [u8; 36] = [
0x16, 0x9e, 0x1e, 0x83, 0xe9, 0x30, 0x85, 0x33, 0x91,
0xbc, 0x6f, 0x35, 0xf6, 0x05, 0xc6, 0x75, 0x4c, 0xfe,
0xad, 0x57, 0xcf, 0x83, 0x87, 0x63, 0x9d, 0x3b, 0x40,
0x96, 0xc5, 0x4f, 0x18, 0xf4, 0x00, 0x00, 0x00, 0x00
];

let bob_scan_seckey: [u8; 32] = [
0xa8, 0x90, 0x54, 0xc9, 0x5b, 0xe3, 0xc3, 0x01,
0x56, 0x65, 0x74, 0xf2, 0xaa, 0x93, 0xad, 0xe0,
0x51, 0x85, 0x09, 0x03, 0xa6, 0x9c, 0xbd, 0xd1,
0xd4, 0x7e, 0xae, 0x26, 0x3d, 0x7b, 0xc0, 0x31
];

let bob_spend_pubkey: [u8; 33] = [
0x02, 0xee, 0x97, 0xdf, 0x83, 0xb2, 0x54, 0x6a,
0xf5, 0xa7, 0xd0, 0x62, 0x15, 0xd9, 0x8b, 0xcb,
0x63, 0x7f, 0xe0, 0x5d, 0xd0, 0xfa, 0x37, 0x3b,
0xd8, 0x20, 0xe6, 0x64, 0xd3, 0x72, 0xde, 0x9a, 0x01
];

let bob_address: [[u8; 33]; 2] = [
[
0x02, 0x15, 0x40, 0xae, 0xa8, 0x97, 0x54, 0x7a,
0xd4, 0x39, 0xb4, 0xe0, 0xf6, 0x09, 0xe5, 0xf0,
0xfa, 0x63, 0xde, 0x89, 0xab, 0x11, 0xed, 0xe3,
0x1e, 0x8c, 0xde, 0x4b, 0xe2, 0x19, 0x42, 0x5f, 0x23
],
[
0x02, 0x3e, 0xff, 0xf8, 0x18, 0x51, 0x65, 0xea,
0x63, 0xa9, 0x92, 0xb3, 0x9f, 0x31, 0xd8, 0xfd,
0x8e, 0x0e, 0x64, 0xae, 0xf9, 0xd3, 0x88, 0x07,
0x34, 0x97, 0x37, 0x14, 0xa5, 0x3d, 0x83, 0x11, 0x8d
]
];

let carol_scan_key: [u8; 32] = [
0x04, 0xb2, 0xa4, 0x11, 0x63, 0x5c, 0x09, 0x77,
0x59, 0xaa, 0xcd, 0x0f, 0x00, 0x5a, 0x4c, 0x82,
0xc8, 0xc9, 0x28, 0x62, 0xc6, 0xfc, 0x28, 0x4b,
0x80, 0xb8, 0xef, 0xeb, 0xc2, 0x0c, 0x3d, 0x17
];

let carol_address: [[u8; 33]; 2] = [
[
0x03, 0xbb, 0xc6, 0x3f, 0x12, 0x74, 0x5d, 0x3b,
0x9e, 0x9d, 0x24, 0xc6, 0xcd, 0x7a, 0x1e, 0xfe,
0xba, 0xd0, 0xa7, 0xf4, 0x69, 0x23, 0x2f, 0xbe,
0xcf, 0x31, 0xfb, 0xa7, 0xb4, 0xf7, 0xdd, 0xed, 0xa8
],
[
0x03, 0x81, 0xeb, 0x9a, 0x9a, 0x9e, 0xc7, 0x39,
0xd5, 0x27, 0xc1, 0x63, 0x1b, 0x31, 0xb4, 0x21,
0x56, 0x6f, 0x5c, 0x2a, 0x47, 0xb4, 0xab, 0x5b,
0x1f, 0x6a, 0x68, 0x6d, 0xfb, 0x68, 0xea, 0xb7, 0x16
]
];

let address_amounts = ["1.0 BTC", "2.0 BTC", "3.0 BTC"];

let n_tx_outputs = 3;

let mut sp_addresses: [&[[u8; 33]; 2]; 3] = [&[[0; 33]; 2]; 3];

// Assign references to the addresses
sp_addresses[0] = &carol_address; // : 1.0 BTC
sp_addresses[1] = &bob_address; // : 2.0 BTC
sp_addresses[2] = &carol_address;

let mut recipients = Vec::<SilentpaymentsRecipient>::new();

let mut tx_inputs = Vec::<XOnlyPublicKey>::new();

for i in 0..n_tx_outputs {
let recipient_index = i;

let recipient_scan_pubkey = PublicKey::from_slice(&sp_addresses[i][0]).unwrap();
let recipient_spend_pubkey = PublicKey::from_slice(&sp_addresses[i][1]).unwrap();

let silentpayment_recipient = SilentpaymentsRecipient::new(
&recipient_scan_pubkey,
&recipient_spend_pubkey,
recipient_index
);

recipients.push(silentpayment_recipient);
}

let recipients = recipients.as_slice();

let mut taproot_seckeys = Vec::<Keypair>::new();

for &key in sender_secret_keys.iter() {
let seckey: [u8; 32] = key;

let keypair = Keypair::from_seckey_slice(&secp, &seckey).unwrap();

taproot_seckeys.push(keypair);

tx_inputs.push(keypair.x_only_public_key().0);
}

let taproot_seckeys = taproot_seckeys.as_slice();

let mut tx_outputs: Vec<XOnlyPublicKey> = Vec::new();

let out_pubkeys = silentpayments_sender_create_outputs(
&secp,
recipients,
&smallest_outpoint,
Some(taproot_seckeys),
None
).unwrap();

println!("{}:", "Alice created the following outputs for Bob and Carol:");
for (i, out_pubkey) in out_pubkeys.iter().enumerate() {
print!("\t{} : 0x", address_amounts[i]);
for byte in out_pubkey.serialize().iter().cloned() {
print!("{:02x}", byte);
}
println!();

tx_outputs.push(out_pubkey.clone());
}

let bob_scan_secretkey = SecretKey::from_slice(&bob_scan_seckey).unwrap();
let m: u32 = 1;

let label_tweak_result = silentpayments_recipient_create_label_tweak(&secp, &bob_scan_secretkey, m).unwrap();

let bob_spend_publickey = PublicKey::from_slice(&bob_spend_pubkey).unwrap();

let _labelled_spend_pubkey = silentpayments_recipient_create_labelled_spend_pubkey(
&secp,
&bob_spend_publickey,
&label_tweak_result.pubkey
).unwrap();

let public_data: SilentpaymentsPublicData = SilentpaymentsPublicData::create(
&secp,
&smallest_outpoint,
Some(&tx_inputs),
None
).unwrap();

let mut cache = LabelsCache {
entries_used: 0,
entries: [LabelCacheEntry {
label: [0; 33],
label_tweak: [0; 32]
}; 5]
};

cache.entries[0].label = label_tweak_result.pubkey.serialize();
cache.entries[0].label_tweak = label_tweak_result.label_tweak;
cache.entries_used += 1;

let _label_tweak = rust_secp256k1_silentpayments_label_lookup(
label_tweak_result.pubkey.serialize().as_ptr(),
&cache as *const LabelsCache as *const c_void
);

let tx_outputs_slice = tx_outputs.as_slice();

let bob_spend_publickey = PublicKey::from_slice(&bob_spend_pubkey).unwrap();

let found_output = silentpayments_recipient_scan_outputs(
&secp,
tx_outputs_slice,
&bob_scan_secretkey,
&public_data,
&bob_spend_publickey,
rust_secp256k1_silentpayments_label_lookup,
cache
).unwrap();

println!();
println!("{} :", "Bob found the following outputs:");
for output in found_output.iter() {
println!("\t{}", output);
}

let light_client_data33 = public_data.serialize(&secp).unwrap();

let carol_public_data = SilentpaymentsPublicData::parse(&secp, &light_client_data33).unwrap();

let carol_scan_seckey = SecretKey::from_slice(&carol_scan_key).unwrap();

let shared_secret = carol_public_data.recipient_create_shared_secret(&secp, &carol_scan_seckey).unwrap();

let mut found: bool;
let mut k: u32 = 0;
let mut ser_found_outputs: Vec<XOnlyPublicKey> = Vec::new();

let carol_spend_pubkey = PublicKey::from_slice(&carol_address[1]).unwrap();

println!();

loop {

let potential_output =
silentpayments_recipient_create_output_pubkey(&secp, &shared_secret, &carol_spend_pubkey, k).unwrap();

found = false;
for i in 0..n_tx_outputs {
if tx_outputs[i] == potential_output {
ser_found_outputs.push(potential_output);
found = true;
k += 1;
break;
}
}

if !found {
break;
}
}

println!("{}:", "Carol found the following outputs");
for output in ser_found_outputs.iter() {
print!("\t{}", "0x");
for byte in output.serialize().iter().cloned() {
print!("{:02x}", byte);
}
println!();
}
}

0 comments on commit c217147

Please sign in to comment.