Skip to content

Commit 759eb1f

Browse files
committed
silentpayments: add private tweak data creation routine
1 parent b7efbd5 commit 759eb1f

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

include/secp256k1_silentpayments.h

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,38 @@ extern "C" {
2828
* operations.
2929
*/
3030

31-
/* TODO: add function API for sender side. */
31+
/** Create Silent Payment tweak data from input private keys.
32+
*
33+
* Given a list of n private keys a_0...a_(n-1) (one for each input to spend)
34+
* and an outpoints_hash, compute the corresponding input private keys tweak data:
35+
*
36+
* a_tweaked = (a_0 + a_1 + ... a_(n-1)) * outpoints_hash
37+
*
38+
* If necessary, the private keys are negated to enforce the right y-parity.
39+
* For that reason, the private keys have to be passed in via two different parameter
40+
* pairs, depending on whether they were used for creating taproot outputs or not.
41+
* The resulting data is needed to create a shared secret for the sender side.
42+
*
43+
* Returns: 1 if shared secret creation was successful. 0 if an error occured.
44+
* Args: ctx: pointer to a context object
45+
* Out: tweak_data32: pointer to the resulting 32-byte tweak data
46+
* In: plain_seckeys: pointer to an array of 32-byte private keys of non-taproot inputs
47+
* (can be NULL if no private keys of non-taproot inputs are used)
48+
* n_plain_seckeys: the number of sender's non-taproot input private keys
49+
* taproot_seckeys: pointer to an array of 32-byte private keys of taproot inputs
50+
* (can be NULL if no private keys of taproot inputs are used)
51+
* n_taproot_seckeys: the number of sender's taproot input private keys
52+
* outpoints_hash32: hash of the sorted serialized outpoints
53+
*/
54+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_silentpayments_create_private_tweak_data(
55+
const secp256k1_context *ctx,
56+
unsigned char *tweak_data32,
57+
const unsigned char *plain_seckeys,
58+
size_t n_plain_seckeys,
59+
const unsigned char *taproot_seckeys,
60+
size_t n_taproot_seckeys,
61+
const unsigned char *outpoints_hash32
62+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(7);
3263

3364
/* TODO: add function API for receiver side. */
3465

src/modules/silentpayments/main_impl.h

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,66 @@
99
#include "../../../include/secp256k1.h"
1010
#include "../../../include/secp256k1_silentpayments.h"
1111

12-
/* TODO: implement functions for sender side. */
12+
int secp256k1_silentpayments_create_private_tweak_data(const secp256k1_context *ctx, unsigned char *tweak_data32, const unsigned char *plain_seckeys, size_t n_plain_seckeys, const unsigned char *taproot_seckeys, size_t n_taproot_seckeys, const unsigned char *outpoints_hash32) {
13+
size_t i;
14+
unsigned char a_tweaked[32];
15+
16+
/* Sanity check inputs. */
17+
VERIFY_CHECK(ctx != NULL);
18+
ARG_CHECK(tweak_data32 != NULL);
19+
memset(tweak_data32, 0, 32);
20+
ARG_CHECK(plain_seckeys == NULL || n_plain_seckeys >= 1);
21+
ARG_CHECK(taproot_seckeys == NULL || n_taproot_seckeys >= 1);
22+
ARG_CHECK((plain_seckeys != NULL) || (taproot_seckeys != NULL));
23+
ARG_CHECK((n_plain_seckeys + n_taproot_seckeys) >= 1);
24+
ARG_CHECK(outpoints_hash32 != NULL);
25+
26+
/* Compute input private keys tweak: a_tweaked = (a_0 + a_1 + ... + a_(n-1)) * outpoints_hash */
27+
for (i = 0; i < n_plain_seckeys; i++) {
28+
const unsigned char *seckey_to_add = &plain_seckeys[i*32];
29+
if (i == 0) {
30+
memcpy(a_tweaked, seckey_to_add, 32);
31+
continue;
32+
}
33+
if (!secp256k1_ec_seckey_tweak_add(ctx, a_tweaked, seckey_to_add)) {
34+
return 0;
35+
}
36+
}
37+
/* private keys used for taproot outputs have to be negated if they resulted in an odd point */
38+
for (i = 0; i < n_taproot_seckeys; i++) {
39+
unsigned char seckey_to_add[32];
40+
secp256k1_pubkey pubkey;
41+
secp256k1_ge ge;
42+
43+
memcpy(seckey_to_add, &taproot_seckeys[32*i], 32);
44+
if (!secp256k1_ec_pubkey_create(ctx, &pubkey, seckey_to_add)) {
45+
return 0;
46+
}
47+
if (!secp256k1_pubkey_load(ctx, &ge, &pubkey)) {
48+
return 0;
49+
}
50+
if (secp256k1_fe_is_odd(&ge.y)) {
51+
if (!secp256k1_ec_seckey_negate(ctx, seckey_to_add)) {
52+
return 0;
53+
}
54+
}
55+
56+
if (i == 0 && n_plain_seckeys == 0) {
57+
memcpy(a_tweaked, seckey_to_add, 32);
58+
continue;
59+
}
60+
if (!secp256k1_ec_seckey_tweak_add(ctx, a_tweaked, seckey_to_add)) {
61+
return 0;
62+
}
63+
}
64+
65+
if (!secp256k1_ec_seckey_tweak_mul(ctx, a_tweaked, outpoints_hash32)) {
66+
return 0;
67+
}
68+
69+
memcpy(tweak_data32, a_tweaked, 32);
70+
return 1;
71+
}
1372

1473
/* TODO: implement functions for receiver side. */
1574

0 commit comments

Comments
 (0)