Skip to content

Commit ed161e1

Browse files
theStackjosibake
authored andcommitted
silentpayments: recipient label support
Add function for creating a label tweak. This requires a tagged hash function for labels. This function is used by the receiver for creating labels to be used for a) creating labeled addresses and b) to populate a labels cache when scanning. Add function for creating a labeled spend pubkey. This involves taking a label tweak, turning it into a public key and adding it to the spend public key. This function is used by the receiver to create a labeled silent payment address. Add tests for the label API.
1 parent 42c3a35 commit ed161e1

File tree

3 files changed

+147
-0
lines changed

3 files changed

+147
-0
lines changed

include/secp256k1_silentpayments.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,57 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_sender_c
113113
size_t n_plain_seckeys
114114
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
115115

116+
/** Create Silent Payment label tweak and label.
117+
*
118+
* Given a recipient's 32 byte scan key b_scan and a label integer m, calculate the
119+
* corresponding label tweak and label:
120+
*
121+
* label_tweak = hash(b_scan || m)
122+
* label = label_tweak * G
123+
*
124+
* Returns: 1 if label tweak and label creation was successful.
125+
* 0 if an error occurred.
126+
* Args: ctx: pointer to a context object
127+
* Out: label: pointer to the resulting label public key
128+
* label_tweak32: pointer to the 32 byte label tweak
129+
* In: recipient_scan_key32: pointer to the recipient's 32 byte scan key
130+
* m: label integer (0 is used for change outputs)
131+
*/
132+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_create_label(
133+
const secp256k1_context *ctx,
134+
secp256k1_pubkey *label,
135+
unsigned char *label_tweak32,
136+
const unsigned char *recipient_scan_key32,
137+
uint32_t m
138+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
139+
140+
/** Create Silent Payment labeled spend public key.
141+
*
142+
* Given a recipient's spend public key B_spend and a label, calculate the
143+
* corresponding labeled spend public key:
144+
*
145+
* B_m = B_spend + label
146+
*
147+
* The result is used by the recipient to create a Silent Payment address,
148+
* consisting of the serialized and concatenated scan public key and
149+
* (labeled) spend public key each.
150+
*
151+
* Returns: 1 if labeled spend public key creation was successful.
152+
* 0 if an error occurred.
153+
* Args: ctx: pointer to a context object
154+
* Out: labeled_spend_pubkey: pointer to the resulting labeled spend
155+
* public key
156+
* In: recipient_spend_pubkey: pointer to the recipient's spend pubkey
157+
* label: pointer to the the recipient's label public
158+
* key
159+
*/
160+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_recipient_create_labeled_spend_pubkey(
161+
const secp256k1_context *ctx,
162+
secp256k1_pubkey *labeled_spend_pubkey,
163+
const secp256k1_pubkey *recipient_spend_pubkey,
164+
const secp256k1_pubkey *label
165+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
166+
116167
#ifdef __cplusplus
117168
}
118169
#endif

src/modules/silentpayments/main_impl.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,73 @@ int secp256k1_silentpayments_sender_create_outputs(
294294
return 1;
295295
}
296296

297+
/** Set hash state to the BIP340 tagged hash midstate for "BIP0352/Label". */
298+
static void secp256k1_silentpayments_sha256_init_label(secp256k1_sha256* hash) {
299+
secp256k1_sha256_initialize(hash);
300+
hash->s[0] = 0x26b95d63ul;
301+
hash->s[1] = 0x8bf1b740ul;
302+
hash->s[2] = 0x10a5986ful;
303+
hash->s[3] = 0x06a387a5ul;
304+
hash->s[4] = 0x2d1c1c30ul;
305+
hash->s[5] = 0xd035951aul;
306+
hash->s[6] = 0x2d7f0f96ul;
307+
hash->s[7] = 0x29e3e0dbul;
308+
309+
hash->bytes = 64;
310+
}
311+
312+
int secp256k1_silentpayments_recipient_create_label(const secp256k1_context *ctx, secp256k1_pubkey *label, unsigned char *label_tweak32, const unsigned char *recipient_scan_key, uint32_t m) {
313+
secp256k1_sha256 hash;
314+
unsigned char m_serialized[4];
315+
316+
/* Sanity check inputs. */
317+
VERIFY_CHECK(ctx != NULL);
318+
ARG_CHECK(label != NULL);
319+
ARG_CHECK(label_tweak32 != NULL);
320+
ARG_CHECK(recipient_scan_key != NULL);
321+
322+
/* Compute label_tweak = hash(ser_256(b_scan) || ser_32(m)) [sha256 with tag "BIP0352/Label"] */
323+
secp256k1_silentpayments_sha256_init_label(&hash);
324+
secp256k1_sha256_write(&hash, recipient_scan_key, 32);
325+
secp256k1_write_be32(m_serialized, m);
326+
secp256k1_sha256_write(&hash, m_serialized, sizeof(m_serialized));
327+
secp256k1_sha256_finalize(&hash, label_tweak32);
328+
329+
/* Compute label = label_tweak * G */
330+
return secp256k1_ec_pubkey_create(ctx, label, label_tweak32);
331+
}
332+
333+
int secp256k1_silentpayments_recipient_create_labeled_spend_pubkey(const secp256k1_context *ctx, secp256k1_pubkey *labeled_spend_pubkey, const secp256k1_pubkey *recipient_spend_pubkey, const secp256k1_pubkey *label) {
334+
secp256k1_ge B_m, label_addend;
335+
secp256k1_gej result_gej;
336+
secp256k1_ge result_ge;
337+
int ret;
338+
339+
/* Sanity check inputs. */
340+
VERIFY_CHECK(ctx != NULL);
341+
ARG_CHECK(labeled_spend_pubkey != NULL);
342+
ARG_CHECK(recipient_spend_pubkey != NULL);
343+
ARG_CHECK(label != NULL);
344+
345+
/* Calculate B_m = B_spend + label
346+
* If either the label or spend public key is an invalid public key,
347+
* return early
348+
*/
349+
ret = secp256k1_pubkey_load(ctx, &B_m, recipient_spend_pubkey);
350+
ret &= secp256k1_pubkey_load(ctx, &label_addend, label);
351+
if (!ret) {
352+
return ret;
353+
}
354+
secp256k1_gej_set_ge(&result_gej, &B_m);
355+
secp256k1_gej_add_ge_var(&result_gej, &result_gej, &label_addend, NULL);
356+
if (secp256k1_gej_is_infinity(&result_gej)) {
357+
return 0;
358+
}
359+
360+
secp256k1_ge_set_gej(&result_ge, &result_gej);
361+
secp256k1_pubkey_save(labeled_spend_pubkey, &result_ge);
362+
363+
return 1;
364+
}
365+
297366
#endif

src/modules/silentpayments/tests_impl.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,36 @@ static void test_send_api(void) {
239239
}
240240
}
241241

