diff --git a/ecmult.h b/ecmult.h index f97efa0e32..7fd22a5586 100644 --- a/ecmult.h +++ b/ecmult.h @@ -5,10 +5,10 @@ #include #include "group.h" -#include "scalar.h" +#include "num.h" #define WINDOW_A 5 -#define WINDOW_G 11 +#define WINDOW_G 15 namespace secp256k1 { @@ -17,19 +17,22 @@ private: G pre[1 << (W-2)]; public: - WNAFPrecomp(const G &base) { + WNAFPrecomp() {} + + void Build(const G &base) { pre[0] = base; GroupElemJac x(base); -// printf("base=%s x=%s\n", base.ToString().c_str(), x.ToString().c_str()); GroupElemJac d; d.SetDouble(x); -// printf("d=%s\n", d.ToString().c_str()); for (int i=1; i<(1 << (W-2)); i++) { x.SetAdd(d,pre[i-1]); pre[i].SetJac(x); -// printf("precomp %s*%i = %s\n", base.ToString().c_str(), i*2 +1, pre[i].ToString().c_str()); } } + WNAFPrecomp(const G &base) { + Build(base); + } + void Get(G &out, int exp) const { assert((exp & 1) == 1); assert(exp >= -((1 << (W-1)) - 1)); @@ -55,11 +58,16 @@ private: } public: - WNAF(Context &ctx, const Scalar &exp, int w) : used(0) { + WNAF(Context &ctx, const Number &exp, int w) : used(0) { int zeroes = 0; Context ct(ctx); - Scalar x(ct); + Number x(ct); x.SetNumber(exp); + int sign = 1; + if (x.IsNeg()) { + sign = -1; + x.Negate(); + } while (!x.IsZero()) { while (!x.IsOdd()) { zeroes++; @@ -68,9 +76,9 @@ public: int word = x.ShiftLowBits(ctx,w); if (word & (1 << (w-1))) { x.Inc(); - PushNAF(word - (1 << w), zeroes); + PushNAF(sign * (word - (1 << w)), zeroes); } else { - PushNAF(word, zeroes); + PushNAF(sign * word, zeroes); } zeroes = w-1; } @@ -100,9 +108,20 @@ public: class ECMultConsts { public: - const WNAFPrecomp wpg; + WNAFPrecomp wpg; + WNAFPrecomp wpg128; - ECMultConsts() : wpg(GetGroupConst().g) {} + ECMultConsts() { + printf("Precomputing G multiplies...\n"); + const GroupElem &g = GetGroupConst().g; + GroupElemJac g128j(g); + for (int i=0; i<128; i++) + g128j.SetDouble(g128j); + GroupElem g128; g128.SetJac(g128j); + wpg.Build(g); + wpg128.Build(g128); + printf("Done precomputing\n"); + } }; const ECMultConsts &GetECMultConsts() { @@ -110,15 +129,33 @@ const ECMultConsts &GetECMultConsts() { return ecmult_consts; } -void ECMult(Context &ctx, GroupElemJac &out, const GroupElemJac &a, Scalar &an, Scalar &gn) { - WNAF<256> wa(ctx, an, WINDOW_A); - WNAF<256> wg(ctx, gn, WINDOW_G); - WNAFPrecomp wpa(a); - const WNAFPrecomp &wpg = GetECMultConsts().wpg; +void ECMult(Context &ctx, GroupElemJac &out, const GroupElemJac &a, Number &an, Number &gn) { + Context ct(ctx); + Number an1(ct), an2(ct); + Number gn1(ct), gn2(ct); - int size_a = wa.GetSize(); - int size_g = wg.GetSize(); - int size = std::max(size_a, size_g); + SplitExp(ct, an, an1, an2); +// printf("an=%s\n", an.ToString().c_str()); +// printf("an1=%s\n", an1.ToString().c_str()); +// printf("an2=%s\n", an2.ToString().c_str()); +// printf("an1.len=%i\n", an1.GetBits()); +// printf("an2.len=%i\n", an2.GetBits()); + gn.SplitInto(ct, 128, gn1, gn2); + + WNAF<129> wa1(ct, an1, WINDOW_A); + WNAF<129> wa2(ct, an2, WINDOW_A); + WNAF<128> wg1(ct, gn1, WINDOW_G); + WNAF<128> wg2(ct, gn2, WINDOW_G); + GroupElemJac a2; a2.SetMulLambda(a); + WNAFPrecomp wpa1(a); + WNAFPrecomp wpa2(a2); + const ECMultConsts &c = GetECMultConsts(); + + int size_a1 = wa1.GetSize(); + int size_a2 = wa2.GetSize(); + int size_g1 = wg1.GetSize(); + int size_g2 = wg2.GetSize(); + int size = std::max(std::max(size_a1, size_a2), std::max(size_g1, size_g2)); out = GroupElemJac(); GroupElemJac tmpj; @@ -127,12 +164,20 @@ void ECMult(Context &ctx, GroupElemJac &out, const GroupElemJac &a, Scalar &an, for (int i=size-1; i>=0; i--) { out.SetDouble(out); int nw; - if (i < size_a && (nw = wa.Get(i))) { - wpa.Get(tmpj, nw); + if (i < size_a1 && (nw = wa1.Get(i))) { + wpa1.Get(tmpj, nw); out.SetAdd(out, tmpj); } - if (i < size_g && (nw = wg.Get(i))) { - wpg.Get(tmpa, nw); + if (i < size_a2 && (nw = wa2.Get(i))) { + wpa2.Get(tmpj, nw); + out.SetAdd(out, tmpj); + } + if (i < size_g1 && (nw = wg1.Get(i))) { + c.wpg.Get(tmpa, nw); + out.SetAdd(out, tmpa); + } + if (i < size_g2 && (nw = wg2.Get(i))) { + c.wpg128.Get(tmpa, nw); out.SetAdd(out, tmpa); } } diff --git a/group.h b/group.h index fa76a72beb..880ac3ea44 100644 --- a/group.h +++ b/group.h @@ -239,6 +239,8 @@ public: cop.GetAffine(aff); return aff.ToString(); } + + void SetMulLambda(const GroupElemJac &p); }; void GroupElem::SetJac(GroupElemJac &jac) { @@ -260,6 +262,22 @@ static const unsigned char g_y_[] = {0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65, 0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19, 0x9C,0x47,0xD0,0x8F,0xFB,0x10,0xD4,0xB8}; +// properties of secp256k1's efficiently computable endomorphism +static const unsigned char lambda_[] = {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0, + 0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, + 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78, + 0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72}; +static const unsigned char beta_[] = {0x7a,0xe9,0x6a,0x2b,0x65,0x7c,0x07,0x10, + 0x6e,0x64,0x47,0x9e,0xac,0x34,0x34,0xe9, + 0x9c,0xf0,0x49,0x75,0x12,0xf5,0x89,0x95, + 0xc1,0x39,0x6c,0x28,0x71,0x95,0x01,0xee}; +static const unsigned char a1b2_[] = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd, + 0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15}; +static const unsigned char b1_[] = {0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28, + 0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3}; +static const unsigned char a2_[] = {0x01, + 0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6, + 0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8}; class GroupConstants { private: Context ctx; @@ -269,10 +287,16 @@ private: public: const Number order; const GroupElem g; + const FieldElem beta; + const Number lambda, a1b2, b1, a2; GroupConstants() : order(ctx, order_, sizeof(order_)), - g_x(g_x_), g_y(g_y_), - g(g_x,g_y) {} + g_x(g_x_), g_y(g_y_), g(g_x,g_y), + beta(beta_), + lambda(ctx, lambda_, sizeof(lambda_)), + a1b2(ctx, a1b2_, sizeof(a1b2_)), + b1(ctx, b1_, sizeof(b1_)), + a2(ctx, a2_, sizeof(a2_)) {} }; const GroupConstants &GetGroupConst() { @@ -280,6 +304,36 @@ const GroupConstants &GetGroupConst() { return group_const; } +void GroupElemJac::SetMulLambda(const GroupElemJac &p) { + FieldElem beta = GetGroupConst().beta; + *this = p; + x.SetMult(x, beta); +} + +void SplitExp(Context &ctx, const Number &exp, Number &exp1, Number exp2) { + const GroupConstants &c = GetGroupConst(); + Context ct(ctx); + Number bnc1(ct), bnc2(ct), bnt1(ct), bnt2(ct), bnn2(ct); + bnn2.SetNumber(c.order); + bnn2.Shift1(); + + bnc1.SetMult(ct, exp, c.a1b2); + bnc1.SetAdd(ct, bnc1, bnn2); + bnc1.SetDiv(ct, bnc1, c.order); + + bnc2.SetMult(ct, exp, c.b1); + bnc2.SetAdd(ct, bnc2, bnn2); + bnc2.SetDiv(ct, bnc2, c.order); + + bnt1.SetMult(ct, bnc1, c.a1b2); + bnt2.SetMult(ct, bnc2, c.a2); + bnt1.SetAdd(ct, bnt1, bnt2); + exp1.SetSub(ct, exp, bnt1); + bnt1.SetMult(ct, bnc1, c.b1); + bnt2.SetMult(ct, bnc2, c.a1b2); + exp2.SetSub(ct, bnt1, bnt2); +} + } #endif diff --git a/num.h b/num.h index 87ef1d7034..bff7f16b9a 100644 --- a/num.h +++ b/num.h @@ -74,6 +74,18 @@ public: void SetModMul(Context &ctx, const Number &f, const Number &m) { BN_mod_mul(bn, bn, f.bn, m.bn, ctx); } + void SetAdd(Context &ctx, const Number &a1, const Number &a2) { + BN_add(bn, a1.bn, a2.bn); + } + void SetSub(Context &ctx, const Number &a1, const Number &a2) { + BN_sub(bn, a1.bn, a2.bn); + } + void SetMult(Context &ctx, const Number &a1, const Number &a2) { + BN_mul(bn, a1.bn, a2.bn, ctx); + } + void SetDiv(Context &ctx, const Number &a1, const Number &a2) { + BN_div(bn, NULL, a1.bn, a2.bn, ctx); + } int GetBits() const { return BN_num_bits(bn); } @@ -91,10 +103,15 @@ public: bool IsZero() { return BN_is_zero(bn); } - // right-shift as many zeroes as possible - int IsOdd() { + bool IsOdd() { return BN_is_odd(bn); } + bool IsNeg() { + return BN_is_negative(bn); + } + void Negate() { + BN_set_negative(bn, !IsNeg()); + } void Shift1() { BN_rshift1(bn,bn); } @@ -104,6 +121,12 @@ public: void SetHex(const std::string &str) { BN_hex2bn(&bn, str.c_str()); } + void SplitInto(Context &ctx, int bits, Number &low, Number &high) const { + BN_copy(low.bn, bn); + BN_mask_bits(low.bn, bits); + BN_rshift(high.bn, bn, bits); + } + std::string ToString() { char *str = BN_bn2hex(bn); std::string ret(str); diff --git a/scalar.h b/scalar.h deleted file mode 100644 index 47ef587913..0000000000 --- a/scalar.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _SECP256K1_SCALAR_ -#define _SECP256K1_SCALAR_ - -#include "num.h" -#include "group.h" - -namespace secp256k1 { -/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141, - * using OpenSSL's BIGNUM - */ -class Scalar : public Number { -public: - Scalar(Context &ctx) : Number(ctx) {} - - void Multiply(Context &ctx, const Scalar &f) { - const GroupConstants &c = GetGroupConst(); - SetModMul(ctx, f, c.order); - } -}; - -} - -#endif diff --git a/secp256k1.cpp b/secp256k1.cpp index 5bee747072..5965c2b1bd 100644 --- a/secp256k1.cpp +++ b/secp256k1.cpp @@ -3,7 +3,6 @@ #include "num.h" #include "field.h" #include "group.h" -#include "scalar.h" #include "ecmult.h" using namespace secp256k1; @@ -11,25 +10,30 @@ using namespace secp256k1; int main() { Context ctx; FieldElem x,y; + const Number &order = GetGroupConst().order; x.SetHex("8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004"); y.SetHex("a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f"); GroupElemJac a(x,y); printf("a=%s\n", a.ToString().c_str()); - Scalar an(ctx); + Number an(ctx); an.SetHex("8b30bce9ad2a890696b23f671709eff3727fd8cc04d3362c6c7bf458f2846fff"); - Scalar af(ctx); + Number af(ctx); af.SetHex("1337"); printf("an=%s\n", an.ToString().c_str()); - Scalar gn(ctx); + Number gn(ctx); gn.SetHex("f557be925d4b65381409fdf30514750f1eb4343a91216a4f71163cb35f2f6e0e"); - Scalar gf(ctx); - gf.SetHex("2113"); + Number gf(ctx); + gf.SetHex("7113"); printf("gn=%s\n", gn.ToString().c_str()); - for (int i=0; i<50000; i++) { + for (int i=0; i<1000000; i++) { ECMult(ctx, a, a, an, gn); - an.Multiply(ctx, af); - gn.Multiply(ctx, gf); +// an.SetModMul(ctx, af, order); +// gn.SetModMul(ctx, gf, order); + an.Inc(); + gn.Inc(); } + printf("%s\n", an.ToString().c_str()); + printf("%s\n", gn.ToString().c_str()); printf("%s\n", a.ToString().c_str()); return 0; }