diff --git a/ecdsa.cpp b/ecdsa.cpp index 1b8ab6905e..fa6f9a6d07 100644 --- a/ecdsa.cpp +++ b/ecdsa.cpp @@ -40,7 +40,28 @@ bool Signature::Parse(const unsigned char *sig, int size) { return true; } -bool Signature::RecomputeR(Number &r2, const GroupElemJac &pubkey, const Number &message) { +bool Signature::Serialize(unsigned char *sig, int *size) { + int lenR = (r.GetBits() + 7)/8; + if (lenR == 0 || r.CheckBit(lenR*8-1)) + lenR++; + int lenS = (s.GetBits() + 7)/8; + if (lenS == 0 || s.CheckBit(lenS*8-1)) + lenS++; + if (*size < 6+lenS+lenR) + return false; + *size = 6 + lenS + lenR; + sig[0] = 0x30; + sig[1] = 4 + lenS + lenR; + sig[2] = 0x02; + sig[3] = lenR; + r.GetBytes(sig+4, lenR); + sig[4+lenR] = 0x02; + sig[5+lenR] = lenS; + s.GetBytes(sig+6, lenS); + return true; +} + +bool Signature::RecomputeR(Number &r2, const GroupElemJac &pubkey, const Number &message) const { const GroupConstants &c = GetGroupConst(); if (r.IsNeg() || s.IsNeg()) @@ -63,13 +84,36 @@ bool Signature::RecomputeR(Number &r2, const GroupElemJac &pubkey, const Number return true; } -bool Signature::Verify(const GroupElemJac &pubkey, const Number &message) { +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::Sign(const Number &seckey, const Number &message, const Number &nonce) { + const GroupConstants &c = GetGroupConst(); + + GroupElemJac rp; + ECMultBase(rp, nonce); + FieldElem rx; + rp.GetX(rx); + unsigned char b[32]; + 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()) + return false; + if (s.IsOdd()) + s.SetSub(c.order, s); + return true; +} + void Signature::SetRS(const Number &rin, const Number &sin) { r = rin; s = sin; diff --git a/ecdsa.h b/ecdsa.h index 4763dc3194..bef35dbd0a 100644 --- a/ecdsa.h +++ b/ecdsa.h @@ -9,8 +9,10 @@ private: public: bool Parse(const unsigned char *sig, int size); - bool RecomputeR(Number &r2, const GroupElemJac &pubkey, const Number &message); - bool Verify(const GroupElemJac &pubkey, const Number &message); + 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); std::string ToString() const; }; diff --git a/ecmult.cpp b/ecmult.cpp index e48c09bac9..67d78547d4 100644 --- a/ecmult.cpp +++ b/ecmult.cpp @@ -112,6 +112,8 @@ class ECMultConsts { public: WNAFPrecomp wpg; WNAFPrecomp wpg128; + GroupElem prec[64][16]; // prec[j][i] = 16^j * (i+1) * G + GroupElem fin; // -(sum(prec[j][0], j=0..63)) ECMultConsts() { const GroupElem &g = GetGroupConst().g; @@ -121,6 +123,20 @@ public: GroupElem g128; g128.SetJac(g128j); wpg.Build(g); wpg128.Build(g128); + GroupElemJac gg(g); + GroupElem ad(g); + GroupElemJac fn; + for (int j=0; j<64; j++) { + prec[j][0].SetJac(gg); + fn.SetAdd(fn, gg); + for (int i=1; i<16; i++) { + gg.SetAdd(gg, ad); + prec[j][i].SetJac(gg); + } + ad = prec[j][15]; + } + fn.SetNeg(fn); + fin.SetJac(fn); } }; @@ -129,6 +145,16 @@ const ECMultConsts &GetECMultConsts() { return ecmult_consts; } +void ECMultBase(GroupElemJac &out, const Number &gn) { + Number n; n.SetNumber(gn); + const ECMultConsts &c = GetECMultConsts(); + out.SetAffine(c.prec[0][n.ShiftLowBits(4)]); + for (int j=1; j<64; j++) { + out.SetAdd(out, c.prec[j][n.ShiftLowBits(4)]); + } + out.SetAdd(out, c.fin); +} + void ECMult(GroupElemJac &out, const GroupElemJac &a, const Number &an, const Number &gn) { Number an1, an2; Number gn1, gn2; diff --git a/ecmult.h b/ecmult.h index 0ad57e76a6..b779feaf62 100644 --- a/ecmult.h +++ b/ecmult.h @@ -6,6 +6,7 @@ namespace secp256k1 { +void ECMultBase(GroupElemJac &out, const Number &gn); void ECMult(GroupElemJac &out, const GroupElemJac &a, const Number &an, const Number &gn); } diff --git a/group.cpp b/group.cpp index af38b5d440..3a66174e20 100644 --- a/group.cpp +++ b/group.cpp @@ -47,10 +47,17 @@ GroupElemJac::GroupElemJac(const FieldElem &xin, const FieldElem &yin) : GroupEl GroupElemJac::GroupElemJac(const GroupElem &in) : GroupElem(in), z(1) {} -void GroupElemJac::SetJac(GroupElemJac &jac) { +void GroupElemJac::SetJac(const GroupElemJac &jac) { *this = jac; } +void GroupElemJac::SetAffine(const GroupElem &aff) { + fInfinity = aff.fInfinity; + x = aff.x; + y = aff.y; + z = FieldElem(1); +} + bool GroupElemJac::IsValid() const { if (IsInfinity()) return false; diff --git a/group.h b/group.h index d95e08cdbb..42a167797f 100644 --- a/group.h +++ b/group.h @@ -55,7 +55,9 @@ public: GroupElemJac(const GroupElem &in); - void SetJac(GroupElemJac &jac); + void SetJac(const GroupElemJac &jac); + + void SetAffine(const GroupElem &aff); /** Checks whether this is a non-infinite point on the curve */ bool IsValid() const; diff --git a/num_gmp.cpp b/num_gmp.cpp index 7945d60563..5f04c40cbc 100644 --- a/num_gmp.cpp +++ b/num_gmp.cpp @@ -58,6 +58,10 @@ 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); diff --git a/num_gmp.h b/num_gmp.h index ea330b446b..850328dee6 100644 --- a/num_gmp.h +++ b/num_gmp.h @@ -33,6 +33,7 @@ public: bool IsZero() const; bool IsOdd() const; bool IsNeg() const; + bool CheckBit(int pos) const; void Negate(); void Shift1(); void Inc(); diff --git a/num_openssl.cpp b/num_openssl.cpp index c95a733d67..cd2673ea53 100644 --- a/num_openssl.cpp +++ b/num_openssl.cpp @@ -138,6 +138,10 @@ bool Number::IsOdd() const { return BN_is_odd((const BIGNUM*)*this); } +bool Number::CheckBit(int pos) const { + return BN_is_bit_set((const BIGNUM*)*this, pos); +} + bool Number::IsNeg() const { return BN_is_negative((const BIGNUM*)*this); } diff --git a/num_openssl.h b/num_openssl.h index ddd73b9834..586d49f69b 100644 --- a/num_openssl.h +++ b/num_openssl.h @@ -35,6 +35,7 @@ public: bool IsZero() const; bool IsOdd() const; bool IsNeg() const; + bool CheckBit(int pos) const; void Negate(); void Shift1(); void Inc(); diff --git a/secp256k1.cpp b/secp256k1.cpp index 0ea273ac2e..755f93cf3e 100644 --- a/secp256k1.cpp +++ b/secp256k1.cpp @@ -25,4 +25,5 @@ int VerifyECDSA(const unsigned char *msg, int msglen, const unsigned char *sig, return 1; } + } \ No newline at end of file diff --git a/tests.cpp b/tests.cpp index 2f342b6950..49ca712120 100644 --- a/tests.cpp +++ b/tests.cpp @@ -103,9 +103,31 @@ void test_run_wnaf() { } } +void test_ecdsa_sign_verify() { + const GroupConstants &c = GetGroupConst(); + Number msg; msg.SetPseudoRand(c.order); + Number key; key.SetPseudoRand(c.order); + Number nonce; + GroupElemJac pub; ECMultBase(pub, key); + Signature sig; + do { + nonce.SetPseudoRand(c.order); + } while(!sig.Sign(key, msg, nonce)); + assert(sig.Verify(pub, msg)); + msg.Inc(); + assert(!sig.Verify(pub, msg)); +} + +void test_run_ecdsa_sign_verify() { + for (int i=0; i<1000; i++) { + test_ecdsa_sign_verify(); + } +} + int main(void) { test_run_wnaf(); test_run_point_times_order(); test_run_ecmult_chain(); + test_run_ecdsa_sign_verify(); return 0; }