Skip to content

Commit cec4d35

Browse files
committed
add dleq implementation
- modify secp256k1-zkp's dleq implementation to be consistent with BIP 374. - use BIP374 notations. - add DLEQ tests
1 parent 86d8507 commit cec4d35

File tree

3 files changed

+380
-0
lines changed

3 files changed

+380
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
include_HEADERS += include/secp256k1_silentpayments.h
22
noinst_HEADERS += src/modules/silentpayments/main_impl.h
3+
noinst_HEADERS += src/modules/silentpayments/dleq_impl.h
34
noinst_HEADERS += src/modules/silentpayments/bench_impl.h
45
noinst_HEADERS += src/modules/silentpayments/tests_impl.h
56
noinst_HEADERS += src/modules/silentpayments/vectors.h
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
#ifndef SECP256K1_DLEQ_IMPL_H
2+
#define SECP256K1_DLEQ_IMPL_H
3+
4+
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
5+
* SHA256 to SHA256("BIP0374/aux")||SHA256("BIP0374/aux"). */
6+
static void secp256k1_nonce_function_bip374_sha256_tagged_aux(secp256k1_sha256 *sha) {
7+
secp256k1_sha256_initialize(sha);
8+
sha->s[0] = 0x48479343ul;
9+
sha->s[1] = 0xa9eb648cul;
10+
sha->s[2] = 0x58952fe4ul;
11+
sha->s[3] = 0x4772d3b2ul;
12+
sha->s[4] = 0x977ab0a0ul;
13+
sha->s[5] = 0xcb8e2740ul;
14+
sha->s[6] = 0x60bb4b81ul;
15+
sha->s[7] = 0x68a41b66ul;
16+
17+
sha->bytes = 64;
18+
}
19+
20+
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
21+
* SHA256 to SHA256("BIP0374/nonce")||SHA256("BIP0374/nonce"). */
22+
static void secp256k1_nonce_function_bip374_sha256_tagged(secp256k1_sha256 *sha) {
23+
secp256k1_sha256_initialize(sha);
24+
sha->s[0] = 0xa810fc87ul;
25+
sha->s[1] = 0x3b4a4d2aul;
26+
sha->s[2] = 0xe302cfb4ul;
27+
sha->s[3] = 0x322df1a0ul;
28+
sha->s[4] = 0xd2e7fb82ul;
29+
sha->s[5] = 0x7808570dul;
30+
sha->s[6] = 0x9c33e0cdul;
31+
sha->s[7] = 0x2dfbf7f6ul;
32+
33+
sha->bytes = 64;
34+
}
35+
36+
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
37+
* SHA256 to SHA256("BIP0374/challenge")||SHA256("BIP0374/challenge"). */
38+
static void secp256k1_dleq_sha256_tagged(secp256k1_sha256 *sha) {
39+
secp256k1_sha256_initialize(sha);
40+
sha->s[0] = 0x24f1c9c7ul;
41+
sha->s[1] = 0xd1538c75ul;
42+
sha->s[2] = 0xc9874ae8ul;
43+
sha->s[3] = 0x6566de76ul;
44+
sha->s[4] = 0x487843c9ul;
45+
sha->s[5] = 0xc13d8026ul;
46+
sha->s[6] = 0x39a2f3eful;
47+
sha->s[7] = 0x2ad0fcb3ul;
48+
49+
sha->bytes = 64;
50+
}
51+
52+
/* algo argument for nonce_function_dleq to derive the nonce using a tagged hash function. */
53+
static const unsigned char dleq_algo[] = {'D', 'L', 'E', 'Q'};
54+
55+
static int secp256k1_dleq_hash_point(secp256k1_sha256 *sha, secp256k1_ge *p) {
56+
unsigned char buf[33];
57+
size_t size = 33;
58+
if (!secp256k1_eckey_pubkey_serialize(p, buf, &size, 1)) {
59+
return 0;
60+
}
61+
secp256k1_sha256_write(sha, buf, size);
62+
return 1;
63+
}
64+
65+
static int nonce_function_dleq(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) {
66+
secp256k1_sha256 sha;
67+
unsigned char masked_key[32];
68+
int i;
69+
if (xonly_pk32 != NULL) {
70+
return 0;
71+
}
72+
73+
if (data != NULL) {
74+
secp256k1_nonce_function_bip374_sha256_tagged_aux(&sha);
75+
secp256k1_sha256_write(&sha, data, 32);
76+
secp256k1_sha256_finalize(&sha, masked_key);
77+
for (i = 0; i < 32; i++) {
78+
masked_key[i] ^= key32[i];
79+
}
80+
} else {
81+
/* Precomputed TaggedHash("BIP0374/aux", 0x0000...00); */
82+
static const unsigned char ZERO_MASK[32] = {
83+
38, 255, 199, 133, 21, 94, 75, 99,
84+
18, 166, 0, 53, 197, 146, 253, 84,
85+
197, 228, 235, 145, 124, 59, 203, 21,
86+
66, 88, 250, 253, 207, 123, 43, 55
87+
};
88+
for (i = 0; i < 32; i++) {
89+
masked_key[i] = key32[i] ^ ZERO_MASK[i];
90+
}
91+
}
92+
93+
if (algolen == sizeof(dleq_algo) && secp256k1_memcmp_var(algo, dleq_algo, algolen) == 0) {
94+
secp256k1_nonce_function_bip374_sha256_tagged(&sha);
95+
} else {
96+
secp256k1_sha256_initialize_tagged(&sha, algo, algolen);
97+
}
98+
99+
/* Hash masked-key||msg using the tagged hash as per the spec */
100+
secp256k1_sha256_write(&sha, masked_key, 32);
101+
secp256k1_sha256_write(&sha, msg, msglen);
102+
secp256k1_sha256_finalize(&sha, nonce32);
103+
return 1;
104+
}
105+
106+
const secp256k1_nonce_function_hardened secp256k1_nonce_function_dleq = nonce_function_dleq;
107+
108+
/* Generates a nonce as defined in BIP0374 */
109+
static int secp256k1_dleq_nonce(secp256k1_scalar *k, const unsigned char *a32, const unsigned char *A_33, const unsigned char *C_33, secp256k1_nonce_function_hardened noncefp, void *ndata) {
110+
unsigned char buf[66];
111+
unsigned char nonce[32];
112+
113+
if (noncefp == NULL) {
114+
noncefp = secp256k1_nonce_function_dleq;
115+
}
116+
memcpy(buf, A_33, 33);
117+
memcpy(buf + 33, C_33, 33);
118+
if (!noncefp(nonce, buf, 66, a32, NULL, dleq_algo, 4, ndata)) {
119+
return 0;
120+
}
121+
122+
secp256k1_scalar_set_b32(k, nonce, NULL);
123+
if (secp256k1_scalar_is_zero(k)) {
124+
return 0;
125+
}
126+
127+
return 1;
128+
}
129+
130+
/* Generates a challenge as defined in BIP0374 */
131+
static void secp256k1_dleq_challenge(secp256k1_scalar *e, secp256k1_ge *B, secp256k1_ge *R1, secp256k1_ge *R2, secp256k1_ge *A, secp256k1_ge *C, const unsigned char *m) {
132+
unsigned char buf[32];
133+
secp256k1_sha256 sha;
134+
secp256k1_ge generator_point = secp256k1_ge_const_g;
135+
136+
secp256k1_dleq_sha256_tagged(&sha);
137+
secp256k1_dleq_hash_point(&sha, A);
138+
secp256k1_dleq_hash_point(&sha, B);
139+
secp256k1_dleq_hash_point(&sha, C);
140+
secp256k1_dleq_hash_point(&sha, &generator_point);
141+
secp256k1_dleq_hash_point(&sha, R1);
142+
secp256k1_dleq_hash_point(&sha, R2);
143+
if (m) secp256k1_sha256_write(&sha, m, 32);
144+
secp256k1_sha256_finalize(&sha, buf);
145+
146+
secp256k1_scalar_set_b32(e, buf, NULL);
147+
}
148+
149+
/* Generate points from scalar a such that A = a*G and C = a*B */
150+
static void secp256k1_dleq_pair(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_ge *A, secp256k1_ge *C, const secp256k1_scalar *a, const secp256k1_ge *B) {
151+
secp256k1_gej Aj, Cj;
152+
153+
secp256k1_ecmult_gen(ecmult_gen_ctx, &Aj, a);
154+
secp256k1_ge_set_gej(A, &Aj);
155+
secp256k1_ecmult_const(&Cj, B, a);
156+
secp256k1_ge_set_gej(C, &Cj);
157+
}
158+
159+
/* DLEQ Proof Generation
160+
*
161+
* For given elliptic curve points A, B, C, and G, the prover generates a proof to prove knowledge of a scalar a such
162+
* that A = a⋅G and C = a⋅B without revealing anything about a.
163+
*
164+
* Returns: 1 if proof creation was successful. 0 if an error occurred.
165+
* Out: scalar e: part of proof = bytes(32, e) || bytes(32, s).
166+
* scalar s: other part of proof = bytes(32, e) || bytes(32, s).
167+
* In: a : scalar a to be proven that both A and C were generated from
168+
* B : point on the curve
169+
* A : point on the curve(a⋅G) generated from a
170+
* C : point on the curve(a⋅B) generated from a
171+
* noncefp : pointer to a nonce generation function. If NULL, secp256k1_nonce_function_dleq is used.
172+
* ndata : pointer to arbitrary data used by the nonce generation function (can be NULL). If it is non-NULL and
173+
* secp256k1_nonce_function_dleq is used, then ndata must be a pointer to 32-byte auxiliary randomness
174+
* */
175+
static int secp256k1_dleq_prove(const secp256k1_context *ctx, secp256k1_scalar *s, secp256k1_scalar *e, const secp256k1_scalar *a, secp256k1_ge *B, secp256k1_ge *A, secp256k1_ge *C, unsigned char *aux_rand32, const unsigned char *m) {
176+
secp256k1_ge R1, R2;
177+
secp256k1_scalar k = { 0 };
178+
unsigned char a32[32];
179+
unsigned char A_33[33];
180+
unsigned char B_33[33];
181+
unsigned char C_33[33];
182+
int ret = 1;
183+
size_t pubkey_size = 33;
184+
185+
secp256k1_scalar_get_b32(a32, a);
186+
if (!secp256k1_eckey_pubkey_serialize(B, B_33, &pubkey_size, 1)) {
187+
return 0;
188+
}
189+
if (!secp256k1_eckey_pubkey_serialize(A, A_33, &pubkey_size, 1)) {
190+
return 0;
191+
}
192+
if (!secp256k1_eckey_pubkey_serialize(C, C_33, &pubkey_size, 1)) {
193+
return 0;
194+
}
195+
ret &= secp256k1_dleq_nonce(&k, a32, A_33, C_33, secp256k1_nonce_function_dleq, aux_rand32);
196+
197+
/* R1 = k*G, R2 = k*B */
198+
secp256k1_dleq_pair(&ctx->ecmult_gen_ctx, &R1, &R2, &k, B);
199+
/* We declassify the non-secret values R1 and R2 to allow using them as
200+
* branch points. */
201+
secp256k1_declassify(ctx, &R1, sizeof(R1));
202+
secp256k1_declassify(ctx, &R2, sizeof(R2));
203+
204+
/* e = tagged hash(A, B, C, R1, R2) */
205+
/* s = k + e * a */
206+
secp256k1_dleq_challenge(e, B, &R1, &R2, A, C, m);
207+
secp256k1_scalar_mul(s, e, a);
208+
secp256k1_scalar_add(s, s, &k);
209+
210+
secp256k1_scalar_clear(&k);
211+
return ret;
212+
}
213+
214+
/* DLEQ Proof Verification
215+
*
216+
* Verifies the proof. If the following algorithm succeeds, the points A and C were both generated from the same scalar.
217+
* The former from multiplying by G, and the latter from multiplying by B.
218+
*
219+
* Returns: 1 if proof verification was successful. 0 if an error occurred.
220+
* In: proof : proof bytes(32, e) || bytes(32, s) consists of scalar e and scalar s
221+
* A : point on the curve(a⋅G) computed from a
222+
* B : point on the curve
223+
* C : point on the curve(a⋅B) computed from a
224+
* m : optional message
225+
* */
226+
static int secp256k1_dleq_verify(secp256k1_scalar *s, secp256k1_scalar *e, secp256k1_ge *A, secp256k1_ge *B, secp256k1_ge *C, const unsigned char *m) {
227+
secp256k1_scalar e_neg;
228+
secp256k1_scalar e_expected;
229+
secp256k1_gej Bj;
230+
secp256k1_gej Aj, Cj;
231+
secp256k1_gej R1j, R2j;
232+
secp256k1_ge R1, R2;
233+
secp256k1_gej tmpj;
234+
235+
secp256k1_gej_set_ge(&Aj, A);
236+
secp256k1_gej_set_ge(&Cj, C);
237+
238+
secp256k1_scalar_negate(&e_neg, e);
239+
/* R1 = s*G - e*A */
240+
secp256k1_ecmult(&R1j, &Aj, &e_neg, s);
241+
/* R2 = s*B - e*C */
242+
secp256k1_ecmult(&tmpj, &Cj, &e_neg, &secp256k1_scalar_zero);
243+
secp256k1_gej_set_ge(&Bj, B);
244+
secp256k1_ecmult(&R2j, &Bj, s, &secp256k1_scalar_zero);
245+
secp256k1_gej_add_var(&R2j, &R2j, &tmpj, NULL);
246+
247+
secp256k1_ge_set_gej(&R1, &R1j);
248+
secp256k1_ge_set_gej(&R2, &R2j);
249+
secp256k1_dleq_challenge(&e_expected, B, &R1, &R2, A, C, m);
250+
251+
secp256k1_scalar_add(&e_expected, &e_expected, &e_neg);
252+
return secp256k1_scalar_is_zero(&e_expected);
253+
}
254+
255+
#endif

0 commit comments

Comments
 (0)