Skip to content

Commit 0e8602c

Browse files
committed
Add X-only ECDH unit tests
1 parent b62b7b7 commit 0e8602c

File tree

1 file changed

+71
-2
lines changed

1 file changed

+71
-2
lines changed

src/modules/ecdh/tests_impl.h

Lines changed: 71 additions & 2 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,9 +31,17 @@ 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
secp256k1_pubkey point;
2943
unsigned char res[32];
44+
unsigned char x32[32];
3045
unsigned char s_one[32] = { 0 };
3146
s_one[31] = 1;
3247

@@ -38,14 +53,28 @@ static void test_ecdh_api(void) {
3853
CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, NULL, s_one, NULL, NULL));
3954
CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, &point, NULL, NULL, NULL));
4055
CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1);
56+
57+
/* And the same for secp256k1_ecdh_xonly. */
58+
memset(x32, 131, 32); /* sum(131*256^j, j=0..31) is a valid x coordinate. */
59+
CHECK(secp256k1_ecdh_xonly(CTX, res, x32, s_one, NULL, NULL) == 1);
60+
CHECK_ILLEGAL(CTX, secp256k1_ecdh_xonly(CTX, NULL, x32, s_one, NULL, NULL));
61+
CHECK_ILLEGAL(CTX, secp256k1_ecdh_xonly(CTX, res, NULL, s_one, NULL, NULL));
62+
CHECK_ILLEGAL(CTX, secp256k1_ecdh_xonly(CTX, res, x32, NULL, NULL, NULL));
63+
CHECK(secp256k1_ecdh_xonly(CTX, res, x32, s_one, NULL, NULL) == 1);
64+
memset(x32, 205, 32); /* sum(205*256^j, j=0..31) is not a valid x coordinate. */
65+
CHECK(secp256k1_ecdh_xonly(CTX, res, x32, s_one, NULL, NULL) == 0);
4166
}
4267

4368
static void test_ecdh_generator_basepoint(void) {
4469
unsigned char s_one[32] = { 0 };
70+
unsigned char x32_g[32];
4571
secp256k1_pubkey point[2];
4672
int i;
4773

4874
s_one[31] = 1;
75+
CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1);
76+
secp256k1_fe_get_b32(x32_g, &secp256k1_ge_const_g.x);
77+
4978
/* Check against pubkey creation when the basepoint is the generator */
5079
for (i = 0; i < 2 * COUNT; ++i) {
5180
secp256k1_sha256 sha;
@@ -59,7 +88,6 @@ static void test_ecdh_generator_basepoint(void) {
5988
random_scalar_order(&s);
6089
secp256k1_scalar_get_b32(s_b32, &s);
6190

62-
CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1);
6391
CHECK(secp256k1_ec_pubkey_create(CTX, &point[1], s_b32) == 1);
6492

6593
/* compute using ECDH function with custom hash function */
@@ -69,6 +97,11 @@ static void test_ecdh_generator_basepoint(void) {
6997
/* compare */
7098
CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0);
7199

100+
/* Do the same with x-only ECDH. */
101+
CHECK(secp256k1_ecdh_xonly(CTX, output_ecdh, x32_g, s_b32, ecdh_xonly_hash_function_custom, NULL) == 1);
102+
/* compare */
103+
CHECK(secp256k1_memcmp_var(output_ecdh, point_ser + 1, 32) == 0);
104+
72105
/* compute using ECDH function with default hash function */
73106
CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, NULL, NULL) == 1);
74107
/* compute "explicitly" */
@@ -78,6 +111,15 @@ static void test_ecdh_generator_basepoint(void) {
78111
secp256k1_sha256_finalize(&sha, output_ser);
79112
/* compare */
80113
CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0);
114+
115+
/* And the same with x-only ECDH. */
116+
CHECK(secp256k1_ecdh_xonly(CTX, output_ecdh, x32_g, s_b32, NULL, NULL) == 1);
117+
/* compute "explicitly" */
118+
secp256k1_sha256_initialize(&sha);
119+
secp256k1_sha256_write(&sha, point_ser +1 , 32);
120+
secp256k1_sha256_finalize(&sha, output_ser);
121+
/* compare */
122+
CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0);
81123
}
82124
}
83125

