mirror of
https://github.com/dashpay/dash.git
synced 2024-12-27 04:52:59 +01:00
Require compressed keys in segwit as policy and disable signing with uncompressed keys for segwit scripts
This commit is contained in:
parent
3ade2f64cf
commit
4c0c25a604
@ -1,5 +1,5 @@
|
|||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2015 The Bitcoin developers
|
// Copyright (c) 2009-2016 The Bitcoin developers
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
@ -54,7 +54,8 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY
|
|||||||
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
|
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
|
||||||
SCRIPT_VERIFY_LOW_S |
|
SCRIPT_VERIFY_LOW_S |
|
||||||
SCRIPT_VERIFY_WITNESS |
|
SCRIPT_VERIFY_WITNESS |
|
||||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM;
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
|
||||||
|
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE;
|
||||||
|
|
||||||
/** For convenience, standard but not mandatory verify flags. */
|
/** For convenience, standard but not mandatory verify flags. */
|
||||||
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
|
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
|
||||||
|
@ -85,6 +85,18 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool static IsCompressedPubKey(const valtype &vchPubKey) {
|
||||||
|
if (vchPubKey.size() != 33) {
|
||||||
|
// Non-canonical public key: invalid length for compressed key
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (vchPubKey[0] != 0x02 && vchPubKey[0] != 0x03) {
|
||||||
|
// Non-canonical public key: invalid prefix for compressed key
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
|
* 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
|
* Where R and S are not negative (their first byte has its highest bit not set), and not
|
||||||
@ -199,10 +211,14 @@ bool CheckSignatureEncoding(const vector<unsigned char> &vchSig, unsigned int fl
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) {
|
bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, const SigVersion &sigversion, ScriptError* serror) {
|
||||||
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchSig)) {
|
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {
|
||||||
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
|
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
|
||||||
}
|
}
|
||||||
|
// Only compressed keys are accepted in segwit
|
||||||
|
if ((flags & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) != 0 && sigversion == SIGVERSION_WITNESS_V0 && !IsCompressedPubKey(vchPubKey)) {
|
||||||
|
return set_error(serror, SCRIPT_ERR_WITNESS_PUBKEYTYPE);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -879,7 +895,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
|||||||
scriptCode.FindAndDelete(CScript(vchSig));
|
scriptCode.FindAndDelete(CScript(vchSig));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
|
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
|
||||||
//serror is set
|
//serror is set
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -953,7 +969,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
|||||||
// Note how this makes the exact order of pubkey/signature evaluation
|
// Note how this makes the exact order of pubkey/signature evaluation
|
||||||
// distinguishable by CHECKMULTISIG NOT if the STRICTENC flag is set.
|
// distinguishable by CHECKMULTISIG NOT if the STRICTENC flag is set.
|
||||||
// See the script_(in)valid tests for details.
|
// See the script_(in)valid tests for details.
|
||||||
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
|
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
|
||||||
// serror is set
|
// serror is set
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
// Copyright (c) 2009-2016 The Bitcoin Core developers
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
@ -102,6 +102,10 @@ enum
|
|||||||
// Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed
|
// Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed
|
||||||
//
|
//
|
||||||
SCRIPT_VERIFY_NULLFAIL = (1U << 14),
|
SCRIPT_VERIFY_NULLFAIL = (1U << 14),
|
||||||
|
|
||||||
|
// Public keys in segregated witness scripts must be compressed
|
||||||
|
//
|
||||||
|
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
|
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
|
||||||
|
@ -85,6 +85,8 @@ const char* ScriptErrorString(const ScriptError serror)
|
|||||||
return "Witness requires only-redeemscript scriptSig";
|
return "Witness requires only-redeemscript scriptSig";
|
||||||
case SCRIPT_ERR_WITNESS_UNEXPECTED:
|
case SCRIPT_ERR_WITNESS_UNEXPECTED:
|
||||||
return "Witness provided for non-witness script";
|
return "Witness provided for non-witness script";
|
||||||
|
case SCRIPT_ERR_WITNESS_PUBKEYTYPE:
|
||||||
|
return "Using non-compressed keys in segwit";
|
||||||
case SCRIPT_ERR_UNKNOWN_ERROR:
|
case SCRIPT_ERR_UNKNOWN_ERROR:
|
||||||
case SCRIPT_ERR_ERROR_COUNT:
|
case SCRIPT_ERR_ERROR_COUNT:
|
||||||
default: break;
|
default: break;
|
||||||
|
@ -62,6 +62,7 @@ typedef enum ScriptError_t
|
|||||||
SCRIPT_ERR_WITNESS_MALLEATED,
|
SCRIPT_ERR_WITNESS_MALLEATED,
|
||||||
SCRIPT_ERR_WITNESS_MALLEATED_P2SH,
|
SCRIPT_ERR_WITNESS_MALLEATED_P2SH,
|
||||||
SCRIPT_ERR_WITNESS_UNEXPECTED,
|
SCRIPT_ERR_WITNESS_UNEXPECTED,
|
||||||
|
SCRIPT_ERR_WITNESS_PUBKEYTYPE,
|
||||||
|
|
||||||
SCRIPT_ERR_ERROR_COUNT
|
SCRIPT_ERR_ERROR_COUNT
|
||||||
} ScriptError;
|
} ScriptError;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
// Copyright (c) 2009-2016 The Bitcoin Core developers
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
@ -26,6 +26,10 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
|
|||||||
if (!keystore->GetKey(address, key))
|
if (!keystore->GetKey(address, key))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Signing with uncompressed keys is disabled in witness scripts
|
||||||
|
if (sigversion == SIGVERSION_WITNESS_V0 && !key.IsCompressed())
|
||||||
|
return false;
|
||||||
|
|
||||||
uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
|
uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
|
||||||
if (!key.Sign(hash, vchSig))
|
if (!key.Sign(hash, vchSig))
|
||||||
return false;
|
return false;
|
||||||
|
@ -99,6 +99,7 @@ static ScriptErrorDesc script_errors[]={
|
|||||||
{SCRIPT_ERR_WITNESS_MALLEATED, "WITNESS_MALLEATED"},
|
{SCRIPT_ERR_WITNESS_MALLEATED, "WITNESS_MALLEATED"},
|
||||||
{SCRIPT_ERR_WITNESS_MALLEATED_P2SH, "WITNESS_MALLEATED_P2SH"},
|
{SCRIPT_ERR_WITNESS_MALLEATED_P2SH, "WITNESS_MALLEATED_P2SH"},
|
||||||
{SCRIPT_ERR_WITNESS_UNEXPECTED, "WITNESS_UNEXPECTED"},
|
{SCRIPT_ERR_WITNESS_UNEXPECTED, "WITNESS_UNEXPECTED"},
|
||||||
|
{SCRIPT_ERR_WITNESS_PUBKEYTYPE, "WITNESS_PUBKEYTYPE"},
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *FormatScriptError(ScriptError_t err)
|
const char *FormatScriptError(ScriptError_t err)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2011-2015 The Bitcoin Core developers
|
// Copyright (c) 2011-2016 The Bitcoin Core developers
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
@ -55,7 +55,8 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
|
|||||||
(string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
|
(string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
|
||||||
(string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
|
(string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
|
||||||
(string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS)
|
(string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS)
|
||||||
(string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM);
|
(string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)
|
||||||
|
(string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE);
|
||||||
|
|
||||||
unsigned int ParseScriptFlags(string strFlags)
|
unsigned int ParseScriptFlags(string strFlags)
|
||||||
{
|
{
|
||||||
@ -429,7 +430,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
|
|||||||
mtx.nVersion = 1;
|
mtx.nVersion = 1;
|
||||||
|
|
||||||
CKey key;
|
CKey key;
|
||||||
key.MakeNewKey(false);
|
key.MakeNewKey(true); // Need to use compressed keys in segwit or the signing will fail
|
||||||
CBasicKeyStore keystore;
|
CBasicKeyStore keystore;
|
||||||
keystore.AddKeyPubKey(key, key.GetPubKey());
|
keystore.AddKeyPubKey(key, key.GetPubKey());
|
||||||
CKeyID hash = key.GetPubKey().GetID();
|
CKeyID hash = key.GetPubKey().GetID();
|
||||||
@ -625,30 +626,13 @@ BOOST_AUTO_TEST_CASE(test_witness)
|
|||||||
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
|
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
|
||||||
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
|
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
|
||||||
|
|
||||||
// Witness pay-to-uncompressed-pubkey (v1).
|
// Signing disabled for witness pay-to-uncompressed-pubkey (v1).
|
||||||
CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey1L), output1, input1);
|
CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey1L), output1, input1, false);
|
||||||
CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2L), output2, input2);
|
CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2L), output2, input2, false);
|
||||||
CheckWithFlag(output1, input1, 0, true);
|
|
||||||
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
|
|
||||||
CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
|
|
||||||
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
|
|
||||||
CheckWithFlag(output1, input2, 0, true);
|
|
||||||
CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true);
|
|
||||||
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
|
|
||||||
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
|
|
||||||
|
|
||||||
// P2SH witness pay-to-uncompressed-pubkey (v1).
|
// Signing disabled for P2SH witness pay-to-uncompressed-pubkey (v1).
|
||||||
CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1L))), output1, input1);
|
CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1L))), output1, input1, false);
|
||||||
CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2L))), output2, input2);
|
CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2L))), output2, input2, false);
|
||||||
ReplaceRedeemScript(input2.vin[0].scriptSig, GetScriptForWitness(scriptPubkey1L));
|
|
||||||
CheckWithFlag(output1, input1, 0, true);
|
|
||||||
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
|
|
||||||
CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
|
|
||||||
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
|
|
||||||
CheckWithFlag(output1, input2, 0, true);
|
|
||||||
CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true);
|
|
||||||
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
|
|
||||||
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
|
|
||||||
|
|
||||||
// Normal 2-of-2 multisig
|
// Normal 2-of-2 multisig
|
||||||
CreateCreditAndSpend(keystore, scriptMulti, output1, input1, false);
|
CreateCreditAndSpend(keystore, scriptMulti, output1, input1, false);
|
||||||
|
Loading…
Reference in New Issue
Block a user