Merge bitcoin-core/secp256k1#1299: Infinity handling: ecmult_const(infinity) works, and group verification

bbc834467c5d14e3e53744211e7c4fa9d8fabe41 Avoid secp256k1_ge_set_gej_zinv with uninitialized z (Pieter Wuille)
0a2e0b2ae456c7ae60e92ddc354071f21fb6aa62 Make secp256k1_{fe,ge,gej}_verify work as no-op if non-VERIFY (Pieter Wuille)
f20266722ac93ca66d1beb0d2f2d2469b95aafea Add invariant checking to group elements (Pieter Wuille)
a18821d5b1d44db0e7c8335f338cc9876bec98cb Always initialize output coordinates in secp256k1_ge_set_gej (Pieter Wuille)
3086cb90acd9d61c5b38e862877fdeacaff74a50 Expose secp256k1_fe_verify to other modules (Pieter Wuille)
a0e696fd4da3788758bb3fdae66c7ae262dbf224 Make secp256k1_ecmult_const handle infinity (Gregory Maxwell)

Pull request description:

  Rebase of #791.

  * Clean up infinity handling, make x/y/z always initialized for infinity.
  * Make secp256k1_ecmult_const handle infinity.
    * Infinity isn't currently needed here, but correctly handling it is a little more safe against future changes.
    * Update docs for it to make it clear that it is not constant time in Q. It never was constant time in Q (and would be a little complicated to make constant time in Q: needs a constant time addition function that tracks RZR). It isn't typical for ECDH to be constant time in terms of the pubkey. If it was later made constant time in Q infinity support would be easy to preserve, e.g. by running it on a dummy value and cmoving infinity into the output.
  * Add group verification (`secp256k1_ge_verify` and `secp256k1_gej_verify`, mimicking `secp256k1_fe_verify`).
  * Make the `secp256k1_{fe,ge,gej}_verify` functions also defined (as no-ops) in non-VERIFY mode.

ACKs for top commit:
  jonasnick:
    ACK bbc834467c5d14e3e53744211e7c4fa9d8fabe41
  real-or-random:
    ACK bbc834467c5d14e3e53744211e7c4fa9d8fabe41

Tree-SHA512: 82cb51faa2c207603aa10359a311ea618fcb5a81ba175bf15515bf84043223db6428434875854cdfce9ae95f9cfd68c74e4e415f26bd574f1791b5dec1615d19
This commit is contained in:
Tim Ruffing 2023-05-10 18:43:59 +02:00
commit 341cc19726
No known key found for this signature in database
GPG Key ID: 8C461CCD293F6011
8 changed files with 129 additions and 27 deletions

View File

@ -11,8 +11,7 @@
#include "group.h" #include "group.h"
/** /**
* Multiply: R = q*A (in constant-time) * Multiply: R = q*A (in constant-time for q)
* A must not be infinity.
*/ */
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);

View File

@ -144,6 +144,11 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
int i; int i;
if (secp256k1_ge_is_infinity(a)) {
secp256k1_gej_set_infinity(r);
return;
}
/* build wnaf representation for q. */ /* build wnaf representation for q. */
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar); secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar);

View File

@ -143,4 +143,7 @@ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
/** Determine whether a is a square (modulo p). */ /** Determine whether a is a square (modulo p). */
static int secp256k1_fe_is_square_var(const secp256k1_fe *a); static int secp256k1_fe_is_square_var(const secp256k1_fe *a);
/** Check invariants on a field element (no-op unless VERIFY is enabled). */
static void secp256k1_fe_verify(const secp256k1_fe *a);
#endif /* SECP256K1_FIELD_H */ #endif /* SECP256K1_FIELD_H */

View File

