Skip to content

Commit a4f3583

Browse files
theStackjosibake
authored andcommitted
silentpayments: implement output pubkey creation
Add methods for creating an xonly output from a shared secret. This involves adding a tagged hash for creating the output. This function will be exposed in the API in a later commit for the receiver to use when scanning as a light client.
1 parent f35ab7d commit a4f3583

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

src/modules/silentpayments/main_impl.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "../../../include/secp256k1.h"
1010
#include "../../../include/secp256k1_ecdh.h"
11+
#include "../../../include/secp256k1_extrakeys.h"
1112
#include "../../../include/secp256k1_silentpayments.h"
1213

1314
/** Sort an array of silent payment recipients. This is used to group recipients by scan pubkey to
@@ -118,4 +119,54 @@ int secp256k1_silentpayments_create_shared_secret(const secp256k1_context *ctx,
118119
return 1;
119120
}
120121

122+
/** Set hash state to the BIP340 tagged hash midstate for "BIP0352/SharedSecret". */
123+
static void secp256k1_silentpayments_sha256_init_sharedsecret(secp256k1_sha256* hash) {
124+
secp256k1_sha256_initialize(hash);
125+
hash->s[0] = 0x88831537ul;
126+
hash->s[1] = 0x5127079bul;
127+
hash->s[2] = 0x69c2137bul;
128+
hash->s[3] = 0xab0303e6ul;
129+
hash->s[4] = 0x98fa21faul;
130+
hash->s[5] = 0x4a888523ul;
131+
hash->s[6] = 0xbd99daabul;
132+
hash->s[7] = 0xf25e5e0aul;
133+
134+
hash->bytes = 64;
135+
}
136+
137+
static void secp256k1_silentpayments_create_t_k(secp256k1_scalar *t_k_scalar, const unsigned char *shared_secret33, unsigned int k) {
138+
secp256k1_sha256 hash;
139+
unsigned char hash_ser[32];
140+
unsigned char k_serialized[4];
141+
142+
/* Compute t_k = hash(shared_secret || ser_32(k)) [sha256 with tag "BIP0352/SharedSecret"] */
143+
secp256k1_silentpayments_sha256_init_sharedsecret(&hash);
144+
secp256k1_sha256_write(&hash, shared_secret33, 33);
145+
secp256k1_write_be32(k_serialized, k);
146+
secp256k1_sha256_write(&hash, k_serialized, sizeof(k_serialized));
147+
secp256k1_sha256_finalize(&hash, hash_ser);
148+
secp256k1_scalar_set_b32(t_k_scalar, hash_ser, NULL);
149+
}
150+
151+
int secp256k1_silentpayments_create_output_pubkey(const secp256k1_context *ctx, secp256k1_xonly_pubkey *P_output_xonly, const unsigned char *shared_secret33, const secp256k1_pubkey *recipient_spend_pubkey, unsigned int k) {
152+
secp256k1_ge P_output_ge;
153+
secp256k1_scalar t_k_scalar;
154+
155+
/* Sanity check inputs */
156+
VERIFY_CHECK(ctx != NULL);
157+
ARG_CHECK(P_output_xonly != NULL);
158+
ARG_CHECK(shared_secret33 != NULL);
159+
ARG_CHECK(recipient_spend_pubkey != NULL);
160+
161+
/* Calculate and return P_output_xonly = B_spend + t_k * G */
162+
secp256k1_silentpayments_create_t_k(&t_k_scalar, shared_secret33, k);
163+
secp256k1_pubkey_load(ctx, &P_output_ge, recipient_spend_pubkey);
164+
if (!secp256k1_eckey_pubkey_tweak_add(&P_output_ge, &t_k_scalar)) {
165+
return 0;
166+
}
167+
secp256k1_xonly_pubkey_save(P_output_xonly, &P_output_ge);
168+
169+
return 1;
170+
}
171+
121172
#endif

0 commit comments

Comments
 (0)