Skip to content

Commit

Permalink
Expose API for constant time point multiplication
Browse files Browse the repository at this point in the history
  • Loading branch information
apoelstra committed Jun 29, 2015
1 parent c5d1a9b commit 38b4bf5
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 0 deletions.
18 changes: 18 additions & 0 deletions include/secp256k1.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,24 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact(
int recid
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);


/** Do an elliptic curve scalar multiplication in constant time.
* Returns: 1: exponentiation was successful
* 0: scalar was zero (cannot serialize output point)
* -1: scalar overflow
* -2: invalid input point
* In: scalar: a 32-byte scalar with which to multiply the point
* In/Out: point: pointer to 33 or 65 byte array containing an EC point
* which will be updated in place
* pointlen: length of the point array, which will be updated by
* the multiplication
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh_point_multiply(
unsigned char *point,
int *pointlen,
const unsigned char *scalar
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);

/** Verify an ECDSA secret key.
* Returns: 1: secret key is valid
* 0: secret key is invalid
Expand Down
26 changes: 26 additions & 0 deletions src/secp256k1.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,32 @@ int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsign
return ret;
}

int secp256k1_ecdh_point_multiply(unsigned char *point, int *pointlen, const unsigned char *scalar) {
int ret = 0;
int overflow = 0;
secp256k1_gej_t res;
secp256k1_ge_t pt;
secp256k1_scalar_t s;
DEBUG_CHECK(point != NULL);
DEBUG_CHECK(pointlen != NULL);
DEBUG_CHECK(scalar != NULL);

if (secp256k1_eckey_pubkey_parse(&pt, point, *pointlen)) {
secp256k1_scalar_set_b32(&s, scalar, &overflow);
if (overflow) {
ret = -1;
} else {
secp256k1_point_multiply(&res, &pt, &s);
secp256k1_ge_set_gej(&pt, &res);
ret = secp256k1_eckey_pubkey_serialize(&pt, point, pointlen, *pointlen <= 33);
}
} else {
ret = -2;
}
secp256k1_scalar_clear(&s);
return ret;
}

int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) {
secp256k1_scalar_t sec;
int ret;
Expand Down
69 changes: 69 additions & 0 deletions src/tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -1328,6 +1328,74 @@ void run_ecdh_tests(void) {
ecdh_commutativity();
}

void run_ecdh_api_tests(void) {
/* Check known result (randomly generated test problem from sage) */
const unsigned char scalar[] = {0x49, 0x68, 0xd5, 0x24, 0x2a, 0xbf, 0x9b, 0x7a,
0x46, 0x6a, 0xbb, 0xcf, 0x34, 0xb1, 0x1b, 0x6d,
0xcd, 0x83, 0xd3, 0x07, 0x82, 0x7b, 0xed, 0x62,
0x05, 0xfa, 0xd0, 0xce, 0x18, 0xfa, 0xe6, 0x3b};
const unsigned char expected_uncomp[] = {
0x04,
/* x */
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd,
0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb,
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f,
/* y */
0x5d, 0x19, 0x5d, 0x20, 0xe1, 0x91, 0xbf, 0x7f,
0x1b, 0xe3, 0xe5, 0x5f, 0x56, 0xa8, 0x01, 0x96,
0x60, 0x71, 0xad, 0x01, 0xf1, 0x46, 0x2f, 0x66,
0xc9, 0x97, 0xfa, 0x94, 0xdb, 0x85, 0x84, 0x35
};
const unsigned char expected_comp[] = {
/* y */
0x03,
/* x */
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd,
0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb,
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
};
unsigned char point[65];
unsigned char point2[65];
int pointlen = sizeof(point);
int point2len = sizeof(point2);
secp256k1_ge_t gen = secp256k1_ge_const_g;
int i;
/* uncompressed */
secp256k1_eckey_pubkey_serialize(&gen, point, &pointlen, 0);
for (i = 0; i < 100; ++i) {
CHECK(secp256k1_ecdh_point_multiply(point, &pointlen, scalar) == 1);
}
CHECK(memcmp(point, expected_uncomp, 65) == 0);
/* compressed */
secp256k1_eckey_pubkey_serialize(&gen, point, &pointlen, 1);
for (i = 0; i < 100; ++i) {
CHECK(secp256k1_ecdh_point_multiply(point, &pointlen, scalar) == 1);
}
CHECK(memcmp(point, expected_comp, 33) == 0);

/* Check against pubkey creation when the basepoint is the generator */
for (i = 0; i < 100; ++i) {
unsigned char s_b32[32];
secp256k1_scalar_t s;
random_scalar_order(&s);
secp256k1_scalar_get_b32(s_b32, &s);
/* uncompressed */
secp256k1_eckey_pubkey_serialize(&gen, point, &pointlen, 0);
secp256k1_eckey_pubkey_serialize(&gen, point2, &point2len, 0);
CHECK(secp256k1_ecdh_point_multiply(point, &pointlen, s_b32) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, point2, &point2len, s_b32, 0) == 1);
CHECK(memcmp(point, point2, 65) == 0);
/* compressed */
secp256k1_eckey_pubkey_serialize(&gen, point, &pointlen, 1);
secp256k1_eckey_pubkey_serialize(&gen, point2, &point2len, 1);
CHECK(secp256k1_ecdh_point_multiply(point, &pointlen, s_b32) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, point2, &point2len, s_b32, 1) == 1);
CHECK(memcmp(point, point2, 33) == 0);
}
}

/***** ECMULT TESTS *****/

void run_ecmult_chain(void) {
Expand Down Expand Up @@ -2423,6 +2491,7 @@ int main(int argc, char **argv) {

/* ecdh tests */
run_ecdh_tests();
run_ecdh_api_tests();

/* ecdsa tests */
run_random_pubkeys();
Expand Down

0 comments on commit 38b4bf5

Please sign in to comment.