// Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "arith_uint256.h" #include "blind.h" #include "coins.h" #include "uint256.h" #include "test/test_bitcoin.h" #include BOOST_FIXTURE_TEST_SUITE(blind_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(naive_blinding_test) { CCoinsView viewBase; CCoinsViewCache cache(&viewBase); CKey key1; CKey key2; CKey keyDummy; unsigned char k1[32] = {1,2,3}; unsigned char k2[32] = {22,33,44}; unsigned char kDummy[32] = {133,144,155}; key1.Set(&k1[0], &k1[32], true); key2.Set(&k2[0], &k2[32], true); keyDummy.Set(&kDummy[0], &kDummy[32], true); CPubKey pubkey1 = key1.GetPubKey(); CPubKey pubkey2 = key2.GetPubKey(); CPubKey pubkeyDummy = keyDummy.GetPubKey(); uint256 blind3, blind4, blindDummy; { CCoinsModifier tx1 = cache.ModifyCoins(ArithToUint256(1)); tx1->vout.resize(1); tx1->vout[0].nValue = 11; } { CCoinsModifier tx2 = cache.ModifyCoins(ArithToUint256(2)); tx2->vout.resize(2); tx2->vout[0].nValue = 111; } { // Build a transaction that spends 2 unblinded coins (11, 111), and produces a single blinded one (100) and fee (22). CMutableTransaction tx3; tx3.vin.resize(2); tx3.vin[0].prevout.hash = ArithToUint256(1); tx3.vin[0].prevout.n = 0; tx3.vin[1].prevout.hash = ArithToUint256(2); tx3.vin[1].prevout.n = 0; tx3.vout.resize(1); tx3.vout[0].nValue = 100; tx3.nTxFee = 22; BOOST_CHECK(cache.VerifyAmounts(tx3, tx3.nTxFee)); // Try to blind with a single output, which fails as its blinding factor ends up being zero. std::vector input_blinds; std::vector output_blinds; std::vector output_pubkeys; input_blinds.push_back(uint256()); input_blinds.push_back(uint256()); output_blinds.push_back(uint256()); output_pubkeys.push_back(pubkey1); BOOST_CHECK(!BlindOutputs(input_blinds, output_blinds, output_pubkeys, tx3)); // Add a dummy output. tx3.vout.resize(2); tx3.vout[1].nValue = 0; output_blinds.push_back(uint256()); output_pubkeys.push_back(pubkeyDummy); BOOST_CHECK(BlindOutputs(input_blinds, output_blinds, output_pubkeys, tx3)); BOOST_CHECK(!tx3.vout[0].nValue.IsAmount()); BOOST_CHECK(!tx3.vout[1].nValue.IsAmount()); BOOST_CHECK(cache.VerifyAmounts(tx3, tx3.nTxFee)); CAmount unblinded_amount; BOOST_CHECK(UnblindOutput(key2, tx3.vout[0], unblinded_amount, blind3) == 0); BOOST_CHECK(UnblindOutput(key1, tx3.vout[0], unblinded_amount, blind3) == 1); BOOST_CHECK(unblinded_amount == 100); BOOST_CHECK(UnblindOutput(keyDummy, tx3.vout[1], unblinded_amount, blindDummy) == 1); BOOST_CHECK(unblinded_amount == 0); CCoinsModifier in3 = cache.ModifyCoins(ArithToUint256(3)); in3->vout.resize(2); in3->vout[0] = tx3.vout[0]; in3->vout[1] = tx3.vout[1]; tx3.nTxFee--; BOOST_CHECK(!cache.VerifyAmounts(tx3, tx3.nTxFee)); } { // Build a transactions that spends an unblinded (111) and blinded (100) coin, and produces only unblinded coins (impossible) CMutableTransaction tx4; tx4.vin.resize(2); tx4.vin[0].prevout.hash = ArithToUint256(2); tx4.vin[0].prevout.n = 0; tx4.vin[1].prevout.hash = ArithToUint256(3); tx4.vin[1].prevout.n = 0; tx4.vout.resize(2); tx4.vout[0].nValue = 30; tx4.vout[1].nValue = 40; tx4.nTxFee = 100 + 111 - 30 - 40; BOOST_CHECK(!cache.VerifyAmounts(tx4, tx4.nTxFee)); // Spends a blinded coin with no blinded outputs to compensate. std::vector input_blinds; std::vector output_blinds; std::vector output_pubkeys; input_blinds.push_back(uint256()); input_blinds.push_back(blind3); output_blinds.push_back(uint256()); output_blinds.push_back(uint256()); output_pubkeys.push_back(CPubKey()); output_pubkeys.push_back(CPubKey()); BOOST_CHECK(!BlindOutputs(input_blinds, output_blinds, output_pubkeys, tx4)); // fails as there is no place to put the blinding factor } { // Build a transactions that spends an unblinded (111) and blinded (100) coin, and produces a blinded (30), unblinded (40), and blinded (50) coin and fee (91) CMutableTransaction tx4; tx4.vin.resize(2); tx4.vin[0].prevout.hash = ArithToUint256(2); tx4.vin[0].prevout.n = 0; tx4.vin[1].prevout.hash = ArithToUint256(3); tx4.vin[1].prevout.n = 0; tx4.vout.resize(3); tx4.vout[0].nValue = 30; tx4.vout[1].nValue = 40; tx4.vout[2].nValue = 50; tx4.nTxFee = 100 + 111 - 30 - 40 - 50; BOOST_CHECK(!cache.VerifyAmounts(tx4, tx4.nTxFee)); // Spends a blinded coin with no blinded outputs to compensate. std::vector input_blinds; std::vector output_blinds; std::vector output_pubkeys; input_blinds.push_back(uint256()); input_blinds.push_back(blind3); output_blinds.push_back(uint256()); output_blinds.push_back(uint256()); output_blinds.push_back(uint256()); output_pubkeys.push_back(pubkey2); output_pubkeys.push_back(CPubKey()); output_pubkeys.push_back(pubkey2); BOOST_CHECK(BlindOutputs(input_blinds, output_blinds, output_pubkeys, tx4)); BOOST_CHECK(!tx4.vout[0].nValue.IsAmount()); BOOST_CHECK(tx4.vout[1].nValue.IsAmount()); BOOST_CHECK(!tx4.vout[2].nValue.IsAmount()); BOOST_CHECK(cache.VerifyAmounts(tx4, tx4.nTxFee)); CAmount unblinded_amount; BOOST_CHECK(UnblindOutput(key1, tx4.vout[0], unblinded_amount, blind4) == 0); BOOST_CHECK(UnblindOutput(key2, tx4.vout[0], unblinded_amount, blind4) == 1); BOOST_CHECK(unblinded_amount == 30); BOOST_CHECK(UnblindOutput(key2, tx4.vout[2], unblinded_amount, blind4) == 1); BOOST_CHECK(unblinded_amount == 50); CCoinsModifier in4 = cache.ModifyCoins(ArithToUint256(4)); in4->vout.resize(3); in4->vout[0] = tx4.vout[0]; in4->vout[1] = tx4.vout[1]; in4->vout[2] = tx4.vout[2]; tx4.nTxFee--; BOOST_CHECK(!cache.VerifyAmounts(tx4, tx4.nTxFee)); } } BOOST_AUTO_TEST_SUITE_END()