diff --git a/src/gtest/test_joinsplit.cpp b/src/gtest/test_joinsplit.cpp index 979d0d518..dfde47c69 100644 --- a/src/gtest/test_joinsplit.cpp +++ b/src/gtest/test_joinsplit.cpp @@ -6,6 +6,9 @@ #include "zcash/prf.h" #include "util.h" +#include "streams.h" +#include "version.h" +#include "serialize.h" #include "zcash/JoinSplit.hpp" #include "zcash/Note.hpp" @@ -52,7 +55,7 @@ void test_full_api(ZCJoinSplit* js) JSOutput() // dummy output }; - boost::array output_notes; + boost::array output_notes; // Perform the proof proof = js->prove( @@ -91,7 +94,7 @@ void test_full_api(ZCJoinSplit* js) auto h_sig = js->h_sig(randomSeed, nullifiers, pubKeyHash); ZCNoteDecryption decryptor(recipient_key.receiving_key()); - auto note_pt = NotePlaintext::decrypt( + auto note_pt = SproutNotePlaintext::decrypt( decryptor, ciphertexts[0], ephemeralKey, @@ -101,7 +104,7 @@ void test_full_api(ZCJoinSplit* js) auto decrypted_note = note_pt.note(recipient_addr); - ASSERT_TRUE(decrypted_note.value == 10); + ASSERT_TRUE(decrypted_note.value() == 10); // Insert the commitments from the last tx into the tree tree.append(commitments[0]); @@ -127,7 +130,7 @@ void test_full_api(ZCJoinSplit* js) JSOutput() // dummy output }; - boost::array output_notes; + boost::array output_notes; // Perform the proof proof = js->prove( @@ -180,7 +183,7 @@ void invokeAPI( boost::array commitments; boost::array ciphertexts; - boost::array output_notes; + boost::array output_notes; ZCProof proof = js->prove( inputs, @@ -316,15 +319,15 @@ TEST(joinsplit, full_api_test) increment_note_witnesses(uint256(), witnesses, tree); SpendingKey sk = SpendingKey::random(); PaymentAddress addr = sk.address(); - Note note1(addr.a_pk, 100, random_uint256(), random_uint256()); + SproutNote note1(addr.a_pk, 100, random_uint256(), random_uint256()); increment_note_witnesses(note1.cm(), witnesses, tree); - Note note2(addr.a_pk, 100, random_uint256(), random_uint256()); + SproutNote note2(addr.a_pk, 100, random_uint256(), random_uint256()); increment_note_witnesses(note2.cm(), witnesses, tree); - Note note3(addr.a_pk, 2100000000000001, random_uint256(), random_uint256()); + SproutNote note3(addr.a_pk, 2100000000000001, random_uint256(), random_uint256()); increment_note_witnesses(note3.cm(), witnesses, tree); - Note note4(addr.a_pk, 1900000000000000, random_uint256(), random_uint256()); + SproutNote note4(addr.a_pk, 1900000000000000, random_uint256(), random_uint256()); increment_note_witnesses(note4.cm(), witnesses, tree); - Note note5(addr.a_pk, 1900000000000000, random_uint256(), random_uint256()); + SproutNote note5(addr.a_pk, 1900000000000000, random_uint256(), random_uint256()); increment_note_witnesses(note5.cm(), witnesses, tree); // Should work @@ -523,7 +526,7 @@ TEST(joinsplit, note_plaintexts) ZCNoteEncryption encryptor(h_sig); uint256 epk = encryptor.get_epk(); - Note note(a_pk, + SproutNote note(a_pk, 1945813, random_uint256(), random_uint256() @@ -531,19 +534,52 @@ TEST(joinsplit, note_plaintexts) boost::array memo; - NotePlaintext note_pt(note, memo); + SproutNotePlaintext note_pt(note, memo); ZCNoteEncryption::Ciphertext ct = note_pt.encrypt(encryptor, pk_enc); ZCNoteDecryption decryptor(sk_enc); - auto decrypted = NotePlaintext::decrypt(decryptor, ct, epk, h_sig, 0); + auto decrypted = SproutNotePlaintext::decrypt(decryptor, ct, epk, h_sig, 0); auto decrypted_note = decrypted.note(addr_pk); ASSERT_TRUE(decrypted_note.a_pk == note.a_pk); ASSERT_TRUE(decrypted_note.rho == note.rho); ASSERT_TRUE(decrypted_note.r == note.r); - ASSERT_TRUE(decrypted_note.value == note.value); + ASSERT_TRUE(decrypted_note.value() == note.value()); - ASSERT_TRUE(decrypted.memo == note_pt.memo); + ASSERT_TRUE(decrypted.memo() == note_pt.memo()); + + // Check serialization of note plaintext + CDataStream ss(SER_DISK, PROTOCOL_VERSION); + ss << note_pt; + SproutNotePlaintext note_pt2; + ss >> note_pt2; + ASSERT_EQ(note_pt.value(), note.value()); + ASSERT_EQ(note_pt.value(), note_pt2.value()); + ASSERT_EQ(note_pt.memo(), note_pt2.memo()); + ASSERT_EQ(note_pt.rho, note_pt2.rho); + ASSERT_EQ(note_pt.r, note_pt2.r); +} + +TEST(joinsplit, note_class) +{ + uint252 a_sk = uint252(uint256S("f6da8716682d600f74fc16bd0187faad6a26b4aa4c24d5c055b216d94516840e")); + uint256 a_pk = PRF_addr_a_pk(a_sk); + uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk); + uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc); + PaymentAddress addr_pk(a_pk, pk_enc); + + SproutNote note(a_pk, + 1945813, + random_uint256(), + random_uint256()); + + SproutNote clone = note; + ASSERT_NE(¬e, &clone); + ASSERT_EQ(note.value(), clone.value()); + ASSERT_EQ(note.cm(), clone.cm()); + ASSERT_EQ(note.rho, clone.rho); + ASSERT_EQ(note.r, clone.r); + ASSERT_EQ(note.a_pk, clone.a_pk); } diff --git a/src/gtest/test_transaction.cpp b/src/gtest/test_transaction.cpp index fb68fd35c..0f78fcb39 100644 --- a/src/gtest/test_transaction.cpp +++ b/src/gtest/test_transaction.cpp @@ -15,7 +15,7 @@ TEST(Transaction, JSDescriptionRandomized) { libzcash::SpendingKey k = libzcash::SpendingKey::random(); libzcash::PaymentAddress addr = k.address(); - libzcash::Note note(addr.a_pk, 100, uint256(), uint256()); + libzcash::SproutNote note(addr.a_pk, 100, uint256(), uint256()); // commitment from coin uint256 commitment = note.cm(); diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 9bcc0e8a0..70c308380 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -20,7 +20,7 @@ JSDescription::JSDescription(ZCJoinSplit& params, uint256 *esk // payment disclosure ) : vpub_old(vpub_old), vpub_new(vpub_new), anchor(anchor) { - boost::array notes; + boost::array notes; proof = params.prove( inputs, diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 8225fce5d..c51cd1fb2 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -204,7 +204,7 @@ uint256 appendRandomCommitment(ZCIncrementalMerkleTree &tree) libzcash::SpendingKey k = libzcash::SpendingKey::random(); libzcash::PaymentAddress addr = k.address(); - libzcash::Note note(addr.a_pk, 0, uint256(), uint256()); + libzcash::SproutNote note(addr.a_pk, 0, uint256(), uint256()); auto cm = note.cm(); tree.append(cm); diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index 81d8e3a62..54ff5337a 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -1183,7 +1183,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals) BOOST_CHECK( string(e.what()).find("anchor is null")!= string::npos); } - info.notes.push_back(Note()); + info.notes.push_back(SproutNote()); try { proxy.perform_joinsplit(info); } catch (const std::runtime_error & e) { @@ -1721,7 +1721,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_internals) BOOST_CHECK( string(e.what()).find("anchor is null")!= string::npos); } - info.notes.push_back(Note()); + info.notes.push_back(SproutNote()); try { proxy.perform_joinsplit(info); BOOST_FAIL("Should have caused an error"); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 767f9f75f..4702f10e5 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -345,7 +345,7 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification) libzcash::SpendingKey k = libzcash::SpendingKey::random(); libzcash::PaymentAddress addr = k.address(); - libzcash::Note note(addr.a_pk, 100, uint256(), uint256()); + libzcash::SproutNote note(addr.a_pk, 100, uint256(), uint256()); // commitment from coin uint256 commitment = note.cm(); diff --git a/src/utiltest.cpp b/src/utiltest.cpp index 4599cec3c..e1b7b8275 100644 --- a/src/utiltest.cpp +++ b/src/utiltest.cpp @@ -38,8 +38,6 @@ CWalletTx GetValidReceive(ZCJoinSplit& params, libzcash::JSOutput(sk.address(), value) }; - boost::array output_notes; - // Prepare JoinSplits uint256 rt; JSDescription jsdesc {params, mtx.joinSplitPubKey, rt, @@ -63,12 +61,12 @@ CWalletTx GetValidReceive(ZCJoinSplit& params, return wtx; } -libzcash::Note GetNote(ZCJoinSplit& params, +libzcash::SproutNote GetNote(ZCJoinSplit& params, const libzcash::SpendingKey& sk, const CTransaction& tx, size_t js, size_t n) { ZCNoteDecryption decryptor {sk.receiving_key()}; auto hSig = tx.vjoinsplit[js].h_sig(params, tx.joinSplitPubKey); - auto note_pt = libzcash::NotePlaintext::decrypt( + auto note_pt = libzcash::SproutNotePlaintext::decrypt( decryptor, tx.vjoinsplit[js].ciphertexts[n], tx.vjoinsplit[js].ephemeralKey, @@ -79,7 +77,7 @@ libzcash::Note GetNote(ZCJoinSplit& params, CWalletTx GetValidSpend(ZCJoinSplit& params, const libzcash::SpendingKey& sk, - const libzcash::Note& note, CAmount value) { + const libzcash::SproutNote& note, CAmount value) { CMutableTransaction mtx; mtx.vout.resize(2); mtx.vout[0].nValue = value; @@ -98,14 +96,14 @@ CWalletTx GetValidSpend(ZCJoinSplit& params, libzcash::JSInput dummyin; { - if (note.value > value) { + if (note.value() > value) { libzcash::SpendingKey dummykey = libzcash::SpendingKey::random(); libzcash::PaymentAddress dummyaddr = dummykey.address(); - dummyout = libzcash::JSOutput(dummyaddr, note.value - value); - } else if (note.value < value) { + dummyout = libzcash::JSOutput(dummyaddr, note.value() - value); + } else if (note.value() < value) { libzcash::SpendingKey dummykey = libzcash::SpendingKey::random(); libzcash::PaymentAddress dummyaddr = dummykey.address(); - libzcash::Note dummynote(dummyaddr.a_pk, (value - note.value), uint256(), uint256()); + libzcash::SproutNote dummynote(dummyaddr.a_pk, (value - note.value()), uint256(), uint256()); tree.append(dummynote.cm()); dummyin = libzcash::JSInput(tree.witness(), dummynote, dummykey); } @@ -123,8 +121,6 @@ CWalletTx GetValidSpend(ZCJoinSplit& params, libzcash::JSOutput() // dummy output }; - boost::array output_notes; - // Prepare JoinSplits uint256 rt = tree.root(); JSDescription jsdesc {params, mtx.joinSplitPubKey, rt, diff --git a/src/utiltest.h b/src/utiltest.h index 8cfa60d06..d9da2a1de 100644 --- a/src/utiltest.h +++ b/src/utiltest.h @@ -10,9 +10,9 @@ CWalletTx GetValidReceive(ZCJoinSplit& params, const libzcash::SpendingKey& sk, CAmount value, bool randomInputs); -libzcash::Note GetNote(ZCJoinSplit& params, +libzcash::SproutNote GetNote(ZCJoinSplit& params, const libzcash::SpendingKey& sk, const CTransaction& tx, size_t js, size_t n); CWalletTx GetValidSpend(ZCJoinSplit& params, const libzcash::SpendingKey& sk, - const libzcash::Note& note, CAmount value); + const libzcash::SproutNote& note, CAmount value); diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index d029c79c5..2c9cdcb1d 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -455,22 +455,22 @@ bool AsyncRPCOperation_mergetoaddress::main_impl() ZCNoteDecryption decryptor(changeKey.receiving_key()); auto hSig = prevJoinSplit.h_sig(*pzcashParams, tx_.joinSplitPubKey); try { - NotePlaintext plaintext = NotePlaintext::decrypt( + SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt( decryptor, prevJoinSplit.ciphertexts[changeOutputIndex], prevJoinSplit.ephemeralKey, hSig, (unsigned char)changeOutputIndex); - Note note = plaintext.note(changeAddress); + SproutNote note = plaintext.note(changeAddress); info.notes.push_back(note); info.zkeys.push_back(changeKey); - jsInputValue += plaintext.value; + jsInputValue += plaintext.value(); LogPrint("zrpcunsafe", "%s: spending change (amount=%s)\n", getId(), - FormatMoney(plaintext.value)); + FormatMoney(plaintext.value())); } catch (const std::exception& e) { throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Error decrypting output note of previous JoinSplit: %s", e.what())); @@ -481,7 +481,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl() // // Consume spendable non-change notes // - std::vector vInputNotes; + std::vector vInputNotes; std::vector vInputZKeys; std::vector vOutPoints; std::vector> vInputWitnesses; @@ -490,7 +490,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl() while (numInputsNeeded++ < ZC_NUM_JS_INPUTS && zInputsDeque.size() > 0) { MergeToAddressInputNote t = zInputsDeque.front(); JSOutPoint jso = std::get<0>(t); - Note note = std::get<1>(t); + SproutNote note = std::get<1>(t); CAmount noteFunds = std::get<2>(t); SpendingKey zkey = std::get<3>(t); zInputsDeque.pop_front(); @@ -753,7 +753,7 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit( getId(), tx_.vjoinsplit.size(), FormatMoney(info.vpub_old), FormatMoney(info.vpub_new), - FormatMoney(info.vjsin[0].note.value), FormatMoney(info.vjsin[1].note.value), + FormatMoney(info.vjsin[0].note.value()), FormatMoney(info.vjsin[1].note.value()), FormatMoney(info.vjsout[0].value), FormatMoney(info.vjsout[1].value)); // Generate the proof, this can take over a minute. diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.h b/src/wallet/asyncrpcoperation_mergetoaddress.h index 34548a5ba..9b291cdf6 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.h +++ b/src/wallet/asyncrpcoperation_mergetoaddress.h @@ -28,7 +28,7 @@ using namespace libzcash; typedef std::tuple MergeToAddressInputUTXO; // Input JSOP is a tuple of JSOutpoint, note, amount, spending key -typedef std::tuple MergeToAddressInputNote; +typedef std::tuple MergeToAddressInputNote; // A recipient is a tuple of address, memo (optional if zaddr) typedef std::tuple MergeToAddressRecipient; @@ -37,7 +37,7 @@ typedef std::tuple MergeToAddressRecipient; struct MergeToAddressJSInfo { std::vector vjsin; std::vector vjsout; - std::vector notes; + std::vector notes; std::vector zkeys; CAmount vpub_old = 0; CAmount vpub_new = 0; diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 35c5fcfcb..567fb7248 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -571,21 +571,21 @@ bool AsyncRPCOperation_sendmany::main_impl() { ZCNoteDecryption decryptor(spendingkey_.receiving_key()); auto hSig = prevJoinSplit.h_sig(*pzcashParams, tx_.joinSplitPubKey); try { - NotePlaintext plaintext = NotePlaintext::decrypt( + SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt( decryptor, prevJoinSplit.ciphertexts[changeOutputIndex], prevJoinSplit.ephemeralKey, hSig, (unsigned char) changeOutputIndex); - Note note = plaintext.note(frompaymentaddress_); + SproutNote note = plaintext.note(frompaymentaddress_); info.notes.push_back(note); - jsInputValue += plaintext.value; + jsInputValue += plaintext.value(); LogPrint("zrpcunsafe", "%s: spending change (amount=%s)\n", getId(), - FormatMoney(plaintext.value) + FormatMoney(plaintext.value()) ); } catch (const std::exception& e) { @@ -597,7 +597,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { // // Consume spendable non-change notes // - std::vector vInputNotes; + std::vector vInputNotes; std::vector vOutPoints; std::vector> vInputWitnesses; uint256 inputAnchor; @@ -605,7 +605,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { while (numInputsNeeded++ < ZC_NUM_JS_INPUTS && zInputsDeque.size() > 0) { SendManyInputJSOP t = zInputsDeque.front(); JSOutPoint jso = std::get<0>(t); - Note note = std::get<1>(t); + SproutNote note = std::get<1>(t); CAmount noteFunds = std::get<2>(t); zInputsDeque.pop_front(); @@ -877,21 +877,21 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) { bool AsyncRPCOperation_sendmany::find_unspent_notes() { - std::vector entries; + std::vector entries; { LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->GetFilteredNotes(entries, fromaddress_, mindepth_); } - for (CNotePlaintextEntry & entry : entries) { - z_inputs_.push_back(SendManyInputJSOP(entry.jsop, entry.plaintext.note(frompaymentaddress_), CAmount(entry.plaintext.value))); - std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end()); + for (CSproutNotePlaintextEntry & entry : entries) { + z_inputs_.push_back(SendManyInputJSOP(entry.jsop, entry.plaintext.note(frompaymentaddress_), CAmount(entry.plaintext.value()))); + std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end()); LogPrint("zrpcunsafe", "%s: found unspent note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n", getId(), entry.jsop.hash.ToString().substr(0, 10), entry.jsop.js, int(entry.jsop.n), // uint8_t - FormatMoney(entry.plaintext.value), + FormatMoney(entry.plaintext.value()), HexStr(data).substr(0, 10) ); } @@ -968,7 +968,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit( getId(), tx_.vjoinsplit.size(), FormatMoney(info.vpub_old), FormatMoney(info.vpub_new), - FormatMoney(info.vjsin[0].note.value), FormatMoney(info.vjsin[1].note.value), + FormatMoney(info.vjsin[0].note.value()), FormatMoney(info.vjsin[1].note.value()), FormatMoney(info.vjsout[0].value), FormatMoney(info.vjsout[1].value) ); diff --git a/src/wallet/asyncrpcoperation_sendmany.h b/src/wallet/asyncrpcoperation_sendmany.h index 113f11f49..97c4533f1 100644 --- a/src/wallet/asyncrpcoperation_sendmany.h +++ b/src/wallet/asyncrpcoperation_sendmany.h @@ -31,14 +31,14 @@ typedef std::tuple SendManyRecipient; typedef std::tuple SendManyInputUTXO; // Input JSOP is a tuple of JSOutpoint, note and amount -typedef std::tuple SendManyInputJSOP; +typedef std::tuple SendManyInputJSOP; // Package of info which is passed to perform_joinsplit methods. struct AsyncJoinSplitInfo { std::vector vjsin; std::vector vjsout; - std::vector notes; + std::vector notes; CAmount vpub_old = 0; CAmount vpub_new = 0; }; diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp index b7ace4dd5..dcadc6a78 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp @@ -341,7 +341,7 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf getId(), tx_.vjoinsplit.size(), FormatMoney(info.vpub_old), FormatMoney(info.vpub_new), - FormatMoney(info.vjsin[0].note.value), FormatMoney(info.vjsin[1].note.value), + FormatMoney(info.vjsin[0].note.value()), FormatMoney(info.vjsin[1].note.value()), FormatMoney(info.vjsout[0].value), FormatMoney(info.vjsout[1].value) ); diff --git a/src/wallet/gtest/test_wallet.cpp b/src/wallet/gtest/test_wallet.cpp index e976e4ae4..18df6feff 100644 --- a/src/wallet/gtest/test_wallet.cpp +++ b/src/wallet/gtest/test_wallet.cpp @@ -72,13 +72,13 @@ CWalletTx GetValidReceive(const libzcash::SpendingKey& sk, CAmount value, bool r return GetValidReceive(*params, sk, value, randomInputs); } -libzcash::Note GetNote(const libzcash::SpendingKey& sk, +libzcash::SproutNote GetNote(const libzcash::SpendingKey& sk, const CTransaction& tx, size_t js, size_t n) { return GetNote(*params, sk, tx, js, n); } CWalletTx GetValidSpend(const libzcash::SpendingKey& sk, - const libzcash::Note& note, CAmount value) { + const libzcash::SproutNote& note, CAmount value) { return GetValidSpend(*params, sk, note, value); } @@ -155,7 +155,7 @@ TEST(wallet_tests, find_unspent_notes) { EXPECT_FALSE(wallet.IsSpent(nullifier)); // We currently have an unspent and unconfirmed note in the wallet (depth of -1) - std::vector entries; + std::vector entries; wallet.GetFilteredNotes(entries, "", 0); EXPECT_EQ(0, entries.size()); entries.clear(); diff --git a/src/wallet/rpcdisclosure.cpp b/src/wallet/rpcdisclosure.cpp index 539cf4b2a..d4f87ab39 100644 --- a/src/wallet/rpcdisclosure.cpp +++ b/src/wallet/rpcdisclosure.cpp @@ -274,16 +274,16 @@ UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp) CDataStream ssPlain(SER_NETWORK, PROTOCOL_VERSION); ssPlain << plaintext; - NotePlaintext npt; + SproutNotePlaintext npt; ssPlain >> npt; - string memoHexString = HexStr(npt.memo.data(), npt.memo.data() + npt.memo.size()); + string memoHexString = HexStr(npt.memo().data(), npt.memo().data() + npt.memo().size()); o.push_back(Pair("memo", memoHexString)); - o.push_back(Pair("value", ValueFromAmount(npt.value))); + o.push_back(Pair("value", ValueFromAmount(npt.value()))); // Check the blockchain commitment matches decrypted note commitment uint256 cm_blockchain = jsdesc.commitments[pd.payload.n]; - Note note = npt.note(zaddr); + SproutNote note = npt.note(zaddr); uint256 cm_decrypted = note.cm(); bool cm_match = (cm_decrypted == cm_blockchain); o.push_back(Pair("commitmentMatch", cm_match)); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ead413296..8cdc3a092 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2537,9 +2537,9 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) UniValue results(UniValue::VARR); if (zaddrs.size() > 0) { - std::vector entries; + std::vector entries; pwalletMain->GetUnspentFilteredNotes(entries, zaddrs, nMinDepth, nMaxDepth, !fIncludeWatchonly); - for (CUnspentNotePlaintextEntry & entry : entries) { + for (CUnspentSproutNotePlaintextEntry & entry : entries) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid",entry.jsop.hash.ToString())); obj.push_back(Pair("jsindex", (int)entry.jsop.js )); @@ -2547,8 +2547,8 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) obj.push_back(Pair("confirmations", entry.nHeight)); obj.push_back(Pair("spendable", pwalletMain->HaveSpendingKey(entry.address))); obj.push_back(Pair("address", CZCPaymentAddress(entry.address).ToString())); - obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value)))); - std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end()); + obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value())))); + std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end()); obj.push_back(Pair("memo", HexStr(data))); results.push_back(obj); } @@ -2807,7 +2807,7 @@ UniValue zc_raw_receive(const UniValue& params, bool fHelp) ZCNoteDecryption decryptor(k.receiving_key()); - NotePlaintext npt = NotePlaintext::decrypt( + SproutNotePlaintext npt = SproutNotePlaintext::decrypt( decryptor, ct, epk, @@ -2815,7 +2815,7 @@ UniValue zc_raw_receive(const UniValue& params, bool fHelp) nonce ); PaymentAddress payment_addr = k.address(); - Note decrypted_note = npt.note(payment_addr); + SproutNote decrypted_note = npt.note(payment_addr); assert(pwalletMain != NULL); std::vector> witnesses; @@ -2831,7 +2831,7 @@ UniValue zc_raw_receive(const UniValue& params, bool fHelp) ss << npt; UniValue result(UniValue::VOBJ); - result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value))); + result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value()))); result.push_back(Pair("note", HexStr(ss.begin(), ss.end()))); result.push_back(Pair("exists", (bool) witnesses[0])); return result; @@ -2889,7 +2889,7 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp) std::vector vjsin; std::vector vjsout; - std::vector notes; + std::vector notes; std::vector keys; std::vector commitments; @@ -2899,7 +2899,7 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp) keys.push_back(k); - NotePlaintext npt; + SproutNotePlaintext npt; { CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION); @@ -2907,7 +2907,7 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp) } PaymentAddress addr = k.address(); - Note note = npt.note(addr); + SproutNote note = npt.note(addr); notes.push_back(note); commitments.push_back(note.cm()); } @@ -3173,11 +3173,11 @@ CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ign CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) { CAmount balance = 0; - std::vector entries; + std::vector entries; LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->GetFilteredNotes(entries, address, minDepth, true, ignoreUnspendable); for (auto & entry : entries) { - balance += CAmount(entry.plaintext.value); + balance += CAmount(entry.plaintext.value()); } return balance; } @@ -3233,13 +3233,13 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) UniValue result(UniValue::VARR); - std::vector entries; + std::vector entries; pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false, false); - for (CNotePlaintextEntry & entry : entries) { + for (CSproutNotePlaintextEntry & entry : entries) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid",entry.jsop.hash.ToString())); - obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value)))); - std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end()); + obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value())))); + std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end()); obj.push_back(Pair("memo", HexStr(data))); // (txid, jsindex, jsoutindex) is needed to globally identify a note obj.push_back(Pair("jsindex", entry.jsop.js)); @@ -4138,13 +4138,13 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp) if (useAny || useAnyNote || zaddrs.size() > 0) { // Get available notes - std::vector entries; + std::vector entries; pwalletMain->GetFilteredNotes(entries, zaddrs); // Find unspent notes and update estimated size - for (CNotePlaintextEntry& entry : entries) { + for (CSproutNotePlaintextEntry& entry : entries) { noteCounter++; - CAmount nValue = entry.plaintext.value; + CAmount nValue = entry.plaintext.value(); if (!maxedOutNotesFlag) { // If we haven't added any notes yet and the merge is to a diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index d6d0a274a..448dd50e7 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1264,7 +1264,7 @@ boost::optional CWallet::GetNoteNullifier(const JSDescription& jsdesc, uint8_t n) const { boost::optional ret; - auto note_pt = libzcash::NotePlaintext::decrypt( + auto note_pt = libzcash::SproutNotePlaintext::decrypt( dec, jsdesc.ciphertexts[n], jsdesc.ephemeralKey, @@ -3712,7 +3712,7 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee) * Find notes in the wallet filtered by payment address, min depth and ability to spend. * These notes are decrypted and added to the output parameter vector, outEntries. */ -void CWallet::GetFilteredNotes(std::vector & outEntries, std::string address, int minDepth, bool ignoreSpent, bool ignoreUnspendable) +void CWallet::GetFilteredNotes(std::vector & outEntries, std::string address, int minDepth, bool ignoreSpent, bool ignoreUnspendable) { std::set filterAddresses; @@ -3728,7 +3728,7 @@ void CWallet::GetFilteredNotes(std::vector & outEntries, st * These notes are decrypted and added to the output parameter vector, outEntries. */ void CWallet::GetFilteredNotes( - std::vector& outEntries, + std::vector& outEntries, std::set& filterAddresses, int minDepth, bool ignoreSpent, @@ -3786,14 +3786,14 @@ void CWallet::GetFilteredNotes( // determine amount of funds in the note auto hSig = wtx.vjoinsplit[i].h_sig(*pzcashParams, wtx.joinSplitPubKey); try { - NotePlaintext plaintext = NotePlaintext::decrypt( + SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt( decryptor, wtx.vjoinsplit[i].ciphertexts[j], wtx.vjoinsplit[i].ephemeralKey, hSig, (unsigned char) j); - outEntries.push_back(CNotePlaintextEntry{jsop, pa, plaintext}); + outEntries.push_back(CSproutNotePlaintextEntry{jsop, pa, plaintext}); } catch (const note_decryption_failed &err) { // Couldn't decrypt with this spending key @@ -3809,7 +3809,7 @@ void CWallet::GetFilteredNotes( /* Find unspent notes filtered by payment address, min depth and max depth */ void CWallet::GetUnspentFilteredNotes( - std::vector& outEntries, + std::vector& outEntries, std::set& filterAddresses, int minDepth, int maxDepth, @@ -3862,14 +3862,14 @@ void CWallet::GetUnspentFilteredNotes( // determine amount of funds in the note auto hSig = wtx.vjoinsplit[i].h_sig(*pzcashParams, wtx.joinSplitPubKey); try { - NotePlaintext plaintext = NotePlaintext::decrypt( + SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt( decryptor, wtx.vjoinsplit[i].ciphertexts[j], wtx.vjoinsplit[i].ephemeralKey, hSig, (unsigned char) j); - outEntries.push_back(CUnspentNotePlaintextEntry{jsop, pa, plaintext, wtx.GetDepthInMainChain()}); + outEntries.push_back(CUnspentSproutNotePlaintextEntry{jsop, pa, plaintext, wtx.GetDepthInMainChain()}); } catch (const note_decryption_failed &err) { // Couldn't decrypt with this spending key diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 6c968fca9..6c05244e4 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -265,18 +265,18 @@ public: typedef std::map mapNoteData_t; /** Decrypted note and its location in a transaction. */ -struct CNotePlaintextEntry +struct CSproutNotePlaintextEntry { JSOutPoint jsop; libzcash::PaymentAddress address; - libzcash::NotePlaintext plaintext; + libzcash::SproutNotePlaintext plaintext; }; /** Decrypted note, location in a transaction, and confirmation height. */ -struct CUnspentNotePlaintextEntry { +struct CUnspentSproutNotePlaintextEntry { JSOutPoint jsop; libzcash::PaymentAddress address; - libzcash::NotePlaintext plaintext; + libzcash::SproutNotePlaintext plaintext; int nHeight; }; @@ -1139,21 +1139,21 @@ public: void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; } /* Find notes filtered by payment address, min depth, ability to spend */ - void GetFilteredNotes(std::vector & outEntries, + void GetFilteredNotes(std::vector & outEntries, std::string address, int minDepth=1, bool ignoreSpent=true, bool ignoreUnspendable=true); /* Find notes filtered by payment addresses, min depth, ability to spend */ - void GetFilteredNotes(std::vector& outEntries, + void GetFilteredNotes(std::vector& outEntries, std::set& filterAddresses, int minDepth=1, bool ignoreSpent=true, bool ignoreUnspendable=true); /* Find unspent notes filtered by payment address, min depth and max depth */ - void GetUnspentFilteredNotes(std::vector& outEntries, + void GetUnspentFilteredNotes(std::vector& outEntries, std::set& filterAddresses, int minDepth=1, int maxDepth=INT_MAX, diff --git a/src/zcash/JoinSplit.cpp b/src/zcash/JoinSplit.cpp index 2685569d3..d4dee9bb9 100644 --- a/src/zcash/JoinSplit.cpp +++ b/src/zcash/JoinSplit.cpp @@ -139,7 +139,7 @@ public: ZCProof prove( const boost::array& inputs, const boost::array& outputs, - boost::array& out_notes, + boost::array& out_notes, boost::array& out_ciphertexts, uint256& out_ephemeralKey, const uint256& pubKeyHash, @@ -168,7 +168,7 @@ public: // Sanity checks of input { // If note has nonzero value - if (inputs[i].note.value != 0) { + if (inputs[i].note.value() != 0) { // The witness root must equal the input root. if (inputs[i].witness.root() != rt) { throw std::invalid_argument("joinsplit not anchored to the correct root"); @@ -186,11 +186,11 @@ public: } // Balance must be sensical - if (inputs[i].note.value > MAX_MONEY) { + if (inputs[i].note.value() > MAX_MONEY) { throw std::invalid_argument("nonsensical input note value"); } - lhs_value += inputs[i].note.value; + lhs_value += inputs[i].note.value(); if (lhs_value > MAX_MONEY) { throw std::invalid_argument("nonsensical left hand size of joinsplit balance"); @@ -246,7 +246,7 @@ public: ZCNoteEncryption encryptor(h_sig); for (size_t i = 0; i < NumOutputs; i++) { - NotePlaintext pt(out_notes[i], outputs[i].memo); + SproutNotePlaintext pt(out_notes[i], outputs[i].memo); out_ciphertexts[i] = pt.encrypt(encryptor, outputs[i].addr.pk_enc); } @@ -364,10 +364,10 @@ uint256 JoinSplit::h_sig( return output; } -Note JSOutput::note(const uint252& phi, const uint256& r, size_t i, const uint256& h_sig) const { +SproutNote JSOutput::note(const uint252& phi, const uint256& r, size_t i, const uint256& h_sig) const { uint256 rho = PRF_rho(phi, i, h_sig); - return Note(addr.a_pk, value, rho, r); + return SproutNote(addr.a_pk, value, rho, r); } JSOutput::JSOutput() : addr(uint256(), uint256()), value(0) { @@ -377,7 +377,7 @@ JSOutput::JSOutput() : addr(uint256(), uint256()), value(0) { JSInput::JSInput() : witness(ZCIncrementalMerkleTree().witness()), key(SpendingKey::random()) { - note = Note(key.address().a_pk, 0, random_uint256(), random_uint256()); + note = SproutNote(key.address().a_pk, 0, random_uint256(), random_uint256()); ZCIncrementalMerkleTree dummy_tree; dummy_tree.append(note.cm()); witness = dummy_tree.witness(); diff --git a/src/zcash/JoinSplit.hpp b/src/zcash/JoinSplit.hpp index 6a2d4e1f2..28ca98e97 100644 --- a/src/zcash/JoinSplit.hpp +++ b/src/zcash/JoinSplit.hpp @@ -18,12 +18,12 @@ namespace libzcash { class JSInput { public: ZCIncrementalWitness witness; - Note note; + SproutNote note; SpendingKey key; JSInput(); JSInput(ZCIncrementalWitness witness, - Note note, + SproutNote note, SpendingKey key) : witness(witness), note(note), key(key) { } uint256 nullifier() const { @@ -40,7 +40,7 @@ public: JSOutput(); JSOutput(PaymentAddress addr, uint64_t value) : addr(addr), value(value) { } - Note note(const uint252& phi, const uint256& r, size_t i, const uint256& h_sig) const; + SproutNote note(const uint252& phi, const uint256& r, size_t i, const uint256& h_sig) const; }; template @@ -62,7 +62,7 @@ public: virtual ZCProof prove( const boost::array& inputs, const boost::array& outputs, - boost::array& out_notes, + boost::array& out_notes, boost::array& out_ciphertexts, uint256& out_ephemeralKey, const uint256& pubKeyHash, diff --git a/src/zcash/Note.cpp b/src/zcash/Note.cpp index afef81458..407925e15 100644 --- a/src/zcash/Note.cpp +++ b/src/zcash/Note.cpp @@ -9,21 +9,20 @@ namespace libzcash { -Note::Note() { +SproutNote::SproutNote() { a_pk = random_uint256(); rho = random_uint256(); r = random_uint256(); - value = 0; } -uint256 Note::cm() const { +uint256 SproutNote::cm() const { unsigned char discriminant = 0xb0; CSHA256 hasher; hasher.Write(&discriminant, 1); hasher.Write(a_pk.begin(), 32); - auto value_vec = convertIntToVectorLE(value); + auto value_vec = convertIntToVectorLE(value_); hasher.Write(&value_vec[0], value_vec.size()); hasher.Write(rho.begin(), 32); @@ -35,25 +34,24 @@ uint256 Note::cm() const { return result; } -uint256 Note::nullifier(const SpendingKey& a_sk) const { +uint256 SproutNote::nullifier(const SpendingKey& a_sk) const { return PRF_nf(a_sk, rho); } -NotePlaintext::NotePlaintext( - const Note& note, - boost::array memo) : memo(memo) +SproutNotePlaintext::SproutNotePlaintext( + const SproutNote& note, + boost::array memo) : BaseNotePlaintext(note, memo) { - value = note.value; rho = note.rho; r = note.r; } -Note NotePlaintext::note(const PaymentAddress& addr) const +SproutNote SproutNotePlaintext::note(const PaymentAddress& addr) const { - return Note(addr.a_pk, value, rho, r); + return SproutNote(addr.a_pk, value_, rho, r); } -NotePlaintext NotePlaintext::decrypt(const ZCNoteDecryption& decryptor, +SproutNotePlaintext SproutNotePlaintext::decrypt(const ZCNoteDecryption& decryptor, const ZCNoteDecryption::Ciphertext& ciphertext, const uint256& ephemeralKey, const uint256& h_sig, @@ -65,7 +63,7 @@ NotePlaintext NotePlaintext::decrypt(const ZCNoteDecryption& decryptor, CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << plaintext; - NotePlaintext ret; + SproutNotePlaintext ret; ss >> ret; assert(ss.size() == 0); @@ -73,7 +71,7 @@ NotePlaintext NotePlaintext::decrypt(const ZCNoteDecryption& decryptor, return ret; } -ZCNoteEncryption::Ciphertext NotePlaintext::encrypt(ZCNoteEncryption& encryptor, +ZCNoteEncryption::Ciphertext SproutNotePlaintext::encrypt(ZCNoteEncryption& encryptor, const uint256& pk_enc ) const { diff --git a/src/zcash/Note.hpp b/src/zcash/Note.hpp index 9b2676931..8254717bb 100644 --- a/src/zcash/Note.hpp +++ b/src/zcash/Note.hpp @@ -8,34 +8,62 @@ namespace libzcash { -class Note { +class BaseNote { +protected: + uint64_t value_ = 0; +public: + BaseNote() {} + BaseNote(uint64_t value) : value_(value) {}; + virtual ~BaseNote() {}; + + virtual uint256 cm() const {}; + inline uint64_t value() const { return value_; }; +}; + +class SproutNote : public BaseNote { public: uint256 a_pk; - uint64_t value; uint256 rho; uint256 r; - Note(uint256 a_pk, uint64_t value, uint256 rho, uint256 r) - : a_pk(a_pk), value(value), rho(rho), r(r) {} + SproutNote(uint256 a_pk, uint64_t value, uint256 rho, uint256 r) + : BaseNote(value), a_pk(a_pk), rho(rho), r(r) {} - Note(); + SproutNote(); + + virtual ~SproutNote() {}; + + virtual uint256 cm() const override; - uint256 cm() const; uint256 nullifier(const SpendingKey& a_sk) const; }; -class NotePlaintext { +class BaseNotePlaintext { +protected: + uint64_t value_ = 0; + boost::array memo_; +public: + BaseNotePlaintext() {} + BaseNotePlaintext(const BaseNote& note, boost::array memo) + : value_(note.value()), memo_(memo) {} + virtual ~BaseNotePlaintext() {} + + inline uint64_t value() const { return value_; } + inline boost::array memo() const { return memo_; } +}; + +class SproutNotePlaintext : public BaseNotePlaintext { public: - uint64_t value = 0; uint256 rho; uint256 r; - boost::array memo; - NotePlaintext() {} + SproutNotePlaintext() {} - NotePlaintext(const Note& note, boost::array memo); + SproutNotePlaintext(const SproutNote& note, boost::array memo); - Note note(const PaymentAddress& addr) const; + SproutNote note(const PaymentAddress& addr) const; + + virtual ~SproutNotePlaintext() {} ADD_SERIALIZE_METHODS; @@ -45,16 +73,16 @@ public: READWRITE(leadingByte); if (leadingByte != 0x00) { - throw std::ios_base::failure("lead byte of NotePlaintext is not recognized"); + throw std::ios_base::failure("lead byte of SproutNotePlaintext is not recognized"); } - READWRITE(value); + READWRITE(value_); READWRITE(rho); READWRITE(r); - READWRITE(memo); + READWRITE(memo_); } - static NotePlaintext decrypt(const ZCNoteDecryption& decryptor, + static SproutNotePlaintext decrypt(const ZCNoteDecryption& decryptor, const ZCNoteDecryption::Ciphertext& ciphertext, const uint256& ephemeralKey, const uint256& h_sig, diff --git a/src/zcash/circuit/gadget.tcc b/src/zcash/circuit/gadget.tcc index 141ec834e..6d057459f 100644 --- a/src/zcash/circuit/gadget.tcc +++ b/src/zcash/circuit/gadget.tcc @@ -191,7 +191,7 @@ public: const uint256& rt, const uint256& h_sig, const boost::array& inputs, - const boost::array& outputs, + const boost::array& outputs, uint64_t vpub_old, uint64_t vpub_new ) { @@ -222,7 +222,7 @@ public: // Witness total_uint64 bits uint64_t left_side_acc = vpub_old; for (size_t i = 0; i < NumInputs; i++) { - left_side_acc += inputs[i].note.value; + left_side_acc += inputs[i].note.value(); } zk_total_uint64.fill_with_bits( diff --git a/src/zcash/circuit/note.tcc b/src/zcash/circuit/note.tcc index f472cb151..d1534ec4b 100644 --- a/src/zcash/circuit/note.tcc +++ b/src/zcash/circuit/note.tcc @@ -21,9 +21,9 @@ public: r->generate_r1cs_constraints(); } - void generate_r1cs_witness(const Note& note) { + void generate_r1cs_witness(const SproutNote& note) { r->bits.fill_with_bits(this->pb, uint256_to_bool_vector(note.r)); - value.fill_with_bits(this->pb, uint64_to_bool_vector(note.value)); + value.fill_with_bits(this->pb, uint64_to_bool_vector(note.value())); } }; @@ -119,7 +119,7 @@ public: void generate_r1cs_witness( const MerklePath& path, const SpendingKey& key, - const Note& note + const SproutNote& note ) { note_gadget::generate_r1cs_witness(note); @@ -158,7 +158,7 @@ public: ); // Set enforce flag for nonzero input value - this->pb.val(value_enforce) = (note.value != 0) ? FieldT::one() : FieldT::zero(); + this->pb.val(value_enforce) = (note.value() != 0) ? FieldT::one() : FieldT::zero(); // Witness merkle tree authentication path witness_input->generate_r1cs_witness(path); @@ -222,7 +222,7 @@ public: commit_to_outputs->generate_r1cs_constraints(); } - void generate_r1cs_witness(const Note& note) { + void generate_r1cs_witness(const SproutNote& note) { note_gadget::generate_r1cs_witness(note); prevent_faerie_gold->generate_r1cs_witness();