Skip to content

Commit c15235d

Browse files
theStackjosibake
authored andcommitted
silentpayments: implement shared secret creation
Add function for calculating either a*B or A*b. This function is used by both the sender and the recipient (i.e. a*B == A*b). Add functions for generating the tagged input hash, as this is used when creating the shared secret. In a later commit, `create_shared_secret` will be exposed in the API for the receiver to use when scanning as a light client.
1 parent b05b381 commit c15235d

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

src/modules/silentpayments/main_impl.h

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define SECP256K1_MODULE_SILENTPAYMENTS_MAIN_H
88

99
#include "../../../include/secp256k1.h"
10+
#include "../../../include/secp256k1_ecdh.h"
1011
#include "../../../include/secp256k1_silentpayments.h"
1112

1213
/** Sort an array of silent payment recipients. This is used to group recipients by scan pubkey to
@@ -37,4 +38,84 @@ int secp256k1_silentpayments_recipient_sort(const secp256k1_context* ctx, const
3738
return 1;
3839
}
3940

41+
/** Set hash state to the BIP340 tagged hash midstate for "BIP0352/Inputs". */
42+
static void secp256k1_silentpayments_sha256_init_inputs(secp256k1_sha256* hash) {
43+
secp256k1_sha256_initialize(hash);
44+
hash->s[0] = 0xd4143ffcul;
45+
hash->s[1] = 0x012ea4b5ul;
46+
hash->s[2] = 0x36e21c8ful;
47+
hash->s[3] = 0xf7ec7b54ul;
48+
hash->s[4] = 0x4dd4e2acul;
49+
hash->s[5] = 0x9bcaa0a4ul;
50+
hash->s[6] = 0xe244899bul;
51+
hash->s[7] = 0xcd06903eul;
52+
53+
hash->bytes = 64;
54+
}
55+
56+
static void secp256k1_silentpayments_calculate_input_hash(unsigned char *input_hash, const unsigned char *outpoint_smallest36, secp256k1_ge *pubkey_sum) {
57+
secp256k1_sha256 hash;
58+
unsigned char pubkey_sum_ser[33];
59+
size_t ser_size;
60+
int ser_ret;
61+
62+
secp256k1_silentpayments_sha256_init_inputs(&hash);
63+
secp256k1_sha256_write(&hash, outpoint_smallest36, 36);
64+
ser_ret = secp256k1_eckey_pubkey_serialize(pubkey_sum, pubkey_sum_ser, &ser_size, 1);
65+
VERIFY_CHECK(ser_ret && ser_size == sizeof(pubkey_sum_ser));
66+
(void)ser_ret;
67+
secp256k1_sha256_write(&hash, pubkey_sum_ser, sizeof(pubkey_sum_ser));
68+
secp256k1_sha256_finalize(&hash, input_hash);
69+
}
70+
71+
/* secp256k1_ecdh expects a hash function to be passed in or uses its default
72+
* hashing function. We don't want to hash the ECDH result yet (it will be
73+
* hashed later with a counter `k`), so we define a custom function which simply
74+
* returns the pubkey without hashing.
75+
*/
76+
static int secp256k1_silentpayments_ecdh_return_pubkey(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
77+
secp256k1_ge point;
78+
secp256k1_fe x, y;
79+
size_t ser_size;
80+
int ser_ret;
81+
82+
(void)data;
83+
/* Parse point as group element */
84+
if (!secp256k1_fe_set_b32_limit(&x, x32) || !secp256k1_fe_set_b32_limit(&y, y32)) {
85+
return 0;
86+
}
87+
secp256k1_ge_set_xy(&point, &x, &y);
88+
89+
/* Serialize as compressed pubkey */
90+
ser_ret = secp256k1_eckey_pubkey_serialize(&point, output, &ser_size, 1);
91+
VERIFY_CHECK(ser_ret && ser_size == 33);
92+
(void)ser_ret;
93+
94+
return 1;
95+
}
96+
97+
int secp256k1_silentpayments_create_shared_secret(const secp256k1_context *ctx, unsigned char *shared_secret33, const unsigned char *secret_component, const secp256k1_pubkey *public_component, unsigned char *input_hash) {
98+
unsigned char tweaked_secret_component[32];
99+
/* Sanity check inputs */
100+
ARG_CHECK(shared_secret33 != NULL);
101+
memset(shared_secret33, 0, 33);
102+
ARG_CHECK(public_component != NULL);
103+
ARG_CHECK(secret_component != NULL);
104+
105+
/* Tweak secret component with input hash, if available */
106+
memcpy(tweaked_secret_component, secret_component, 32);
107+
if (input_hash != NULL) {
108+
if (!secp256k1_ec_seckey_tweak_mul(ctx, tweaked_secret_component, input_hash)) {
109+
return 0;
110+
}
111+
}
112+
113+
/* Compute shared_secret = tweaked_secret_component * Public_component */
114+
if (!secp256k1_ecdh(ctx, shared_secret33, public_component, tweaked_secret_component, secp256k1_silentpayments_ecdh_return_pubkey, NULL)) {
115+
return 0;
116+
}
117+
118+
return 1;
119+
}
120+
40121
#endif

0 commit comments

Comments
 (0)