From e6d142a8dc3d465c7e3c00183f510437108c73ad Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 30 Mar 2013 21:49:09 +0100 Subject: [PATCH] Move 5x52 specific code to field_5x52 --- Makefile | 6 +- field.cpp | 409 +----------------------------------------------- field.h | 73 +-------- field_5x52.cpp | 412 +++++++++++++++++++++++++++++++++++++++++++++++++ field_5x52.h | 80 ++++++++++ 5 files changed, 499 insertions(+), 481 deletions(-) create mode 100644 field_5x52.cpp create mode 100644 field_5x52.h diff --git a/Makefile b/Makefile index b84e7c02454..2f0454d9a0c 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,8 @@ FLAGS_PROD:=-DNDEBUG -O2 -march=native FLAGS_DEBUG:=-DVERIFY_MAGNITUDE -ggdb3 -O1 FLAGS_TEST:=-DVERIFY_MAGNITUDE -ggdb3 -O2 -march=native -SECP256K1_FILES := num.h field.h group.h ecmult.h ecdsa.h \ - num.cpp field.cpp group.cpp ecmult.cpp ecdsa.cpp +SECP256K1_FILES := num.h field.h field_5x52.h group.h ecmult.h ecdsa.h \ + num.cpp field.cpp field_5x52.cpp group.cpp ecmult.cpp ecdsa.cpp ifndef CONF CONF := gmp @@ -46,7 +46,7 @@ clean: bench-any: bench-$(CONF) tests-any: tests-$(CONF) -all-$(CONF): bench-$(CONF) tests-$(CONF) +all-$(CONF): bench-$(CONF) tests-$(CONF) obj/secp256k1-$(CONF).o clean-$(CONF): rm -f bench-$(CONF) tests-$(CONF) obj/secp256k1-$(CONF).o diff --git a/field.cpp b/field.cpp index 748572a58ee..e3d2dd6bb61 100644 --- a/field.cpp +++ b/field.cpp @@ -1,363 +1,8 @@ -#include -#include -#include -#include "num.h" -#include "field.h" -#include - -using namespace std; - -#ifdef INLINE_ASM -#include "lin64.h" -#endif +// just one implementation for now +#include "field_5x52.cpp" 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; - normalized = true; -#endif -} - -FieldElem::FieldElem(const unsigned char *b32) { - SetBytes(b32); -} - -void FieldElem::Normalize() { - uint64_t c; - 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; - - // The following code will not modify the t's if c is initially 0. - 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; - - // 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); - -#ifdef VERIFY_MAGNITUDE - magnitude = 1; - normalized = true; -#endif -} - -bool inline FieldElem::IsZero() const { -#ifdef VERIFY_MAGNITUDE - assert(normalized); -#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); -#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 FieldElem::GetBytes(unsigned char *o) { -#ifdef VERIFY_MAGNITUDE - assert(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); - } - 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; - normalized = true; -#endif -} - -void inline FieldElem::SetNeg(const FieldElem &a, int magnitudeIn) { -#ifdef VERIFY_MAGNITUDE - assert(a.magnitude <= magnitudeIn); - magnitude = magnitudeIn + 1; - 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]; -} - -void inline FieldElem::operator*=(int v) { -#ifdef VERIFY_MAGNITUDE - magnitude *= v; - normalized = false; -#endif - n[0] *= v; - n[1] *= v; - n[2] *= v; - n[3] *= v; - n[4] *= v; -} - -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); -#endif - -#ifdef INLINE_ASM - ExSetMult((uint64_t *) a.n,(uint64_t *) b.n, (uint64_t *) n); -#else - 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]; - 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; -#endif -#ifdef VERIFY_MAGNITUDE - magnitude = 1; - normalized = false; -#endif -} - -void FieldElem::SetSquare(const FieldElem &a) { -#ifdef VERIFY_MAGNITUDE - assert(a.magnitude <= 8); -#endif - -#ifdef INLINE_ASM - ExSetSquare((uint64_t *)a.n,(uint64_t *)n); -#else - __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; -#endif - -#ifdef VERIFY_MAGNITUDE - assert(a.magnitude <= 8); - normalized = false; -#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); -} - 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, @@ -377,54 +22,4 @@ const FieldConstants &GetFieldConst() { return field_const; } -// 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.h b/field.h index 3851409832e..873b5f695af 100644 --- a/field.h +++ b/field.h @@ -1,80 +1,11 @@ #ifndef _SECP256K1_FIELD_ #define _SECP256K1_FIELD_ -using namespace std; - -#include -#include - -#include "num.h" - -// #define VERIFY_MAGNITUDE 1 +// just one implementation for now +#include "field_5x52.h" 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: - // X = sum(i=0..4, elem[i]*2^52) mod n - uint64_t n[5]; -#ifdef VERIFY_MAGNITUDE - int magnitude; - bool 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); -}; - class FieldConstants { public: secp256k1_num_t field_p; diff --git a/field_5x52.cpp b/field_5x52.cpp new file mode 100644 index 00000000000..bc08ecc35fa --- /dev/null +++ b/field_5x52.cpp @@ -0,0 +1,412 @@ +#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 + * 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; + normalized = true; +#endif +} + +FieldElem::FieldElem(const unsigned char *b32) { + SetBytes(b32); +} + +void FieldElem::Normalize() { + uint64_t c; + 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; + + // The following code will not modify the t's if c is initially 0. + 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; + + // 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); + +#ifdef VERIFY_MAGNITUDE + magnitude = 1; + normalized = true; +#endif +} + +bool inline FieldElem::IsZero() const { +#ifdef VERIFY_MAGNITUDE + assert(normalized); +#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); +#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 FieldElem::GetBytes(unsigned char *o) { +#ifdef VERIFY_MAGNITUDE + assert(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); + } + 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; + normalized = true; +#endif +} + +void inline FieldElem::SetNeg(const FieldElem &a, int magnitudeIn) { +#ifdef VERIFY_MAGNITUDE + assert(a.magnitude <= magnitudeIn); + magnitude = magnitudeIn + 1; + 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]; +} + +void inline FieldElem::operator*=(int v) { +#ifdef VERIFY_MAGNITUDE + magnitude *= v; + normalized = false; +#endif + n[0] *= v; + n[1] *= v; + n[2] *= v; + n[3] *= v; + n[4] *= v; +} + +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); +#endif + +#ifdef INLINE_ASM + ExSetMult((uint64_t *) a.n,(uint64_t *) b.n, (uint64_t *) n); +#else + 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]; + 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; +#endif +#ifdef VERIFY_MAGNITUDE + magnitude = 1; + normalized = false; +#endif +} + +void FieldElem::SetSquare(const FieldElem &a) { +#ifdef VERIFY_MAGNITUDE + assert(a.magnitude <= 8); +#endif + +#ifdef INLINE_ASM + ExSetSquare((uint64_t *)a.n,(uint64_t *)n); +#else + __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; +#endif + +#ifdef VERIFY_MAGNITUDE + assert(a.magnitude <= 8); + normalized = false; +#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 new file mode 100644 index 00000000000..bf25aeaec2e --- /dev/null +++ b/field_5x52.h @@ -0,0 +1,80 @@ +#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: + // X = sum(i=0..4, elem[i]*2^52) mod n + uint64_t n[5]; +#ifdef VERIFY_MAGNITUDE + int magnitude; + bool 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); +}; + +} + +#endif