Skip to content

Commit 4c0c25a

Browse files
committed
Require compressed keys in segwit as policy and disable signing with uncompressed keys for segwit scripts
1 parent 3ade2f6 commit 4c0c25a

File tree

8 files changed

+49
-36
lines changed

8 files changed

+49
-36
lines changed

src/policy/policy.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (c) 2009-2010 Satoshi Nakamoto
2-
// Copyright (c) 2009-2015 The Bitcoin developers
2+
// Copyright (c) 2009-2016 The Bitcoin developers
33
// Distributed under the MIT software license, see the accompanying
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

@@ -54,7 +54,8 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY
5454
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
5555
SCRIPT_VERIFY_LOW_S |
5656
SCRIPT_VERIFY_WITNESS |
57-
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM;
57+
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
58+
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE;
5859

5960
/** For convenience, standard but not mandatory verify flags. */
6061
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;

src/script/interpreter.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,20 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
7979
return false;
8080
}
8181
} else {
82-
// Non-canonical public key: neither compressed nor uncompressed
83-
return false;
82+
// Non-canonical public key: neither compressed nor uncompressed
83+
return false;
84+
}
85+
return true;
86+
}
87+
88+
bool static IsCompressedPubKey(const valtype &vchPubKey) {
89+
if (vchPubKey.size() != 33) {
90+
// Non-canonical public key: invalid length for compressed key
91+
return false;
92+
}
93+
if (vchPubKey[0] != 0x02 && vchPubKey[0] != 0x03) {
94+
// Non-canonical public key: invalid prefix for compressed key
95+
return false;
8496
}
8597
return true;
8698
}
@@ -199,10 +211,14 @@ bool CheckSignatureEncoding(const vector<unsigned char> &vchSig, unsigned int fl
199211
return true;
200212
}
201213

202-
bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) {
203-
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchSig)) {
214+
bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, const SigVersion &sigversion, ScriptError* serror) {
215+
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {
204216
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
205217
}
218+
// Only compressed keys are accepted in segwit
219+
if ((flags & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) != 0 && sigversion == SIGVERSION_WITNESS_V0 && !IsCompressedPubKey(vchPubKey)) {
220+
return set_error(serror, SCRIPT_ERR_WITNESS_PUBKEYTYPE);
221+
}
206222
return true;
207223
}
208224

@@ -879,7 +895,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
879895
scriptCode.FindAndDelete(CScript(vchSig));
880896
}
881897

882-
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
898+
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
883899
//serror is set
884900
return false;
885901
}
@@ -953,7 +969,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
953969
// Note how this makes the exact order of pubkey/signature evaluation
954970
// distinguishable by CHECKMULTISIG NOT if the STRICTENC flag is set.
955971
// See the script_(in)valid tests for details.
956-
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
972+
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
957973
// serror is set
958974
return false;
959975
}

src/script/interpreter.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (c) 2009-2010 Satoshi Nakamoto
2-
// Copyright (c) 2009-2015 The Bitcoin Core developers
2+
// Copyright (c) 2009-2016 The Bitcoin Core developers
33
// Distributed under the MIT software license, see the accompanying
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

@@ -102,6 +102,10 @@ enum
102102
// Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed
103103
//
104104
SCRIPT_VERIFY_NULLFAIL = (1U << 14),
105+
106+
// Public keys in segregated witness scripts must be compressed
107+
//
108+
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
105109
};
106110

107111
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);

src/script/script_error.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ const char* ScriptErrorString(const ScriptError serror)
8585
return "Witness requires only-redeemscript scriptSig";
8686
case SCRIPT_ERR_WITNESS_UNEXPECTED:
8787
return "Witness provided for non-witness script";
88+
case SCRIPT_ERR_WITNESS_PUBKEYTYPE:
89+
return "Using non-compressed keys in segwit";
8890
case SCRIPT_ERR_UNKNOWN_ERROR:
8991
case SCRIPT_ERR_ERROR_COUNT:
9092
default: break;

