From 9039d6b673fee6d5f98b1cd79a92bd6241b19a6a Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Wed, 20 Dec 2023 23:01:58 +0100 Subject: [PATCH] silentpayments: implement output spending privkey creation (for receiver) --- include/secp256k1_silentpayments.h | 29 ++++++++++++++++++++++++ src/modules/silentpayments/main_impl.h | 31 ++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/include/secp256k1_silentpayments.h b/include/secp256k1_silentpayments.h index 7f02ec111e..8b3c0c6a35 100644 --- a/include/secp256k1_silentpayments.h +++ b/include/secp256k1_silentpayments.h @@ -221,6 +221,35 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_create_o const unsigned char *label_tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +/** Create Silent Payment output private key (for spending receiver's funds). + * + * Given a shared_secret, a recipient's spend private key b_spend, an output + * counter k, and an optional label_tweak, calculate the corresponding + * output private key d: + * + * b_m = b_spend + label_tweak + * (if no label tweak is used, them b_m = b_spend) + * d = (b_m + hash(shared_secret || ser_32(k))) mod n + * + * Returns: 1 if private key creation was successful. 0 if an error occured. + * Args: ctx: pointer to a context object + * Out: output_seckey: pointer to the resulting spending private key + * In: shared_secret33: shared secret, derived from either sender's + * or receiver's perspective with routines from above + * receiver_spend_seckey: pointer to the receiver's spend private key + * k: output counter (usually set to 0, should be increased for + * every additional output to the same recipient) + * label_tweak32: an optional 32-byte label tweak (NULL if no label is used) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_create_output_seckey( + const secp256k1_context *ctx, + unsigned char *output_seckey, + const unsigned char *shared_secret33, + const unsigned char *receiver_spend_seckey, + unsigned int k, + const unsigned char *label_tweak32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + #ifdef __cplusplus } #endif diff --git a/src/modules/silentpayments/main_impl.h b/src/modules/silentpayments/main_impl.h index 2859ed36ef..abbc94c203 100644 --- a/src/modules/silentpayments/main_impl.h +++ b/src/modules/silentpayments/main_impl.h @@ -320,4 +320,35 @@ int secp256k1_silentpayments_create_output_pubkey(const secp256k1_context *ctx, return 1; } +int secp256k1_silentpayments_create_output_seckey(const secp256k1_context *ctx, unsigned char *output_seckey, const unsigned char *shared_secret33, const unsigned char *receiver_spend_seckey, unsigned int k, const unsigned char *label_tweak32) { + secp256k1_scalar t_k_scalar; + secp256k1_scalar final_seckey; + int ret; + + /* Sanity check inputs */ + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output_seckey != NULL); + memset(output_seckey, 0, 32); + ARG_CHECK(shared_secret33 != NULL); + ARG_CHECK(receiver_spend_seckey != NULL); + + /* Apply label tweak if provided */ + ret = secp256k1_scalar_set_b32_seckey(&final_seckey, receiver_spend_seckey); + VERIFY_CHECK(ret); + (void)ret; + if (label_tweak32 != NULL) { + secp256k1_scalar tweak_scalar; + secp256k1_scalar_set_b32(&tweak_scalar, label_tweak32, NULL); + secp256k1_eckey_privkey_tweak_add(&final_seckey, &tweak_scalar); + } + + /* Compute and return d = (b_m + t_k) mod n */ + secp256k1_silentpayments_create_t_k(&t_k_scalar, shared_secret33, k); + secp256k1_eckey_privkey_tweak_add(&final_seckey, &t_k_scalar); + secp256k1_scalar_get_b32(output_seckey, &final_seckey); + secp256k1_scalar_clear(&final_seckey); + + return 1; +} + #endif