diff --git a/.travis.yml b/.travis.yml index 12692deafa..3a85e8cba0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ env: - FIELD=32bit - FIELD=32bit ENDOMORPHISM=yes - BIGNUM=none + - BIGNUM=none ENDOMORPHISM=yes - BUILD=distcheck - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC before_script: ./autogen.sh diff --git a/configure.ac b/configure.ac index f0d69f93de..6e6fccd7fd 100644 --- a/configure.ac +++ b/configure.ac @@ -270,10 +270,7 @@ if test x"$set_field" = x"gmp" || test x"$set_bignum" = x"gmp"; then fi if test x"$use_endomorphism" = x"yes"; then - if test x"$set_bignum" = x"none"; then - AC_MSG_ERROR([Cannot use endomorphism optimization without a bignum implementation]) - fi - AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism]) + AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) fi AC_MSG_NOTICE([Using field implementation: $set_field]) diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index bbf731c88a..445b81593f 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -168,10 +168,10 @@ static void secp256k1_ecmult(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_split_lambda_var(&na_1, &na_lam, na); /* build wnaf representation for na_1 and na_lam. */ - int wnaf_na_1[129]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A); - int wnaf_na_lam[129]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A); - VERIFY_CHECK(bits_na_1 <= 129); - VERIFY_CHECK(bits_na_lam <= 129); + int wnaf_na_1[130]; int bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A); + int wnaf_na_lam[130]; int bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A); + VERIFY_CHECK(bits_na_1 <= 130); + VERIFY_CHECK(bits_na_lam <= 130); int bits = bits_na_1; if (bits_na_lam > bits) bits = bits_na_lam; #else diff --git a/src/scalar_impl.h b/src/scalar_impl.h index df7a24e1f8..7fc159df77 100644 --- a/src/scalar_impl.h +++ b/src/scalar_impl.h @@ -29,7 +29,7 @@ typedef struct { secp256k1_num_t order; #endif #ifdef USE_ENDOMORPHISM - secp256k1_num_t a1b2, b1, a2, g1, g2; + secp256k1_scalar_t minus_lambda, minus_b1, minus_b2, g1, g2; #endif } secp256k1_scalar_consts_t; @@ -52,20 +52,30 @@ static void secp256k1_scalar_start(void) { secp256k1_num_set_bin(&ret->order, secp256k1_scalar_consts_order, sizeof(secp256k1_scalar_consts_order)); #endif #ifdef USE_ENDOMORPHISM - static const unsigned char secp256k1_scalar_consts_a1b2[] = { - 0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd, - 0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15 - }; - static const unsigned char secp256k1_scalar_consts_b1[] = { - 0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28, - 0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3 - }; - static const unsigned char secp256k1_scalar_consts_a2[] = { - 0x01, - 0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6, - 0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8 + /** + * Lambda is a scalar which has the property for secp256k1 that point multiplication by + * it is efficiently computable (see secp256k1_gej_mul_lambda). */ + static const unsigned char secp256k1_scalar_consts_lambda[32] = { + 0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0, + 0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, + 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78, + 0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72 }; /** + * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm + * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 + * and k2 have a small size. + * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are: + * + * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} + * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3} + * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8} + * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} + * + * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives + * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and + * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2. + * * g1, g2 are precomputed constants used to replace division with a rounded multiplication * when decomposing the scalar for an endomorphism-based point multiplication. * @@ -82,21 +92,38 @@ static void secp256k1_scalar_start(void) { * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda'). */ - static const unsigned char secp256k1_scalar_consts_g1[] = { - 0x30,0x86, + static const unsigned char secp256k1_scalar_consts_minus_b1[32] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28, + 0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3 + }; + static const unsigned char secp256k1_scalar_consts_b2[32] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd, + 0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15 + }; + static const unsigned char secp256k1_scalar_consts_g1[32] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x86, 0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c, 0x90,0xe4,0x92,0x84,0xeb,0x15,0x3d,0xab }; - static const unsigned char secp256k1_scalar_consts_g2[] = { - 0xe4,0x43, + static const unsigned char secp256k1_scalar_consts_g2[32] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0x43, 0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54, 0x7f,0xa9,0x0a,0xbf,0xe4,0xc4,0x22,0x12 }; - secp256k1_num_set_bin(&ret->a1b2, secp256k1_scalar_consts_a1b2, sizeof(secp256k1_scalar_consts_a1b2)); - secp256k1_num_set_bin(&ret->a2, secp256k1_scalar_consts_a2, sizeof(secp256k1_scalar_consts_a2)); - secp256k1_num_set_bin(&ret->b1, secp256k1_scalar_consts_b1, sizeof(secp256k1_scalar_consts_b1)); - secp256k1_num_set_bin(&ret->g1, secp256k1_scalar_consts_g1, sizeof(secp256k1_scalar_consts_g1)); - secp256k1_num_set_bin(&ret->g2, secp256k1_scalar_consts_g2, sizeof(secp256k1_scalar_consts_g2)); + + secp256k1_scalar_set_b32(&ret->minus_lambda, secp256k1_scalar_consts_lambda, NULL); + secp256k1_scalar_negate(&ret->minus_lambda, &ret->minus_lambda); + secp256k1_scalar_set_b32(&ret->minus_b1, secp256k1_scalar_consts_minus_b1, NULL); + secp256k1_scalar_set_b32(&ret->minus_b2, secp256k1_scalar_consts_b2, NULL); + secp256k1_scalar_negate(&ret->minus_b2, &ret->minus_b2); + secp256k1_scalar_set_b32(&ret->g1, secp256k1_scalar_consts_g1, NULL); + secp256k1_scalar_set_b32(&ret->g2, secp256k1_scalar_consts_g2, NULL); #endif /* Set the global pointer. */ @@ -293,47 +320,16 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_ #ifdef USE_ENDOMORPHISM static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { - unsigned char b[32]; - secp256k1_scalar_get_b32(b, a); - secp256k1_num_t na; - secp256k1_num_set_bin(&na, b, 32); - - secp256k1_num_t rn1, rn2; - - const secp256k1_scalar_consts_t *c = secp256k1_scalar_consts; - secp256k1_num_t d1, d2, t, one; - unsigned char cone[1] = {0x01}; - secp256k1_num_set_bin(&one, cone, 1); - - secp256k1_num_mul(&d1, &na, &c->g1); - secp256k1_num_shift(&d1, 271); - secp256k1_num_add(&d1, &d1, &one); - secp256k1_num_shift(&d1, 1); - - secp256k1_num_mul(&d2, &na, &c->g2); - secp256k1_num_shift(&d2, 271); - secp256k1_num_add(&d2, &d2, &one); - secp256k1_num_shift(&d2, 1); - - secp256k1_num_mul(&t, &d1, &c->a1b2); - secp256k1_num_sub(&rn1, &na, &t); - secp256k1_num_mul(&t, &d2, &c->a2); - secp256k1_num_sub(&rn1, &rn1, &t); - - secp256k1_num_mul(&rn2, &d1, &c->b1); - secp256k1_num_mul(&t, &d2, &c->a1b2); - secp256k1_num_sub(&rn2, &rn2, &t); - - secp256k1_num_get_bin(b, 32, &rn1); - secp256k1_scalar_set_b32(r1, b, NULL); - if (secp256k1_num_is_neg(&rn1)) { - secp256k1_scalar_negate(r1, r1); - } - secp256k1_num_get_bin(b, 32, &rn2); - secp256k1_scalar_set_b32(r2, b, NULL); - if (secp256k1_num_is_neg(&rn2)) { - secp256k1_scalar_negate(r2, r2); - } + VERIFY_CHECK(r1 != a); + VERIFY_CHECK(r2 != a); + secp256k1_scalar_t c1, c2; + secp256k1_scalar_mul_shift_var(&c1, a, &secp256k1_scalar_consts->g1, 272); + secp256k1_scalar_mul_shift_var(&c2, a, &secp256k1_scalar_consts->g2, 272); + secp256k1_scalar_mul(&c1, &c1, &secp256k1_scalar_consts->minus_b1); + secp256k1_scalar_mul(&c2, &c2, &secp256k1_scalar_consts->minus_b2); + secp256k1_scalar_add(r2, &c1, &c2); + secp256k1_scalar_mul(r1, r2, &secp256k1_scalar_consts->minus_lambda); + secp256k1_scalar_add(r1, r1, a); } #endif