From 4adf6b2a329d0fbed4254cd35223e225864bb06d Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 24 Mar 2013 10:38:35 +0100 Subject: [PATCH] First step in converting to C: num --- Makefile | 6 +- bench.cpp | 27 +++--- ecdsa.cpp | 103 +++++++++++++---------- ecdsa.h | 19 +++-- ecmult.cpp | 51 ++++++++---- ecmult.h | 4 +- field.cpp | 20 +++-- field.h | 3 +- group.cpp | 74 +++++++++++------ group.h | 7 +- num.h | 28 +++++++ num_gmp.cpp | 185 ++++++++++++++++++----------------------- num_gmp.h | 44 +--------- num_openssl.cpp | 215 ++++++++++++++++++++---------------------------- num_openssl.h | 46 +---------- secp256k1.cpp | 29 ++++--- tests.cpp | 119 +++++++++++++++++++-------- 17 files changed, 508 insertions(+), 472 deletions(-) diff --git a/Makefile b/Makefile index bbe02e6..b84e7c0 100644 --- a/Makefile +++ b/Makefile @@ -54,8 +54,8 @@ clean-$(CONF): obj/secp256k1-$(CONF).o: $(SECP256K1_FILES) $(CXX) $(FLAGS_COMMON) $(FLAGS_PROD) $(FLAGS_CONF) secp256k1.cpp -c -o obj/secp256k1-$(CONF).o -bench-$(CONF): obj/secp256k1-$(CONF).o bench.cpp - $(CXX) $(FLAGS_COMMON) $(FLAGS_PROD) $(FLAGS_CONF) obj/secp256k1-$(CONF).o bench.cpp $(LIBS) -o bench-$(CONF) +bench-$(CONF): $(SECP256K1_FILES) bench.cpp + $(CXX) $(FLAGS_COMMON) $(FLAGS_PROD) $(FLAGS_CONF) bench.cpp $(LIBS) -o bench-$(CONF) tests-$(CONF): $(SECP256K1_FILES) tests.cpp - $(CXX) $(FLAGS_COMMON) $(FLAGS_TEST) $(FLAGS_CONF) tests.cpp $(LIBS) -o tests-$(CONF) + $(CXX) $(FLAGS_COMMON) $(FLAGS_DEBUG) $(FLAGS_CONF) tests.cpp $(LIBS) -o tests-$(CONF) diff --git a/bench.cpp b/bench.cpp index 9450a75..19254ff 100644 --- a/bench.cpp +++ b/bench.cpp @@ -1,25 +1,29 @@ #include -#include "num.h" -#include "field.h" -#include "group.h" -#include "ecmult.h" -#include "ecdsa.h" +#include "num.cpp" +#include "field.cpp" +#include "group.cpp" +#include "ecmult.cpp" +#include "ecdsa.cpp" using namespace secp256k1; int main() { FieldElem x; - const Number &order = GetGroupConst().order; - Number r, s, m; + 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"); int cnt = 0; int good = 0; for (int i=0; i<1000000; i++) { - r.SetPseudoRand(order); - s.SetPseudoRand(order); - m.SetPseudoRand(order); + secp256k1_num_set_rand(&r, &order); + secp256k1_num_set_rand(&s, &order); + secp256k1_num_set_rand(&m, &order); sig.SetRS(r,s); GroupElemJac pubkey; pubkey.SetCompressed(x, true); if (pubkey.IsValid()) { @@ -28,5 +32,8 @@ int main() { } } printf("%i/%i\n", good, cnt); + secp256k1_num_free(&r); + secp256k1_num_free(&s); + secp256k1_num_free(&m); return 0; } diff --git a/ecdsa.cpp b/ecdsa.cpp index 0011907..b0ecf95 100644 --- a/ecdsa.cpp +++ b/ecdsa.cpp @@ -35,17 +35,17 @@ bool Signature::Parse(const unsigned char *sig, int size) { if (lenr == 0) return false; if (sig[lenr+4] != 0x02) return false; if (lens == 0) return false; - r.SetBytes(sig+4, lenr); - s.SetBytes(sig+6+lenr, lens); + secp256k1_num_set_bin(&r, sig+4, lenr); + secp256k1_num_set_bin(&s, sig+6+lenr, lens); return true; } bool Signature::Serialize(unsigned char *sig, int *size) { - int lenR = (r.GetBits() + 7)/8; - if (lenR == 0 || r.CheckBit(lenR*8-1)) + int lenR = (secp256k1_num_bits(&r) + 7)/8; + if (lenR == 0 || secp256k1_num_get_bit(&r, lenR*8-1)) lenR++; - int lenS = (s.GetBits() + 7)/8; - if (lenS == 0 || s.CheckBit(lenS*8-1)) + int lenS = (secp256k1_num_bits(&s) + 7)/8; + if (lenS == 0 || secp256k1_num_get_bit(&s, lenS*8-1)) lenS++; if (*size < 6+lenS+lenR) return false; @@ -54,45 +54,56 @@ bool Signature::Serialize(unsigned char *sig, int *size) { sig[1] = 4 + lenS + lenR; sig[2] = 0x02; sig[3] = lenR; - r.GetBytes(sig+4, lenR); + secp256k1_num_get_bin(sig+4, lenR, &r); sig[4+lenR] = 0x02; sig[5+lenR] = lenS; - s.GetBytes(sig+6, lenS); + secp256k1_num_get_bin(sig+lenR+6, lenS, &s); return true; } -bool Signature::RecomputeR(Number &r2, const GroupElemJac &pubkey, const Number &message) const { +bool Signature::RecomputeR(secp256k1_num_t &r2, const GroupElemJac &pubkey, const secp256k1_num_t &message) const { const GroupConstants &c = GetGroupConst(); - if (r.IsNeg() || s.IsNeg()) + if (secp256k1_num_is_neg(&r) || secp256k1_num_is_neg(&s)) return false; - if (r.IsZero() || s.IsZero()) + if (secp256k1_num_is_zero(&r) || secp256k1_num_is_zero(&s)) return false; - if (r.Compare(c.order) >= 0 || s.Compare(c.order) >= 0) + if (secp256k1_num_cmp(&r, &c.order) >= 0 || secp256k1_num_cmp(&s, &c.order) >= 0) return false; - Number sn, u1, u2; - sn.SetModInverse(s, c.order); - u1.SetModMul(sn, message, c.order); - u2.SetModMul(sn, r, c.order); + bool ret = false; + secp256k1_num_t sn, u1, u2; + secp256k1_num_init(&sn); + secp256k1_num_init(&u1); + secp256k1_num_init(&u2); + secp256k1_num_mod_inverse(&sn, &s, &c.order); + secp256k1_num_mod_mul(&u1, &sn, &message, &c.order); + secp256k1_num_mod_mul(&u2, &sn, &r, &c.order); GroupElemJac pr; ECMult(pr, pubkey, u2, u1); - if (pr.IsInfinity()) - return false; - FieldElem xr; pr.GetX(xr); - xr.Normalize(); - unsigned char xrb[32]; xr.GetBytes(xrb); - r2.SetBytes(xrb,32); r2.SetMod(r2,c.order); - return true; + if (!pr.IsInfinity()) { + FieldElem xr; pr.GetX(xr); + xr.Normalize(); + unsigned char xrb[32]; xr.GetBytes(xrb); + secp256k1_num_set_bin(&r2, xrb, 32); + secp256k1_num_mod(&r2, &r2, &c.order); + ret = true; + } + secp256k1_num_free(&sn); + secp256k1_num_free(&u1); + secp256k1_num_free(&u2); + return ret; } -bool Signature::Verify(const GroupElemJac &pubkey, const Number &message) const { - Number r2; - if (!RecomputeR(r2, pubkey, message)) - return false; - return r2.Compare(r) == 0; +bool Signature::Verify(const GroupElemJac &pubkey, const secp256k1_num_t &message) const { + secp256k1_num_t r2; + secp256k1_num_init(&r2); + bool ret = false; + ret = RecomputeR(r2, pubkey, message) && secp256k1_num_cmp(&r, &r2) == 0; + secp256k1_num_free(&r2); + return ret; } -bool Signature::Sign(const Number &seckey, const Number &message, const Number &nonce) { +bool Signature::Sign(const secp256k1_num_t &seckey, const secp256k1_num_t &message, const secp256k1_num_t &nonce) { const GroupConstants &c = GetGroupConst(); GroupElemJac rp; @@ -102,27 +113,33 @@ bool Signature::Sign(const Number &seckey, const Number &message, const Number & unsigned char b[32]; rx.Normalize(); rx.GetBytes(b); - r.SetBytes(b, 32); - r.SetMod(r, c.order); - Number n; - n.SetModMul(r, seckey, c.order); - n.SetAdd(message, n); - s.SetModInverse(nonce, c.order); - s.SetModMul(s, n, c.order); - if (s.IsZero()) + secp256k1_num_set_bin(&r, b, 32); + secp256k1_num_mod(&r, &r, &c.order); + secp256k1_num_t n; + secp256k1_num_init(&n); + secp256k1_num_mod_mul(&n, &r, &seckey, &c.order); + secp256k1_num_add(&n, &n, &message); + secp256k1_num_mod_inverse(&s, &nonce, &c.order); + secp256k1_num_mod_mul(&s, &s, &n, &c.order); + secp256k1_num_free(&n); + if (secp256k1_num_is_zero(&s)) return false; - if (s.IsOdd()) - s.SetSub(c.order, s); + if (secp256k1_num_is_odd(&s)) + secp256k1_num_sub(&s, &c.order, &s); return true; } -void Signature::SetRS(const Number &rin, const Number &sin) { - r = rin; - s = sin; +void Signature::SetRS(const secp256k1_num_t &rin, const secp256k1_num_t &sin) { + secp256k1_num_copy(&r, &rin); + secp256k1_num_copy(&s, &sin); } std::string Signature::ToString() const { - return "(" + r.ToString() + "," + s.ToString() + ")"; + char rs[65], ss[65]; + int rl = 65, sl = 65; + secp256k1_num_get_hex(rs, &rl, &r); + secp256k1_num_get_hex(ss, &sl, &s); + return "(" + std::string(rs) + "," + std::string(ss) + ")"; } } diff --git a/ecdsa.h b/ecdsa.h index bef35db..6ce4ff2 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -5,15 +5,24 @@ namespace secp256k1 { class Signature { private: - Number r,s; + secp256k1_num_t r,s; public: + Signature() { + secp256k1_num_init(&r); + secp256k1_num_init(&s); + } + ~Signature() { + secp256k1_num_free(&r); + secp256k1_num_free(&s); + } + bool Parse(const unsigned char *sig, int size); bool Serialize(unsigned char *sig, int *size); - bool RecomputeR(Number &r2, const GroupElemJac &pubkey, const Number &message) const; - bool Verify(const GroupElemJac &pubkey, const Number &message) const; - bool Sign(const Number &seckey, const Number &message, const Number &nonce); - void SetRS(const Number &rin, const Number &sin); + bool RecomputeR(secp256k1_num_t &r2, const GroupElemJac &pubkey, const secp256k1_num_t &message) const; + bool Verify(const GroupElemJac &pubkey, const secp256k1_num_t &message) const; + bool Sign(const secp256k1_num_t &seckey, const secp256k1_num_t &message, const secp256k1_num_t &nonce); + void SetRS(const secp256k1_num_t &rin, const secp256k1_num_t &sin); std::string ToString() const; }; diff --git a/ecmult.cpp b/ecmult.cpp index 67d7854..84dce7b 100644 --- a/ecmult.cpp +++ b/ecmult.cpp @@ -61,29 +61,31 @@ private: } public: - WNAF(const Number &exp, int w) : used(0) { + WNAF(const secp256k1_num_t &exp, int w) : used(0) { int zeroes = 0; - Number x; - x.SetNumber(exp); + secp256k1_num_t x; + secp256k1_num_init(&x); + secp256k1_num_copy(&x, &exp); int sign = 1; - if (x.IsNeg()) { + if (secp256k1_num_is_neg(&x)) { sign = -1; - x.Negate(); + secp256k1_num_negate(&x); } - while (!x.IsZero()) { - while (!x.IsOdd()) { + while (!secp256k1_num_is_zero(&x)) { + while (!secp256k1_num_is_odd(&x)) { zeroes++; - x.Shift1(); + secp256k1_num_shift(&x, 1); } - int word = x.ShiftLowBits(w); + int word = secp256k1_num_shift(&x, w); if (word & (1 << (w-1))) { - x.Inc(); + secp256k1_num_inc(&x); PushNAF(sign * (word - (1 << w)), zeroes); } else { PushNAF(sign * word, zeroes); } zeroes = w-1; } + secp256k1_num_free(&x); } int GetSize() const { @@ -145,19 +147,27 @@ const ECMultConsts &GetECMultConsts() { return ecmult_consts; } -void ECMultBase(GroupElemJac &out, const Number &gn) { - Number n; n.SetNumber(gn); +void ECMultBase(GroupElemJac &out, const secp256k1_num_t &gn) { + secp256k1_num_t n; + secp256k1_num_init(&n); + secp256k1_num_copy(&n, &gn); const ECMultConsts &c = GetECMultConsts(); - out.SetAffine(c.prec[0][n.ShiftLowBits(4)]); + out.SetAffine(c.prec[0][secp256k1_num_shift(&n, 4)]); for (int j=1; j<64; j++) { - out.SetAdd(out, c.prec[j][n.ShiftLowBits(4)]); + out.SetAdd(out, c.prec[j][secp256k1_num_shift(&n, 4)]); } + secp256k1_num_free(&n); out.SetAdd(out, c.fin); } -void ECMult(GroupElemJac &out, const GroupElemJac &a, const Number &an, const Number &gn) { - Number an1, an2; - Number gn1, gn2; +void ECMult(GroupElemJac &out, const GroupElemJac &a, const secp256k1_num_t &an, const secp256k1_num_t &gn) { + secp256k1_num_t an1, an2; + secp256k1_num_t gn1, gn2; + + secp256k1_num_init(&an1); + secp256k1_num_init(&an2); + secp256k1_num_init(&gn1); + secp256k1_num_init(&gn2); SplitExp(an, an1, an2); // printf("an=%s\n", an.ToString().c_str()); @@ -165,7 +175,7 @@ void ECMult(GroupElemJac &out, const GroupElemJac &a, const Number &an, const Nu // printf("an2=%s\n", an2.ToString().c_str()); // printf("an1.len=%i\n", an1.GetBits()); // printf("an2.len=%i\n", an2.GetBits()); - gn.SplitInto(128, gn1, gn2); + secp256k1_num_split(&gn1, &gn2, &gn, 128); WNAF<128> wa1(an1, WINDOW_A); WNAF<128> wa2(an2, WINDOW_A); @@ -206,6 +216,11 @@ void ECMult(GroupElemJac &out, const GroupElemJac &a, const Number &an, const Nu out.SetAdd(out, tmpa); } } + + secp256k1_num_free(&an1); + secp256k1_num_free(&an2); + secp256k1_num_free(&gn1); + secp256k1_num_free(&gn2); } } diff --git a/ecmult.h b/ecmult.h index b779fea..08b2563 100644 --- a/ecmult.h +++ b/ecmult.h @@ -6,8 +6,8 @@ namespace secp256k1 { -void ECMultBase(GroupElemJac &out, const Number &gn); -void ECMult(GroupElemJac &out, const GroupElemJac &a, const Number &an, const Number &gn); +void ECMultBase(GroupElemJac &out, const secp256k1_num_t &gn); +void ECMult(GroupElemJac &out, const GroupElemJac &a, const secp256k1_num_t &an, const secp256k1_num_t &gn); } diff --git a/field.cpp b/field.cpp index de51953..748572a 100644 --- a/field.cpp +++ b/field.cpp @@ -363,7 +363,14 @@ 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,0xFE,0xFF,0xFF,0xFC,0x2F}; -FieldConstants::FieldConstants() : field_p(field_p_, sizeof(field_p_)) {} +FieldConstants::FieldConstants() { + secp256k1_num_init(&field_p); + secp256k1_num_set_bin(&field_p, field_p_, sizeof(field_p_)); +} + +FieldConstants::~FieldConstants() { + secp256k1_num_free(&field_p); +} const FieldConstants &GetFieldConst() { static const FieldConstants field_const; @@ -408,10 +415,13 @@ void FieldElem::SetInverse(FieldElem &a) { a.Normalize(); a.GetBytes(b); { - const Number &p = GetFieldConst().field_p; - Number n; n.SetBytes(b, 32); - n.SetModInverse(n, p); - n.GetBytes(b, 32); + 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 5191900..3851409 100644 --- a/field.h +++ b/field.h @@ -77,9 +77,10 @@ public: class FieldConstants { public: - const Number field_p; + secp256k1_num_t field_p; FieldConstants(); + ~FieldConstants(); }; const FieldConstants &GetFieldConst(); diff --git a/group.cpp b/group.cpp index a22a9a8..b19e5d1 100644 --- a/group.cpp +++ b/group.cpp @@ -291,13 +291,28 @@ static const unsigned char a2_[] = {0x01, 0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8}; GroupConstants::GroupConstants() : g_x(g_x_), g_y(g_y_), - order(order_, sizeof(order_)), g(g_x,g_y), - beta(beta_), - lambda(lambda_, sizeof(lambda_)), - a1b2(a1b2_, sizeof(a1b2_)), - b1(b1_, sizeof(b1_)), - a2(a2_, sizeof(a2_)) {} + beta(beta_) { + secp256k1_num_init(&order); + secp256k1_num_init(&lambda); + secp256k1_num_init(&a1b2); + secp256k1_num_init(&b1); + secp256k1_num_init(&a2); + + secp256k1_num_set_bin(&order, order_, sizeof(order_)); + secp256k1_num_set_bin(&lambda, lambda_, sizeof(lambda_)); + secp256k1_num_set_bin(&a1b2, a1b2_, sizeof(a1b2_)); + secp256k1_num_set_bin(&b1, b1_, sizeof(b1_)); + secp256k1_num_set_bin(&a2, a2_, sizeof(a2_)); +} + +GroupConstants::~GroupConstants() { + secp256k1_num_free(&order); + secp256k1_num_free(&lambda); + secp256k1_num_free(&a1b2); + secp256k1_num_free(&b1); + secp256k1_num_free(&a2); +} const GroupConstants &GetGroupConst() { static const GroupConstants group_const; @@ -310,27 +325,40 @@ void GroupElemJac::SetMulLambda(const GroupElemJac &p) { x.SetMult(x, beta); } -void SplitExp(const Number &exp, Number &exp1, Number &exp2) { +void SplitExp(const secp256k1_num_t &exp, secp256k1_num_t &exp1, secp256k1_num_t &exp2) { const GroupConstants &c = GetGroupConst(); - Number bnc1, bnc2, bnt1, bnt2, bnn2; - bnn2.SetNumber(c.order); - bnn2.Shift1(); + secp256k1_num_t bnc1, bnc2, bnt1, bnt2, bnn2; - bnc1.SetMult(exp, c.a1b2); - bnc1.SetAdd(bnc1, bnn2); - bnc1.SetDiv(bnc1, c.order); + secp256k1_num_init(&bnc1); + secp256k1_num_init(&bnc2); + secp256k1_num_init(&bnt1); + secp256k1_num_init(&bnt2); + secp256k1_num_init(&bnn2); - bnc2.SetMult(exp, c.b1); - bnc2.SetAdd(bnc2, bnn2); - bnc2.SetDiv(bnc2, c.order); + secp256k1_num_copy(&bnn2, &c.order); + secp256k1_num_shift(&bnn2, 1); - bnt1.SetMult(bnc1, c.a1b2); - bnt2.SetMult(bnc2, c.a2); - bnt1.SetAdd(bnt1, bnt2); - exp1.SetSub(exp, bnt1); - bnt1.SetMult(bnc1, c.b1); - bnt2.SetMult(bnc2, c.a1b2); - exp2.SetSub(bnt1, bnt2); + secp256k1_num_mul(&bnc1, &exp, &c.a1b2); + secp256k1_num_add(&bnc1, &bnc1, &bnn2); + secp256k1_num_div(&bnc1, &bnc1, &c.order); + + secp256k1_num_mul(&bnc2, &exp, &c.b1); + secp256k1_num_add(&bnc2, &bnc2, &bnn2); + secp256k1_num_div(&bnc2, &bnc2, &c.order); + + secp256k1_num_mul(&bnt1, &bnc1, &c.a1b2); + secp256k1_num_mul(&bnt2, &bnc2, &c.a2); + secp256k1_num_add(&bnt1, &bnt1, &bnt2); + secp256k1_num_sub(&exp1, &exp, &bnt1); + secp256k1_num_mul(&bnt1, &bnc1, &c.b1); + secp256k1_num_mul(&bnt2, &bnc2, &c.a1b2); + secp256k1_num_sub(&exp2, &bnt1, &bnt2); + + secp256k1_num_free(&bnc1); + secp256k1_num_free(&bnc2); + secp256k1_num_free(&bnt1); + secp256k1_num_free(&bnt2); + secp256k1_num_free(&bnn2); } } diff --git a/group.h b/group.h index 42a1677..6fe7e38 100644 --- a/group.h +++ b/group.h @@ -95,17 +95,18 @@ private: const FieldElem g_y; public: - const Number order; + secp256k1_num_t order; const GroupElem g; const FieldElem beta; - const Number lambda, a1b2, b1, a2; + secp256k1_num_t lambda, a1b2, b1, a2; GroupConstants(); + ~GroupConstants(); }; const GroupConstants &GetGroupConst(); -void SplitExp(const Number &exp, Number &exp1, Number &exp2); +void SplitExp(const secp256k1_num_t &exp, secp256k1_num_t &exp1, secp256k1_num_t &exp2); } diff --git a/num.h b/num.h index ff69b11..58723c5 100644 --- a/num.h +++ b/num.h @@ -9,4 +9,32 @@ #error "Please select num implementation" #endif +void static secp256k1_num_start(void); +void static secp256k1_num_init(secp256k1_num_t *r); +void static secp256k1_num_free(secp256k1_num_t *r); +void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a); +void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a); +void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen); +void static secp256k1_num_set_int(secp256k1_num_t *r, int a); +void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m); +void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m); +int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b); +void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +int static secp256k1_num_bits(const secp256k1_num_t *a); +int static secp256k1_num_shift(secp256k1_num_t *r, int bits); +int static secp256k1_num_is_zero(const secp256k1_num_t *a); +int static secp256k1_num_is_odd(const secp256k1_num_t *a); +int static secp256k1_num_is_neg(const secp256k1_num_t *a); +int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos); +void static secp256k1_num_inc(secp256k1_num_t *r); +void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen); +void static secp256k1_num_get_hex(char *r, int *rlen, const secp256k1_num_t *a); +void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits); +void static secp256k1_num_negate(secp256k1_num_t *r); +void static secp256k1_num_set_rand(secp256k1_num_t *r, const secp256k1_num_t *a); + #endif diff --git a/num_gmp.cpp b/num_gmp.cpp index 5f04c40..5facce2 100644 --- a/num_gmp.cpp +++ b/num_gmp.cpp @@ -1,171 +1,148 @@ #include -#include #include #include #include -#include "num_gmp.h" +#include "num.h" -namespace secp256k1 { - -class NumberState { -private: +typedef struct { + int initialized; gmp_randstate_t rng; +} secp256k1_num_state_t; -public: - NumberState() { - gmp_randinit_default(rng); - } +static secp256k1_num_state_t secp256k1_num_state = {}; - ~NumberState() { - gmp_randclear(rng); - } - - void gen(mpz_t out, mpz_t size) { - mpz_urandomm(out, rng, size); - } -}; - -static NumberState number_state; - -Number::Number(const Number &x) { - mpz_init_set(bn, x.bn); +void static secp256k1_num_start(void) { + if (secp256k1_num_state.initialized) + return; + secp256k1_num_state.initialized = 1; + gmp_randinit_default(secp256k1_num_state.rng); } -Number::Number() { - mpz_init(bn); +void static secp256k1_num_init(secp256k1_num_t *r) { + mpz_init(r->bn); } -Number::~Number() { - mpz_clear(bn); +void static secp256k1_num_free(secp256k1_num_t *r) { + mpz_clear(r->bn); } -Number &Number::operator=(const Number &x) { - mpz_set(bn, x.bn); - return *this; +void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) { + mpz_set(r->bn, a->bn); } -void Number::SetNumber(const Number &x) { - mpz_set(bn, x.bn); -} - -Number::Number(const unsigned char *bin, int len) { - mpz_init(bn); - SetBytes(bin,len); -} - -void Number::SetBytes(const unsigned char *bin, unsigned int len) { - mpz_import(bn, len, 1, 1, 1, 0, bin); -} - -bool Number::CheckBit(int pos) const { - return mpz_tstbit(bn, pos); -} - -void Number::GetBytes(unsigned char *bin, unsigned int len) { - unsigned int size = (mpz_sizeinbase(bn,2)+7)/8; - assert(size <= len); - memset(bin,0,len); +void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) { + unsigned int size = (mpz_sizeinbase(a->bn,2)+7)/8; + assert(size <= rlen); + memset(r,0,rlen); size_t count = 0; - mpz_export(bin + len - size, &count, 1, 1, 1, 0, bn); + mpz_export(r + rlen - size, &count, 1, 1, 1, 0, a->bn); assert(count == 0 || size == count); } -void Number::SetInt(int x) { - mpz_set_si(bn, x); +void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) { + mpz_import(r->bn, alen, 1, 1, 1, 0, a); } -void Number::SetModInverse(const Number &x, const Number &m) { - mpz_invert(bn, x.bn, m.bn); +void static secp256k1_num_set_int(secp256k1_num_t *r, int a) { + mpz_set_si(r->bn, a); } -void Number::SetModMul(const Number &a, const Number &b, const Number &m) { - mpz_mul(bn, a.bn, b.bn); - mpz_mod(bn, bn, m.bn); +void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) { + mpz_invert(r->bn, a->bn, m->bn); } -void Number::SetAdd(const Number &a1, const Number &a2) { - mpz_add(bn, a1.bn, a2.bn); +void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) { + mpz_mul(r->bn, a->bn, b->bn); + mpz_mod(r->bn, r->bn, m->bn); } -void Number::SetSub(const Number &a1, const Number &a2) { - mpz_sub(bn, a1.bn, a2.bn); +int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) { + return mpz_cmp(a->bn, b->bn); } -void Number::SetMult(const Number &a1, const Number &a2) { - mpz_mul(bn, a1.bn, a2.bn); +void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + mpz_add(r->bn, a->bn, b->bn); } -void Number::SetDiv(const Number &a1, const Number &a2) { - mpz_tdiv_q(bn, a1.bn, a2.bn); +void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + mpz_sub(r->bn, a->bn, b->bn); } -void Number::SetMod(const Number &a, const Number &m) { - mpz_mod(bn, a.bn, m.bn); +void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + mpz_mul(r->bn, a->bn, b->bn); } -int Number::Compare(const Number &a) const { - return mpz_cmp(bn, a.bn); +void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + mpz_tdiv_q(r->bn, a->bn, b->bn); } -int Number::GetBits() const { - return mpz_sizeinbase(bn,2); +void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + mpz_mod(r->bn, a->bn, b->bn); } -int Number::ShiftLowBits(int bits) { - int ret = mpz_get_ui(bn) & ((1 << bits) - 1); - mpz_fdiv_q_2exp(bn, bn, bits); +int static secp256k1_num_bits(const secp256k1_num_t *a) { + return mpz_sizeinbase(a->bn,2); +} + +int static secp256k1_num_shift(secp256k1_num_t *r, int bits) { + int ret = mpz_get_ui(r->bn) & ((1 << bits) - 1); + mpz_fdiv_q_2exp(r->bn, r->bn, bits); return ret; } -bool Number::IsZero() const { - return mpz_size(bn) == 0; +int static secp256k1_num_is_zero(const secp256k1_num_t *a) { + return mpz_size(a->bn) == 0; } -bool Number::IsOdd() const { - return mpz_get_ui(bn) & 1; +int static secp256k1_num_is_odd(const secp256k1_num_t *a) { + return mpz_get_ui(a->bn) & 1; } -bool Number::IsNeg() const { - return mpz_sgn(bn) < 0; +int static secp256k1_num_is_neg(const secp256k1_num_t *a) { + return mpz_sgn(a->bn) < 0; } -void Number::Negate() { - mpz_neg(bn, bn); +int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos) { + return mpz_tstbit(a->bn, pos); } -void Number::Shift1() { - mpz_fdiv_q_2exp(bn, bn, 1); +void static secp256k1_num_inc(secp256k1_num_t *r) { + mpz_add_ui(r->bn, r->bn, 1); } -void Number::Inc() { - mpz_add_ui(bn, bn, 1); +void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen) { + char *str = (char*)malloc(alen+1); + memcpy(str, a, alen); + str[alen] = 0; + mpz_set_str(r->bn, str, 16); + free(str); } -void Number::SetHex(const std::string &str) { - mpz_set_str(bn, str.c_str(), 16); +void static secp256k1_num_get_hex(char *r, int *rlen, const secp256k1_num_t *a) { + int len = mpz_sizeinbase(a->bn, 16) + 2; + if (*rlen < len) { + *rlen = len; + return; + } + mpz_get_str(r, 16, a->bn); + *rlen = len; } -void Number::SetPseudoRand(const Number &max) { - number_state.gen(bn, max.bn); -} - -void Number::SplitInto(int bits, Number &low, Number &high) const { +void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits) { mpz_t tmp; mpz_init_set_ui(tmp,1); - mpz_mul_2exp(tmp,tmp,bits); + mpz_mul_2exp(tmp, tmp, bits); mpz_sub_ui(tmp,tmp,1); - mpz_and(low.bn, bn, tmp); + mpz_and(rl->bn, a->bn, tmp); mpz_clear(tmp); - mpz_fdiv_q_2exp(high.bn, bn, bits); + mpz_fdiv_q_2exp(rh->bn, a->bn, bits); } -std::string Number::ToString() const { - char *str = (char*)malloc(mpz_sizeinbase(bn,16) + 2); - mpz_get_str(str, 16, bn); - std::string ret(str); - free(str); - return ret; +void static secp256k1_num_negate(secp256k1_num_t *r) { + mpz_neg(r->bn, r->bn); } +void static secp256k1_num_set_rand(secp256k1_num_t *r, const secp256k1_num_t *a) { + mpz_urandomm(r->bn, secp256k1_num_state.rng, a->bn); } diff --git a/num_gmp.h b/num_gmp.h index 850328d..d908e00 100644 --- a/num_gmp.h +++ b/num_gmp.h @@ -1,48 +1,10 @@ #ifndef _SECP256K1_NUM_GMP_ #define _SECP256K1_NUM_GMP_ -#include #include -namespace secp256k1 { - -class Number { -private: - mutable mpz_t bn; - Number(const Number &x); - -public: - Number(); - ~Number(); - Number(const unsigned char *bin, int len); - Number &operator=(const Number &x); - void SetNumber(const Number &x); - void SetBytes(const unsigned char *bin, unsigned int len); - void GetBytes(unsigned char *bin, unsigned int len); - void SetInt(int x); - void SetModInverse(const Number &x, const Number &m); - void SetModMul(const Number &a, const Number &b, const Number &m); - void SetAdd(const Number &a1, const Number &a2); - void SetSub(const Number &a1, const Number &a2); - void SetMult(const Number &a1, const Number &a2); - void SetDiv(const Number &a1, const Number &a2); - void SetMod(const Number &a, const Number &m); - int Compare(const Number &a) const; - int GetBits() const; - int ShiftLowBits(int bits); - bool IsZero() const; - bool IsOdd() const; - bool IsNeg() const; - bool CheckBit(int pos) const; - void Negate(); - void Shift1(); - void Inc(); - void SetHex(const std::string &str); - void SetPseudoRand(const Number &max); - void SplitInto(int bits, Number &low, Number &high) const; - std::string ToString() const; -}; - -} +typedef struct { + mpz_t bn; +} secp256k1_num_t; #endif diff --git a/num_openssl.cpp b/num_openssl.cpp index cd2673e..50c4f6c 100644 --- a/num_openssl.cpp +++ b/num_openssl.cpp @@ -1,183 +1,146 @@ #include -#include #include +#include #include #include -#include "num_openssl.h" +#include "num.h" -namespace secp256k1 { - -class Context { -private: - BN_CTX *ctx; - - operator BN_CTX*() { - return ctx; - } - - friend class Number; -public: - Context() { - ctx = BN_CTX_new(); - } - - ~Context() { - BN_CTX_free(ctx); - } -}; - -Number::operator const BIGNUM*() const { - return &b; +void static secp256k1_num_start() { } -Number::operator BIGNUM*() { - return &b; +void static secp256k1_num_init(secp256k1_num_t *r) { + BN_init(&r->bn); } -Number::Number() { - BN_init(*this); +void static secp256k1_num_free(secp256k1_num_t *r) { + BN_free(&r->bn); } -Number::~Number() { - BN_free(*this); +void static secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) { + BN_copy(&r->bn, &a->bn); } -Number::Number(const unsigned char *bin, int len) { - BN_init(*this); - SetBytes(bin,len); +void static secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) { + unsigned int size = BN_num_bytes(&a->bn); + assert(size <= rlen); + memset(r,0,rlen); + BN_bn2bin(&a->bn, r + rlen - size); } -void Number::SetNumber(const Number &x) { - BN_copy(*this, x); +void static secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) { + BN_bin2bn(a, alen, &r->bn); } -Number::Number(const Number &x) { - BN_init(*this); - BN_copy(*this, x); +void static secp256k1_num_set_int(secp256k1_num_t *r, int a) { + BN_set_word(&r->bn, a < 0 ? -a : a); + BN_set_negative(&r->bn, a < 0); } -Number &Number::operator=(const Number &x) { - BN_copy(*this, x); - return *this; +void static secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) { + BN_CTX *ctx = BN_CTX_new(); + BN_mod_inverse(&r->bn, &a->bn, &m->bn, ctx); + BN_CTX_free(ctx); } -void Number::SetBytes(const unsigned char *bin, int len) { - BN_bin2bn(bin, len, *this); +void static secp256k1_num_mod_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, const secp256k1_num_t *m) { + BN_CTX *ctx = BN_CTX_new(); + BN_mod_mul(&r->bn, &a->bn, &b->bn, &m->bn, ctx); + BN_CTX_free(ctx); } -void Number::GetBytes(unsigned char *bin, int len) { - int size = BN_num_bytes(*this); - assert(size <= len); - memset(bin,0,len); - BN_bn2bin(*this, bin + len - size); +int static secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) { + return BN_cmp(&a->bn, &b->bn); } -void Number::SetInt(int x) { - if (x >= 0) { - BN_set_word(*this, x); - } else { - BN_set_word(*this, -x); - BN_set_negative(*this, 1); - } +void static secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + BN_add(&r->bn, &a->bn, &b->bn); } -void Number::SetModInverse(const Number &x, const Number &m) { - Context ctx; - BN_mod_inverse(*this, x, m, ctx); +void static secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + BN_sub(&r->bn, &a->bn, &b->bn); } -void Number::SetModMul(const Number &a, const Number &b, const Number &m) { - Context ctx; - BN_mod_mul(*this, a, b, m, ctx); +void static secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + BN_CTX *ctx = BN_CTX_new(); + BN_mul(&r->bn, &a->bn, &b->bn, ctx); + BN_CTX_free(ctx); } -void Number::SetAdd(const Number &a1, const Number &a2) { - BN_add(*this, a1, a2); +void static secp256k1_num_div(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + BN_CTX *ctx = BN_CTX_new(); + BN_div(&r->bn, NULL, &a->bn, &b->bn, ctx); + BN_CTX_free(ctx); } -void Number::SetSub(const Number &a1, const Number &a2) { - BN_sub(*this, a1, a2); +void static secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + BN_CTX *ctx = BN_CTX_new(); + BN_nnmod(&r->bn, &a->bn, &b->bn, ctx); + BN_CTX_free(ctx); } -void Number::SetMult(const Number &a1, const Number &a2) { - Context ctx; - BN_mul(*this, a1, a2, ctx); +int static secp256k1_num_bits(const secp256k1_num_t *a) { + return BN_num_bits(&a->bn); } -void Number::SetDiv(const Number &a1, const Number &a2) { - Context ctx; - BN_div(*this, NULL, a1, a2, ctx); -} - -void Number::SetMod(const Number &a, const Number &m) { - Context ctx; - BN_nnmod(*this, a, m, ctx); -} - -int Number::Compare(const Number &a) const { - return BN_cmp(*this, a); -} - -int Number::GetBits() const { - return BN_num_bits(*this); -} - -int Number::ShiftLowBits(int bits) { - BIGNUM *bn = *this; - int ret = BN_is_zero(bn) ? 0 : bn->d[0] & ((1 << bits) - 1); - BN_rshift(*this, *this, bits); +int static secp256k1_num_shift(secp256k1_num_t *r, int bits) { + int ret = BN_is_zero(&r->bn) ? 0 : r->bn.d[0] & ((1 << bits) - 1); + BN_rshift(&r->bn, &r->bn, bits); return ret; } -bool Number::IsZero() const { - return BN_is_zero((const BIGNUM*)*this); +int static secp256k1_num_is_zero(const secp256k1_num_t *a) { + return BN_is_zero(&a->bn); } -bool Number::IsOdd() const { - return BN_is_odd((const BIGNUM*)*this); +int static secp256k1_num_is_odd(const secp256k1_num_t *a) { + return BN_is_odd(&a->bn); } -bool Number::CheckBit(int pos) const { - return BN_is_bit_set((const BIGNUM*)*this, pos); +int static secp256k1_num_is_neg(const secp256k1_num_t *a) { + return BN_is_negative(&a->bn); } -bool Number::IsNeg() const { - return BN_is_negative((const BIGNUM*)*this); +int static secp256k1_num_get_bit(const secp256k1_num_t *a, int pos) { + return BN_is_bit_set(&a->bn, pos); } -void Number::Negate() { - BN_set_negative(*this, !IsNeg()); +void static secp256k1_num_inc(secp256k1_num_t *r) { + BN_add_word(&r->bn, 1); } -void Number::Shift1() { - BN_rshift1(*this,*this); +void static secp256k1_num_set_hex(secp256k1_num_t *r, const char *a, int alen) { + char *str = (char*)malloc(alen+1); + memcpy(str, a, alen); + str[alen] = 0; + BIGNUM *pbn = &r->bn; + BN_hex2bn(&pbn, str); + free(str); } -void Number::Inc() { - BN_add_word(*this,1); -} - -void Number::SetHex(const std::string &str) { - BIGNUM *bn = *this; - BN_hex2bn(&bn, str.c_str()); -} - -void Number::SetPseudoRand(const Number &max) { - BN_pseudo_rand_range(*this, max); -} - -void Number::SplitInto(int bits, Number &low, Number &high) const { - BN_copy(low, *this); - BN_mask_bits(low, bits); - BN_rshift(high, *this, bits); -} - -std::string Number::ToString() const { - char *str = BN_bn2hex(*this); - std::string ret(str); +void static secp256k1_num_get_hex(char *r, int *rlen, const secp256k1_num_t *a) { + char *str = BN_bn2hex(&a->bn); + int len = strlen(str) + 1; + if (len > *rlen) { + *rlen = strlen(str); + OPENSSL_free(str); + return; + } + memcpy(r, str, len); OPENSSL_free(str); - return ret; + *rlen = len; } +void static secp256k1_num_split(secp256k1_num_t *rl, secp256k1_num_t *rh, const secp256k1_num_t *a, int bits) { + BN_copy(&rl->bn, &a->bn); + BN_rshift(&rh->bn, &a->bn, bits); + BN_mask_bits(&rl->bn, bits); +} + +void static secp256k1_num_negate(secp256k1_num_t *r) { + BN_set_negative(&r->bn, !BN_is_negative(&r->bn)); +} + +void static secp256k1_num_set_rand(secp256k1_num_t *r, const secp256k1_num_t *a) { + BN_pseudo_rand_range(&r->bn, &a->bn); } diff --git a/num_openssl.h b/num_openssl.h index 586d49f..22c502a 100644 --- a/num_openssl.h +++ b/num_openssl.h @@ -1,50 +1,10 @@ #ifndef _SECP256K1_NUM_OPENSSL_ #define _SECP256K1_NUM_OPENSSL_ -#include #include -namespace secp256k1 { - -class Number { -private: - BIGNUM b; - Number(const Number &x); - - operator const BIGNUM*() const; - operator BIGNUM*(); -public: - Number(); - ~Number(); - Number(const unsigned char *bin, int len); - void SetNumber(const Number &x); - Number &operator=(const Number &x); - void SetBytes(const unsigned char *bin, int len); - void GetBytes(unsigned char *bin, int len); - void SetInt(int x); - void SetModInverse(const Number &x, const Number &m); - void SetModMul(const Number &a, const Number &b, const Number &m); - void SetAdd(const Number &a1, const Number &a2); - void SetSub(const Number &a1, const Number &a2); - void SetMult(const Number &a1, const Number &a2); - void SetDiv(const Number &a1, const Number &a2); - void SetMod(const Number &a, const Number &m); - int Compare(const Number &a) const; - int GetBits() const; - int ShiftLowBits(int bits); - bool IsZero() const; - bool IsOdd() const; - bool IsNeg() const; - bool CheckBit(int pos) const; - void Negate(); - void Shift1(); - void Inc(); - void SetHex(const std::string &str); - void SetPseudoRand(const Number &max); - void SplitInto(int bits, Number &low, Number &high) const; - std::string ToString() const; -}; - -} +typedef struct { + BIGNUM bn; +} secp256k1_num_t; #endif diff --git a/secp256k1.cpp b/secp256k1.cpp index 755f93c..5cdadae 100644 --- a/secp256k1.cpp +++ b/secp256k1.cpp @@ -7,23 +7,32 @@ namespace secp256k1 { int VerifyECDSA(const unsigned char *msg, int msglen, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { - Number m; + int ret = -3; + secp256k1_num_t m; + secp256k1_num_init(&m); Signature s; GroupElemJac q; - m.SetBytes(msg, msglen); - if (!ParsePubKey(q, pubkey, pubkeylen)) - return -1; + secp256k1_num_set_bin(&m, msg, msglen); + if (!ParsePubKey(q, pubkey, pubkeylen)) { + ret = -1; + goto end; + } if (!s.Parse(sig, siglen)) { fprintf(stderr, "Can't parse signature: "); for (int i=0; i wnaf(number, w); int zeroes = -1; for (int i=wnaf.GetSize()-1; i>=0; i--) { - x.SetMult(x, two); + secp256k1_num_mul(&x, &x, &two); int v = wnaf.Get(i); if (v) { assert(zeroes == -1 || zeroes >= w-1); // check that distance between non-zero elements is at least w-1 @@ -87,44 +116,64 @@ void test_wnaf(const Number &number, int w) { assert(zeroes != -1); // check that no unnecessary zero padding exists zeroes++; } - t.SetInt(v); - x.SetAdd(x, t); + secp256k1_num_set_int(&t, v); + secp256k1_num_add(&x, &x, &t); } - assert(x.Compare(number) == 0); // check that wnaf represents number + assert(secp256k1_num_cmp(&x, &number) == 0); // check that wnaf represents number + secp256k1_num_free(&x); + secp256k1_num_free(&two); + secp256k1_num_free(&t); } void test_run_wnaf() { - Number range, min, n; - range.SetHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); // 2^1024-1 - min = range; min.Shift1(); min.Negate(); - for (int i=0; i<100; i++) { - n.SetPseudoRand(range); n.SetAdd(n,min); + secp256k1_num_t range, min, n; + secp256k1_num_init(&range); + secp256k1_num_init(&min); + secp256k1_num_init(&n); + secp256k1_num_set_hex(&range, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 256); + secp256k1_num_copy(&min, &range); + secp256k1_num_shift(&min, 1); + secp256k1_num_negate(&min); + for (int i=0; i