diff --git a/field.cpp b/field.cpp new file mode 100644 index 00000000000..c5993961aad --- /dev/null +++ b/field.cpp @@ -0,0 +1,386 @@ +using namespace std; + +#include +#include +#include + +#include "num.h" +#include "field.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. 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 + * 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. + */ + +FieldElem::FieldElem(int x) { + n[0] = x; + n[1] = n[2] = n[3] = n[4] = 0; +#ifdef VERIFY_MAGNITUDE + magnitude = 1; +#endif +} + +FieldElem::FieldElem(const unsigned char *b32) { + SetBytes(b32); +} + +void FieldElem::Normalize() { + uint64_t c; + if (n[0] > 0xFFFFFFFFFFFFFULL || n[1] > 0xFFFFFFFFFFFFFULL || n[2] > 0xFFFFFFFFFFFFFULL || n[3] > 0xFFFFFFFFFFFFFULL || n[4] > 0xFFFFFFFFFFFFULL) { + c = n[0]; + uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; + c = (c >> 52) + n[1]; + uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; + c = (c >> 52) + n[2]; + uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; + c = (c >> 52) + n[3]; + uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; + c = (c >> 52) + n[4]; + uint64_t t4 = c & 0x0FFFFFFFFFFFFULL; + c >>= 48; + if (c) { + c = c * 0x1000003D1ULL + t0; + t0 = c & 0xFFFFFFFFFFFFFULL; + c = (c >> 52) + t1; + t1 = c & 0xFFFFFFFFFFFFFULL; + c = (c >> 52) + t2; + t2 = c & 0xFFFFFFFFFFFFFULL; + c = (c >> 52) + t3; + t3 = c & 0xFFFFFFFFFFFFFULL; + c = (c >> 52) + t4; + t4 = c & 0x0FFFFFFFFFFFFULL; + c >>= 48; + } + n[0] = t0; n[1] = t1; n[2] = t2; n[3] = t3; n[4] = t4; + } + if (n[4] == 0xFFFFFFFFFFFFULL && n[3] == 0xFFFFFFFFFFFFFULL && n[2] == 0xFFFFFFFFFFFFFULL && n[1] == 0xFFFFFFFFFFFFF && n[0] >= 0xFFFFEFFFFFC2FULL) { + n[4] = 0; + n[3] = 0; + n[2] = 0; + n[1] = 0; + n[0] -= 0xFFFFEFFFFFC2FULL; + } +#ifdef VERIFY_MAGNITUDE + magnitude = 1; +#endif +} + +bool FieldElem::IsZero() { + Normalize(); + return (n[0] == 0 && n[1] == 0 && n[2] == 0 && n[3] == 0 && n[4] == 0); +} + +bool operator==(FieldElem &a, FieldElem &b) { + a.Normalize(); + b.Normalize(); + 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 FieldElem::GetBytes(unsigned char *o) { + Normalize(); + 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); + } + o[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; +#endif +} + +void FieldElem::SetNeg(const FieldElem &a, int magnitudeIn) { +#ifdef VERIFY_MAGNITUDE + assert(a.magnitude <= magnitudeIn); + magnitude = magnitudeIn + 1; +#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]; +} + +void FieldElem::operator*=(int v) { +#ifdef VERIFY_MAGNITUDE + magnitude *= v; +#endif + n[0] *= v; + n[1] *= v; + n[2] *= v; + n[3] *= v; + n[4] *= v; +} + +void FieldElem::operator+=(const FieldElem &a) { +#ifdef VERIFY_MAGNITUDE + magnitude += a.magnitude; +#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); +#endif + __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]; + 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]; + 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]; + 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]; + 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]; + 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]; + 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]; + uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE + c = c + (__int128)a.n[4] * b.n[4]; + uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E + uint64_t t9 = c; + c = t0 + (__int128)t5 * 0x1000003D10ULL; + + t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 + 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 + c = c + t3 + (__int128)t8 * 0x1000003D10ULL; + 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 + c = t0 + (__int128)c * 0x1000003D1ULL; + n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008 + n[1] = t1 + c; +#ifdef VERIFY_MAGNITUDE + magnitude = 1; +#endif +} + +void FieldElem::SetSquare(const FieldElem &a) { +#ifdef VERIFY_MAGNITUDE + assert(a.magnitude <= 8); +#endif + __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]; + 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]; + 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]; + 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]; + 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]; + 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]; + uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE + 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]; + uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E + uint64_t t9 = c; + c = t0 + (__int128)t5 * 0x1000003D10ULL; + t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 + 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 + c = c + t3 + (__int128)t8 * 0x1000003D10ULL; + 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 + c = t0 + (__int128)c * 0x1000003D1ULL; + n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008 + n[1] = t1 + c; +#ifdef VERIFY_MAGNITUDE + assert(a.magnitude <= 8); +#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() { + Normalize(); + return n[0] & 1; +} + +std::string FieldElem::ToString() { + unsigned char tmp[32]; + 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); +} + +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() : field_p(ctx, field_p_, sizeof(field_p_)) {} + +const FieldConstants &GetFieldConst() { + static const FieldConstants field_const; + return field_const; +} + +void FieldElem::SetInverse(Context &ctx, 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.GetBytes(b); + { + const Number &p = GetFieldConst().field_p; + Context ct(ctx); + Number n(ct); n.SetBytes(b, 32); + n.SetModInverse(ct, n, p); + n.GetBytes(b, 32); + } + SetBytes(b); +#endif +} + +} diff --git a/field.h b/field.h index d67c01adcc2..705374eaa00 100644 --- a/field.h +++ b/field.h @@ -3,7 +3,6 @@ using namespace std; -#include #include #include @@ -22,7 +21,7 @@ namespace secp256k1 { */ class FieldElem { private: - // X = sum(i=0..4, elem[i]*2^52) + // X = sum(i=0..4, elem[i]*2^52) mod n uint64_t n[5]; #ifdef VERIFY_MAGNITUDE int magnitude; @@ -31,328 +30,50 @@ private: public: /** Creates a constant field element. Magnitude=1 */ - FieldElem(int x = 0) { - n[0] = x; - n[1] = n[2] = n[3] = n[4] = 0; -#ifdef VERIFY_MAGNITUDE - magnitude = 1; -#endif - } + FieldElem(int x = 0); - FieldElem(const unsigned char *b32) { - SetBytes(b32); - } + FieldElem(const unsigned char *b32); /** Normalizes the internal representation entries. Magnitude=1 */ - void Normalize() { - uint64_t c; - if (n[0] > 0xFFFFFFFFFFFFFULL || n[1] > 0xFFFFFFFFFFFFFULL || n[2] > 0xFFFFFFFFFFFFFULL || n[3] > 0xFFFFFFFFFFFFFULL || n[4] > 0xFFFFFFFFFFFFULL) { - c = n[0]; - uint64_t t0 = c & 0xFFFFFFFFFFFFFULL; - c = (c >> 52) + n[1]; - uint64_t t1 = c & 0xFFFFFFFFFFFFFULL; - c = (c >> 52) + n[2]; - uint64_t t2 = c & 0xFFFFFFFFFFFFFULL; - c = (c >> 52) + n[3]; - uint64_t t3 = c & 0xFFFFFFFFFFFFFULL; - c = (c >> 52) + n[4]; - uint64_t t4 = c & 0x0FFFFFFFFFFFFULL; - c >>= 48; - if (c) { - c = c * 0x1000003D1ULL + t0; - t0 = c & 0xFFFFFFFFFFFFFULL; - c = (c >> 52) + t1; - t1 = c & 0xFFFFFFFFFFFFFULL; - c = (c >> 52) + t2; - t2 = c & 0xFFFFFFFFFFFFFULL; - c = (c >> 52) + t3; - t3 = c & 0xFFFFFFFFFFFFFULL; - c = (c >> 52) + t4; - t4 = c & 0x0FFFFFFFFFFFFULL; - c >>= 48; - } - n[0] = t0; n[1] = t1; n[2] = t2; n[3] = t3; n[4] = t4; - } - if (n[4] == 0xFFFFFFFFFFFFULL && n[3] == 0xFFFFFFFFFFFFFULL && n[2] == 0xFFFFFFFFFFFFFULL && n[1] == 0xFFFFFFFFFFFFF && n[0] >= 0xFFFFEFFFFFC2FULL) { - n[4] = 0; - n[3] = 0; - n[2] = 0; - n[1] = 0; - n[0] -= 0xFFFFEFFFFFC2FULL; - } -#ifdef VERIFY_MAGNITUDE - magnitude = 1; -#endif - } + void Normalize(); - bool IsZero() { - Normalize(); - return (n[0] == 0 && n[1] == 0 && n[2] == 0 && n[3] == 0 && n[4] == 0); - } + bool IsZero(); - bool friend operator==(FieldElem &a, FieldElem &b) { - a.Normalize(); - b.Normalize(); - 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]); - } + bool friend operator==(FieldElem &a, FieldElem &b); /** extract as 32-byte big endian array */ - void GetBytes(unsigned char *o) { - Normalize(); - 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); - } - o[31-i] = c; - } - } + void GetBytes(unsigned char *o); /** set value of 32-byte big endian array */ - void 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; -#endif - } + 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) { -#ifdef VERIFY_MAGNITUDE - assert(a.magnitude <= magnitudeIn); - magnitude = magnitudeIn + 1; -#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]; - } + void SetNeg(const FieldElem &a, int magnitudeIn); /** Multiplies this FieldElem with an integer constant. Magnitude is multiplied by v */ - void operator*=(int v) { -#ifdef VERIFY_MAGNITUDE - magnitude *= v; -#endif - n[0] *= v; - n[1] *= v; - n[2] *= v; - n[3] *= v; - n[4] *= v; - } + void operator*=(int v); - void operator+=(const FieldElem &a) { -#ifdef VERIFY_MAGNITUDE - magnitude += a.magnitude; -#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 operator+=(const FieldElem &a); /** Set this FieldElem to be the multiplication of two others. Magnitude=1 */ - void SetMult(const FieldElem &a, const FieldElem &b) { -#ifdef VERIFY_MAGNITUDE - assert(a.magnitude <= 8); - assert(b.magnitude <= 8); -#endif - __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]; - 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]; - 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]; - 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]; - 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]; - 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]; - 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]; - uint64_t t7 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 02000000000000FE - c = c + (__int128)a.n[4] * b.n[4]; - uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E - uint64_t t9 = c; - c = t0 + (__int128)t5 * 0x1000003D10ULL; - t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 - 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 - c = c + t3 + (__int128)t8 * 0x1000003D10ULL; - 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 - c = t0 + (__int128)c * 0x1000003D1ULL; - n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008 - n[1] = t1 + c; -#ifdef VERIFY_MAGNITUDE - magnitude = 1; -#endif - } + void SetMult(const FieldElem &a, const FieldElem &b); /** Set this FieldElem to be the square of another. Magnitude=1 */ - void SetSquare(const FieldElem &a) { -#ifdef VERIFY_MAGNITUDE - assert(a.magnitude <= 8); -#endif - __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]; - 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]; - 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]; - 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]; - 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]; - 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]; - uint64_t t6 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 12000000000001DE - 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]; - uint64_t t8 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 001000000000001E - uint64_t t9 = c; - c = t0 + (__int128)t5 * 0x1000003D10ULL; - t0 = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 0000001000003D10 - 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 - c = c + t3 + (__int128)t8 * 0x1000003D10ULL; - 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 - c = t0 + (__int128)c * 0x1000003D1ULL; - n[0] = c & 0xFFFFFFFFFFFFFULL; c = c >> 52; // c max 1000008 - n[1] = t1 + c; -#ifdef VERIFY_MAGNITUDE - assert(a.magnitude <= 8); -#endif - } + void SetSquare(const FieldElem &a); /** Set this to be the (modular) square root of another FieldElem. Magnitude=1 */ - void 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); - } + void SetSquareRoot(const FieldElem &a); - bool IsOdd() { - Normalize(); - return n[0] & 1; - } + bool IsOdd(); /** Set this to be the (modular) inverse of another FieldElem. Magnitude=1 */ void SetInverse(Context &ctx, FieldElem &a); - std::string ToString() { - unsigned char tmp[32]; - 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; - } + std::string ToString(); - void 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); - } + void SetHex(const std::string &str); }; -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}; - class FieldConstants { private: Context ctx; @@ -360,59 +81,10 @@ private: public: const Number field_p; - FieldConstants() : field_p(ctx, field_p_, sizeof(field_p_)) {} + FieldConstants(); }; -const FieldConstants &GetFieldConst() { - static const FieldConstants field_const; - return field_const; -} - -void FieldElem::SetInverse(Context &ctx, 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.GetBytes(b); - { - const Number &p = GetFieldConst().field_p; - Context ct(ctx); - Number n(ct); n.SetBytes(b, 32); - n.SetModInverse(ct, n, p); - n.GetBytes(b, 32); - } - SetBytes(b); -#endif -} +const FieldConstants &GetFieldConst(); }