Skip to content

Commit 9566ad2

Browse files
committed
Add example file
1 parent 6fbb059 commit 9566ad2

File tree

2 files changed

+315
-0
lines changed

2 files changed

+315
-0
lines changed

Cargo.toml

+7
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ serde_cbor = "0.10.0"
4646
serde_test = "1.0.19"
4747
bincode = "1.3.3"
4848
hex_lit = "0.1.1"
49+
# only used in the example of silent payments
50+
libc = { version = "0.2" }
51+
cc = { version = "1.0" }
4952

5053
[target.wasm32-unknown-unknown.dev-dependencies]
5154
wasm-bindgen-test = "0.3"
@@ -66,6 +69,10 @@ required-features = ["hashes", "std"]
6669
name = "generate_keys"
6770
required-features = ["rand", "std"]
6871

72+
[[example]]
73+
name = "silentpayments"
74+
required-features = ["rand", "std"]
75+
6976
[workspace]
7077
members = ["secp256k1-sys"]
7178
exclude = ["no_std_test"]

examples/silentpayments.rs

+308
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
extern crate secp256k1;
2+
3+
use secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey, XOnlyPublicKey};
4+
use secp256k1::silentpayments::{
5+
silentpayments_recipient_create_label_tweak,
6+
silentpayments_sender_create_outputs,
7+
SilentpaymentsRecipient,
8+
silentpayments_recipient_scan_outputs,
9+
SilentpaymentsPublicData,
10+
silentpayments_recipient_create_output_pubkey,
11+
silentpayments_recipient_create_labelled_spend_pubkey
12+
};
13+
14+
use libc::{c_uchar, c_void, size_t};
15+
use std::slice;
16+
17+
#[repr(C)]
18+
#[derive(Debug, Copy, Clone)]
19+
struct LabelCacheEntry {
20+
label: [u8; 33],
21+
label_tweak: [u8; 32],
22+
}
23+
24+
#[repr(C)]
25+
#[derive(Debug, Copy, Clone)]
26+
struct LabelsCache {
27+
entries_used: size_t,
28+
entries: [LabelCacheEntry; 5],
29+
}
30+
31+
#[no_mangle]
32+
pub extern "C" fn rust_secp256k1_silentpayments_label_lookup(
33+
label33: *const c_uchar,
34+
cache_ptr: *const c_void,
35+
) -> *const c_uchar {
36+
// Safety checks
37+
if label33.is_null() || cache_ptr.is_null() {
38+
return std::ptr::null();
39+
}
40+
41+
unsafe {
42+
let cache = &*(cache_ptr as *const LabelsCache);
43+
let label33_slice = slice::from_raw_parts(label33, 33);
44+
45+
for i in 0..cache.entries_used {
46+
if cache.entries[i].label == *label33_slice {
47+
return cache.entries[i].label_tweak.as_ptr();
48+
}
49+
}
50+
51+
std::ptr::null()
52+
}
53+
}
54+
55+
fn main() {
56+
57+
let secp = Secp256k1::new();
58+
59+
let sender_secret_keys: [[u8; 32]; 2] = [
60+
[
61+
0x34, 0x18, 0x5f, 0xd2, 0xc0, 0xc3, 0x71, 0x19,
62+
0x73, 0x46, 0x2e, 0xc7, 0x7b, 0x65, 0x69, 0x95,
63+
0x43, 0x20, 0x5a, 0xee, 0x4f, 0x30, 0xf4, 0xee,
64+
0x32, 0x5b, 0xd8, 0x37, 0x6a, 0x1b, 0x36, 0xf3
65+
],
66+
[
67+
0xcf, 0x3e, 0x69, 0x66, 0x58, 0xa9, 0x6e, 0x45,
68+
0x70, 0x96, 0xcb, 0x2e, 0xc9, 0xa9, 0x7c, 0x27,
69+
0x8c, 0x1b, 0xf0, 0xc6, 0x0d, 0x1d, 0xc3, 0x13,
70+
0x92, 0x7d, 0xef, 0xac, 0xc2, 0x86, 0xae, 0x88
71+
]
72+
];
73+
74+
let smallest_outpoint: [u8; 36] = [
75+
0x16, 0x9e, 0x1e, 0x83, 0xe9, 0x30, 0x85, 0x33, 0x91,
76+
0xbc, 0x6f, 0x35, 0xf6, 0x05, 0xc6, 0x75, 0x4c, 0xfe,
77+
0xad, 0x57, 0xcf, 0x83, 0x87, 0x63, 0x9d, 0x3b, 0x40,
78+
0x96, 0xc5, 0x4f, 0x18, 0xf4, 0x00, 0x00, 0x00, 0x00
79+
];
80+
81+
let bob_scan_seckey: [u8; 32] = [
82+
0xa8, 0x90, 0x54, 0xc9, 0x5b, 0xe3, 0xc3, 0x01,
83+
0x56, 0x65, 0x74, 0xf2, 0xaa, 0x93, 0xad, 0xe0,
84+
0x51, 0x85, 0x09, 0x03, 0xa6, 0x9c, 0xbd, 0xd1,
85+
0xd4, 0x7e, 0xae, 0x26, 0x3d, 0x7b, 0xc0, 0x31
86+
];
87+
88+
let bob_spend_pubkey: [u8; 33] = [
89+
0x02, 0xee, 0x97, 0xdf, 0x83, 0xb2, 0x54, 0x6a,
90+
0xf5, 0xa7, 0xd0, 0x62, 0x15, 0xd9, 0x8b, 0xcb,
91+
0x63, 0x7f, 0xe0, 0x5d, 0xd0, 0xfa, 0x37, 0x3b,
92+
0xd8, 0x20, 0xe6, 0x64, 0xd3, 0x72, 0xde, 0x9a, 0x01
93+
];
94+
95+
let bob_address: [[u8; 33]; 2] = [
96+
[
97+
0x02, 0x15, 0x40, 0xae, 0xa8, 0x97, 0x54, 0x7a,
98+
0xd4, 0x39, 0xb4, 0xe0, 0xf6, 0x09, 0xe5, 0xf0,
99+
0xfa, 0x63, 0xde, 0x89, 0xab, 0x11, 0xed, 0xe3,
100+
0x1e, 0x8c, 0xde, 0x4b, 0xe2, 0x19, 0x42, 0x5f, 0x23
101+
],
102+
[
103+
0x02, 0x3e, 0xff, 0xf8, 0x18, 0x51, 0x65, 0xea,
104+
0x63, 0xa9, 0x92, 0xb3, 0x9f, 0x31, 0xd8, 0xfd,
105+
0x8e, 0x0e, 0x64, 0xae, 0xf9, 0xd3, 0x88, 0x07,
106+
0x34, 0x97, 0x37, 0x14, 0xa5, 0x3d, 0x83, 0x11, 0x8d
107+
]
108+
];
109+
110+
let carol_scan_key: [u8; 32] = [
111+
0x04, 0xb2, 0xa4, 0x11, 0x63, 0x5c, 0x09, 0x77,
112+
0x59, 0xaa, 0xcd, 0x0f, 0x00, 0x5a, 0x4c, 0x82,
113+
0xc8, 0xc9, 0x28, 0x62, 0xc6, 0xfc, 0x28, 0x4b,
114+
0x80, 0xb8, 0xef, 0xeb, 0xc2, 0x0c, 0x3d, 0x17
115+
];
116+
117+
let carol_address: [[u8; 33]; 2] = [
118+
[
119+
0x03, 0xbb, 0xc6, 0x3f, 0x12, 0x74, 0x5d, 0x3b,
120+
0x9e, 0x9d, 0x24, 0xc6, 0xcd, 0x7a, 0x1e, 0xfe,
121+
0xba, 0xd0, 0xa7, 0xf4, 0x69, 0x23, 0x2f, 0xbe,
122+
0xcf, 0x31, 0xfb, 0xa7, 0xb4, 0xf7, 0xdd, 0xed, 0xa8
123+
],
124+
[
125+
0x03, 0x81, 0xeb, 0x9a, 0x9a, 0x9e, 0xc7, 0x39,
126+
0xd5, 0x27, 0xc1, 0x63, 0x1b, 0x31, 0xb4, 0x21,
127+
0x56, 0x6f, 0x5c, 0x2a, 0x47, 0xb4, 0xab, 0x5b,
128+
0x1f, 0x6a, 0x68, 0x6d, 0xfb, 0x68, 0xea, 0xb7, 0x16
129+
]
130+
];
131+
132+
let address_amounts = ["1.0 BTC", "2.0 BTC", "3.0 BTC"];
133+
134+
let n_tx_outputs = 3;
135+
136+
let mut sp_addresses: [&[[u8; 33]; 2]; 3] = [&[[0; 33]; 2]; 3];
137+
138+
// Assign references to the addresses
139+
sp_addresses[0] = &carol_address; // : 1.0 BTC
140+
sp_addresses[1] = &bob_address; // : 2.0 BTC
141+
sp_addresses[2] = &carol_address;
142+
143+
let mut recipients = Vec::<SilentpaymentsRecipient>::new();
144+
145+
let mut tx_inputs = Vec::<XOnlyPublicKey>::new();
146+
147+
for i in 0..n_tx_outputs {
148+
let recipient_index = i;
149+
150+
let recipient_scan_pubkey = PublicKey::from_slice(&sp_addresses[i][0]).unwrap();
151+
let recipient_spend_pubkey = PublicKey::from_slice(&sp_addresses[i][1]).unwrap();
152+
153+
let silentpayment_recipient = SilentpaymentsRecipient::new(
154+
&recipient_scan_pubkey,
155+
&recipient_spend_pubkey,
156+
recipient_index
157+
);
158+
159+
recipients.push(silentpayment_recipient);
160+
}
161+
162+
let recipients = recipients.as_slice();
163+
let mut recipients_ref: Vec<&SilentpaymentsRecipient> = recipients.iter().collect();
164+
let recipients_ref = recipients_ref.as_mut_slice();
165+
166+
let mut taproot_seckeys = Vec::<Keypair>::new();
167+
168+
for &key in sender_secret_keys.iter() {
169+
let seckey: [u8; 32] = key;
170+
171+
let keypair = Keypair::from_seckey_slice(&secp, &seckey).unwrap();
172+
173+
taproot_seckeys.push(keypair);
174+
175+
tx_inputs.push(keypair.x_only_public_key().0);
176+
}
177+
178+
let taproot_seckeys = taproot_seckeys.as_slice();
179+
let taproot_seckeys_ref: Vec<&Keypair> = taproot_seckeys.iter().collect();
180+
let taproot_seckeys_ref = taproot_seckeys_ref.as_slice();
181+
182+
let mut tx_outputs: Vec<XOnlyPublicKey> = Vec::new();
183+
184+
let out_pubkeys = silentpayments_sender_create_outputs(
185+
&secp,
186+
recipients_ref,
187+
&smallest_outpoint,
188+
Some(taproot_seckeys_ref),
189+
None
190+
).unwrap();
191+
192+
println!("{}:", "Alice created the following outputs for Bob and Carol:");
193+
for (i, out_pubkey) in out_pubkeys.iter().enumerate() {
194+
print!("\t{} : 0x", address_amounts[i]);
195+
for byte in out_pubkey.serialize().iter().cloned() {
196+
print!("{:02x}", byte);
197+
}
198+
println!();
199+
200+
tx_outputs.push(out_pubkey.clone());
201+
}
202+
203+
let bob_scan_secretkey = SecretKey::from_slice(&bob_scan_seckey).unwrap();
204+
let m: u32 = 1;
205+
206+
let label_tweak_result = silentpayments_recipient_create_label_tweak(&secp, &bob_scan_secretkey, m).unwrap();
207+
208+
let bob_spend_publickey = PublicKey::from_slice(&bob_spend_pubkey).unwrap();
209+
210+
let _labelled_spend_pubkey = silentpayments_recipient_create_labelled_spend_pubkey(
211+
&secp,
212+
&bob_spend_publickey,
213+
&label_tweak_result.pubkey
214+
).unwrap();
215+
216+
let tx_inputs_ref: Vec<&XOnlyPublicKey> = tx_inputs.iter().collect();
217+
let tx_inputs_ref = tx_inputs_ref.as_slice();
218+
219+
let public_data: SilentpaymentsPublicData = SilentpaymentsPublicData::create(
220+
&secp,
221+
&smallest_outpoint,
222+
Some(tx_inputs_ref),
223+
None
224+
).unwrap();
225+
226+
let mut cache = LabelsCache {
227+
entries_used: 0,
228+
entries: [LabelCacheEntry {
229+
label: [0; 33],
230+
label_tweak: [0; 32]
231+
}; 5]
232+
};
233+
234+
cache.entries[0].label = label_tweak_result.pubkey.serialize();
235+
cache.entries[0].label_tweak = label_tweak_result.label_tweak;
236+
cache.entries_used += 1;
237+
238+
let _label_tweak = rust_secp256k1_silentpayments_label_lookup(
239+
label_tweak_result.pubkey.serialize().as_ptr(),
240+
&cache as *const LabelsCache as *const c_void
241+
);
242+
243+
let tx_outputs_slice_ref: Vec<&XOnlyPublicKey> = tx_outputs.iter().collect();
244+
let tx_outputs_slice_ref = tx_outputs_slice_ref.as_slice();
245+
246+
let bob_spend_publickey = PublicKey::from_slice(&bob_spend_pubkey).unwrap();
247+
248+
let found_output = silentpayments_recipient_scan_outputs(
249+
&secp,
250+
tx_outputs_slice_ref,
251+
&bob_scan_secretkey,
252+
&public_data,
253+
&bob_spend_publickey,
254+
rust_secp256k1_silentpayments_label_lookup,
255+
cache
256+
).unwrap();
257+
258+
println!();
259+
println!("{} :", "Bob found the following outputs:");
260+
for output in found_output.iter() {
261+
println!("\t{}", output);
262+
}
263+
264+
let light_client_data33 = public_data.serialize(&secp).unwrap();
265+
266+
let carol_public_data = SilentpaymentsPublicData::parse(&secp, &light_client_data33).unwrap();
267+
268+
let carol_scan_seckey = SecretKey::from_slice(&carol_scan_key).unwrap();
269+
270+
let shared_secret = carol_public_data.recipient_create_shared_secret(&secp, &carol_scan_seckey).unwrap();
271+
272+
let mut found: bool;
273+
let mut k: u32 = 0;
274+
let mut ser_found_outputs: Vec<XOnlyPublicKey> = Vec::new();
275+
276+
let carol_spend_pubkey = PublicKey::from_slice(&carol_address[1]).unwrap();
277+
278+
println!();
279+
280+
loop {
281+
282+
let potential_output =
283+
silentpayments_recipient_create_output_pubkey(&secp, &shared_secret, &carol_spend_pubkey, k).unwrap();
284+
285+
found = false;
286+
for i in 0..n_tx_outputs {
287+
if tx_outputs[i] == potential_output {
288+
ser_found_outputs.push(potential_output);
289+
found = true;
290+
k += 1;
291+
break;
292+
}
293+
}
294+
295+
if !found {
296+
break;
297+
}
298+
}
299+
300+
println!("{}:", "Carol found the following outputs");
301+
for output in ser_found_outputs.iter() {
302+
print!("\t{}", "0x");
303+
for byte in output.serialize().iter().cloned() {
304+
print!("{:02x}", byte);
305+
}
306+
println!();
307+
}
308+
}

0 commit comments

Comments
 (0)