8000 Only create signatures with even S, and verification mode to check. by sipa · Pull Request #2131 · bitcoin/bitcoin · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Only create signatures with even S, and verification mode to check. #2131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 16, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/key.cpp
10000
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,26 @@ class CECKey {
}

bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) {
vchSig.clear();
ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
if (sig == NULL)
return false;
if (BN_is_odd(sig->s)) {
// enforce even S values, by negating the value (modulo the order) if odd
BN_CTX *ctx = BN_CTX_new();
BN_CTX_start(ctx);
const EC_GROUP *group = EC_KEY_get0_group(pkey);
BIGNUM *order = BN_CTX_get(ctx);
EC_GROUP_get_order(group, order, ctx);
BN_sub(sig->s, order, sig->s);
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
unsigned int nSize = ECDSA_size(pkey);
vchSig.resize(nSize); // Make sure it is big enough
assert(ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey));
unsigned char *pos = &vchSig[0];
nSize = i2d_ECDSA_SIG(sig, &pos);
ECDSA_SIG_free(sig);
vchSig.resize(nSize); // Shrink to fit actual size
return true;
}
Expand Down
26 changes: 17 additions & 9 deletions src/script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,10 @@ const char* GetOpName(opcodetype opcode)
}
}

bool IsCanonicalPubKey(const valtype &vchPubKey) {
bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) {
if (!(flags & SCRIPT_VERIFY_STRICTENC))
return true;

if (vchPubKey.size() < 33)
return error("Non-canonical public key: too short");
if (vchPubKey[0] == 0x04) {
Expand All @@ -242,7 +245,10 @@ bool IsCanonicalPubKey(const valtype &vchPubKey) {
return true;
}

bool IsCanonicalSignature(const valtype &vchSig) {
bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) {
if (!(flags & SCRIPT_VERIFY_STRICTENC))
return true;

// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
// A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
// Where R and S are not negative (their first byte has its highest bit not set), and not
Expand Down Expand Up @@ -286,6 +292,11 @@ bool IsCanonicalSignature(const valtype &vchSig) {
if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80))
return error("Non-canonical signature: S value excessively padded");

if (flags & SCRIPT_VERIFY_EVEN_S) {
if (S[nLenS-1] & 1)
return error("Non-canonical signature: S value odd");
}

return true;
}

Expand All @@ -302,7 +313,6 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
if (script.size() > 10000)
return false;
int nOpCount = 0;
bool fStrictEncodings = flags & SCRIPT_VERIFY_STRICTENC;

try
{
Expand Down Expand Up @@ -841,9 +851,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
// Drop the signature, since there's no way for a signature to sign itself
scriptCode.FindAndDelete(CScript(vchSig));

bool fSuccess = (!fStrictEncodings || (IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey)));
if (fSuccess)
fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags);
bool fSuccess = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) &&
CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags);

popstack(stack);
popstack(stack);
Expand Down Expand Up @@ -903,9 +912,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
valtype& vchPubKey = stacktop(-ikey);

// Check signature
bool fOk = (!fStrictEncodings || (IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey)));
if (fOk)
fOk = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags);
bool fOk = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) &&
CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType, flags);

if (fOk) {
isig++;
Expand Down
11 changes: 6 additions & 5 deletions src/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ enum
enum
{
SCRIPT_VERIFY_NONE = 0,
SCRIPT_VERIFY_P2SH = (1U << 0),
SCRIPT_VERIFY_STRICTENC = (1U << 1),
SCRIPT_VERIFY_NOCACHE = (1U << 2),
SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys
SCRIPT_VERIFY_EVEN_S = (1U << 2), // enforce even S values in signatures (depends on STRICTENC)
SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it)
};

enum txnouttype
Expand Down Expand Up @@ -665,8 +666,8 @@ class CScriptCompressor
}
};

bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey);
bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig);
bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags);
bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int flags);

bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType);
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
Expand Down
4 changes: 2 additions & 2 deletions src/test/canonical_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(script_canon)
string test = tv.get_str();
if (IsHex(test)) {
std::vector<unsigned char> sig = ParseHex(test);
BOOST_CHECK_MESSAGE(IsCanonicalSignature(sig), test);
BOOST_CHECK_MESSAGE(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test);
BOOST_CHECK_MESSAGE(IsCanonicalSignature_OpenSSL(sig), test);
}
}
Expand All @@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(script_noncanon)
string test = tv.get_str();
if (IsHex(test)) {
std::vector<unsigned char> sig = ParseHex(test);
BOOST_CHECK_MESSAGE(!IsCanonicalSignature(sig), test);
BOOST_CHECK_MESSAGE(!IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test);
BOOST_CHECK_MESSAGE(!IsCanonicalSignature_OpenSSL(sig), test);
}
}
Expand Down
0