Skip to content

Commit c5d32d7

Browse files
committed
silentpayments: implement output pubkey creation (both sender and receiver)
1 parent ac0f2b3 commit c5d32d7

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

include/secp256k1_silentpayments.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,35 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_create_a
190190
const unsigned char *label_tweak32
191191
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
192192

193+
/** Create Silent Payment output public key (both for sender and receiver).
194+
*
195+
* Given a shared_secret, a recipient's spend public key B_spend, an output
196+
* counter k, and an optional label_tweak, calculate the corresponding
197+
* output public key:
198+
*
199+
* B_m = B_spend + label_tweak * G
200+
* (if no label tweak is used, then B_m = B_spend)
201+
* P_output = B_m + hash(shared_secret || ser_32(k)) * G
202+
*
203+
* Returns: 1 if outputs creation was successful. 0 if an error occured.
204+
* Args: ctx: pointer to a context object
205+
* Out: output_xonly_pubkey: pointer to the resulting output x-only pubkey
206+
* In: shared_secret33: shared secret, derived from either sender's
207+
* or receiver's perspective with routines from above
208+
* receiver_spend_pubkey: pointer to the receiver's spend pubkey
209+
* k: output counter (usually set to 0, should be increased for
210+
* every additional output to the same recipient)
211+
* label_tweak32: an optional 32-byte label tweak (NULL if no label is used)
212+
*/
213+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_create_output_pubkey(
214+
const secp256k1_context *ctx,
215+
secp256k1_xonly_pubkey *output_xonly_pubkey,
216+
const unsigned char *shared_secret33,
217+
const secp256k1_pubkey *receiver_spend_pubkey,
218+
unsigned int k,
219+
const unsigned char *label_tweak32
220+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
221+
193222
#ifdef __cplusplus
194223
}
195224
#endif

src/modules/silentpayments/main_impl.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "../../../include/secp256k1_ecdh.h"
1111
#include "../../../include/secp256k1_extrakeys.h"
1212
#include "../../../include/secp256k1_silentpayments.h"
13+
#include "../../hash.h"
1314

1415
/** Set hash state to the BIP340 tagged hash midstate for "BIP0352/Inputs". */
1516
static void secp256k1_silentpayments_sha256_init_inputs(secp256k1_sha256* hash) {
@@ -278,4 +279,60 @@ int secp256k1_silentpayments_create_address_spend_pubkey(const secp256k1_context
278279
return 1;
279280
}
280281

282+
/** Set hash state to the BIP340 tagged hash midstate for "BIP0352/SharedSecret". */
283+
static void secp256k1_silentpayments_sha256_init_sharedsecret(secp256k1_sha256* hash) {
284+
secp256k1_sha256_initialize(hash);
285+
hash->s[0] = 0x88831537ul;
286+
hash->s[1] = 0x5127079bul;
287+
hash->s[2] = 0x69c2137bul;
288+
hash->s[3] = 0xab0303e6ul;
289+
hash->s[4] = 0x98fa21faul;
290+
hash->s[5] = 0x4a888523ul;
291+
hash->s[6] = 0xbd99daabul;
292+
hash->s[7] = 0xf25e5e0aul;
293+
294+
hash->bytes = 64;
295+
}
296+
297+
static void secp256k1_silentpayments_create_t_k(secp256k1_scalar *t_k_scalar, const unsigned char *shared_secret33, unsigned int k) {
298+
secp256k1_sha256 hash;
299+
unsigned char hash_ser[32];
300+
unsigned char k_serialized[4];
301+
302+
/* Compute t_k = hash(shared_secret || ser_32(k)) [sha256 with tag "BIP0352/SharedSecret"] */
303+
secp256k1_silentpayments_sha256_init_sharedsecret(&hash);
304+
secp256k1_sha256_write(&hash, shared_secret33, 33);
305+
secp256k1_write_be32(k_serialized, k);
306+
secp256k1_sha256_write(&hash, k_serialized, sizeof(k_serialized));
307+
secp256k1_sha256_finalize(&hash, hash_ser);
308+
secp256k1_scalar_set_b32(t_k_scalar, hash_ser, NULL);
309+
}
310+
311+
int secp256k1_silentpayments_create_output_pubkey(const secp256k1_context *ctx, secp256k1_xonly_pubkey *output_xonly_pubkey, const unsigned char *shared_secret33, const secp256k1_pubkey *receiver_spend_pubkey, unsigned int k, const unsigned char *label_tweak32) {
312+
secp256k1_ge P_output;
313+
secp256k1_scalar t_k_scalar;
314+
315+
/* Sanity check inputs */
316+
VERIFY_CHECK(ctx != NULL);
317+
ARG_CHECK(output_xonly_pubkey != NULL);
318+
ARG_CHECK(receiver_spend_pubkey != NULL);
319+
320+
/* Apply label tweak if provided: B_m = B_spend + label_tweak * G */
321+
secp256k1_pubkey_load(ctx, &P_output, receiver_spend_pubkey);
322+
if (label_tweak32 != NULL) {
323+
if (!secp256k1_ec_pubkey_tweak_add_helper(&P_output, label_tweak32)) {
324+
return 0;
325+
}
326+
}
327+
328+
/* Calculate and return P_output = B_m + t_k * G */
329+
secp256k1_silentpayments_create_t_k(&t_k_scalar, shared_secret33, k);
330+
if (!secp256k1_eckey_pubkey_tweak_add(&P_output, &t_k_scalar)) {
331+
return 0;
332+
}
333+
secp256k1_xonly_pubkey_save(output_xonly_pubkey, &P_output);
334+
335+
return 1;
336+
}
337+
281338
#endif

0 commit comments

Comments
 (0)