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