Skip to content

Commit 7e11e76

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 3321771 commit 7e11e76

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

include/secp256k1_silentpayments.h

+52
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,58 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipien
272272
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
273273
SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
274274

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

src/modules/silentpayments/main_impl.h

+19
Original file line numberDiff line numberDiff line change
@@ -556,4 +556,23 @@ int secp256k1_silentpayments_recipient_scan_outputs(
556556
return 1;
557557
}
558558

559+
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) {
560+
secp256k1_pubkey A_tweaked;
561+
/* Sanity check inputs */
562+
ARG_CHECK(shared_secret33 != NULL);
563+
ARG_CHECK(recipient_scan_key != NULL);
564+
ARG_CHECK(public_data != NULL);
565+
ARG_CHECK(public_data->data[0] == 1);
566+
if (!secp256k1_silentpayments_recipient_public_data_load(ctx, &A_tweaked, NULL, public_data)) {
567+
return 0;
568+
}
569+
return secp256k1_silentpayments_create_shared_secret(ctx, shared_secret33, recipient_scan_key, &A_tweaked, NULL);
570+
}
571+
572+
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 *recipient_spend_pubkey, unsigned int k)
573+
{
574+
return secp256k1_silentpayments_create_output_pubkey(ctx, P_output_xonly, shared_secret33, recipient_spend_pubkey, k);
575+
}
576+
577+
559578
#endif

0 commit comments

Comments
 (0)