Skip to content

Commit c217147

Browse files
committed
Add example file
1 parent 0e7e062 commit c217147

File tree

2 files changed

+308
-0
lines changed

2 files changed

+308
-0
lines changed

Cargo.toml

+8
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ serde = { version = "1.0.103", default-features = false, optional = true }
4040
hashes = { package = "bitcoin_hashes", version = ">= 0.12, <= 0.14", default-features = false, optional = true }
4141
rand = { version = "0.8", default-features = false, optional = true }
4242

43+
# only used in the example of silent payments
44+
libc = { version = "0.2", optional = true }
45+
cc = { version = "1.0", optional = true }
46+
4347
[dev-dependencies]
4448
rand_core = "0.6"
4549
serde_cbor = "0.10.0"
@@ -66,6 +70,10 @@ required-features = ["hashes", "std"]
6670
name = "generate_keys"
6771
required-features = ["rand", "std"]
6872

73+
[[example]]
74+
name = "silentpayments"
75+
required-features = ["rand", "std", "libc", "cc"]
76+
6977
[workspace]
7078
members = ["secp256k1-sys"]
7179
exclude = ["no_std_test"]

examples/silentpayments.rs

+300
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
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+
164+
let mut taproot_seckeys = Vec::<Keypair>::new();
165+
166+
for &key in sender_secret_keys.iter() {
167+
let seckey: [u8; 32] = key;
168+
169+
let keypair = Keypair::from_seckey_slice(&secp, &seckey).unwrap();
170+
171+
taproot_seckeys.push(keypair);
172+
173+
tx_inputs.push(keypair.x_only_public_key().0);
174+
}
175+
176+
let taproot_seckeys = taproot_seckeys.as_slice();
177+
178+
let mut tx_outputs: Vec<XOnlyPublicKey> = Vec::new();
179+
180+
let out_pubkeys = silentpayments_sender_create_outputs(
181+
&secp,
182+
recipients,
183+
&smallest_outpoint,
184+
Some(taproot_seckeys),
185+
None
186+
).unwrap();
187+
188+
println!("{}:", "Alice created the following outputs for Bob and Carol:");
189+
for (i, out_pubkey) in out_pubkeys.iter().enumerate() {
190+
print!("\t{} : 0x", address_amounts[i]);
191+
for byte in out_pubkey.serialize().iter().cloned() {
192+
print!("{:02x}", byte);
193+
}
194+
println!();
195+
196+
tx_outputs.push(out_pubkey.clone());
197+
}
198+
199+
let bob_scan_secretkey = SecretKey::from_slice(&bob_scan_seckey).unwrap();
200+
let m: u32 = 1;
201+
202+
let label_tweak_result = silentpayments_recipient_create_label_tweak(&secp, &bob_scan_secretkey, m).unwrap();
203+
204+
let bob_spend_publickey = PublicKey::from_slice(&bob_spend_pubkey).unwrap();
205+
206+
let _labelled_spend_pubkey = silentpayments_recipient_create_labelled_spend_pubkey(
207+
&secp,
208+
&bob_spend_publickey,
209+
&label_tweak_result.pubkey
210+
).unwrap();
211+
212+
let public_data: SilentpaymentsPublicData = SilentpaymentsPublicData::create(
213+
&secp,
214+
&smallest_outpoint,
215+
Some(&tx_inputs),
216+
None
217+
).unwrap();
218+
219+
let mut cache = LabelsCache {
220+
entries_used: 0,
221+
entries: [LabelCacheEntry {
222+
label: [0; 33],
223+
label_tweak: [0; 32]
224+
}; 5]
225+
};
226+
227+
cache.entries[0].label = label_tweak_result.pubkey.serialize();
228+
cache.entries[0].label_tweak = label_tweak_result.label_tweak;
229+
cache.entries_used += 1;
230+
231+
let _label_tweak = rust_secp256k1_silentpayments_label_lookup(
232+
label_tweak_result.pubkey.serialize().as_ptr(),
233+
&cache as *const LabelsCache as *const c_void
234+
);
235+
236+
let tx_outputs_slice = tx_outputs.as_slice();
237+
238+
let bob_spend_publickey = PublicKey::from_slice(&bob_spend_pubkey).unwrap();
239+
240+
let found_output = silentpayments_recipient_scan_outputs(
241+
&secp,
242+
tx_outputs_slice,
243+
&bob_scan_secretkey,
244+
&public_data,
245+
&bob_spend_publickey,
246+
rust_secp256k1_silentpayments_label_lookup,
247+
cache
248+
).unwrap();
249+
250+
println!();
251+
println!("{} :", "Bob found the following outputs:");
252+
for output in found_output.iter() {
253+
println!("\t{}", output);
254+
}
255+
256+
let light_client_data33 = public_data.serialize(&secp).unwrap();
257+
258+
let carol_public_data = SilentpaymentsPublicData::parse(&secp, &light_client_data33).unwrap();
259+
260+
let carol_scan_seckey = SecretKey::from_slice(&carol_scan_key).unwrap();
261+
262+
let shared_secret = carol_public_data.recipient_create_shared_secret(&secp, &carol_scan_seckey).unwrap();
263+
264+
let mut found: bool;
265+
let mut k: u32 = 0;
266+
let mut ser_found_outputs: Vec<XOnlyPublicKey> = Vec::new();
267+
268+
let carol_spend_pubkey = PublicKey::from_slice(&carol_address[1]).unwrap();
269+
270+
println!();
271+
272+
loop {
273+
274+
let potential_output =
275+
silentpayments_recipient_create_output_pubkey(&secp, &shared_secret, &carol_spend_pubkey, k).unwrap();
276+
277+
found = false;
278+
for i in 0..n_tx_outputs {
279+
if tx_outputs[i] == potential_output {
280+
ser_found_outputs.push(potential_output);
281+
found = true;
282+
k += 1;
283+
break;
284+
}
285+
}
286+
287+
if !found {
288+
break;
289+
}
290+
}
291+
292+
println!("{}:", "Carol found the following outputs");
293+
for output in ser_found_outputs.iter() {
294+
print!("\t{}", "0x");
295+
for byte in output.serialize().iter().cloned() {
296+
print!("{:02x}", byte);
297+
}
298+
println!();
299+
}
300+
}

0 commit comments

Comments
 (0)