Skip to content

Commit 7229d49

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 9d6769f commit 7229d49

File tree

3 files changed

+148
-0
lines changed

3 files changed

+148
-0
lines changed

include/secp256k1_silentpayments.h

+51
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,57 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_sender_c
107107
size_t n_plain_seckeys
108108
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
109109

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

src/modules/silentpayments/main_impl.h

+70
Original file line numberDiff line numberDiff line change
@@ -252,4 +252,74 @@ int secp256k1_silentpayments_sender_create_outputs(
252252
return ret;
253253
}
254254

255+
/** Set hash state to the BIP340 tagged hash midstate for "BIP0352/Label". */
256+
static void secp256k1_silentpayments_sha256_init_label(secp256k1_sha256* hash) {
257+
secp256k1_sha256_initialize(hash);
258+
hash->s[0] = 0x26b95d63ul;
259+
hash->s[1] = 0x8bf1b740ul;
260+
hash->s[2] = 0x10a5986ful;
261+
hash->s[3] = 0x06a387a5ul;
262+
hash->s[4] = 0x2d1c1c30ul;
263+
hash->s[5] = 0xd035951aul;
264+
hash->s[6] = 0x2d7f0f96ul;
265+
hash->s[7] = 0x29e3e0dbul;
266+
267+
hash->bytes = 64;
268+
}
269+
270+
int secp256k1_silentpayments_recipient_create_label_tweak(const secp256k1_context *ctx, secp256k1_pubkey *label, unsigned char *label_tweak32, const unsigned char *recipient_scan_key, unsigned int m) {
271+
secp256k1_sha256 hash;
272+
unsigned char m_serialized[4];
273+
274+
/* Sanity check inputs. */
275+
VERIFY_CHECK(ctx != NULL);
276+
ARG_CHECK(label != NULL);
277+
ARG_CHECK(label_tweak32 != NULL);
278+
ARG_CHECK(recipient_scan_key != NULL);
279+
280+
/* Compute label_tweak = hash(ser_256(b_scan) || ser_32(m)) [sha256 with tag "BIP0352/Label"] */
281+
secp256k1_silentpayments_sha256_init_label(&hash);
282+
secp256k1_sha256_write(&hash, recipient_scan_key, 32);
283+
secp256k1_write_be32(m_serialized, m);
284+
secp256k1_sha256_write(&hash, m_serialized, sizeof(m_serialized));
285+
secp256k1_sha256_finalize(&hash, label_tweak32);
286+
287+
/* Compute label = label_tweak * G */
288+
return secp256k1_ec_pubkey_create(ctx, label, label_tweak32);
289+
}
290+
291+
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) {
292+
secp256k1_ge B_m, label_addend;
293+
secp256k1_gej result_gej;
294+
secp256k1_ge result_ge;
295+
int ret;
296+
297+
/* Sanity check inputs. */
298+
VERIFY_CHECK(ctx != NULL);
299+
ARG_CHECK(labelled_spend_pubkey != NULL);
300+
ARG_CHECK(recipient_spend_pubkey != NULL);
301+
ARG_CHECK(label != NULL);
302+
303+
/* Calculate B_m = B_spend + label
304+
* If either the label or spend public key is an invalid public key,
305+
* return early
306+
*/
307+
ret = secp256k1_pubkey_load(ctx, &B_m, recipient_spend_pubkey);
308+
ret &= secp256k1_pubkey_load(ctx, &label_addend, label);
309+
if (!ret) {
310+
return ret;
311+
}
312+
secp256k1_gej_set_ge(&result_gej, &B_m);
313+
secp256k1_gej_add_ge_var(&result_gej, &result_gej, &label_addend, NULL);
314+
if (secp256k1_gej_is_infinity(&result_gej)) {
315+
return 0;
316+
}
317+
318+
/* Serialize B_m */
319+
secp256k1_ge_set_gej(&result_ge, &result_gej);
320+
secp256k1_pubkey_save(labelled_spend_pubkey, &result_ge);
321+
322+
return 1;
323+
}
324+
255325
#endif

src/modules/silentpayments/tests_impl.h

+27
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,36 @@ static void test_send_api(void) {
225225
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_sender_create_outputs(CTX, op, rp, 1, SMALLEST_OUTPOINT, NULL, 0, p, 1));
226226
}
227227

228+
static void test_label_api(void) {
229+
secp256k1_pubkey l, s, ls, e; /* label pk, spend pk, labelled spend pk, expected labelled spend pk */
230+
unsigned char lt[32]; /* label tweak */
231+
const unsigned char expected[33] = {
232+
0x03,0xdc,0x7f,0x09,0x9a,0xbe,0x95,0x7a,
233+
0x58,0x43,0xd2,0xb6,0xbb,0x35,0x79,0x61,
234+
0x5c,0x60,0x36,0xa4,0x9b,0x86,0xf4,0xbe,
235+
0x46,0x38,0x60,0x28,0xa8,0x1a,0x77,0xd4,0x91
236+
};
237+
238+
/* Create a label and labelled spend public key, verify we get the expected result */
239+
CHECK(secp256k1_ec_pubkey_parse(CTX, &s, BOB_ADDRESS[1], 33));
240+
CHECK(secp256k1_silentpayments_recipient_create_label_tweak(CTX, &l, lt, ALICE_SECKEY, 1));
241+
CHECK(secp256k1_silentpayments_recipient_create_labelled_spend_pubkey(CTX, &ls, &s, &l));
242+
CHECK(secp256k1_ec_pubkey_parse(CTX, &e, expected, 33));
243+
CHECK(secp256k1_ec_pubkey_cmp(CTX, &ls, &e) == 0);
244+
245+
/* Check null values are handled */
246+
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_recipient_create_label_tweak(CTX, NULL, lt, ALICE_SECKEY, 1));
247+
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_recipient_create_label_tweak(CTX, &l, NULL, ALICE_SECKEY, 1));
248+
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_recipient_create_label_tweak(CTX, &l, lt, NULL, 1));
249+
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_recipient_create_labelled_spend_pubkey(CTX, NULL, &s, &l));
250+
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_recipient_create_labelled_spend_pubkey(CTX, &ls, NULL, &l));
251+
CHECK_ILLEGAL(CTX, secp256k1_silentpayments_recipient_create_labelled_spend_pubkey(CTX, &ls, &s, NULL));
252+
}
253+
228254
void run_silentpayments_tests(void) {
229255
test_recipient_sort();
230256
test_send_api();
257+
test_label_api();
231258
}
232259

233260
#endif

0 commit comments

Comments
 (0)