242+
static void test_label_api(void) {
243+
secp256k1_pubkey l, s, ls, e; /* label pk, spend pk, labelled spend pk, expected labelled spend pk */
244+
unsigned char lt[32]; /* label tweak */
245+
const unsigned char expected[33] = {
246+
0x03,0xdc,0x7f,0x09,0x9a,0xbe,0x95,0x7a,
247+
0x58,0x43,0xd2,0xb6,0xbb,0x35,0x79,0x61,
248+
0x5c,0x60,0x36,0xa4,0x9b,0x86,0xf4,0xbe,
249+
0x46,0x38,0x60,0x28,0xa8,0x1a,0x77,0xd4,0x91
250+
};
251+
252+
/* Create a label and labelled spend public key, verify we get the expected result */
253+
CHECK(secp256k1_ec_pubkey_parse(CTX, &s, BOB_ADDRESS[1], 33));
254+
CHECK(secp256k1_silentpayments_recipient_create_label(CTX, &l, lt, ALICE_SECKEY, 1));
255+
CHECK(secp256k1_silentpayments_recipient_create_labeled_spend_pubkey(CTX, &ls, &s, &l));
256+
CHECK(secp256k1_ec_pubkey_parse(CTX, &e, expected, 33));
257+
CHECK(secp256k1_ec_pubkey_cmp(CTX, &ls, &e) == 0);
258+
259+
/* Check null values are handled */
260+
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_recipient_create_label(CTX, NULL, lt, ALICE_SECKEY, 1));
261+
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_recipient_create_label(CTX, &l, NULL, ALICE_SECKEY, 1));
262+
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_recipient_create_label(CTX, &l, lt, NULL, 1));
263+
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_recipient_create_labeled_spend_pubkey(CTX, NULL, &s, &l));
264+
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_recipient_create_labeled_spend_pubkey(CTX, &ls, NULL, &l));
265+
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_recipient_create_labeled_spend_pubkey(CTX, &ls, &s, NULL));
266+
}
267+
242268
void run_silentpayments_tests(void) {
243269
test_recipient_sort();
244270
test_send_api();
271+
test_label_api();
245272
}
246273

247274
#endif

0 commit comments

Comments
 (0)