From 580540df2de7b70b109c61c2752e636e6980f531 Mon Sep 17 00:00:00 2001 From: iAmMichaelConnor Date: Wed, 5 Apr 2023 12:35:41 +0000 Subject: [PATCH] feat: partial logic to check existence of vk in contract tree (missing merkle tree membership calls) --- .../abis/private_kernel/new_contract_data.hpp | 2 + .../abis/private_kernel/private_call_data.hpp | 8 +- .../private/native_private_kernel_circuit.cpp | 178 ++++++++++++------ 3 files changed, 134 insertions(+), 54 deletions(-) diff --git a/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp b/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp index 0878b60a..809387ed 100644 --- a/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp +++ b/cpp/src/aztec3/circuits/abis/private_kernel/new_contract_data.hpp @@ -112,4 +112,6 @@ template std::ostream& operator<<(std::ostream& os, NewContractDa << "function_tree_root: " << new_contract_data.function_tree_root << "\n"; } +template using ContractLeafPreimage = NewContractData; + } // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp b/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp index 32059608..35baf05a 100644 --- a/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp +++ b/cpp/src/aztec3/circuits/abis/private_kernel/private_call_data.hpp @@ -37,6 +37,7 @@ template struct PrivateCallData { MembershipWitness contract_leaf_membership_witness; fr portal_contract_address; // an ETH address + fr acir_hash; boolean operator==(PrivateCallData const& other) const { @@ -46,6 +47,7 @@ template struct PrivateCallData { function_leaf_membership_witness == other.function_leaf_membership_witness && contract_leaf_membership_witness == other.contract_leaf_membership_witness && portal_contract_address == other.portal_contract_address; + acir_hash == other.acir_hash; }; // WARNING: the `proof` does NOT get converted! (because the current implementation of `verify_proof` takes a proof @@ -72,6 +74,7 @@ template struct PrivateCallData { to_circuit_type(contract_leaf_membership_witness), to_ct(portal_contract_address), + to_ct(acir_hash), }; return data; @@ -89,6 +92,7 @@ template void read(uint8_t const*& it, PrivateCallData& obj) read(it, obj.function_leaf_membership_witness); read(it, obj.contract_leaf_membership_witness); read(it, obj.portal_contract_address); + read(it, obj.acir_hash); }; template void write(std::vector& buf, PrivateCallData const& obj) @@ -102,6 +106,7 @@ template void write(std::vector& buf, PrivateCallData std::ostream& operator<<(std::ostream& os, PrivateCallData const& obj) @@ -118,7 +123,8 @@ template std::ostream& operator<<(std::ostream& os, PrivateCallDa << obj.function_leaf_membership_witness << "\n" << "contract_leaf_membership_witness:\n" << obj.contract_leaf_membership_witness << "\n" - << "portal_contract_address: " << obj.portal_contract_address << "\n"; + << "portal_contract_address: " << obj.portal_contract_address << "\n" + << "acir_hash: " << obj.acir_hash << "\n"; } } // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.cpp b/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.cpp index 553ac312..d839de81 100644 --- a/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.cpp +++ b/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.cpp @@ -1,15 +1,20 @@ -#include "aztec3/constants.hpp" #include "init.hpp" +#include "aztec3/circuits/abis/function_leaf_preimage.hpp" #include #include #include #include #include +#include "aztec3/constants.hpp" + +#include namespace aztec3::circuits::kernel::private_kernel { +using aztec3::circuits::abis::FunctionLeafPreimage; +using aztec3::circuits::abis::private_kernel::ContractLeafPreimage; using aztec3::circuits::abis::private_kernel::NewContractData; using aztec3::circuits::abis::private_kernel::PrivateInputs; using aztec3::circuits::abis::private_kernel::PublicInputs; @@ -23,6 +28,8 @@ using aztec3::utils::push_array_to_array; using aztec3::circuits::compute_constructor_hash; using aztec3::circuits::compute_contract_address; +// using plonk::stdlib::merkle_tree:: + // // TODO: NEED TO RECONCILE THE `proof`'s public inputs (which are uint8's) with the // // private_call.call_stack_item.public_inputs! // CT::AggregationObject verify_proofs(Composer& composer, @@ -62,73 +69,138 @@ void initialise_end_values(PrivateInputs const& private_inputs, PublicInputs end.optionally_revealed_data = start.optionally_revealed_data; } -void update_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) +void contract_logic(PrivateInputs const& private_inputs, PublicInputs& public_inputs) { const auto private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; - - const auto& new_commitments = private_call_public_inputs.new_commitments; - const auto& new_nullifiers = private_call_public_inputs.new_nullifiers; - - const auto& is_static_call = private_call_public_inputs.call_context.is_static_call; - - if (is_static_call) { - // No state changes are allowed for static calls: - ASSERT(is_array_empty(new_commitments) == true); - ASSERT(is_array_empty(new_nullifiers) == true); - } - const auto& storage_contract_address = private_call_public_inputs.call_context.storage_contract_address; const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; const auto& deployer_address = private_call_public_inputs.call_context.msg_sender; const auto& contract_deployment_data = private_inputs.signed_tx_request.tx_request.tx_context.contract_deployment_data; - { // contract deployment - // input storage contract address must be 0 if its a constructor call and non-zero otherwise - auto is_contract_deployment = public_inputs.constants.tx_context.is_contract_deployment_tx; + // contract deployment - auto private_call_vk_hash = stdlib::recursion::verification_key::compress_native( - private_inputs.private_call.vk, GeneratorIndex::VK); + // input storage contract address must be 0 if its a constructor call and non-zero otherwise + auto is_contract_deployment = public_inputs.constants.tx_context.is_contract_deployment_tx; - auto constructor_hash = compute_constructor_hash(private_inputs.signed_tx_request.tx_request.function_data, - private_call_public_inputs.args, - private_call_vk_hash); + auto private_call_vk_hash = stdlib::recursion::verification_key::compress_native( + private_inputs.private_call.vk, GeneratorIndex::VK); - if (is_contract_deployment) { - ASSERT(contract_deployment_data.constructor_vk_hash == private_call_vk_hash); - } + auto constructor_hash = compute_constructor_hash(private_inputs.signed_tx_request.tx_request.function_data, + private_call_public_inputs.args, + private_call_vk_hash); - auto contract_address = compute_contract_address(deployer_address, - contract_deployment_data.contract_address_salt, - contract_deployment_data.function_tree_root, - constructor_hash); - - if (is_contract_deployment) { - // must imply == derived address - ASSERT(storage_contract_address == contract_address); - } else { - // non-contract deployments must specify contract address being interacted with - ASSERT(storage_contract_address != 0); - } + if (is_contract_deployment) { + ASSERT(contract_deployment_data.constructor_vk_hash == private_call_vk_hash); + } - // compute contract address nullifier - auto blake_input = contract_address.to_field().to_buffer(); - auto contract_address_nullifier = NT::fr::serialize_from_buffer(NT::blake3s(blake_input).data()); + auto const new_contract_address = compute_contract_address(deployer_address, + contract_deployment_data.contract_address_salt, + contract_deployment_data.function_tree_root, + constructor_hash); - // push the contract address nullifier to nullifier vector - if (is_contract_deployment) { - array_push(public_inputs.end.new_nullifiers, contract_address_nullifier); - } + if (is_contract_deployment) { + // must imply == derived address + ASSERT(storage_contract_address == new_contract_address); + } else { + // non-contract deployments must specify contract address being interacted with + ASSERT(storage_contract_address != 0); + } - // Add new contract data if its a contract deployment function - auto native_new_contract_data = NewContractData{ contract_address, - portal_contract_address, - contract_deployment_data.function_tree_root }; + // compute contract address nullifier + auto const blake_input = new_contract_address.to_field().to_buffer(); + auto const new_contract_address_nullifier = NT::fr::serialize_from_buffer(NT::blake3s(blake_input).data()); - array_push, KERNEL_NEW_CONTRACTS_LENGTH>(public_inputs.end.new_contracts, - native_new_contract_data); + // push the contract address nullifier to nullifier vector + if (is_contract_deployment) { + array_push(public_inputs.end.new_nullifiers, new_contract_address_nullifier); } + // Add new contract data if its a contract deployment function + NewContractData native_new_contract_data{ new_contract_address, + portal_contract_address, + contract_deployment_data.function_tree_root }; + + array_push, KERNEL_NEW_CONTRACTS_LENGTH>(public_inputs.end.new_contracts, + native_new_contract_data); + + // We need to compute the root of the contract tree, starting from the function's VK: + + // Compute the vk_hash (already done above) + // + // Compute the function_leaf: hash(function_selector, is_private, vk_hash, acir_hash) + // + // Hash the function_leaf with the function_leaf's sibling_path to get the function_tree_root + // + // Compute the contract_leaf: hash(contract_address, portal_contract_address, function_tree_root) + // + // Hash the function_leaf with the contract_leaf's sibling_path to get the contract_tree_root + + const auto function_leaf_preimage = FunctionLeafPreimage{ + .function_selector = private_inputs.private_call.call_stack_item.function_data.function_selector, + .is_private = true, + .vk_hash = private_call_vk_hash, + .acir_hash = private_inputs.private_call.acir_hash, + }; + + const auto function_leaf = function_leaf_preimage.hash(); + + // TODO: compute function_tree_root using: + // the function_leaf, + auto& function_leaf_index = private_inputs.private_call.function_leaf_membership_witness.leaf_index; + auto& function_leaf_sibling_path = private_inputs.private_call.function_leaf_membership_witness.sibling_path; + + const auto function_tree_root = 1; // TODO: compute the root properly!!! + + const ContractLeafPreimage contract_leaf_preimage{ + storage_contract_address, + portal_contract_address, + function_tree_root, + }; + + const auto contract_leaf = contract_leaf_preimage.hash(); + + // TODO: compute the contract_tree_root using: + // the contract_leaf, + auto& contract_leaf_index = private_inputs.private_call.contract_leaf_membership_witness.leaf_index; + auto& contract_leaf_sibling_path = private_inputs.private_call.contract_leaf_membership_witness.sibling_path; + + // TODO remove prints + info("function_leaf: ", function_leaf); + info("function_leaf_index: ", function_leaf_index); + info("function_leaf_sibling_path: ", function_leaf_sibling_path); + info("contract_leaf: ", contract_leaf); + info("contract_leaf_index: ", contract_leaf_index); + info("contract_leaf_sibling_path: ", contract_leaf_sibling_path); + + const auto computed_contract_tree_root = 2; // TODO: compute the root properly!!! + + auto& purported_contract_tree_root = + private_inputs.private_call.call_stack_item.public_inputs.historic_contract_tree_root; + ASSERT(computed_contract_tree_root == purported_contract_tree_root); + + auto& previous_kernel_contract_tree_root = + private_inputs.previous_kernel.public_inputs.constants.old_tree_roots.contract_tree_root; + ASSERT(purported_contract_tree_root == previous_kernel_contract_tree_root); +} + +void update_end_values(PrivateInputs const& private_inputs, PublicInputs& public_inputs) +{ + const auto private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; + + const auto& new_commitments = private_call_public_inputs.new_commitments; + const auto& new_nullifiers = private_call_public_inputs.new_nullifiers; + + const auto& is_static_call = private_call_public_inputs.call_context.is_static_call; + + if (is_static_call) { + // No state changes are allowed for static calls: + ASSERT(is_array_empty(new_commitments) == true); + ASSERT(is_array_empty(new_nullifiers) == true); + } + + const auto& storage_contract_address = private_call_public_inputs.call_context.storage_contract_address; + { // Nonce nullifier // DANGER: This is terrible. This should not be part of the protocol. This is an intentional bodge to reach a @@ -183,11 +255,11 @@ void validate_this_private_call_hash(PrivateInputs const& private_inputs) const auto& start = private_inputs.previous_kernel.public_inputs.end; // TODO: this logic might need to change to accommodate the weird edge 3 initial txs (the 'main' tx, the 'fee' tx, // and the 'gas rebate' tx). - const auto this_private_call_hash = array_pop(start.private_call_stack); + const auto popped_private_call_hash = array_pop(start.private_call_stack); const auto calculated_this_private_call_hash = private_inputs.private_call.call_stack_item.hash(); - ASSERT(this_private_call_hash == - calculated_this_private_call_hash); // "this private_call_hash does not reconcile"); + ASSERT(popped_private_call_hash == + calculated_this_private_call_hash); // "this private_call_hash does not reconcile"; }; void validate_this_private_call_stack(PrivateInputs const& private_inputs)