From cd4c4f235f88b7e166400cedf069499be8506c52 Mon Sep 17 00:00:00 2001 From: ludamad Date: Tue, 10 Jan 2023 11:53:02 +0000 Subject: [PATCH 1/6] Elide sig check on 'merge' join-split proofs --- cpp/src/aztec/rollup/constants.hpp | 14 +- .../aztec/rollup/proofs/account/account.cpp | 3 +- .../proofs/join_split/join_split.test.cpp | 431 ++++++++++-------- .../proofs/join_split/join_split_circuit.cpp | 38 +- .../proofs/join_split/verify_signature.hpp | 24 +- .../stdlib/encryption/schnorr/schnorr.cpp | 16 +- .../stdlib/encryption/schnorr/schnorr.hpp | 16 +- .../encryption/schnorr/schnorr.test.cpp | 6 +- 8 files changed, 321 insertions(+), 227 deletions(-) diff --git a/cpp/src/aztec/rollup/constants.hpp b/cpp/src/aztec/rollup/constants.hpp index 9275e9c82a..60da9276c1 100644 --- a/cpp/src/aztec/rollup/constants.hpp +++ b/cpp/src/aztec/rollup/constants.hpp @@ -34,8 +34,8 @@ is_circuit_change_expected to zero and change the modified circuit gate counts a constexpr bool is_circuit_change_expected = 0; /* The below constants are only used for regression testing; to identify accidental changes to circuit constraints. They need to be changed when there is a circuit change. */ -constexpr uint32_t ACCOUNT = 23958; -constexpr uint32_t JOIN_SPLIT = 64000; +constexpr uint32_t ACCOUNT = 23967; +constexpr uint32_t JOIN_SPLIT = 64043; constexpr uint32_t CLAIM = 22684; constexpr uint32_t ROLLUP = 1173221; constexpr uint32_t ROOT_ROLLUP = 5481327; @@ -57,13 +57,13 @@ namespace circuit_vk_hash { /* These below constants are only used for regression testing; to identify accidental changes to circuit constraints. They need to be changed when there is a circuit change. Note that they are written in the reverse order to comply with the from_buffer<>() method. */ -constexpr auto ACCOUNT = uint256_t(0x78ebf096ab73e440, 0xaa1dc7c26a125f6e, 0x488a97e465b96964, 0xf9d3e501b89bf466); -constexpr auto JOIN_SPLIT = uint256_t(0x5e67a4a4503ebf25, 0xb3c070c061e76d1a, 0xb18c6c6a5bcad5fb, 0xe0d5f46cafb33ecf); +constexpr auto ACCOUNT = uint256_t(0xcd6d70c733eaf823, 0x6505d3402817ad3d, 0xbf9e2b6a262589cf, 0xafcc546b55cc45e3); +constexpr auto JOIN_SPLIT = uint256_t(0x5cb3fad96d99c1dd, 0x9d6cb4da6534bed5, 0xde45f710d14e4c8f, 0xbbd799c6bc1604c6); constexpr auto CLAIM = uint256_t(0x878301ebba40ab60, 0x931466762c62d661, 0x40aad71ec3496905, 0x9f47aaa109759d0a); -constexpr auto ROLLUP = uint256_t(0x160731cc44173fdc, 0x6a6d55e46bf198bd, 0x9ce1d4608ae26fb0, 0x865ced5c16cb6152); -constexpr auto ROOT_ROLLUP = uint256_t(0xd77e82eae9e6efc7, 0x2b5ddf767012a4cf, 0x8b5982bb3d64616f, 0x20b515f5a9c78048); +constexpr auto ROLLUP = uint256_t(0xd553ea0ac51c58e9, 0x86d42c1ccbea7aa6, 0x4a909dd1739f5a4d, 0x858ee674e0e6563a); +constexpr auto ROOT_ROLLUP = uint256_t(0x27e4fc32f1b1c7c1, 0x494949a979fce5ba, 0x261c3a86be3b691f, 0xce98cdfea4b4f39c); constexpr auto ROOT_VERIFIER = - uint256_t(0x8e8313d6015ca626, 0x62ccf70b81c4e099, 0x33bee0072a20f36a, 0x44bd24daa009cd59); + uint256_t(0xe8e502db8a4f8d42, 0x6337b5d53c3ca77d, 0xdb4da3d73331c7ef, 0x213a2f3f34e8ad04); }; // namespace circuit_vk_hash namespace ProofIds { diff --git a/cpp/src/aztec/rollup/proofs/account/account.cpp b/cpp/src/aztec/rollup/proofs/account/account.cpp index 03173f5c27..1270e85556 100644 --- a/cpp/src/aztec/rollup/proofs/account/account.cpp +++ b/cpp/src/aztec/rollup/proofs/account/account.cpp @@ -105,7 +105,8 @@ void account_circuit(Composer& composer, account_tx const& tx) nullifier_1, nullifier_2 }; const byte_array_ct message = pedersen::compress(to_compress); - stdlib::schnorr::verify_signature(message, signer, signature); + const bool_ct verified = stdlib::schnorr::verify_signature(message, signer, signature); + verified.assert_equal(true, "verify signature failed"); if (composer.failed && !composerAlreadyFailed) { // only assign this error if an error hasn't already been assigned. composer.err = "verify signature failed"; diff --git a/cpp/src/aztec/rollup/proofs/join_split/join_split.test.cpp b/cpp/src/aztec/rollup/proofs/join_split/join_split.test.cpp index fe11637dde..b921c6bfdc 100644 --- a/cpp/src/aztec/rollup/proofs/join_split/join_split.test.cpp +++ b/cpp/src/aztec/rollup/proofs/join_split/join_split.test.cpp @@ -40,13 +40,14 @@ class join_split_tests : public ::testing::Test { { store = std::make_unique(); tree = std::make_unique>(*store, 32); - user = rollup::fixtures::create_user_context(); + input_user = rollup::fixtures::create_user_context(); + output_user = rollup::fixtures::create_user_context(); default_value_note = { .value = 100, .asset_id = asset_id, .account_required = false, - .owner = user.owner.public_key, - .secret = user.note_secret, + .owner = input_user.owner.public_key, + .secret = input_user.note_secret, .creator_pubkey = 0, .input_nullifier = fr::random_element() }; @@ -56,7 +57,7 @@ class join_split_tests : public ::testing::Test { value_note.input_nullifier = fr::random_element(); // to ensure uniqueness } - value_notes[0].creator_pubkey = user.owner.public_key.x; + value_notes[0].creator_pubkey = input_user.owner.public_key.x; value_notes[1].value = 50; value_notes[1].creator_pubkey = rollup::fixtures::create_key_pair(nullptr).public_key.x; @@ -76,16 +77,16 @@ class join_split_tests : public ::testing::Test { value_notes[6].value = 90; value_notes[6].asset_id = asset_id + 1; - value_notes[6].creator_pubkey = user.owner.public_key.x; + value_notes[6].creator_pubkey = input_user.owner.public_key.x; // Value chosen to cause tests to fail. value_notes[7].value = 110; value_notes[7].asset_id = asset_id + 1; - value_notes[7].creator_pubkey = user.owner.public_key.x; + value_notes[7].creator_pubkey = input_user.owner.public_key.x; // Similar to value_notes[0], but a different value of 90, to match defi_deposit_value in tests. value_notes[8].value = 90; - value_notes[8].creator_pubkey = user.owner.public_key.x; + value_notes[8].creator_pubkey = input_user.owner.public_key.x; // Similar previous virtual notes, but a different value of 90, to match defi_deposit_value in tests. value_notes[9].value = 90; @@ -113,12 +114,14 @@ class join_split_tests : public ::testing::Test { */ void preload_account_notes() { - tree->update_element( - tree->size(), - create_account_leaf_data(user.alias_hash, user.owner.public_key, user.signing_keys[0].public_key)); - tree->update_element( - tree->size(), - create_account_leaf_data(user.alias_hash, user.owner.public_key, user.signing_keys[1].public_key)); + tree->update_element(tree->size(), + create_account_leaf_data(input_user.alias_hash, + input_user.owner.public_key, + input_user.signing_keys[0].public_key)); + tree->update_element(tree->size(), + create_account_leaf_data(input_user.alias_hash, + input_user.owner.public_key, + input_user.signing_keys[1].public_key)); } /** @@ -143,24 +146,25 @@ class join_split_tests : public ::testing::Test { */ join_split_tx create_join_split_tx(std::array const& input_indices, std::array const& input_notes, + rollup::fixtures::user_context& output_user, uint32_t account_note_index = 0, bool account_required = false) { uint32_t tx_asset_id = input_notes[0].asset_id; - auto input_nullifier1 = compute_nullifier(input_notes[0].commit(), user.owner.private_key, true); - auto input_nullifier2 = compute_nullifier(input_notes[1].commit(), user.owner.private_key, true); + auto input_nullifier1 = compute_nullifier(input_notes[0].commit(), input_user.owner.private_key, true); + auto input_nullifier2 = compute_nullifier(input_notes[1].commit(), input_user.owner.private_key, true); value::value_note output_note1 = { .value = input_notes[0].value + input_notes[1].value, .asset_id = tx_asset_id, .account_required = account_required, - .owner = user.owner.public_key, - .secret = user.note_secret, + .owner = output_user.owner.public_key, + .secret = output_user.note_secret, .creator_pubkey = 0, .input_nullifier = input_nullifier1 }; value::value_note output_note2 = { .value = 0, .asset_id = tx_asset_id, .account_required = account_required, - .owner = user.owner.public_key, - .secret = user.note_secret, + .owner = output_user.owner.public_key, + .secret = output_user.note_secret, .creator_pubkey = 0, .input_nullifier = input_nullifier2 }; @@ -176,11 +180,11 @@ class join_split_tests : public ::testing::Test { tx.public_owner = fr(0); tx.account_note_index = account_note_index; tx.account_note_path = tree->get_hash_path(account_note_index); - tx.signing_pub_key = user.signing_keys[0].public_key; + tx.signing_pub_key = input_user.signing_keys[0].public_key; tx.asset_id = tx_asset_id; - tx.account_private_key = user.owner.private_key; + tx.account_private_key = input_user.owner.private_key; tx.partial_claim_note.input_nullifier = 0; - tx.alias_hash = !account_required ? rollup::fixtures::generate_alias_hash("penguin") : user.alias_hash; + tx.alias_hash = !account_required ? rollup::fixtures::generate_alias_hash("penguin") : input_user.alias_hash; tx.account_required = account_required; // default to no chaining: tx.backward_link = 0; @@ -194,13 +198,15 @@ class join_split_tests : public ::testing::Test { */ join_split_tx simple_setup(std::array const& input_indices = { 0, 1 }, uint32_t account_note_index = 0, - bool account_required = false) + bool account_required = false, + rollup::fixtures::user_context* tx_output_user = nullptr) { // The tree, user and notes are initialised in SetUp(). preload_value_notes(); preload_account_notes(); // indices: [ACCOUNT_INDEX, ACCOUNT_INDEX + 1] return create_join_split_tx(input_indices, { value_notes[input_indices[0]], value_notes[input_indices[1]] }, + tx_output_user ? *tx_output_user : output_user, account_note_index, account_required); @@ -214,17 +220,32 @@ class join_split_tests : public ::testing::Test { */ } + join_split_tx same_owner_setup(std::array const& input_indices = { 0, 1 }, + uint32_t account_note_index = 0, + bool account_required = false) + { + return simple_setup(input_indices, account_note_index, account_required, &input_user); + } + /** * Return a join split tx with 0-valued input notes. */ join_split_tx zero_input_setup() { - value::value_note input_note1 = { 0, 0, 0, user.owner.public_key, user.note_secret, 0, fr::random_element() }; - value::value_note input_note2 = { 0, 0, 0, user.owner.public_key, user.note_secret, 0, fr::random_element() }; - auto input_nullifier1 = compute_nullifier(input_note1.commit(), user.owner.private_key, false); - auto input_nullifier2 = compute_nullifier(input_note2.commit(), user.owner.private_key, false); - value::value_note output_note1 = { 0, 0, 0, user.owner.public_key, user.note_secret, 0, input_nullifier1 }; - value::value_note output_note2 = { 0, 0, 0, user.owner.public_key, user.note_secret, 0, input_nullifier2 }; + value::value_note input_note1 = { + 0, 0, 0, input_user.owner.public_key, input_user.note_secret, 0, fr::random_element() + }; + value::value_note input_note2 = { + 0, 0, 0, input_user.owner.public_key, input_user.note_secret, 0, fr::random_element() + }; + auto input_nullifier1 = compute_nullifier(input_note1.commit(), input_user.owner.private_key, false); + auto input_nullifier2 = compute_nullifier(input_note2.commit(), input_user.owner.private_key, false); + value::value_note output_note1 = { + 0, 0, 0, input_user.owner.public_key, input_user.note_secret, 0, input_nullifier1 + }; + value::value_note output_note2 = { + 0, 0, 0, input_user.owner.public_key, input_user.note_secret, 0, input_nullifier2 + }; join_split_tx tx; tx.proof_id = ProofIds::SEND; @@ -238,12 +259,12 @@ class join_split_tests : public ::testing::Test { tx.input_note = { input_note1, input_note2 }; tx.output_note = { output_note1, output_note2 }; tx.partial_claim_note.input_nullifier = 0; - tx.account_private_key = user.owner.private_key; + tx.account_private_key = input_user.owner.private_key; tx.alias_hash = rollup::fixtures::generate_alias_hash("penguin"); tx.account_required = false; tx.account_note_index = 0; tx.account_note_path = tree->get_hash_path(0); - tx.signing_pub_key = user.signing_keys[0].public_key; + tx.signing_pub_key = input_user.signing_keys[0].public_key; tx.backward_link = 0; tx.allow_chain = 0; return tx; @@ -285,7 +306,8 @@ class join_split_tests : public ::testing::Test { return verify_logic(tx); } - rollup::fixtures::user_context user; + rollup::fixtures::user_context input_user; + rollup::fixtures::user_context output_user; std::unique_ptr store; std::unique_ptr> tree; bridge_call_data empty_bridge_call_data = { .bridge_address_id = 0, @@ -433,9 +455,10 @@ TEST_F(join_split_tests, test_invalid_num_input_notes_fails) tx.num_input_notes = 100; // <-- testing this fails. tx.input_note[1].value = 0; tx.output_note[0].value = tx.input_note[0].value; - tx.output_note[1].input_nullifier = compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); + tx.output_note[1].input_nullifier = + compute_nullifier(tx.input_note[1].commit(), input_user.owner.private_key, false); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "invalid num_input_notes"); } @@ -447,7 +470,7 @@ TEST_F(join_split_tests, test_deposit_public_value_invalid_fails) tx.public_value = 0; // <-- invalid, should be nonzero tx.public_owner = fr::random_element(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "public value invalid"); } @@ -458,7 +481,7 @@ TEST_F(join_split_tests, test_send_public_value_invalid_fails) tx.public_value = 10; // <-- invalid - should be 0 tx.public_owner = fr::random_element(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "public value invalid"); } @@ -470,7 +493,7 @@ TEST_F(join_split_tests, test_withdraw_public_value_invalid_fails) tx.public_value = 0; // <-- invalid - should be nonzero tx.public_owner = fr::random_element(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "public value invalid"); } @@ -489,7 +512,7 @@ TEST_F(join_split_tests, test_defi_deposit_public_value_invalid_fails) bridge_call_data.input_asset_id_a = tx.input_note[0].asset_id; tx.partial_claim_note.bridge_call_data = bridge_call_data.to_uint256_t(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "public value invalid"); } @@ -501,7 +524,7 @@ TEST_F(join_split_tests, test_deposit_public_owner_invalid_fails) tx.public_value = 10; tx.public_owner = 0; // <-- invalid - should be nonzero - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "public owner invalid"); } @@ -512,7 +535,7 @@ TEST_F(join_split_tests, test_send_public_owner_invalid_fails) tx.public_value = 0; tx.public_owner = fr::random_element(); // <-- invalid - should be 0 - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "public owner invalid"); } @@ -524,7 +547,7 @@ TEST_F(join_split_tests, test_withdraw_public_owner_invalid_fails) tx.public_value = 10; tx.public_owner = 0; // <-- invalid - should be nonzero - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "public owner invalid"); } @@ -543,7 +566,7 @@ TEST_F(join_split_tests, test_defi_deposit_public_owner_invalid_fails) bridge_call_data.input_asset_id_a = tx.input_note[0].asset_id; tx.partial_claim_note.bridge_call_data = bridge_call_data.to_uint256_t(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "public owner invalid"); } @@ -553,7 +576,7 @@ TEST_F(join_split_tests, test_wrong_proof_id) join_split_tx tx = zero_input_setup(); tx.proof_id = ProofIds::DEFI_CLAIM; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "invalid proof id"); } @@ -561,7 +584,7 @@ TEST_F(join_split_tests, test_wrong_proof_id) TEST_F(join_split_tests, test_joining_same_note_fails) { join_split_tx tx = simple_setup({ 1, 1 }); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "joining same note"); } @@ -570,7 +593,7 @@ TEST_F(join_split_tests, test_send_with_0_input_notes_fails) { join_split_tx tx = zero_input_setup(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "can only deposit"); } @@ -582,7 +605,7 @@ TEST_F(join_split_tests, test_withdraw_with_0_input_notes_fails) tx.public_value = 10; tx.public_owner = fr::random_element(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "can only deposit"); } @@ -592,7 +615,7 @@ TEST_F(join_split_tests, test_defi_deposit_with_0_input_notes_fails) join_split_tx tx = zero_input_setup(); tx.proof_id = ProofIds::DEFI_DEPOSIT; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "can only deposit"); } @@ -602,7 +625,7 @@ TEST_F(join_split_tests, test_wrong_asset_id_fails) join_split_tx tx = simple_setup(); tx.asset_id = 3; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "asset ids don't match"); } @@ -612,7 +635,7 @@ TEST_F(join_split_tests, test_different_input_note_1_asset_id_fails) join_split_tx tx = simple_setup(); tx.input_note[0].asset_id = 3; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "asset ids don't match"); } @@ -622,7 +645,7 @@ TEST_F(join_split_tests, test_different_output_note_1_asset_id_fails) join_split_tx tx = simple_setup(); tx.output_note[0].asset_id = 3; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "asset ids don't match"); } @@ -632,7 +655,7 @@ TEST_F(join_split_tests, test_different_output_note_2_asset_id_fails) join_split_tx tx = simple_setup(); tx.output_note[1].asset_id = 3; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "asset ids don't match"); } @@ -645,7 +668,7 @@ TEST_F(join_split_tests, test_deposit_but_different_input_note_2_asset_id_fails) tx.public_owner = fr::random_element(); tx.input_note[1].asset_id = 3; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "input asset ids must match unless defi-depositing"); } @@ -655,7 +678,7 @@ TEST_F(join_split_tests, test_send_but_different_input_note_2_asset_id_fails) join_split_tx tx = simple_setup(); tx.input_note[1].asset_id = 3; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "input asset ids must match unless defi-depositing"); } @@ -668,7 +691,7 @@ TEST_F(join_split_tests, test_withdraw_but_different_input_note_2_asset_id_fails tx.public_owner = fr::random_element(); tx.input_note[1].asset_id = 3; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "input asset ids must match unless defi-depositing"); } @@ -685,7 +708,7 @@ TEST_F(join_split_tests, test_0_input_notes_and_detect_circuit_change) tx.public_owner = fr::random_element(); tx.output_note[0].value = 30; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); // The below part detects any changes in the join-split circuit @@ -724,7 +747,7 @@ TEST_F(join_split_tests, test_0_input_notes_create_dupicate_output_notes_fails) tx.output_note[1] = tx.output_note[0]; // <-- attempt to maliciously create duplicate output notes. tx.input_note[1] = tx.input_note[0]; // <-- for output notes to be equal, input_nullifiers must be equal. - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "joining same note"); } @@ -744,7 +767,7 @@ TEST_F(join_split_tests, test_0_input_notes_create_dupicate_output_notes_fails_2 1; // <-- to avoid 'joining same note', modify input_note[1], but then hit the error that requirement for // different input_nullifiers will force the output_notes to be different. - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "output note 2 has incorrect input nullifier"); } @@ -759,7 +782,7 @@ TEST_F(join_split_tests, test_dummy_input_note_1_non_0_value_fails) tx.input_note[0].value = 10; tx.output_note[0].value = 20; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "padding note non zero"); } @@ -774,7 +797,7 @@ TEST_F(join_split_tests, test_dummy_input_note_2_non_0_value_fails) tx.input_note[1].value = 10; tx.output_note[0].value = 20; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "padding note non zero"); } @@ -785,9 +808,10 @@ TEST_F(join_split_tests, test_1_input_note) tx.num_input_notes = 1; // <-- testing this tx.input_note[1].value = 0; tx.output_note[0].value = tx.input_note[0].value; - tx.output_note[1].input_nullifier = compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); + tx.output_note[1].input_nullifier = + compute_nullifier(tx.input_note[1].commit(), input_user.owner.private_key, false); - EXPECT_TRUE(sign_and_verify_logic(tx, user.owner).valid); + EXPECT_TRUE(sign_and_verify_logic(tx, input_user.owner).valid); } // Bespoke test seeking bug. @@ -799,10 +823,12 @@ TEST_F(join_split_tests, test_1_input_note_with_num_input_notes_as_0) tx.input_note[1].value = 0; tx.output_note[0].value = tx.input_note[0].value; // create a cheeky nullifier for tx.input_note[0] where is_real = false - tx.output_note[0].input_nullifier = compute_nullifier(tx.input_note[0].commit(), user.owner.private_key, false); - tx.output_note[1].input_nullifier = compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); + tx.output_note[0].input_nullifier = + compute_nullifier(tx.input_note[0].commit(), input_user.owner.private_key, false); + tx.output_note[1].input_nullifier = + compute_nullifier(tx.input_note[1].commit(), input_user.owner.private_key, false); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "can only deposit"); } @@ -810,7 +836,7 @@ TEST_F(join_split_tests, test_1_input_note_with_num_input_notes_as_0) TEST_F(join_split_tests, test_2_input_notes) { join_split_tx tx = simple_setup(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); EXPECT_EQ(result.public_inputs.size(), InnerProofFields::NUM_FIELDS); } @@ -824,7 +850,7 @@ TEST_F(join_split_tests, test_0_output_notes) tx.public_value = tx.input_note[0].value + tx.input_note[1].value; tx.public_owner = fr::random_element(); - EXPECT_TRUE(sign_and_verify_logic(tx, user.owner).valid); + EXPECT_TRUE(sign_and_verify_logic(tx, input_user.owner).valid); } // ************************************************************************************************************* @@ -834,10 +860,10 @@ TEST_F(join_split_tests, test_0_output_notes) class test_valid_allow_chain_permutations : public join_split_tests, public ::testing::WithParamInterface {}; TEST_P(test_valid_allow_chain_permutations, ) { - join_split_tx tx = simple_setup(); + join_split_tx tx = same_owner_setup(); // sending to self is implied here, by the fixture's default values tx.allow_chain = GetParam(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); EXPECT_EQ(result.public_inputs[InnerProofFields::ALLOW_CHAIN], GetParam()); } @@ -847,7 +873,7 @@ TEST_F(join_split_tests, test_allow_chain_out_of_range_fails) { join_split_tx tx = simple_setup(); tx.backward_link = fr::random_element(); // choose a value unrelated to the inputs being spent - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "backward_link unrelated to inputs"); } @@ -856,7 +882,7 @@ TEST_F(join_split_tests, test_unrelated_backward_link_fails) { join_split_tx tx = simple_setup(); tx.allow_chain = 4; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "allow_chain out of range"); } @@ -867,7 +893,7 @@ TEST_P(test_allow_chain_to_other_users_fail, ) join_split_tx tx = simple_setup(); tx.allow_chain = GetParam(); tx.output_note[tx.allow_chain - 1].owner = grumpkin::g1::element::random_element(); // i.e. not owned by self. - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "inter-user chaining disallowed"); } @@ -899,7 +925,7 @@ TEST_P(test_propagated_notes_skip_membership_check, ) assign_backward_link(tx, indicator); tx.input_path[indicator - 1] = tree->get_hash_path(99); // select a clearly incorrect path for the input note being propagated. - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); } INSTANTIATE_TEST_SUITE_P(join_split_tests, test_propagated_notes_skip_membership_check, ::testing::Values(1, 2)); @@ -923,7 +949,7 @@ TEST_F(join_split_tests, test_propagated_input_note1_no_double_spend) tx.output_note[0].input_nullifier }; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "joining same note"); @@ -941,7 +967,7 @@ TEST_F(join_split_tests, test_max_public_input) tx.output_note[0].value = max_value; tx.public_owner = fr::random_element(); - EXPECT_TRUE(sign_and_verify_logic(tx, user.owner).valid); + EXPECT_TRUE(sign_and_verify_logic(tx, input_user.owner).valid); } TEST_F(join_split_tests, test_overflow_public_value_fails) @@ -951,7 +977,7 @@ TEST_F(join_split_tests, test_overflow_public_value_fails) tx.public_value = max_value + 1; tx.public_owner = fr::random_element(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "safe_uint_t range constraint failure: public_value"); } @@ -967,7 +993,7 @@ TEST_F(join_split_tests, test_non_zero_tx_fee) tx.public_value += 10; tx.public_owner = fr::random_element(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); EXPECT_EQ(result.public_inputs[InnerProofFields::TX_FEE], 10); } @@ -977,7 +1003,7 @@ TEST_F(join_split_tests, test_non_zero_tx_fee_zero_public_values) join_split_tx tx = simple_setup(); tx.output_note[0].value -= 10; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); EXPECT_EQ(result.public_inputs[InnerProofFields::TX_FEE], 10); } @@ -990,7 +1016,7 @@ TEST_F(join_split_tests, test_max_tx_fee) tx.public_value += tx_fee; tx.public_owner = fr::random_element(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); EXPECT_EQ(result.public_inputs[InnerProofFields::TX_FEE], fr(tx_fee)); } @@ -1003,7 +1029,7 @@ TEST_F(join_split_tests, test_overflow_tx_fee_fails) tx.public_value += tx_fee; tx.public_owner = fr::random_element(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "safe_uint_t range constraint failure: subtract: total_in_value < total_out_value"); } @@ -1013,7 +1039,7 @@ TEST_F(join_split_tests, test_total_output_value_larger_than_total_input_value_f join_split_tx tx = simple_setup(); tx.output_note[0].value += 1; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "safe_uint_t range constraint failure: subtract: total_in_value < total_out_value"); } @@ -1027,7 +1053,7 @@ TEST_F(join_split_tests, test_different_input_note_owners_fails) join_split_tx tx = simple_setup({ 1, 2 }); tx.input_note[0].owner = grumpkin::g1::affine_element::hash_to_curve(1).second; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "input note owners don't match"); } @@ -1036,7 +1062,7 @@ TEST_F(join_split_tests, test_different_input_note_account_requireds_fails) { join_split_tx tx = simple_setup({ 1, 2 }); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "input note account_required don't match"); } @@ -1056,13 +1082,13 @@ TEST_F(join_split_tests, test_different_input_note_account_requireds_fails) TEST_F(join_split_tests, test_spend_notes_with_registered_account) { join_split_tx tx = simple_setup({ 2, 3 }, ACCOUNT_INDEX, 1); - EXPECT_TRUE(sign_and_verify_logic(tx, user.signing_keys[0]).valid); + EXPECT_TRUE(sign_and_verify_logic(tx, input_user.signing_keys[0]).valid); } TEST_F(join_split_tests, test_different_note_account_required_vs_account_required_fails) { join_split_tx tx = simple_setup({ 2, 3 }, ACCOUNT_INDEX, 0); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "account_required incorrect"); } @@ -1073,7 +1099,7 @@ TEST_F(join_split_tests, test_wrong_input_note_owner_fails) tx.input_note[0].owner = grumpkin::g1::element::random_element(); tx.input_note[1].owner = tx.input_note[0].owner; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "account_private_key incorrect"); } @@ -1084,7 +1110,7 @@ TEST_F(join_split_tests, test_random_output_note_owners) tx.output_note[0].owner = grumpkin::g1::element::random_element(); tx.output_note[1].owner = grumpkin::g1::element::random_element(); - EXPECT_TRUE(sign_and_verify_logic(tx, user.owner).valid); + EXPECT_TRUE(sign_and_verify_logic(tx, input_user.owner).valid); } TEST_F(join_split_tests, test_tainted_output_owner_fails) @@ -1092,12 +1118,12 @@ TEST_F(join_split_tests, test_tainted_output_owner_fails) join_split_tx tx = simple_setup(); tx.proof_id = ProofIds::DEPOSIT; tx.public_value = 1; - tx.signing_pub_key = user.owner.public_key; + tx.signing_pub_key = input_user.owner.public_key; uint8_t public_owner[32] = { 0x01, 0xaa, 0x42, 0xd4, 0x72, 0x88, 0x8e, 0xae, 0xa5, 0x56, 0x39, 0x46, 0xeb, 0x5c, 0xf5, 0x6c, 0x81, 0x6, 0x4d, 0x80, 0xc6, 0xf5, 0xa5, 0x38, 0xcc, 0x87, 0xae, 0x54, 0xae, 0xdb, 0x75, 0xd9 }; tx.public_owner = from_buffer(public_owner); - tx.signature = sign_join_split_tx(tx, user.owner); + tx.signature = sign_join_split_tx(tx, input_user.owner); auto prover = new_join_split_prover(tx, false); auto proof = prover.construct_proof(); @@ -1117,7 +1143,7 @@ TEST_F(join_split_tests, test_wrong_account_private_key_fails) join_split_tx tx = simple_setup(); tx.account_private_key = grumpkin::fr::random_element(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "account_private_key incorrect"); } @@ -1130,7 +1156,7 @@ TEST_F(join_split_tests, test_wrong_public_owner_sig_fail) tx.public_owner = fr::random_element(); // sign over a different public owner - tx.signature = sign_join_split_tx(tx, user.owner); + tx.signature = sign_join_split_tx(tx, input_user.owner); tx.public_owner = fr::random_element(); @@ -1139,10 +1165,56 @@ TEST_F(join_split_tests, test_wrong_public_owner_sig_fail) EXPECT_EQ(result.err, "verify signature failed"); } +TEST_F(join_split_tests, test_merge_with_different_owners_sig_fail) +{ + // Negative case of "Simple merge transactions do not need to be signed" + // Here since our recipient does not equal our sender, this fails + // See https://hackmd.io/@aztec-network/H10r1JqOo + join_split_tx tx = simple_setup(); + tx.proof_id = ProofIds::SEND; + // sign with the wrong signer + // since this is a merge with *different* owners, this will fail + tx.signature = sign_join_split_tx(tx, output_user.owner); + + auto result = verify_logic(tx); + EXPECT_FALSE(result.valid); + EXPECT_EQ(result.err, "verify signature failed"); +} + +TEST_F(join_split_tests, test_merge_with_diff_amounts_sig_fail) +{ + // Negative case of "Simple merge transactions do not need to be signed" + // Here since our input and output amounts don't match, this fails + // See https://hackmd.io/@aztec-network/H10r1JqOo + join_split_tx tx = simple_setup(); + tx.output_note[0].value = 0; + tx.output_note[1].value = 0; + tx.proof_id = ProofIds::SEND; + // sign with the wrong signer + // since this is a merge with same owners and amount, this will still pass + tx.signature = sign_join_split_tx(tx, output_user.owner); + auto result = verify_logic(tx); + EXPECT_FALSE(result.valid); + EXPECT_EQ(result.err, "verify signature failed"); +} + +TEST_F(join_split_tests, test_merge_with_same_owners_same_amounts_sig_bypass) +{ + // Simple merge transactions do not need to be signed + // Since our recipient equals our sender, amounts are the same, and it is a send, this passes + // See https://hackmd.io/@aztec-network/H10r1JqOo + join_split_tx tx = same_owner_setup(); + tx.proof_id = ProofIds::SEND; + // sign with the wrong signer + // since this is a merge with same owners and amount, this will still pass + tx.signature = sign_join_split_tx(tx, output_user.owner); + EXPECT_TRUE(verify_logic(tx).valid); +} + TEST_F(join_split_tests, test_spend_notes_with_signing_key_when_account_required_is_false_fails) { join_split_tx tx = simple_setup(); - auto result = sign_and_verify_logic(tx, user.signing_keys[0]); + auto result = sign_and_verify_logic(tx, input_user.signing_keys[0]); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "verify signature failed"); } @@ -1150,7 +1222,7 @@ TEST_F(join_split_tests, test_spend_notes_with_signing_key_when_account_required TEST_F(join_split_tests, test_spend_registered_notes_with_owner_key_fails) { auto tx = simple_setup({ 2, 3 }, ACCOUNT_INDEX, 1); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "verify signature failed"); } @@ -1164,7 +1236,7 @@ TEST_F(join_split_tests, test_wrong_alias_hash_fails) join_split_tx tx = simple_setup({ 2, 3 }, ACCOUNT_INDEX, 1); tx.alias_hash = rollup::fixtures::generate_alias_hash("chicken"); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "account check_membership failed"); } @@ -1175,7 +1247,7 @@ TEST_F(join_split_tests, test_nonregistered_signing_key_fails) auto keys = rollup::fixtures::create_key_pair(nullptr); tx.signing_pub_key = keys.public_key; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "account check_membership failed"); } @@ -1189,7 +1261,7 @@ TEST_F(join_split_tests, test_wrong_merkle_root_fails) join_split_tx tx = simple_setup(); tx.old_data_root = fr::random_element(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "input note not a member"); } @@ -1200,7 +1272,7 @@ TEST_F(join_split_tests, test_wrong_note_hash_path_fails) auto gibberish_path = fr_hash_path(32, std::make_pair(fr::random_element(), fr::random_element())); tx.input_path[0] = gibberish_path; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "input note not a member"); } @@ -1210,7 +1282,7 @@ TEST_F(join_split_tests, test_wrong_leaf_index_fails) join_split_tx tx = simple_setup(); tx.input_index[0] = 99; - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "input note not a member"); } @@ -1224,7 +1296,7 @@ TEST_F(join_split_tests, test_incorrect_input_nullifier_in_output_note_1_fails) join_split_tx tx = simple_setup(); tx.output_note[0].input_nullifier = 1; // incorrect nullifier - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "output note 1 has incorrect input nullifier"); } @@ -1234,7 +1306,7 @@ TEST_F(join_split_tests, test_incorrect_input_nullifier_in_output_note_2_fails) join_split_tx tx = simple_setup(); tx.output_note[1].input_nullifier = 1; // incorrect nullifier - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "output note 2 has incorrect input nullifier"); } @@ -1248,8 +1320,8 @@ TEST_F(join_split_tests, test_defi_deposit_one_virtual_input) join_split_tx tx = simple_setup({ 4, 13 }); tx.num_input_notes = 1; - tx.output_note[1].input_nullifier = - compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); // input note 2 is a dummy note + tx.output_note[1].input_nullifier = compute_nullifier( + tx.input_note[1].commit(), input_user.owner.private_key, false); // input note 2 is a dummy note tx.proof_id = ProofIds::DEFI_DEPOSIT; tx.partial_claim_note.deposit_value = 90; @@ -1267,7 +1339,7 @@ TEST_F(join_split_tests, test_defi_deposit_one_virtual_input) * - 10 paid as fee */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); } @@ -1294,7 +1366,7 @@ TEST_F(join_split_tests, test_defi_deposit_one_real_one_virtual_inputs) * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); } @@ -1320,7 +1392,7 @@ TEST_F(join_split_tests, test_defi_deposit_one_virtual_one_real_inputs) * - 110 deposited via bridge input 2 (virtual) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); } @@ -1347,7 +1419,7 @@ TEST_F(join_split_tests, test_defi_deposit_one_real_one_virtual_inputs_same_asse * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); } @@ -1374,7 +1446,7 @@ TEST_F(join_split_tests, test_defi_deposit_two_real_inputs_different_asset_ids) * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); } @@ -1401,7 +1473,7 @@ TEST_F(join_split_tests, test_defi_deposit_two_virtual_inputs_different_asset_id * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); } @@ -1430,7 +1502,7 @@ TEST_F(join_split_tests, * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "all of input note 2 must be defi-deposited"); } @@ -1459,7 +1531,7 @@ TEST_F(join_split_tests, test_defi_deposit_two_real_inputs_different_asset_ids_a * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "all of input note 2 must be defi-deposited"); } @@ -1488,7 +1560,7 @@ TEST_F(join_split_tests, test_defi_deposit_two_real_inputs_different_asset_ids_a * - 5 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "all of input note 2 must be defi-deposited"); } @@ -1518,7 +1590,7 @@ TEST_F(join_split_tests, test_defi_invalid_tx_fee_asset_id_fails) * - 10 paid as fee (incorrect asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "asset ids don't match"); } @@ -1536,7 +1608,7 @@ TEST_F(join_split_tests, test_defi_deposit_of_zero_fails) bridge_call_data.input_asset_id_a = tx.input_note[0].asset_id; tx.partial_claim_note.bridge_call_data = bridge_call_data.to_uint256_t(); - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "Expected a nonzero defi_deposit_value for a defi-deposit"); } @@ -1564,12 +1636,12 @@ TEST_F(join_split_tests, test_defi_non_zero_output_note_1_ignored) * - 0 paid as fee */ - EXPECT_TRUE(sign_and_verify_logic(tx, user.owner).valid); + EXPECT_TRUE(sign_and_verify_logic(tx, input_user.owner).valid); } TEST_F(join_split_tests, test_defi_allow_chain_1_fails) { - join_split_tx tx = simple_setup(); + join_split_tx tx = same_owner_setup(); tx.proof_id = ProofIds::DEFI_DEPOSIT; tx.output_note[1].value = 100; tx.partial_claim_note.deposit_value = 50; @@ -1591,7 +1663,7 @@ TEST_F(join_split_tests, test_defi_allow_chain_1_fails) * - trying to chain off output_note_1, which is not allowed for defi deposits. */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "cannot chain from a partial claim note"); } @@ -1601,8 +1673,8 @@ TEST_F(join_split_tests, test_defi_deposit_incorrect_input_nullifier_in_partial_ join_split_tx tx = simple_setup({ 4, 13 }); tx.num_input_notes = 1; - tx.output_note[1].input_nullifier = - compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); // input note 2 is a dummy note + tx.output_note[1].input_nullifier = compute_nullifier( + tx.input_note[1].commit(), input_user.owner.private_key, false); // input note 2 is a dummy note tx.proof_id = ProofIds::DEFI_DEPOSIT; tx.partial_claim_note.deposit_value = 90; @@ -1620,7 +1692,7 @@ TEST_F(join_split_tests, test_defi_deposit_incorrect_input_nullifier_in_partial_ * - 10 paid as fee */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "partial claim note has incorrect input nullifier"); } @@ -1652,7 +1724,7 @@ TEST_F(join_split_tests, test_defi_deposit_bridge_call_data_second_bridge_input_ * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "Expected second_input_in_use, given input_asset_id_b != 0"); } @@ -1662,8 +1734,8 @@ TEST_F(join_split_tests, test_defi_deposit_bridge_call_data_second_bridge_output join_split_tx tx = simple_setup({ 4, 13 }); tx.num_input_notes = 1; - tx.output_note[1].input_nullifier = - compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); // input note 2 is a dummy note + tx.output_note[1].input_nullifier = compute_nullifier( + tx.input_note[1].commit(), input_user.owner.private_key, false); // input note 2 is a dummy note tx.proof_id = ProofIds::DEFI_DEPOSIT; tx.partial_claim_note.deposit_value = 90; @@ -1684,7 +1756,7 @@ TEST_F(join_split_tests, test_defi_deposit_bridge_call_data_second_bridge_output * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "Expected second_output_in_use, given output_asset_id_b != 0"); } @@ -1715,7 +1787,7 @@ TEST_F(join_split_tests, test_defi_deposit_second_bridge_input_in_use_but_same_b * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "input asset ids must be different for the second bridge input to be in-use"); } @@ -1725,8 +1797,8 @@ TEST_F(join_split_tests, test_defi_deposit_second_bridge_output_in_use_and_same_ join_split_tx tx = simple_setup({ 4, 13 }); tx.num_input_notes = 1; - tx.output_note[1].input_nullifier = - compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); // input note 2 is a dummy note + tx.output_note[1].input_nullifier = compute_nullifier( + tx.input_note[1].commit(), input_user.owner.private_key, false); // input note 2 is a dummy note tx.proof_id = ProofIds::DEFI_DEPOSIT; tx.partial_claim_note.deposit_value = 90; @@ -1749,7 +1821,7 @@ TEST_F(join_split_tests, test_defi_deposit_second_bridge_output_in_use_and_same_ * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_TRUE(result.valid); } @@ -1758,8 +1830,8 @@ TEST_F(join_split_tests, test_defi_deposit_second_bridge_output_in_use_but_same_ join_split_tx tx = simple_setup({ 4, 13 }); tx.num_input_notes = 1; - tx.output_note[1].input_nullifier = - compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); // input note 2 is a dummy note + tx.output_note[1].input_nullifier = compute_nullifier( + tx.input_note[1].commit(), input_user.owner.private_key, false); // input note 2 is a dummy note tx.proof_id = ProofIds::DEFI_DEPOSIT; tx.partial_claim_note.deposit_value = 90; @@ -1782,7 +1854,7 @@ TEST_F(join_split_tests, test_defi_deposit_second_bridge_output_in_use_but_same_ * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "real output asset ids must be different for the second bridge output to be in-use"); } @@ -1792,8 +1864,8 @@ TEST_F(join_split_tests, test_defi_deposit_first_bridge_output_asset_id_virtual_ join_split_tx tx = simple_setup({ 4, 13 }); tx.num_input_notes = 1; - tx.output_note[1].input_nullifier = - compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); // input note 2 is a dummy note + tx.output_note[1].input_nullifier = compute_nullifier( + tx.input_note[1].commit(), input_user.owner.private_key, false); // input note 2 is a dummy note tx.proof_id = ProofIds::DEFI_DEPOSIT; tx.partial_claim_note.deposit_value = 90; @@ -1813,7 +1885,7 @@ TEST_F(join_split_tests, test_defi_deposit_first_bridge_output_asset_id_virtual_ * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "output_asset_id_a detected as virtual, but has incorrect placeholder value"); } @@ -1823,8 +1895,8 @@ TEST_F(join_split_tests, test_defi_deposit_second_bridge_output_asset_id_virtual join_split_tx tx = simple_setup({ 4, 13 }); tx.num_input_notes = 1; - tx.output_note[1].input_nullifier = - compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); // input note 2 is a dummy note + tx.output_note[1].input_nullifier = compute_nullifier( + tx.input_note[1].commit(), input_user.owner.private_key, false); // input note 2 is a dummy note tx.proof_id = ProofIds::DEFI_DEPOSIT; tx.partial_claim_note.deposit_value = 90; @@ -1846,7 +1918,7 @@ TEST_F(join_split_tests, test_defi_deposit_second_bridge_output_asset_id_virtual * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "output_asset_id_b detected as virtual, but has incorrect placeholder value"); } @@ -1860,8 +1932,8 @@ TEST_F(join_split_tests, test_defi_wrong_first_asset_id_in_bridge_call_data_fail join_split_tx tx = simple_setup({ 4, 13 }); tx.num_input_notes = 1; - tx.output_note[1].input_nullifier = - compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); // input note 2 is a dummy note + tx.output_note[1].input_nullifier = compute_nullifier( + tx.input_note[1].commit(), input_user.owner.private_key, false); // input note 2 is a dummy note tx.proof_id = ProofIds::DEFI_DEPOSIT; tx.partial_claim_note.deposit_value = 90; @@ -1879,7 +1951,7 @@ TEST_F(join_split_tests, test_defi_wrong_first_asset_id_in_bridge_call_data_fail * - 10 paid as fee */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "Expected bridge_call_data_local.input_asset_id_a == input_note_1.asset_id for a defi-deposit"); @@ -1890,8 +1962,8 @@ TEST_F(join_split_tests, test_defi_bridge_call_data_config_second_input_in_use_b join_split_tx tx = simple_setup({ 4, 13 }); tx.num_input_notes = 1; - tx.output_note[1].input_nullifier = - compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); // input note 2 is a dummy note + tx.output_note[1].input_nullifier = compute_nullifier( + tx.input_note[1].commit(), input_user.owner.private_key, false); // input note 2 is a dummy note tx.proof_id = ProofIds::DEFI_DEPOSIT; tx.partial_claim_note.deposit_value = 90; @@ -1911,7 +1983,7 @@ TEST_F(join_split_tests, test_defi_bridge_call_data_config_second_input_in_use_b * - 10 paid as fee */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "Expected input_note_2_in_use, given bridge_call_data_local.config.second_input_in_use"); } @@ -1937,7 +2009,7 @@ TEST_F(join_split_tests, test_defi_missing_second_asset_in_bridge_call_data_fail * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "Expected bridge_call_data_local.config.second_input_in_use, given input_note_2_in_use && " @@ -1967,7 +2039,7 @@ TEST_F(join_split_tests, test_defi_wrong_second_asset_id_in_bridge_call_data_fai * - 10 paid as fee (in1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "Expected bridge_call_data_local.input_asset_id_b == input_note_2.asset_id, given " @@ -2002,7 +2074,7 @@ TEST_F(join_split_tests, test_repayment_logic) * - 10 out2 repayment back to depositor (in1's asset_id) */ - EXPECT_TRUE(sign_and_verify_logic(tx, user.owner).valid); + EXPECT_TRUE(sign_and_verify_logic(tx, input_user.owner).valid); } TEST_F(join_split_tests, test_virtual_note_repay_different_asset_id_fail) @@ -2029,7 +2101,7 @@ TEST_F(join_split_tests, test_virtual_note_repay_different_asset_id_fail) * - 10 out2 repayment back to depositor (INVALID asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "asset ids don't match"); } @@ -2056,7 +2128,7 @@ TEST_F(join_split_tests, test_real_input_value_lt_virtual_input_value_fails) * - 10 out2 repayment back to depositor (INVALID asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); // In this context, failure of this subtraction (due to underflow) implies input note 1's value was less than input // note 2's value (and hence the defi_deposit_value) (which is not allowed). @@ -2079,14 +2151,15 @@ TEST_F(join_split_tests, test_send_two_virtual_notes) * - 0 out2 */ - EXPECT_TRUE(sign_and_verify_logic(tx, user.owner).valid); + EXPECT_TRUE(sign_and_verify_logic(tx, input_user.owner).valid); } TEST_F(join_split_tests, test_send_one_virtual_note) { join_split_tx tx = simple_setup({ 4, 13 }); tx.num_input_notes = 1; - tx.output_note[1].input_nullifier = compute_nullifier(tx.input_note[1].commit(), user.owner.private_key, false); + tx.output_note[1].input_nullifier = + compute_nullifier(tx.input_note[1].commit(), input_user.owner.private_key, false); /** * SEND tx represents: @@ -2096,7 +2169,7 @@ TEST_F(join_split_tests, test_send_one_virtual_note) * - 0 out2 */ - EXPECT_TRUE(sign_and_verify_logic(tx, user.owner).valid); + EXPECT_TRUE(sign_and_verify_logic(tx, input_user.owner).valid); } TEST_F(join_split_tests, test_send_two_virtual_notes_nonzero_public_value_fails) @@ -2113,7 +2186,7 @@ TEST_F(join_split_tests, test_send_two_virtual_notes_nonzero_public_value_fails) * - public_value = 10 (not allowed for a send tx) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "public value invalid"); } @@ -2130,7 +2203,7 @@ TEST_F(join_split_tests, test_send_two_virtual_inputs_different_asset_ids_fails) * - 0 out2 */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "input asset ids must match unless defi-depositing"); } @@ -2149,7 +2222,7 @@ TEST_F(join_split_tests, test_send_two_virtual_inputs_different_fee_asset_id_fai * - public_asset_id = 0 (should be same as input_note_1's asset_id) */ - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "asset ids don't match"); } @@ -2162,19 +2235,19 @@ TEST_F(join_split_tests, test_non_zero_output_note_creator_pubkey_x) { { join_split_tx tx = simple_setup(); - tx.output_note[0].creator_pubkey = user.owner.public_key.x; - tx.output_note[1].creator_pubkey = user.owner.public_key.x; - EXPECT_TRUE(sign_and_verify_logic(tx, user.owner).valid); + tx.output_note[0].creator_pubkey = input_user.owner.public_key.x; + tx.output_note[1].creator_pubkey = input_user.owner.public_key.x; + EXPECT_TRUE(sign_and_verify_logic(tx, input_user.owner).valid); } { join_split_tx tx = simple_setup(); - tx.output_note[0].creator_pubkey = user.owner.public_key.x; - EXPECT_TRUE(sign_and_verify_logic(tx, user.owner).valid); + tx.output_note[0].creator_pubkey = input_user.owner.public_key.x; + EXPECT_TRUE(sign_and_verify_logic(tx, input_user.owner).valid); } { join_split_tx tx = simple_setup(); - tx.output_note[1].creator_pubkey = user.owner.public_key.x; - EXPECT_TRUE(sign_and_verify_logic(tx, user.owner).valid); + tx.output_note[1].creator_pubkey = input_user.owner.public_key.x; + EXPECT_TRUE(sign_and_verify_logic(tx, input_user.owner).valid); } } @@ -2185,7 +2258,7 @@ TEST_F(join_split_tests, test_incorrect_output_note_creator_pubkey_x) tx.output_note[0].creator_pubkey = rollup::fixtures::create_key_pair(nullptr) .public_key.x; // setting creator to be different from sender (the owner of the input notes). - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "output note 1 creator_pubkey mismatch"); } @@ -2194,7 +2267,7 @@ TEST_F(join_split_tests, test_incorrect_output_note_creator_pubkey_x) tx.output_note[1].creator_pubkey = rollup::fixtures::create_key_pair(nullptr) .public_key.x; // setting creator to be different from sender (the owner of the input notes). - auto result = sign_and_verify_logic(tx, user.owner); + auto result = sign_and_verify_logic(tx, input_user.owner); EXPECT_FALSE(result.valid); EXPECT_EQ(result.err, "output note 2 creator_pubkey mismatch"); } @@ -2219,13 +2292,13 @@ TEST_F(join_split_tests, test_deposit_full_proof) * - fee = 3 */ - auto proof = sign_and_create_proof(tx, user.owner); + auto proof = sign_and_create_proof(tx, input_user.owner); auto proof_data = inner_proof_data(proof.proof_data); auto input_note1_commitment = tx.input_note[0].commit(); auto input_note2_commitment = tx.input_note[1].commit(); - uint256_t nullifier1 = compute_nullifier(input_note1_commitment, user.owner.private_key, false); - uint256_t nullifier2 = compute_nullifier(input_note2_commitment, user.owner.private_key, false); + uint256_t nullifier1 = compute_nullifier(input_note1_commitment, input_user.owner.private_key, false); + uint256_t nullifier2 = compute_nullifier(input_note2_commitment, input_user.owner.private_key, false); auto output_note1_commitment = tx.output_note[0].commit(); auto output_note2_commitment = tx.output_note[1].commit(); @@ -2264,13 +2337,13 @@ TEST_F(join_split_tests, test_withdraw_full_proof) * - 3 paid as fee (in1's asset_id) */ - auto proof = sign_and_create_proof(tx, user.owner); + auto proof = sign_and_create_proof(tx, input_user.owner); auto proof_data = inner_proof_data(proof.proof_data); auto input_note1_commitment = tx.input_note[0].commit(); auto input_note2_commitment = tx.input_note[1].commit(); - uint256_t nullifier1 = compute_nullifier(input_note1_commitment, user.owner.private_key, true); - uint256_t nullifier2 = compute_nullifier(input_note2_commitment, user.owner.private_key, true); + uint256_t nullifier1 = compute_nullifier(input_note1_commitment, input_user.owner.private_key, true); + uint256_t nullifier2 = compute_nullifier(input_note2_commitment, input_user.owner.private_key, true); auto output_note1_commitment = tx.output_note[0].commit(); auto output_note2_commitment = tx.output_note[1].commit(); @@ -2305,15 +2378,15 @@ TEST_F(join_split_tests, test_private_send_full_proof) * - 3 paid as fee (in1's asset_id) */ - auto proof = sign_and_create_proof(tx, user.owner); + auto proof = sign_and_create_proof(tx, input_user.owner); auto proof_data = inner_proof_data(proof.proof_data); auto input_note1_commitment = tx.input_note[0].commit(); auto input_note2_commitment = tx.input_note[1].commit(); auto output_note1_commitment = tx.output_note[0].commit(); auto output_note2_commitment = tx.output_note[1].commit(); - uint256_t nullifier1 = compute_nullifier(input_note1_commitment, user.owner.private_key, true); - uint256_t nullifier2 = compute_nullifier(input_note2_commitment, user.owner.private_key, true); + uint256_t nullifier1 = compute_nullifier(input_note1_commitment, input_user.owner.private_key, true); + uint256_t nullifier2 = compute_nullifier(input_note2_commitment, input_user.owner.private_key, true); EXPECT_EQ(proof_data.proof_id, ProofIds::SEND); EXPECT_EQ(proof_data.note_commitment1, output_note1_commitment); @@ -2360,7 +2433,7 @@ TEST_F(join_split_tests, test_defi_deposit_full_proof) * - 10 paid as fee (in1's asset_id) */ - auto proof = sign_and_create_proof(tx, user.owner); + auto proof = sign_and_create_proof(tx, input_user.owner); EXPECT_TRUE(verify_proof(proof)); auto proof_data = inner_proof_data(proof.proof_data); @@ -2376,8 +2449,8 @@ TEST_F(join_split_tests, test_defi_deposit_full_proof) auto input_note2_commitment = tx.input_note[1].commit(); auto output_note1_commitment = claim_note.partial_commit(); auto output_note2_commitment = tx.output_note[1].commit(); - uint256_t nullifier1 = compute_nullifier(input_note1_commitment, user.owner.private_key, true); - uint256_t nullifier2 = compute_nullifier(input_note2_commitment, user.owner.private_key, true); + uint256_t nullifier1 = compute_nullifier(input_note1_commitment, input_user.owner.private_key, true); + uint256_t nullifier2 = compute_nullifier(input_note2_commitment, input_user.owner.private_key, true); EXPECT_EQ(proof_data.proof_id, ProofIds::DEFI_DEPOSIT); EXPECT_EQ(proof_data.note_commitment1, output_note1_commitment); @@ -2424,7 +2497,7 @@ TEST_F(join_split_tests, test_repayment_full_proof) tx.partial_claim_note.bridge_call_data = bridge_call_data.to_uint256_t(); tx.partial_claim_note.input_nullifier = tx.output_note[0].input_nullifier; - auto proof = sign_and_create_proof(tx, user.owner); + auto proof = sign_and_create_proof(tx, input_user.owner); auto proof_data = inner_proof_data(proof.proof_data); auto partial_commitment = value::create_partial_commitment( @@ -2438,8 +2511,8 @@ TEST_F(join_split_tests, test_repayment_full_proof) auto input_note2_commitment = tx.input_note[1].commit(); auto output_note1_commitment = claim_note.partial_commit(); auto output_note2_commitment = tx.output_note[1].commit(); - uint256_t nullifier1 = compute_nullifier(input_note1_commitment, user.owner.private_key, true); - uint256_t nullifier2 = compute_nullifier(input_note2_commitment, user.owner.private_key, true); + uint256_t nullifier1 = compute_nullifier(input_note1_commitment, input_user.owner.private_key, true); + uint256_t nullifier2 = compute_nullifier(input_note2_commitment, input_user.owner.private_key, true); EXPECT_EQ(proof_data.proof_id, ProofIds::DEFI_DEPOSIT); EXPECT_EQ(proof_data.note_commitment1, output_note1_commitment); @@ -2471,7 +2544,7 @@ TEST_F(join_split_tests, test_send_two_virtual_notes_full_proof) * - 0 out2 */ - auto proof = sign_and_create_proof(tx, user.owner); + auto proof = sign_and_create_proof(tx, input_user.owner); auto proof_data = inner_proof_data(proof.proof_data); @@ -2479,8 +2552,8 @@ TEST_F(join_split_tests, test_send_two_virtual_notes_full_proof) auto input_note2_commitment = tx.input_note[1].commit(); auto output_note1_commitment = tx.output_note[0].commit(); auto output_note2_commitment = tx.output_note[1].commit(); - uint256_t nullifier1 = compute_nullifier(input_note1_commitment, user.owner.private_key, true); - uint256_t nullifier2 = compute_nullifier(input_note2_commitment, user.owner.private_key, true); + uint256_t nullifier1 = compute_nullifier(input_note1_commitment, input_user.owner.private_key, true); + uint256_t nullifier2 = compute_nullifier(input_note2_commitment, input_user.owner.private_key, true); EXPECT_EQ(proof_data.proof_id, ProofIds::SEND); EXPECT_EQ(proof_data.note_commitment1, output_note1_commitment); diff --git a/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp b/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp index 468a43e698..8faa26bae3 100644 --- a/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp +++ b/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp @@ -254,17 +254,33 @@ join_split_outputs join_split_circuit_component(join_split_inputs const& inputs) // A: By passing a signature to the circuit, the 'signing private key' doesn't need to be passed to the proof // construction software. This is useful for multisigs, offline signing, etc., so that the proof construction // software (or machine) doesn't have access to the signing private key. - verify_signature(inputs.public_value.value, - inputs.public_owner, - public_asset_id.value, - output_note_1_commitment, - output_note_2.commitment, - nullifier1, - nullifier2, - signer, - inputs.backward_link, - inputs.allow_chain, - inputs.signature); + // Dec 21, 2022: Added exception for merge notes + const bool_ct verified = verify_signature(inputs.public_value.value, + inputs.public_owner, + public_asset_id.value, + output_note_1_commitment, + output_note_2.commitment, + nullifier1, + nullifier2, + signer, + inputs.backward_link, + inputs.allow_chain, + inputs.signature); + // Check if we can elide our signature, first we check if this is a note merge, + // for the case of spending a bunch of owned notes + // This is a merge if one this is a 'send' proof type and one of the output notes has value 0 + const bool_ct is_merge_send = is_send && (output_note_1_value == 0 || output_note_2_value == 0); + // If we are merging our own notes, we don't need to sign + // Note: when computing is_same_owner, we rely on input_note_1.owner == input_note_2.owner being checked already + // above + const bool_ct is_same_owner = + input_note_1.owner == output_note_1.owner && input_note_2.owner == output_note_2.owner; + const bool_ct is_same_amount = total_in_value == total_out_value; + // Exception: If merging our own notes, allow an invalid signature + // Note: must still passes basic checks, can't be 0s + const bool_ct verified_or_merge_with_same_owners_and_amount = + verified || (is_merge_send && is_same_owner && is_same_amount); + verified_or_merge_with_same_owners_and_amount.assert_equal(true, "verify signature failed"); return { nullifier1, nullifier2, output_note_1_commitment, output_note_2.commitment, public_asset_id, tx_fee, bridge_call_data, defi_deposit_value }; diff --git a/cpp/src/aztec/rollup/proofs/join_split/verify_signature.hpp b/cpp/src/aztec/rollup/proofs/join_split/verify_signature.hpp index 5c5161715e..7862e122af 100644 --- a/cpp/src/aztec/rollup/proofs/join_split/verify_signature.hpp +++ b/cpp/src/aztec/rollup/proofs/join_split/verify_signature.hpp @@ -7,24 +7,24 @@ namespace join_split { using namespace notes; -inline void verify_signature(field_ct const& public_value, - field_ct const& public_owner, - field_ct const& public_asset_id, - field_ct const& output_note1_commitment, - field_ct const& output_note2_commitment, - field_ct const& nullifier1, - field_ct const& nullifier2, - point_ct const& owner_pub_key, - field_ct const& backward_link, - field_ct const& allow_chain, - schnorr::signature_bits const& signature) +inline bool_ct verify_signature(field_ct const& public_value, + field_ct const& public_owner, + field_ct const& public_asset_id, + field_ct const& output_note1_commitment, + field_ct const& output_note2_commitment, + field_ct const& nullifier1, + field_ct const& nullifier2, + point_ct const& owner_pub_key, + field_ct const& backward_link, + field_ct const& allow_chain, + schnorr::signature_bits const& signature) { std::vector to_compress = { public_value, public_owner, public_asset_id, output_note1_commitment, output_note2_commitment, nullifier1, nullifier2, backward_link, allow_chain, }; byte_array_ct message = pedersen::compress(to_compress); - verify_signature(message, owner_pub_key, signature); + return verify_signature(message, owner_pub_key, signature); } } // namespace join_split diff --git a/cpp/src/aztec/stdlib/encryption/schnorr/schnorr.cpp b/cpp/src/aztec/stdlib/encryption/schnorr/schnorr.cpp index de0f4992c1..5b1d255b93 100644 --- a/cpp/src/aztec/stdlib/encryption/schnorr/schnorr.cpp +++ b/cpp/src/aztec/stdlib/encryption/schnorr/schnorr.cpp @@ -271,7 +271,7 @@ point variable_base_mul(const point& pub_key, const point& current_accu * @details TurboPlonk: ~10850 gates (~4k for variable_base_mul, ~6k for blake2s) for a string of length < 32. */ template -void verify_signature(const byte_array& message, const point& pub_key, const signature_bits& sig) +bool_t verify_signature(const byte_array& message, const point& pub_key, const signature_bits& sig) { // Compute [s]g, where s = (s_lo, s_hi) and g = G1::one. point R_1 = group::fixed_base_scalar_mul(sig.s_lo, sig.s_hi); @@ -292,11 +292,10 @@ void verify_signature(const byte_array& message, const point& pub_key, con // compute e' = hash(([s]g + [e]pub).x | message) byte_array output = blake2s(hash_input); - // verify that e' == e field_t output_hi(output.slice(0, 16)); field_t output_lo(output.slice(16, 16)); - output_lo.assert_equal(sig.e_lo, "verify signature failed"); - output_hi.assert_equal(sig.e_hi, "verify signature failed"); + // check that e' == e + return output_lo == sig.e_lo && output_hi == sig.e_hi; } template wnaf_record convert_field_into_wnaf( @@ -311,9 +310,10 @@ template point variable_base_mul( const point&, const wnaf_record&); -template void verify_signature(const byte_array&, - const point&, - const signature_bits&); +template bool_t verify_signature( + const byte_array&, + const point&, + const signature_bits&); template signature_bits convert_signature( waffle::TurboComposer*, const crypto::schnorr::signature&); @@ -321,4 +321,4 @@ template signature_bits convert_signature variable_base_mul(const point& pub_key, const field_t& low_bits, template signature_bits convert_signature(C* context, const crypto::schnorr::signature& sig); template -void verify_signature(const byte_array& message, const point& pub_key, const signature_bits& sig); +bool_t verify_signature(const byte_array& message, const point& pub_key, const signature_bits& sig); extern template point variable_base_mul( const point&, @@ -47,12 +47,14 @@ extern template point variable_base_mul(const point convert_field_into_wnaf( waffle::TurboComposer* context, const field_t& limb); -extern template void verify_signature(const byte_array&, - const point&, - const signature_bits&); -extern template void verify_signature(const byte_array&, - const point&, - const signature_bits&); +extern template bool_t verify_signature( + const byte_array&, + const point&, + const signature_bits&); +extern template bool_t verify_signature( + const byte_array&, + const point&, + const signature_bits&); extern template signature_bits convert_signature( waffle::TurboComposer*, const crypto::schnorr::signature&); diff --git a/cpp/src/aztec/stdlib/encryption/schnorr/schnorr.test.cpp b/cpp/src/aztec/stdlib/encryption/schnorr/schnorr.test.cpp index 1d2d641597..3c65ffb8b3 100644 --- a/cpp/src/aztec/stdlib/encryption/schnorr/schnorr.test.cpp +++ b/cpp/src/aztec/stdlib/encryption/schnorr/schnorr.test.cpp @@ -224,7 +224,8 @@ TEST(stdlib_schnorr, verify_signature) point_ct pub_key{ witness_ct(&composer, account.public_key.x), witness_ct(&composer, account.public_key.y) }; stdlib::schnorr::signature_bits sig = stdlib::schnorr::convert_signature(&composer, signature); byte_array_ct message(&composer, message_string); - stdlib::schnorr::verify_signature(message, pub_key, sig); + bool_ct result_ct = stdlib::schnorr::verify_signature(message, pub_key, sig); + result_ct.assert_equal(true, "verify signature failed"); Prover prover = composer.create_prover(); printf("composer gates = %zu\n", composer.get_num_gates()); @@ -268,7 +269,8 @@ TEST(stdlib_schnorr, verify_signature_failure) point_ct pub_key2_ct{ witness_ct(&composer, account2.public_key.x), witness_ct(&composer, account2.public_key.y) }; stdlib::schnorr::signature_bits sig = stdlib::schnorr::convert_signature(&composer, signature); byte_array_ct message(&composer, message_string); - stdlib::schnorr::verify_signature(message, pub_key2_ct, sig); + bool_ct result_ct = stdlib::schnorr::verify_signature(message, pub_key2_ct, sig); + result_ct.assert_equal(true, "verify signature failed"); Prover prover = composer.create_prover(); From 6035e8a3f5f86a74c2e11d461a861dbba0f228df Mon Sep 17 00:00:00 2001 From: ludamad Date: Tue, 10 Jan 2023 12:32:44 +0000 Subject: [PATCH 2/6] README.md: Mention bootstrap.sh directory --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9e478a22ea..ce9a659055 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ RUN git clone -b release/10.x --depth 1 https://github.com/llvm/llvm-project.git Run the bootstrap script. (The bootstrap script will build both the native and wasm versions of barretenberg) ``` +cd cpp ./bootstrap.sh ``` From 4bf174c7aeb4df5a0a1e8dad4dff4a6adad30e48 Mon Sep 17 00:00:00 2001 From: Adam Domurad Date: Mon, 16 Jan 2023 12:14:10 +0000 Subject: [PATCH 3/6] join_split: simplify from feedback --- .../proofs/join_split/join_split_circuit.cpp | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp b/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp index 8faa26bae3..1969989314 100644 --- a/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp +++ b/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp @@ -254,7 +254,6 @@ join_split_outputs join_split_circuit_component(join_split_inputs const& inputs) // A: By passing a signature to the circuit, the 'signing private key' doesn't need to be passed to the proof // construction software. This is useful for multisigs, offline signing, etc., so that the proof construction // software (or machine) doesn't have access to the signing private key. - // Dec 21, 2022: Added exception for merge notes const bool_ct verified = verify_signature(inputs.public_value.value, inputs.public_owner, public_asset_id.value, @@ -266,21 +265,17 @@ join_split_outputs join_split_circuit_component(join_split_inputs const& inputs) inputs.backward_link, inputs.allow_chain, inputs.signature); - // Check if we can elide our signature, first we check if this is a note merge, - // for the case of spending a bunch of owned notes - // This is a merge if one this is a 'send' proof type and one of the output notes has value 0 - const bool_ct is_merge_send = is_send && (output_note_1_value == 0 || output_note_2_value == 0); - // If we are merging our own notes, we don't need to sign - // Note: when computing is_same_owner, we rely on input_note_1.owner == input_note_2.owner being checked already - // above + // is_same_owner: we rely on input_note_1.owner == input_note_2.owner being checked already const bool_ct is_same_owner = input_note_1.owner == output_note_1.owner && input_note_2.owner == output_note_2.owner; const bool_ct is_same_amount = total_in_value == total_out_value; - // Exception: If merging our own notes, allow an invalid signature - // Note: must still passes basic checks, can't be 0s - const bool_ct verified_or_merge_with_same_owners_and_amount = - verified || (is_merge_send && is_same_owner && is_same_amount); - verified_or_merge_with_same_owners_and_amount.assert_equal(true, "verify signature failed"); + // is_merge_send: + // if true, we can elide our signature if this is a same-owner, same-amount send + // where one of the output notes has value 0 + const bool_ct is_merge_send = + is_send && (output_note_1_value == 0 || output_note_2_value == 0) && is_same_owner && is_same_amount; + // Caveat: A signature of all 0's will still fail basic checks + (verified || is_merge_send).assert_equal(true, "verify signature failed"); return { nullifier1, nullifier2, output_note_1_commitment, output_note_2.commitment, public_asset_id, tx_fee, bridge_call_data, defi_deposit_value }; From fa2777f9036e0370d89ad963549af77dccee0c71 Mon Sep 17 00:00:00 2001 From: Adam Domurad Date: Mon, 16 Jan 2023 12:16:12 +0000 Subject: [PATCH 4/6] Update join_split_circuit.cpp --- cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp b/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp index 1969989314..3339593cfb 100644 --- a/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp +++ b/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp @@ -270,7 +270,7 @@ join_split_outputs join_split_circuit_component(join_split_inputs const& inputs) input_note_1.owner == output_note_1.owner && input_note_2.owner == output_note_2.owner; const bool_ct is_same_amount = total_in_value == total_out_value; // is_merge_send: - // if true, we can elide our signature if this is a same-owner, same-amount send + // if true, we can elide our signature as this is a same-owner, same-amount send // where one of the output notes has value 0 const bool_ct is_merge_send = is_send && (output_note_1_value == 0 || output_note_2_value == 0) && is_same_owner && is_same_amount; From 0bc1b9d6e966fd977ea7d99ab2e826d5b74b75dd Mon Sep 17 00:00:00 2001 From: Adam Domurad Date: Mon, 16 Jan 2023 12:18:07 +0000 Subject: [PATCH 5/6] Update join_split_circuit.cpp --- cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp b/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp index 3339593cfb..1997f9fbd3 100644 --- a/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp +++ b/cpp/src/aztec/rollup/proofs/join_split/join_split_circuit.cpp @@ -272,9 +272,9 @@ join_split_outputs join_split_circuit_component(join_split_inputs const& inputs) // is_merge_send: // if true, we can elide our signature as this is a same-owner, same-amount send // where one of the output notes has value 0 + // Caveat: A signature of all 0's will still fail basic checks const bool_ct is_merge_send = is_send && (output_note_1_value == 0 || output_note_2_value == 0) && is_same_owner && is_same_amount; - // Caveat: A signature of all 0's will still fail basic checks (verified || is_merge_send).assert_equal(true, "verify signature failed"); return { nullifier1, nullifier2, output_note_1_commitment, output_note_2.commitment, From 92096a22bcf73804e74162c5a8647b2a4c541229 Mon Sep 17 00:00:00 2001 From: ludamad Date: Mon, 16 Jan 2023 12:46:36 +0000 Subject: [PATCH 6/6] constants.hpp: redo vk hashes --- cpp/src/aztec/rollup/constants.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/src/aztec/rollup/constants.hpp b/cpp/src/aztec/rollup/constants.hpp index 60da9276c1..5c1f5328f4 100644 --- a/cpp/src/aztec/rollup/constants.hpp +++ b/cpp/src/aztec/rollup/constants.hpp @@ -58,12 +58,12 @@ namespace circuit_vk_hash { constraints. They need to be changed when there is a circuit change. Note that they are written in the reverse order to comply with the from_buffer<>() method. */ constexpr auto ACCOUNT = uint256_t(0xcd6d70c733eaf823, 0x6505d3402817ad3d, 0xbf9e2b6a262589cf, 0xafcc546b55cc45e3); -constexpr auto JOIN_SPLIT = uint256_t(0x5cb3fad96d99c1dd, 0x9d6cb4da6534bed5, 0xde45f710d14e4c8f, 0xbbd799c6bc1604c6); +constexpr auto JOIN_SPLIT = uint256_t(0x7f154a0f7899ffe5, 0xb131200661bf1911, 0x9a0c8cd44c9c087b, 0x1038d50b67f8a5b3); constexpr auto CLAIM = uint256_t(0x878301ebba40ab60, 0x931466762c62d661, 0x40aad71ec3496905, 0x9f47aaa109759d0a); -constexpr auto ROLLUP = uint256_t(0xd553ea0ac51c58e9, 0x86d42c1ccbea7aa6, 0x4a909dd1739f5a4d, 0x858ee674e0e6563a); -constexpr auto ROOT_ROLLUP = uint256_t(0x27e4fc32f1b1c7c1, 0x494949a979fce5ba, 0x261c3a86be3b691f, 0xce98cdfea4b4f39c); +constexpr auto ROLLUP = uint256_t(0x10909f6022cbe853, 0x05540f4a6cdd597a, 0x89b7c29dfbfc50e2, 0xa3a335eed6b774d6); +constexpr auto ROOT_ROLLUP = uint256_t(0x4d135bb2a2aa9ac1, 0xadf2e42748b53e53, 0x501463f9b3207d2b, 0xa0d8b0d4053698ba); constexpr auto ROOT_VERIFIER = - uint256_t(0xe8e502db8a4f8d42, 0x6337b5d53c3ca77d, 0xdb4da3d73331c7ef, 0x213a2f3f34e8ad04); + uint256_t(0x85521cebe5e98f46, 0x02141f667a54d17e, 0xd8d43be20eea9560, 0xade9412d8afbb6b9); }; // namespace circuit_vk_hash namespace ProofIds {