Skip to content

Commit 877a231

Browse files
committed
silentpayments: add recipient light client support
Expose a shared secret routine in the public API and a output_pubkey creation routine. These are simple wrappers around the same functions the module is using under the hood. They are exposed for the light client as the minimal set of operations they need to do scanning without access to the transaction outputs. This means the light client will need to manage their own scanning state, so wherever possible it is preferrable to use the `_recipient_scan_ouputs` function.
1 parent a0ee789 commit 877a231

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

include/secp256k1_silentpayments.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,58 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipien
273273
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
274274
SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
275275

276+
/** Create Silent Payment shared secret.
277+
*
278+
* Given the public input data (A_tweaked = input_hash * A_sum), calculate the shared secret using ECDH:
279+
*
280+
* shared_secret = b_scan * A_tweaked [Recipient, Light client scenario]
281+
*
282+
* The resulting shared secret is needed as input for creating silent payments
283+
* outputs belonging to the same recipient scan public key.
284+
*
285+
* Returns: 1 if shared secret creation was successful. 0 if an error occured.
286+
* Args: ctx: pointer to a context object
287+
* Out: shared_secret33: pointer to the resulting 33-byte shared secret
288+
* In: recipient_scan_key: pointer to the recipient's scan key
289+
* public_data: pointer to the input public key sum, tweaked with the input_hash
290+
* (see `_recipient_compute_public_data`)
291+
*/
292+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_create_shared_secret(
293+
const secp256k1_context *ctx,
294+
unsigned char *shared_secret33,
295+
const unsigned char *recipient_scan_key,
296+
const secp256k1_silentpayments_public_data *public_data
297+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
298+
299+
/** Create Silent Payment output public key.
300+
*
301+
* Given a shared_secret, a public key B_spend, and an output counter k,
302+
* calculate the corresponding output public key:
303+
*
304+
* P_output_xonly = B_spend + hash(shared_secret || ser_32(k)) * G
305+
*
306+
* This function is used by the recipient when scanning for outputs without access to the
307+
* transaction outputs (e.g. using BIP158 block filters).
308+
* When scanning with this function, it is the scanners responsibility to determine if the generated
309+
* output exists in a block before proceeding to the next value of `k`.
310+
*
311+
* Returns: 1 if output creation was successful. 0 if an error occured.
312+
* Args: ctx: pointer to a context object
313+
* Out: P_output_xonly: pointer to the resulting output x-only pubkey
314+
* In: shared_secret33: shared secret, derived from either sender's
315+
* or receiver's perspective with routines from above
316+
* receiver_spend_pubkey: pointer to the receiver's spend pubkey (labelled or unlabelled)
317+
* k: output counter (initially set to 0, must be incremented for each
318+
* additional output created or after each output found when scanning)
319+
*/
320+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_create_output_pubkey(
321+
const secp256k1_context *ctx,
322+
secp256k1_xonly_pubkey *P_output_xonly,
323+
const unsigned char *shared_secret33,
324+
const secp256k1_pubkey *receiver_spend_pubkey,
325+
unsigned int k
326+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
327+
276328
#ifdef __cplusplus
277329
}
278330
#endif

src/modules/silentpayments/main_impl.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,4 +566,23 @@ int secp256k1_silentpayments_recipient_scan_outputs(
566566
return 1;
567567
}
568568

569+
int secp256k1_silentpayments_recipient_create_shared_secret(const secp256k1_context *ctx, unsigned char *shared_secret33, const unsigned char *recipient_scan_key, const secp256k1_silentpayments_public_data *public_data) {
570+
secp256k1_pubkey A_tweaked;
571+
/* Sanity check inputs */
572+
ARG_CHECK(shared_secret33 != NULL);
573+
ARG_CHECK(recipient_scan_key != NULL);
574+
ARG_CHECK(public_data != NULL);
575+
ARG_CHECK(public_data->data[0] == 1);
576+
if (!secp256k1_silentpayments_recipient_public_data_load(ctx, &A_tweaked, NULL, public_data)) {
577+
return 0;
578+
}
579+
return secp256k1_silentpayments_create_shared_secret(ctx, shared_secret33, recipient_scan_key, &A_tweaked, NULL);
580+
}
581+
582+
int secp256k1_silentpayments_recipient_create_output_pubkey(const secp256k1_context *ctx, secp256k1_xonly_pubkey *P_output_xonly, const unsigned char *shared_secret33, const secp256k1_pubkey *receiver_spend_pubkey, unsigned int k)
583+
{
584+
return secp256k1_silentpayments_create_output_pubkey(ctx, P_output_xonly, shared_secret33, receiver_spend_pubkey, k);
585+
}
586+
587+
569588
#endif

0 commit comments

Comments
 (0)