Skip to content

Commit 3ebb897

Browse files
committed
Expose API for constant time point multiplication
1 parent d4a3c09 commit 3ebb897

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 elliptic 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
@@ -1314,6 +1314,51 @@ void run_ecdh_tests(void) {
13141314
ecdh_commutativity();
13151315
}
13161316

1317+
void run_ecdh_api_tests(void) {
1318+
const unsigned char scalar[] = {0x49, 0x68, 0xd5, 0x24, 0x2a, 0xbf, 0x9b, 0x7a,
1319+
0x46, 0x6a, 0xbb, 0xcf, 0x34, 0xb1, 0x1b, 0x6d,
1320+
0xcd, 0x83, 0xd3, 0x07, 0x82, 0x7b, 0xed, 0x62,
1321+
0x05, 0xfa, 0xd0, 0xce, 0x18, 0xfa, 0xe6, 0x3b};
1322+
const unsigned char expected_uncomp[] = {
1323+
0x04,
1324+
/* x */
1325+
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
1326+
0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd,
1327+
0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb,
1328+
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f,
1329+
/* y */
1330+
0x5d, 0x19, 0x5d, 0x20, 0xe1, 0x91, 0xbf, 0x7f,
1331+
0x1b, 0xe3, 0xe5, 0x5f, 0x56, 0xa8, 0x01, 0x96,
1332+
0x60, 0x71, 0xad, 0x01, 0xf1, 0x46, 0x2f, 0x66,
1333+
0xc9, 0x97, 0xfa, 0x94, 0xdb, 0x85, 0x84, 0x35
1334+
};
1335+
const unsigned char expected_comp[] = {
1336+
/* y */
1337+
0x03,
1338+
/* x */
1339+
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
1340+
0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd,
1341+
0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb,
1342+
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
1343+
};
1344+
unsigned char point[65];
1345+
int pointlen = sizeof(point);
1346+
secp256k1_ge_t gen = secp256k1_ge_const_g;
1347+
int i;
1348+
/* uncompressed */
1349+
secp256k1_eckey_pubkey_serialize(&gen, point, &pointlen, 0);
1350+
for (i = 0; i < 100; ++i) {
1351+
CHECK(secp256k1_point_multiply(point, &pointlen, scalar) == 1);
1352+
}
1353+
CHECK(memcmp(point, expected_uncomp, 65) == 0);
1354+
/* compressed */
1355+
secp256k1_eckey_pubkey_serialize(&gen, point, &pointlen, 1);
1356+
for (i = 0; i < 100; ++i) {
1357+
CHECK(secp256k1_point_multiply(point, &pointlen, scalar) == 1);
1358+
}
1359+
CHECK(memcmp(point, expected_comp, 33) == 0);
1360+
}
1361+
13171362
/***** ECMULT TESTS *****/
13181363

13191364
void run_ecmult_chain(void) {
@@ -2409,6 +2454,7 @@ int main(int argc, char **argv) {
24092454

24102455
/* ecdh tests */
24112456
run_ecdh_tests();
2457+
run_ecdh_api_tests();
24122458

24132459
/* ecdsa tests */
24142460
run_random_pubkeys();

0 commit comments

Comments
 (0)