LCOV - code coverage report
Current view: top level - src/test - sighash_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 194 297 65.3 %
Date: 2025-02-23 09:33:43 Functions: 9 9 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2013 The Bitcoin Core developers
       2             : // Copyright (c) 2017-2022 The PIVX Core developers
       3             : // Distributed under the MIT/X11 software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include "test/test_pivx.h"
       7             : 
       8             : #include "test/data/sighash.json.h"
       9             : 
      10             : #include "consensus/tx_verify.h"
      11             : #include "serialize.h"
      12             : #include "script/script.h"
      13             : #include "script/interpreter.h"
      14             : #include "util/system.h"
      15             : #include "validation.h"
      16             : #include "version.h"
      17             : 
      18             : #include <iostream>
      19             : 
      20             : #include <boost/test/unit_test.hpp>
      21             : 
      22             : #include <univalue.h>
      23             : 
      24             : extern UniValue read_json(const std::string& jsondata);
      25             : 
      26             : // Old script.cpp SignatureHash function
      27       50000 : uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
      28             : {
      29       50000 :     if (nIn >= txTo.vin.size())
      30             :     {
      31           0 :         printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn);
      32           0 :         return UINT256_ONE;
      33             :     }
      34       50000 :     CMutableTransaction txTmp(txTo);
      35             : 
      36             :     // In case concatenating two scripts ends up with two codeseparators,
      37             :     // or an extra one at the end, this prevents all those possible incompatibilities.
      38       50000 :     scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR));
      39             : 
      40             :     // Blank out other inputs' signatures
      41      175079 :     for (unsigned int i = 0; i < txTmp.vin.size(); i++)
      42      125079 :         txTmp.vin[i].scriptSig = CScript();
      43       50000 :     txTmp.vin[nIn].scriptSig = scriptCode;
      44             : 
      45             :     // Blank out some of the outputs
      46       50000 :     if ((nHashType & 0x1f) == SIGHASH_NONE)
      47             :     {
      48             :         // Wildcard payee
      49        1526 :         txTmp.vout.clear();
      50             : 
      51             :         // Let the others update at will
      52        5375 :         for (unsigned int i = 0; i < txTmp.vin.size(); i++)
      53        3849 :             if (i != nIn)
      54        2323 :                 txTmp.vin[i].nSequence = 0;
      55             :     }
      56       48474 :     else if ((nHashType & 0x1f) == SIGHASH_SINGLE)
      57             :     {
      58             :         // Only lock-in the txout payee at same index as txin
      59        1532 :         unsigned int nOut = nIn;
      60        1532 :         if (nOut >= txTmp.vout.size())
      61             :         {
      62           0 :             printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut);
      63           0 :             return UINT256_ONE;
      64             :         }
      65        1532 :         txTmp.vout.resize(nOut+1);
      66        2672 :         for (unsigned int i = 0; i < nOut; i++)
      67        1140 :             txTmp.vout[i].SetNull();
      68             : 
      69             :         // Let the others update at will
      70        5323 :         for (unsigned int i = 0; i < txTmp.vin.size(); i++)
      71        3791 :             if (i != nIn)
      72        2259 :                 txTmp.vin[i].nSequence = 0;
      73             :     }
      74             : 
      75             :     // Blank out other inputs completely, not recommended for open transactions
      76       50000 :     if (nHashType & SIGHASH_ANYONECANPAY)
      77             :     {
      78       25008 :         txTmp.vin[0] = txTmp.vin[nIn];
      79       25008 :         txTmp.vin.resize(1);
      80             :     }
      81             : 
      82             :     // Serialize and hash
      83       50000 :     CHashWriter ss(SER_GETHASH, 0);
      84       50000 :     ss << txTmp << nHashType;
      85      100000 :     return ss.GetHash();
      86             : }
      87             : 
      88      352780 : void static RandomScript(CScript &script) {
      89      352780 :     static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR};
      90      352780 :     script = CScript();
      91      352780 :     int ops = (InsecureRandRange(10));
      92     1940310 :     for (int i=0; i<ops; i++)
      93     4410290 :         script << oplist[InsecureRandRange(sizeof(oplist)/sizeof(oplist[0]))];
      94      352780 : }
      95             : 
      96       55000 : void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
      97       55000 :     bool isSapling = !(InsecureRand32() % 7);
      98       55000 :     tx.nVersion = isSapling ? CTransaction::TxVersion::SAPLING : CTransaction::TxVersion::LEGACY;
      99       55000 :     tx.vin.clear();
     100       55000 :     tx.vout.clear();
     101       55000 :     tx.sapData->vShieldedSpend.clear();
     102       55000 :     tx.sapData->vShieldedOutput.clear();
     103       55000 :     tx.nLockTime = (InsecureRandBool()) ? InsecureRand32() : 0;
     104       55000 :     int ins = (InsecureRandBits(2)) + 1;
     105      108468 :     int outs = fSingle ? ins : (InsecureRandBits(2)) + 1;
     106      192577 :     for (int in = 0; in < ins; in++) {
     107      137577 :         tx.vin.emplace_back();
     108      137577 :         CTxIn &txin = tx.vin.back();
     109      137577 :         txin.prevout.hash = InsecureRand256();
     110      137577 :         txin.prevout.n = InsecureRandBits(2);
     111      137577 :         RandomScript(txin.scriptSig);
     112      206638 :         txin.nSequence = (InsecureRandBool()) ? InsecureRand32() : (unsigned int)-1;
     113             :     }
     114      192625 :     for (int out = 0; out < outs; out++) {
     115      137625 :         tx.vout.emplace_back();
     116      137625 :         CTxOut &txout = tx.vout.back();
     117      137625 :         txout.nValue = InsecureRandRange(100000000);
     118      137625 :         RandomScript(txout.scriptPubKey);
     119             :     }
     120             : 
     121       55000 :     if (tx.nVersion == 2) {
     122           0 :         int shielded_spends = (InsecureRandBits(2)) + 1;
     123           0 :         int shielded_outs = (InsecureRandBits(2)) + 1;
     124           0 :         tx.sapData->valueBalance = InsecureRandRange(100000000);;
     125           0 :         for (int spend = 0; spend < shielded_spends; spend++) {
     126           0 :             SpendDescription sdesc;
     127           0 :             sdesc.cv = GetRandHash();
     128           0 :             sdesc.anchor = GetRandHash();
     129           0 :             sdesc.nullifier = GetRandHash();
     130           0 :             sdesc.rk = GetRandHash();
     131           0 :             randombytes_buf(sdesc.zkproof.begin(), sdesc.zkproof.size());
     132           0 :             tx.sapData->vShieldedSpend.push_back(sdesc);
     133             :         }
     134           0 :         for (int out = 0; out < shielded_outs; out++) {
     135           0 :             OutputDescription odesc;
     136           0 :             odesc.cv = GetRandHash();
     137           0 :             odesc.cmu = GetRandHash();
     138           0 :             odesc.ephemeralKey = GetRandHash();
     139           0 :             randombytes_buf(odesc.encCiphertext.begin(), odesc.encCiphertext.size());
     140           0 :             randombytes_buf(odesc.outCiphertext.begin(), odesc.outCiphertext.size());
     141           0 :             randombytes_buf(odesc.zkproof.begin(), odesc.zkproof.size());
     142           0 :             tx.sapData->vShieldedOutput.push_back(odesc);
     143             :         }
     144             :     }
     145       55000 : }
     146             : 
     147             : BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup)
     148             : 
     149           2 : BOOST_AUTO_TEST_CASE(sighash_test)
     150             : {
     151             :     #if defined(PRINT_SIGHASH_JSON)
     152             :     std::cout << "[\n";
     153             :     std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n";
     154             :     #endif
     155           1 :     int nRandomTests = 50000;
     156             : 
     157             :     #if defined(PRINT_SIGHASH_JSON)
     158             :     nRandomTests = 500;
     159             :     #endif
     160       50001 :     for (int i=0; i<nRandomTests; i++) {
     161       50000 :         int nHashType = InsecureRand32();
     162       50000 :         CMutableTransaction txTo;
     163       50000 :         RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE);
     164      100000 :         CScript scriptCode;
     165       50000 :         RandomScript(scriptCode);
     166       50000 :         int nIn = InsecureRandRange(txTo.vin.size());
     167             : 
     168      100000 :         uint256 sh, sho;
     169      150000 :         sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType);
     170       93008 :         sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, txTo.GetRequiredSigVersion());
     171             :         #if defined(PRINT_SIGHASH_JSON)
     172             :         CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
     173             :         ss << txTo;
     174             :         std::cout << "\t[\"" ;
     175             :         std::cout << HexStr(ss) << "\", \"";
     176             :         std::cout << HexStr(scriptCode) << "\", ";
     177             :         std::cout << nIn << ", ";
     178             :         std::cout << nHashType << ", \"";
     179             :         std::cout << sho.GetHex() << "\"]";
     180             :         if (i+1 != nRandomTests) {
     181             :           std::cout << ",";
     182             :         }
     183             :         std::cout << "\n";
     184             :         #endif
     185       50000 :         if (txTo.nVersion < CTransaction::TxVersion::SAPLING) { // Sapling has a different signature.
     186       86016 :             BOOST_CHECK(sh == sho);
     187             :         }
     188             :     }
     189             :     #if defined(PRINT_SIGHASH_JSON)
     190             :     std::cout << "]\n";
     191             :     #endif
     192           1 : }
     193             : 
     194             : // Goal: check that SignatureHash generates correct hash
     195             : // TODO: Update with Sapling transactions..
     196           2 : BOOST_AUTO_TEST_CASE(sighash_from_data)
     197             : {
     198           3 :     UniValue tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash)));
     199             : 
     200         501 :     for (unsigned int idx = 0; idx < tests.size(); idx++) {
     201         500 :         UniValue test = tests[idx];
     202         999 :         std::string strTest = test.write();
     203         500 :         if (test.size() < 1) // Allow for extra stuff (useful for comments)
     204             :         {
     205           0 :             BOOST_ERROR("Bad test: " << strTest);
     206           1 :             continue;
     207             :         }
     208         500 :         if (test.size() == 1) continue; // comment
     209             : 
     210        1611 :         std::string raw_tx, raw_script, sigHashHex;
     211         499 :         int nIn, nHashType;
     212         499 :         uint256 sh;
     213         499 :         CTransactionRef tx;
     214         998 :         CScript scriptCode = CScript();
     215             : 
     216         499 :         try {
     217             :           // deserialize test data
     218         499 :           raw_tx = test[0].get_str();
     219         499 :           raw_script = test[1].get_str();
     220         499 :           nIn = test[2].get_int();
     221         499 :           nHashType = test[3].get_int();
     222         499 :           sigHashHex = test[4].get_str();
     223             : 
     224         499 :           uint256 sh;
     225         998 :           CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
     226         499 :           stream >> tx;
     227             : 
     228         998 :           CValidationState state;
     229         998 :           BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state, false), strTest);
     230         998 :           BOOST_CHECK(state.IsValid());
     231             : 
     232         998 :           std::vector<unsigned char> raw = ParseHex(raw_script);
     233         998 :           scriptCode.insert(scriptCode.end(), raw.begin(), raw.end());
     234           0 :         } catch (...) {
     235           0 :           BOOST_ERROR("Bad test, couldn't deserialize data: " << strTest);
     236           0 :           continue;
     237             :         }
     238             : 
     239         892 :         sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, tx->GetRequiredSigVersion());
     240        1497 :         BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest);
     241             : 
     242             :     }
     243           1 : }
     244             : 
     245           2 : BOOST_AUTO_TEST_CASE(malleated_tx)
     246             : {
     247           1 :     int nRandomTests = 5000;
     248           1 :     std::vector<uint256> vsh;
     249           1 :     std::vector<CScript> vScriptCode;
     250        5001 :     for (int t = 0; t < nRandomTests; t++) {
     251        5000 :         vsh.clear();
     252        5000 :         vScriptCode.clear();
     253             :         // create a random tx and get the signature hashes
     254       10000 :         CMutableTransaction _tx;
     255        5000 :         RandomTransaction(_tx, false);
     256       10000 :         const CTransaction tx(_tx);
     257       17498 :         for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     258       12498 :             vScriptCode.emplace_back();
     259       12498 :             RandomScript(vScriptCode.back());
     260       23311 :             vsh.emplace_back(SignatureHash(vScriptCode.back(), tx, nIn, SIGHASH_ALL, 0, tx.GetRequiredSigVersion()));
     261             :         }
     262             : 
     263             :         // -- create malleated txes
     264       10000 :         CMutableTransaction mtx = _tx;
     265       17498 :         for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     266       35809 :             BOOST_CHECK(vsh[nIn] == SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, tx.GetRequiredSigVersion()));
     267             :         }
     268             : 
     269             :         // remove one transparent input
     270        5000 :         if (mtx.vin.size() > 0) {
     271        5000 :             mtx.vin.pop_back();
     272       10000 :             CTransaction tx2(mtx);
     273       12498 :             for (int nIn = 0; nIn < (int) tx.vin.size() - 1; nIn++) {
     274       21472 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], tx2, nIn, SIGHASH_ALL, 0, tx2.GetRequiredSigVersion()));
     275             :             }
     276             :         }
     277             : 
     278             :         // change the prevout of the transparent input being signed
     279        5000 :         mtx = _tx;
     280       17498 :         for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     281       24996 :             while (mtx.vin[nIn].prevout.hash == tx.vin[nIn].prevout.hash)
     282       12498 :                 mtx.vin[nIn].prevout.hash = InsecureRand256();
     283       24996 :             CTransaction tx2(mtx);
     284       35809 :             BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], tx2, nIn, SIGHASH_ALL, 0, tx2.GetRequiredSigVersion()));
     285             :         }
     286             : 
     287             :         // add one random transparent input
     288        5000 :         {
     289        5000 :             mtx = _tx;
     290        5000 :             CTxIn in(InsecureRand256(), InsecureRandBits(2));
     291        5000 :             RandomScript(in.scriptSig);
     292        5000 :             in.nSequence = (InsecureRandBool()) ? InsecureRand32() : (unsigned int)-1;
     293        5000 :             mtx.vin.emplace_back(in);
     294       10000 :             CTransaction tx2(mtx);
     295       17498 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     296       35809 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], tx2, nIn, SIGHASH_ALL, 0, tx2.GetRequiredSigVersion()));
     297             :             }
     298             :         }
     299             : 
     300             :         // Shield inputs
     301        5000 :         if (tx.sapData && tx.sapData->vShieldedSpend.size() > 0) {
     302             :             // remove one spend
     303           0 :             mtx = _tx;
     304           0 :             mtx.sapData->vShieldedSpend.pop_back();
     305           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     306           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     307             :             }
     308             : 
     309             :             // modify one spend (cv, anchor, nullifier, rk, zkproof, spendAuthSig)
     310           0 :             int i = InsecureRandRange(tx.sapData->vShieldedSpend.size());
     311             : 
     312           0 :             mtx = _tx;
     313           0 :             while (mtx.sapData->vShieldedSpend[i].cv == tx.sapData->vShieldedSpend[i].cv)
     314           0 :                 mtx.sapData->vShieldedSpend[i].cv = GetRandHash();
     315           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     316           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     317             :             }
     318             : 
     319           0 :             mtx = _tx;
     320           0 :             while (mtx.sapData->vShieldedSpend[i].anchor == tx.sapData->vShieldedSpend[i].anchor)
     321           0 :                 mtx.sapData->vShieldedSpend[i].anchor = GetRandHash();
     322           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     323           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     324             :             }
     325             : 
     326           0 :             mtx = _tx;
     327           0 :             while (mtx.sapData->vShieldedSpend[i].nullifier == tx.sapData->vShieldedSpend[i].nullifier)
     328           0 :                 mtx.sapData->vShieldedSpend[i].nullifier = GetRandHash();
     329           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     330           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     331             :             }
     332             : 
     333           0 :             mtx = _tx;
     334           0 :             while (mtx.sapData->vShieldedSpend[i].rk == tx.sapData->vShieldedSpend[i].rk)
     335           0 :                 mtx.sapData->vShieldedSpend[i].rk = GetRandHash();
     336           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     337           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     338             :             }
     339             : 
     340           0 :             mtx = _tx;
     341           0 :             auto zkproof = &mtx.sapData->vShieldedSpend[i].zkproof;
     342           0 :             randombytes_buf(zkproof->begin(), zkproof->size());
     343           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     344           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     345             :             }
     346             : 
     347           0 :             mtx = _tx;
     348           0 :             auto spendAuthSig = &mtx.sapData->vShieldedSpend[i].spendAuthSig;
     349           0 :             randombytes_buf(spendAuthSig->begin(), spendAuthSig->size());
     350           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     351           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     352             :             }
     353             :         }
     354             : 
     355             :         // add one random spend
     356        5000 :         mtx = _tx;
     357        5000 :         SpendDescription sdesc;
     358        5000 :         sdesc.cv = GetRandHash();
     359        5000 :         sdesc.anchor = GetRandHash();
     360        5000 :         sdesc.nullifier = GetRandHash();
     361        5000 :         sdesc.rk = GetRandHash();
     362        5000 :         randombytes_buf(sdesc.zkproof.begin(), sdesc.zkproof.size());
     363        5000 :         mtx.sapData->vShieldedSpend.push_back(sdesc);
     364       17498 :         for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     365       24996 :             BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     366             :         }
     367             : 
     368             :         // Transparent outputs
     369        5000 :         if (mtx.vout.size() > 0) {
     370             :             // remove one
     371        5000 :             mtx = _tx;
     372        5000 :             mtx.vout.pop_back();
     373       10000 :             CTransaction tx2(mtx);
     374       17498 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     375       35809 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], tx2, nIn, SIGHASH_ALL, 0, tx2.GetRequiredSigVersion()));
     376             :             }
     377             : 
     378             :             // modify one (amount, script)
     379        5000 :             int i = InsecureRandRange(tx.vout.size());
     380        5000 :             mtx = _tx;
     381       10000 :             while (mtx.vout[i].nValue == tx.vout[i].nValue)
     382       11724 :                 mtx.vout[i].nValue = InsecureRandRange(100000000);
     383       10000 :             CTransaction tx3 = CTransaction(mtx);
     384       17498 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     385       35809 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], tx3, nIn, SIGHASH_ALL, 0, tx3.GetRequiredSigVersion()));
     386             :             }
     387             : 
     388        5000 :             mtx = _tx;
     389       10080 :             while (mtx.vout[i].scriptPubKey == tx.vout[i].scriptPubKey)
     390        5080 :                 RandomScript(mtx.vout[i].scriptPubKey);
     391       10000 :             CTransaction tx4 = CTransaction(mtx);
     392       17498 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     393       35809 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], tx4, nIn, SIGHASH_ALL, 0, tx4.GetRequiredSigVersion()));
     394             :             }
     395             :         }
     396             : 
     397             :         // add a random transparent output
     398        5000 :         {
     399        5000 :             mtx = _tx;
     400        5000 :             CTxOut out;
     401        5000 :             out.nValue = InsecureRandRange(100000000);
     402        5000 :             RandomScript(out.scriptPubKey);
     403        5000 :             mtx.vout.emplace_back(out);
     404       10000 :             CTransaction tx2(mtx);
     405       17498 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     406       35809 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], tx2, nIn, SIGHASH_ALL, 0, tx2.GetRequiredSigVersion()));
     407             :             }
     408             :         }
     409             : 
     410             :         // Shield outputs
     411        5000 :         if (tx.sapData && tx.sapData->vShieldedOutput.size() > 0) {
     412             :             // remove one output
     413           0 :             mtx = _tx;
     414           0 :             mtx.sapData->vShieldedOutput.pop_back();
     415           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     416           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     417             :             }
     418             : 
     419             :             // modify one output (cv, cmu, nullifier, ephemeralKey, encCiphertext, outCiphertext, zkproof)
     420           0 :             int i = InsecureRandRange(tx.sapData->vShieldedOutput.size());
     421             : 
     422           0 :             mtx = _tx;
     423           0 :             while (mtx.sapData->vShieldedOutput[i].cv == tx.sapData->vShieldedOutput[i].cv)
     424           0 :                 mtx.sapData->vShieldedOutput[i].cv = GetRandHash();
     425           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     426           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     427             :             }
     428             : 
     429           0 :             mtx = _tx;
     430           0 :             while (mtx.sapData->vShieldedOutput[i].cmu == tx.sapData->vShieldedOutput[i].cmu)
     431           0 :                 mtx.sapData->vShieldedOutput[i].cmu = GetRandHash();
     432           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     433           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     434             :             }
     435             : 
     436           0 :             mtx = _tx;
     437           0 :             while (mtx.sapData->vShieldedOutput[i].ephemeralKey == tx.sapData->vShieldedOutput[i].ephemeralKey)
     438           0 :                 mtx.sapData->vShieldedOutput[i].ephemeralKey = GetRandHash();
     439           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     440           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     441             :             }
     442             : 
     443           0 :             mtx = _tx;
     444           0 :             auto encCiphertext = &mtx.sapData->vShieldedOutput[i].encCiphertext;
     445           0 :             randombytes_buf(encCiphertext->begin(), encCiphertext->size());
     446           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     447           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     448             :             }
     449             : 
     450           0 :             mtx = _tx;
     451           0 :             auto outCiphertext = &mtx.sapData->vShieldedOutput[i].outCiphertext;
     452           0 :             randombytes_buf(outCiphertext->begin(), outCiphertext->size());
     453           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     454           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     455             :             }
     456             : 
     457           0 :             mtx = _tx;
     458           0 :             auto zkproof = &mtx.sapData->vShieldedOutput[i].zkproof;
     459           0 :             randombytes_buf(zkproof->begin(), zkproof->size());
     460           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     461           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     462             :             }
     463             :         }
     464             : 
     465             :         // add one random output
     466        5000 :         mtx = _tx;
     467        5000 :         OutputDescription odesc;
     468        5000 :         odesc.cv = GetRandHash();
     469        5000 :         odesc.cmu = GetRandHash();
     470        5000 :         odesc.ephemeralKey = GetRandHash();
     471        5000 :         randombytes_buf(odesc.encCiphertext.begin(), odesc.encCiphertext.size());
     472        5000 :         randombytes_buf(odesc.outCiphertext.begin(), odesc.outCiphertext.size());
     473        5000 :         randombytes_buf(odesc.zkproof.begin(), odesc.zkproof.size());
     474        5000 :         mtx.sapData->vShieldedOutput.push_back(odesc);
     475       17498 :         for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     476       24996 :             BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     477             :         }
     478             : 
     479             :         // modify the value balance
     480        5000 :         if (tx.sapData &&
     481        5000 :                 (!tx.sapData->vShieldedOutput.empty() || !tx.sapData->vShieldedSpend.empty())) {
     482           0 :             mtx = _tx;
     483           0 :             while (mtx.sapData->valueBalance == tx.sapData->valueBalance)
     484           0 :                 mtx.sapData->valueBalance = InsecureRandRange(100000000);
     485           0 :             for (int nIn = 0; nIn < (int) tx.vin.size(); nIn++) {
     486           0 :                 BOOST_CHECK(vsh[nIn] != SignatureHash(vScriptCode[nIn], CTransaction(mtx), nIn, SIGHASH_ALL, 0, SigVersion::SIGVERSION_SAPLING));
     487             :             }
     488             :         }
     489             : 
     490             :     }
     491           1 : }
     492             : 
     493             : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.14