// Copyright (c) 2013 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 "consensus/validation.h" #include "data/sighash.json.h" #include "main.h" #include "random.h" #include "script/interpreter.h" #include "script/script.h" #include "serialize.h" #include "test/test_bitcoin.h" #include "util.h" #include "version.h" #include "sodium.h" #include #include #include "json/json_spirit_reader_template.h" #include "json/json_spirit_utils.h" #include "json/json_spirit_writer_template.h" using namespace json_spirit; extern Array read_json(const std::string& jsondata); // Old script.cpp SignatureHash function uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) { static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); if (nIn >= txTo.vin.size()) { printf("ERROR: SignatureHash(): nIn=%d out of range\n", nIn); return one; } CMutableTransaction txTmp(txTo); // In case concatenating two scripts ends up with two codeseparators, // or an extra one at the end, this prevents all those possible incompatibilities. scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR)); // Blank out other inputs' signatures for (unsigned int i = 0; i < txTmp.vin.size(); i++) txTmp.vin[i].scriptSig = CScript(); txTmp.vin[nIn].scriptSig = scriptCode; // Blank out some of the outputs if ((nHashType & 0x1f) == SIGHASH_NONE) { // Wildcard payee txTmp.vout.clear(); // Let the others update at will for (unsigned int i = 0; i < txTmp.vin.size(); i++) if (i != nIn) txTmp.vin[i].nSequence = 0; } else if ((nHashType & 0x1f) == SIGHASH_SINGLE) { // Only lock-in the txout payee at same index as txin unsigned int nOut = nIn; if (nOut >= txTmp.vout.size()) { printf("ERROR: SignatureHash(): nOut=%d out of range\n", nOut); return one; } txTmp.vout.resize(nOut+1); for (unsigned int i = 0; i < nOut; i++) txTmp.vout[i].SetNull(); // Let the others update at will for (unsigned int i = 0; i < txTmp.vin.size(); i++) if (i != nIn) txTmp.vin[i].nSequence = 0; } // Blank out other inputs completely, not recommended for open transactions if (nHashType & SIGHASH_ANYONECANPAY) { txTmp.vin[0] = txTmp.vin[nIn]; txTmp.vin.resize(1); } // Blank out the joinsplit signature. memset(&txTmp.joinSplitSig[0], 0, txTmp.joinSplitSig.size()); // Serialize and hash CHashWriter ss(SER_GETHASH, 0); ss << txTmp << nHashType; return ss.GetHash(); } void static RandomScript(CScript &script) { static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR}; script = CScript(); int ops = (insecure_rand() % 10); for (int i=0; i= 2) { for (int pour = 0; pour < pours; pour++) { JSDescription pourtx; if (insecure_rand() % 2 == 0) { pourtx.vpub_old = insecure_rand() % 100000000; } else { pourtx.vpub_new = insecure_rand() % 100000000; } pourtx.anchor = GetRandHash(); pourtx.nullifiers[0] = GetRandHash(); pourtx.nullifiers[1] = GetRandHash(); pourtx.ephemeralKey = GetRandHash(); pourtx.randomSeed = GetRandHash(); randombytes_buf(pourtx.ciphertexts[0].begin(), pourtx.ciphertexts[0].size()); randombytes_buf(pourtx.ciphertexts[1].begin(), pourtx.ciphertexts[1].size()); randombytes_buf(pourtx.proof.begin(), pourtx.proof.size()); pourtx.macs[0] = GetRandHash(); pourtx.macs[1] = GetRandHash(); tx.vjoinsplit.push_back(pourtx); } unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES]; crypto_sign_keypair(tx.joinSplitPubKey.begin(), joinSplitPrivKey); // TODO: #966. static const uint256 one(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); // Empty output script. CScript scriptCode; CTransaction signTx(tx); uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL); BOOST_CHECK(dataToBeSigned != one); assert(crypto_sign_detached(&tx.joinSplitSig[0], NULL, dataToBeSigned.begin(), 32, joinSplitPrivKey ) == 0); } } BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sighash_test) { seed_insecure_rand(false); #if defined(PRINT_SIGHASH_JSON) std::cout << "[\n"; std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n"; #endif int nRandomTests = 50000; #if defined(PRINT_SIGHASH_JSON) nRandomTests = 500; #endif for (int i=0; i> tx; CValidationState state; BOOST_CHECK_MESSAGE(CheckTransactionWithoutProofVerification(tx, state), strTest); BOOST_CHECK(state.IsValid()); std::vector raw = ParseHex(raw_script); scriptCode.insert(scriptCode.end(), raw.begin(), raw.end()); } catch (...) { BOOST_ERROR("Bad test, couldn't deserialize data: " << strTest); continue; } sh = SignatureHash(scriptCode, tx, nIn, nHashType); BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); } } BOOST_AUTO_TEST_SUITE_END()