Skip to content

Commit b94f321

Browse files
committed
Expose API for constant time point multiplication
1 parent afa4408 commit b94f321

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed

include/secp256k1.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,24 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact(
217217
int recid
218218
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
219219

220+
221+
/** Do an ellitic curve scalar multiplication in constant time.
222+
* Returns: 1: exponentiation was successful
223+
* -1: scalar was zero (cannot serialize output point)
224+
* -2: scalar overflow
225+
* -3: invalid input point
226+
* In: scalar: a 32-byte scalar with which to multiple the point
227+
* In/Out: point: pointer to 33 or 65 byte array containing an EC point
228+
* which will be updated in place
229+
* pointlen: length of the point array, which will be updated by
230+
* the multiplication
231+
*/
232+
SECP256K1_WARN_UNUSED_RESULT int secp256k1_point_multiply(
233+
unsigned char *point,
234+
int *pointlen,
235+
const unsigned char *scalar
236+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
237+
220238
/** Verify an ECDSA secret key.
221239
* Returns: 1: secret key is valid
222240
* 0: secret key is invalid

src/secp256k1.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,32 @@ int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsign
225225
return ret;
226226
}
227227

228+
int secp256k1_point_multiply(unsigned char *point, int *pointlen, const unsigned char *scalar) {
229+
int ret = 0;
230+
int overflow = 0;
231+
secp256k1_gej_t res;
232+
secp256k1_ge_t pt;
233+
secp256k1_scalar_t s;
234+
DEBUG_CHECK(point != NULL);
235+
DEBUG_CHECK(pointlen != NULL);
236+
DEBUG_CHECK(scalar != NULL);
237+
238+
if (secp256k1_eckey_pubkey_parse(&pt, point, *pointlen)) {
239+
secp256k1_scalar_set_b32(&s, scalar, &overflow);
240+
if (overflow) {
241+
ret = -2;
242+
} else {
243+
secp256k1_ecdh_point_multiply(&res, &pt, &s);
244+
secp256k1_ge_set_gej(&pt, &res);
245+
ret = secp256k1_eckey_pubkey_serialize(&pt, point, pointlen, *pointlen <= 33);
246+
}
247+
} else {
248+
ret = -3;
249+
}
250+
secp256k1_scalar_clear(&s);
251+
return ret;
252+
}
253+
228254
int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) {
229255
secp256k1_scalar_t sec;
230256
int ret;

src/tests.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,6 +1249,51 @@ void run_ecdh_tests(void) {
12491249
ecdh_commutativity();
12501250
}
12511251

1252+
void run_ecdh_api_tests(void) {
1253+
const unsigned char scalar[] = {0x49, 0x68, 0xd5, 0x24, 0x2a, 0xbf, 0x9b, 0x7a,
1254+
0x46, 0x6a, 0xbb, 0xcf, 0x34, 0xb1, 0x1b, 0x6d,
1255+
0xcd, 0x83, 0xd3, 0x07, 0x82, 0x7b, 0xed, 0x62,
1256+
0x05, 0xfa, 0xd0, 0xce, 0x18, 0xfa, 0xe6, 0x3b};
1257+
const unsigned char expected_uncomp[] = {
1258+
0x04,
1259+
/* x */
1260+
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
1261+
0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd,
1262+
0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb,
1263+
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f,
1264+
/* y */
1265+
0x5d, 0x19, 0x5d, 0x20, 0xe1, 0x91, 0xbf, 0x7f,
1266+
0x1b, 0xe3, 0xe5, 0x5f, 0x56, 0xa8, 0x01, 0x96,
1267+
0x60, 0x71, 0xad, 0x01, 0xf1, 0x46, 0x2f, 0x66,
1268+
0xc9, 0x97, 0xfa, 0x94, 0xdb, 0x85, 0x84, 0x35
1269+
};
1270+
const unsigned char expected_comp[] = {
1271+
/* y */
1272+
0x03,
1273+
/* x */
1274+
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
1275+
0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd,
1276+
0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb,
1277+
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
1278+
};
1279+
unsigned char point[65];
1280+
int pointlen = sizeof(point);
1281+
secp256k1_ge_t gen = secp256k1_ge_const_g;
1282+
int i;
1283+
/* uncompressed */
1284+
secp256k1_eckey_pubkey_serialize(&gen, point, &pointlen, 0);
1285+
for (i = 0; i < 100; ++i) {
1286+
CHECK(secp256k1_point_multiply(point, &pointlen, scalar) == 1);
1287+
}
1288+
CHECK(memcmp(point, expected_uncomp, 65) == 0);
1289+
/* compressed */
1290+
secp256k1_eckey_pubkey_serialize(&gen, point, &pointlen, 1);
1291+
for (i = 0; i < 100; ++i) {
1292+
CHECK(secp256k1_point_multiply(point, &pointlen, scalar) == 1);
1293+
}
1294+
CHECK(memcmp(point, expected_comp, 33) == 0);
1295+
}
1296+
12521297
/***** ECMULT TESTS *****/
12531298

12541299
void run_ecmult_chain(void) {
@@ -2299,6 +2344,7 @@ int main(int argc, char **argv) {
22992344

23002345
/* ecdh tests */
23012346
run_ecdh_tests();
2347+
run_ecdh_api_tests();
23022348

23032349
/* ecdsa tests */
23042350
run_random_pubkeys();

0 commit comments

Comments
 (0)