Skip to content

Commit 22e4b40

Browse files
committed
add secp256k1_silentpayments_sender_create_outputs_with_proof
- add new API which returns DLEQ proofs along with outputs for recipients - the existing API secp256k1_silentpayments_sender_create_outputs simply calls secp256k1_silentpayments_sender_create_outputs_with_proof internally.
1 parent fae6014 commit 22e4b40

File tree

2 files changed

+73
-5
lines changed

2 files changed

+73
-5
lines changed

include/secp256k1_silentpayments.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,36 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_sender_c
120120
size_t n_plain_seckeys
121121
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
122122

123+
/** Create Silent Payment outputs and associated DLEQ proof(s) for recipient(s).
124+
*
125+
* Similar to secp256k1_silentpayments_sender_create_outputs,
126+
* but also returns information about associated DLEQ proof.
127+
*
128+
* Returns: 1 if creation of outputs was successful. 0 if an error occurred.
129+
* Args: ctx: pointer to a context object
130+
* Out: generated_outputs: pointer to an array of pointers to xonly pubkeys,
131+
* one per recipient.
132+
* The order of outputs here matches the original
133+
* ordering of the recipients array.
134+
* dleq_data: pointer to an array of pointers to secp256k1_silentpayments_dleq_data,
135+
* one per unique recipient.
136+
* n_dleq_size: number of DLEQ proofs generated (equivalent to number of unique recipients)
137+
* In: See input parameters in secp256k1_silentpayments_sender_create_outputs
138+
*/
139+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_sender_create_outputs_with_proof(
140+
const secp256k1_context *ctx,
141+
secp256k1_xonly_pubkey **generated_outputs,
142+
secp256k1_silentpayments_dleq_data **dleq_data,
143+
size_t *n_dleq_size,
144+
const secp256k1_silentpayments_recipient **recipients,
145+
size_t n_recipients,
146+
const unsigned char *outpoint_smallest36,
147+
const secp256k1_keypair * const *taproot_seckeys,
148+
size_t n_taproot_seckeys,
149+
const unsigned char * const *plain_seckeys,
150+
size_t n_plain_seckeys
151+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7);
152+
123153
/** Create Silent Payment label tweak and label.
124154
*
125155
* Given a recipient's scan key b_scan and a label integer m, calculate the

src/modules/silentpayments/main_impl.h

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,11 @@ static int secp256k1_silentpayments_create_output_pubkey(const secp256k1_context
175175
return ret;
176176
}
177177

178-
int secp256k1_silentpayments_sender_create_outputs(
178+
int secp256k1_silentpayments_sender_create_outputs_with_proof(
179179
const secp256k1_context *ctx,
180180
secp256k1_xonly_pubkey **generated_outputs,
181+
secp256k1_silentpayments_dleq_data **dleq_data,
182+
size_t *n_dleq_size,
181183
const secp256k1_silentpayments_recipient **recipients,
182184
size_t n_recipients,
183185
const unsigned char *outpoint_smallest36,
@@ -191,10 +193,14 @@ int secp256k1_silentpayments_sender_create_outputs(
191193
secp256k1_ge A_sum_ge;
192194
secp256k1_gej A_sum_gej;
193195
unsigned char input_hash[32];
194-
unsigned char shared_secret[33];
196+
secp256k1_ge shared_secret;
197+
unsigned char shared_secret33[33];
198+
unsigned char proof64[64];
195199
secp256k1_silentpayments_recipient last_recipient;
196200
int overflow = 0;
197201
int ret = 1;
202+
int j = 0;
203+
size_t len;
198204

199205
/* Sanity check inputs. */
200206
VERIFY_CHECK(ctx != NULL);
@@ -264,13 +270,30 @@ int secp256k1_silentpayments_sender_create_outputs(
264270
secp256k1_ge pk;
265271
ret &= secp256k1_pubkey_load(ctx, &pk, &recipients[i]->scan_pubkey);
266272
if (!ret) break;
267-
secp256k1_silentpayments_create_shared_secret(ctx, shared_secret, &a_sum_scalar, &pk);
273+
/* Compute shared_secret = tweaked_secret_component * Public_component */
274+
secp256k1_silentpayments_create_shared_secret_with_proof(ctx, proof64, &shared_secret, &a_sum_scalar, &pk);
275+
if (dleq_data != NULL) {
276+
secp256k1_pubkey pubkey;
277+
size_t pklen = 33;
278+
secp256k1_pubkey_save(&pubkey, &shared_secret);
279+
secp256k1_ec_pubkey_serialize(ctx, dleq_data[j]->shared_secret, &pklen, &pubkey, SECP256K1_EC_COMPRESSED);
280+
memcpy(dleq_data[j]->proof, proof64, 64);
281+
dleq_data[j]->index = recipients[i]->index;
282+
}
283+
/* This can only fail if the shared secret is the point at infinity, which should be
284+
* impossible at this point, considering we have already validated the public key and
285+
* the secret key being used
286+
*/
287+
ret = secp256k1_eckey_pubkey_serialize(&shared_secret, shared_secret33, &len, 1);
288+
VERIFY_CHECK(ret && len == 33);
268289
k = 0;
290+
j++;
269291
}
270-
ret &= secp256k1_silentpayments_create_output_pubkey(ctx, generated_outputs[recipients[i]->index], shared_secret, &recipients[i]->spend_pubkey, k);
292+
ret &= secp256k1_silentpayments_create_output_pubkey(ctx, generated_outputs[recipients[i]->index], shared_secret33, &recipients[i]->spend_pubkey, k);
271293
k++;
272294
last_recipient = *recipients[i];
273295
}
296+
*n_dleq_size = j;
274297
/* Explicitly clear variables containing secret data */
275298
secp256k1_scalar_clear(&addend);
276299
secp256k1_scalar_clear(&a_sum_scalar);
@@ -279,10 +302,25 @@ int secp256k1_silentpayments_sender_create_outputs(
279302
* could result in a third party being able to identify the transaction as a silent payments transaction
280303
* and potentially link the transaction back to a silent payment address
281304
*/
282-
memset(&shared_secret, 0, sizeof(shared_secret));
305+
memset(&shared_secret33, 0, sizeof(shared_secret33));
283306
return ret;
284307
}
285308

309+
int secp256k1_silentpayments_sender_create_outputs(
310+
const secp256k1_context *ctx,
311+
secp256k1_xonly_pubkey **generated_outputs,
312+
const secp256k1_silentpayments_recipient **recipients,
313+
size_t n_recipients,
314+
const unsigned char *outpoint_smallest36,
315+
const secp256k1_keypair * const *taproot_seckeys,
316+
size_t n_taproot_seckeys,
317+
const unsigned char * const *plain_seckeys,
318+
size_t n_plain_seckeys
319+
) {
320+
size_t n_dleq_size;
321+
return secp256k1_silentpayments_sender_create_outputs_with_proof(ctx, generated_outputs, NULL, &n_dleq_size, recipients, n_recipients, outpoint_smallest36, taproot_seckeys, n_taproot_seckeys, plain_seckeys, n_plain_seckeys);
322+
}
323+
286324
/** Set hash state to the BIP340 tagged hash midstate for "BIP0352/Label". */
287325
static void secp256k1_silentpayments_sha256_init_label(secp256k1_sha256* hash) {
288326
secp256k1_sha256_initialize(hash);

0 commit comments

Comments
 (0)