@@ -91,13 +133,16 @@ static void test_bad_scalar(void) {
91133
};
92134
unsigned char s_rand[32] = { 0 };
93135
unsigned char output[32];
136+
unsigned char point_ser[33];
94137
secp256k1_scalar rand;
95138
secp256k1_pubkey point;
139+
size_t point_ser_len = sizeof(point_ser);
96140

97141
/* Create random point */
98142
random_scalar_order(&rand);
99143
secp256k1_scalar_get_b32(s_rand, &rand);
100144
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_rand) == 1);
145+
CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point, SECP256K1_EC_COMPRESSED) == 1);
101146

102147
/* Try to multiply it by bad values */
103148
CHECK(secp256k1_ecdh(CTX, output, &point, s_zero, NULL, NULL) == 0);
@@ -106,39 +151,63 @@ static void test_bad_scalar(void) {
106151
s_overflow[31] -= 1;
107152
CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 1);
108153

154+
/* And repeat for x-only. */
155+
s_overflow[31] += 1;
156+
CHECK(secp256k1_ecdh_xonly(CTX, output, point_ser + 1, s_zero, NULL, NULL) == 0);
157+
CHECK(secp256k1_ecdh_xonly(CTX, output, point_ser + 1, s_overflow, NULL, NULL) == 0);
158+
s_overflow[31] -= 1;
159+
CHECK(secp256k1_ecdh_xonly(CTX, output, point_ser + 1, s_overflow, NULL, NULL) == 1);
160+
109161
/* Hash function failure results in ecdh failure */
110162
CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
163+
CHECK(secp256k1_ecdh_xonly(CTX, output, point_ser, s_overflow, ecdh_xonly_hash_function_test_fail, NULL) == 0);
111164
}
112165

113166
/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */
114167
static void test_result_basepoint(void) {
115168
secp256k1_pubkey point;
116169
secp256k1_scalar rand;
170+
unsigned char point_ser[33];
171+
unsigned char x32_g[32];
117172
unsigned char s[32];
118173
unsigned char s_inv[32];
119174
unsigned char out[32];
120175
unsigned char out_inv[32];
121176
unsigned char out_base[32];
177+
unsigned char out_base_xonly[32];
178+
size_t point_ser_len;
122179
int i;
123180

124181
unsigned char s_one[32] = { 0 };
125182
s_one[31] = 1;
183+
secp256k1_fe_get_b32(x32_g, &secp256k1_ge_const_g.x);
126184
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1);
127185
CHECK(secp256k1_ecdh(CTX, out_base, &point, s_one, NULL, NULL) == 1);
186+
CHECK(secp256k1_ecdh_xonly(CTX, out_base_xonly, x32_g, s_one, NULL, NULL) == 1);
128187

129188
for (i = 0; i < 2 * COUNT; i++) {
130189
random_scalar_order(&rand);
131190
secp256k1_scalar_get_b32(s, &rand);
132-
secp256k1_scalar_inverse(&rand, &rand);
191+
secp256k1_scalar_inverse_var(&rand, &rand);
133192
secp256k1_scalar_get_b32(s_inv, &rand);
134193

135194
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s) == 1);
195+
point_ser_len = sizeof(point_ser);
196+
CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point, SECP256K1_EC_COMPRESSED));
197+
136198
CHECK(secp256k1_ecdh(CTX, out, &point, s_inv, NULL, NULL) == 1);
137199
CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0);
200+
CHECK(secp256k1_ecdh_xonly(CTX, out, point_ser + 1, s_inv, NULL, NULL) == 1);
201+
CHECK(secp256k1_memcmp_var(out, out_base_xonly, 32) == 0);
138202

139203
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_inv) == 1);
140204
CHECK(secp256k1_ecdh(CTX, out_inv, &point, s, NULL, NULL) == 1);
205+
point_ser_len = sizeof(point_ser);
206+
CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point, SECP256K1_EC_COMPRESSED));
207+
141208
CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0);
209+
CHECK(secp256k1_ecdh_xonly(CTX, out_inv, point_ser + 1, s, NULL, NULL) == 1);
210+
CHECK(secp256k1_memcmp_var(out_inv, out_base_xonly, 32) == 0);
142211
}
143212
}
144213

0 commit comments

Comments
 (0)