@@ -111,13 +111,14 @@ const unsigned char* label_lookup(
111111}
112112
113113int  main (void ) {
114-     enum  { N_INPUTS  =  2 , N_OUTPUTS  =  3  };
114+     enum  { N_INPUTS  =  2 , N_OUTPUTS  =  3 ,  N_RECIPIENTS   =   2  };
115115    unsigned char   randomize [32 ];
116116    unsigned char   xonly_print [32 ];
117117    secp256k1_xonly_pubkey  tx_inputs [N_INPUTS ];
118118    secp256k1_xonly_pubkey  tx_outputs [N_OUTPUTS ];
119119    int  ret ;
120120    size_t  i ;
121+     unsigned char   dleq_proof [N_RECIPIENTS ][64 ];
121122
122123    /* Before we can call actual API functions, we need to create a "context" */ 
123124    secp256k1_context *  ctx  =  secp256k1_context_create (SECP256K1_CONTEXT_NONE );
@@ -218,14 +219,63 @@ int main(void) {
218219        for  (i  =  0 ; i  <  N_OUTPUTS ; i ++ ) {
219220            generated_output_ptrs [i ] =  & generated_outputs [i ];
220221        }
221-         ret  =  secp256k1_silentpayments_sender_create_outputs (ctx ,
222-             generated_output_ptrs ,
223-             recipient_ptrs , N_OUTPUTS ,
224-             smallest_outpoint ,
225-             sender_seckey_ptrs , N_INPUTS ,
226-             NULL , 0 
227-         );
228-         assert (ret );
222+ 
223+         /* Sender can perform 1 of the following options: 
224+          * Option 1: generate outputs without DLEQ proofs 
225+             ret = secp256k1_silentpayments_sender_create_outputs(ctx, 
226+                 generated_output_ptrs, 
227+                 recipient_ptrs, N_OUTPUTS, 
228+                 smallest_outpoint, 
229+                 sender_seckey_ptrs, N_INPUTS, 
230+                 NULL, 0 
231+             ); 
232+             assert(ret); 
233+          */ 
234+         {
235+             /* Option 2: generate outputs with DLEQ proofs*/ 
236+             secp256k1_silentpayments_public_data  public_data ;
237+             const  secp256k1_xonly_pubkey  * tx_input_ptrs [N_INPUTS ];
238+             size_t  n_dleq_size ;
239+             secp256k1_silentpayments_dleq_data  dleq_data [N_RECIPIENTS ];
240+             secp256k1_silentpayments_dleq_data  * dleq_data_ptrs [N_RECIPIENTS ];
241+             for  (i  =  0 ; i  <  N_RECIPIENTS ; i ++ ) {
242+                 dleq_data_ptrs [i ] =  & dleq_data [i ];
243+             }
244+             for  (i  =  0 ; i  <  N_INPUTS ; i ++ ) {
245+                 tx_input_ptrs [i ] =  & tx_inputs [i ];
246+             }
247+             ret  =  secp256k1_silentpayments_recipient_public_data_create (ctx , & public_data , smallest_outpoint ,
248+                                                                         tx_input_ptrs , N_INPUTS , NULL , 0 );
249+             assert (ret );
250+ 
251+             ret  =  secp256k1_silentpayments_sender_create_outputs_with_proof (ctx ,
252+                 generated_output_ptrs , dleq_data_ptrs , & n_dleq_size ,
253+                 recipient_ptrs , N_OUTPUTS ,
254+                 smallest_outpoint ,
255+                 sender_seckey_ptrs , N_INPUTS ,
256+                 NULL , 0 
257+             );
258+             assert (n_dleq_size  ==  N_RECIPIENTS );
259+             assert (ret );
260+             /* Ensure that outputs are generated correctly at the sender side by verifying the DLEQ proof */ 
261+             for  (i  =  0 ; i  <  N_RECIPIENTS ; i ++ ) {
262+                 /* Serialized form of proof can be sent from 1 sender side device to another sender side device. 
263+                  * ex: hardware wallet (which can do ECDH + proof calculation) to wallet application. */ 
264+                 unsigned char   ss_proof_index_bytes [33  +  64  +  4 ];
265+                 secp256k1_silentpayments_dleq_data  data ;
266+                 secp256k1_silentpayments_dleq_data_serialize (ss_proof_index_bytes , & dleq_data [i ]);
267+                 /* Parse the serialized proof on the second device. (ex: wallet application) */ 
268+                 secp256k1_silentpayments_dleq_data_parse (& data , ss_proof_index_bytes );
269+                 /* Proof verification can be done on the second device. */ 
270+                 ret  =  secp256k1_silentpayments_verify_proof (ctx , data .shared_secret , data .proof ,
271+                                                             & recipients [data .index ].scan_pubkey ,
272+                                                             & public_data );
273+                 assert (ret );
274+                 /* Store proof to send to different receivers (Bob, Carol) later. */ 
275+                 memcpy (dleq_proof [i ], ss_proof_index_bytes  +  33 , 64 );
276+             }
277+         }
278+ 
229279        printf ("Alice created the following outputs for Bob and Carol: \n" );
230280        for  (i  =  0 ; i  <  N_OUTPUTS ; i ++ ) {
231281            printf ("    " );
@@ -400,6 +450,25 @@ int main(void) {
400450                );
401451                print_hex (xonly_print , sizeof (xonly_print ));
402452            }
453+             {
454+                 /* Optionally, Bob can use DLEQ proof to prove ownership of his address without revealing private keys 
455+                  * DLEQ proof verification needs proof, input pubkey sum, Bob's scan pubkey and shared secret as inputs. */ 
456+                 unsigned char   shared_secret [33 ];
457+                 secp256k1_pubkey  scan_pubkey ;
458+                 /* 1. Get Bob's scan pubkey */ 
459+                 ret  =  secp256k1_ec_pubkey_parse (ctx , & scan_pubkey , bob_address [0 ], 33 );
460+                 assert (ret );
461+                 /* 2. Compute input pubkey sum */ 
462+                 ret  =  secp256k1_silentpayments_recipient_public_data_parse (ctx , & public_data , light_client_data33 );
463+                 assert (ret );
464+                 /* 3. Bob computes shared secret */ 
465+                 ret  =  secp256k1_silentpayments_recipient_create_shared_secret (ctx , shared_secret , bob_scan_key ,
466+                                                                               & public_data );
467+                 assert (ret );
468+                 /* 4. Use proof we obtained from Alice for verification */ 
469+                 ret  &= secp256k1_silentpayments_verify_proof (ctx , shared_secret , dleq_proof [0 ], & scan_pubkey , & public_data );
470+                 assert (ret );
471+             }
403472        }
404473        {
405474            /*** Scanning as a light client (Carol) *** 
@@ -494,6 +563,18 @@ int main(void) {
494563                printf ("    " );
495564                print_hex (ser_found_outputs [i ], 32 );
496565            }
566+             {
567+                 /* Optionally, Carol can use DLEQ proof to prove ownership of her address without revealing private keys 
568+                  * DLEQ proof verification needs proof, input pubkey sum, Carol's scan pubkey and shared secret as inputs. */ 
569+                 /* 1. Get Carol's scan pubkey */ 
570+                 secp256k1_pubkey  scan_pubkey ;
571+                 ret  =  secp256k1_ec_pubkey_parse (ctx , & scan_pubkey , carol_address [0 ], 33 );
572+                 assert (ret );
573+                 /* 2. Input pubkey sum and shared secret already computed at this point, so verify_proof directly */ 
574+                 /* 3. Use proof we obtained from Alice for verification */ 
575+                 ret  &= secp256k1_silentpayments_verify_proof (ctx , shared_secret , dleq_proof [1 ], & scan_pubkey , & public_data );
576+                 assert (ret );
577+             }
497578        }
498579    }
499580
0 commit comments