@ -21,8 +21,8 @@
* - 2*M*(2^26-1) is the max (inclusive) of the remaining limbs * - 2*M*(2^26-1) is the max (inclusive) of the remaining limbs
*/ */
#ifdef VERIFY
static void secp256k1_fe_verify(const secp256k1_fe *a) { static void secp256k1_fe_verify(const secp256k1_fe *a) {
#ifdef VERIFY
const uint32_t *d = a->n; const uint32_t *d = a->n;
int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
r &= (d[0] <= 0x3FFFFFFUL * m); r &= (d[0] <= 0x3FFFFFFUL * m);
@ -47,8 +47,9 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
} }
} }
VERIFY_CHECK(r == 1); VERIFY_CHECK(r == 1);
}
#endif #endif
(void)a;
}
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
VERIFY_CHECK(m >= 0); VERIFY_CHECK(m >= 0);
@ -458,9 +459,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
} }
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
#ifdef VERIFY
secp256k1_fe_verify(a); secp256k1_fe_verify(a);
#endif
r->n[0] += a->n[0]; r->n[0] += a->n[0];
r->n[1] += a->n[1]; r->n[1] += a->n[1];
r->n[2] += a->n[2]; r->n[2] += a->n[2];
@ -479,11 +478,9 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f
} }
SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
#ifdef VERIFY
secp256k1_fe_verify(r); secp256k1_fe_verify(r);
VERIFY_CHECK(a >= 0); VERIFY_CHECK(a >= 0);
VERIFY_CHECK(a <= 0x7FFF); VERIFY_CHECK(a <= 0x7FFF);
#endif
r->n[0] += a; r->n[0] += a;
#ifdef VERIFY #ifdef VERIFY
r->magnitude += 1; r->magnitude += 1;

View File

@ -33,8 +33,8 @@
* 0 or 1, and its value is already reduced modulo the order of the field. * 0 or 1, and its value is already reduced modulo the order of the field.
*/ */
#ifdef VERIFY
static void secp256k1_fe_verify(const secp256k1_fe *a) { static void secp256k1_fe_verify(const secp256k1_fe *a) {
#ifdef VERIFY
const uint64_t *d = a->n; const uint64_t *d = a->n;
int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
/* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
@ -52,8 +52,9 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
} }
} }
VERIFY_CHECK(r == 1); VERIFY_CHECK(r == 1);
}
#endif #endif
(void)a;
}
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) { static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
VERIFY_CHECK(m >= 0); VERIFY_CHECK(m >= 0);
@ -422,11 +423,9 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
} }
SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
#ifdef VERIFY
secp256k1_fe_verify(r); secp256k1_fe_verify(r);
VERIFY_CHECK(a >= 0); VERIFY_CHECK(a >= 0);
VERIFY_CHECK(a <= 0x7FFF); VERIFY_CHECK(a <= 0x7FFF);
#endif
r->n[0] += a; r->n[0] += a;
#ifdef VERIFY #ifdef VERIFY
r->magnitude += 1; r->magnitude += 1;
@ -436,9 +435,7 @@ SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
} }
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
#ifdef VERIFY
secp256k1_fe_verify(a); secp256k1_fe_verify(a);
#endif
r->n[0] += a->n[0]; r->n[0] += a->n[0];
r->n[1] += a->n[1]; r->n[1] += a->n[1];
r->n[2] += a->n[2]; r->n[2] += a->n[2];

View File

@ -164,4 +164,10 @@ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
*/ */
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge); static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge);
/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */
static void secp256k1_ge_verify(const secp256k1_ge *a);
/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */
static void secp256k1_gej_verify(const secp256k1_gej *a);
#endif /* SECP256K1_GROUP_H */ #endif /* SECP256K1_GROUP_H */

View File

