diff --git a/src/ecwrapper.cpp b/src/ecwrapper.cpp index ebaa35026..3377dce0c 100644 --- a/src/ecwrapper.cpp +++ b/src/ecwrapper.cpp @@ -193,7 +193,7 @@ bool CECKey::SetPubKey(const unsigned char* pubkey, size_t size) { return o2i_ECPublicKey(&pkey, &pubkey, size) != NULL; } -bool CECKey::Sign(const uint256 &hash, std::vector& vchSig, bool lowS) { +bool CECKey::Sign(const uint256 &hash, std::vector& vchSig) { vchSig.clear(); ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); if (sig == NULL) @@ -205,7 +205,7 @@ bool CECKey::Sign(const uint256 &hash, std::vector& vchSig, bool BIGNUM *halforder = BN_CTX_get(ctx); EC_GROUP_get_order(group, order, ctx); BN_rshift1(halforder, order); - if (lowS && BN_cmp(sig->s, halforder) > 0) { + if (BN_cmp(sig->s, halforder) > 0) { // enforce low S values, by negating the value (modulo the order) if above order/2. BN_sub(sig->s, order, sig->s); } diff --git a/src/ecwrapper.h b/src/ecwrapper.h index 3457ca5f5..a7847d190 100644 --- a/src/ecwrapper.h +++ b/src/ecwrapper.h @@ -28,7 +28,7 @@ public: bool SetPrivKey(const unsigned char* privkey, size_t size, bool fSkipCheck=false); void GetPubKey(std::vector& pubkey, bool fCompressed); bool SetPubKey(const unsigned char* pubkey, size_t size); - bool Sign(const uint256 &hash, std::vector& vchSig, bool lowS); + bool Sign(const uint256 &hash, std::vector& vchSig); bool Verify(const uint256 &hash, const std::vector& vchSig); bool SignCompact(const uint256 &hash, unsigned char *p64, int &rec); diff --git a/src/key.cpp b/src/key.cpp index 1b539d073..0ca9a681a 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -102,7 +102,7 @@ CPubKey CKey::GetPubKey() const { return result; } -bool CKey::Sign(const uint256 &hash, std::vector& vchSig, bool lowS) const { +bool CKey::Sign(const uint256 &hash, std::vector& vchSig) const { if (!fValid) return false; #ifdef USE_SECP256K1 @@ -119,7 +119,7 @@ bool CKey::Sign(const uint256 &hash, std::vector& vchSig, bool lo #else CECKey key; key.SetSecretBytes(vch); - return key.Sign(hash, vchSig, lowS); + return key.Sign(hash, vchSig); #endif } diff --git a/src/key.h b/src/key.h index f36e658de..0bb05482c 100644 --- a/src/key.h +++ b/src/key.h @@ -122,7 +122,7 @@ public: CPubKey GetPubKey() const; //! Create a DER-serialized signature. - bool Sign(const uint256& hash, std::vector& vchSig, bool lowS = true) const; + bool Sign(const uint256& hash, std::vector& vchSig) const; /** * Create a compact signature (65 bytes), which allows reconstructing the used public key. diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index a41552fea..cff1664a1 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -95,6 +95,48 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bo BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, SignatureChecker(BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)), 0)) == expect, message); } +void static NegateSignatureS(std::vector& vchSig) { + // Parse the signature. + std::vector r, s; + r = std::vector(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]); + s = std::vector(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]); + unsigned char hashtype = vchSig.back(); + + // Really ugly to implement mod-n negation here, but it would be feature creep to expose such functionality from libsecp256k1. + static const unsigned char order[33] = { + 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, + 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 + }; + while (s.size() < 33) { + s.insert(s.begin(), 0x00); + } + int carry = 0; + for (int p = 32; p >= 1; p--) { + int n = (int)order[p] - s[p] - carry; + s[p] = (n + 256) & 0xFF; + carry = (n < 0); + } + assert(carry == 0); + if (s.size() > 1 && s[0] == 0 && s[1] < 0x80) { + s.erase(s.begin()); + } + + // Reconstruct the signature. + vchSig.clear(); + vchSig.push_back(0x30); + vchSig.push_back(4 + r.size() + s.size()); + vchSig.push_back(0x02); + vchSig.push_back(r.size()); + vchSig.insert(vchSig.end(), r.begin(), r.end()); + vchSig.push_back(0x02); + vchSig.push_back(s.size()); + vchSig.insert(vchSig.end(), s.begin(), s.end()); + vchSig.push_back(hashtype); +} + namespace { const unsigned char vchKey0[32] = {0,0,0,0,0,0,0,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}; @@ -194,7 +236,10 @@ public: uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType); std::vector vchSig, r, s; do { - key.Sign(hash, vchSig, lenS <= 32); + key.Sign(hash, vchSig); + if ((lenS == 33) != (vchSig[5 + vchSig[3]] == 33)) { + NegateSignatureS(vchSig); + } r = std::vector(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]); s = std::vector(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]); } while (lenR != r.size() || lenS != s.size());