|  | 
| 18 | 18 | 
 | 
| 19 | 19 | #define N_INPUTS  2 | 
| 20 | 20 | #define N_OUTPUTS 3 | 
|  | 21 | +#define N_RECIPIENTS 2 | 
| 21 | 22 | 
 | 
| 22 | 23 | /* Static data for Bob and Carol's silent payment addresses */ | 
| 23 | 24 | static unsigned char smallest_outpoint[36] = { | 
| @@ -127,6 +128,7 @@ int main(void) { | 
| 127 | 128 |     secp256k1_xonly_pubkey *tx_output_ptrs[N_OUTPUTS]; | 
| 128 | 129 |     int ret; | 
| 129 | 130 |     size_t i; | 
|  | 131 | +    unsigned char dleq_proof[N_RECIPIENTS][64]; | 
| 130 | 132 | 
 | 
| 131 | 133 |     /* Before we can call actual API functions, we need to create a "context" */ | 
| 132 | 134 |     secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); | 
| @@ -229,18 +231,66 @@ int main(void) { | 
| 229 | 231 |         for (i = 0; i < N_OUTPUTS; i++) { | 
| 230 | 232 |             tx_output_ptrs[i] = &tx_outputs[i]; | 
| 231 | 233 |         } | 
| 232 |  | -        ret = secp256k1_silentpayments_sender_create_outputs(ctx, | 
| 233 |  | -            tx_output_ptrs, | 
| 234 |  | -            recipient_ptrs, N_OUTPUTS, | 
| 235 |  | -            smallest_outpoint, | 
| 236 |  | -            sender_keypair_ptrs, N_INPUTS, | 
| 237 |  | -            NULL, 0 | 
| 238 |  | -        ); | 
| 239 |  | -        if (!ret) { | 
| 240 |  | -            printf("Something went wrong, try again with different inputs.\n"); | 
| 241 |  | -            return EXIT_FAILURE; | 
|  | 234 | + | 
|  | 235 | +        /* Sender can perform 1 of the following options: | 
|  | 236 | +         * Option 1: generate outputs without DLEQ proofs | 
|  | 237 | +            ret = secp256k1_silentpayments_sender_create_outputs(ctx, | 
|  | 238 | +                tx_output_ptrs, | 
|  | 239 | +                recipient_ptrs, N_OUTPUTS, | 
|  | 240 | +                smallest_outpoint, | 
|  | 241 | +                sender_keypair_ptrs, N_INPUTS, | 
|  | 242 | +                NULL, 0 | 
|  | 243 | +            ); | 
|  | 244 | +            if (!ret) { | 
|  | 245 | +                printf("Something went wrong, try again with different inputs.\n"); | 
|  | 246 | +                return EXIT_FAILURE; | 
|  | 247 | +            } | 
|  | 248 | +         */ | 
|  | 249 | +        { | 
|  | 250 | +            /* Option 2: generate outputs with DLEQ proofs*/ | 
|  | 251 | +            secp256k1_silentpayments_prevouts_summary prevouts_summary; | 
|  | 252 | +            size_t n_dleq_size; | 
|  | 253 | +            secp256k1_silentpayments_dleq_data dleq_data[N_RECIPIENTS]; | 
|  | 254 | +            secp256k1_silentpayments_dleq_data *dleq_data_ptrs[N_RECIPIENTS]; | 
|  | 255 | +            for (i = 0; i < N_RECIPIENTS; i++) { | 
|  | 256 | +                dleq_data_ptrs[i] = &dleq_data[i]; | 
|  | 257 | +            } | 
|  | 258 | +            for (i = 0; i < N_INPUTS; i++) { | 
|  | 259 | +                tx_input_ptrs[i] = &tx_inputs[i]; | 
|  | 260 | +            } | 
|  | 261 | +            ret = secp256k1_silentpayments_recipient_prevouts_summary_create(ctx, &prevouts_summary, smallest_outpoint, | 
|  | 262 | +                                                                        tx_input_ptrs, N_INPUTS, NULL, 0); | 
|  | 263 | +            assert(ret); | 
|  | 264 | + | 
|  | 265 | +            ret = secp256k1_silentpayments_sender_create_outputs_with_proof(ctx, | 
|  | 266 | +                tx_output_ptrs, dleq_data_ptrs, &n_dleq_size, | 
|  | 267 | +                recipient_ptrs, N_OUTPUTS, | 
|  | 268 | +                smallest_outpoint, | 
|  | 269 | +                sender_keypair_ptrs, N_INPUTS, | 
|  | 270 | +                NULL, 0 | 
|  | 271 | +            ); | 
|  | 272 | +            assert(n_dleq_size == N_RECIPIENTS); | 
|  | 273 | +            assert(ret); | 
|  | 274 | +            /* Ensure that outputs are generated correctly at the sender side by verifying the DLEQ proof */ | 
|  | 275 | +            for (i = 0; i < N_RECIPIENTS; i++) { | 
|  | 276 | +                /* Serialized form of proof can be sent from 1 sender side device to another sender side device. | 
|  | 277 | +                 * ex: hardware wallet (which can do ECDH + proof calculation) to wallet application. */ | 
|  | 278 | +                unsigned char ss_proof_index_bytes[33 + 64 + 4]; | 
|  | 279 | +                secp256k1_silentpayments_dleq_data data; | 
|  | 280 | +                secp256k1_silentpayments_dleq_data_serialize(ss_proof_index_bytes, &dleq_data[i]); | 
|  | 281 | +                /* Parse the serialized proof on the second device. (ex: wallet application) */ | 
|  | 282 | +                secp256k1_silentpayments_dleq_data_parse(&data, ss_proof_index_bytes); | 
|  | 283 | +                /* Proof verification can be done on the second device. */ | 
|  | 284 | +                ret = secp256k1_silentpayments_verify_proof(ctx, data.shared_secret, data.proof, | 
|  | 285 | +                                                            &recipients[data.index].scan_pubkey, | 
|  | 286 | +                                                            &prevouts_summary); | 
|  | 287 | +                assert(ret); | 
|  | 288 | +                /* Store proof to send to different receivers (Bob, Carol) later. */ | 
|  | 289 | +                memcpy(dleq_proof[i], ss_proof_index_bytes + 33, 64); | 
|  | 290 | +            } | 
| 242 | 291 |         } | 
| 243 |  | -        printf("Alice created the following outputs for Bob and Carol:\n"); | 
|  | 292 | + | 
|  | 293 | +        printf("Alice created the following outputs for Bob and Carol: \n"); | 
| 244 | 294 |         for (i = 0; i < N_OUTPUTS; i++) { | 
| 245 | 295 |             printf("    "); | 
| 246 | 296 |             ret = secp256k1_xonly_pubkey_serialize(ctx, | 
| @@ -481,6 +531,25 @@ int main(void) { | 
| 481 | 531 |             } else { | 
| 482 | 532 |                 printf("Bob did not find any outputs in this transaction.\n"); | 
| 483 | 533 |             } | 
|  | 534 | +            { | 
|  | 535 | +                /* Optionally, Bob can use DLEQ proof to prove ownership of his address without revealing private keys | 
|  | 536 | +                 * DLEQ proof verification needs proof, input pubkey sum, Bob's scan pubkey and shared secret as inputs. */ | 
|  | 537 | +                unsigned char shared_secret[33]; | 
|  | 538 | +                secp256k1_pubkey scan_pubkey; | 
|  | 539 | +                /* 1. Get Bob's scan pubkey */ | 
|  | 540 | +                ret = secp256k1_ec_pubkey_parse(ctx, &scan_pubkey, bob_address[0], 33); | 
|  | 541 | +                assert(ret); | 
|  | 542 | +                /* 2. Compute input pubkey sum */ | 
|  | 543 | +                ret = secp256k1_silentpayments_recipient_prevouts_summary_serialize(ctx, light_client_data33, &prevouts_summary); | 
|  | 544 | +                assert(ret); | 
|  | 545 | +                /* 3. Bob computes shared secret */ | 
|  | 546 | +                ret = secp256k1_silentpayments_recipient_create_shared_secret(ctx, shared_secret, bob_scan_key, | 
|  | 547 | +                                                                              &prevouts_summary); | 
|  | 548 | +                assert(ret); | 
|  | 549 | +                /* 4. Use proof we obtained from Alice for verification */ | 
|  | 550 | +                ret &= secp256k1_silentpayments_verify_proof(ctx, shared_secret, dleq_proof[0], &scan_pubkey, &prevouts_summary); | 
|  | 551 | +                assert(ret); | 
|  | 552 | +            } | 
| 484 | 553 |         } | 
| 485 | 554 |         { | 
| 486 | 555 |             /*** Scanning as a light client (Carol) *** | 
| @@ -608,6 +677,18 @@ int main(void) { | 
| 608 | 677 |             } else { | 
| 609 | 678 |                 printf("Carol did not find any outputs in this transaction.\n"); | 
| 610 | 679 |             } | 
|  | 680 | +            { | 
|  | 681 | +                /* Optionally, Carol can use DLEQ proof to prove ownership of her address without revealing private keys | 
|  | 682 | +                 * DLEQ proof verification needs proof, input pubkey sum, Carol's scan pubkey and shared secret as inputs. */ | 
|  | 683 | +                /* 1. Get Carol's scan pubkey */ | 
|  | 684 | +                secp256k1_pubkey scan_pubkey; | 
|  | 685 | +                ret = secp256k1_ec_pubkey_parse(ctx, &scan_pubkey, carol_address[0], 33); | 
|  | 686 | +                assert(ret); | 
|  | 687 | +                /* 2. Input pubkey sum and shared secret already computed at this point, so verify_proof directly */ | 
|  | 688 | +                /* 3. Use proof we obtained from Alice for verification */ | 
|  | 689 | +                ret &= secp256k1_silentpayments_verify_proof(ctx, shared_secret, dleq_proof[1], &scan_pubkey, &prevouts_summary); | 
|  | 690 | +                assert(ret); | 
|  | 691 | +            } | 
| 611 | 692 |         } | 
| 612 | 693 |     } | 
| 613 | 694 | 
 | 
|  | 
0 commit comments