@ -73,35 +73,80 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;
#endif #endif
/* End of section generated by sage/gen_exhaustive_groups.sage. */ /* End of section generated by sage/gen_exhaustive_groups.sage. */
static void secp256k1_ge_verify(const secp256k1_ge *a) {
#ifdef VERIFY
secp256k1_fe_verify(&a->x);
secp256k1_fe_verify(&a->y);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
#endif
(void)a;
}
static void secp256k1_gej_verify(const secp256k1_gej *a) {
#ifdef VERIFY
secp256k1_fe_verify(&a->x);
secp256k1_fe_verify(&a->y);
secp256k1_fe_verify(&a->z);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
#endif
(void)a;
}
/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
secp256k1_fe zi2; secp256k1_fe zi2;
secp256k1_fe zi3; secp256k1_fe zi3;
secp256k1_gej_verify(a);
secp256k1_fe_verify(zi);
VERIFY_CHECK(!a->infinity); VERIFY_CHECK(!a->infinity);
secp256k1_fe_sqr(&zi2, zi); secp256k1_fe_sqr(&zi2, zi);
secp256k1_fe_mul(&zi3, &zi2, zi); secp256k1_fe_mul(&zi3, &zi2, zi);
secp256k1_fe_mul(&r->x, &a->x, &zi2); secp256k1_fe_mul(&r->x, &a->x, &zi2);
secp256k1_fe_mul(&r->y, &a->y, &zi3); secp256k1_fe_mul(&r->y, &a->y, &zi3);
r->infinity = a->infinity; r->infinity = a->infinity;
secp256k1_ge_verify(r);
}
/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */
static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, const secp256k1_fe *zi) {
secp256k1_fe zi2;
secp256k1_fe zi3;
secp256k1_ge_verify(a);
secp256k1_fe_verify(zi);
VERIFY_CHECK(!a->infinity);
secp256k1_fe_sqr(&zi2, zi);
secp256k1_fe_mul(&zi3, &zi2, zi);
secp256k1_fe_mul(&r->x, &a->x, &zi2);
secp256k1_fe_mul(&r->y, &a->y, &zi3);
r->infinity = a->infinity;
secp256k1_ge_verify(r);
} }
static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) {
secp256k1_fe_verify(x);
secp256k1_fe_verify(y);
r->infinity = 0; r->infinity = 0;
r->x = *x; r->x = *x;
r->y = *y; r->y = *y;
secp256k1_ge_verify(r);
} }
static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { static int secp256k1_ge_is_infinity(const secp256k1_ge *a) {
secp256k1_ge_verify(a);
return a->infinity; return a->infinity;
} }
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) {
secp256k1_ge_verify(a);
*r = *a; *r = *a;
secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_normalize_weak(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1); secp256k1_fe_negate(&r->y, &r->y, 1);
secp256k1_ge_verify(r);
} }
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe z2, z3; secp256k1_fe z2, z3;
secp256k1_gej_verify(a);
r->infinity = a->infinity; r->infinity = a->infinity;
secp256k1_fe_inv(&a->z, &a->z); secp256k1_fe_inv(&a->z, &a->z);
secp256k1_fe_sqr(&z2, &a->z); secp256k1_fe_sqr(&z2, &a->z);
@ -111,14 +156,17 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe_set_int(&a->z, 1); secp256k1_fe_set_int(&a->z, 1);
r->x = a->x; r->x = a->x;
r->y = a->y; r->y = a->y;
secp256k1_ge_verify(r);
} }
static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe z2, z3; secp256k1_fe z2, z3;
if (a->infinity) { secp256k1_gej_verify(a);
if (secp256k1_gej_is_infinity(a)) {
secp256k1_ge_set_infinity(r); secp256k1_ge_set_infinity(r);
return; return;
} }
r->infinity = 0;
secp256k1_fe_inv_var(&a->z, &a->z); secp256k1_fe_inv_var(&a->z, &a->z);
secp256k1_fe_sqr(&z2, &a->z); secp256k1_fe_sqr(&z2, &a->z);
secp256k1_fe_mul(&z3, &a->z, &z2); secp256k1_fe_mul(&z3, &a->z, &z2);
@ -126,6 +174,7 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe_mul(&a->y, &a->y, &z3); secp256k1_fe_mul(&a->y, &a->y, &z3);
secp256k1_fe_set_int(&a->z, 1); secp256k1_fe_set_int(&a->z, 1);
secp256k1_ge_set_xy(r, &a->x, &a->y); secp256k1_ge_set_xy(r, &a->x, &a->y);
secp256k1_ge_verify(r);
} }
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) { static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
@ -134,6 +183,7 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
size_t last_i = SIZE_MAX; size_t last_i = SIZE_MAX;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
secp256k1_gej_verify(&a[i]);
if (a[i].infinity) { if (a[i].infinity) {
secp256k1_ge_set_infinity(&r[i]); secp256k1_ge_set_infinity(&r[i]);
} else { } else {
@ -167,6 +217,7 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
if (!a[i].infinity) { if (!a[i].infinity) {
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x); secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
} }
secp256k1_ge_verify(&r[i]);
} }
} }
@ -175,21 +226,25 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se
secp256k1_fe zs; secp256k1_fe zs;
if (len > 0) { if (len > 0) {
/* Verify inputs a[len-1] and zr[len-1]. */
secp256k1_ge_verify(&a[i]);
secp256k1_fe_verify(&zr[i]);
/* Ensure all y values are in weak normal form for fast negation of points */ /* Ensure all y values are in weak normal form for fast negation of points */
secp256k1_fe_normalize_weak(&a[i].y); secp256k1_fe_normalize_weak(&a[i].y);
zs = zr[i]; zs = zr[i];
/* Work our way backwards, using the z-ratios to scale the x/y values. */ /* Work our way backwards, using the z-ratios to scale the x/y values. */
while (i > 0) { while (i > 0) {
secp256k1_gej tmpa; /* Verify all inputs a[i] and zr[i]. */
secp256k1_fe_verify(&zr[i]);
secp256k1_ge_verify(&a[i]);
if (i != len - 1) { if (i != len - 1) {
secp256k1_fe_mul(&zs, &zs, &zr[i]); secp256k1_fe_mul(&zs, &zs, &zr[i]);
} }
i--; i--;
tmpa.x = a[i].x; secp256k1_ge_set_ge_zinv(&a[i], &a[i], &zs);
tmpa.y = a[i].y; /* Verify the output a[i]. */
tmpa.infinity = 0; secp256k1_ge_verify(&a[i]);
secp256k1_ge_set_gej_zinv(&a[i], &tmpa, &zs);
} }
} }
} }
@ -199,12 +254,14 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y); secp256k1_fe_clear(&r->y);
secp256k1_fe_clear(&r->z); secp256k1_fe_clear(&r->z);
secp256k1_gej_verify(r);
} }
static void secp256k1_ge_set_infinity(secp256k1_ge *r) { static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
r->infinity = 1; r->infinity = 1;
secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y); secp256k1_fe_clear(&r->y);
secp256k1_ge_verify(r);
} }
static void secp256k1_gej_clear(secp256k1_gej *r) { static void secp256k1_gej_clear(secp256k1_gej *r) {
@ -222,31 +279,35 @@ static void secp256k1_ge_clear(secp256k1_ge *r) {
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
secp256k1_fe x2, x3; secp256k1_fe x2, x3;
int ret;
secp256k1_fe_verify(x);
r->x = *x; r->x = *x;
secp256k1_fe_sqr(&x2, x); secp256k1_fe_sqr(&x2, x);
secp256k1_fe_mul(&x3, x, &x2); secp256k1_fe_mul(&x3, x, &x2);
r->infinity = 0; r->infinity = 0;
secp256k1_fe_add_int(&x3, SECP256K1_B); secp256k1_fe_add_int(&x3, SECP256K1_B);
if (!secp256k1_fe_sqrt(&r->y, &x3)) { ret = secp256k1_fe_sqrt(&r->y, &x3);
return 0;
}
secp256k1_fe_normalize_var(&r->y); secp256k1_fe_normalize_var(&r->y);
if (secp256k1_fe_is_odd(&r->y) != odd) { if (secp256k1_fe_is_odd(&r->y) != odd) {
secp256k1_fe_negate(&r->y, &r->y, 1); secp256k1_fe_negate(&r->y, &r->y, 1);
} }
return 1; secp256k1_ge_verify(r);
return ret;
} }
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {
secp256k1_ge_verify(a);
r->infinity = a->infinity; r->infinity = a->infinity;
r->x = a->x; r->x = a->x;
r->y = a->y; r->y = a->y;
secp256k1_fe_set_int(&r->z, 1); secp256k1_fe_set_int(&r->z, 1);
secp256k1_gej_verify(r);
} }
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) { static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) {
secp256k1_gej tmp; secp256k1_gej tmp;
secp256k1_gej_verify(b);
secp256k1_gej_verify(a);
secp256k1_gej_neg(&tmp, a); secp256k1_gej_neg(&tmp, a);
secp256k1_gej_add_var(&tmp, &tmp, b, NULL); secp256k1_gej_add_var(&tmp, &tmp, b, NULL);
return secp256k1_gej_is_infinity(&tmp); return secp256k1_gej_is_infinity(&tmp);
@ -254,6 +315,8 @@ static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b)
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) {
secp256k1_fe r, r2; secp256k1_fe r, r2;
secp256k1_fe_verify(x);
secp256k1_gej_verify(a);
VERIFY_CHECK(!a->infinity); VERIFY_CHECK(!a->infinity);
secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x);
r2 = a->x; secp256k1_fe_normalize_weak(&r2); r2 = a->x; secp256k1_fe_normalize_weak(&r2);
@ -261,20 +324,24 @@ static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a)
} }
static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) { static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) {
secp256k1_gej_verify(a);
r->infinity = a->infinity; r->infinity = a->infinity;
r->x = a->x; r->x = a->x;
r->y = a->y; r->y = a->y;
r->z = a->z; r->z = a->z;
secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_normalize_weak(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1); secp256k1_fe_negate(&r->y, &r->y, 1);
secp256k1_gej_verify(r);
} }
static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { static int secp256k1_gej_is_infinity(const secp256k1_gej *a) {
secp256k1_gej_verify(a);
return a->infinity; return a->infinity;
} }
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
secp256k1_fe y2, x3; secp256k1_fe y2, x3;
secp256k1_ge_verify(a);
if (a->infinity) { if (a->infinity) {
return 0; return 0;
} }
@ -290,6 +357,7 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
/* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */ /* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */
secp256k1_fe l, s, t; secp256k1_fe l, s, t;
secp256k1_gej_verify(a);
r->infinity = a->infinity; r->infinity = a->infinity;
/* Formula used: /* Formula used:
@ -316,6 +384,7 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */ secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */
secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */ secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */
secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */ secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */
secp256k1_gej_verify(r);
} }
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
@ -329,6 +398,7 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
* the infinity flag even though the point doubles to infinity, and the result * the infinity flag even though the point doubles to infinity, and the result
* point will be gibberish (z = 0 but infinity = 0). * point will be gibberish (z = 0 but infinity = 0).
*/ */
secp256k1_gej_verify(a);
if (a->infinity) { if (a->infinity) {
secp256k1_gej_set_infinity(r); secp256k1_gej_set_infinity(r);
if (rzr != NULL) { if (rzr != NULL) {
@ -343,12 +413,15 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
} }
secp256k1_gej_double(r, a); secp256k1_gej_double(r, a);
secp256k1_gej_verify(r);
} }
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) { static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
/* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ /* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t; secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t;
secp256k1_gej_verify(a);
secp256k1_gej_verify(b);
if (a->infinity) { if (a->infinity) {
VERIFY_CHECK(rzr == NULL); VERIFY_CHECK(rzr == NULL);
*r = *b; *r = *b;
@ -403,11 +476,14 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons
secp256k1_fe_mul(&r->y, &t, &i); secp256k1_fe_mul(&r->y, &t, &i);
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3); secp256k1_fe_add(&r->y, &h3);
secp256k1_gej_verify(r);
} }
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) { static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) {
/* 8 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */ /* 8 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */
secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t; secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t;
secp256k1_gej_verify(a);
secp256k1_ge_verify(b);
if (a->infinity) { if (a->infinity) {
VERIFY_CHECK(rzr == NULL); VERIFY_CHECK(rzr == NULL);
secp256k1_gej_set_ge(r, b); secp256k1_gej_set_ge(r, b);
@ -460,12 +536,16 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
secp256k1_fe_mul(&r->y, &t, &i); secp256k1_fe_mul(&r->y, &t, &i);
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3); secp256k1_fe_add(&r->y, &h3);
secp256k1_gej_verify(r);
if (rzr != NULL) secp256k1_fe_verify(rzr);
} }
static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) { static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) {
/* 9 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */ /* 9 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */
secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t; secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t;
secp256k1_ge_verify(b);
secp256k1_fe_verify(bzinv);
if (a->infinity) { if (a->infinity) {
secp256k1_fe bzinv2, bzinv3; secp256k1_fe bzinv2, bzinv3;
r->infinity = b->infinity; r->infinity = b->infinity;
@ -524,6 +604,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
secp256k1_fe_mul(&r->y, &t, &i); secp256k1_fe_mul(&r->y, &t, &i);
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3); secp256k1_fe_add(&r->y, &h3);
secp256k1_gej_verify(r);
} }
@ -532,6 +613,8 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
secp256k1_fe m_alt, rr_alt; secp256k1_fe m_alt, rr_alt;
int degenerate; int degenerate;
secp256k1_gej_verify(a);
secp256k1_ge_verify(b);
VERIFY_CHECK(!b->infinity); VERIFY_CHECK(!b->infinity);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
@ -657,21 +740,26 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
* We have degenerate = false, r->z = (y1 + y2) * Z. * We have degenerate = false, r->z = (y1 + y2) * Z.
* Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */ * Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */
r->infinity = secp256k1_fe_normalizes_to_zero(&r->z); r->infinity = secp256k1_fe_normalizes_to_zero(&r->z);
secp256k1_gej_verify(r);
} }
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
/* Operations: 4 mul, 1 sqr */ /* Operations: 4 mul, 1 sqr */
secp256k1_fe zz; secp256k1_fe zz;
secp256k1_gej_verify(r);
secp256k1_fe_verify(s);
VERIFY_CHECK(!secp256k1_fe_is_zero(s)); VERIFY_CHECK(!secp256k1_fe_is_zero(s));
secp256k1_fe_sqr(&zz, s); secp256k1_fe_sqr(&zz, s);
secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */
secp256k1_fe_mul(&r->y, &r->y, &zz); secp256k1_fe_mul(&r->y, &r->y, &zz);
secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */
secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */
secp256k1_gej_verify(r);
} }
static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) { static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) {
secp256k1_fe x, y; secp256k1_fe x, y;
secp256k1_ge_verify(a);
VERIFY_CHECK(!a->infinity); VERIFY_CHECK(!a->infinity);
x = a->x; x = a->x;
secp256k1_fe_normalize(&x); secp256k1_fe_normalize(&x);
@ -685,14 +773,18 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag
secp256k1_fe_from_storage(&r->x, &a->x); secp256k1_fe_from_storage(&r->x, &a->x);
secp256k1_fe_from_storage(&r->y, &a->y); secp256k1_fe_from_storage(&r->y, &a->y);
r->infinity = 0; r->infinity = 0;
secp256k1_ge_verify(r);
} }
static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) { static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) {
secp256k1_gej_verify(r);
secp256k1_gej_verify(a);
secp256k1_fe_cmov(&r->x, &a->x, flag); secp256k1_fe_cmov(&r->x, &a->x, flag);
secp256k1_fe_cmov(&r->y, &a->y, flag); secp256k1_fe_cmov(&r->y, &a->y, flag);
secp256k1_fe_cmov(&r->z, &a->z, flag); secp256k1_fe_cmov(&r->z, &a->z, flag);
r->infinity ^= (r->infinity ^ a->infinity) & flag; r->infinity ^= (r->infinity ^ a->infinity) & flag;
secp256k1_gej_verify(r);
} }
static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) {
@ -702,7 +794,9 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r,
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
*r = *a; *r = *a;
secp256k1_ge_verify(a);
secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta); secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta);
secp256k1_ge_verify(r);
} }
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) { static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
@ -710,6 +804,7 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
secp256k1_gej out; secp256k1_gej out;
int i; int i;
secp256k1_ge_verify(ge);
/* A very simple EC multiplication ladder that avoids a dependency on ecmult. */ /* A very simple EC multiplication ladder that avoids a dependency on ecmult. */
secp256k1_gej_set_infinity(&out); secp256k1_gej_set_infinity(&out);
for (i = 0; i < 32; ++i) { for (i = 0; i < 32; ++i) {

View File

@ -193,7 +193,7 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge
} }
for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) {
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) {
int ret; int ret;
secp256k1_gej tmp; secp256k1_gej tmp;
secp256k1_fe xn, xd, tmpf; secp256k1_fe xn, xd, tmpf;
@ -207,7 +207,7 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge
secp256k1_ecmult_const(&tmp, &group[i], &ng); secp256k1_ecmult_const(&tmp, &group[i], &ng);
ge_equals_gej(&group[(i * j) % EXHAUSTIVE_TEST_ORDER], &tmp); ge_equals_gej(&group[(i * j) % EXHAUSTIVE_TEST_ORDER], &tmp);
if (j != 0) { if (i != 0 && j != 0) {
/* Test secp256k1_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */ /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */
ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 0); ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 0);
CHECK(ret); CHECK(ret);