|
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