diff --git a/bench.cpp b/bench.cpp index 19254ff..2801dc2 100644 --- a/bench.cpp +++ b/bench.cpp @@ -9,15 +9,17 @@ using namespace secp256k1; int main() { - FieldElem x; + secp256k1_num_start(); + secp256k1_fe_start(); + + secp256k1_fe_t x; const secp256k1_num_t &order = GetGroupConst().order; secp256k1_num_t r, s, m; - secp256k1_num_start(); secp256k1_num_init(&r); secp256k1_num_init(&s); secp256k1_num_init(&m); Signature sig; - x.SetHex("a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f"); + secp256k1_fe_set_hex(&x, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64); int cnt = 0; int good = 0; for (int i=0; i<1000000; i++) { @@ -35,5 +37,7 @@ int main() { secp256k1_num_free(&r); secp256k1_num_free(&s); secp256k1_num_free(&m); + + secp256k1_fe_stop(); return 0; } diff --git a/ecdsa.cpp b/ecdsa.cpp index b0ecf95..2e64a07 100644 --- a/ecdsa.cpp +++ b/ecdsa.cpp @@ -8,15 +8,15 @@ namespace secp256k1 { bool ParsePubKey(GroupElemJac &elem, const unsigned char *pub, int size) { if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) { - FieldElem x; - x.SetBytes(pub+1); + secp256k1_fe_t x; + secp256k1_fe_set_b32(&x, pub+1); elem.SetCompressed(x, pub[0] == 0x03); } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { - FieldElem x,y; - x.SetBytes(pub+1); - y.SetBytes(pub+33); + secp256k1_fe_t x,y; + secp256k1_fe_set_b32(&x, pub+1); + secp256k1_fe_set_b32(&y, pub+33); elem = GroupElem(x,y); - if ((pub[0] == 0x06 || pub[0] == 0x07) && y.IsOdd() != (pub[0] == 0x07)) + if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) return false; } else { return false; @@ -81,9 +81,9 @@ bool Signature::RecomputeR(secp256k1_num_t &r2, const GroupElemJac &pubkey, cons secp256k1_num_mod_mul(&u2, &sn, &r, &c.order); GroupElemJac pr; ECMult(pr, pubkey, u2, u1); if (!pr.IsInfinity()) { - FieldElem xr; pr.GetX(xr); - xr.Normalize(); - unsigned char xrb[32]; xr.GetBytes(xrb); + secp256k1_fe_t xr; pr.GetX(xr); + secp256k1_fe_normalize(&xr); + unsigned char xrb[32]; secp256k1_fe_get_b32(xrb, &xr); secp256k1_num_set_bin(&r2, xrb, 32); secp256k1_num_mod(&r2, &r2, &c.order); ret = true; @@ -108,11 +108,11 @@ bool Signature::Sign(const secp256k1_num_t &seckey, const secp256k1_num_t &messa GroupElemJac rp; ECMultBase(rp, nonce); - FieldElem rx; + secp256k1_fe_t rx; rp.GetX(rx); unsigned char b[32]; - rx.Normalize(); - rx.GetBytes(b); + secp256k1_fe_normalize(&rx); + secp256k1_fe_get_b32(b, &rx); secp256k1_num_set_bin(&r, b, 32); secp256k1_num_mod(&r, &r, &c.order); secp256k1_num_t n; diff --git a/field.cpp b/field.cpp index e3d2dd6..ca201d1 100644 --- a/field.cpp +++ b/field.cpp @@ -1,25 +1,151 @@ // just one implementation for now #include "field_5x52.cpp" -namespace secp256k1 { +static const unsigned char secp256k1_fe_consts_p[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F +}; -static const unsigned char field_p_[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F}; - -FieldConstants::FieldConstants() { - secp256k1_num_init(&field_p); - secp256k1_num_set_bin(&field_p, field_p_, sizeof(field_p_)); +void static secp256k1_fe_start(void) { + if (secp256k1_fe_consts == NULL) { + secp256k1_fe_consts_t *ret = (secp256k1_fe_consts_t*)malloc(sizeof(secp256k1_fe_t)); + secp256k1_num_set_bin(&ret->p, secp256k1_fe_consts_p, sizeof(secp256k1_fe_consts_p)); + secp256k1_fe_consts = ret; + } } -FieldConstants::~FieldConstants() { - secp256k1_num_free(&field_p); +void static secp256k1_fe_stop(void) { + if (secp256k1_fe_consts != NULL) { + free((void*)secp256k1_fe_consts); + secp256k1_fe_consts = NULL; + } } -const FieldConstants &GetFieldConst() { - static const FieldConstants field_const; - return field_const; +void static secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a) { + if (*rlen < 65) { + *rlen = 65; + return; + } + *rlen = 65; + unsigned char tmp[32]; + secp256k1_fe_t b = *a; + secp256k1_fe_normalize(&b); + secp256k1_fe_get_b32(tmp, &b); + for (int i=0; i<32; i++) { + static const char *c = "0123456789ABCDEF"; + r[2*i] = c[(tmp[i] >> 4) & 0xF]; + r[2*i+1] = c[(tmp[i]) & 0xF]; + } + r[64] = 0x00; } +void static secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen) { + unsigned char tmp[32] = {}; + static const int cvt[256] = {0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, + 0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0, + 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, + 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}; + for (int i=0; i<32; i++) { + if (alen > i*2) + tmp[32 - alen/2 + i] = (cvt[(unsigned char)a[2*i]] << 4) + cvt[(unsigned char)a[2*i+1]]; + } + secp256k1_fe_set_b32(r, tmp); +} + +void static secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a) { + // calculate a^p, with p={15,780,1022,1023} + secp256k1_fe_t a2; secp256k1_fe_sqr(&a2, a); + secp256k1_fe_t a3; secp256k1_fe_mul(&a3, &a2, a); + secp256k1_fe_t a6; secp256k1_fe_sqr(&a6, &a3); + secp256k1_fe_t a12; secp256k1_fe_sqr(&a12, &a6); + secp256k1_fe_t a15; secp256k1_fe_mul(&a15, &a12, &a3); + secp256k1_fe_t a30; secp256k1_fe_sqr(&a30, &a15); + secp256k1_fe_t a60; secp256k1_fe_sqr(&a60, &a30); + secp256k1_fe_t a120; secp256k1_fe_sqr(&a120, &a60); + secp256k1_fe_t a240; secp256k1_fe_sqr(&a240, &a120); + secp256k1_fe_t a255; secp256k1_fe_mul(&a255, &a240, &a15); + secp256k1_fe_t a510; secp256k1_fe_sqr(&a510, &a255); + secp256k1_fe_t a750; secp256k1_fe_mul(&a750, &a510, &a240); + secp256k1_fe_t a780; secp256k1_fe_mul(&a780, &a750, &a30); + secp256k1_fe_t a1020; secp256k1_fe_sqr(&a1020, &a510); + secp256k1_fe_t a1022; secp256k1_fe_mul(&a1022, &a1020, &a2); + secp256k1_fe_t a1023; secp256k1_fe_mul(&a1023, &a1022, a); + secp256k1_fe_t x = a15; + for (int i=0; i<21; i++) { + for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x); + secp256k1_fe_mul(&x, &x, &a1023); + } + for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x); + secp256k1_fe_mul(&x, &x, &a1022); + for (int i=0; i<2; i++) { + for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x); + secp256k1_fe_mul(&x, &x, &a1023); + } + for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x); + secp256k1_fe_mul(r, &x, &a780); +} + +void static secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) { + // calculate a^p, with p={45,63,1019,1023} + secp256k1_fe_t a2; secp256k1_fe_sqr(&a2, a); + secp256k1_fe_t a3; secp256k1_fe_mul(&a3, &a2, a); + secp256k1_fe_t a4; secp256k1_fe_sqr(&a4, &a2); + secp256k1_fe_t a5; secp256k1_fe_mul(&a5, &a4, a); + secp256k1_fe_t a10; secp256k1_fe_sqr(&a10, &a5); + secp256k1_fe_t a11; secp256k1_fe_mul(&a11, &a10, a); + secp256k1_fe_t a21; secp256k1_fe_mul(&a21, &a11, &a10); + secp256k1_fe_t a42; secp256k1_fe_sqr(&a42, &a21); + secp256k1_fe_t a45; secp256k1_fe_mul(&a45, &a42, &a3); + secp256k1_fe_t a63; secp256k1_fe_mul(&a63, &a42, &a21); + secp256k1_fe_t a126; secp256k1_fe_sqr(&a126, &a63); + secp256k1_fe_t a252; secp256k1_fe_sqr(&a252, &a126); + secp256k1_fe_t a504; secp256k1_fe_sqr(&a504, &a252); + secp256k1_fe_t a1008; secp256k1_fe_sqr(&a1008, &a504); + secp256k1_fe_t a1019; secp256k1_fe_mul(&a1019, &a1008, &a11); + secp256k1_fe_t a1023; secp256k1_fe_mul(&a1023, &a1019, &a4); + secp256k1_fe_t x = a63; + for (int i=0; i<21; i++) { + for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x); + secp256k1_fe_mul(&x, &x, &a1023); + } + for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x); + secp256k1_fe_mul(&x, &x, &a1019); + for (int i=0; i<2; i++) { + for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x); + secp256k1_fe_mul(&x, &x, &a1023); + } + for (int j=0; j<10; j++) secp256k1_fe_sqr(&x, &x); + secp256k1_fe_mul(r, &x, &a45); +} + +void static secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +#if defined(USE_FIELDINVERSE_BUILTIN) + secp256k1_fe_inv(r, a); +#else + unsigned char b[32]; + secp256k1_fe_t c = *a; + secp256k1_fe_normalize(&c); + secp256k1_fe_get_b32(b, &c); + secp256k1_num_t n; + secp256k1_num_init(&n); + secp256k1_num_set_bin(&n, b, 32); + secp256k1_num_mod_inverse(&n, &n, &secp256k1_fe_consts->p); + secp256k1_num_get_bin(b, 32, &n); + secp256k1_num_free(&n); + secp256k1_fe_set_b32(&c, b); +#endif } diff --git a/field.h b/field.h index 873b5f6..a266b87 100644 --- a/field.h +++ b/field.h @@ -1,21 +1,88 @@ #ifndef _SECP256K1_FIELD_ #define _SECP256K1_FIELD_ +/** Field element module. + * + * Field elements can be represented in several ways, but code accessing + * it (and implementations) need to take certain properaties into account: + * - Each field element can be normalized or not. + * - Each field element has a magnitude, which represents how far away + * its representation is away from normalization. Normalized elements + * always have a magnitude of 1, but a magnitude of 1 doesn't imply + * normality. + */ + // just one implementation for now #include "field_5x52.h" -namespace secp256k1 { +typedef struct { + secp256k1_num_t p; +} secp256k1_fe_consts_t; -class FieldConstants { -public: - secp256k1_num_t field_p; +static const secp256k1_fe_consts_t *secp256k1_fe_consts = NULL; - FieldConstants(); - ~FieldConstants(); -}; +/** Initialize field element precomputation data. */ +void static secp256k1_fe_start(void); -const FieldConstants &GetFieldConst(); +/** Unload field element precomputation data. */ +void static secp256k1_fe_stop(void); -} +/** Normalize a field element. */ +void static secp256k1_fe_normalize(secp256k1_fe_t *r); + +/** Set a field element equal to a small integer. Resulting field element is normalized. */ +void static secp256k1_fe_set_int(secp256k1_fe_t *r, int a); + +/** Verify whether a field element is zero. Requires the input to be normalized. */ +int static secp256k1_fe_is_zero(const secp256k1_fe_t *a); + +/** Check the "oddness" of a field element. Requires the input to be normalized. */ +int static secp256k1_fe_is_odd(const secp256k1_fe_t *a); + +/** Compare two field elements. Requires both inputs to be normalized */ +int static secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b); + +/** Set a field element equal to 32-byte big endian value. Resulting field element is normalized. */ +void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a); + +/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a); + +/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input + * as an argument. The magnitude of the output is one higher. */ +void static secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m); + +/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that + * small integer. */ +void static secp256k1_fe_mul_int(secp256k1_fe_t *r, int a); + +/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ +void static secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a); + +/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. + * The output magnitude is 1 (but not guaranteed to be normalized). */ +void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b); + +/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. + * The output magnitude is 1 (but not guaranteed to be normalized). */ +void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a); + +/** Sets a field element to be the (modular) square root of another. Requires the inputs' magnitude to + * be at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ +void static secp256k1_fe_sqrt(secp256k1_fe_t *r, const secp256k1_fe_t *a); + +/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be + * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ +void static secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a); + +/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ +void static secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a); + + +/** Convert a field element to a hexadecimal string. */ +void static secp256k1_fe_get_hex(char *r, int *rlen, const secp256k1_fe_t *a); + +/** Convert a hexadecimal string to a field element. */ +void static secp256k1_fe_set_hex(secp256k1_fe_t *r, const char *a, int alen); #endif diff --git a/field_5x52.cpp b/field_5x52.cpp index bc08ecc..b5a8f51 100644 --- a/field_5x52.cpp +++ b/field_5x52.cpp @@ -1,18 +1,12 @@ #include -#include -#include +#include #include "num.h" #include "field.h" -#include - -using namespace std; #ifdef INLINE_ASM #include "lin64.h" #endif -namespace secp256k1 { - /** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, * represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular, * each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element @@ -21,30 +15,17 @@ namespace secp256k1 { * output. */ -FieldElem::FieldElem(int x) { - n[0] = x; - n[1] = n[2] = n[3] = n[4] = 0; -#ifdef VERIFY_MAGNITUDE - magnitude = 1; - normalized = true; -#endif -} - -FieldElem::FieldElem(const unsigned char *b32) { - SetBytes(b32); -} - -void FieldElem::Normalize() { +void static secp256k1_fe_normalize(secp256k1_fe_t *r) { uint64_t c; - c = n[0]; + c = r->n[0]; uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; - c = (c >> 52) + n[1]; + c = (c >> 52) + r->n[1]; uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; - c = (c >> 52) + n[2]; + c = (c >> 52) + r->n[2]; uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; - c = (c >> 52) + n[3]; + c = (c >> 52) + r->n[3]; uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; - c = (c >> 52) + n[4]; + c = (c >> 52) + r->n[4]; uint64_t t4 = c & 0x0FFFFFFFFFFFFULL; c >>= 48; @@ -60,149 +41,166 @@ void FieldElem::Normalize() { c = (c >> 52) + t4; t4 = c & 0x0FFFFFFFFFFFFULL; - // Replace n's with t's if one of the n's overflows. - // If none of the n's overflow to begin with, the t's will just be the n's already and - // we effectively ignore the results of the previous computations. - n[0] = t0; n[1] = t1; n[2] = t2; n[3] = t3; n[4] = t4; - // Subtract p if result >= p - uint64_t mask = -(int64_t)((n[4] < 0xFFFFFFFFFFFFULL) | (n[3] < 0xFFFFFFFFFFFFFULL) | (n[2] < 0xFFFFFFFFFFFFFULL) | (n[1] < 0xFFFFFFFFFFFFFULL) | (n[0] < 0xFFFFEFFFFFC2FULL)); - n[4] &= mask; - n[3] &= mask; - n[2] &= mask; - n[1] &= mask; - n[0] -= (~mask & 0xFFFFEFFFFFC2FULL); + uint64_t mask = -(int64_t)((t4 < 0xFFFFFFFFFFFFULL) | (t3 < 0xFFFFFFFFFFFFFULL) | (t2 < 0xFFFFFFFFFFFFFULL) | (t1 < 0xFFFFFFFFFFFFFULL) | (t0 < 0xFFFFEFFFFFC2FULL)); + t4 &= mask; + t3 &= mask; + t2 &= mask; + t1 &= mask; + t0 -= (~mask & 0xFFFFEFFFFFC2FULL); -#ifdef VERIFY_MAGNITUDE - magnitude = 1; - normalized = true; + // push internal variables back + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; #endif } -bool inline FieldElem::IsZero() const { -#ifdef VERIFY_MAGNITUDE - assert(normalized); +void static 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; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; #endif - return (n[0] == 0 && n[1] == 0 && n[2] == 0 && n[3] == 0 && n[4] == 0); } -bool inline operator==(const FieldElem &a, const FieldElem &b) { -#ifdef VERIFY_MAGNITUDE - assert(a.normalized); - assert(b.normalized); +// TODO: not constant time! +int static secp256k1_fe_is_zero(const secp256k1_fe_t *a) { +#ifdef VERIFY + assert(a->normalized); #endif - return (a.n[0] == b.n[0] && a.n[1] == b.n[1] && a.n[2] == b.n[2] && a.n[3] == b.n[3] && a.n[4] == b.n[4]); + return (a->n[0] == 0 && a->n[1] == 0 && a->n[2] == 0 && a->n[3] == 0 && a->n[4] == 0); } -void FieldElem::GetBytes(unsigned char *o) { -#ifdef VERIFY_MAGNITUDE - assert(normalized); +int static secp256k1_fe_is_odd(const secp256k1_fe_t *a) { +#ifdef VERIFY + assert(a->normalized); +#endif + return a->n[0] & 1; +} + +// TODO: not constant time! +int static secp256k1_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { +#ifdef VERIFY + assert(a->normalized); + assert(b->normalized); +#endif + return (a->n[0] == b->n[0] && a->n[1] == b->n[1] && a->n[2] == b->n[2] && a->n[3] == b->n[3] && a->n[4] == b->n[4]); +} + +void static secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { + r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; + for (int i=0; i<32; i++) { + for (int j=0; j<2; j++) { + int limb = (8*i+4*j)/52; + int shift = (8*i+4*j)%52; + r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift; + } + } +#ifdef VERIFY + r->magnitude = 1; + r->normalized = true; +#endif +} + +/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +void static secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { +#ifdef VERIFY + assert(a->normalized); #endif for (int i=0; i<32; i++) { int c = 0; for (int j=0; j<2; j++) { int limb = (8*i+4*j)/52; int shift = (8*i+4*j)%52; - c |= ((n[limb] >> shift) & 0xF) << (4 * j); + c |= ((a->n[limb] >> shift) & 0xF) << (4 * j); } - o[31-i] = c; + r[31-i] = c; } } -void FieldElem::SetBytes(const unsigned char *in) { - n[0] = n[1] = n[2] = n[3] = n[4] = 0; - for (int i=0; i<32; i++) { - for (int j=0; j<2; j++) { - int limb = (8*i+4*j)/52; - int shift = (8*i+4*j)%52; - n[limb] |= (uint64_t)((in[31-i] >> (4*j)) & 0xF) << shift; - } - } -#ifdef VERIFY_MAGNITUDE - magnitude = 1; - normalized = true; +void static secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) { +#ifdef VERIFY + assert(a->magnitude <= m); + r->magnitude = m + 1; + r->normalized = 0; #endif + r->n[0] = 0xFFFFEFFFFFC2FULL * (m + 1) - a->n[0]; + r->n[1] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[1]; + r->n[2] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[2]; + r->n[3] = 0xFFFFFFFFFFFFFULL * (m + 1) - a->n[3]; + r->n[4] = 0x0FFFFFFFFFFFFULL * (m + 1) - a->n[4]; } -void inline FieldElem::SetNeg(const FieldElem &a, int magnitudeIn) { -#ifdef VERIFY_MAGNITUDE - assert(a.magnitude <= magnitudeIn); - magnitude = magnitudeIn + 1; - normalized = false; +void static secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { +#ifdef VERIFY + r->magnitude *= a; + r->normalized = false; #endif - n[0] = 0xFFFFEFFFFFC2FULL * (magnitudeIn + 1) - a.n[0]; - n[1] = 0xFFFFFFFFFFFFFULL * (magnitudeIn + 1) - a.n[1]; - n[2] = 0xFFFFFFFFFFFFFULL * (magnitudeIn + 1) - a.n[2]; - n[3] = 0xFFFFFFFFFFFFFULL * (magnitudeIn + 1) - a.n[3]; - n[4] = 0x0FFFFFFFFFFFFULL * (magnitudeIn + 1) - a.n[4]; + r->n[0] *= a; + r->n[1] *= a; + r->n[2] *= a; + r->n[3] *= a; + r->n[4] *= a; } -void inline FieldElem::operator*=(int v) { -#ifdef VERIFY_MAGNITUDE - magnitude *= v; - normalized = false; +void static secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +#ifdef VERIFY + r->magnitude += a->magnitude; + r->normalized = 0; #endif - n[0] *= v; - n[1] *= v; - n[2] *= v; - n[3] *= v; - n[4] *= v; + r->n[0] += a->n[0]; + r->n[1] += a->n[1]; + r->n[2] += a->n[2]; + r->n[3] += a->n[3]; + r->n[4] += a->n[4]; } -void inline FieldElem::operator+=(const FieldElem &a) { -#ifdef VERIFY_MAGNITUDE - magnitude += a.magnitude; - normalized = false; -#endif - n[0] += a.n[0]; - n[1] += a.n[1]; - n[2] += a.n[2]; - n[3] += a.n[3]; - n[4] += a.n[4]; -} - -void FieldElem::SetMult(const FieldElem &a, const FieldElem &b) { -#ifdef VERIFY_MAGNITUDE - assert(a.magnitude <= 8); - assert(b.magnitude <= 8); +void static secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t *b) { +#ifdef VERIFY + assert(a->magnitude <= 8); + assert(b->magnitude <= 8); #endif #ifdef INLINE_ASM - ExSetMult((uint64_t *) a.n,(uint64_t *) b.n, (uint64_t *) n); + ExSetMult((uint64_t*)a->n, (uint64_t*)b->n, (uint64_t*)r->n); #else - unsigned __int128 c = (__int128)a.n[0] * b.n[0]; + unsigned __int128 c = (__int128)a->n[0] * b->n[0]; uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0 - c = c + (__int128)a.n[0] * b.n[1] + - (__int128)a.n[1] * b.n[0]; + c = c + (__int128)a->n[0] * b->n[1] + + (__int128)a->n[1] * b->n[0]; uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF - c = c + (__int128)a.n[0] * b.n[2] + - (__int128)a.n[1] * b.n[1] + - (__int128)a.n[2] * b.n[0]; + c = c + (__int128)a->n[0] * b->n[2] + + (__int128)a->n[1] * b->n[1] + + (__int128)a->n[2] * b->n[0]; uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0 - c = c + (__int128)a.n[0] * b.n[3] + - (__int128)a.n[1] * b.n[2] + - (__int128)a.n[2] * b.n[1] + - (__int128)a.n[3] * b.n[0]; + c = c + (__int128)a->n[0] * b->n[3] + + (__int128)a->n[1] * b->n[2] + + (__int128)a->n[2] * b->n[1] + + (__int128)a->n[3] * b->n[0]; uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280 - c = c + (__int128)a.n[0] * b.n[4] + - (__int128)a.n[1] * b.n[3] + - (__int128)a.n[2] * b.n[2] + - (__int128)a.n[3] * b.n[1] + - (__int128)a.n[4] * b.n[0]; + c = c + (__int128)a->n[0] * b->n[4] + + (__int128)a->n[1] * b->n[3] + + (__int128)a->n[2] * b->n[2] + + (__int128)a->n[3] * b->n[1] + + (__int128)a->n[4] * b->n[0]; uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E - c = c + (__int128)a.n[1] * b.n[4] + - (__int128)a.n[2] * b.n[3] + - (__int128)a.n[3] * b.n[2] + - (__int128)a.n[4] * b.n[1]; + c = c + (__int128)a->n[1] * b->n[4] + + (__int128)a->n[2] * b->n[3] + + (__int128)a->n[3] * b->n[2] + + (__int128)a->n[4] * b->n[1]; uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE - c = c + (__int128)a.n[2] * b.n[4] + - (__int128)a.n[3] * b.n[3] + - (__int128)a.n[4] * b.n[2]; + c = c + (__int128)a->n[2] * b->n[4] + + (__int128)a->n[3] * b->n[3] + + (__int128)a->n[4] * b->n[2]; uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE - c = c + (__int128)a.n[3] * b.n[4] + - (__int128)a.n[4] * b.n[3]; + c = c + (__int128)a->n[3] * b->n[4] + + (__int128)a->n[4] * b->n[3]; uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE - c = c + (__int128)a.n[4] * b.n[4]; + c = c + (__int128)a->n[4] * b->n[4]; uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E uint64_t t9 = c; @@ -211,52 +209,52 @@ void FieldElem::SetMult(const FieldElem &a, const FieldElem &b) { c = c + t1 + (__int128)t6 * 0x1000003D10ULL; t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 c = c + t2 + (__int128)t7 * 0x1000003D10ULL; - n[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 + r->n[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 c = c + t3 + (__int128)t8 * 0x1000003D10ULL; - n[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 + r->n[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 c = c + t4 + (__int128)t9 * 0x1000003D10ULL; - n[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110 + r->n[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110 c = t0 + (__int128)c * 0x1000003D1ULL; - n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008 - n[1] = t1 + c; + r->n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008 + r->n[1] = t1 + c; #endif -#ifdef VERIFY_MAGNITUDE - magnitude = 1; - normalized = false; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; #endif } -void FieldElem::SetSquare(const FieldElem &a) { -#ifdef VERIFY_MAGNITUDE - assert(a.magnitude <= 8); +void static secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +#ifdef VERIFY + assert(a->magnitude <= 8); #endif #ifdef INLINE_ASM - ExSetSquare((uint64_t *)a.n,(uint64_t *)n); + ExSetSquare((uint64_t*)&a->n, (uint64_t*)&r->n); #else - __int128 c = (__int128)a.n[0] * a.n[0]; + __int128 c = (__int128)a->n[0] * a->n[0]; uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0FFFFFFFFFFFFFE0 - c = c + (__int128)(a.n[0]*2) * a.n[1]; + c = c + (__int128)(a->n[0]*2) * a->n[1]; uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 20000000000000BF - c = c + (__int128)(a.n[0]*2) * a.n[2] + - (__int128)a.n[1] * a.n[1]; + c = c + (__int128)(a->n[0]*2) * a->n[2] + + (__int128)a->n[1] * a->n[1]; uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 30000000000001A0 - c = c + (__int128)(a.n[0]*2) * a.n[3] + - (__int128)(a.n[1]*2) * a.n[2]; + c = c + (__int128)(a->n[0]*2) * a->n[3] + + (__int128)(a->n[1]*2) * a->n[2]; uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 4000000000000280 - c = c + (__int128)(a.n[0]*2) * a.n[4] + - (__int128)(a.n[1]*2) * a.n[3] + - (__int128)a.n[2] * a.n[2]; + c = c + (__int128)(a->n[0]*2) * a->n[4] + + (__int128)(a->n[1]*2) * a->n[3] + + (__int128)a->n[2] * a->n[2]; uint64_t t4 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 320000000000037E - c = c + (__int128)(a.n[1]*2) * a.n[4] + - (__int128)(a.n[2]*2) * a.n[3]; + c = c + (__int128)(a->n[1]*2) * a->n[4] + + (__int128)(a->n[2]*2) * a->n[3]; uint64_t t5 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 22000000000002BE - c = c + (__int128)(a.n[2]*2) * a.n[4] + - (__int128)a.n[3] * a.n[3]; + c = c + (__int128)(a->n[2]*2) * a->n[4] + + (__int128)a->n[3] * a->n[3]; uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE - c = c + (__int128)(a.n[3]*2) * a.n[4]; + c = c + (__int128)(a->n[3]*2) * a->n[4]; uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE - c = c + (__int128)a.n[4] * a.n[4]; + c = c + (__int128)a->n[4] * a->n[4]; uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E uint64_t t9 = c; c = t0 + (__int128)t5 * 0x1000003D10ULL; @@ -264,149 +262,18 @@ void FieldElem::SetSquare(const FieldElem &a) { c = c + t1 + (__int128)t6 * 0x1000003D10ULL; t1 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 c = c + t2 + (__int128)t7 * 0x1000003D10ULL; - n[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 + r->n[2] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 c = c + t3 + (__int128)t8 * 0x1000003D10ULL; - n[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 + r->n[3] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 c = c + t4 + (__int128)t9 * 0x1000003D10ULL; - n[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110 + r->n[4] = c & 0x0FFFFFFFFFFFFULL; c = c >> 48; // c max 000001000003D110 c = t0 + (__int128)c * 0x1000003D1ULL; - n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008 - n[1] = t1 + c; + r->n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008 + r->n[1] = t1 + c; #endif -#ifdef VERIFY_MAGNITUDE - assert(a.magnitude <= 8); - normalized = false; +#ifdef VERIFY + assert(a->magnitude <= 8); + a->normalized = 0; #endif } - -void FieldElem::SetSquareRoot(const FieldElem &a) { - // calculate a^p, with p={15,780,1022,1023} - FieldElem a2; a2.SetSquare(a); - FieldElem a3; a3.SetMult(a2,a); - FieldElem a6; a6.SetSquare(a3); - FieldElem a12; a12.SetSquare(a6); - FieldElem a15; a15.SetMult(a12,a3); - FieldElem a30; a30.SetSquare(a15); - FieldElem a60; a60.SetSquare(a30); - FieldElem a120; a120.SetSquare(a60); - FieldElem a240; a240.SetSquare(a120); - FieldElem a255; a255.SetMult(a240,a15); - FieldElem a510; a510.SetSquare(a255); - FieldElem a750; a750.SetMult(a510,a240); - FieldElem a780; a780.SetMult(a750,a30); - FieldElem a1020; a1020.SetSquare(a510); - FieldElem a1022; a1022.SetMult(a1020,a2); - FieldElem a1023; a1023.SetMult(a1022,a); - FieldElem x = a15; - for (int i=0; i<21; i++) { - for (int j=0; j<10; j++) x.SetSquare(x); - x.SetMult(x,a1023); - } - for (int j=0; j<10; j++) x.SetSquare(x); - x.SetMult(x,a1022); - for (int i=0; i<2; i++) { - for (int j=0; j<10; j++) x.SetSquare(x); - x.SetMult(x,a1023); - } - for (int j=0; j<10; j++) x.SetSquare(x); - SetMult(x,a780); -} - -bool FieldElem::IsOdd() const { -#ifdef VERIFY_MAGNITUDE - assert(normalized); -#endif - return n[0] & 1; -} - -std::string FieldElem::ToString() { - unsigned char tmp[32]; - Normalize(); - GetBytes(tmp); - std::string ret; - for (int i=0; i<32; i++) { - static const char *c = "0123456789ABCDEF"; - ret += c[(tmp[i] >> 4) & 0xF]; - ret += c[(tmp[i]) & 0xF]; - } - return ret; -} - -void FieldElem::SetHex(const std::string &str) { - unsigned char tmp[32] = {}; - static const int cvt[256] = {0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 1, 2, 3, 4, 5, 6,7,8,9,0,0,0,0,0,0, - 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0, - 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0}; - for (unsigned int i=0; i<32; i++) { - if (str.length() > i*2) - tmp[32 - str.length()/2 + i] = (cvt[(unsigned char)str[2*i]] << 4) + cvt[(unsigned char)str[2*i+1]]; - } - SetBytes(tmp); -} - - -// Nonbuiltin Field Inverse is not constant time. -void FieldElem::SetInverse(FieldElem &a) { -#if defined(USE_FIELDINVERSE_BUILTIN) - // calculate a^p, with p={45,63,1019,1023} - FieldElem a2; a2.SetSquare(a); - FieldElem a3; a3.SetMult(a2,a); - FieldElem a4; a4.SetSquare(a2); - FieldElem a5; a5.SetMult(a4,a); - FieldElem a10; a10.SetSquare(a5); - FieldElem a11; a11.SetMult(a10,a); - FieldElem a21; a21.SetMult(a11,a10); - FieldElem a42; a42.SetSquare(a21); - FieldElem a45; a45.SetMult(a42,a3); - FieldElem a63; a63.SetMult(a42,a21); - FieldElem a126; a126.SetSquare(a63); - FieldElem a252; a252.SetSquare(a126); - FieldElem a504; a504.SetSquare(a252); - FieldElem a1008; a1008.SetSquare(a504); - FieldElem a1019; a1019.SetMult(a1008,a11); - FieldElem a1023; a1023.SetMult(a1019,a4); - FieldElem x = a63; - for (int i=0; i<21; i++) { - for (int j=0; j<10; j++) x.SetSquare(x); - x.SetMult(x,a1023); - } - for (int j=0; j<10; j++) x.SetSquare(x); - x.SetMult(x,a1019); - for (int i=0; i<2; i++) { - for (int j=0; j<10; j++) x.SetSquare(x); - x.SetMult(x,a1023); - } - for (int j=0; j<10; j++) x.SetSquare(x); - SetMult(x,a45); -#else - unsigned char b[32]; - a.Normalize(); - a.GetBytes(b); - { - const secp256k1_num_t &p = GetFieldConst().field_p; - secp256k1_num_t n; - secp256k1_num_init(&n); - secp256k1_num_set_bin(&n, b, 32); - secp256k1_num_mod_inverse(&n, &n, &p); - secp256k1_num_get_bin(b, 32, &n); - secp256k1_num_free(&n); - } - SetBytes(b); -#endif -} - -} diff --git a/field_5x52.h b/field_5x52.h index bf25aea..f6be208 100644 --- a/field_5x52.h +++ b/field_5x52.h @@ -1,80 +1,15 @@ #ifndef _SECP256K1_FIELD_5x52_ #define _SECP256K1_FIELD_5x52_ -using namespace std; - #include -#include -#include "num.h" - -// #define VERIFY_MAGNITUDE 1 - -namespace secp256k1 { - -/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, - * represented as 5 uint64_t's in base 2^52. he values are allowed to contain >52 each. In particular, - * each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element - * is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations - * accept any input with magnitude at most M, and have different rules for propagating magnitude to their - * output. - */ -class FieldElem { -private: +typedef struct { // X = sum(i=0..4, elem[i]*2^52) mod n uint64_t n[5]; -#ifdef VERIFY_MAGNITUDE +#ifdef VERIFY int magnitude; - bool normalized; + int normalized; #endif - -public: - - /** Creates a constant field element. Magnitude=1 */ - FieldElem(int x = 0); - - FieldElem(const unsigned char *b32); - - /** Normalizes the internal representation entries. Magnitude=1 */ - void Normalize(); - - bool IsZero() const; - - bool friend operator==(const FieldElem &a, const FieldElem &b); - - /** extract as 32-byte big endian array */ - void GetBytes(unsigned char *o); - - /** set value of 32-byte big endian array */ - void SetBytes(const unsigned char *in); - - /** Set a FieldElem to be the negative of another. Increases magnitude by one. */ - void SetNeg(const FieldElem &a, int magnitudeIn); - - /** Multiplies this FieldElem with an integer constant. Magnitude is multiplied by v */ - void operator*=(int v); - - void operator+=(const FieldElem &a); - - /** Set this FieldElem to be the multiplication of two others. Magnitude=1 (variable time) */ - void SetMult(const FieldElem &a, const FieldElem &b); - - /** Set this FieldElem to be the square of another. Magnitude=1 (variable time) */ - void SetSquare(const FieldElem &a); - - /** Set this to be the (modular) square root of another FieldElem. Magnitude=1 */ - void SetSquareRoot(const FieldElem &a); - - bool IsOdd() const; - - /** Set this to be the (modular) inverse of another FieldElem. Magnitude=1 (variable time) */ - void SetInverse(FieldElem &a); - - std::string ToString(); - - void SetHex(const std::string &str); -}; - -} +} secp256k1_fe_t; #endif diff --git a/group.cpp b/group.cpp index b19e5d1..6f4d1bf 100644 --- a/group.cpp +++ b/group.cpp @@ -10,7 +10,7 @@ GroupElem::GroupElem() { fInfinity = true; } -GroupElem::GroupElem(const FieldElem &xin, const FieldElem &yin) { +GroupElem::GroupElem(const secp256k1_fe_t &xin, const secp256k1_fe_t &yin) { fInfinity = false; x = xin; y = yin; @@ -22,30 +22,40 @@ bool GroupElem::IsInfinity() const { void GroupElem::SetNeg(const GroupElem &p) { *this = p; - y.Normalize(); - y.SetNeg(y, 1); + secp256k1_fe_normalize(&y); + secp256k1_fe_negate(&y, &y, 1); } -void GroupElem::GetX(FieldElem &xout) { +void GroupElem::GetX(secp256k1_fe_t &xout) { xout = x; } -void GroupElem::GetY(FieldElem &yout) { +void GroupElem::GetY(secp256k1_fe_t &yout) { yout = y; } std::string GroupElem::ToString() const { if (fInfinity) return "(inf)"; - FieldElem xc = x, yc = y; - return "(" + xc.ToString() + "," + yc.ToString() + ")"; + secp256k1_fe_t xc = x, yc = y; + char xo[65], yo[65]; + int xl = 65, yl = 65; + secp256k1_fe_get_hex(xo, &xl, &xc); + secp256k1_fe_get_hex(yo, &yl, &yc); + return "(" + std::string(xo) + "," + std::string(yo) + ")"; } -GroupElemJac::GroupElemJac() : GroupElem(), z(1) {} +GroupElemJac::GroupElemJac() : GroupElem() { + secp256k1_fe_set_int(&z, 1); +} -GroupElemJac::GroupElemJac(const FieldElem &xin, const FieldElem &yin) : GroupElem(xin,yin), z(1) {} +GroupElemJac::GroupElemJac(const secp256k1_fe_t &xin, const secp256k1_fe_t &yin) : GroupElem(xin,yin) { + secp256k1_fe_set_int(&z, 1); +} -GroupElemJac::GroupElemJac(const GroupElem &in) : GroupElem(in), z(1) {} +GroupElemJac::GroupElemJac(const GroupElem &in) : GroupElem(in) { + secp256k1_fe_set_int(&z, 1); +} void GroupElemJac::SetJac(const GroupElemJac &jac) { *this = jac; @@ -55,7 +65,7 @@ void GroupElemJac::SetAffine(const GroupElem &aff) { fInfinity = aff.fInfinity; x = aff.x; y = aff.y; - z = FieldElem(1); + secp256k1_fe_set_int(&z, 1); } bool GroupElemJac::IsValid() const { @@ -65,43 +75,38 @@ bool GroupElemJac::IsValid() const { // (Y/Z^3)^2 = (X/Z^2)^3 + 7 // Y^2 / Z^6 = X^3 / Z^6 + 7 // Y^2 = X^3 + 7*Z^6 - FieldElem y2; y2.SetSquare(y); - FieldElem x3; x3.SetSquare(x); x3.SetMult(x3,x); - FieldElem z2; z2.SetSquare(z); - FieldElem z6; z6.SetSquare(z2); z6.SetMult(z6,z2); - z6 *= 7; - x3 += z6; - y2.Normalize(); - x3.Normalize(); - return y2 == x3; + secp256k1_fe_t y2; secp256k1_fe_sqr(&y2, &y); + secp256k1_fe_t x3; secp256k1_fe_sqr(&x3, &x); secp256k1_fe_mul(&x3, &x3, &x); + secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &z); + secp256k1_fe_t z6; secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2); + secp256k1_fe_mul_int(&z6, 7); + secp256k1_fe_add(&x3, &z6); + secp256k1_fe_normalize(&y2); + secp256k1_fe_normalize(&x3); + return secp256k1_fe_equal(&y2, &x3); } void GroupElemJac::GetAffine(GroupElem &aff) { - z.SetInverse(z); - FieldElem z2; - z2.SetSquare(z); - FieldElem z3; - z3.SetMult(z,z2); - x.SetMult(x,z2); - y.SetMult(y,z3); - z = FieldElem(1); + secp256k1_fe_inv(&z, &z); + secp256k1_fe_t z2; secp256k1_fe_sqr(&z2, &z); + secp256k1_fe_t z3; secp256k1_fe_mul(&z3, &z, &z2); + secp256k1_fe_mul(&x, &x, &z2); + secp256k1_fe_mul(&y, &y, &z3); + secp256k1_fe_set_int(&z, 1); aff.fInfinity = fInfinity; aff.x = x; aff.y = y; } -void GroupElemJac::GetX(FieldElem &xout) { - FieldElem zi; - zi.SetInverse(z); - zi.SetSquare(zi); - xout.SetMult(x, zi); +void GroupElemJac::GetX(secp256k1_fe_t &xout) { + secp256k1_fe_t zi2; secp256k1_fe_inv(&zi2, &z); secp256k1_fe_sqr(&zi2, &zi2); + secp256k1_fe_mul(&xout, &x, &zi2); } -void GroupElemJac::GetY(FieldElem &yout) { - FieldElem zi; - zi.SetInverse(z); - FieldElem zi3; zi3.SetSquare(zi); zi3.SetMult(zi, zi3); - yout.SetMult(y, zi3); +void GroupElemJac::GetY(secp256k1_fe_t &yout) { + secp256k1_fe_t zi; secp256k1_fe_inv(&zi, &z); + secp256k1_fe_t zi3; secp256k1_fe_sqr(&zi3, &zi); secp256k1_fe_mul(&zi3, &zi, &zi3); + secp256k1_fe_mul(&yout, &y, &zi3); } bool GroupElemJac::IsInfinity() const { @@ -111,53 +116,53 @@ bool GroupElemJac::IsInfinity() const { void GroupElemJac::SetNeg(const GroupElemJac &p) { *this = p; - y.Normalize(); - y.SetNeg(y, 1); + secp256k1_fe_normalize(&y); + secp256k1_fe_negate(&y, &y, 1); } -void GroupElemJac::SetCompressed(const FieldElem &xin, bool fOdd) { +void GroupElemJac::SetCompressed(const secp256k1_fe_t &xin, bool fOdd) { x = xin; - FieldElem x2; x2.SetSquare(x); - FieldElem x3; x3.SetMult(x,x2); + secp256k1_fe_t x2; secp256k1_fe_sqr(&x2, &x); + secp256k1_fe_t x3; secp256k1_fe_mul(&x3, &x, &x2); fInfinity = false; - FieldElem c(7); - c += x3; - y.SetSquareRoot(c); - z = FieldElem(1); - y.Normalize(); - if (y.IsOdd() != fOdd) - y.SetNeg(y,1); + secp256k1_fe_t c; secp256k1_fe_set_int(&c, 7); + secp256k1_fe_add(&c, &x3); + secp256k1_fe_sqrt(&y, &c); + secp256k1_fe_set_int(&z, 1); + secp256k1_fe_normalize(&y); + if (secp256k1_fe_is_odd(&y) != fOdd) + secp256k1_fe_negate(&y, &y, 1); } void GroupElemJac::SetDouble(const GroupElemJac &p) { - FieldElem t5 = p.y; - t5.Normalize(); - if (p.fInfinity || t5.IsZero()) { + secp256k1_fe_t t5 = p.y; + secp256k1_fe_normalize(&t5); + if (p.fInfinity || secp256k1_fe_is_zero(&t5)) { fInfinity = true; return; } - FieldElem t1,t2,t3,t4; - z.SetMult(t5,p.z); - z *= 2; // Z' = 2*Y*Z (2) - t1.SetSquare(p.x); - t1 *= 3; // T1 = 3*X^2 (3) - t2.SetSquare(t1); // T2 = 9*X^4 (1) - t3.SetSquare(t5); - t3 *= 2; // T3 = 2*Y^2 (2) - t4.SetSquare(t3); - t4 *= 2; // T4 = 8*Y^4 (2) - t3.SetMult(p.x,t3); // T3 = 2*X*Y^2 (1) + secp256k1_fe_t t1,t2,t3,t4; + secp256k1_fe_mul(&z, &t5, &p.z); + secp256k1_fe_mul_int(&z, 2); // Z' = 2*Y*Z (2) + secp256k1_fe_sqr(&t1, &p.x); + secp256k1_fe_mul_int(&t1, 3); // T1 = 3*X^2 (3) + secp256k1_fe_sqr(&t2, &t1); // T2 = 9*X^4 (1) + secp256k1_fe_sqr(&t3, &t5); + secp256k1_fe_mul_int(&t3, 2); // T3 = 2*Y^2 (2) + secp256k1_fe_sqr(&t4, &t3); + secp256k1_fe_mul_int(&t4, 2); // T4 = 8*Y^4 (2) + secp256k1_fe_mul(&t3, &p.x, &t3); // T3 = 2*X*Y^2 (1) x = t3; - x *= 4; // X' = 8*X*Y^2 (4) - x.SetNeg(x,4); // X' = -8*X*Y^2 (5) - x += t2; // X' = 9*X^4 - 8*X*Y^2 (6) - t2.SetNeg(t2,1); // T2 = -9*X^4 (2) - t3 *= 6; // T3 = 12*X*Y^2 (6) - t3 += t2; // T3 = 12*X*Y^2 - 9*X^4 (8) - y.SetMult(t1,t3); // Y' = 36*X^3*Y^2 - 27*X^6 (1) - t2.SetNeg(t4,2); // T2 = -8*Y^4 (3) - y += t2; // Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) + secp256k1_fe_mul_int(&x, 4); // X' = 8*X*Y^2 (4) + secp256k1_fe_negate(&x, &x, 4); // X' = -8*X*Y^2 (5) + secp256k1_fe_add(&x, &t2); // X' = 9*X^4 - 8*X*Y^2 (6) + secp256k1_fe_negate(&t2, &t2, 1); // T2 = -9*X^4 (2) + secp256k1_fe_mul_int(&t3, 6); // T3 = 12*X*Y^2 (6) + secp256k1_fe_add(&t3, &t2); // T3 = 12*X*Y^2 - 9*X^4 (8) + secp256k1_fe_mul(&y, &t1, &t3); // Y' = 36*X^3*Y^2 - 27*X^6 (1) + secp256k1_fe_negate(&t2, &t4, 2); // T2 = -8*Y^4 (3) + secp256k1_fe_add(&y, &t2); // Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) fInfinity = false; } @@ -171,36 +176,36 @@ void GroupElemJac::SetAdd(const GroupElemJac &p, const GroupElemJac &q) { return; } fInfinity = false; - const FieldElem &x1 = p.x, &y1 = p.y, &z1 = p.z, &x2 = q.x, &y2 = q.y, &z2 = q.z; - FieldElem z22; z22.SetSquare(z2); - FieldElem z12; z12.SetSquare(z1); - FieldElem u1; u1.SetMult(x1, z22); - FieldElem u2; u2.SetMult(x2, z12); - FieldElem s1; s1.SetMult(y1, z22); s1.SetMult(s1, z2); - FieldElem s2; s2.SetMult(y2, z12); s2.SetMult(s2, z1); - u1.Normalize(); - u2.Normalize(); - if (u1 == u2) { - s1.Normalize(); - s2.Normalize(); - if (s1 == s2) { + const secp256k1_fe_t &x1 = p.x, &y1 = p.y, &z1 = p.z, &x2 = q.x, &y2 = q.y, &z2 = q.z; + secp256k1_fe_t z22; secp256k1_fe_sqr(&z22, &z2); + secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &z1); + secp256k1_fe_t u1; secp256k1_fe_mul(&u1, &x1, &z22); + secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &x2, &z12); + secp256k1_fe_t s1; secp256k1_fe_mul(&s1, &y1, &z22); secp256k1_fe_mul(&s1, &s1, &z2); + secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &y2, &z12); secp256k1_fe_mul(&s2, &s2, &z1); + secp256k1_fe_normalize(&u1); + secp256k1_fe_normalize(&u2); + if (secp256k1_fe_equal(&u1, &u2)) { + secp256k1_fe_normalize(&s1); + secp256k1_fe_normalize(&s2); + if (secp256k1_fe_equal(&s1, &s2)) { SetDouble(p); } else { fInfinity = true; } return; } - FieldElem h; h.SetNeg(u1,1); h += u2; - FieldElem r; r.SetNeg(s1,1); r += s2; - FieldElem r2; r2.SetSquare(r); - FieldElem h2; h2.SetSquare(h); - FieldElem h3; h3.SetMult(h,h2); - z.SetMult(z1,z2); z.SetMult(z, h); - FieldElem t; t.SetMult(u1,h2); - x = t; x *= 2; x += h3; x.SetNeg(x,3); x += r2; - y.SetNeg(x,5); y += t; y.SetMult(y,r); - h3.SetMult(h3,s1); h3.SetNeg(h3,1); - y += h3; + secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_t r; secp256k1_fe_negate(&r, &s1, 1); secp256k1_fe_add(&r, &s2); + secp256k1_fe_t r2; secp256k1_fe_sqr(&r2, &r); + secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2); + secp256k1_fe_mul(&z, &z1, &z2); secp256k1_fe_mul(&z, &z, &h); + secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2); + x = t; secp256k1_fe_mul_int(&x, 2); secp256k1_fe_add(&x, &h3); secp256k1_fe_negate(&x, &x, 3); secp256k1_fe_add(&x, &r2); + secp256k1_fe_negate(&y, &x, 5); secp256k1_fe_add(&y, &t); secp256k1_fe_mul(&y, &y, &r); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + secp256k1_fe_add(&y, &h3); } void GroupElemJac::SetAdd(const GroupElemJac &p, const GroupElem &q) { @@ -208,7 +213,7 @@ void GroupElemJac::SetAdd(const GroupElemJac &p, const GroupElem &q) { x = q.x; y = q.y; fInfinity = q.fInfinity; - z = FieldElem(1); + secp256k1_fe_set_int(&z, 1); return; } if (q.fInfinity) { @@ -216,35 +221,35 @@ void GroupElemJac::SetAdd(const GroupElemJac &p, const GroupElem &q) { return; } fInfinity = false; - const FieldElem &x1 = p.x, &y1 = p.y, &z1 = p.z, &x2 = q.x, &y2 = q.y; - FieldElem z12; z12.SetSquare(z1); - FieldElem u1 = x1; u1.Normalize(); - FieldElem u2; u2.SetMult(x2, z12); - FieldElem s1 = y1; s1.Normalize(); - FieldElem s2; s2.SetMult(y2, z12); s2.SetMult(s2, z1); - u1.Normalize(); - u2.Normalize(); - if (u1 == u2) { - s1.Normalize(); - s2.Normalize(); - if (s1 == s2) { + const secp256k1_fe_t &x1 = p.x, &y1 = p.y, &z1 = p.z, &x2 = q.x, &y2 = q.y; + secp256k1_fe_t z12; secp256k1_fe_sqr(&z12, &z1); + secp256k1_fe_t u1 = x1; secp256k1_fe_normalize(&u1); + secp256k1_fe_t u2; secp256k1_fe_mul(&u2, &x2, &z12); + secp256k1_fe_t s1 = y1; secp256k1_fe_normalize(&s1); + secp256k1_fe_t s2; secp256k1_fe_mul(&s2, &y2, &z12); secp256k1_fe_mul(&s2, &s2, &z1); + secp256k1_fe_normalize(&u1); + secp256k1_fe_normalize(&u2); + if (secp256k1_fe_equal(&u1, &u2)) { + secp256k1_fe_normalize(&s1); + secp256k1_fe_normalize(&s2); + if (secp256k1_fe_equal(&s1, &s2)) { SetDouble(p); } else { fInfinity = true; } return; } - FieldElem h; h.SetNeg(u1,1); h += u2; - FieldElem r; r.SetNeg(s1,1); r += s2; - FieldElem r2; r2.SetSquare(r); - FieldElem h2; h2.SetSquare(h); - FieldElem h3; h3.SetMult(h,h2); - z = p.z; z.SetMult(z, h); - FieldElem t; t.SetMult(u1,h2); - x = t; x *= 2; x += h3; x.SetNeg(x,3); x += r2; - y.SetNeg(x,5); y += t; y.SetMult(y,r); - h3.SetMult(h3,s1); h3.SetNeg(h3,1); - y += h3; + secp256k1_fe_t h; secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_t r; secp256k1_fe_negate(&r, &s1, 1); secp256k1_fe_add(&r, &s2); + secp256k1_fe_t r2; secp256k1_fe_sqr(&r2, &r); + secp256k1_fe_t h2; secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_t h3; secp256k1_fe_mul(&h3, &h, &h2); + z = p.z; secp256k1_fe_mul(&z, &z, &h); + secp256k1_fe_t t; secp256k1_fe_mul(&t, &u1, &h2); + x = t; secp256k1_fe_mul_int(&x, 2); secp256k1_fe_add(&x, &h3); secp256k1_fe_negate(&x, &x, 3); secp256k1_fe_add(&x, &r2); + secp256k1_fe_negate(&y, &x, 5); secp256k1_fe_add(&y, &t); secp256k1_fe_mul(&y, &y, &r); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + secp256k1_fe_add(&y, &h3); } std::string GroupElemJac::ToString() const { @@ -290,15 +295,19 @@ static const unsigned char a2_[] = {0x01, 0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6, 0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8}; -GroupConstants::GroupConstants() : g_x(g_x_), g_y(g_y_), - g(g_x,g_y), - beta(beta_) { +GroupConstants::GroupConstants() { secp256k1_num_init(&order); secp256k1_num_init(&lambda); secp256k1_num_init(&a1b2); secp256k1_num_init(&b1); secp256k1_num_init(&a2); + secp256k1_fe_set_b32(&g_x, g_x_); + secp256k1_fe_set_b32(&g_y, g_y_); + secp256k1_fe_set_b32(&beta, beta_); + + g = GroupElem(g_x, g_y); + secp256k1_num_set_bin(&order, order_, sizeof(order_)); secp256k1_num_set_bin(&lambda, lambda_, sizeof(lambda_)); secp256k1_num_set_bin(&a1b2, a1b2_, sizeof(a1b2_)); @@ -320,9 +329,9 @@ const GroupConstants &GetGroupConst() { } void GroupElemJac::SetMulLambda(const GroupElemJac &p) { - FieldElem beta = GetGroupConst().beta; + const secp256k1_fe_t &beta = GetGroupConst().beta; *this = p; - x.SetMult(x, beta); + secp256k1_fe_mul(&x, &x, &beta); } void SplitExp(const secp256k1_num_t &exp, secp256k1_num_t &exp1, secp256k1_num_t &exp2) { diff --git a/group.h b/group.h index 6fe7e38..0a46208 100644 --- a/group.h +++ b/group.h @@ -14,8 +14,8 @@ class GroupElemJac; class GroupElem { protected: bool fInfinity; - FieldElem x; - FieldElem y; + secp256k1_fe_t x; + secp256k1_fe_t y; public: @@ -23,16 +23,16 @@ public: GroupElem(); /** Creates the point with given affine coordinates */ - GroupElem(const FieldElem &xin, const FieldElem &yin); + GroupElem(const secp256k1_fe_t &xin, const secp256k1_fe_t &yin); /** Checks whether this is the point at infinity */ bool IsInfinity() const; void SetNeg(const GroupElem &p); - void GetX(FieldElem &xout); + void GetX(secp256k1_fe_t &xout); - void GetY(FieldElem &yout); + void GetY(secp256k1_fe_t &yout); std::string ToString() const; @@ -44,14 +44,14 @@ public: /** Represents a point on the secp256k1 curve, with jacobian coordinates */ class GroupElemJac : private GroupElem { protected: - FieldElem z; + secp256k1_fe_t z; public: /** Creates the point at infinity */ GroupElemJac(); /** Creates the point with given affine coordinates */ - GroupElemJac(const FieldElem &xin, const FieldElem &yin); + GroupElemJac(const secp256k1_fe_t &xin, const secp256k1_fe_t &yin); GroupElemJac(const GroupElem &in); @@ -65,15 +65,15 @@ public: /** Returns the affine coordinates of this point */ void GetAffine(GroupElem &aff); - void GetX(FieldElem &xout); - void GetY(FieldElem &yout); + void GetX(secp256k1_fe_t &xout); + void GetY(secp256k1_fe_t &yout); bool IsInfinity() const; void SetNeg(const GroupElemJac &p); /** Sets this point to have a given X coordinate & given Y oddness */ - void SetCompressed(const FieldElem &xin, bool fOdd); + void SetCompressed(const secp256k1_fe_t &xin, bool fOdd); /** Sets this point to be the EC double of another */ void SetDouble(const GroupElemJac &p); @@ -91,13 +91,13 @@ public: class GroupConstants { private: - const FieldElem g_x; - const FieldElem g_y; + secp256k1_fe_t g_x; + secp256k1_fe_t g_y; public: secp256k1_num_t order; - const GroupElem g; - const FieldElem beta; + GroupElem g; + secp256k1_fe_t beta; secp256k1_num_t lambda, a1b2, b1, a2; GroupConstants(); diff --git a/tests.cpp b/tests.cpp index f76a870..0d5ca87 100644 --- a/tests.cpp +++ b/tests.cpp @@ -13,8 +13,8 @@ using namespace secp256k1; void test_run_ecmult_chain() { // random starting point A (on the curve) - FieldElem ax; ax.SetHex("8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004"); - FieldElem ay; ay.SetHex("a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f"); + secp256k1_fe_t ax; secp256k1_fe_set_hex(&ax, "8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004", 64); + secp256k1_fe_t ay; secp256k1_fe_set_hex(&ay, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64); GroupElemJac a(ax,ay); // two random initial factors xn and gn secp256k1_num_t xn; @@ -85,13 +85,15 @@ void test_point_times_order(const GroupElemJac &point) { } void test_run_point_times_order() { - FieldElem x; x.SetHex("02"); + secp256k1_fe_t x; secp256k1_fe_set_hex(&x, "02", 2); for (int i=0; i<500; i++) { GroupElemJac j; j.SetCompressed(x, true); test_point_times_order(j); - x.SetSquare(x); + secp256k1_fe_sqr(&x, &x); } - assert(x.ToString() == "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45"); // 0x02 ^ (2^500) + char c[65]; int cl=65; + secp256k1_fe_get_hex(c, &cl, &x); + assert(strcmp(c, "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45") == 0); } void test_wnaf(const secp256k1_num_t &number, int w) { @@ -173,10 +175,13 @@ void test_run_ecdsa_sign_verify() { int main(void) { secp256k1_num_start(); + secp256k1_fe_start(); test_run_wnaf(); test_run_point_times_order(); test_run_ecmult_chain(); test_run_ecdsa_sign_verify(); + + secp256k1_fe_stop(); return 0; }