diff --git a/src/key.cpp b/src/key.cpp index ad544b389..cf39bd3ee 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -1,358 +1,358 @@ // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "key.h" #include "arith_uint256.h" #include "crypto/common.h" #include "crypto/hmac_sha512.h" #include "pubkey.h" #include "random.h" #include #include static secp256k1_context *secp256k1_context_sign = nullptr; /** These functions are taken from the libsecp256k1 distribution and are very * ugly. */ static int ec_privkey_import_der(const secp256k1_context *ctx, uint8_t *out32, const uint8_t *privkey, size_t privkeylen) { const uint8_t *end = privkey + privkeylen; int lenb = 0; int len = 0; memset(out32, 0, 32); /* sequence header */ if (end < privkey + 1 || *privkey != 0x30) { return 0; } privkey++; /* sequence length constructor */ if (end < privkey + 1 || !(*privkey & 0x80)) { return 0; } lenb = *privkey & ~0x80; privkey++; if (lenb < 1 || lenb > 2) { return 0; } if (end < privkey + lenb) { return 0; } /* sequence length */ len = privkey[lenb - 1] | (lenb > 1 ? privkey[lenb - 2] << 8 : 0); privkey += lenb; if (end < privkey + len) { return 0; } /* sequence element 0: version number (=1) */ if (end < privkey + 3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { return 0; } privkey += 3; /* sequence element 1: octet string, up to 32 bytes */ if (end < privkey + 2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey + 2 + privkey[1]) { return 0; } memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); if (!secp256k1_ec_seckey_verify(ctx, out32)) { memset(out32, 0, 32); return 0; } return 1; } static int ec_privkey_export_der(const secp256k1_context *ctx, uint8_t *privkey, size_t *privkeylen, const uint8_t *key32, int compressed) { secp256k1_pubkey pubkey; size_t pubkeylen = 0; if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { *privkeylen = 0; return 0; } if (compressed) { static const uint8_t begin[] = {0x30, 0x81, 0xD3, 0x02, 0x01, 0x01, 0x04, 0x20}; static const uint8_t middle[] = { 0xA0, 0x81, 0x85, 0x30, 0x81, 0x82, 0x02, 0x01, 0x01, 0x30, 0x2C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, 0x30, 0x06, 0x04, 0x01, 0x00, 0x04, 0x01, 0x07, 0x04, 0x21, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x21, 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, 0x02, 0x01, 0x01, 0xA1, 0x24, 0x03, 0x22, 0x00}; uint8_t *ptr = privkey; memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); memcpy(ptr, key32, 32); ptr += 32; memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); pubkeylen = 33; secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); ptr += pubkeylen; *privkeylen = ptr - privkey; } else { static const uint8_t begin[] = {0x30, 0x82, 0x01, 0x13, 0x02, 0x01, 0x01, 0x04, 0x20}; static const uint8_t middle[] = { 0xA0, 0x81, 0xA5, 0x30, 0x81, 0xA2, 0x02, 0x01, 0x01, 0x30, 0x2C, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x01, 0x01, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F, 0x30, 0x06, 0x04, 0x01, 0x00, 0x04, 0x01, 0x07, 0x04, 0x41, 0x04, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, 0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, 0xB8, 0x02, 0x21, 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, 0x02, 0x01, 0x01, 0xA1, 0x44, 0x03, 0x42, 0x00}; uint8_t *ptr = privkey; memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); memcpy(ptr, key32, 32); ptr += 32; memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); pubkeylen = 65; secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); ptr += pubkeylen; *privkeylen = ptr - privkey; } return 1; } bool CKey::Check(const uint8_t *vch) { return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch); } void CKey::MakeNewKey(bool fCompressedIn) { do { GetStrongRandBytes(keydata.data(), keydata.size()); } while (!Check(keydata.data())); fValid = true; fCompressed = fCompressedIn; } CPrivKey CKey::GetPrivKey() const { assert(fValid); CPrivKey privkey; int ret; size_t privkeylen; privkey.resize(279); privkeylen = 279; ret = ec_privkey_export_der( secp256k1_context_sign, (uint8_t *)&privkey[0], &privkeylen, begin(), fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); assert(ret); privkey.resize(privkeylen); return privkey; } CPubKey CKey::GetPubKey() const { assert(fValid); secp256k1_pubkey pubkey; size_t clen = 65; CPubKey result; int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin()); assert(ret); secp256k1_ec_pubkey_serialize( secp256k1_context_sign, (uint8_t *)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); assert(result.size() == clen); assert(result.IsValid()); return result; } -bool CKey::Sign(const uint256 &hash, std::vector &vchSig, - uint32_t test_case) const { +bool CKey::SignECDSA(const uint256 &hash, std::vector &vchSig, + uint32_t test_case) const { if (!fValid) return false; vchSig.resize(72); size_t nSigLen = 72; uint8_t extra_entropy[32] = {0}; WriteLE32(extra_entropy, test_case); secp256k1_ecdsa_signature sig; int ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : nullptr); assert(ret); secp256k1_ecdsa_signature_serialize_der( secp256k1_context_sign, (uint8_t *)&vchSig[0], &nSigLen, &sig); vchSig.resize(nSigLen); return true; } bool CKey::VerifyPubKey(const CPubKey &pubkey) const { if (pubkey.IsCompressed() != fCompressed) { return false; } uint8_t rnd[8]; std::string str = "Bitcoin key verification\n"; GetRandBytes(rnd, sizeof(rnd)); uint256 hash; CHash256() .Write((uint8_t *)str.data(), str.size()) .Write(rnd, sizeof(rnd)) .Finalize(hash.begin()); std::vector vchSig; - Sign(hash, vchSig); - return pubkey.Verify(hash, vchSig); + SignECDSA(hash, vchSig); + return pubkey.VerifyECDSA(hash, vchSig); } bool CKey::SignCompact(const uint256 &hash, std::vector &vchSig) const { if (!fValid) return false; vchSig.resize(65); int rec = -1; secp256k1_ecdsa_recoverable_signature sig; int ret = secp256k1_ecdsa_sign_recoverable( secp256k1_context_sign, &sig, hash.begin(), begin(), secp256k1_nonce_function_rfc6979, nullptr); assert(ret); secp256k1_ecdsa_recoverable_signature_serialize_compact( secp256k1_context_sign, (uint8_t *)&vchSig[1], &rec, &sig); assert(ret); assert(rec != -1); vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); return true; } bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck = false) { if (!ec_privkey_import_der(secp256k1_context_sign, (uint8_t *)begin(), &privkey[0], privkey.size())) return false; fCompressed = vchPubKey.IsCompressed(); fValid = true; if (fSkipCheck) return true; return VerifyPubKey(vchPubKey); } bool CKey::Derive(CKey &keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode &cc) const { assert(IsValid()); assert(IsCompressed()); std::vector> vout(64); if ((nChild >> 31) == 0) { CPubKey pubkey = GetPubKey(); assert(pubkey.begin() + 33 == pubkey.end()); BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin() + 1, vout.data()); } else { assert(begin() + 32 == end()); BIP32Hash(cc, nChild, 0, begin(), vout.data()); } memcpy(ccChild.begin(), vout.data() + 32, 32); memcpy((uint8_t *)keyChild.begin(), begin(), 32); bool ret = secp256k1_ec_privkey_tweak_add( secp256k1_context_sign, (uint8_t *)keyChild.begin(), vout.data()); keyChild.fCompressed = true; keyChild.fValid = ret; return ret; } bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const { out.nDepth = nDepth + 1; CKeyID id = key.GetPubKey().GetID(); memcpy(&out.vchFingerprint[0], &id, 4); out.nChild = _nChild; return key.Derive(out.key, out.chaincode, _nChild, chaincode); } void CExtKey::SetMaster(const uint8_t *seed, unsigned int nSeedLen) { static const uint8_t hashkey[] = {'B', 'i', 't', 'c', 'o', 'i', 'n', ' ', 's', 'e', 'e', 'd'}; std::vector> vout(64); CHMAC_SHA512(hashkey, sizeof(hashkey)) .Write(seed, nSeedLen) .Finalize(vout.data()); key.Set(&vout[0], &vout[32], true); memcpy(chaincode.begin(), &vout[32], 32); nDepth = 0; nChild = 0; memset(vchFingerprint, 0, sizeof(vchFingerprint)); } CExtPubKey CExtKey::Neuter() const { CExtPubKey ret; ret.nDepth = nDepth; memcpy(&ret.vchFingerprint[0], &vchFingerprint[0], 4); ret.nChild = nChild; ret.pubkey = key.GetPubKey(); ret.chaincode = chaincode; return ret; } void CExtKey::Encode(uint8_t code[BIP32_EXTKEY_SIZE]) const { code[0] = nDepth; memcpy(code + 1, vchFingerprint, 4); code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF; code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF; memcpy(code + 9, chaincode.begin(), 32); code[41] = 0; assert(key.size() == 32); memcpy(code + 42, key.begin(), 32); } void CExtKey::Decode(const uint8_t code[BIP32_EXTKEY_SIZE]) { nDepth = code[0]; memcpy(vchFingerprint, code + 1, 4); nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8]; memcpy(chaincode.begin(), code + 9, 32); key.Set(code + 42, code + BIP32_EXTKEY_SIZE, true); } bool ECC_InitSanityCheck() { CKey key; key.MakeNewKey(true); CPubKey pubkey = key.GetPubKey(); return key.VerifyPubKey(pubkey); } void ECC_Start() { assert(secp256k1_context_sign == nullptr); secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); assert(ctx != nullptr); { // Pass in a random blinding seed to the secp256k1 context. std::vector> vseed(32); GetRandBytes(vseed.data(), 32); bool ret = secp256k1_context_randomize(ctx, vseed.data()); assert(ret); } secp256k1_context_sign = ctx; } void ECC_Stop() { secp256k1_context *ctx = secp256k1_context_sign; secp256k1_context_sign = nullptr; if (ctx) { secp256k1_context_destroy(ctx); } } diff --git a/src/key.h b/src/key.h index bf6d39a30..ca4f928cd 100644 --- a/src/key.h +++ b/src/key.h @@ -1,189 +1,190 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_KEY_H #define BITCOIN_KEY_H #include "pubkey.h" #include "serialize.h" #include "support/allocators/secure.h" #include "uint256.h" #include #include /** * secp256k1: * const unsigned int PRIVATE_KEY_SIZE = 279; * const unsigned int PUBLIC_KEY_SIZE = 65; * const unsigned int SIGNATURE_SIZE = 72; * * see www.keylength.com * script supports up to 75 for single byte push */ /** * secure_allocator is defined in allocators.h * CPrivKey is a serialized private key, with all parameters included (279 * bytes) */ typedef std::vector> CPrivKey; -/** An encapsulated private key. */ +/** An encapsulated secp256k1 private key. */ class CKey { private: //! Whether this private key is valid. We check for correctness when //! modifying the key data, so fValid should always correspond to the actual //! state. bool fValid; //! Whether the public key corresponding to this private key is (to be) //! compressed. bool fCompressed; //! The actual byte data std::vector> keydata; //! Check whether the 32-byte array pointed to be vch is valid keydata. static bool Check(const uint8_t *vch); public: //! Construct an invalid private key. CKey() : fValid(false), fCompressed(false) { // Important: vch must be 32 bytes in length to not break serialization keydata.resize(32); } //! Destructor (again necessary because of memlocking). ~CKey() {} friend bool operator==(const CKey &a, const CKey &b) { return a.fCompressed == b.fCompressed && a.size() == b.size() && memcmp(a.keydata.data(), b.keydata.data(), a.size()) == 0; } //! Initialize using begin and end iterators to byte data. template void Set(const T pbegin, const T pend, bool fCompressedIn) { if (size_t(pend - pbegin) != keydata.size()) { fValid = false; } else if (Check(&pbegin[0])) { memcpy(keydata.data(), (uint8_t *)&pbegin[0], keydata.size()); fValid = true; fCompressed = fCompressedIn; } else { fValid = false; } } //! Simple read-only vector-like interface. unsigned int size() const { return (fValid ? keydata.size() : 0); } const uint8_t *begin() const { return keydata.data(); } const uint8_t *end() const { return keydata.data() + size(); } //! Check whether this private key is valid. bool IsValid() const { return fValid; } //! Check whether the public key corresponding to this private key is (to //! be) compressed. bool IsCompressed() const { return fCompressed; } //! Generate a new private key using a cryptographic PRNG. void MakeNewKey(bool fCompressed); /** * Convert the private key to a CPrivKey (serialized OpenSSL private key * data). * This is expensive. */ CPrivKey GetPrivKey() const; /** * Compute the public key from a private key. * This is expensive. */ CPubKey GetPubKey() const; /** - * Create a DER-serialized signature. + * Create a DER-serialized ECDSA signature. * The test_case parameter tweaks the deterministic nonce. */ - bool Sign(const uint256 &hash, std::vector &vchSig, - uint32_t test_case = 0) const; + bool SignECDSA(const uint256 &hash, std::vector &vchSig, + uint32_t test_case = 0) const; /** - * Create a compact signature (65 bytes), which allows reconstructing the - * used public key. + * Create a compact ECDSA signature (65 bytes), which allows reconstructing + * the used public key. * The format is one header byte, followed by two times 32 bytes for the * serialized r and s values. * The header byte: 0x1B = first key with even y, 0x1C = first key with odd * y, * 0x1D = second key with even y, 0x1E = second key with * odd y, * add 0x04 for compressed keys. */ bool SignCompact(const uint256 &hash, std::vector &vchSig) const; //! Derive BIP32 child key. bool Derive(CKey &keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode &cc) const; /** * Verify thoroughly whether a private key and a public key match. * This is done using a different mechanism than just regenerating it. + * (An ECDSA signature is created then verified.) */ bool VerifyPubKey(const CPubKey &vchPubKey) const; //! Load private key and check that public key matches. bool Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck); }; struct CExtKey { uint8_t nDepth; uint8_t vchFingerprint[4]; unsigned int nChild; ChainCode chaincode; CKey key; friend bool operator==(const CExtKey &a, const CExtKey &b) { return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 && a.nChild == b.nChild && a.chaincode == b.chaincode && a.key == b.key; } void Encode(uint8_t code[BIP32_EXTKEY_SIZE]) const; void Decode(const uint8_t code[BIP32_EXTKEY_SIZE]); bool Derive(CExtKey &out, unsigned int nChild) const; CExtPubKey Neuter() const; void SetMaster(const uint8_t *seed, unsigned int nSeedLen); template void Serialize(Stream &s) const { unsigned int len = BIP32_EXTKEY_SIZE; ::WriteCompactSize(s, len); uint8_t code[BIP32_EXTKEY_SIZE]; Encode(code); s.write((const char *)&code[0], len); } template void Unserialize(Stream &s) { unsigned int len = ::ReadCompactSize(s); uint8_t code[BIP32_EXTKEY_SIZE]; s.read((char *)&code[0], len); Decode(code); } }; /** Initialize the elliptic curve support. May not be called twice without * calling ECC_Stop first. */ void ECC_Start(void); /** Deinitialize the elliptic curve support. No-op if ECC_Start wasn't called * first. */ void ECC_Stop(void); /** Check that required EC support is available at runtime. */ bool ECC_InitSanityCheck(void); #endif // BITCOIN_KEY_H diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 0c0d0bbbb..9fb51ac4a 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -1,333 +1,333 @@ // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "pubkey.h" #include #include namespace { /* Global secp256k1_context object used for verification. */ secp256k1_context *secp256k1_context_verify = nullptr; } // namespace /** * This function is taken from the libsecp256k1 distribution and implements DER * parsing for ECDSA signatures, while supporting an arbitrary subset of format * violations. * * Supported violations include negative integers, excessive padding, garbage at * the end, and overly long length descriptors. This is safe to use in Bitcoin * because since the activation of BIP66, signatures are verified to be strict * DER before being passed to this module, and we know it supports all * violations present in the blockchain before that point. */ static int ecdsa_signature_parse_der_lax(const secp256k1_context *ctx, secp256k1_ecdsa_signature *sig, const uint8_t *input, size_t inputlen) { size_t rpos, rlen, spos, slen; size_t pos = 0; size_t lenbyte; uint8_t tmpsig[64] = {0}; int overflow = 0; /* Hack to initialize sig with a correctly-parsed but invalid signature. */ secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); /* Sequence tag byte */ if (pos == inputlen || input[pos] != 0x30) { return 0; } pos++; /* Sequence length bytes */ if (pos == inputlen) { return 0; } lenbyte = input[pos++]; if (lenbyte & 0x80) { lenbyte -= 0x80; if (pos + lenbyte > inputlen) { return 0; } pos += lenbyte; } /* Integer tag byte for R */ if (pos == inputlen || input[pos] != 0x02) { return 0; } pos++; /* Integer length for R */ if (pos == inputlen) { return 0; } lenbyte = input[pos++]; if (lenbyte & 0x80) { lenbyte -= 0x80; if (pos + lenbyte > inputlen) { return 0; } while (lenbyte > 0 && input[pos] == 0) { pos++; lenbyte--; } if (lenbyte >= sizeof(size_t)) { return 0; } rlen = 0; while (lenbyte > 0) { rlen = (rlen << 8) + input[pos]; pos++; lenbyte--; } } else { rlen = lenbyte; } if (rlen > inputlen - pos) { return 0; } rpos = pos; pos += rlen; /* Integer tag byte for S */ if (pos == inputlen || input[pos] != 0x02) { return 0; } pos++; /* Integer length for S */ if (pos == inputlen) { return 0; } lenbyte = input[pos++]; if (lenbyte & 0x80) { lenbyte -= 0x80; if (pos + lenbyte > inputlen) { return 0; } while (lenbyte > 0 && input[pos] == 0) { pos++; lenbyte--; } if (lenbyte >= sizeof(size_t)) { return 0; } slen = 0; while (lenbyte > 0) { slen = (slen << 8) + input[pos]; pos++; lenbyte--; } } else { slen = lenbyte; } if (slen > inputlen - pos) { return 0; } spos = pos; /* Ignore leading zeroes in R */ while (rlen > 0 && input[rpos] == 0) { rlen--; rpos++; } /* Copy R value */ if (rlen > 32) { overflow = 1; } else { memcpy(tmpsig + 32 - rlen, input + rpos, rlen); } /* Ignore leading zeroes in S */ while (slen > 0 && input[spos] == 0) { slen--; spos++; } /* Copy S value */ if (slen > 32) { overflow = 1; } else { memcpy(tmpsig + 64 - slen, input + spos, slen); } if (!overflow) { overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); } if (overflow) { /* Overwrite the result again with a correctly-parsed but invalid signature if parsing failed. */ memset(tmpsig, 0, 64); secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); } return 1; } -bool CPubKey::Verify(const uint256 &hash, - const std::vector &vchSig) const { +bool CPubKey::VerifyECDSA(const uint256 &hash, + const std::vector &vchSig) const { if (!IsValid()) { return false; } secp256k1_pubkey pubkey; secp256k1_ecdsa_signature sig; if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) { return false; } if (vchSig.size() == 0) { return false; } if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) { return false; } /** * libsecp256k1's ECDSA verification requires lower-S signatures, which have * not historically been enforced in Bitcoin, so normalize them first. */ secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, &sig, &sig); return secp256k1_ecdsa_verify(secp256k1_context_verify, &sig, hash.begin(), &pubkey); } bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector &vchSig) { if (vchSig.size() != 65) { return false; } int recid = (vchSig[0] - 27) & 3; bool fComp = ((vchSig[0] - 27) & 4) != 0; secp256k1_pubkey pubkey; secp256k1_ecdsa_recoverable_signature sig; if (!secp256k1_ecdsa_recoverable_signature_parse_compact( secp256k1_context_verify, &sig, &vchSig[1], recid)) { return false; } if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) { return false; } uint8_t pub[65]; size_t publen = 65; secp256k1_ec_pubkey_serialize( secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); Set(pub, pub + publen); return true; } bool CPubKey::IsFullyValid() const { if (!IsValid()) { return false; } secp256k1_pubkey pubkey; return secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size()); } bool CPubKey::Decompress() { if (!IsValid()) { return false; } secp256k1_pubkey pubkey; if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) { return false; } uint8_t pub[65]; size_t publen = 65; secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED); Set(pub, pub + publen); return true; } bool CPubKey::Derive(CPubKey &pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode &cc) const { assert(IsValid()); assert((nChild >> 31) == 0); assert(begin() + 33 == end()); uint8_t out[64]; BIP32Hash(cc, nChild, *begin(), begin() + 1, out); memcpy(ccChild.begin(), out + 32, 32); secp256k1_pubkey pubkey; if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, &(*this)[0], size())) { return false; } if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) { return false; } uint8_t pub[33]; size_t publen = 33; secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED); pubkeyChild.Set(pub, pub + publen); return true; } void CExtPubKey::Encode(uint8_t code[BIP32_EXTKEY_SIZE]) const { code[0] = nDepth; memcpy(code + 1, vchFingerprint, 4); code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF; code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF; memcpy(code + 9, chaincode.begin(), 32); assert(pubkey.size() == 33); memcpy(code + 41, pubkey.begin(), 33); } void CExtPubKey::Decode(const uint8_t code[BIP32_EXTKEY_SIZE]) { nDepth = code[0]; memcpy(vchFingerprint, code + 1, 4); nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8]; memcpy(chaincode.begin(), code + 9, 32); pubkey.Set(code + 41, code + BIP32_EXTKEY_SIZE); } bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const { out.nDepth = nDepth + 1; CKeyID id = pubkey.GetID(); memcpy(&out.vchFingerprint[0], &id, 4); out.nChild = _nChild; return pubkey.Derive(out.pubkey, out.chaincode, _nChild, chaincode); } bool CPubKey::CheckLowS( const boost::sliced_range> &vchSig) { secp256k1_ecdsa_signature sig; if (!ecdsa_signature_parse_der_lax(secp256k1_context_verify, &sig, &vchSig[0], vchSig.size())) { return false; } return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_verify, nullptr, &sig)); } /* static */ int ECCVerifyHandle::refcount = 0; ECCVerifyHandle::ECCVerifyHandle() { if (refcount == 0) { assert(secp256k1_context_verify == nullptr); secp256k1_context_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); assert(secp256k1_context_verify != nullptr); } refcount++; } ECCVerifyHandle::~ECCVerifyHandle() { refcount--; if (refcount == 0) { assert(secp256k1_context_verify != nullptr); secp256k1_context_destroy(secp256k1_context_verify); secp256k1_context_verify = nullptr; } } diff --git a/src/pubkey.h b/src/pubkey.h index 2dda62048..375b5713d 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -1,218 +1,219 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_PUBKEY_H #define BITCOIN_PUBKEY_H #include "hash.h" #include "serialize.h" #include "uint256.h" #include #include #include /** * secp256k1: * const unsigned int PRIVATE_KEY_SIZE = 279; * const unsigned int PUBLIC_KEY_SIZE = 65; * const unsigned int SIGNATURE_SIZE = 72; * * see www.keylength.com * script supports up to 75 for single byte push */ const unsigned int BIP32_EXTKEY_SIZE = 74; /** A reference to a CKey: the Hash160 of its serialized public key */ class CKeyID : public uint160 { public: CKeyID() : uint160() {} explicit CKeyID(const uint160 &in) : uint160(in) {} }; typedef uint256 ChainCode; -/** An encapsulated public key. */ +/** An encapsulated secp256k1 public key. */ class CPubKey { private: /** * Just store the serialized data. * Its length can very cheaply be computed from the first byte. */ uint8_t vch[65]; //! Compute the length of a pubkey with a given first byte. static unsigned int GetLen(uint8_t chHeader) { if (chHeader == 2 || chHeader == 3) return 33; if (chHeader == 4 || chHeader == 6 || chHeader == 7) return 65; return 0; } //! Set this key data to be invalid void Invalidate() { vch[0] = 0xFF; } public: //! Construct an invalid public key. CPubKey() { Invalidate(); } //! Initialize a public key using begin/end iterators to byte data. template void Set(const T pbegin, const T pend) { int len = pend == pbegin ? 0 : GetLen(pbegin[0]); if (len && len == (pend - pbegin)) memcpy(vch, (uint8_t *)&pbegin[0], len); else Invalidate(); } //! Construct a public key using begin/end iterators to byte data. template CPubKey(const T pbegin, const T pend) { Set(pbegin, pend); } //! Construct a public key from a byte vector. explicit CPubKey(const std::vector &_vch) { Set(_vch.begin(), _vch.end()); } //! Simple read-only vector-like interface to the pubkey data. unsigned int size() const { return GetLen(vch[0]); } const uint8_t *begin() const { return vch; } const uint8_t *end() const { return vch + size(); } const uint8_t &operator[](unsigned int pos) const { return vch[pos]; } //! Comparator implementation. friend bool operator==(const CPubKey &a, const CPubKey &b) { return a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) == 0; } friend bool operator!=(const CPubKey &a, const CPubKey &b) { return !(a == b); } friend bool operator<(const CPubKey &a, const CPubKey &b) { return a.vch[0] < b.vch[0] || (a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0); } //! Implement serialization, as if this was a byte vector. template void Serialize(Stream &s) const { unsigned int len = size(); ::WriteCompactSize(s, len); s.write((char *)vch, len); } template void Unserialize(Stream &s) { unsigned int len = ::ReadCompactSize(s); if (len <= 65) { s.read((char *)vch, len); } else { // invalid pubkey, skip available data char dummy; while (len--) s.read(&dummy, 1); Invalidate(); } } //! Get the KeyID of this public key (hash of its serialization) CKeyID GetID() const { return CKeyID(Hash160(vch, vch + size())); } //! Get the 256-bit hash of this public key. uint256 GetHash() const { return Hash(vch, vch + size()); } /* * Check syntactic correctness. * * Note that this is consensus critical as CheckSig() calls it! */ bool IsValid() const { return size() > 0; } //! fully validate whether this is a valid public key (more expensive than //! IsValid()) bool IsFullyValid() const; //! Check whether this is a compressed public key. bool IsCompressed() const { return size() == 33; } /** - * Verify a DER signature (~72 bytes). + * Verify a DER-serialized ECDSA signature (~72 bytes). * If this public key is not fully valid, the return value will be false. */ - bool Verify(const uint256 &hash, const std::vector &vchSig) const; + bool VerifyECDSA(const uint256 &hash, + const std::vector &vchSig) const; /** - * Check whether a signature is normalized (lower-S). + * Check whether a DER-serialized ECDSA signature is normalized (lower-S). */ static bool CheckLowS(const boost::sliced_range> &vchSig); static bool CheckLowS(const std::vector &vchSig) { return CheckLowS(vchSig | boost::adaptors::sliced(0, vchSig.size())); } - //! Recover a public key from a compact signature. + //! Recover a public key from a compact ECDSA signature. bool RecoverCompact(const uint256 &hash, const std::vector &vchSig); //! Turn this public key into an uncompressed public key. bool Decompress(); //! Derive BIP32 child pubkey. bool Derive(CPubKey &pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode &cc) const; }; struct CExtPubKey { uint8_t nDepth; uint8_t vchFingerprint[4]; unsigned int nChild; ChainCode chaincode; CPubKey pubkey; friend bool operator==(const CExtPubKey &a, const CExtPubKey &b) { return a.nDepth == b.nDepth && memcmp(&a.vchFingerprint[0], &b.vchFingerprint[0], sizeof(vchFingerprint)) == 0 && a.nChild == b.nChild && a.chaincode == b.chaincode && a.pubkey == b.pubkey; } void Encode(uint8_t code[BIP32_EXTKEY_SIZE]) const; void Decode(const uint8_t code[BIP32_EXTKEY_SIZE]); bool Derive(CExtPubKey &out, unsigned int nChild) const; void Serialize(CSizeComputer &s) const { // Optimized implementation for ::GetSerializeSize that avoids copying. // add one byte for the size (compact int) s.seek(BIP32_EXTKEY_SIZE + 1); } template void Serialize(Stream &s) const { unsigned int len = BIP32_EXTKEY_SIZE; ::WriteCompactSize(s, len); uint8_t code[BIP32_EXTKEY_SIZE]; Encode(code); s.write((const char *)&code[0], len); } template void Unserialize(Stream &s) { unsigned int len = ::ReadCompactSize(s); uint8_t code[BIP32_EXTKEY_SIZE]; if (len != BIP32_EXTKEY_SIZE) throw std::runtime_error("Invalid extended key size\n"); s.read((char *)&code[0], len); Decode(code); } }; /** * Users of this module must hold an ECCVerifyHandle. The constructor and * destructor of these are not allowed to run in parallel, though. */ class ECCVerifyHandle { static int refcount; public: ECCVerifyHandle(); ~ECCVerifyHandle(); }; #endif // BITCOIN_PUBKEY_H diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index a005cde5a..d8f9c3a3a 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1,1664 +1,1664 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017-2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "interpreter.h" #include "crypto/ripemd160.h" #include "crypto/sha1.h" #include "crypto/sha256.h" #include "primitives/transaction.h" #include "pubkey.h" #include "script/script.h" #include "script/script_flags.h" #include "script/sigencoding.h" #include "uint256.h" bool CastToBool(const valtype &vch) { for (size_t i = 0; i < vch.size(); i++) { if (vch[i] != 0) { // Can be negative zero if (i == vch.size() - 1 && vch[i] == 0x80) { return false; } return true; } } return false; } /** * Script is a stack machine (like Forth) that evaluates a predicate * returning a bool indicating valid or not. There are no loops. */ #define stacktop(i) (stack.at(stack.size() + (i))) #define altstacktop(i) (altstack.at(altstack.size() + (i))) static inline void popstack(std::vector &stack) { if (stack.empty()) { throw std::runtime_error("popstack(): stack empty"); } stack.pop_back(); } static void CleanupScriptCode(CScript &scriptCode, const std::vector &vchSig, uint32_t flags) { // Drop the signature in scripts when SIGHASH_FORKID is not used. SigHashType sigHashType = GetHashType(vchSig); if (!(flags & SCRIPT_ENABLE_SIGHASH_FORKID) || !sigHashType.hasForkId()) { scriptCode.FindAndDelete(CScript(vchSig)); } } static bool CheckMinimalPush(const valtype &data, opcodetype opcode) { if (data.size() == 0) { // Could have used OP_0. return opcode == OP_0; } if (data.size() == 1 && data[0] >= 1 && data[0] <= 16) { // Could have used OP_1 .. OP_16. return opcode == OP_1 + (data[0] - 1); } if (data.size() == 1 && data[0] == 0x81) { // Could have used OP_1NEGATE. return opcode == OP_1NEGATE; } if (data.size() <= 75) { // Could have used a direct push (opcode indicating number of bytes // pushed + those bytes). return opcode == data.size(); } if (data.size() <= 255) { // Could have used OP_PUSHDATA. return opcode == OP_PUSHDATA1; } if (data.size() <= 65535) { // Could have used OP_PUSHDATA2. return opcode == OP_PUSHDATA2; } return true; } static bool IsOpcodeDisabled(opcodetype opcode, uint32_t flags) { switch (opcode) { case OP_INVERT: case OP_2MUL: case OP_2DIV: case OP_MUL: case OP_LSHIFT: case OP_RSHIFT: // Disabled opcodes. return true; default: break; } return false; } bool EvalScript(std::vector &stack, const CScript &script, uint32_t flags, const BaseSignatureChecker &checker, ScriptError *serror) { static const CScriptNum bnZero(0); static const CScriptNum bnOne(1); static const valtype vchFalse(0); static const valtype vchTrue(1, 1); CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); CScript::const_iterator pbegincodehash = script.begin(); opcodetype opcode; valtype vchPushValue; std::vector vfExec; std::vector altstack; set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); if (script.size() > MAX_SCRIPT_SIZE) { return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE); } int nOpCount = 0; bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; try { while (pc < pend) { bool fExec = !count(vfExec.begin(), vfExec.end(), false); // // Read instruction // if (!script.GetOp(pc, opcode, vchPushValue)) { return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) { return set_error(serror, SCRIPT_ERR_PUSH_SIZE); } // Note how OP_RESERVED does not count towards the opcode limit. if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) { return set_error(serror, SCRIPT_ERR_OP_COUNT); } // Some opcodes are disabled. if (IsOpcodeDisabled(opcode, flags)) { return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); } if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) { if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) { return set_error(serror, SCRIPT_ERR_MINIMALDATA); } stack.push_back(vchPushValue); } else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) { switch (opcode) { // // Push value // case OP_1NEGATE: case OP_1: case OP_2: case OP_3: case OP_4: case OP_5: case OP_6: case OP_7: case OP_8: case OP_9: case OP_10: case OP_11: case OP_12: case OP_13: case OP_14: case OP_15: case OP_16: { // ( -- value) CScriptNum bn((int)opcode - (int)(OP_1 - 1)); stack.push_back(bn.getvch()); // The result of these opcodes should always be the // minimal way to push the data they push, so no need // for a CheckMinimalPush here. } break; // // Control // case OP_NOP: break; case OP_CHECKLOCKTIMEVERIFY: { if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) { // not enabled; treat as a NOP2 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { return set_error( serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); } break; } if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } // Note that elsewhere numeric opcodes are limited to // operands in the range -2**31+1 to 2**31-1, however it // is legal for opcodes to produce results exceeding // that range. This limitation is implemented by // CScriptNum's default 4-byte limit. // // If we kept to that limit we'd have a year 2038 // problem, even though the nLockTime field in // transactions themselves is uint32 which only becomes // meaningless after the year 2106. // // Thus as a special case we tell CScriptNum to accept // up to 5-byte bignums, which are good until 2**39-1, // well beyond the 2**32-1 limit of the nLockTime field // itself. const CScriptNum nLockTime(stacktop(-1), fRequireMinimal, 5); // In the rare event that the argument may be < 0 due to // some arithmetic being done first, you can always use // 0 MAX CHECKLOCKTIMEVERIFY. if (nLockTime < 0) { return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME); } // Actually compare the specified lock time with the // transaction. if (!checker.CheckLockTime(nLockTime)) { return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME); } break; } case OP_CHECKSEQUENCEVERIFY: { if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) { // not enabled; treat as a NOP3 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { return set_error( serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); } break; } if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } // nSequence, like nLockTime, is a 32-bit unsigned // integer field. See the comment in CHECKLOCKTIMEVERIFY // regarding 5-byte numeric operands. const CScriptNum nSequence(stacktop(-1), fRequireMinimal, 5); // In the rare event that the argument may be < 0 due to // some arithmetic being done first, you can always use // 0 MAX CHECKSEQUENCEVERIFY. if (nSequence < 0) { return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME); } // To provide for future soft-fork extensibility, if the // operand has the disabled lock-time flag set, // CHECKSEQUENCEVERIFY behaves as a NOP. if ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0) { break; } // Compare the specified sequence number with the input. if (!checker.CheckSequence(nSequence)) { return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME); } break; } case OP_NOP1: case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: { if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) { return set_error( serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS); } } break; case OP_IF: case OP_NOTIF: { // if [statements] [else [statements]] // endif bool fValue = false; if (fExec) { if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); } valtype &vch = stacktop(-1); if (flags & SCRIPT_VERIFY_MINIMALIF) { if (vch.size() > 1) { return set_error(serror, SCRIPT_ERR_MINIMALIF); } if (vch.size() == 1 && vch[0] != 1) { return set_error(serror, SCRIPT_ERR_MINIMALIF); } } fValue = CastToBool(vch); if (opcode == OP_NOTIF) { fValue = !fValue; } popstack(stack); } vfExec.push_back(fValue); } break; case OP_ELSE: { if (vfExec.empty()) { return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); } vfExec.back() = !vfExec.back(); } break; case OP_ENDIF: { if (vfExec.empty()) { return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); } vfExec.pop_back(); } break; case OP_VERIFY: { // (true -- ) or // (false -- false) and return if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } bool fValue = CastToBool(stacktop(-1)); if (fValue) { popstack(stack); } else { return set_error(serror, SCRIPT_ERR_VERIFY); } } break; case OP_RETURN: { return set_error(serror, SCRIPT_ERR_OP_RETURN); } break; // // Stack ops // case OP_TOALTSTACK: { if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } altstack.push_back(stacktop(-1)); popstack(stack); } break; case OP_FROMALTSTACK: { if (altstack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_ALTSTACK_OPERATION); } stack.push_back(altstacktop(-1)); popstack(altstack); } break; case OP_2DROP: { // (x1 x2 -- ) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } popstack(stack); popstack(stack); } break; case OP_2DUP: { // (x1 x2 -- x1 x2 x1 x2) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch1 = stacktop(-2); valtype vch2 = stacktop(-1); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_3DUP: { // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) if (stack.size() < 3) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch1 = stacktop(-3); valtype vch2 = stacktop(-2); valtype vch3 = stacktop(-1); stack.push_back(vch1); stack.push_back(vch2); stack.push_back(vch3); } break; case OP_2OVER: { // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) if (stack.size() < 4) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch1 = stacktop(-4); valtype vch2 = stacktop(-3); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_2ROT: { // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) if (stack.size() < 6) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch1 = stacktop(-6); valtype vch2 = stacktop(-5); stack.erase(stack.end() - 6, stack.end() - 4); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_2SWAP: { // (x1 x2 x3 x4 -- x3 x4 x1 x2) if (stack.size() < 4) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } swap(stacktop(-4), stacktop(-2)); swap(stacktop(-3), stacktop(-1)); } break; case OP_IFDUP: { // (x - 0 | x x) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch = stacktop(-1); if (CastToBool(vch)) { stack.push_back(vch); } } break; case OP_DEPTH: { // -- stacksize CScriptNum bn(stack.size()); stack.push_back(bn.getvch()); } break; case OP_DROP: { // (x -- ) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } popstack(stack); } break; case OP_DUP: { // (x -- x x) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch = stacktop(-1); stack.push_back(vch); } break; case OP_NIP: { // (x1 x2 -- x2) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } stack.erase(stack.end() - 2); } break; case OP_OVER: { // (x1 x2 -- x1 x2 x1) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch = stacktop(-2); stack.push_back(vch); } break; case OP_PICK: case OP_ROLL: { // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } int n = CScriptNum(stacktop(-1), fRequireMinimal).getint(); popstack(stack); if (n < 0 || n >= (int)stack.size()) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch = stacktop(-n - 1); if (opcode == OP_ROLL) { stack.erase(stack.end() - n - 1); } stack.push_back(vch); } break; case OP_ROT: { // (x1 x2 x3 -- x2 x3 x1) // x2 x1 x3 after first swap // x2 x3 x1 after second swap if (stack.size() < 3) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } swap(stacktop(-3), stacktop(-2)); swap(stacktop(-2), stacktop(-1)); } break; case OP_SWAP: { // (x1 x2 -- x2 x1) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } swap(stacktop(-2), stacktop(-1)); } break; case OP_TUCK: { // (x1 x2 -- x2 x1 x2) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype vch = stacktop(-1); stack.insert(stack.end() - 2, vch); } break; case OP_SIZE: { // (in -- in size) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } CScriptNum bn(stacktop(-1).size()); stack.push_back(bn.getvch()); } break; // // Bitwise logic // case OP_AND: case OP_OR: case OP_XOR: { // (x1 x2 - out) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &vch1 = stacktop(-2); valtype &vch2 = stacktop(-1); // Inputs must be the same size if (vch1.size() != vch2.size()) { return set_error(serror, SCRIPT_ERR_INVALID_OPERAND_SIZE); } // To avoid allocating, we modify vch1 in place. switch (opcode) { case OP_AND: for (size_t i = 0; i < vch1.size(); ++i) { vch1[i] &= vch2[i]; } break; case OP_OR: for (size_t i = 0; i < vch1.size(); ++i) { vch1[i] |= vch2[i]; } break; case OP_XOR: for (size_t i = 0; i < vch1.size(); ++i) { vch1[i] ^= vch2[i]; } break; default: break; } // And pop vch2. popstack(stack); } break; case OP_EQUAL: case OP_EQUALVERIFY: // case OP_NOTEQUAL: // use OP_NUMNOTEQUAL { // (x1 x2 - bool) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &vch1 = stacktop(-2); valtype &vch2 = stacktop(-1); bool fEqual = (vch1 == vch2); // OP_NOTEQUAL is disabled because it would be too // easy to say something like n != 1 and have some // wiseguy pass in 1 with extra zero bytes after it // (numerically, 0x01 == 0x0001 == 0x000001) // if (opcode == OP_NOTEQUAL) // fEqual = !fEqual; popstack(stack); popstack(stack); stack.push_back(fEqual ? vchTrue : vchFalse); if (opcode == OP_EQUALVERIFY) { if (fEqual) { popstack(stack); } else { return set_error(serror, SCRIPT_ERR_EQUALVERIFY); } } } break; // // Numeric // case OP_1ADD: case OP_1SUB: case OP_NEGATE: case OP_ABS: case OP_NOT: case OP_0NOTEQUAL: { // (in -- out) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } CScriptNum bn(stacktop(-1), fRequireMinimal); switch (opcode) { case OP_1ADD: bn += bnOne; break; case OP_1SUB: bn -= bnOne; break; case OP_NEGATE: bn = -bn; break; case OP_ABS: if (bn < bnZero) { bn = -bn; } break; case OP_NOT: bn = (bn == bnZero); break; case OP_0NOTEQUAL: bn = (bn != bnZero); break; default: assert(!"invalid opcode"); break; } popstack(stack); stack.push_back(bn.getvch()); } break; case OP_ADD: case OP_SUB: case OP_DIV: case OP_MOD: case OP_BOOLAND: case OP_BOOLOR: case OP_NUMEQUAL: case OP_NUMEQUALVERIFY: case OP_NUMNOTEQUAL: case OP_LESSTHAN: case OP_GREATERTHAN: case OP_LESSTHANOREQUAL: case OP_GREATERTHANOREQUAL: case OP_MIN: case OP_MAX: { // (x1 x2 -- out) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } CScriptNum bn1(stacktop(-2), fRequireMinimal); CScriptNum bn2(stacktop(-1), fRequireMinimal); CScriptNum bn(0); switch (opcode) { case OP_ADD: bn = bn1 + bn2; break; case OP_SUB: bn = bn1 - bn2; break; case OP_DIV: // denominator must not be 0 if (bn2 == 0) { return set_error(serror, SCRIPT_ERR_DIV_BY_ZERO); } bn = bn1 / bn2; break; case OP_MOD: // divisor must not be 0 if (bn2 == 0) { return set_error(serror, SCRIPT_ERR_MOD_BY_ZERO); } bn = bn1 % bn2; break; case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; case OP_NUMEQUAL: bn = (bn1 == bn2); break; case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; case OP_LESSTHAN: bn = (bn1 < bn2); break; case OP_GREATERTHAN: bn = (bn1 > bn2); break; case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break; case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break; default: assert(!"invalid opcode"); break; } popstack(stack); popstack(stack); stack.push_back(bn.getvch()); if (opcode == OP_NUMEQUALVERIFY) { if (CastToBool(stacktop(-1))) { popstack(stack); } else { return set_error(serror, SCRIPT_ERR_NUMEQUALVERIFY); } } } break; case OP_WITHIN: { // (x min max -- out) if (stack.size() < 3) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } CScriptNum bn1(stacktop(-3), fRequireMinimal); CScriptNum bn2(stacktop(-2), fRequireMinimal); CScriptNum bn3(stacktop(-1), fRequireMinimal); bool fValue = (bn2 <= bn1 && bn1 < bn3); popstack(stack); popstack(stack); popstack(stack); stack.push_back(fValue ? vchTrue : vchFalse); } break; // // Crypto // case OP_RIPEMD160: case OP_SHA1: case OP_SHA256: case OP_HASH160: case OP_HASH256: { // (in -- hash) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &vch = stacktop(-1); valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); if (opcode == OP_RIPEMD160) { CRIPEMD160() .Write(vch.data(), vch.size()) .Finalize(vchHash.data()); } else if (opcode == OP_SHA1) { CSHA1() .Write(vch.data(), vch.size()) .Finalize(vchHash.data()); } else if (opcode == OP_SHA256) { CSHA256() .Write(vch.data(), vch.size()) .Finalize(vchHash.data()); } else if (opcode == OP_HASH160) { CHash160() .Write(vch.data(), vch.size()) .Finalize(vchHash.data()); } else if (opcode == OP_HASH256) { CHash256() .Write(vch.data(), vch.size()) .Finalize(vchHash.data()); } popstack(stack); stack.push_back(vchHash); } break; case OP_CODESEPARATOR: { // Hash starts after the code separator pbegincodehash = pc; } break; case OP_CHECKSIG: case OP_CHECKSIGVERIFY: { // (sig pubkey -- bool) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &vchSig = stacktop(-2); valtype &vchPubKey = stacktop(-1); if (!CheckTransactionSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) { // serror is set return false; } // Subset of script starting at the most recent // codeseparator CScript scriptCode(pbegincodehash, pend); // Remove signature for pre-fork scripts CleanupScriptCode(scriptCode, vchSig, flags); bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, flags); if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size()) { return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); } popstack(stack); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKSIGVERIFY) { if (fSuccess) { popstack(stack); } else { return set_error(serror, SCRIPT_ERR_CHECKSIGVERIFY); } } } break; case OP_CHECKDATASIG: case OP_CHECKDATASIGVERIFY: { // Make sure this remains an error before activation. if ((flags & SCRIPT_ENABLE_CHECKDATASIG) == 0) { return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } // (sig message pubkey -- bool) if (stack.size() < 3) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &vchSig = stacktop(-3); valtype &vchMessage = stacktop(-2); valtype &vchPubKey = stacktop(-1); if (!CheckDataSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) { // serror is set return false; } bool fSuccess = false; if (vchSig.size()) { valtype vchHash(32); CSHA256() .Write(vchMessage.data(), vchMessage.size()) .Finalize(vchHash.data()); fSuccess = checker.VerifySignature( vchSig, CPubKey(vchPubKey), uint256(vchHash)); } if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size()) { return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); } popstack(stack); popstack(stack); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKDATASIGVERIFY) { if (fSuccess) { popstack(stack); } else { return set_error(serror, SCRIPT_ERR_CHECKDATASIGVERIFY); } } } break; case OP_CHECKMULTISIG: case OP_CHECKMULTISIGVERIFY: { // ([sig ...] num_of_signatures [pubkey ...] // num_of_pubkeys -- bool) int i = 1; if ((int)stack.size() < i) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); if (nKeysCount < 0 || nKeysCount > MAX_PUBKEYS_PER_MULTISIG) { return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT); } nOpCount += nKeysCount; if (nOpCount > MAX_OPS_PER_SCRIPT) { return set_error(serror, SCRIPT_ERR_OP_COUNT); } int ikey = ++i; // ikey2 is the position of last non-signature item in // the stack. Top stack item = 1. With // SCRIPT_VERIFY_NULLFAIL, this is used for cleanup if // operation fails. int ikey2 = nKeysCount + 2; i += nKeysCount; if ((int)stack.size() < i) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } int nSigsCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); if (nSigsCount < 0 || nSigsCount > nKeysCount) { return set_error(serror, SCRIPT_ERR_SIG_COUNT); } int isig = ++i; i += nSigsCount; if ((int)stack.size() < i) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } // Subset of script starting at the most recent // codeseparator CScript scriptCode(pbegincodehash, pend); // Remove signature for pre-fork scripts for (int k = 0; k < nSigsCount; k++) { valtype &vchSig = stacktop(-isig - k); CleanupScriptCode(scriptCode, vchSig, flags); } bool fSuccess = true; while (fSuccess && nSigsCount > 0) { valtype &vchSig = stacktop(-isig); valtype &vchPubKey = stacktop(-ikey); // Note how this makes the exact order of // pubkey/signature evaluation distinguishable by // CHECKMULTISIG NOT if the STRICTENC flag is set. // See the script_(in)valid tests for details. if (!CheckTransactionSignatureEncoding( vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) { // serror is set return false; } // Check signature bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, flags); if (fOk) { isig++; nSigsCount--; } ikey++; nKeysCount--; // If there are more signatures left than keys left, // then too many signatures have failed. Exit early, // without checking any further signatures. if (nSigsCount > nKeysCount) { fSuccess = false; } } // Clean up stack of actual arguments while (i-- > 1) { // If the operation failed, we require that all // signatures must be empty vector if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && !ikey2 && stacktop(-1).size()) { return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); } if (ikey2 > 0) { ikey2--; } popstack(stack); } // A bug causes CHECKMULTISIG to consume one extra // argument whose contents were not checked in any way. // // Unfortunately this is a potential source of // mutability, so optionally verify it is exactly equal // to zero prior to removing it from the stack. if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size()) { return set_error(serror, SCRIPT_ERR_SIG_NULLDUMMY); } popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKMULTISIGVERIFY) { if (fSuccess) { popstack(stack); } else { return set_error( serror, SCRIPT_ERR_CHECKMULTISIGVERIFY); } } } break; // // Byte string operations // case OP_CAT: { // (x1 x2 -- out) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &vch1 = stacktop(-2); valtype &vch2 = stacktop(-1); if (vch1.size() + vch2.size() > MAX_SCRIPT_ELEMENT_SIZE) { return set_error(serror, SCRIPT_ERR_PUSH_SIZE); } vch1.insert(vch1.end(), vch2.begin(), vch2.end()); popstack(stack); } break; case OP_SPLIT: { // (in position -- x1 x2) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } const valtype &data = stacktop(-2); // Make sure the split point is apropriate. uint64_t position = CScriptNum(stacktop(-1), fRequireMinimal).getint(); if (position > data.size()) { return set_error(serror, SCRIPT_ERR_INVALID_SPLIT_RANGE); } // Prepare the results in their own buffer as `data` // will be invalidated. valtype n1(data.begin(), data.begin() + position); valtype n2(data.begin() + position, data.end()); // Replace existing stack values by the new values. stacktop(-2) = std::move(n1); stacktop(-1) = std::move(n2); } break; // // Conversion operations // case OP_NUM2BIN: { // (in size -- out) if (stack.size() < 2) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } uint64_t size = CScriptNum(stacktop(-1), fRequireMinimal).getint(); if (size > MAX_SCRIPT_ELEMENT_SIZE) { return set_error(serror, SCRIPT_ERR_PUSH_SIZE); } popstack(stack); valtype &rawnum = stacktop(-1); // Try to see if we can fit that number in the number of // byte requested. CScriptNum::MinimallyEncode(rawnum); if (rawnum.size() > size) { // We definitively cannot. return set_error(serror, SCRIPT_ERR_IMPOSSIBLE_ENCODING); } // We already have an element of the right size, we // don't need to do anything. if (rawnum.size() == size) { break; } uint8_t signbit = 0x00; if (rawnum.size() > 0) { signbit = rawnum.back() & 0x80; rawnum[rawnum.size() - 1] &= 0x7f; } rawnum.reserve(size); while (rawnum.size() < size - 1) { rawnum.push_back(0x00); } rawnum.push_back(signbit); } break; case OP_BIN2NUM: { // (in -- out) if (stack.size() < 1) { return set_error( serror, SCRIPT_ERR_INVALID_STACK_OPERATION); } valtype &n = stacktop(-1); CScriptNum::MinimallyEncode(n); // The resulting number must be a valid number. if (!CScriptNum::IsMinimallyEncoded(n)) { return set_error(serror, SCRIPT_ERR_INVALID_NUMBER_RANGE); } } break; default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } } // Size limits if (stack.size() + altstack.size() > 1000) { return set_error(serror, SCRIPT_ERR_STACK_SIZE); } } } catch (...) { return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); } if (!vfExec.empty()) { return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); } return set_success(serror); } namespace { /** * Wrapper that serializes like CTransaction, but with the modifications * required for the signature hash done in-place */ class CTransactionSignatureSerializer { private: //!< reference to the spending transaction (the one being serialized) const CTransaction &txTo; //!< output script being consumed const CScript &scriptCode; //!< input index of txTo being signed const unsigned int nIn; //!< container for hashtype flags const SigHashType sigHashType; public: CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, SigHashType sigHashTypeIn) : txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn), sigHashType(sigHashTypeIn) {} /** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */ template void SerializeScriptCode(S &s) const { CScript::const_iterator it = scriptCode.begin(); CScript::const_iterator itBegin = it; opcodetype opcode; unsigned int nCodeSeparators = 0; while (scriptCode.GetOp(it, opcode)) { if (opcode == OP_CODESEPARATOR) { nCodeSeparators++; } } ::WriteCompactSize(s, scriptCode.size() - nCodeSeparators); it = itBegin; while (scriptCode.GetOp(it, opcode)) { if (opcode == OP_CODESEPARATOR) { s.write((char *)&itBegin[0], it - itBegin - 1); itBegin = it; } } if (itBegin != scriptCode.end()) { s.write((char *)&itBegin[0], it - itBegin); } } /** Serialize an input of txTo */ template void SerializeInput(S &s, unsigned int nInput) const { // In case of SIGHASH_ANYONECANPAY, only the input being signed is // serialized if (sigHashType.hasAnyoneCanPay()) { nInput = nIn; } // Serialize the prevout ::Serialize(s, txTo.vin[nInput].prevout); // Serialize the script if (nInput != nIn) { // Blank out other inputs' signatures ::Serialize(s, CScript()); } else { SerializeScriptCode(s); } // Serialize the nSequence if (nInput != nIn && (sigHashType.getBaseType() == BaseSigHashType::SINGLE || sigHashType.getBaseType() == BaseSigHashType::NONE)) { // let the others update at will ::Serialize(s, (int)0); } else { ::Serialize(s, txTo.vin[nInput].nSequence); } } /** Serialize an output of txTo */ template void SerializeOutput(S &s, unsigned int nOutput) const { if (sigHashType.getBaseType() == BaseSigHashType::SINGLE && nOutput != nIn) { // Do not lock-in the txout payee at other indices as txin ::Serialize(s, CTxOut()); } else { ::Serialize(s, txTo.vout[nOutput]); } } /** Serialize txTo */ template void Serialize(S &s) const { // Serialize nVersion ::Serialize(s, txTo.nVersion); // Serialize vin unsigned int nInputs = sigHashType.hasAnyoneCanPay() ? 1 : txTo.vin.size(); ::WriteCompactSize(s, nInputs); for (unsigned int nInput = 0; nInput < nInputs; nInput++) { SerializeInput(s, nInput); } // Serialize vout unsigned int nOutputs = (sigHashType.getBaseType() == BaseSigHashType::NONE) ? 0 : ((sigHashType.getBaseType() == BaseSigHashType::SINGLE) ? nIn + 1 : txTo.vout.size()); ::WriteCompactSize(s, nOutputs); for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++) { SerializeOutput(s, nOutput); } // Serialize nLockTime ::Serialize(s, txTo.nLockTime); } }; uint256 GetPrevoutHash(const CTransaction &txTo) { CHashWriter ss(SER_GETHASH, 0); for (size_t n = 0; n < txTo.vin.size(); n++) { ss << txTo.vin[n].prevout; } return ss.GetHash(); } uint256 GetSequenceHash(const CTransaction &txTo) { CHashWriter ss(SER_GETHASH, 0); for (size_t n = 0; n < txTo.vin.size(); n++) { ss << txTo.vin[n].nSequence; } return ss.GetHash(); } uint256 GetOutputsHash(const CTransaction &txTo) { CHashWriter ss(SER_GETHASH, 0); for (size_t n = 0; n < txTo.vout.size(); n++) { ss << txTo.vout[n]; } return ss.GetHash(); } } // namespace PrecomputedTransactionData::PrecomputedTransactionData( const CTransaction &txTo) { hashPrevouts = GetPrevoutHash(txTo); hashSequence = GetSequenceHash(txTo); hashOutputs = GetOutputsHash(txTo); } uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo, unsigned int nIn, SigHashType sigHashType, const Amount amount, const PrecomputedTransactionData *cache, uint32_t flags) { if (flags & SCRIPT_ENABLE_REPLAY_PROTECTION) { // Legacy chain's value for fork id must be of the form 0xffxxxx. // By xoring with 0xdead, we ensure that the value will be different // from the original one, even if it already starts with 0xff. uint32_t newForkValue = sigHashType.getForkValue() ^ 0xdead; sigHashType = sigHashType.withForkValue(0xff0000 | newForkValue); } if (sigHashType.hasForkId() && (flags & SCRIPT_ENABLE_SIGHASH_FORKID)) { uint256 hashPrevouts; uint256 hashSequence; uint256 hashOutputs; if (!sigHashType.hasAnyoneCanPay()) { hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo); } if (!sigHashType.hasAnyoneCanPay() && (sigHashType.getBaseType() != BaseSigHashType::SINGLE) && (sigHashType.getBaseType() != BaseSigHashType::NONE)) { hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo); } if ((sigHashType.getBaseType() != BaseSigHashType::SINGLE) && (sigHashType.getBaseType() != BaseSigHashType::NONE)) { hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo); } else if ((sigHashType.getBaseType() == BaseSigHashType::SINGLE) && (nIn < txTo.vout.size())) { CHashWriter ss(SER_GETHASH, 0); ss << txTo.vout[nIn]; hashOutputs = ss.GetHash(); } CHashWriter ss(SER_GETHASH, 0); // Version ss << txTo.nVersion; // Input prevouts/nSequence (none/all, depending on flags) ss << hashPrevouts; ss << hashSequence; // The input being signed (replacing the scriptSig with scriptCode + // amount). The prevout may already be contained in hashPrevout, and the // nSequence may already be contain in hashSequence. ss << txTo.vin[nIn].prevout; ss << scriptCode; ss << amount; ss << txTo.vin[nIn].nSequence; // Outputs (none/one/all, depending on flags) ss << hashOutputs; // Locktime ss << txTo.nLockTime; // Sighash type ss << sigHashType; return ss.GetHash(); } static const uint256 one(uint256S( "0000000000000000000000000000000000000000000000000000000000000001")); if (nIn >= txTo.vin.size()) { // nIn out of range return one; } // Check for invalid use of SIGHASH_SINGLE if ((sigHashType.getBaseType() == BaseSigHashType::SINGLE) && (nIn >= txTo.vout.size())) { // nOut out of range return one; } // Wrapper to serialize only the necessary parts of the transaction being // signed CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, sigHashType); // Serialize and hash CHashWriter ss(SER_GETHASH, 0); ss << txTmp << sigHashType; return ss.GetHash(); } bool BaseSignatureChecker::VerifySignature(const std::vector &vchSig, const CPubKey &pubkey, const uint256 &sighash) const { - return pubkey.Verify(sighash, vchSig); + return pubkey.VerifyECDSA(sighash, vchSig); } bool TransactionSignatureChecker::CheckSig( const std::vector &vchSigIn, const std::vector &vchPubKey, const CScript &scriptCode, uint32_t flags) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) { return false; } // Hash type is one byte tacked on to the end of the signature std::vector vchSig(vchSigIn); if (vchSig.empty()) { return false; } SigHashType sigHashType = GetHashType(vchSig); vchSig.pop_back(); uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, sigHashType, amount, this->txdata, flags); if (!VerifySignature(vchSig, pubkey, sighash)) { return false; } return true; } bool TransactionSignatureChecker::CheckLockTime( const CScriptNum &nLockTime) const { // There are two kinds of nLockTime: lock-by-blockheight and // lock-by-blocktime, distinguished by whether nLockTime < // LOCKTIME_THRESHOLD. // // We want to compare apples to apples, so fail the script unless the type // of nLockTime being tested is the same as the nLockTime in the // transaction. if (!((txTo->nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) || (txTo->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD))) { return false; } // Now that we know we're comparing apples-to-apples, the comparison is a // simple numeric one. if (nLockTime > int64_t(txTo->nLockTime)) { return false; } // Finally the nLockTime feature can be disabled and thus // CHECKLOCKTIMEVERIFY bypassed if every txin has been finalized by setting // nSequence to maxint. The transaction would be allowed into the // blockchain, making the opcode ineffective. // // Testing if this vin is not final is sufficient to prevent this condition. // Alternatively we could test all inputs, but testing just this input // minimizes the data required to prove correct CHECKLOCKTIMEVERIFY // execution. if (CTxIn::SEQUENCE_FINAL == txTo->vin[nIn].nSequence) { return false; } return true; } bool TransactionSignatureChecker::CheckSequence( const CScriptNum &nSequence) const { // Relative lock times are supported by comparing the passed in operand to // the sequence number of the input. const int64_t txToSequence = int64_t(txTo->vin[nIn].nSequence); // Fail if the transaction's version number is not set high enough to // trigger BIP 68 rules. if (static_cast(txTo->nVersion) < 2) { return false; } // Sequence numbers with their most significant bit set are not consensus // constrained. Testing that the transaction's sequence number do not have // this bit set prevents using this property to get around a // CHECKSEQUENCEVERIFY check. if (txToSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) { return false; } // Mask off any bits that do not have consensus-enforced meaning before // doing the integer comparisons const uint32_t nLockTimeMask = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | CTxIn::SEQUENCE_LOCKTIME_MASK; const int64_t txToSequenceMasked = txToSequence & nLockTimeMask; const CScriptNum nSequenceMasked = nSequence & nLockTimeMask; // There are two kinds of nSequence: lock-by-blockheight and // lock-by-blocktime, distinguished by whether nSequenceMasked < // CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG. // // We want to compare apples to apples, so fail the script unless the type // of nSequenceMasked being tested is the same as the nSequenceMasked in the // transaction. if (!((txToSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) || (txToSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG))) { return false; } // Now that we know we're comparing apples-to-apples, the comparison is a // simple numeric one. if (nSequenceMasked > txToSequenceMasked) { return false; } return true; } bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, uint32_t flags, const BaseSignatureChecker &checker, ScriptError *serror) { set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); // If FORKID is enabled, we also ensure strict encoding. if (flags & SCRIPT_ENABLE_SIGHASH_FORKID) { flags |= SCRIPT_VERIFY_STRICTENC; } if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) { return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); } std::vector stack, stackCopy; if (!EvalScript(stack, scriptSig, flags, checker, serror)) { // serror is set return false; } if (flags & SCRIPT_VERIFY_P2SH) { stackCopy = stack; } if (!EvalScript(stack, scriptPubKey, flags, checker, serror)) { // serror is set return false; } if (stack.empty()) { return set_error(serror, SCRIPT_ERR_EVAL_FALSE); } if (CastToBool(stack.back()) == false) { return set_error(serror, SCRIPT_ERR_EVAL_FALSE); } // Additional validation for spend-to-script-hash transactions: if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) { // scriptSig must be literals-only or validation fails if (!scriptSig.IsPushOnly()) { return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); } // Restore stack. swap(stack, stackCopy); // stack cannot be empty here, because if it was the P2SH HASH <> EQUAL // scriptPubKey would be evaluated with an empty stack and the // EvalScript above would return false. assert(!stack.empty()); const valtype &pubKeySerialized = stack.back(); CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stack); if (!EvalScript(stack, pubKey2, flags, checker, serror)) { // serror is set return false; } if (stack.empty()) { return set_error(serror, SCRIPT_ERR_EVAL_FALSE); } if (!CastToBool(stack.back())) { return set_error(serror, SCRIPT_ERR_EVAL_FALSE); } } // The CLEANSTACK check is only performed after potential P2SH evaluation, // as the non-P2SH evaluation of a P2SH script will obviously not result in // a clean stack (the P2SH inputs remain). The same holds for witness // evaluation. if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) { // Disallow CLEANSTACK without P2SH, as otherwise a switch // CLEANSTACK->P2SH+CLEANSTACK would be possible, which is not a // softfork (and P2SH should be one). assert((flags & SCRIPT_VERIFY_P2SH) != 0); if (stack.size() != 1) { return set_error(serror, SCRIPT_ERR_CLEANSTACK); } } return set_success(serror); } diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 65c16519f..ffa43f643 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -1,389 +1,389 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "script/sign.h" #include "key.h" #include "keystore.h" #include "policy/policy.h" #include "primitives/transaction.h" #include "script/standard.h" #include "uint256.h" typedef std::vector valtype; TransactionSignatureCreator::TransactionSignatureCreator( const CKeyStore *keystoreIn, const CTransaction *txToIn, unsigned int nInIn, const Amount amountIn, SigHashType sigHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), amount(amountIn), sigHashType(sigHashTypeIn), checker(txTo, nIn, amountIn) {} bool TransactionSignatureCreator::CreateSig(std::vector &vchSig, const CKeyID &address, const CScript &scriptCode) const { CKey key; if (!keystore->GetKey(address, key)) { return false; } uint256 hash = SignatureHash(scriptCode, *txTo, nIn, sigHashType, amount); - if (!key.Sign(hash, vchSig)) { + if (!key.SignECDSA(hash, vchSig)) { return false; } vchSig.push_back(uint8_t(sigHashType.getRawSigHashType())); return true; } static bool Sign1(const CKeyID &address, const BaseSignatureCreator &creator, const CScript &scriptCode, std::vector &ret) { std::vector vchSig; if (!creator.CreateSig(vchSig, address, scriptCode)) { return false; } ret.push_back(vchSig); return true; } static bool SignN(const std::vector &multisigdata, const BaseSignatureCreator &creator, const CScript &scriptCode, std::vector &ret) { int nSigned = 0; int nRequired = multisigdata.front()[0]; for (size_t i = 1; i < multisigdata.size() - 1 && nSigned < nRequired; i++) { const valtype &pubkey = multisigdata[i]; CKeyID keyID = CPubKey(pubkey).GetID(); if (Sign1(keyID, creator, scriptCode, ret)) { ++nSigned; } } return nSigned == nRequired; } /** * Sign scriptPubKey using signature made with creator. * Signatures are returned in scriptSigRet (or returns false if scriptPubKey * can't be signed), unless whichTypeRet is TX_SCRIPTHASH, in which case * scriptSigRet is the redemption script. * Returns false if scriptPubKey could not be completely satisfied. */ static bool SignStep(const BaseSignatureCreator &creator, const CScript &scriptPubKey, std::vector &ret, txnouttype &whichTypeRet) { CScript scriptRet; uint160 h160; ret.clear(); std::vector vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) { return false; } CKeyID keyID; switch (whichTypeRet) { case TX_NONSTANDARD: case TX_NULL_DATA: return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); return Sign1(keyID, creator, scriptPubKey, ret); case TX_PUBKEYHASH: { keyID = CKeyID(uint160(vSolutions[0])); if (!Sign1(keyID, creator, scriptPubKey, ret)) { return false; } CPubKey vch; creator.KeyStore().GetPubKey(keyID, vch); ret.push_back(ToByteVector(vch)); return true; } case TX_SCRIPTHASH: if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) { ret.push_back( std::vector(scriptRet.begin(), scriptRet.end())); return true; } return false; case TX_MULTISIG: // workaround CHECKMULTISIG bug ret.push_back(valtype()); return (SignN(vSolutions, creator, scriptPubKey, ret)); default: return false; } } static CScript PushAll(const std::vector &values) { CScript result; for (const valtype &v : values) { if (v.size() == 0) { result << OP_0; } else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) { result << CScript::EncodeOP_N(v[0]); } else { result << v; } } return result; } bool ProduceSignature(const BaseSignatureCreator &creator, const CScript &fromPubKey, SignatureData &sigdata) { CScript script = fromPubKey; bool solved = true; std::vector result; txnouttype whichType; solved = SignStep(creator, script, result, whichType); CScript subscript; if (solved && whichType == TX_SCRIPTHASH) { // Solver returns the subscript that needs to be evaluated; the final // scriptSig is the signatures from that and then the serialized // subscript: script = subscript = CScript(result[0].begin(), result[0].end()); solved = solved && SignStep(creator, script, result, whichType) && whichType != TX_SCRIPTHASH; result.push_back( std::vector(subscript.begin(), subscript.end())); } sigdata.scriptSig = PushAll(result); // Test solution return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); } SignatureData DataFromTransaction(const CMutableTransaction &tx, unsigned int nIn) { SignatureData data; assert(tx.vin.size() > nIn); data.scriptSig = tx.vin[nIn].scriptSig; return data; } void UpdateTransaction(CMutableTransaction &tx, unsigned int nIn, const SignatureData &data) { assert(tx.vin.size() > nIn); tx.vin[nIn].scriptSig = data.scriptSig; } bool SignSignature(const CKeyStore &keystore, const CScript &fromPubKey, CMutableTransaction &txTo, unsigned int nIn, const Amount amount, SigHashType sigHashType) { assert(nIn < txTo.vin.size()); CTransaction txToConst(txTo); TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, sigHashType); SignatureData sigdata; bool ret = ProduceSignature(creator, fromPubKey, sigdata); UpdateTransaction(txTo, nIn, sigdata); return ret; } bool SignSignature(const CKeyStore &keystore, const CTransaction &txFrom, CMutableTransaction &txTo, unsigned int nIn, SigHashType sigHashType) { assert(nIn < txTo.vin.size()); CTxIn &txin = txTo.vin[nIn]; assert(txin.prevout.GetN() < txFrom.vout.size()); const CTxOut &txout = txFrom.vout[txin.prevout.GetN()]; return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, sigHashType); } static std::vector CombineMultisig( const CScript &scriptPubKey, const BaseSignatureChecker &checker, const std::vector &vSolutions, const std::vector &sigs1, const std::vector &sigs2) { // Combine all the signatures we've got: std::set allsigs; for (const valtype &v : sigs1) { if (!v.empty()) { allsigs.insert(v); } } for (const valtype &v : sigs2) { if (!v.empty()) { allsigs.insert(v); } } // Build a map of pubkey -> signature by matching sigs to pubkeys: assert(vSolutions.size() > 1); unsigned int nSigsRequired = vSolutions.front()[0]; unsigned int nPubKeys = vSolutions.size() - 2; std::map sigs; for (const valtype &sig : allsigs) { for (unsigned int i = 0; i < nPubKeys; i++) { const valtype &pubkey = vSolutions[i + 1]; // Already got a sig for this pubkey if (sigs.count(pubkey)) { continue; } if (checker.CheckSig(sig, pubkey, scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS)) { sigs[pubkey] = sig; break; } } } // Now build a merged CScript: unsigned int nSigsHave = 0; // pop-one-too-many workaround std::vector result; result.push_back(valtype()); for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++) { if (sigs.count(vSolutions[i + 1])) { result.push_back(sigs[vSolutions[i + 1]]); ++nSigsHave; } } // Fill any missing with OP_0: for (unsigned int i = nSigsHave; i < nSigsRequired; i++) { result.push_back(valtype()); } return result; } namespace { struct Stacks { std::vector script; Stacks() {} explicit Stacks(const std::vector &scriptSigStack_) : script(scriptSigStack_) {} explicit Stacks(const SignatureData &data) { EvalScript(script, data.scriptSig, MANDATORY_SCRIPT_VERIFY_FLAGS, BaseSignatureChecker()); } SignatureData Output() const { SignatureData result; result.scriptSig = PushAll(script); return result; } }; } // namespace static Stacks CombineSignatures(const CScript &scriptPubKey, const BaseSignatureChecker &checker, const txnouttype txType, const std::vector &vSolutions, Stacks sigs1, Stacks sigs2) { switch (txType) { case TX_NONSTANDARD: case TX_NULL_DATA: // Don't know anything about this, assume bigger one is correct: if (sigs1.script.size() >= sigs2.script.size()) { return sigs1; } return sigs2; case TX_PUBKEY: case TX_PUBKEYHASH: // Signatures are bigger than placeholders or empty scripts: if (sigs1.script.empty() || sigs1.script[0].empty()) { return sigs2; } return sigs1; case TX_SCRIPTHASH: { if (sigs1.script.empty() || sigs1.script.back().empty()) { return sigs2; } if (sigs2.script.empty() || sigs2.script.back().empty()) { return sigs1; } // Recur to combine: valtype spk = sigs1.script.back(); CScript pubKey2(spk.begin(), spk.end()); txnouttype txType2; std::vector> vSolutions2; Solver(pubKey2, txType2, vSolutions2); sigs1.script.pop_back(); sigs2.script.pop_back(); Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2); result.script.push_back(spk); return result; } case TX_MULTISIG: return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script)); default: return Stacks(); } } SignatureData CombineSignatures(const CScript &scriptPubKey, const BaseSignatureChecker &checker, const SignatureData &scriptSig1, const SignatureData &scriptSig2) { txnouttype txType; std::vector> vSolutions; Solver(scriptPubKey, txType, vSolutions); return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2)) .Output(); } namespace { /** Dummy signature checker which accepts all signatures. */ class DummySignatureChecker : public BaseSignatureChecker { public: DummySignatureChecker() {} bool CheckSig(const std::vector &scriptSig, const std::vector &vchPubKey, const CScript &scriptCode, uint32_t flags) const override { return true; } }; const DummySignatureChecker dummyChecker; } // namespace const BaseSignatureChecker &DummySignatureCreator::Checker() const { return dummyChecker; } bool DummySignatureCreator::CreateSig(std::vector &vchSig, const CKeyID &keyid, const CScript &scriptCode) const { // Create a dummy signature that is a valid DER-encoding vchSig.assign(72, '\000'); vchSig[0] = 0x30; vchSig[1] = 69; vchSig[2] = 0x02; vchSig[3] = 33; vchSig[4] = 0x01; vchSig[4 + 33] = 0x02; vchSig[5 + 33] = 32; vchSig[6 + 33] = 0x01; vchSig[6 + 33 + 32] = SIGHASH_ALL | SIGHASH_FORKID; return true; } diff --git a/src/test/checkdatasig_tests.cpp b/src/test/checkdatasig_tests.cpp index e5ff698b4..de99d084e 100644 --- a/src/test/checkdatasig_tests.cpp +++ b/src/test/checkdatasig_tests.cpp @@ -1,224 +1,224 @@ // Copyright (c) 2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "test/test_bitcoin.h" #include "policy/policy.h" #include "script/interpreter.h" #include #include typedef std::vector valtype; typedef std::vector stacktype; BOOST_FIXTURE_TEST_SUITE(checkdatasig_tests, BasicTestingSetup) std::array flagset{ {0, STANDARD_SCRIPT_VERIFY_FLAGS, MANDATORY_SCRIPT_VERIFY_FLAGS}}; const uint8_t vchPrivkey[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}; struct KeyData { CKey privkey, privkeyC; CPubKey pubkey, pubkeyC, pubkeyH; KeyData() { privkey.Set(vchPrivkey, vchPrivkey + 32, false); privkeyC.Set(vchPrivkey, vchPrivkey + 32, true); pubkey = privkey.GetPubKey(); pubkeyH = privkey.GetPubKey(); pubkeyC = privkeyC.GetPubKey(); *const_cast(&pubkeyH[0]) = 0x06 | (pubkeyH[64] & 1); } }; static void CheckError(uint32_t flags, const stacktype &original_stack, const CScript &script, ScriptError expected) { BaseSignatureChecker sigchecker; ScriptError err = SCRIPT_ERR_OK; stacktype stack{original_stack}; bool r = EvalScript(stack, script, flags, sigchecker, &err); BOOST_CHECK(!r); BOOST_CHECK_EQUAL(err, expected); } static void CheckPass(uint32_t flags, const stacktype &original_stack, const CScript &script, const stacktype &expected) { BaseSignatureChecker sigchecker; ScriptError err = SCRIPT_ERR_OK; stacktype stack{original_stack}; bool r = EvalScript(stack, script, flags, sigchecker, &err); BOOST_CHECK(r); BOOST_CHECK_EQUAL(err, SCRIPT_ERR_OK); BOOST_CHECK(stack == expected); } /** * General utility functions to check for script passing/failing. */ static void CheckTestResultForAllFlags(const stacktype &original_stack, const CScript &script, const stacktype &expected) { for (uint32_t flags : flagset) { // Make sure that we get a bad opcode when the activation flag is not // passed. CheckError(flags, original_stack, script, SCRIPT_ERR_BAD_OPCODE); // The script execute as expected if the opcodes are activated. CheckPass(flags | SCRIPT_ENABLE_CHECKDATASIG, original_stack, script, expected); } } static void CheckErrorForAllFlags(const stacktype &original_stack, const CScript &script, ScriptError expected) { for (uint32_t flags : flagset) { // Make sure that we get a bad opcode when the activation flag is not // passed. CheckError(flags, original_stack, script, SCRIPT_ERR_BAD_OPCODE); // The script generates the proper error if the opcodes are activated. CheckError(flags | SCRIPT_ENABLE_CHECKDATASIG, original_stack, script, expected); } } BOOST_AUTO_TEST_CASE(checkdatasig_test) { // Empty stack. CheckErrorForAllFlags({}, CScript() << OP_CHECKDATASIG, SCRIPT_ERR_INVALID_STACK_OPERATION); CheckErrorForAllFlags({{0x00}}, CScript() << OP_CHECKDATASIG, SCRIPT_ERR_INVALID_STACK_OPERATION); CheckErrorForAllFlags({{0x00}, {0x00}}, CScript() << OP_CHECKDATASIG, SCRIPT_ERR_INVALID_STACK_OPERATION); CheckErrorForAllFlags({}, CScript() << OP_CHECKDATASIGVERIFY, SCRIPT_ERR_INVALID_STACK_OPERATION); CheckErrorForAllFlags({{0x00}}, CScript() << OP_CHECKDATASIGVERIFY, SCRIPT_ERR_INVALID_STACK_OPERATION); CheckErrorForAllFlags({{0x00}, {0x00}}, CScript() << OP_CHECKDATASIGVERIFY, SCRIPT_ERR_INVALID_STACK_OPERATION); // Check various pubkey encoding. const valtype message{}; valtype vchHash(32); CSHA256().Write(message.data(), message.size()).Finalize(vchHash.data()); uint256 messageHash(vchHash); KeyData kd; valtype pubkey = ToByteVector(kd.pubkey); valtype pubkeyC = ToByteVector(kd.pubkeyC); valtype pubkeyH = ToByteVector(kd.pubkeyH); CheckTestResultForAllFlags({{}, message, pubkey}, CScript() << OP_CHECKDATASIG, {{}}); CheckTestResultForAllFlags({{}, message, pubkeyC}, CScript() << OP_CHECKDATASIG, {{}}); CheckErrorForAllFlags({{}, message, pubkey}, CScript() << OP_CHECKDATASIGVERIFY, SCRIPT_ERR_CHECKDATASIGVERIFY); CheckErrorForAllFlags({{}, message, pubkeyC}, CScript() << OP_CHECKDATASIGVERIFY, SCRIPT_ERR_CHECKDATASIGVERIFY); // Flags dependent checks. const CScript script = CScript() << OP_CHECKDATASIG << OP_NOT << OP_VERIFY; const CScript scriptverify = CScript() << OP_CHECKDATASIGVERIFY; // Check valid signatures (as in the signature format is valid). valtype validsig; - kd.privkey.Sign(messageHash, validsig); + kd.privkey.SignECDSA(messageHash, validsig); CheckTestResultForAllFlags({validsig, message, pubkey}, CScript() << OP_CHECKDATASIG, {{0x01}}); CheckTestResultForAllFlags({validsig, message, pubkey}, CScript() << OP_CHECKDATASIGVERIFY, {}); const valtype minimalsig{0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; const valtype nondersig{0x30, 0x80, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; const valtype highSSig{ 0x30, 0x45, 0x02, 0x20, 0x3e, 0x45, 0x16, 0xda, 0x72, 0x53, 0xcf, 0x06, 0x8e, 0xff, 0xec, 0x6b, 0x95, 0xc4, 0x12, 0x21, 0xc0, 0xcf, 0x3a, 0x8e, 0x6c, 0xcb, 0x8c, 0xbf, 0x17, 0x25, 0xb5, 0x62, 0xe9, 0xaf, 0xde, 0x2c, 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0}; // If we add many more flags, this loop can get too expensive, but we can // rewrite in the future to randomly pick a set of flags to evaluate. for (uint32_t flags = 0; flags < (1U << 18); flags++) { // Make sure we activate the opcodes. flags |= SCRIPT_ENABLE_CHECKDATASIG; if (flags & SCRIPT_VERIFY_STRICTENC) { // When strict encoding is enforced, hybrid key are invalid. CheckError(flags, {{}, message, pubkeyH}, script, SCRIPT_ERR_PUBKEYTYPE); CheckError(flags, {{}, message, pubkeyH}, scriptverify, SCRIPT_ERR_PUBKEYTYPE); } else { // When strict encoding is not enforced, hybrid key are valid. CheckPass(flags, {{}, message, pubkeyH}, script, {}); CheckError(flags, {{}, message, pubkeyH}, scriptverify, SCRIPT_ERR_CHECKDATASIGVERIFY); } if (flags & SCRIPT_VERIFY_NULLFAIL) { // When strict encoding is enforced, hybrid key are invalid. CheckError(flags, {minimalsig, message, pubkey}, script, SCRIPT_ERR_SIG_NULLFAIL); CheckError(flags, {minimalsig, message, pubkey}, scriptverify, SCRIPT_ERR_SIG_NULLFAIL); // Invalid message cause checkdatasig to fail. CheckError(flags, {validsig, {0x01}, pubkey}, script, SCRIPT_ERR_SIG_NULLFAIL); CheckError(flags, {validsig, {0x01}, pubkey}, scriptverify, SCRIPT_ERR_SIG_NULLFAIL); } else { // When nullfail is not enforced, invalid signature are just false. CheckPass(flags, {minimalsig, message, pubkey}, script, {}); CheckError(flags, {minimalsig, message, pubkey}, scriptverify, SCRIPT_ERR_CHECKDATASIGVERIFY); // Invalid message cause checkdatasig to fail. CheckPass(flags, {validsig, {0x01}, pubkey}, script, {}); CheckError(flags, {validsig, {0x01}, pubkey}, scriptverify, SCRIPT_ERR_CHECKDATASIGVERIFY); } if (flags & SCRIPT_VERIFY_LOW_S) { // If we do enforce low S, then high S sigs are rejected. CheckError(flags, {highSSig, message, pubkey}, script, SCRIPT_ERR_SIG_HIGH_S); CheckError(flags, {highSSig, message, pubkey}, scriptverify, SCRIPT_ERR_SIG_HIGH_S); } else { // If we do not enforce low S, then high S sigs are accepted. CheckPass(flags, {highSSig, message, pubkey}, script, {}); CheckError(flags, {highSSig, message, pubkey}, scriptverify, SCRIPT_ERR_CHECKDATASIGVERIFY); } if (flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) { // If we get any of the dersig flags, the non canonical dersig // signature fails. CheckError(flags, {nondersig, message, pubkey}, script, SCRIPT_ERR_SIG_DER); CheckError(flags, {nondersig, message, pubkey}, scriptverify, SCRIPT_ERR_SIG_DER); } else { // If we do not check, then it is accepted. CheckPass(flags, {nondersig, message, pubkey}, script, {}); CheckError(flags, {nondersig, message, pubkey}, scriptverify, SCRIPT_ERR_CHECKDATASIGVERIFY); } } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index cb5ba46b7..a8308f0d8 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -1,185 +1,185 @@ // Copyright (c) 2012-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "key.h" #include "base58.h" #include "dstencode.h" #include "script/script.h" #include "test/test_bitcoin.h" #include "uint256.h" #include "util.h" #include "utilstrencodings.h" #include #include #include static const std::string strSecret1 = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"; static const std::string strSecret2 = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"; static const std::string strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"; static const std::string strSecret2C = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g"; static const std::string addr1 = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ"; static const std::string addr2 = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ"; static const std::string addr1C = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs"; static const std::string addr2C = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"; static const std::string strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"; BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(key_test1) { CBitcoinSecret bsecret1, bsecret2, bsecret1C, bsecret2C, baddress1; BOOST_CHECK(bsecret1.SetString(strSecret1)); BOOST_CHECK(bsecret2.SetString(strSecret2)); BOOST_CHECK(bsecret1C.SetString(strSecret1C)); BOOST_CHECK(bsecret2C.SetString(strSecret2C)); BOOST_CHECK(!baddress1.SetString(strAddressBad)); CKey key1 = bsecret1.GetKey(); BOOST_CHECK(key1.IsCompressed() == false); CKey key2 = bsecret2.GetKey(); BOOST_CHECK(key2.IsCompressed() == false); CKey key1C = bsecret1C.GetKey(); BOOST_CHECK(key1C.IsCompressed() == true); CKey key2C = bsecret2C.GetKey(); BOOST_CHECK(key2C.IsCompressed() == true); CPubKey pubkey1 = key1.GetPubKey(); CPubKey pubkey2 = key2.GetPubKey(); CPubKey pubkey1C = key1C.GetPubKey(); CPubKey pubkey2C = key2C.GetPubKey(); BOOST_CHECK(key1.VerifyPubKey(pubkey1)); BOOST_CHECK(!key1.VerifyPubKey(pubkey1C)); BOOST_CHECK(!key1.VerifyPubKey(pubkey2)); BOOST_CHECK(!key1.VerifyPubKey(pubkey2C)); BOOST_CHECK(!key1C.VerifyPubKey(pubkey1)); BOOST_CHECK(key1C.VerifyPubKey(pubkey1C)); BOOST_CHECK(!key1C.VerifyPubKey(pubkey2)); BOOST_CHECK(!key1C.VerifyPubKey(pubkey2C)); BOOST_CHECK(!key2.VerifyPubKey(pubkey1)); BOOST_CHECK(!key2.VerifyPubKey(pubkey1C)); BOOST_CHECK(key2.VerifyPubKey(pubkey2)); BOOST_CHECK(!key2.VerifyPubKey(pubkey2C)); BOOST_CHECK(!key2C.VerifyPubKey(pubkey1)); BOOST_CHECK(!key2C.VerifyPubKey(pubkey1C)); BOOST_CHECK(!key2C.VerifyPubKey(pubkey2)); BOOST_CHECK(key2C.VerifyPubKey(pubkey2C)); const CChainParams &chainParams = Params(); BOOST_CHECK(DecodeDestination(addr1, chainParams) == CTxDestination(pubkey1.GetID())); BOOST_CHECK(DecodeDestination(addr2, chainParams) == CTxDestination(pubkey2.GetID())); BOOST_CHECK(DecodeDestination(addr1C, chainParams) == CTxDestination(pubkey1C.GetID())); BOOST_CHECK(DecodeDestination(addr2C, chainParams) == CTxDestination(pubkey2C.GetID())); for (int n = 0; n < 16; n++) { std::string strMsg = strprintf("Very secret message %i: 11", n); uint256 hashMsg = Hash(strMsg.begin(), strMsg.end()); // normal signatures std::vector sign1, sign2, sign1C, sign2C; - BOOST_CHECK(key1.Sign(hashMsg, sign1)); - BOOST_CHECK(key2.Sign(hashMsg, sign2)); - BOOST_CHECK(key1C.Sign(hashMsg, sign1C)); - BOOST_CHECK(key2C.Sign(hashMsg, sign2C)); - - BOOST_CHECK(pubkey1.Verify(hashMsg, sign1)); - BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2)); - BOOST_CHECK(pubkey1.Verify(hashMsg, sign1C)); - BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C)); - - BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1)); - BOOST_CHECK(pubkey2.Verify(hashMsg, sign2)); - BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C)); - BOOST_CHECK(pubkey2.Verify(hashMsg, sign2C)); - - BOOST_CHECK(pubkey1C.Verify(hashMsg, sign1)); - BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2)); - BOOST_CHECK(pubkey1C.Verify(hashMsg, sign1C)); - BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C)); - - BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1)); - BOOST_CHECK(pubkey2C.Verify(hashMsg, sign2)); - BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C)); - BOOST_CHECK(pubkey2C.Verify(hashMsg, sign2C)); + BOOST_CHECK(key1.SignECDSA(hashMsg, sign1)); + BOOST_CHECK(key2.SignECDSA(hashMsg, sign2)); + BOOST_CHECK(key1C.SignECDSA(hashMsg, sign1C)); + BOOST_CHECK(key2C.SignECDSA(hashMsg, sign2C)); + + BOOST_CHECK(pubkey1.VerifyECDSA(hashMsg, sign1)); + BOOST_CHECK(!pubkey1.VerifyECDSA(hashMsg, sign2)); + BOOST_CHECK(pubkey1.VerifyECDSA(hashMsg, sign1C)); + BOOST_CHECK(!pubkey1.VerifyECDSA(hashMsg, sign2C)); + + BOOST_CHECK(!pubkey2.VerifyECDSA(hashMsg, sign1)); + BOOST_CHECK(pubkey2.VerifyECDSA(hashMsg, sign2)); + BOOST_CHECK(!pubkey2.VerifyECDSA(hashMsg, sign1C)); + BOOST_CHECK(pubkey2.VerifyECDSA(hashMsg, sign2C)); + + BOOST_CHECK(pubkey1C.VerifyECDSA(hashMsg, sign1)); + BOOST_CHECK(!pubkey1C.VerifyECDSA(hashMsg, sign2)); + BOOST_CHECK(pubkey1C.VerifyECDSA(hashMsg, sign1C)); + BOOST_CHECK(!pubkey1C.VerifyECDSA(hashMsg, sign2C)); + + BOOST_CHECK(!pubkey2C.VerifyECDSA(hashMsg, sign1)); + BOOST_CHECK(pubkey2C.VerifyECDSA(hashMsg, sign2)); + BOOST_CHECK(!pubkey2C.VerifyECDSA(hashMsg, sign1C)); + BOOST_CHECK(pubkey2C.VerifyECDSA(hashMsg, sign2C)); // compact signatures (with key recovery) std::vector csign1, csign2, csign1C, csign2C; BOOST_CHECK(key1.SignCompact(hashMsg, csign1)); BOOST_CHECK(key2.SignCompact(hashMsg, csign2)); BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C)); BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C)); CPubKey rkey1, rkey2, rkey1C, rkey2C; BOOST_CHECK(rkey1.RecoverCompact(hashMsg, csign1)); BOOST_CHECK(rkey2.RecoverCompact(hashMsg, csign2)); BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C)); BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C)); BOOST_CHECK(rkey1 == pubkey1); BOOST_CHECK(rkey2 == pubkey2); BOOST_CHECK(rkey1C == pubkey1C); BOOST_CHECK(rkey2C == pubkey2C); } // test deterministic signing std::vector detsig, detsigc; std::string strMsg = "Very deterministic message"; uint256 hashMsg = Hash(strMsg.begin(), strMsg.end()); - BOOST_CHECK(key1.Sign(hashMsg, detsig)); - BOOST_CHECK(key1C.Sign(hashMsg, detsigc)); + BOOST_CHECK(key1.SignECDSA(hashMsg, detsig)); + BOOST_CHECK(key1C.SignECDSA(hashMsg, detsigc)); BOOST_CHECK(detsig == detsigc); BOOST_CHECK(detsig == ParseHex("3045022100c6ab5f8acfccc114da39dd5ad0b1ef4d39df6a721e8" "24c22e00b7bc7944a1f7802206ff23df3802e241ee234a8b66c40" "c82e56a6cc37f9b50463111c9f9229b8f3b3")); - BOOST_CHECK(key2.Sign(hashMsg, detsig)); - BOOST_CHECK(key2C.Sign(hashMsg, detsigc)); + BOOST_CHECK(key2.SignECDSA(hashMsg, detsig)); + BOOST_CHECK(key2C.SignECDSA(hashMsg, detsigc)); BOOST_CHECK(detsig == detsigc); BOOST_CHECK(detsig == ParseHex("304502210094dc5a77b8d5db6b42b66c29d7033cd873fac7a1272" "4a90373726f60bb9f852a02204eb4c98b9a2f5c017f9417ba7c43" "279c20c84bb058dc05b3beeb9333016b15bb")); BOOST_CHECK(key1.SignCompact(hashMsg, detsig)); BOOST_CHECK(key1C.SignCompact(hashMsg, detsigc)); BOOST_CHECK(detsig == ParseHex("1b8c56f224d51415e6ce329144aa1e1c1563e297a005f450df015" "14f3d047681760277e79d57502df27b8feebb001a588aa3a8c2bc" "f5b2367273c15f840638cfc8")); BOOST_CHECK(detsigc == ParseHex("1f8c56f224d51415e6ce329144aa1e1c1563e297a005f450df015" "14f3d047681760277e79d57502df27b8feebb001a588aa3a8c2bc" "f5b2367273c15f840638cfc8")); BOOST_CHECK(key2.SignCompact(hashMsg, detsig)); BOOST_CHECK(key2C.SignCompact(hashMsg, detsigc)); BOOST_CHECK(detsig == ParseHex("1c9ffc56b38fbfc0e3eb2c42dff99d2375982449f35019c1b3d56" "ca62bef187c5103e483a0ad481eaacc224fef4ee2995027300d5f" "2457f7a20c43547aeddbae6e")); BOOST_CHECK(detsigc == ParseHex("209ffc56b38fbfc0e3eb2c42dff99d2375982449f35019c1b3d56" "ca62bef187c5103e483a0ad481eaacc224fef4ee2995027300d5f" "2457f7a20c43547aeddbae6e")); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 11a3bcd51..6157760eb 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -1,360 +1,360 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "key.h" #include "keystore.h" #include "policy/policy.h" #include "script/interpreter.h" #include "script/ismine.h" #include "script/script.h" #include "script/script_error.h" #include "script/sighashtype.h" #include "script/sign.h" #include "test/test_bitcoin.h" #include "uint256.h" #include typedef std::vector valtype; BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup) CScript sign_multisig(CScript scriptPubKey, std::vector keys, CMutableTransaction mutableTransaction, int whichIn) { uint256 hash = SignatureHash(scriptPubKey, CTransaction(mutableTransaction), whichIn, SigHashType(), Amount::zero()); CScript result; // CHECKMULTISIG bug workaround result << OP_0; for (const CKey &key : keys) { std::vector vchSig; - BOOST_CHECK(key.Sign(hash, vchSig)); + BOOST_CHECK(key.SignECDSA(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL)); result << vchSig; } return result; } BOOST_AUTO_TEST_CASE(multisig_verify) { uint32_t flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; ScriptError err; CKey key[4]; Amount amount = Amount::zero(); for (int i = 0; i < 4; i++) { key[i].MakeNewKey(true); } CScript a_and_b; a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; CScript a_or_b; a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; CScript escrow; escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; // Funding transaction CMutableTransaction txFrom; txFrom.vout.resize(3); txFrom.vout[0].scriptPubKey = a_and_b; txFrom.vout[1].scriptPubKey = a_or_b; txFrom.vout[2].scriptPubKey = escrow; // Spending transaction CMutableTransaction txTo[3]; for (int i = 0; i < 3; i++) { txTo[i].vin.resize(1); txTo[i].vout.resize(1); txTo[i].vin[0].prevout = COutPoint(txFrom.GetId(), i); txTo[i].vout[0].nValue = SATOSHI; } std::vector keys; CScript s; // Test a AND b: keys.assign(1, key[0]); keys.push_back(key[1]); s = sign_multisig(a_and_b, keys, txTo[0], 0); BOOST_CHECK(VerifyScript( s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); for (int i = 0; i < 4; i++) { keys.assign(1, key[i]); s = sign_multisig(a_and_b, keys, txTo[0], 0); BOOST_CHECK_MESSAGE( !VerifyScript( s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 1: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); keys.assign(1, key[1]); keys.push_back(key[i]); s = sign_multisig(a_and_b, keys, txTo[0], 0); BOOST_CHECK_MESSAGE( !VerifyScript( s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 2: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } // Test a OR b: for (int i = 0; i < 4; i++) { keys.assign(1, key[i]); s = sign_multisig(a_or_b, keys, txTo[1], 0); if (i == 0 || i == 1) { BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker( &txTo[1], 0, amount), &err), strprintf("a|b: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } else { BOOST_CHECK_MESSAGE( !VerifyScript( s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } } s.clear(); s << OP_0 << OP_1; BOOST_CHECK(!VerifyScript( s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err)); for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) { keys.assign(1, key[i]); keys.push_back(key[j]); s = sign_multisig(escrow, keys, txTo[2], 0); if (i < j && i < 3 && j < 3) { BOOST_CHECK_MESSAGE( VerifyScript( s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 1: %d %d", i, j)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } else { BOOST_CHECK_MESSAGE( !VerifyScript( s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 2: %d %d", i, j)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } } } BOOST_AUTO_TEST_CASE(multisig_IsStandard) { CKey key[4]; for (int i = 0; i < 4; i++) key[i].MakeNewKey(true); txnouttype whichType; CScript a_and_b; a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(::IsStandard(a_and_b, whichType)); CScript a_or_b; a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(::IsStandard(a_or_b, whichType)); CScript escrow; escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; BOOST_CHECK(::IsStandard(escrow, whichType)); CScript one_of_four; one_of_four << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << ToByteVector(key[3].GetPubKey()) << OP_4 << OP_CHECKMULTISIG; BOOST_CHECK(!::IsStandard(one_of_four, whichType)); CScript malformed[6]; malformed[0] << OP_3 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; malformed[1] << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; malformed[2] << OP_0 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; malformed[3] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_0 << OP_CHECKMULTISIG; malformed[4] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_CHECKMULTISIG; malformed[5] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()); for (int i = 0; i < 6; i++) BOOST_CHECK(!::IsStandard(malformed[i], whichType)); } BOOST_AUTO_TEST_CASE(multisig_Solver1) { // Tests Solver() that returns lists of keys that are required to satisfy a // ScriptPubKey // // Also tests IsMine() and ExtractDestination() // // Note: ExtractDestination for the multisignature transactions always // returns false for this release, even if you have one key that would // satisfy an (a|b) or 2-of-3 keys needed to spend an escrow transaction. // CBasicKeyStore keystore, emptykeystore, partialkeystore; CKey key[3]; CTxDestination keyaddr[3]; for (int i = 0; i < 3; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); keyaddr[i] = key[i].GetPubKey().GetID(); } partialkeystore.AddKey(key[0]); { std::vector solutions; txnouttype whichType; CScript s; s << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK(solutions.size() == 1); CTxDestination addr; BOOST_CHECK(ExtractDestination(s, addr)); BOOST_CHECK(addr == keyaddr[0]); BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); } { std::vector solutions; txnouttype whichType; CScript s; s << OP_DUP << OP_HASH160 << ToByteVector(key[0].GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK(solutions.size() == 1); CTxDestination addr; BOOST_CHECK(ExtractDestination(s, addr)); BOOST_CHECK(addr == keyaddr[0]); BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); } { std::vector solutions; txnouttype whichType; CScript s; s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK_EQUAL(solutions.size(), 4U); CTxDestination addr; BOOST_CHECK(!ExtractDestination(s, addr)); BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); BOOST_CHECK(!IsMine(partialkeystore, s)); } { std::vector solutions; txnouttype whichType; CScript s; s << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK_EQUAL(solutions.size(), 4U); std::vector addrs; int nRequired; BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired)); BOOST_CHECK(addrs[0] == keyaddr[0]); BOOST_CHECK(addrs[1] == keyaddr[1]); BOOST_CHECK(nRequired == 1); BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s)); BOOST_CHECK(!IsMine(partialkeystore, s)); } { std::vector solutions; txnouttype whichType; CScript s; s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK(solutions.size() == 5); } } BOOST_AUTO_TEST_CASE(multisig_Sign) { // Test SignSignature() (and therefore the version of Solver() that signs // transactions) CBasicKeyStore keystore; CKey key[4]; for (int i = 0; i < 4; i++) { key[i].MakeNewKey(true); keystore.AddKey(key[i]); } CScript a_and_b; a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; CScript a_or_b; a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; CScript escrow; escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; // Funding transaction CMutableTransaction txFrom; txFrom.vout.resize(3); txFrom.vout[0].scriptPubKey = a_and_b; txFrom.vout[1].scriptPubKey = a_or_b; txFrom.vout[2].scriptPubKey = escrow; // Spending transaction CMutableTransaction txTo[3]; for (int i = 0; i < 3; i++) { txTo[i].vin.resize(1); txTo[i].vout.resize(1); txTo[i].vin[0].prevout = COutPoint(txFrom.GetId(), i); txTo[i].vout[0].nValue = SATOSHI; } for (int i = 0; i < 3; i++) { BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SigHashType().withForkId()), strprintf("SignSignature %d", i)); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index da082fe3d..9a0f1fcf9 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1,2070 +1,2070 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Copyright (c) 2017-2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "data/script_tests.json.h" #include "core_io.h" #include "key.h" #include "keystore.h" #include "rpc/server.h" #include "script/script.h" #include "script/script_error.h" #include "script/sighashtype.h" #include "script/sign.h" #include "test/jsonutil.h" #include "test/scriptflags.h" #include "test/sigutil.h" #include "test/test_bitcoin.h" #include "util.h" #include "utilstrencodings.h" #if defined(HAVE_CONSENSUS_LIB) #include "script/bitcoinconsensus.h" #endif #include #include #include #include #include #include // Uncomment if you want to output updated JSON tests. // #define UPDATE_JSON_TESTS static const uint32_t gFlags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; struct ScriptErrorDesc { ScriptError_t err; const char *name; }; static ScriptErrorDesc script_errors[] = { {SCRIPT_ERR_OK, "OK"}, {SCRIPT_ERR_UNKNOWN_ERROR, "UNKNOWN_ERROR"}, {SCRIPT_ERR_EVAL_FALSE, "EVAL_FALSE"}, {SCRIPT_ERR_OP_RETURN, "OP_RETURN"}, {SCRIPT_ERR_SCRIPT_SIZE, "SCRIPT_SIZE"}, {SCRIPT_ERR_PUSH_SIZE, "PUSH_SIZE"}, {SCRIPT_ERR_OP_COUNT, "OP_COUNT"}, {SCRIPT_ERR_STACK_SIZE, "STACK_SIZE"}, {SCRIPT_ERR_SIG_COUNT, "SIG_COUNT"}, {SCRIPT_ERR_PUBKEY_COUNT, "PUBKEY_COUNT"}, {SCRIPT_ERR_INVALID_OPERAND_SIZE, "OPERAND_SIZE"}, {SCRIPT_ERR_INVALID_NUMBER_RANGE, "INVALID_NUMBER_RANGE"}, {SCRIPT_ERR_IMPOSSIBLE_ENCODING, "IMPOSSIBLE_ENCODING"}, {SCRIPT_ERR_INVALID_SPLIT_RANGE, "SPLIT_RANGE"}, {SCRIPT_ERR_VERIFY, "VERIFY"}, {SCRIPT_ERR_EQUALVERIFY, "EQUALVERIFY"}, {SCRIPT_ERR_CHECKMULTISIGVERIFY, "CHECKMULTISIGVERIFY"}, {SCRIPT_ERR_CHECKSIGVERIFY, "CHECKSIGVERIFY"}, {SCRIPT_ERR_CHECKDATASIGVERIFY, "CHECKDATASIGVERIFY"}, {SCRIPT_ERR_NUMEQUALVERIFY, "NUMEQUALVERIFY"}, {SCRIPT_ERR_BAD_OPCODE, "BAD_OPCODE"}, {SCRIPT_ERR_DISABLED_OPCODE, "DISABLED_OPCODE"}, {SCRIPT_ERR_INVALID_STACK_OPERATION, "INVALID_STACK_OPERATION"}, {SCRIPT_ERR_INVALID_ALTSTACK_OPERATION, "INVALID_ALTSTACK_OPERATION"}, {SCRIPT_ERR_UNBALANCED_CONDITIONAL, "UNBALANCED_CONDITIONAL"}, {SCRIPT_ERR_NEGATIVE_LOCKTIME, "NEGATIVE_LOCKTIME"}, {SCRIPT_ERR_UNSATISFIED_LOCKTIME, "UNSATISFIED_LOCKTIME"}, {SCRIPT_ERR_SIG_HASHTYPE, "SIG_HASHTYPE"}, {SCRIPT_ERR_SIG_DER, "SIG_DER"}, {SCRIPT_ERR_MINIMALDATA, "MINIMALDATA"}, {SCRIPT_ERR_SIG_PUSHONLY, "SIG_PUSHONLY"}, {SCRIPT_ERR_SIG_HIGH_S, "SIG_HIGH_S"}, {SCRIPT_ERR_SIG_NULLDUMMY, "SIG_NULLDUMMY"}, {SCRIPT_ERR_PUBKEYTYPE, "PUBKEYTYPE"}, {SCRIPT_ERR_CLEANSTACK, "CLEANSTACK"}, {SCRIPT_ERR_MINIMALIF, "MINIMALIF"}, {SCRIPT_ERR_SIG_NULLFAIL, "NULLFAIL"}, {SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, "DISCOURAGE_UPGRADABLE_NOPS"}, {SCRIPT_ERR_NONCOMPRESSED_PUBKEY, "NONCOMPRESSED_PUBKEY"}, {SCRIPT_ERR_ILLEGAL_FORKID, "ILLEGAL_FORKID"}, {SCRIPT_ERR_MUST_USE_FORKID, "MISSING_FORKID"}, {SCRIPT_ERR_DIV_BY_ZERO, "DIV_BY_ZERO"}, {SCRIPT_ERR_MOD_BY_ZERO, "MOD_BY_ZERO"}, }; const char *FormatScriptError(ScriptError_t err) { for (size_t i = 0; i < ARRAYLEN(script_errors); ++i) { if (script_errors[i].err == err) { return script_errors[i].name; } } BOOST_ERROR("Unknown scripterror enumeration value, update script_errors " "in script_tests.cpp."); return ""; } ScriptError_t ParseScriptError(const std::string &name) { for (size_t i = 0; i < ARRAYLEN(script_errors); ++i) { if (script_errors[i].name == name) { return script_errors[i].err; } } BOOST_ERROR("Unknown scripterror \"" << name << "\" in test description"); return SCRIPT_ERR_UNKNOWN_ERROR; } BOOST_FIXTURE_TEST_SUITE(script_tests, BasicTestingSetup) static CMutableTransaction BuildCreditingTransaction(const CScript &scriptPubKey, const Amount nValue) { CMutableTransaction txCredit; txCredit.nVersion = 1; txCredit.nLockTime = 0; txCredit.vin.resize(1); txCredit.vout.resize(1); txCredit.vin[0].prevout = COutPoint(); txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0); txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; txCredit.vout[0].scriptPubKey = scriptPubKey; txCredit.vout[0].nValue = nValue; return txCredit; } static CMutableTransaction BuildSpendingTransaction(const CScript &scriptSig, const CMutableTransaction &txCredit) { CMutableTransaction txSpend; txSpend.nVersion = 1; txSpend.nLockTime = 0; txSpend.vin.resize(1); txSpend.vout.resize(1); txSpend.vin[0].prevout = COutPoint(txCredit.GetId(), 0); txSpend.vin[0].scriptSig = scriptSig; txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; txSpend.vout[0].scriptPubKey = CScript(); txSpend.vout[0].nValue = txCredit.vout[0].nValue; return txSpend; } static void DoTest(const CScript &scriptPubKey, const CScript &scriptSig, uint32_t flags, const std::string &message, int scriptError, const Amount nValue) { bool expect = (scriptError == SCRIPT_ERR_OK); if (flags & SCRIPT_VERIFY_CLEANSTACK) { flags |= SCRIPT_VERIFY_P2SH; } ScriptError err; CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey, nValue); CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit); CMutableTransaction tx2 = tx; BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker( &tx, 0, txCredit.vout[0].nValue), &err) == expect, message); BOOST_CHECK_MESSAGE( err == scriptError, std::string(FormatScriptError(err)) + " where " + std::string(FormatScriptError((ScriptError_t)scriptError)) + " expected: " + message); #if defined(HAVE_CONSENSUS_LIB) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << tx2; uint32_t libconsensus_flags = flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL; if (libconsensus_flags == flags) { if (flags & bitcoinconsensus_SCRIPT_ENABLE_SIGHASH_FORKID) { BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount( scriptPubKey.data(), scriptPubKey.size(), txCredit.vout[0].nValue / SATOSHI, (const uint8_t *)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message); } else { BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount( scriptPubKey.data(), scriptPubKey.size(), 0, (const uint8_t *)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message); BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script( scriptPubKey.data(), scriptPubKey.size(), (const uint8_t *)&stream[0], stream.size(), 0, libconsensus_flags, nullptr) == expect, message); } } #endif } namespace { const uint8_t 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}; const uint8_t vchKey1[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, 1, 0}; const uint8_t vchKey2[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, 1, 0, 0}; struct KeyData { CKey key0, key0C, key1, key1C, key2, key2C; CPubKey pubkey0, pubkey0C, pubkey0H; CPubKey pubkey1, pubkey1C; CPubKey pubkey2, pubkey2C; KeyData() { key0.Set(vchKey0, vchKey0 + 32, false); key0C.Set(vchKey0, vchKey0 + 32, true); pubkey0 = key0.GetPubKey(); pubkey0H = key0.GetPubKey(); pubkey0C = key0C.GetPubKey(); *const_cast(&pubkey0H[0]) = 0x06 | (pubkey0H[64] & 1); key1.Set(vchKey1, vchKey1 + 32, false); key1C.Set(vchKey1, vchKey1 + 32, true); pubkey1 = key1.GetPubKey(); pubkey1C = key1C.GetPubKey(); key2.Set(vchKey2, vchKey2 + 32, false); key2C.Set(vchKey2, vchKey2 + 32, true); pubkey2 = key2.GetPubKey(); pubkey2C = key2C.GetPubKey(); } }; class TestBuilder { private: //! Actually executed script CScript script; //! The P2SH redeemscript CScript redeemscript; CTransactionRef creditTx; CMutableTransaction spendTx; bool havePush; std::vector push; std::string comment; uint32_t flags; int scriptError; Amount nValue; void DoPush() { if (havePush) { spendTx.vin[0].scriptSig << push; havePush = false; } } void DoPush(const std::vector &data) { DoPush(); push = data; havePush = true; } std::vector DoSign(const CKey &key, const uint256 &hash, unsigned int lenR = 32, unsigned int lenS = 32) const { std::vector vchSig, r, s; uint32_t iter = 0; do { - key.Sign(hash, vchSig, iter++); + key.SignECDSA(hash, vchSig, iter++); 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()); return vchSig; } public: TestBuilder(const CScript &script_, const std::string &comment_, uint32_t flags_, bool P2SH = false, Amount nValue_ = Amount::zero()) : script(script_), havePush(false), comment(comment_), flags(flags_), scriptError(SCRIPT_ERR_OK), nValue(nValue_) { CScript scriptPubKey = script; if (P2SH) { redeemscript = scriptPubKey; scriptPubKey = CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemscript)) << OP_EQUAL; } creditTx = MakeTransactionRef(BuildCreditingTransaction(scriptPubKey, nValue)); spendTx = BuildSpendingTransaction(CScript(), *creditTx); } TestBuilder &ScriptError(ScriptError_t err) { scriptError = err; return *this; } TestBuilder &Add(const CScript &_script) { DoPush(); spendTx.vin[0].scriptSig += _script; return *this; } TestBuilder &Num(int num) { DoPush(); spendTx.vin[0].scriptSig << num; return *this; } TestBuilder &Push(const std::string &hex) { DoPush(ParseHex(hex)); return *this; } TestBuilder &Push(const uint256 &hash) { DoPush(ToByteVector(hash)); return *this; } TestBuilder &Push(const CScript &_script) { DoPush(std::vector(_script.begin(), _script.end())); return *this; } TestBuilder &PushSig(const CKey &key, SigHashType sigHashType = SigHashType(), unsigned int lenR = 32, unsigned int lenS = 32, Amount amount = Amount::zero(), uint32_t sigFlags = SCRIPT_ENABLE_SIGHASH_FORKID) { uint256 hash = SignatureHash(script, CTransaction(spendTx), 0, sigHashType, amount, nullptr, sigFlags); std::vector vchSig = DoSign(key, hash, lenR, lenS); vchSig.push_back(static_cast(sigHashType.getRawSigHashType())); DoPush(vchSig); return *this; } TestBuilder &PushDataSig(const CKey &key, const std::vector &data, unsigned int lenR = 32, unsigned int lenS = 32) { std::vector vchHash(32); CSHA256().Write(data.data(), data.size()).Finalize(vchHash.data()); DoPush(DoSign(key, uint256(vchHash), lenR, lenS)); return *this; } TestBuilder &Push(const CPubKey &pubkey) { DoPush(std::vector(pubkey.begin(), pubkey.end())); return *this; } TestBuilder &PushRedeem() { DoPush(std::vector(redeemscript.begin(), redeemscript.end())); return *this; } TestBuilder &EditPush(unsigned int pos, const std::string &hexin, const std::string &hexout) { assert(havePush); std::vector datain = ParseHex(hexin); std::vector dataout = ParseHex(hexout); assert(pos + datain.size() <= push.size()); BOOST_CHECK_MESSAGE( std::vector(push.begin() + pos, push.begin() + pos + datain.size()) == datain, comment); push.erase(push.begin() + pos, push.begin() + pos + datain.size()); push.insert(push.begin() + pos, dataout.begin(), dataout.end()); return *this; } TestBuilder &DamagePush(unsigned int pos) { assert(havePush); assert(pos < push.size()); push[pos] ^= 1; return *this; } TestBuilder &Test() { // Make a copy so we can rollback the push. TestBuilder copy = *this; DoPush(); DoTest(creditTx->vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, comment, scriptError, nValue); *this = copy; return *this; } UniValue GetJSON() { DoPush(); UniValue array(UniValue::VARR); if (nValue != Amount::zero()) { UniValue amount(UniValue::VARR); amount.push_back(ValueFromAmount(nValue)); array.push_back(amount); } array.push_back(FormatScript(spendTx.vin[0].scriptSig)); array.push_back(FormatScript(creditTx->vout[0].scriptPubKey)); array.push_back(FormatScriptFlags(flags)); array.push_back(FormatScriptError((ScriptError_t)scriptError)); array.push_back(comment); return array; } std::string GetComment() const { return comment; } }; std::string JSONPrettyPrint(const UniValue &univalue) { std::string ret = univalue.write(4); // Workaround for libunivalue pretty printer, which puts a space between // commas and newlines size_t pos = 0; while ((pos = ret.find(" \n", pos)) != std::string::npos) { ret.replace(pos, 2, "\n"); pos++; } return ret; } } // namespace BOOST_AUTO_TEST_CASE(script_build) { const KeyData keys; std::vector tests; tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK", 0) .PushSig(keys.key0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK, bad sig", 0) .PushSig(keys.key0) .DamagePush(10) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH", 0) .PushSig(keys.key1) .Push(keys.pubkey1C)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey2C.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH, bad pubkey", 0) .PushSig(keys.key2) .Push(keys.pubkey2C) .DamagePush(5) .ScriptError(SCRIPT_ERR_EQUALVERIFY)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK anyonecanpay", 0) .PushSig(keys.key1, SigHashType().withAnyoneCanPay())); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK anyonecanpay marked with normal hashtype", 0) .PushSig(keys.key1, SigHashType().withAnyoneCanPay()) .EditPush(70, "81", "01") .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, "P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .PushRedeem()); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, "P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .PushRedeem() .DamagePush(10) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey0.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH)", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .Push(keys.pubkey0) .PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true) .PushSig(keys.key0) .DamagePush(10) .PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2SH(P2PKH), bad sig", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .DamagePush(10) .PushRedeem() .ScriptError(SCRIPT_ERR_EQUALVERIFY)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3", 0) .Num(0) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3, 2 sigs", 0) .Num(0) .PushSig(keys.key0) .PushSig(keys.key1) .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "P2SH(2-of-3)", SCRIPT_VERIFY_P2SH, true) .Num(0) .PushSig(keys.key1) .PushSig(keys.key2) .PushRedeem()); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "P2SH(2-of-3), 1 sig", SCRIPT_VERIFY_P2SH, true) .Num(0) .PushSig(keys.key1) .Num(0) .PushRedeem() .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much R padding but no DERSIG", 0) .PushSig(keys.key1, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much R padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much S padding but no DERSIG", 0) .PushSig(keys.key1) .EditPush(1, "44", "45") .EditPush(37, "20", "2100")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too much S padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1) .EditPush(1, "44", "45") .EditPush(37, "20", "2100") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too little R padding but no DERSIG", 0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "P2PK with too little R padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with bad sig with too much R padding but no DERSIG", 0) .PushSig(keys.key2, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .DamagePush(10)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with bad sig with too much R padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key2, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .DamagePush(10) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with too much R padding but no DERSIG", 0) .PushSig(keys.key2, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with too much R padding", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key2, SigHashType(), 31, 32) .EditPush(1, "43021F", "44022000") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 1, without DERSIG", 0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 1, with DERSIG", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 2, without DERSIG", 0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 2, with DERSIG", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 3, without DERSIG", 0) .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 3, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, without DERSIG", 0) .Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG, non-null DER-compliant signature", SCRIPT_VERIFY_DERSIG) .Push("300602010102010101")); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG and NULLFAIL", SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLFAIL) .Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 4, with DERSIG and NULLFAIL, " "non-null DER-compliant signature", SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLFAIL) .Push("300602010102010101") .ScriptError(SCRIPT_ERR_SIG_NULLFAIL)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 5, without DERSIG", 0) .Num(1) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, "BIP66 example 5, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(1) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 6, without DERSIG", 0) .Num(1)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, "BIP66 example 6, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(1) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 7, without DERSIG", 0) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .PushSig(keys.key2)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 7, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .PushSig(keys.key2) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 8, without DERSIG", 0) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .PushSig(keys.key2) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 8, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .PushSig(keys.key2) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 9, without DERSIG", 0) .Num(0) .Num(0) .PushSig(keys.key2, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 9, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .Num(0) .PushSig(keys.key2, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 10, without DERSIG", 0) .Num(0) .Num(0) .PushSig(keys.key2, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220")); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 10, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .Num(0) .PushSig(keys.key2, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 11, without DERSIG", 0) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, "BIP66 example 11, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .Num(0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 12, without DERSIG", 0) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .Num(0)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, "BIP66 example 12, with DERSIG", SCRIPT_VERIFY_DERSIG) .Num(0) .PushSig(keys.key1, SigHashType(), 33, 32) .EditPush(1, "45022100", "440220") .Num(0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with multi-byte hashtype, without DERSIG", 0) .PushSig(keys.key2) .EditPush(70, "01", "0101")); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with multi-byte hashtype, with DERSIG", SCRIPT_VERIFY_DERSIG) .PushSig(keys.key2) .EditPush(70, "01", "0101") .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with high S but no LOW_S", 0) .PushSig(keys.key2, SigHashType(), 32, 33)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with high S", SCRIPT_VERIFY_LOW_S) .PushSig(keys.key2, SigHashType(), 32, 33) .ScriptError(SCRIPT_ERR_SIG_HIGH_S)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, "P2PK with hybrid pubkey but no STRICTENC", 0) .PushSig(keys.key0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, "P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key0, SigHashType()) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with hybrid pubkey but no STRICTENC", 0) .PushSig(keys.key0) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key0) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0) .PushSig(keys.key0) .DamagePush(10)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key0) .DamagePush(10) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back( TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the second 1 hybrid pubkey and no STRICTENC", 0) .Num(0) .PushSig(keys.key1)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the second 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .Num(0) .PushSig(keys.key1)); tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0H) << OP_2 << OP_CHECKMULTISIG, "1-of-2 with the first 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC) .Num(0) .PushSig(keys.key1) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK with undefined hashtype but no STRICTENC", 0) .PushSig(keys.key1, SigHashType(5))); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key1, SigHashType(5)) .ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); // Generate P2PKH tests for invalid SigHashType tests.push_back( TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey0.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH with invalid sighashtype", 0) .PushSig(keys.key0, SigHashType(0x21), 32, 32, Amount::zero(), 0) .Push(keys.pubkey0)); tests.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey0.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, "P2PKH with invalid sighashtype and STRICTENC", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key0, SigHashType(0x21), 32, 32, Amount::zero(), SCRIPT_VERIFY_STRICTENC) .Push(keys.pubkey0) // Should fail for STRICTENC .ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); // Generate P2SH tests for invalid SigHashType tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2SH(P2PK) with invalid sighashtype", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key1, SigHashType(0x21)) .PushRedeem()); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, "P2SH(P2PK) with invalid sighashtype and STRICTENC", SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, true) .PushSig(keys.key1, SigHashType(0x21)) .PushRedeem() // Should fail for STRICTENC .ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0) .PushSig(keys.key1, SigHashType(5)) .DamagePush(10)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key1, SigHashType(5)) .DamagePush(10) .ScriptError(SCRIPT_ERR_SIG_HASHTYPE)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3 with nonzero dummy but no NULLDUMMY", 0) .Num(1) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2)); tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, "3-of-3 with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY) .Num(1) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2) .ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); tests.push_back( TestBuilder( CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY", 0) .Num(1) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2) .DamagePush(10)); tests.push_back( TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG << OP_NOT, "3-of-3 NOT with invalid sig with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY) .Num(1) .PushSig(keys.key0) .PushSig(keys.key1) .PushSig(keys.key2) .DamagePush(10) .ScriptError(SCRIPT_ERR_SIG_NULLDUMMY)); tests.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs " "pushed using OP_DUP but no SIGPUSHONLY", 0) .Num(0) .PushSig(keys.key1) .Add(CScript() << OP_DUP)); tests.push_back( TestBuilder( CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs pushed using OP_DUP", SCRIPT_VERIFY_SIGPUSHONLY) .Num(0) .PushSig(keys.key1) .Add(CScript() << OP_DUP) .ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but no P2SH or SIGPUSHONLY", 0, true) .PushSig(keys.key2) .Add(CScript() << OP_NOP8) .PushRedeem()); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2PK with non-push scriptSig but with P2SH validation", 0) .PushSig(keys.key2) .Add(CScript() << OP_NOP8)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key2) .Add(CScript() << OP_NOP8) .PushRedeem() .ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, "P2SH(P2PK) with non-push scriptSig but not P2SH", SCRIPT_VERIFY_SIGPUSHONLY, true) .PushSig(keys.key2) .Add(CScript() << OP_NOP8) .PushRedeem() .ScriptError(SCRIPT_ERR_SIG_PUSHONLY)); tests.push_back( TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, "2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY) .Num(0) .PushSig(keys.key1) .PushSig(keys.key1)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH) .Num(11) .PushSig(keys.key0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH) .Num(11) .PushSig(keys.key0) .ScriptError(SCRIPT_ERR_CLEANSTACK)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH, true) .Num(11) .PushSig(keys.key0) .PushRedeem()); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true) .Num(11) .PushSig(keys.key0) .PushRedeem() .ScriptError(SCRIPT_ERR_CLEANSTACK)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2SH with CLEANSTACK", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true) .PushSig(keys.key0) .PushRedeem()); static const Amount TEST_AMOUNT(int64_t(12345000000000) * SATOSHI); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK FORKID", SCRIPT_ENABLE_SIGHASH_FORKID, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK INVALID AMOUNT", SCRIPT_ENABLE_SIGHASH_FORKID, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT + SATOSHI) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK INVALID FORKID", SCRIPT_VERIFY_STRICTENC, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT) .ScriptError(SCRIPT_ERR_ILLEGAL_FORKID)); // Test replay protection tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK REPLAY PROTECTED", SCRIPT_ENABLE_SIGHASH_FORKID | SCRIPT_ENABLE_REPLAY_PROTECTION, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT, SCRIPT_ENABLE_SIGHASH_FORKID | SCRIPT_ENABLE_REPLAY_PROTECTION)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, "P2PK REPLAY PROTECTED", SCRIPT_ENABLE_SIGHASH_FORKID | SCRIPT_ENABLE_REPLAY_PROTECTION, false, TEST_AMOUNT) .PushSig(keys.key0, SigHashType().withForkId(), 32, 32, TEST_AMOUNT, SCRIPT_ENABLE_SIGHASH_FORKID) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); // Test OP_CHECKDATASIG const uint32_t checkdatasigflags = SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_NULLFAIL | SCRIPT_ENABLE_CHECKDATASIG; tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG, "Standard CHECKDATASIG", checkdatasigflags) .PushDataSig(keys.key1, {}) .Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG << OP_NOT, "CHECKDATASIG with NULLFAIL flags", checkdatasigflags) .PushDataSig(keys.key1, {}) .Num(1) .ScriptError(SCRIPT_ERR_SIG_NULLFAIL)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG << OP_NOT, "CHECKDATASIG without NULLFAIL flags", checkdatasigflags & ~SCRIPT_VERIFY_NULLFAIL) .PushDataSig(keys.key1, {}) .Num(1)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG << OP_NOT, "CHECKDATASIG empty signature", checkdatasigflags) .Num(0) .Num(0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG, "CHECKDATASIG with High S but no Low S", checkdatasigflags) .PushDataSig(keys.key1, {}, 32, 33) .Num(0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG, "CHECKDATASIG with High S", checkdatasigflags | SCRIPT_VERIFY_LOW_S) .PushDataSig(keys.key1, {}, 32, 33) .Num(0) .ScriptError(SCRIPT_ERR_SIG_HIGH_S)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG, "CHECKDATASIG with too little R padding but no DERSIG", checkdatasigflags & ~SCRIPT_VERIFY_STRICTENC) .PushDataSig(keys.key1, {}, 33, 32) .EditPush(1, "45022100", "440220") .Num(0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG, "CHECKDATASIG with too little R padding", checkdatasigflags) .PushDataSig(keys.key1, {}, 33, 32) .EditPush(1, "45022100", "440220") .Num(0) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIG, "CHECKDATASIG with hybrid pubkey but no STRICTENC", checkdatasigflags & ~SCRIPT_VERIFY_STRICTENC) .PushDataSig(keys.key0, {}) .Num(0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIG, "CHECKDATASIG with hybrid pubkey", checkdatasigflags) .PushDataSig(keys.key0, {}) .Num(0) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIG << OP_NOT, "CHECKDATASIG with invalid hybrid pubkey but no STRICTENC", SCRIPT_ENABLE_CHECKDATASIG) .PushDataSig(keys.key0, {}) .DamagePush(10) .Num(0)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIG, "CHECKDATASIG with invalid hybrid pubkey", checkdatasigflags) .PushDataSig(keys.key0, {}) .DamagePush(10) .Num(0) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); // Test OP_CHECKDATASIGVERIFY tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIGVERIFY << OP_TRUE, "Standard CHECKDATASIGVERIFY", checkdatasigflags) .PushDataSig(keys.key1, {}) .Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIGVERIFY << OP_TRUE, "CHECKDATASIGVERIFY with NULLFAIL flags", checkdatasigflags) .PushDataSig(keys.key1, {}) .Num(1) .ScriptError(SCRIPT_ERR_SIG_NULLFAIL)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIGVERIFY << OP_TRUE, "CHECKDATASIGVERIFY without NULLFAIL flags", checkdatasigflags & ~SCRIPT_VERIFY_NULLFAIL) .PushDataSig(keys.key1, {}) .Num(1) .ScriptError(SCRIPT_ERR_CHECKDATASIGVERIFY)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIGVERIFY << OP_TRUE, "CHECKDATASIGVERIFY empty signature", checkdatasigflags) .Num(0) .Num(0) .ScriptError(SCRIPT_ERR_CHECKDATASIGVERIFY)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIGVERIFY << OP_TRUE, "CHECKDATASIG with High S but no Low S", checkdatasigflags) .PushDataSig(keys.key1, {}, 32, 33) .Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIGVERIFY << OP_TRUE, "CHECKDATASIG with High S", checkdatasigflags | SCRIPT_VERIFY_LOW_S) .PushDataSig(keys.key1, {}, 32, 33) .Num(0) .ScriptError(SCRIPT_ERR_SIG_HIGH_S)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIGVERIFY << OP_TRUE, "CHECKDATASIGVERIFY with too little R padding but no DERSIG", checkdatasigflags & ~SCRIPT_VERIFY_STRICTENC) .PushDataSig(keys.key1, {}, 33, 32) .EditPush(1, "45022100", "440220") .Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIGVERIFY << OP_TRUE, "CHECKDATASIGVERIFY with too little R padding", checkdatasigflags) .PushDataSig(keys.key1, {}, 33, 32) .EditPush(1, "45022100", "440220") .Num(0) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIGVERIFY << OP_TRUE, "CHECKDATASIGVERIFY with hybrid pubkey but no STRICTENC", checkdatasigflags & ~SCRIPT_VERIFY_STRICTENC) .PushDataSig(keys.key0, {}) .Num(0)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIGVERIFY << OP_TRUE, "CHECKDATASIGVERIFY with hybrid pubkey", checkdatasigflags) .PushDataSig(keys.key0, {}) .Num(0) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back( TestBuilder( CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIGVERIFY << OP_TRUE, "CHECKDATASIGVERIFY with invalid hybrid pubkey but no STRICTENC", SCRIPT_ENABLE_CHECKDATASIG) .PushDataSig(keys.key0, {}) .DamagePush(10) .Num(0) .ScriptError(SCRIPT_ERR_CHECKDATASIGVERIFY)); tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIGVERIFY << OP_TRUE, "CHECKDATASIGVERIFY with invalid hybrid pubkey", checkdatasigflags) .PushDataSig(keys.key0, {}) .DamagePush(10) .Num(0) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); std::set tests_set; { UniValue json_tests = read_json(std::string( json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); for (unsigned int idx = 0; idx < json_tests.size(); idx++) { const UniValue &tv = json_tests[idx]; tests_set.insert(JSONPrettyPrint(tv.get_array())); } } std::string strGen; for (TestBuilder &test : tests) { test.Test(); std::string str = JSONPrettyPrint(test.GetJSON()); #ifndef UPDATE_JSON_TESTS if (tests_set.count(str) == 0) { BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment()); } #endif strGen += str + ",\n"; } #ifdef UPDATE_JSON_TESTS FILE *file = fopen("script_tests.json.gen", "w"); fputs(strGen.c_str(), file); fclose(file); #endif } BOOST_AUTO_TEST_CASE(script_json_test) { // Read tests from test/data/script_tests.json // Format is an array of arrays // Inner arrays are [ ["wit"..., nValue]?, "scriptSig", "scriptPubKey", // "flags", "expected_scripterror" ] // ... where scriptSig and scriptPubKey are stringified // scripts. UniValue tests = read_json(std::string( json_tests::script_tests, json_tests::script_tests + sizeof(json_tests::script_tests))); for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; std::string strTest = test.write(); Amount nValue = Amount::zero(); unsigned int pos = 0; if (test.size() > 0 && test[pos].isArray()) { nValue = AmountFromValue(test[pos][0]); pos++; } // Allow size > 3; extra stuff ignored (useful for comments) if (test.size() < 4 + pos) { if (test.size() != 1) { BOOST_ERROR("Bad test: " << strTest); } continue; } std::string scriptSigString = test[pos++].get_str(); std::string scriptPubKeyString = test[pos++].get_str(); try { CScript scriptSig = ParseScript(scriptSigString); CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[pos++].get_str()); int scriptError = ParseScriptError(test[pos++].get_str()); DoTest(scriptPubKey, scriptSig, scriptflags, strTest, scriptError, nValue); } catch (std::runtime_error &e) { BOOST_TEST_MESSAGE("Script test failed. scriptSig: " << scriptSigString << " scriptPubKey: " << scriptPubKeyString); BOOST_TEST_MESSAGE("Exception: " << e.what()); throw; } } } BOOST_AUTO_TEST_CASE(script_PushData) { // Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on // the stack as the 1-75 opcodes do. static const uint8_t direct[] = {1, 0x5a}; static const uint8_t pushdata1[] = {OP_PUSHDATA1, 1, 0x5a}; static const uint8_t pushdata2[] = {OP_PUSHDATA2, 1, 0, 0x5a}; static const uint8_t pushdata4[] = {OP_PUSHDATA4, 1, 0, 0, 0, 0x5a}; ScriptError err; std::vector> directStack; BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector> pushdata1Stack; BOOST_CHECK(EvalScript( pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata1Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector> pushdata2Stack; BOOST_CHECK(EvalScript( pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata2Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); std::vector> pushdata4Stack; BOOST_CHECK(EvalScript( pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata4Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } CScript sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction) { uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SigHashType(), Amount::zero()); CScript result; // // NOTE: CHECKMULTISIG has an unfortunate bug; it requires one extra item on // the stack, before the signatures. Putting OP_0 on the stack is the // workaround; fixing the bug would mean splitting the block chain (old // clients would not accept new CHECKMULTISIG transactions, and vice-versa) // result << OP_0; for (const CKey &key : keys) { std::vector vchSig; - BOOST_CHECK(key.Sign(hash, vchSig)); + BOOST_CHECK(key.SignECDSA(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL)); result << vchSig; } return result; } CScript sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction) { std::vector keys; keys.push_back(key); return sign_multisig(scriptPubKey, keys, transaction); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) { ScriptError err; CKey key1, key2, key3; key1.MakeNewKey(true); key2.MakeNewKey(false); key3.MakeNewKey(true); CScript scriptPubKey12; scriptPubKey12 << OP_1 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << OP_2 << OP_CHECKMULTISIG; CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12, Amount::zero()); CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); CScript goodsig1 = sign_multisig(scriptPubKey12, key1, CTransaction(txTo12)); BOOST_CHECK(VerifyScript( goodsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); txTo12.vout[0].nValue = 2 * SATOSHI; BOOST_CHECK(!VerifyScript( goodsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, CTransaction(txTo12)); BOOST_CHECK(VerifyScript( goodsig2, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); CScript badsig1 = sign_multisig(scriptPubKey12, key3, CTransaction(txTo12)); BOOST_CHECK(!VerifyScript( badsig1, scriptPubKey12, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) { ScriptError err; CKey key1, key2, key3, key4; key1.MakeNewKey(true); key2.MakeNewKey(false); key3.MakeNewKey(true); key4.MakeNewKey(false); CScript scriptPubKey23; scriptPubKey23 << OP_2 << ToByteVector(key1.GetPubKey()) << ToByteVector(key2.GetPubKey()) << ToByteVector(key3.GetPubKey()) << OP_3 << OP_CHECKMULTISIG; CMutableTransaction txFrom23 = BuildCreditingTransaction(scriptPubKey23, Amount::zero()); CMutableTransaction mutableTxTo23 = BuildSpendingTransaction(CScript(), txFrom23); // after it has been set up, mutableTxTo23 does not change in this test, // so we can convert it to readonly transaction and use // TransactionSignatureChecker // instead of MutableTransactionSignatureChecker const CTransaction txTo23(mutableTxTo23); std::vector keys; keys.push_back(key1); keys.push_back(key2); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(VerifyScript( goodsig1, scriptPubKey23, gFlags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key3); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(VerifyScript( goodsig2, scriptPubKey23, gFlags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key3); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(VerifyScript( goodsig3, scriptPubKey23, gFlags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key2); // Can't re-use sig CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig1, scriptPubKey23, gFlags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig2, scriptPubKey23, gFlags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig3, scriptPubKey23, gFlags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig4, scriptPubKey23, gFlags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig5, scriptPubKey23, gFlags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); // Must have signatures CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); BOOST_CHECK(!VerifyScript( badsig6, scriptPubKey23, gFlags, TransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_combineSigs) { // Test the CombineSignatures function Amount amount = Amount::zero(); CBasicKeyStore keystore; std::vector keys; std::vector pubkeys; for (int i = 0; i < 3; i++) { CKey key; key.MakeNewKey(i % 2 == 1); keys.push_back(key); pubkeys.push_back(key.GetPubKey()); keystore.AddKey(key); } CMutableTransaction txFrom = BuildCreditingTransaction( GetScriptForDestination(keys[0].GetPubKey().GetID()), Amount::zero()); CMutableTransaction txTo = BuildSpendingTransaction(CScript(), txFrom); CScript &scriptPubKey = txFrom.vout[0].scriptPubKey; CScript &scriptSig = txTo.vin[0].scriptSig; // Although it looks like CMutableTransaction is not modified after it’s // been set up (it is not passed as parameter to any non-const function), // it is actually modified when new value is assigned to scriptPubKey, // which points to mutableTxFrom.vout[0].scriptPubKey. Therefore we can // not use single instance of CTransaction in this test. // CTransaction creates a copy of CMutableTransaction and is not modified // when scriptPubKey is assigned to. SignatureData empty; SignatureData combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty); BOOST_CHECK(combined.scriptSig.empty()); // Single signature case: SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); // changes scriptSig combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); CScript scriptSigCopy = scriptSig; // Signing again will give a different, valid signature: SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // P2SH, single-signature case: CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG; keystore.AddCScript(pkSingle); scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); scriptSigCopy = scriptSig; SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // dummy scriptSigCopy with placeholder, should always choose // non-placeholder: scriptSigCopy = CScript() << OP_0 << std::vector(pkSingle.begin(), pkSingle.end()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy)); BOOST_CHECK(combined.scriptSig == scriptSig); // Hardest case: Multisig 2-of-3 scriptPubKey = GetScriptForMultisig(2, pubkeys); keystore.AddCScript(scriptPubKey); SignSignature(keystore, CTransaction(txFrom), txTo, 0, SigHashType()); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); BOOST_CHECK(combined.scriptSig == scriptSig); // A couple of partially-signed versions: std::vector sig1; uint256 hash1 = SignatureHash(scriptPubKey, CTransaction(txTo), 0, SigHashType(), Amount::zero()); - BOOST_CHECK(keys[0].Sign(hash1, sig1)); + BOOST_CHECK(keys[0].SignECDSA(hash1, sig1)); sig1.push_back(SIGHASH_ALL); std::vector sig2; uint256 hash2 = SignatureHash( scriptPubKey, CTransaction(txTo), 0, SigHashType().withBaseType(BaseSigHashType::NONE), Amount::zero()); - BOOST_CHECK(keys[1].Sign(hash2, sig2)); + BOOST_CHECK(keys[1].SignECDSA(hash2, sig2)); sig2.push_back(SIGHASH_NONE); std::vector sig3; uint256 hash3 = SignatureHash( scriptPubKey, CTransaction(txTo), 0, SigHashType().withBaseType(BaseSigHashType::SINGLE), Amount::zero()); - BOOST_CHECK(keys[2].Sign(hash3, sig3)); + BOOST_CHECK(keys[2].SignECDSA(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); // Not fussy about order (or even existence) of placeholders or signatures: CScript partial1a = CScript() << OP_0 << sig1 << OP_0; CScript partial1b = CScript() << OP_0 << OP_0 << sig1; CScript partial2a = CScript() << OP_0 << sig2; CScript partial2b = CScript() << sig2 << OP_0; CScript partial3a = CScript() << sig3; CScript partial3b = CScript() << OP_0 << OP_0 << sig3; CScript partial3c = CScript() << OP_0 << sig3 << OP_0; CScript complete12 = CScript() << OP_0 << sig1 << sig2; CScript complete13 = CScript() << OP_0 << sig1 << sig3; CScript complete23 = CScript() << OP_0 << sig2 << sig3; combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b)); BOOST_CHECK(combined.scriptSig == partial1a); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a)); BOOST_CHECK(combined.scriptSig == complete12); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a)); BOOST_CHECK(combined.scriptSig == complete12); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b)); BOOST_CHECK(combined.scriptSig == complete12); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b)); BOOST_CHECK(combined.scriptSig == complete13); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a)); BOOST_CHECK(combined.scriptSig == complete23); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b)); BOOST_CHECK(combined.scriptSig == complete23); combined = CombineSignatures( scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a)); BOOST_CHECK(combined.scriptSig == partial3c); } BOOST_AUTO_TEST_CASE(script_standard_push) { ScriptError err; for (int i = 0; i < 67000; i++) { CScript script; script << i; BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push."); BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Number " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } for (unsigned int i = 0; i <= MAX_SCRIPT_ELEMENT_SIZE; i++) { std::vector data(i, '\111'); CScript script; script << data; BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push."); BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Length " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } } BOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts) { // IsPushOnly returns false when given a script containing only pushes that // are invalid due to truncation. IsPushOnly() is consensus critical because // P2SH evaluation uses it, although this specific behavior should not be // consensus critical as the P2SH evaluation would fail first due to the // invalid push. Still, it doesn't hurt to test it explicitly. static const uint8_t direct[] = {1}; BOOST_CHECK(!CScript(direct, direct + sizeof(direct)).IsPushOnly()); } BOOST_AUTO_TEST_CASE(script_GetScriptAsm) { BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2, true)); BOOST_CHECK_EQUAL( "OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true)); BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2)); BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY)); std::string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e" "3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38" "d782e53023ee313d741ad0cfbc0c5090"); std::string pubKey( "03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2"); std::vector vchPubKey = ToByteVector(ParseHex(pubKey)); BOOST_CHECK_EQUAL( derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[ALL] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[ALL|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[ALL|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "41")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[ALL|FORKID|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "c1")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[NONE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[NONE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[NONE|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "42")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[NONE|FORKID|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "c2")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[SINGLE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[SINGLE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[SINGLE|FORKID] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "43")) << vchPubKey, true)); BOOST_CHECK_EQUAL( derSig + "[SINGLE|FORKID|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "c3")) << vchPubKey, true)); BOOST_CHECK_EQUAL(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "01 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "02 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "03 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "81 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "82 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey)); BOOST_CHECK_EQUAL(derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey)); } static CScript ScriptFromHex(const char *hex) { std::vector data = ParseHex(hex); return CScript(data.begin(), data.end()); } BOOST_AUTO_TEST_CASE(script_FindAndDelete) { // Exercise the FindAndDelete functionality CScript s; CScript d; CScript expect; s = CScript() << OP_1 << OP_2; // delete nothing should be a no-op d = CScript(); expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); s = CScript() << OP_1 << OP_2 << OP_3; d = CScript() << OP_2; expect = CScript() << OP_1 << OP_3; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = CScript() << OP_3 << OP_1 << OP_3 << OP_3 << OP_4 << OP_3; d = CScript() << OP_3; expect = CScript() << OP_1 << OP_4; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 4); BOOST_CHECK(s == expect); // PUSH 0x02ff03 onto stack s = ScriptFromHex("0302ff03"); d = ScriptFromHex("0302ff03"); expect = CScript(); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); // PUSH 0x2ff03 PUSH 0x2ff03 s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("0302ff03"); expect = CScript(); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); BOOST_CHECK(s == expect); s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("02"); expect = s; // FindAndDelete matches entire opcodes BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("ff"); expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); // This is an odd edge case: strip of the push-three-bytes prefix, leaving // 02ff03 which is push-two-bytes: s = ScriptFromHex("0302ff030302ff03"); d = ScriptFromHex("03"); expect = CScript() << ParseHex("ff03") << ParseHex("ff03"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); BOOST_CHECK(s == expect); // Byte sequence that spans multiple opcodes: // PUSH(0xfeed) OP_1 OP_VERIFY s = ScriptFromHex("02feed5169"); d = ScriptFromHex("feed51"); expect = s; // doesn't match 'inside' opcodes BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); // PUSH(0xfeed) OP_1 OP_VERIFY s = ScriptFromHex("02feed5169"); d = ScriptFromHex("02feed51"); expect = ScriptFromHex("69"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = ScriptFromHex("516902feed5169"); d = ScriptFromHex("feed51"); expect = s; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 0); BOOST_CHECK(s == expect); s = ScriptFromHex("516902feed5169"); d = ScriptFromHex("02feed51"); expect = ScriptFromHex("516969"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = CScript() << OP_0 << OP_0 << OP_1 << OP_1; d = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass expect = CScript() << OP_0 << OP_1; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = CScript() << OP_0 << OP_0 << OP_1 << OP_0 << OP_1 << OP_1; d = CScript() << OP_0 << OP_1; // FindAndDelete is single-pass expect = CScript() << OP_0 << OP_1; BOOST_CHECK_EQUAL(s.FindAndDelete(d), 2); BOOST_CHECK(s == expect); // Another weird edge case: // End with invalid push (not enough data)... s = ScriptFromHex("0003feed"); // ... can remove the invalid push d = ScriptFromHex("03feed"); expect = ScriptFromHex("00"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); s = ScriptFromHex("0003feed"); d = ScriptFromHex("00"); expect = ScriptFromHex("03feed"); BOOST_CHECK_EQUAL(s.FindAndDelete(d), 1); BOOST_CHECK(s == expect); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 261369491..ed1bbf4d1 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -1,433 +1,433 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "config.h" #include "consensus/validation.h" #include "key.h" #include "keystore.h" #include "miner.h" #include "pubkey.h" #include "random.h" #include "script/scriptcache.h" #include "script/sighashtype.h" #include "script/sign.h" #include "script/standard.h" #include "test/sigutil.h" #include "test/test_bitcoin.h" #include "txmempool.h" #include "utiltime.h" #include "validation.h" #include BOOST_AUTO_TEST_SUITE(txvalidationcache_tests) static bool ToMemPool(const CMutableTransaction &tx) { LOCK(cs_main); CValidationState state; return AcceptToMemoryPool(GetConfig(), g_mempool, state, MakeTransactionRef(tx), false, nullptr, true, Amount::zero()); } BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) { // Make sure skipping validation of transctions that were validated going // into the memory pool does not allow double-spends in blocks to pass // validation when they should not. CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; // Create a double-spend of mature coinbase txn: std::vector spends; spends.resize(2); for (int i = 0; i < 2; i++) { spends[i].nVersion = 1; spends[i].vin.resize(1); spends[i].vin[0].prevout = COutPoint(coinbaseTxns[0].GetId(), 0); spends[i].vout.resize(1); spends[i].vout[0].nValue = 11 * CENT; spends[i].vout[0].scriptPubKey = scriptPubKey; // Sign: std::vector vchSig; uint256 hash = SignatureHash(scriptPubKey, CTransaction(spends[i]), 0, SigHashType().withForkId(), coinbaseTxns[0].vout[0].nValue); - BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); + BOOST_CHECK(coinbaseKey.SignECDSA(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); spends[i].vin[0].scriptSig << vchSig; } CBlock block; // Test 1: block with both of those transactions should be rejected. block = CreateAndProcessBlock(spends, scriptPubKey); BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); // Test 2: ... and should be rejected if spend1 is in the memory pool BOOST_CHECK(ToMemPool(spends[0])); block = CreateAndProcessBlock(spends, scriptPubKey); BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); g_mempool.clear(); // Test 3: ... and should be rejected if spend2 is in the memory pool BOOST_CHECK(ToMemPool(spends[1])); block = CreateAndProcessBlock(spends, scriptPubKey); BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); g_mempool.clear(); // Final sanity test: first spend in mempool, second in block, that's OK: std::vector oneSpend; oneSpend.push_back(spends[0]); BOOST_CHECK(ToMemPool(spends[1])); block = CreateAndProcessBlock(oneSpend, scriptPubKey); BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); // spends[1] should have been removed from the mempool when the block with // spends[0] is accepted: BOOST_CHECK_EQUAL(g_mempool.size(), 0); } // Run CheckInputs (using pcoinsTip) on the given transaction, for all script // flags. Test that CheckInputs passes for all flags that don't overlap with the // failing_flags argument, but otherwise fails. // CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY (and future NOP codes that may // get reassigned) have an interaction with DISCOURAGE_UPGRADABLE_NOPS: if the // script flags used contain DISCOURAGE_UPGRADABLE_NOPS but don't contain // CHECKLOCKTIMEVERIFY (or CHECKSEQUENCEVERIFY), but the script does contain // OP_CHECKLOCKTIMEVERIFY (or OP_CHECKSEQUENCEVERIFY), then script execution // should fail. // Capture this interaction with the upgraded_nop argument: set it when // evaluating any script flag that is implemented as an upgraded NOP code. void ValidateCheckInputsForAllFlags(const CMutableTransaction &mutableTx, uint32_t failing_flags, bool add_to_cache, bool upgraded_nop) { const CTransaction tx(mutableTx); PrecomputedTransactionData txdata(tx); // If we add many more flags, this loop can get too expensive, but we can // rewrite in the future to randomly pick a set of flags to evaluate. for (uint32_t test_flags = 0; test_flags < (1U << 17); test_flags += 1) { CValidationState state; // Make sure the mandatory flags are enabled. test_flags |= MANDATORY_SCRIPT_VERIFY_FLAGS; bool ret = CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, nullptr); // CheckInputs should succeed iff test_flags doesn't intersect with // failing_flags bool expected_return_value = !(test_flags & failing_flags); if (expected_return_value && upgraded_nop) { // If the script flag being tested corresponds to an upgraded NOP, // then script execution should fail if DISCOURAGE_UPGRADABLE_NOPS // is set. expected_return_value = !(test_flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS); } BOOST_CHECK_EQUAL(ret, expected_return_value); // Test the caching if (ret && add_to_cache) { // Check that we get a cache hit if the tx was valid std::vector scriptchecks; BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, &scriptchecks)); BOOST_CHECK(scriptchecks.empty()); } else { // Check that we get script executions to check, if the transaction // was invalid, or we didn't add to cache. std::vector scriptchecks; BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, &scriptchecks)); BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size()); } } } BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) { // Test that passing CheckInputs with one set of script flags doesn't imply // that we would pass again with a different set of flags. InitScriptExecutionCache(); CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; CScript p2sh_scriptPubKey = GetScriptForDestination(CScriptID(p2pk_scriptPubKey)); CScript p2pkh_scriptPubKey = GetScriptForDestination(coinbaseKey.GetPubKey().GetID()); CBasicKeyStore keystore; keystore.AddKey(coinbaseKey); keystore.AddCScript(p2pk_scriptPubKey); CMutableTransaction mutableFunding_tx; // Needed when spending the output of this transaction CScript nulldummyPubKeyScript; // Create a funding transaction that can fail NULLDUMMY checks. This is for // testing consensus vs non-standard rules in `checkinputs_test`. { mutableFunding_tx.nVersion = 1; mutableFunding_tx.vin.resize(1); mutableFunding_tx.vin[0].prevout = COutPoint(coinbaseTxns[0].GetId(), 0); mutableFunding_tx.vout.resize(1); mutableFunding_tx.vout[0].nValue = 50 * COIN; CKey dummyKey; dummyKey.MakeNewKey(true); nulldummyPubKeyScript << OP_1 << ToByteVector(coinbaseKey.GetPubKey()) << ToByteVector(dummyKey.GetPubKey()) << OP_2 << OP_CHECKMULTISIG; mutableFunding_tx.vout[0].scriptPubKey = nulldummyPubKeyScript; std::vector nullDummyVchSig; uint256 nulldummySigHash = SignatureHash( p2pk_scriptPubKey, CTransaction(mutableFunding_tx), 0, SigHashType().withForkId(), coinbaseTxns[0].vout[0].nValue); - BOOST_CHECK(coinbaseKey.Sign(nulldummySigHash, nullDummyVchSig)); + BOOST_CHECK(coinbaseKey.SignECDSA(nulldummySigHash, nullDummyVchSig)); nullDummyVchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); mutableFunding_tx.vin[0].scriptSig << nullDummyVchSig; } const CTransaction funding_tx = CTransaction(mutableFunding_tx); // Spend the funding transaction by mining it into a block { LOCK(cs_main); CBlock block = CreateAndProcessBlock({funding_tx}, p2pk_scriptPubKey); BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash()); } // flags to test: SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, // SCRIPT_VERIFY_CHECKSEQUENCE_VERIFY, SCRIPT_VERIFY_NULLDUMMY, uncompressed // pubkey thing // Create 2 outputs that match the three scripts above, spending the first // coinbase tx. CMutableTransaction mutableSpend_tx; mutableSpend_tx.nVersion = 1; mutableSpend_tx.vin.resize(1); mutableSpend_tx.vin[0].prevout = COutPoint(funding_tx.GetId(), 0); mutableSpend_tx.vout.resize(4); mutableSpend_tx.vout[0].nValue = 11 * CENT; mutableSpend_tx.vout[0].scriptPubKey = p2sh_scriptPubKey; mutableSpend_tx.vout[1].nValue = 11 * CENT; mutableSpend_tx.vout[1].scriptPubKey = CScript() << OP_CHECKLOCKTIMEVERIFY << OP_DROP << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; mutableSpend_tx.vout[2].nValue = 11 * CENT; mutableSpend_tx.vout[2].scriptPubKey = CScript() << OP_CHECKSEQUENCEVERIFY << OP_DROP << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; mutableSpend_tx.vout[3].nValue = 11 * CENT; mutableSpend_tx.vout[3].scriptPubKey = p2sh_scriptPubKey; // Sign the main transaction that we spend from. { std::vector vchSig; uint256 hash = SignatureHash( nulldummyPubKeyScript, CTransaction(mutableSpend_tx), 0, SigHashType().withForkId(), funding_tx.vout[0].nValue); - coinbaseKey.Sign(hash, vchSig); + coinbaseKey.SignECDSA(hash, vchSig); vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); // The last item on the stack will be dropped by CHECKMULTISIG This is // to check nulldummy enforcement. It is OP_1 instead of OP_0. mutableSpend_tx.vin[0].scriptSig << OP_1 << vchSig; } const CTransaction spend_tx(mutableSpend_tx); LOCK(cs_main); // Test that invalidity under a set of flags doesn't preclude validity under // other (eg consensus) flags. // spend_tx is invalid according to NULLDUMMY { CValidationState state; PrecomputedTransactionData ptd_spend_tx(spend_tx); BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip.get(), true, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_NULLDUMMY, true, true, ptd_spend_tx, nullptr)); // If we call again asking for scriptchecks (as happens in // ConnectBlock), we should add a script check object for this -- we're // not caching invalidity (if that changes, delete this test case). std::vector scriptchecks; BOOST_CHECK( CheckInputs(spend_tx, state, pcoinsTip.get(), true, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_NULLDUMMY, true, true, ptd_spend_tx, &scriptchecks)); BOOST_CHECK_EQUAL(scriptchecks.size(), 1); // Test that CheckInputs returns true iff cleanstack-enforcing flags are // not present. Don't add these checks to the cache, so that we can test // later that block validation works fine in the absence of cached // successes. ValidateCheckInputsForAllFlags(spend_tx, SCRIPT_VERIFY_NULLDUMMY, false, false); // And if we produce a block with this tx, it should be valid (LOW_S not // enabled yet), even though there's no cache entry. CBlock block; block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey); BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash()); } // Test P2SH: construct a transaction that is valid without P2SH, and then // test validity with P2SH. { CMutableTransaction invalid_under_p2sh_tx; invalid_under_p2sh_tx.nVersion = 1; invalid_under_p2sh_tx.vin.resize(1); invalid_under_p2sh_tx.vin[0].prevout = COutPoint(spend_tx.GetId(), 0); invalid_under_p2sh_tx.vout.resize(1); invalid_under_p2sh_tx.vout[0].nValue = 11 * CENT; invalid_under_p2sh_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; std::vector vchSig2(p2pk_scriptPubKey.begin(), p2pk_scriptPubKey.end()); invalid_under_p2sh_tx.vin[0].scriptSig << vchSig2; ValidateCheckInputsForAllFlags(invalid_under_p2sh_tx, SCRIPT_VERIFY_P2SH, true, false); } // Test CHECKLOCKTIMEVERIFY { CMutableTransaction invalid_with_cltv_tx; invalid_with_cltv_tx.nVersion = 1; invalid_with_cltv_tx.nLockTime = 100; invalid_with_cltv_tx.vin.resize(1); invalid_with_cltv_tx.vin[0].prevout = COutPoint(spend_tx.GetId(), 1); invalid_with_cltv_tx.vin[0].nSequence = 0; invalid_with_cltv_tx.vout.resize(1); invalid_with_cltv_tx.vout[0].nValue = 11 * CENT; invalid_with_cltv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; // Sign std::vector vchSig; uint256 hash = SignatureHash( spend_tx.vout[1].scriptPubKey, CTransaction(invalid_with_cltv_tx), 0, SigHashType().withForkId(), spend_tx.vout[1].nValue); - BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); + BOOST_CHECK(coinbaseKey.SignECDSA(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101; ValidateCheckInputsForAllFlags(invalid_with_cltv_tx, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true); // Make it valid, and check again invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100; CValidationState state; CTransaction transaction(invalid_with_cltv_tx); PrecomputedTransactionData txdata(transaction); BOOST_CHECK(CheckInputs(transaction, state, pcoinsTip.get(), true, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr)); } // TEST CHECKSEQUENCEVERIFY { CMutableTransaction invalid_with_csv_tx; invalid_with_csv_tx.nVersion = 2; invalid_with_csv_tx.vin.resize(1); invalid_with_csv_tx.vin[0].prevout = COutPoint(spend_tx.GetId(), 2); invalid_with_csv_tx.vin[0].nSequence = 100; invalid_with_csv_tx.vout.resize(1); invalid_with_csv_tx.vout[0].nValue = 11 * CENT; invalid_with_csv_tx.vout[0].scriptPubKey = p2pk_scriptPubKey; // Sign std::vector vchSig; uint256 hash = SignatureHash( spend_tx.vout[2].scriptPubKey, CTransaction(invalid_with_csv_tx), 0, SigHashType().withForkId(), spend_tx.vout[2].nValue); - BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); + BOOST_CHECK(coinbaseKey.SignECDSA(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101; ValidateCheckInputsForAllFlags( invalid_with_csv_tx, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true); // Make it valid, and check again invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100; CValidationState state; CTransaction transaction(invalid_with_csv_tx); PrecomputedTransactionData txdata(transaction); BOOST_CHECK(CheckInputs(transaction, state, pcoinsTip.get(), true, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr)); } // TODO: add tests for remaining script flags { // Test a transaction with multiple inputs. CMutableTransaction tx; tx.nVersion = 1; tx.vin.resize(2); tx.vin[0].prevout = COutPoint(spend_tx.GetId(), 0); tx.vin[1].prevout = COutPoint(spend_tx.GetId(), 3); tx.vout.resize(1); tx.vout[0].nValue = 22 * CENT; tx.vout[0].scriptPubKey = p2pk_scriptPubKey; // Sign SignatureData sigdata; ProduceSignature( MutableTransactionSignatureCreator(&keystore, &tx, 0, 11 * CENT, SigHashType().withForkId()), spend_tx.vout[0].scriptPubKey, sigdata); UpdateTransaction(tx, 0, sigdata); ProduceSignature( MutableTransactionSignatureCreator(&keystore, &tx, 1, 11 * CENT, SigHashType().withForkId()), spend_tx.vout[3].scriptPubKey, sigdata); UpdateTransaction(tx, 1, sigdata); // This should be valid under all script flags ValidateCheckInputsForAllFlags(tx, 0, true, false); // Check that if the second input is invalid, but the first input is // valid, the transaction is not cached. // Invalidate vin[1] tx.vin[1].scriptSig = CScript(); CValidationState state; CTransaction transaction(tx); PrecomputedTransactionData txdata(transaction); // This transaction is now invalid because the second signature is // missing. BOOST_CHECK(!CheckInputs(transaction, state, pcoinsTip.get(), true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, true, txdata, nullptr)); // Make sure this transaction was not cached (ie becausethe first input // was valid) std::vector scriptchecks; BOOST_CHECK(CheckInputs(transaction, state, pcoinsTip.get(), true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, true, txdata, &scriptchecks)); // Should get 2 script checks back -- caching is on a whole-transaction // basis. BOOST_CHECK_EQUAL(scriptchecks.size(), 2); } } BOOST_AUTO_TEST_SUITE_END()