Skip to content

Commit dc7525c

Browse files
committed
Add X-only ECDH unit tests
1 parent d6f6d80 commit dc7525c

File tree

1 file changed

+78
-3
lines changed

1 file changed

+78
-3
lines changed

src/modules/ecdh/tests_impl.h

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ static int ecdh_hash_function_test_fail(unsigned char *output, const unsigned ch
1515
return 0;
1616
}
1717

18+
static int ecdh_xonly_hash_function_test_fail(unsigned char *output, const unsigned char *x, void *data) {
19+
(void)output;
20+
(void)x;
21+
(void)data;
22+
return 0;
23+
}
24+
1825
static int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
1926
(void)data;
2027
/* Save x and y as uncompressed public key */
@@ -24,11 +31,19 @@ static int ecdh_hash_function_custom(unsigned char *output, const unsigned char
2431
return 1;
2532
}
2633

34+
static int ecdh_xonly_hash_function_custom(unsigned char *output, const unsigned char *x, void *data) {
35+
(void)data;
36+
/* Output X coordinate. */
37+
memcpy(output, x, 32);
38+
return 1;
39+
}
40+
2741
static void test_ecdh_api(void) {
2842
/* Setup context that just counts errors */
2943
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
3044
secp256k1_pubkey point;
3145
unsigned char res[32];
46+
unsigned char x32[32];
3247
unsigned char s_one[32] = { 0 };
3348
int32_t ecount = 0;
3449
s_one[31] = 1;
@@ -37,7 +52,7 @@ static void test_ecdh_api(void) {
3752
secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount);
3853
CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
3954

40-
/* Check all NULLs are detected */
55+
/* Check all NULLs are detected by secp256k1_ecdh. */
4156
CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
4257
CHECK(ecount == 0);
4358
CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0);
@@ -49,16 +64,36 @@ static void test_ecdh_api(void) {
4964
CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
5065
CHECK(ecount == 3);
5166

67+
/* And the same for secp256k1_ecdh_xonly. */
68+
memset(x32, 131, 32); /* sum(131*256^j, j=0..31) is a valid x coordinate. */
69+
CHECK(secp256k1_ecdh_xonly(tctx, res, x32, s_one, NULL, NULL) == 1);
70+
CHECK(ecount == 3);
71+
CHECK(secp256k1_ecdh_xonly(tctx, NULL, x32, s_one, NULL, NULL) == 0);
72+
CHECK(ecount == 4);
73+
CHECK(secp256k1_ecdh_xonly(tctx, res, NULL, s_one, NULL, NULL) == 0);
74+
CHECK(ecount == 5);
75+
CHECK(secp256k1_ecdh_xonly(tctx, res, x32, NULL, NULL, NULL) == 0);
76+
CHECK(ecount == 6);
77+
CHECK(secp256k1_ecdh_xonly(tctx, res, x32, s_one, NULL, NULL) == 1);
78+
CHECK(ecount == 6);
79+
memset(x32, 205, 32); /* sum(205*256^j, j=0..31) is not a valid x coordinate. */
80+
CHECK(secp256k1_ecdh_xonly(tctx, res, x32, s_one, NULL, NULL) == 0);
81+
CHECK(ecount == 6);
82+
5283
/* Cleanup */
5384
secp256k1_context_destroy(tctx);
5485
}
5586

5687
static void test_ecdh_generator_basepoint(void) {
5788
unsigned char s_one[32] = { 0 };
89+
unsigned char x32_g[32];
5890
secp256k1_pubkey point[2];
5991
int i;
6092

6193
s_one[31] = 1;
94+
CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1);
95+
secp256k1_fe_get_b32(x32_g, &secp256k1_ge_const_g.x);
96+
6297
/* Check against pubkey creation when the basepoint is the generator */
6398
for (i = 0; i < 2 * COUNT; ++i) {
6499
secp256k1_sha256 sha;
@@ -72,7 +107,6 @@ static void test_ecdh_generator_basepoint(void) {
72107
random_scalar_order(&s);
73108
secp256k1_scalar_get_b32(s_b32, &s);
74109

75-
CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1);
76110
CHECK(secp256k1_ec_pubkey_create(CTX, &point[1], s_b32) == 1);
77111

78112
/* compute using ECDH function with custom hash function */
@@ -82,6 +116,11 @@ static void test_ecdh_generator_basepoint(void) {
82116
/* compare */
83117
CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0);
84118

119+
/* Do the same with x-only ECDH. */
120+
CHECK(secp256k1_ecdh_xonly(CTX, output_ecdh, x32_g, s_b32, ecdh_xonly_hash_function_custom, NULL) == 1);
121+
/* compare */
122+
CHECK(secp256k1_memcmp_var(output_ecdh, point_ser + 1, 32) == 0);
123+
85124
/* compute using ECDH function with default hash function */
86125
CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, NULL, NULL) == 1);
87126
/* compute "explicitly" */
@@ -91,6 +130,15 @@ static void test_ecdh_generator_basepoint(void) {
91130
secp256k1_sha256_finalize(&sha, output_ser);
92131
/* compare */
93132
CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0);
133+
134+
/* And the same with x-only ECDH. */
135+
CHECK(secp256k1_ecdh_xonly(CTX, output_ecdh, x32_g, s_b32, NULL, NULL) == 1);
136+
/* compute "explicitly" */
137+
secp256k1_sha256_initialize(&sha);
138+
secp256k1_sha256_write(&sha, point_ser +1 , 32);
139+
secp256k1_sha256_finalize(&sha, output_ser);
140+
/* compare */
141+
CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0);
94142
}
95143
}
96144