src/script/script_error.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ typedef enum ScriptError_t
6262
SCRIPT_ERR_WITNESS_MALLEATED,
6363
SCRIPT_ERR_WITNESS_MALLEATED_P2SH,
6464
SCRIPT_ERR_WITNESS_UNEXPECTED,
65+
SCRIPT_ERR_WITNESS_PUBKEYTYPE,
6566

6667
SCRIPT_ERR_ERROR_COUNT
6768
} ScriptError;

src/script/sign.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (c) 2009-2010 Satoshi Nakamoto
2-
// Copyright (c) 2009-2015 The Bitcoin Core developers
2+
// Copyright (c) 2009-2016 The Bitcoin Core developers
33
// Distributed under the MIT software license, see the accompanying
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

@@ -26,6 +26,10 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
2626
if (!keystore->GetKey(address, key))
2727
return false;
2828

29+
// Signing with uncompressed keys is disabled in witness scripts
30+
if (sigversion == SIGVERSION_WITNESS_V0 && !key.IsCompressed())
31+
return false;
32+
2933
uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
3034
if (!key.Sign(hash, vchSig))
3135
return false;

src/test/script_tests.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static ScriptErrorDesc script_errors[]={
9999
{SCRIPT_ERR_WITNESS_MALLEATED, "WITNESS_MALLEATED"},
100100
{SCRIPT_ERR_WITNESS_MALLEATED_P2SH, "WITNESS_MALLEATED_P2SH"},
101101
{SCRIPT_ERR_WITNESS_UNEXPECTED, "WITNESS_UNEXPECTED"},
102+
{SCRIPT_ERR_WITNESS_PUBKEYTYPE, "WITNESS_PUBKEYTYPE"},
102103
};
103104

104105
const char *FormatScriptError(ScriptError_t err)

src/test/transaction_tests.cpp

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2011-2015 The Bitcoin Core developers
1+
// Copyright (c) 2011-2016 The Bitcoin Core developers
22
// Distributed under the MIT software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

@@ -55,7 +55,8 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
5555
(string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
5656
(string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
5757
(string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS)
58-
(string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM);
58+
(string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)
59+
(string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE);
5960

6061
unsigned int ParseScriptFlags(string strFlags)
6162
{
@@ -429,7 +430,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
429430
mtx.nVersion = 1;
430431

431432
CKey key;
432-
key.MakeNewKey(false);
433+
key.MakeNewKey(true); // Need to use compressed keys in segwit or the signing will fail
433434
CBasicKeyStore keystore;
434435
keystore.AddKeyPubKey(key, key.GetPubKey());
435436
CKeyID hash = key.GetPubKey().GetID();
@@ -625,30 +626,13 @@ BOOST_AUTO_TEST_CASE(test_witness)
625626
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
626627
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
627628

628-
// Witness pay-to-uncompressed-pubkey (v1).
629-
CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey1L), output1, input1);
630-
CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2L), output2, input2);
631-
CheckWithFlag(output1, input1, 0, true);
632-
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
633-
CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
634-
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
635-
CheckWithFlag(output1, input2, 0, true);
636-
CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true);
637-
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
638-
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
629+
// Signing disabled for witness pay-to-uncompressed-pubkey (v1).
630+
CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey1L), output1, input1, false);
631+
CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2L), output2, input2, false);
639632

640-
// P2SH witness pay-to-uncompressed-pubkey (v1).
641-
CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1L))), output1, input1);
642-
CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2L))), output2, input2);
643-
ReplaceRedeemScript(input2.vin[0].scriptSig, GetScriptForWitness(scriptPubkey1L));
644-
CheckWithFlag(output1, input1, 0, true);
645-
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
646-
CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
647-
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
648-
CheckWithFlag(output1, input2, 0, true);
649-
CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true);
650-
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
651-
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
633+
// Signing disabled for P2SH witness pay-to-uncompressed-pubkey (v1).
634+
CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1L))), output1, input1, false);
635+
CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2L))), output2, input2, false);
652636

653637
// Normal 2-of-2 multisig
654638
CreateCreditAndSpend(keystore, scriptMulti, output1, input1, false);

0 commit comments

Comments
 (0)