From eed599dd7271a7efc3961cd97b17fc87f517a842 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Fri, 12 Dec 2014 12:55:01 +0700 Subject: [PATCH] Add _fe_normalizes_to_zero method --- src/field.h | 4 ++++ src/field_10x26_impl.h | 32 ++++++++++++++++++++++++++++++++ src/field_5x52_impl.h | 23 +++++++++++++++++++++++ src/field_impl.h | 4 ++-- src/group_impl.h | 23 ++++++++++------------- 5 files changed, 71 insertions(+), 15 deletions(-) diff --git a/src/field.h b/src/field.h index 940632f7de8..ed34c965d9d 100644 --- a/src/field.h +++ b/src/field.h @@ -54,6 +54,10 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r); /** Normalize a field element, without constant-time guarantee. */ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r); +/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field + * implementation may optionally normalize the input, but this should not be relied upon. */ +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r); + /** Set a field element equal to a small integer. Resulting field element is normalized. */ static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a); diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 71ae7973f78..7778ac3d5a4 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -122,6 +122,9 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; @@ -187,6 +190,35 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { #endif } +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint32_t z0, z1; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; z0 = t0; z1 = t0 ^ 0x3D0UL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; + z0 |= t9; z1 &= t9 ^ 0x3C00000UL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + return (z0 == 0) | (z1 == 0x3FFFFFFUL); +} + SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 27462b8e743..45f61e0d7e3 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -168,6 +168,29 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { #endif } +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint64_t z0, z1; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0 = t0; z1 = t0 ^ 0x1000003D0ULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; diff --git a/src/field_impl.h b/src/field_impl.h index abd8fa61013..d1b6cd6f330 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -64,12 +64,12 @@ static int secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) { return secp256k1_fe_set_b32(r, tmp); } +/* TODO Not actually var currently */ SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { secp256k1_fe_t na; secp256k1_fe_negate(&na, a, 1); secp256k1_fe_add(&na, b); - secp256k1_fe_normalize_var(&na); - return secp256k1_fe_is_zero(&na); + return secp256k1_fe_normalizes_to_zero(&na); } static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { diff --git a/src/group_impl.h b/src/group_impl.h index 45383c0f154..e62d3209ee3 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -160,9 +160,7 @@ static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a) { static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a) { VERIFY_CHECK(!a->infinity); secp256k1_fe_t r; secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); - secp256k1_fe_t r2 = a->x; - secp256k1_fe_normalize_weak(&r); - secp256k1_fe_normalize_weak(&r2); + secp256k1_fe_t r2 = a->x; secp256k1_fe_normalize_weak(&r2); return secp256k1_fe_equal_var(&r, &r2); } @@ -257,16 +255,16 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12); secp256k1_fe_t s1; secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z); secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); - if (secp256k1_fe_equal_var(&u1, &u2)) { - if (secp256k1_fe_equal_var(&s1, &s2)) { + secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero(&h)) { + if (secp256k1_fe_normalizes_to_zero(&i)) { secp256k1_gej_double_var(r, a); } else { r->infinity = 1; } return; } - secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i); secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h); secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2); @@ -296,16 +294,16 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t * secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &b->x, &z12); secp256k1_fe_t s1 = a->y; secp256k1_fe_normalize_weak(&s1); secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); - if (secp256k1_fe_equal_var(&u1, &u2)) { - if (secp256k1_fe_equal_var(&s1, &s2)) { + secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero(&h)) { + if (secp256k1_fe_normalizes_to_zero(&i)) { secp256k1_gej_double_var(r, a); } else { r->infinity = 1; } return; } - secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); - secp256k1_fe_t i; secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); secp256k1_fe_t i2; secp256k1_fe_sqr(&i2, &i); secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h); secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2); @@ -360,8 +358,7 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c 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); + int infinity = secp256k1_fe_normalizes_to_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) */ secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */