Skip to content

Commit 6eeeb17

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 labelled addresses and b) to populate a labels cache when scanning. Add function for creating a labelled 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 labelled silent payment address. Add tests for the label API.
1 parent f375161 commit 6eeeb17

File tree

3 files changed

+148
-0
lines changed

3 files changed

+148
-0
lines changed

include/secp256k1_silentpayments.h

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

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

src/modules/silentpayments/main_impl.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,4 +285,74 @@ int secp256k1_silentpayments_sender_create_outputs(
285285
return 1;
286286
}
287287

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

src/modules/silentpayments/tests_impl.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,36 @@ static void test_send_api(void) {
234234
*/
235235
}
236236

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

242269
#endif

0 commit comments

Comments
 (0)