sighash_tests.cpp
1 // Copyright (c) 2013-present The Bitcoin Core developers 2 // Distributed under the MIT software license, see the accompanying 3 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 5 #include <common/system.h> 6 #include <consensus/tx_check.h> 7 #include <consensus/validation.h> 8 #include <hash.h> 9 #include <script/interpreter.h> 10 #include <script/script.h> 11 #include <serialize.h> 12 #include <streams.h> 13 #include <test/data/sighash.json.h> 14 #include <test/util/common.h> 15 #include <test/util/json.h> 16 #include <test/util/random.h> 17 #include <test/util/setup_common.h> 18 #include <util/strencodings.h> 19 20 #include <iostream> 21 22 #include <boost/test/unit_test.hpp> 23 24 #include <univalue.h> 25 26 // Old script.cpp SignatureHash function 27 uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) 28 { 29 if (nIn >= txTo.vin.size()) 30 { 31 return uint256::ONE; 32 } 33 CMutableTransaction txTmp(txTo); 34 35 // In case concatenating two scripts ends up with two codeseparators, 36 // or an extra one at the end, this prevents all those possible incompatibilities. 37 FindAndDelete(scriptCode, CScript(OP_CODESEPARATOR)); 38 39 // Blank out other inputs' signatures 40 for (unsigned int i = 0; i < txTmp.vin.size(); i++) 41 txTmp.vin[i].scriptSig = CScript(); 42 txTmp.vin[nIn].scriptSig = scriptCode; 43 44 // Blank out some of the outputs 45 if ((nHashType & 0x1f) == SIGHASH_NONE) 46 { 47 // Wildcard payee 48 txTmp.vout.clear(); 49 50 // Let the others update at will 51 for (unsigned int i = 0; i < txTmp.vin.size(); i++) 52 if (i != nIn) 53 txTmp.vin[i].nSequence = 0; 54 } 55 else if ((nHashType & 0x1f) == SIGHASH_SINGLE) 56 { 57 // Only lock-in the txout payee at same index as txin 58 unsigned int nOut = nIn; 59 if (nOut >= txTmp.vout.size()) 60 { 61 return uint256::ONE; 62 } 63 txTmp.vout.resize(nOut+1); 64 for (unsigned int i = 0; i < nOut; i++) 65 txTmp.vout[i].SetNull(); 66 67 // Let the others update at will 68 for (unsigned int i = 0; i < txTmp.vin.size(); i++) 69 if (i != nIn) 70 txTmp.vin[i].nSequence = 0; 71 } 72 73 // Blank out other inputs completely, not recommended for open transactions 74 if (nHashType & SIGHASH_ANYONECANPAY) 75 { 76 txTmp.vin[0] = txTmp.vin[nIn]; 77 txTmp.vin.resize(1); 78 } 79 80 // Serialize and hash 81 HashWriter ss{}; 82 ss << TX_NO_WITNESS(txTmp) << nHashType; 83 return ss.GetHash(); 84 } 85 86 struct SigHashTest : BasicTestingSetup { 87 void RandomScript(CScript &script) { 88 static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR}; 89 script = CScript(); 90 int ops = (m_rng.randrange(10)); 91 for (int i=0; i<ops; i++) 92 script << oplist[m_rng.randrange(std::size(oplist))]; 93 } 94 95 void RandomTransaction(CMutableTransaction& tx, bool fSingle) 96 { 97 tx.version = m_rng.rand32(); 98 tx.vin.clear(); 99 tx.vout.clear(); 100 tx.nLockTime = (m_rng.randbool()) ? m_rng.rand32() : 0; 101 int ins = (m_rng.randbits(2)) + 1; 102 int outs = fSingle ? ins : (m_rng.randbits(2)) + 1; 103 for (int in = 0; in < ins; in++) { 104 tx.vin.emplace_back(); 105 CTxIn &txin = tx.vin.back(); 106 txin.prevout.hash = Txid::FromUint256(m_rng.rand256()); 107 txin.prevout.n = m_rng.randbits(2); 108 RandomScript(txin.scriptSig); 109 txin.nSequence = (m_rng.randbool()) ? m_rng.rand32() : std::numeric_limits<uint32_t>::max(); 110 } 111 for (int out = 0; out < outs; out++) { 112 tx.vout.emplace_back(); 113 CTxOut &txout = tx.vout.back(); 114 txout.nValue = RandMoney(m_rng); 115 RandomScript(txout.scriptPubKey); 116 } 117 } 118 }; // struct SigHashTest 119 120 BOOST_FIXTURE_TEST_SUITE(sighash_tests, SigHashTest) 121 122 BOOST_AUTO_TEST_CASE(sighash_test) 123 { 124 #if defined(PRINT_SIGHASH_JSON) 125 std::cout << "[\n"; 126 std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n"; 127 int nRandomTests = 500; 128 #else 129 int nRandomTests = 50000; 130 #endif 131 for (int i=0; i<nRandomTests; i++) { 132 int nHashType{int(m_rng.rand32())}; 133 CMutableTransaction txTo; 134 RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); 135 CScript scriptCode; 136 RandomScript(scriptCode); 137 int nIn = m_rng.randrange(txTo.vin.size()); 138 139 uint256 sh, sho; 140 sho = SignatureHashOld(scriptCode, CTransaction(txTo), nIn, nHashType); 141 sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, SigVersion::BASE); 142 #if defined(PRINT_SIGHASH_JSON) 143 DataStream ss; 144 ss << TX_WITH_WITNESS(txTo); 145 146 std::cout << "\t[\"" ; 147 std::cout << HexStr(ss) << "\", \""; 148 std::cout << HexStr(scriptCode) << "\", "; 149 std::cout << nIn << ", "; 150 std::cout << nHashType << ", \""; 151 std::cout << sho.GetHex() << "\"]"; 152 if (i+1 != nRandomTests) { 153 std::cout << ","; 154 } 155 std::cout << "\n"; 156 #endif 157 BOOST_CHECK(sh == sho); 158 } 159 #if defined(PRINT_SIGHASH_JSON) 160 std::cout << "]\n"; 161 #endif 162 } 163 164 // Goal: check that SignatureHash generates correct hash 165 BOOST_AUTO_TEST_CASE(sighash_from_data) 166 { 167 UniValue tests = read_json(json_tests::sighash); 168 169 for (unsigned int idx = 0; idx < tests.size(); idx++) { 170 const UniValue& test = tests[idx]; 171 std::string strTest = test.write(); 172 if (test.size() < 1) // Allow for extra stuff (useful for comments) 173 { 174 BOOST_ERROR("Bad test: " << strTest); 175 continue; 176 } 177 if (test.size() == 1) continue; // comment 178 179 std::string raw_tx, raw_script, sigHashHex; 180 int nIn, nHashType; 181 uint256 sh; 182 CTransactionRef tx; 183 CScript scriptCode = CScript(); 184 185 try { 186 // deserialize test data 187 raw_tx = test[0].get_str(); 188 raw_script = test[1].get_str(); 189 nIn = test[2].getInt<int>(); 190 nHashType = test[3].getInt<int>(); 191 sigHashHex = test[4].get_str(); 192 193 SpanReader{ParseHex(raw_tx)} >> TX_WITH_WITNESS(tx); 194 195 TxValidationState state; 196 BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest); 197 BOOST_CHECK(state.IsValid()); 198 199 std::vector<unsigned char> raw = ParseHex(raw_script); 200 scriptCode.insert(scriptCode.end(), raw.begin(), raw.end()); 201 } catch (...) { 202 BOOST_ERROR("Bad test, couldn't deserialize data: " << strTest); 203 continue; 204 } 205 206 sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, SigVersion::BASE); 207 BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); 208 } 209 } 210 211 BOOST_AUTO_TEST_CASE(sighash_caching) 212 { 213 // Get a script, transaction and parameters as inputs to the sighash function. 214 CScript scriptcode; 215 RandomScript(scriptcode); 216 CScript diff_scriptcode{scriptcode}; 217 diff_scriptcode << OP_1; 218 CMutableTransaction tx; 219 RandomTransaction(tx, /*fSingle=*/false); 220 const auto in_index{static_cast<uint32_t>(m_rng.randrange(tx.vin.size()))}; 221 const auto amount{m_rng.rand<CAmount>()}; 222 223 // Exercise the sighash function under both legacy and segwit v0. 224 for (const auto sigversion: {SigVersion::BASE, SigVersion::WITNESS_V0}) { 225 // For each, run it against all the 6 standard hash types and a few additional random ones. 226 std::vector<int32_t> hash_types{{SIGHASH_ALL, SIGHASH_SINGLE, SIGHASH_NONE, SIGHASH_ALL | SIGHASH_ANYONECANPAY, 227 SIGHASH_SINGLE | SIGHASH_ANYONECANPAY, SIGHASH_NONE | SIGHASH_ANYONECANPAY, 228 SIGHASH_ANYONECANPAY, 0, std::numeric_limits<int32_t>::max()}}; 229 for (int i{0}; i < 10; ++i) { 230 hash_types.push_back(i % 2 == 0 ? m_rng.rand<int8_t>() : m_rng.rand<int32_t>()); 231 } 232 233 // Reuse the same cache across script types. This must not cause any issue as the cached value for one hash type must never 234 // be confused for another (instantiating the cache within the loop instead would prevent testing this). 235 SigHashCache cache; 236 for (const auto hash_type: hash_types) { 237 const bool expect_one{sigversion == SigVersion::BASE && ((hash_type & 0x1f) == SIGHASH_SINGLE) && in_index >= tx.vout.size()}; 238 239 // The result of computing the sighash should be the same with or without cache. 240 const auto sighash_with_cache{SignatureHash(scriptcode, tx, in_index, hash_type, amount, sigversion, nullptr, &cache)}; 241 const auto sighash_no_cache{SignatureHash(scriptcode, tx, in_index, hash_type, amount, sigversion, nullptr, nullptr)}; 242 BOOST_CHECK_EQUAL(sighash_with_cache, sighash_no_cache); 243 244 // Calling the cached version again should return the same value again. 245 BOOST_CHECK_EQUAL(sighash_with_cache, SignatureHash(scriptcode, tx, in_index, hash_type, amount, sigversion, nullptr, &cache)); 246 247 // While here we might as well also check that the result for legacy is the same as for the old SignatureHash() function. 248 if (sigversion == SigVersion::BASE) { 249 BOOST_CHECK_EQUAL(sighash_with_cache, SignatureHashOld(scriptcode, CTransaction(tx), in_index, hash_type)); 250 } 251 252 // Calling with a different scriptcode (for instance in case a CODESEP is encountered) will not return the cache value but 253 // overwrite it. The sighash will always be different except in case of legacy SIGHASH_SINGLE bug. 254 const auto sighash_with_cache2{SignatureHash(diff_scriptcode, tx, in_index, hash_type, amount, sigversion, nullptr, &cache)}; 255 const auto sighash_no_cache2{SignatureHash(diff_scriptcode, tx, in_index, hash_type, amount, sigversion, nullptr, nullptr)}; 256 BOOST_CHECK_EQUAL(sighash_with_cache2, sighash_no_cache2); 257 if (!expect_one) { 258 BOOST_CHECK_NE(sighash_with_cache, sighash_with_cache2); 259 } else { 260 BOOST_CHECK_EQUAL(sighash_with_cache, sighash_with_cache2); 261 BOOST_CHECK_EQUAL(sighash_with_cache, uint256::ONE); 262 } 263 264 // Calling the cached version again should return the same value again. 265 BOOST_CHECK_EQUAL(sighash_with_cache2, SignatureHash(diff_scriptcode, tx, in_index, hash_type, amount, sigversion, nullptr, &cache)); 266 267 // And if we store a different value for this scriptcode and hash type it will return that instead. 268 { 269 HashWriter h{}; 270 h << 42; 271 cache.Store(hash_type, scriptcode, h); 272 const auto stored_hash{h.GetHash()}; 273 BOOST_CHECK(cache.Load(hash_type, scriptcode, h)); 274 const auto loaded_hash{h.GetHash()}; 275 BOOST_CHECK_EQUAL(stored_hash, loaded_hash); 276 } 277 278 // And using this mutated cache with the sighash function will return the new value (except in the legacy SIGHASH_SINGLE bug 279 // case in which it'll return 1). 280 if (!expect_one) { 281 BOOST_CHECK_NE(SignatureHash(scriptcode, tx, in_index, hash_type, amount, sigversion, nullptr, &cache), sighash_with_cache); 282 HashWriter h{}; 283 BOOST_CHECK(cache.Load(hash_type, scriptcode, h)); 284 h << hash_type; 285 const auto new_hash{h.GetHash()}; 286 BOOST_CHECK_EQUAL(SignatureHash(scriptcode, tx, in_index, hash_type, amount, sigversion, nullptr, &cache), new_hash); 287 } else { 288 BOOST_CHECK_EQUAL(SignatureHash(scriptcode, tx, in_index, hash_type, amount, sigversion, nullptr, &cache), uint256::ONE); 289 } 290 291 // Wipe the cache and restore the correct cached value for this scriptcode and hash_type before starting the next iteration. 292 HashWriter dummy{}; 293 cache.Store(hash_type, diff_scriptcode, dummy); 294 (void)SignatureHash(scriptcode, tx, in_index, hash_type, amount, sigversion, nullptr, &cache); 295 BOOST_CHECK(cache.Load(hash_type, scriptcode, dummy) || expect_one); 296 } 297 } 298 } 299 300 BOOST_AUTO_TEST_SUITE_END()