Skip to content

Commit 45911b2

Browse files
committed
dleq: Apply review feedback
Reject proofs that produce infinity points during verification Add public API test case for infinity point scenario Add note to clarify contents of msg to reduce confusion with m Add missing includes Format tools/test_vectors_dleq_generate.py
1 parent 403d245 commit 45911b2

File tree

5 files changed

+47
-28
lines changed

5 files changed

+47
-28
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
include_HEADERS += include/secp256k1_dleq.h
2-
noinst_HEADERS += src/modules/dleq/dleq_vectors.h
32
noinst_HEADERS += src/modules/dleq/main_impl.h
3+
noinst_HEADERS += src/modules/dleq/tests_impl.h
4+
noinst_HEADERS += src/modules/dleq/dleq_vectors.h

src/modules/dleq/dleq_vectors.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Test vectors according to BIP-374 ("Discrete Log Equality Proofs") are included in this file.
55
* Tests are included in src/modules/dleq/tests_impl.h. */
6-
6+
77
static const unsigned char a_bytes[6][32] = {
88
{ 0xC0, 0x8C, 0xA8, 0xE0, 0xBB, 0x59, 0x76, 0x9F, 0xC6, 0xA4, 0xE0, 0x78, 0x45, 0x62, 0x84, 0xE0, 0x0E, 0xA3, 0x4F, 0x65, 0xAD, 0xD9, 0x88, 0xC2, 0x46, 0xE1, 0xBB, 0xA8, 0x58, 0x24, 0xCC, 0xDC },
99
{ 0x8E, 0x64, 0x1B, 0xA6, 0xBF, 0x7F, 0x64, 0xEE, 0xC7, 0x60, 0x05, 0xA2, 0x95, 0x85, 0xA5, 0x03, 0x53, 0x76, 0x37, 0x5F, 0x33, 0xE3, 0x31, 0x21, 0x5A, 0xED, 0xFE, 0x03, 0xB8, 0xE8, 0x0E, 0x7A },

src/modules/dleq/main_impl.h

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

99
#include "../../../include/secp256k1.h"
1010
#include "../../../include/secp256k1_dleq.h"
11+
#include "../../hash.h"
1112

1213
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
1314
* SHA256 to SHA256("BIP0374/aux")||SHA256("BIP0374/aux"). */
@@ -60,10 +61,6 @@ static void secp256k1_dleq_sha256_tagged(secp256k1_sha256 *sha) {
6061
static int secp256k1_dleq_hash_point(secp256k1_sha256 *sha, secp256k1_ge *p) {
6162
unsigned char buf[33];
6263
size_t size = 33;
63-
/* Reject infinity point */
64-
if (secp256k1_ge_is_infinity(p)) {
65-
return 0;
66-
}
6764
secp256k1_eckey_pubkey_serialize33(p, buf);
6865
secp256k1_sha256_write(sha, buf, size);
6966
return 1;
@@ -95,7 +92,8 @@ static void secp256k1_nonce_function_dleq(unsigned char *nonce32, const unsigned
9592
}
9693

9794
secp256k1_nonce_function_bip374_sha256_tagged(&sha);
98-
/* Hash masked-key||msg||m using the tagged hash as per BIP-374 v0.2.0 */
95+
/* Hash masked-key||msg||m using the tagged hash as defined in BIP0374
96+
* Note: msg contains the serialized points A||C (66 bytes) */
9997
secp256k1_sha256_write(&sha, masked_key, 32);
10098
secp256k1_sha256_write(&sha, msg, msglen);
10199
if (m != NULL) {
@@ -106,7 +104,7 @@ static void secp256k1_nonce_function_dleq(unsigned char *nonce32, const unsigned
106104
secp256k1_memclear_explicit(masked_key, sizeof(masked_key));
107105
}
108106

109-
/* Generates a nonce as defined in BIP0374 v0.2.0 */
107+
/* Generates a nonce as defined in BIP0374 */
110108
static int secp256k1_dleq_nonce(secp256k1_scalar *k, const unsigned char *a32, const unsigned char *A_33, const unsigned char *C_33, const unsigned char *aux_rand32, const unsigned char *m) {
111109
unsigned char buf[66];
112110
unsigned char nonce[32];
@@ -237,6 +235,10 @@ static int secp256k1_dleq_verify_internal(secp256k1_scalar *s, secp256k1_scalar
237235
secp256k1_ecmult(&R2j, &Bj, s, &secp256k1_scalar_zero);
238236
secp256k1_gej_add_var(&R2j, &R2j, &tmpj, NULL);
239237

238+
/* Fail verification if R1j or R2j are infinity */
239+
if (secp256k1_gej_is_infinity(&R1j) || secp256k1_gej_is_infinity(&R2j)) {
240+
return 0;
241+
}
240242
secp256k1_ge_set_gej(&R1, &R1j);
241243
secp256k1_ge_set_gej(&R2, &R2j);
242244
secp256k1_dleq_challenge(&e_expected, B, &R1, &R2, A, C, m);
@@ -277,16 +279,14 @@ int secp256k1_dleq_prove(
277279
secp256k1_dleq_pair(&ctx->ecmult_gen_ctx, &A, &C, &a, &B);
278280

279281
ret = secp256k1_dleq_prove_internal(ctx, &s, &e, &a, &B, &A, &C, aux_rand32, msg);
282+
secp256k1_scalar_clear(&a);
280283
if (!ret) {
281-
secp256k1_scalar_clear(&a);
282284
return 0;
283285
}
284286

285287
secp256k1_scalar_get_b32(&proof64[0], &e);
286288
secp256k1_scalar_get_b32(&proof64[32], &s);
287289

288-
secp256k1_scalar_clear(&a);
289-
290290
return 1;
291291
}
292292

src/modules/dleq/tests_impl.h

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

99
#include "dleq_vectors.h"
10+
#include "../../unit_test.h"
1011

1112
static void dleq_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) {
1213
secp256k1_scalar k1, k2;
@@ -176,7 +177,7 @@ static void run_test_dleq_bip374_vectors(void) {
176177
if (i > 2 && i < 6) {
177178
/* Skip tests indices 3-5: proof generation failure cases (a=0, a=N, B=infinity).
178179
* These contain placeholder data from test_vectors_generate_proof.csv that would
179-
* fail to parse. Only indices 0-2 and 6-12 have valid test data.
180+
* fail to parse. Only indices 0-2 and 6-12 have valid test data.
180181
* */
181182
continue;
182183
}
@@ -191,7 +192,7 @@ static void run_test_dleq_bip374_vectors(void) {
191192
if (is_not_empty(msg_bytes[i])) {
192193
m = msg_bytes[i];
193194
}
194-
195+
195196
CHECK(secp256k1_dleq_verify_internal(&s, &e, &A, &B, &C, m) == success[i]);
196197
}
197198
}
@@ -231,7 +232,10 @@ static void run_test_dleq_api(void) {
231232
CHECK_ILLEGAL(CTX, secp256k1_dleq_verify(CTX, proof, NULL, &B, &C, msg));
232233
CHECK_ILLEGAL(CTX, secp256k1_dleq_verify(CTX, proof, &A, NULL, &C, msg));
233234
CHECK_ILLEGAL(CTX, secp256k1_dleq_verify(CTX, proof, &A, &B, NULL, msg));
234-
235+
/* Verify rejects an invalid (all-zero) proof */
236+
memset(proof, 0, sizeof(proof));
237+
CHECK(secp256k1_dleq_verify(CTX, proof, &A, &B, &C, msg) == 0);
238+
235239
/* Verify public API prove and verify functions */
236240
CHECK(secp256k1_dleq_prove(CTX, proof, seckey, &B, aux_rand, msg) == 1);
237241
CHECK(secp256k1_dleq_verify(CTX, proof, &A, &B, &C, msg) == 1);

tools/test_vectors_dleq_generate.py

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,21 @@
1111
print("Usage: %s <dir>" % sys.argv[0])
1212
sys.exit(1)
1313

14-
s = (
15-
"""/**
14+
s = """/**
1615
* Automatically generated by %s.
1716
*
1817
* Test vectors according to BIP-374 ("Discrete Log Equality Proofs") are included in this file.
1918
* Tests are included in src/modules/dleq/tests_impl.h. */
20-
""" % sys.argv[0]
21-
)
19+
""" % sys.argv[0]
20+
2221

2322
def hexstr_to_intarray(str):
2423
try:
2524
return ", ".join([f"0x{b:02X}" for b in bytes.fromhex(str)])
2625
except ValueError:
2726
return "0x00"
2827

28+
2929
def create_init(name, rows, cols):
3030
return """
3131
static const unsigned char %s[%d][%d] = {
@@ -35,9 +35,11 @@ def create_init(name, rows, cols):
3535
cols,
3636
)
3737

38+
3839
def init_array(key):
3940
return textwrap.indent("{ %s };" % ", ".join(test_case[key]), "")
4041

42+
4143
def init_arrays(key):
4244
s = textwrap.indent(
4345
",\n".join(["{ %s }" % hexstr_to_intarray(x) for x in test_case[key]]), 4 * " "
@@ -62,7 +64,7 @@ def init_arrays(key):
6264
}
6365

6466

65-
with open(sys.argv[1] + "/test_vectors_generate_proof.csv", newline='') as csvfile:
67+
with open(sys.argv[1] + "/test_vectors_generate_proof.csv", newline="") as csvfile:
6668
reader = csv.DictReader(csvfile)
6769
# Skip the first 5 rows since those test vectors don't use secp's generator point
6870
for _ in range(5):
@@ -76,27 +78,35 @@ def init_arrays(key):
7678
special_cases = {
7779
"point_B": "INFINITY",
7880
"result_proof": "INVALID",
79-
"message": ""
81+
"message": "",
8082
}
81-
test_case[key].append("0" if row[key] in special_cases.get(key, []) else row[key])
83+
test_case[key].append(
84+
"0" if row[key] in special_cases.get(key, []) else row[key]
85+
)
8286
else:
8387
# these keys are not present in current csv file but are present in test_vectors_verify_proof.csv
8488
if key in {"point_A", "point_C"}:
8589
# "0" is filled as value for these missing keys
8690
test_case[key].append("0")
8791
elif key == "result_success":
8892
# success/failure value is obtained from row["comment"] for the missing key "result_success"
89-
test_case[key].append("1" if "Success" in row.get("comment", "") else "0")
93+
test_case[key].append(
94+
"1" if "Success" in row.get("comment", "") else "0"
95+
)
9096
else:
91-
sys.exit("Unexpected missing_key encountered when parsing test_vectors_generate_proof.csv")
97+
sys.exit(
98+
"Unexpected missing_key encountered when parsing test_vectors_generate_proof.csv"
99+
)
92100

93101

94-
with open(sys.argv[1] + "/test_vectors_verify_proof.csv", newline='') as csvfile:
102+
with open(sys.argv[1] + "/test_vectors_verify_proof.csv", newline="") as csvfile:
95103
reader = csv.DictReader(csvfile)
96-
for _ in range(5): # Skip the first 5 rows since those test vectors don't use secp's generator point
104+
for _ in range(
105+
5
106+
): # Skip the first 5 rows since those test vectors don't use secp's generator point
97107
next(reader, None)
98108

99-
for i in range(3):
109+
for i in range(3):
100110
# Fill point_A and point_C for the 3 success cases (array indices 0-2) from verify CSV
101111
# These correspond to generate and verify CSV rows 5-7
102112
row = next(reader)
@@ -108,15 +118,19 @@ def init_arrays(key):
108118
if key in row:
109119
# these keys are present in test_vectors_verify_proof.csv
110120
# not handling row[key] == "TRUE" since it doesn't appear in the BIP test vectors
111-
test_case[key].append("0" if key == "result_success" and row[key] == "FALSE" else row[key])
121+
test_case[key].append(
122+
"0" if key == "result_success" and row[key] == "FALSE" else row[key]
123+
)
112124
else:
113125
# these keys are not present in current csv file but are present in test_vectors_generate_proof.csv
114126
if key == "result_proof":
115127
# interpret "result_proof" key in the test_vectors_generate_proof.csv test vectors
116128
# same as "proof" key in the test_vectors_verify_proof.csv test vectors
117129
test_case["result_proof"].append(row["proof"])
118130
elif key not in {"scalar_a", "auxrand_r"}: # skip expected missing keys
119-
sys.exit("Unexpected missing key encountered when test_vectors_verify_proof.csv")
131+
sys.exit(
132+
"Unexpected missing key encountered when test_vectors_verify_proof.csv"
133+
)
120134

121135

122136
s += create_init("a_bytes", len(test_case["scalar_a"]), 32)

0 commit comments

Comments
 (0)