@@ -104,13 +152,16 @@ static void test_bad_scalar(void) {
104152
};
105153
unsigned char s_rand[32] = { 0 };
106154
unsigned char output[32];
155+
unsigned char point_ser[33];
107156
secp256k1_scalar rand;
108157
secp256k1_pubkey point;
158+
size_t point_ser_len = sizeof(point_ser);
109159

110160
/* Create random point */
111161
random_scalar_order(&rand);
112162
secp256k1_scalar_get_b32(s_rand, &rand);
113163
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_rand) == 1);
164+
CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point, SECP256K1_EC_COMPRESSED) == 1);
114165

115166
/* Try to multiply it by bad values */
116167
CHECK(secp256k1_ecdh(CTX, output, &point, s_zero, NULL, NULL) == 0);
@@ -119,39 +170,63 @@ static void test_bad_scalar(void) {
119170
s_overflow[31] -= 1;
120171
CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 1);
121172

173+
/* And repeat for x-only. */
174+
s_overflow[31] += 1;
175+
CHECK(secp256k1_ecdh_xonly(CTX, output, point_ser + 1, s_zero, NULL, NULL) == 0);
176+
CHECK(secp256k1_ecdh_xonly(CTX, output, point_ser + 1, s_overflow, NULL, NULL) == 0);
177+
s_overflow[31] -= 1;
178+
CHECK(secp256k1_ecdh_xonly(CTX, output, point_ser + 1, s_overflow, NULL, NULL) == 1);
179+
122180
/* Hash function failure results in ecdh failure */
123181
CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
182+
CHECK(secp256k1_ecdh_xonly(CTX, output, point_ser, s_overflow, ecdh_xonly_hash_function_test_fail, NULL) == 0);
124183
}
125184

126185
/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */
127186
static void test_result_basepoint(void) {
128187
secp256k1_pubkey point;
129188
secp256k1_scalar rand;
189+
unsigned char point_ser[33];
190+
unsigned char x32_g[32];
130191
unsigned char s[32];
131192
unsigned char s_inv[32];
132193
unsigned char out[32];
133194
unsigned char out_inv[32];
134195
unsigned char out_base[32];
196+
unsigned char out_base_xonly[32];
197+
size_t point_ser_len;
135198
int i;
136199

137200
unsigned char s_one[32] = { 0 };
138201
s_one[31] = 1;
202+
secp256k1_fe_get_b32(x32_g, &secp256k1_ge_const_g.x);
139203
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1);
140204
CHECK(secp256k1_ecdh(CTX, out_base, &point, s_one, NULL, NULL) == 1);
205+
CHECK(secp256k1_ecdh_xonly(CTX, out_base_xonly, x32_g, s_one, NULL, NULL) == 1);
141206

142207
for (i = 0; i < 2 * COUNT; i++) {
143208
random_scalar_order(&rand);
144209
secp256k1_scalar_get_b32(s, &rand);
145-
secp256k1_scalar_inverse(&rand, &rand);
210+
secp256k1_scalar_inverse_var(&rand, &rand);
146211
secp256k1_scalar_get_b32(s_inv, &rand);
147212

148213
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s) == 1);
214+
point_ser_len = sizeof(point_ser);
215+
CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point, SECP256K1_EC_COMPRESSED));
216+
149217
CHECK(secp256k1_ecdh(CTX, out, &point, s_inv, NULL, NULL) == 1);
150218
CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0);
219+
CHECK(secp256k1_ecdh_xonly(CTX, out, point_ser + 1, s_inv, NULL, NULL) == 1);
220+
CHECK(secp256k1_memcmp_var(out, out_base_xonly, 32) == 0);
151221

152222
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_inv) == 1);
153223
CHECK(secp256k1_ecdh(CTX, out_inv, &point, s, NULL, NULL) == 1);
224+
point_ser_len = sizeof(point_ser);
225+
CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point, SECP256K1_EC_COMPRESSED));
226+
154227
CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0);
228+
CHECK(secp256k1_ecdh_xonly(CTX, out_inv, point_ser + 1, s, NULL, NULL) == 1);
229+
CHECK(secp256k1_memcmp_var(out_inv, out_base_xonly, 32) == 0);
155230
}
156231
}
157232

0 commit comments

Comments
 (0)