Branch-free point addition
This commit is contained in:
parent
ef6f677679
commit
9338dbf791
|
@ -109,10 +109,7 @@ void static secp256k1_ecmult_gen(secp256k1_gej_t *r, const secp256k1_scalar_t *g
|
|||
bits = secp256k1_scalar_get_bits(gn, j * 4, 4);
|
||||
for (int k=0; k<sizeof(secp256k1_ge_t); k++)
|
||||
((unsigned char*)(&add))[k] = c->prec[j][k][bits];
|
||||
// Note that the next line uses a variable-time addition function, which
|
||||
// is fine, as the inputs are blinded (they have no known corresponding
|
||||
// private key).
|
||||
secp256k1_gej_add_ge_var(r, r, &add);
|
||||
secp256k1_gej_add_ge(r, r, &add);
|
||||
}
|
||||
bits = 0;
|
||||
secp256k1_ge_clear(&add);
|
||||
|
|
|
@ -96,8 +96,12 @@ void static secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *
|
|||
/** Set r equal to the sum of a and b. */
|
||||
void static secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b);
|
||||
|
||||
/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */
|
||||
void static secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b);
|
||||
|
||||
/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient
|
||||
than secp256k1_gej_add. */
|
||||
than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time
|
||||
guarantee, and b is allowed to be infinity. */
|
||||
void static secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b);
|
||||
|
||||
/** Get a hex representation of a point. *rlen will be overwritten with the real length. */
|
||||
|
|
|
@ -108,6 +108,9 @@ void static secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t r[len], cons
|
|||
|
||||
void static secp256k1_gej_set_infinity(secp256k1_gej_t *r) {
|
||||
r->infinity = 1;
|
||||
secp256k1_fe_set_int(&r->x, 0);
|
||||
secp256k1_fe_set_int(&r->y, 0);
|
||||
secp256k1_fe_set_int(&r->z, 0);
|
||||
}
|
||||
|
||||
void static secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) {
|
||||
|
@ -322,6 +325,79 @@ void static secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *
|
|||
secp256k1_fe_add(&r->y, &h3);
|
||||
}
|
||||
|
||||
void static secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) {
|
||||
VERIFY_CHECK(!b->infinity);
|
||||
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
|
||||
|
||||
// In:
|
||||
// Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks.
|
||||
// In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002.
|
||||
// we find as solution for a unified addition/doubling formula:
|
||||
// lambda = ((x1 + x2)^2 - x1 * x2 + a) / (y1 + y2), with a = 0 for secp256k1's curve equation.
|
||||
// x3 = lambda^2 - (x1 + x2)
|
||||
// 2*y3 = lambda * (x1 + x2 - 2 * x3) - (y1 + y2).
|
||||
//
|
||||
// Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives:
|
||||
// U1 = X1*Z2^2, U2 = X2*Z1^2
|
||||
// S1 = X1*Z2^3, S2 = X2*Z2^3
|
||||
// Z = Z1*Z2
|
||||
// T = U1+U2
|
||||
// M = S1+S2
|
||||
// Q = T*M^2
|
||||
// R = T^2-U1*U2
|
||||
// X3 = 4*(R^2-Q)
|
||||
// Y3 = 4*(R*(3*Q-2*R^2)-M^4)
|
||||
// Z3 = 2*M*Z
|
||||
// (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.)
|
||||
|
||||
secp256k1_fe_t zz; secp256k1_fe_sqr(&zz, &a->z); // z = Z1^2
|
||||
secp256k1_fe_t u1 = a->x; secp256k1_fe_normalize(&u1); // u1 = U1 = X1*Z2^2 (1)
|
||||
secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &zz); // u2 = U2 = X2*Z1^2 (1)
|
||||
secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize(&s1); // s1 = S1 = Y1*Z2^3 (1)
|
||||
secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &zz); // s2 = Y2*Z2^2 (1)
|
||||
secp256k1_fe_mul(&s2, &s2, &a->z); // s2 = S2 = Y2*Z1^3 (1)
|
||||
secp256k1_fe_t z = a->z; // z = Z = Z1*Z2 (8)
|
||||
secp256k1_fe_t t = u1; secp256k1_fe_add(&t, &u2); // t = T = U1+U2 (2)
|
||||
secp256k1_fe_t m = s1; secp256k1_fe_add(&m, &s2); // m = M = S1+S2 (2)
|
||||
secp256k1_fe_t n; secp256k1_fe_sqr(&n, &m); // n = M^2 (1)
|
||||
secp256k1_fe_t q; secp256k1_fe_mul(&q, &n, &t); // q = Q = T*M^2 (1)
|
||||
secp256k1_fe_sqr(&n, &n); // n = M^4 (1)
|
||||
secp256k1_fe_negate(&n, &n, 1); // n = -M^4 (2)
|
||||
secp256k1_fe_t rr; secp256k1_fe_sqr(&rr, &t); // rr = T^2 (1)
|
||||
secp256k1_fe_mul(&t, &u1, &u2); secp256k1_fe_negate(&t, &t, 1); // t = -U1*U2 (2)
|
||||
secp256k1_fe_add(&rr, &t); // rr = R = T^2-U1*U2 (3)
|
||||
secp256k1_fe_sqr(&t, &rr); // t = R^2 (1)
|
||||
secp256k1_fe_mul(&r->z, &m, &z); // r->z = M*Z (1)
|
||||
secp256k1_fe_normalize(&r->z);
|
||||
int infinity = secp256k1_fe_is_zero(&r->z) * (1 - a->infinity);
|
||||
secp256k1_fe_mul_int(&r->z, 2 * (1 - a->infinity)); // r->z = Z3 = 2*M*Z (2)
|
||||
r->x = t; // r->x = R^2 (1)
|
||||
r->y = q; secp256k1_fe_mul_int(&r->y, 3); // r->y = 3*Q (3)
|
||||
secp256k1_fe_negate(&q, &q, 1); // q = -Q (2)
|
||||
secp256k1_fe_negate(&t, &t, 1); // t = -R^2 (2)
|
||||
secp256k1_fe_mul_int(&t, 2); // t = -2*R^2 (4)
|
||||
secp256k1_fe_add(&r->x, &q); // r->x = R^2-Q (3)
|
||||
secp256k1_fe_normalize(&r->x);
|
||||
secp256k1_fe_add(&r->y, &t); // r->y = 3*Q-2*R^2
|
||||
secp256k1_fe_mul(&r->y, &r->y, &rr); // r->y = R*(3*Q-2*R^2) (1)
|
||||
secp256k1_fe_add(&r->y, &n); // r->y = R*(3*Q-2*R^2)-M^4 (3)
|
||||
secp256k1_fe_normalize(&r->y);
|
||||
secp256k1_fe_mul_int(&r->x, 4 * (1 - a->infinity)); // r->x = X3 = 4*(R^2-Q)
|
||||
secp256k1_fe_mul_int(&r->y, 4 * (1 - a->infinity)); // r->y = Y3 = 4*R*(3*Q-2*R^2)-4*M^4 (4)
|
||||
|
||||
// In case a->infinity == 1, the above code results in r->x, r->y, and r->z all equal to 0.
|
||||
// Add b->x to x, b->y to y, and 1 to z in that case.
|
||||
t = b->x; secp256k1_fe_mul_int(&t, a->infinity);
|
||||
secp256k1_fe_add(&r->x, &t);
|
||||
t = b->y; secp256k1_fe_mul_int(&t, a->infinity);
|
||||
secp256k1_fe_add(&r->y, &t);
|
||||
secp256k1_fe_set_int(&t, a->infinity);
|
||||
secp256k1_fe_add(&r->z, &t);
|
||||
r->infinity = infinity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void static secp256k1_gej_get_hex(char *r, int *rlen, const secp256k1_gej_t *a) {
|
||||
secp256k1_gej_t c = *a;
|
||||
secp256k1_ge_t t; secp256k1_ge_set_gej(&t, &c);
|
||||
|
|
148
src/tests.c
148
src/tests.c
|
@ -28,6 +28,51 @@ void random_num_negate(secp256k1_num_t *num) {
|
|||
secp256k1_num_negate(num);
|
||||
}
|
||||
|
||||
void random_field_element_test(secp256k1_fe_t *fe) {
|
||||
do {
|
||||
unsigned char b32[32];
|
||||
secp256k1_rand256_test(b32);
|
||||
secp256k1_num_t num;
|
||||
secp256k1_num_set_bin(&num, b32, 32);
|
||||
if (secp256k1_num_cmp(&num, &secp256k1_fe_consts->p) >= 0)
|
||||
continue;
|
||||
secp256k1_fe_set_b32(fe, b32);
|
||||
break;
|
||||
} while(1);
|
||||
}
|
||||
|
||||
void random_field_element_magnitude(secp256k1_fe_t *fe) {
|
||||
secp256k1_fe_normalize(fe);
|
||||
int n = secp256k1_rand32() % 4;
|
||||
for (int i = 0; i < n; i++) {
|
||||
secp256k1_fe_negate(fe, fe, 1 + 2*i);
|
||||
secp256k1_fe_negate(fe, fe, 2 + 2*i);
|
||||
}
|
||||
}
|
||||
|
||||
void random_group_element_test(secp256k1_ge_t *ge) {
|
||||
secp256k1_fe_t fe;
|
||||
do {
|
||||
random_field_element_test(&fe);
|
||||
if (secp256k1_ge_set_xo(ge, &fe, secp256k1_rand32() & 1))
|
||||
break;
|
||||
} while(1);
|
||||
}
|
||||
|
||||
void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge_t *ge) {
|
||||
do {
|
||||
random_field_element_test(&gej->z);
|
||||
if (!secp256k1_fe_is_zero(&gej->z)) {
|
||||
break;
|
||||
}
|
||||
} while(1);
|
||||
secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &gej->z);
|
||||
secp256k1_fe_t z3; secp256k1_fe_mul(&z3, &z2, &gej->z);
|
||||
secp256k1_fe_mul(&gej->x, &ge->x, &z2);
|
||||
secp256k1_fe_mul(&gej->y, &ge->y, &z3);
|
||||
gej->infinity = ge->infinity;
|
||||
}
|
||||
|
||||
void random_num_order_test(secp256k1_num_t *num) {
|
||||
do {
|
||||
unsigned char b32[32];
|
||||
|
@ -546,6 +591,106 @@ void run_sqrt() {
|
|||
}
|
||||
}
|
||||
|
||||
/***** GROUP TESTS *****/
|
||||
|
||||
int ge_equals_ge(const secp256k1_ge_t *a, const secp256k1_ge_t *b) {
|
||||
if (a->infinity && b->infinity)
|
||||
return 1;
|
||||
return check_fe_equal(&a->x, &b->x) && check_fe_equal(&a->y, &b->y);
|
||||
}
|
||||
|
||||
void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) {
|
||||
secp256k1_ge_t bb;
|
||||
secp256k1_gej_t bj = *b;
|
||||
secp256k1_ge_set_gej_var(&bb, &bj);
|
||||
CHECK(ge_equals_ge(a, &bb));
|
||||
}
|
||||
|
||||
void gej_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) {
|
||||
secp256k1_ge_t aa, bb;
|
||||
secp256k1_gej_t aj = *a, bj = *b;
|
||||
secp256k1_ge_set_gej_var(&aa, &aj);
|
||||
secp256k1_ge_set_gej_var(&bb, &bj);
|
||||
CHECK(ge_equals_ge(&aa, &bb));
|
||||
}
|
||||
|
||||
void test_ge() {
|
||||
secp256k1_ge_t a, b, i, n;
|
||||
random_group_element_test(&a);
|
||||
random_group_element_test(&b);
|
||||
n = a;
|
||||
secp256k1_fe_normalize(&a.y);
|
||||
secp256k1_fe_negate(&n.y, &a.y, 1);
|
||||
secp256k1_ge_set_infinity(&i);
|
||||
random_field_element_magnitude(&a.x);
|
||||
random_field_element_magnitude(&a.y);
|
||||
random_field_element_magnitude(&b.x);
|
||||
random_field_element_magnitude(&b.y);
|
||||
random_field_element_magnitude(&n.x);
|
||||
random_field_element_magnitude(&n.y);
|
||||
|
||||
secp256k1_gej_t aj, bj, ij, nj;
|
||||
random_group_element_jacobian_test(&aj, &a);
|
||||
random_group_element_jacobian_test(&bj, &b);
|
||||
secp256k1_gej_set_infinity(&ij);
|
||||
random_group_element_jacobian_test(&nj, &n);
|
||||
random_field_element_magnitude(&aj.x);
|
||||
random_field_element_magnitude(&aj.y);
|
||||
random_field_element_magnitude(&aj.z);
|
||||
random_field_element_magnitude(&bj.x);
|
||||
random_field_element_magnitude(&bj.y);
|
||||
random_field_element_magnitude(&bj.z);
|
||||
random_field_element_magnitude(&nj.x);
|
||||
random_field_element_magnitude(&nj.y);
|
||||
random_field_element_magnitude(&nj.z);
|
||||
|
||||
// gej + gej adds
|
||||
secp256k1_gej_t aaj; secp256k1_gej_add_var(&aaj, &aj, &aj);
|
||||
secp256k1_gej_t abj; secp256k1_gej_add_var(&abj, &aj, &bj);
|
||||
secp256k1_gej_t aij; secp256k1_gej_add_var(&aij, &aj, &ij);
|
||||
secp256k1_gej_t anj; secp256k1_gej_add_var(&anj, &aj, &nj);
|
||||
secp256k1_gej_t iaj; secp256k1_gej_add_var(&iaj, &ij, &aj);
|
||||
secp256k1_gej_t iij; secp256k1_gej_add_var(&iij, &ij, &ij);
|
||||
|
||||
// gej + ge adds
|
||||
secp256k1_gej_t aa; secp256k1_gej_add_ge_var(&aa, &aj, &a);
|
||||
secp256k1_gej_t ab; secp256k1_gej_add_ge_var(&ab, &aj, &b);
|
||||
secp256k1_gej_t ai; secp256k1_gej_add_ge_var(&ai, &aj, &i);
|
||||
secp256k1_gej_t an; secp256k1_gej_add_ge_var(&an, &aj, &n);
|
||||
secp256k1_gej_t ia; secp256k1_gej_add_ge_var(&ia, &ij, &a);
|
||||
secp256k1_gej_t ii; secp256k1_gej_add_ge_var(&ii, &ij, &i);
|
||||
|
||||
// const gej + ge adds
|
||||
secp256k1_gej_t aac; secp256k1_gej_add_ge(&aac, &aj, &a);
|
||||
secp256k1_gej_t abc; secp256k1_gej_add_ge(&abc, &aj, &b);
|
||||
secp256k1_gej_t anc; secp256k1_gej_add_ge(&anc, &aj, &n);
|
||||
secp256k1_gej_t iac; secp256k1_gej_add_ge(&iac, &ij, &a);
|
||||
|
||||
CHECK(secp256k1_gej_is_infinity(&an));
|
||||
CHECK(secp256k1_gej_is_infinity(&anj));
|
||||
CHECK(secp256k1_gej_is_infinity(&anc));
|
||||
gej_equals_gej(&aa, &aaj);
|
||||
gej_equals_gej(&aa, &aac);
|
||||
gej_equals_gej(&ab, &abj);
|
||||
gej_equals_gej(&ab, &abc);
|
||||
gej_equals_gej(&an, &anj);
|
||||
gej_equals_gej(&an, &anc);
|
||||
gej_equals_gej(&ia, &iaj);
|
||||
gej_equals_gej(&ai, &aij);
|
||||
gej_equals_gej(&ii, &iij);
|
||||
ge_equals_gej(&a, &ai);
|
||||
ge_equals_gej(&a, &ai);
|
||||
ge_equals_gej(&a, &iaj);
|
||||
ge_equals_gej(&a, &iaj);
|
||||
ge_equals_gej(&a, &iac);
|
||||
}
|
||||
|
||||
void run_ge() {
|
||||
for (int i = 0; i < 2000*count; i++) {
|
||||
test_ge();
|
||||
}
|
||||
}
|
||||
|
||||
/***** ECMULT TESTS *****/
|
||||
|
||||
void run_ecmult_chain() {
|
||||
|
@ -879,6 +1024,9 @@ int main(int argc, char **argv) {
|
|||
run_sqr();
|
||||
run_sqrt();
|
||||
|
||||
// group tests
|
||||
run_ge();
|
||||
|
||||
// ecmult tests
|
||||
run_wnaf();
|
||||
run_point_times_order();
|
||||
|
|
Loading…
Reference in New Issue