From 78f8ad39ea47839371ca5d5d9d1c21b98ba6301e Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Tue, 28 Mar 2023 21:41:50 +0000 Subject: [PATCH 01/12] initial commit. --- cpp/barretenberg | 2 +- .../abis/private_kernel/new_contract_data.hpp | 15 +++++ .../kernel/private/private_kernel_circuit.cpp | 57 ++++++++++++++++--- cpp/src/aztec3/utils/types/circuit_types.hpp | 8 +++ 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/cpp/barretenberg b/cpp/barretenberg index 303eaf6e..71095d97 160000 --- a/cpp/barretenberg +++ b/cpp/barretenberg @@ -1 +1 @@ -Subproject commit 303eaf6e169acede64046a465146aab67036ab43 +Subproject commit 71095d97adcbd6590a36a5acfc667cc7c0df7f8d 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 536485c0..53734856 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 @@ -14,6 +14,7 @@ using std::is_same; template struct NewContractData { typedef typename NCT::address address; typedef typename NCT::fr fr; + typedef typename NCT::boolean boolean; address contract_address; address portal_contract_address; @@ -45,6 +46,12 @@ template struct NewContractData { return new_contract_data; }; + boolean is_empty() const + { + return ((contract_address.to_field() == fr(0)) && (portal_contract_address.to_field() == fr(0)) && + (function_tree_root == fr(0))); + } + void set_public() { static_assert(!(std::is_same::value)); @@ -64,6 +71,14 @@ template struct NewContractData { return NCT::compress(inputs, GeneratorIndex::CONTRACT_LEAF); } + + void conditional_select(const boolean& condition, const NewContractData& other) + { + contract_address = address::conditional_assign(condition, other.contract_address, contract_address); + portal_contract_address = + address::conditional_assign(condition, other.portal_contract_address, portal_contract_address); + function_tree_root = fr::conditional_assign(condition, other.function_tree_root, function_tree_root); + } }; template void read(uint8_t const*& it, NewContractData& new_contract_data) diff --git a/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 6edc87a6..68d85691 100644 --- a/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -4,14 +4,17 @@ #include #include +#include namespace aztec3::circuits::kernel::private_kernel { +using aztec3::circuits::abis::private_kernel::NewContractData; using aztec3::circuits::abis::private_kernel::PrivateInputs; using aztec3::circuits::abis::private_kernel::PublicInputs; using plonk::stdlib::array_length; using plonk::stdlib::array_pop; +using plonk::stdlib::array_push; using plonk::stdlib::is_array_empty; using plonk::stdlib::push_array_to_array; @@ -69,7 +72,7 @@ void initialise_end_values(PrivateInputs const& private_inputs, PublicInputs end.l1_msg_stack = start.l1_msg_stack; // TODO - // end.new_contracts = start.new_contracts; + end.new_contracts = start.new_contracts; end.optionally_revealed_data = start.optionally_revealed_data; } @@ -87,17 +90,60 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs const auto& new_commitments = private_call_public_inputs.new_commitments; const auto& new_nullifiers = private_call_public_inputs.new_nullifiers; - // TODO: const auto& new_contracts = private_call_public_inputs.new_contracts; - const auto& is_static_call = private_call_public_inputs.call_context.is_static_call; // No state changes are allowed for static calls: is_static_call.must_imply(is_array_empty(new_commitments) == true); is_static_call.must_imply(is_array_empty(new_nullifiers) == true); - // TODO: is_static_call.must_imply(is_array_empty(new_contracts) == true); // TODO: name change (just contract_address) 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; + + { // contracts + // 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; + is_contract_deployment.must_imply(storage_contract_address == CT::fr(0)); + (!is_contract_deployment).must_imply(storage_contract_address != CT::fr(0)); + + auto private_call_vk_hash = private_inputs.private_call.vk->compress(); + auto constructor_hash = CT::compress({ private_inputs.signed_tx_request.tx_request.function_data.hash(), + CT::compress(private_call_public_inputs.args), + private_call_vk_hash }, + CONSTRUCTOR); + + contract_deployment_data.constructor_vk_hash.assert_equal( + private_call_vk_hash, "constructor_vk_hash does not match private call vk hash"); + + // compute the contract address + auto contract_address = CT::compress({ deployer_address.to_field(), + contract_deployment_data.contract_address_salt, + contract_deployment_data.function_tree_root, + constructor_hash }, + CONTRACT_ADDRESS); + + // compute contract address nullifier + auto blake_input = CT::byte_array(contract_address); + auto contract_address_nullifier = CT::fr(CT::blake3s(blake_input)); + + // push the contract address nullifier to nullifier vector + array_push(public_inputs.end.new_nullifiers, contract_address_nullifier); + + // Add new contract data if its a contract deployment function + auto native_new_contract_data = + NewContractData{ .contract_address = NT::address(contract_address.get_value()), + .portal_contract_address = NT::address(portal_contract_address.get_value()), + .function_tree_root = contract_deployment_data.function_tree_root.get_value() }; + + auto context = new_commitments[0].get_context(); + NewContractData new_contract_data = native_new_contract_data.to_circuit_type(*context); + + array_push, KERNEL_NEW_CONTRACTS_LENGTH>(public_inputs.end.new_contracts, + new_contract_data); + } { // commitments, nullifiers, and contracts std::array siloed_new_commitments; @@ -116,7 +162,6 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs CT::compress({ storage_contract_address.to_field(), new_nullifiers[i] }, GeneratorIndex::OUTER_NULLIFIER)); } - // TODO contracts // Add new commitments/etc to AggregatedData push_array_to_array(siloed_new_commitments, public_inputs.end.new_commitments); @@ -131,8 +176,6 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs push_array_to_array(this_private_call_stack, public_inputs.end.private_call_stack); } - // const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; - // { // const auto& l1_msg_stack = private_call_public_inputs.l1_msg_stack; // std::array l1_call_stack; diff --git a/cpp/src/aztec3/utils/types/circuit_types.hpp b/cpp/src/aztec3/utils/types/circuit_types.hpp index 3d889818..8751abe1 100644 --- a/cpp/src/aztec3/utils/types/circuit_types.hpp +++ b/cpp/src/aztec3/utils/types/circuit_types.hpp @@ -63,6 +63,12 @@ template struct CircuitTypes { return plonk::stdlib::pedersen_commitment::compress(inputs, hash_index); } + template static fr compress(std::array const& inputs, const size_t hash_index = 0) + { + std::vector inputs_vec(std::begin(inputs), std::end(inputs)); + return plonk::stdlib::pedersen_commitment::compress(inputs_vec, hash_index); + } + static fr compress(std::vector const& inputs, std::vector const& hash_sub_indices, const size_t hash_index = 0) @@ -86,6 +92,8 @@ template struct CircuitTypes { }; static byte_array blake2s(const byte_array& input) { return plonk::stdlib::blake2s(input); } + + static byte_array blake3s(const byte_array& input) { return plonk::stdlib::blake3s(input); } }; } // namespace aztec3::utils::types \ No newline at end of file From 10284a5432276fa3a8a888306637babfaf8c1ab7 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Tue, 28 Mar 2023 21:44:05 +0000 Subject: [PATCH 02/12] remove old todo --- .../aztec3/circuits/kernel/private/private_kernel_circuit.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 68d85691..73ad8bd8 100644 --- a/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -166,8 +166,6 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs // Add new commitments/etc to AggregatedData push_array_to_array(siloed_new_commitments, public_inputs.end.new_commitments); push_array_to_array(siloed_new_nullifiers, public_inputs.end.new_nullifiers); - - // TODO contracts } { // call stacks From fbb05e9c361c47b0635c6b288442ed62d740df5d Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 29 Mar 2023 11:05:46 +0000 Subject: [PATCH 03/12] native pkc contract deployment. --- .../private/native_private_kernel_circuit.cpp | 52 ++++++++++++++++++- cpp/src/aztec3/utils/array.hpp | 11 ++++ cpp/src/aztec3/utils/types/native_types.hpp | 11 ++++ 3 files changed, 73 insertions(+), 1 deletion(-) 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 0c5a138a..e11a95b0 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 @@ -2,18 +2,20 @@ #include #include +#include #include namespace aztec3::circuits::kernel::private_kernel { +using aztec3::circuits::abis::private_kernel::NewContractData; using aztec3::circuits::abis::private_kernel::PrivateInputs; using aztec3::circuits::abis::private_kernel::PublicInputs; using aztec3::utils::array_length; using aztec3::utils::array_pop; +using aztec3::utils::array_push; using aztec3::utils::is_array_empty; -// using aztec3::utils::array_push; using aztec3::utils::push_array_to_array; // // TODO: NEED TO RECONCILE THE `proof`'s public inputs (which are uint8's) with the @@ -71,6 +73,54 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs } 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; + + { // contracts + // 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; + + if (is_contract_deployment) { + ASSERT(storage_contract_address == 0); + } else { + ASSERT(storage_contract_address != 0); + } + + auto private_call_vk_hash = + stdlib::recursion::verification_key::compress_native(private_inputs.private_call.vk); + auto constructor_hash = NT::compress({ private_inputs.signed_tx_request.tx_request.function_data.hash(), + NT::compress(private_call_public_inputs.args), + private_call_vk_hash }, + CONSTRUCTOR); + + ASSERT(contract_deployment_data.constructor_vk_hash == private_call_vk_hash); + + // compute the contract address + auto contract_address = NT::compress({ deployer_address.to_field(), + contract_deployment_data.contract_address_salt, + contract_deployment_data.function_tree_root, + constructor_hash }, + CONTRACT_ADDRESS); + + // compute contract address nullifier + auto blake_input = contract_address.to_buffer(); + auto contract_address_nullifier = NT::fr::serialize_from_buffer(NT::blake3s(blake_input).data()); + + // push the contract address nullifier to nullifier vector + // TODO: correct this + array_push(public_inputs.end.new_nullifiers, contract_address_nullifier); + + // 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 }; + + // TODO: add array_push for general data type + array_push, KERNEL_NEW_CONTRACTS_LENGTH>(public_inputs.end.new_contracts, + native_new_contract_data); + } { // commitments & nullifiers std::array siloed_new_commitments; diff --git a/cpp/src/aztec3/utils/array.hpp b/cpp/src/aztec3/utils/array.hpp index d706d9a9..ead442a6 100644 --- a/cpp/src/aztec3/utils/array.hpp +++ b/cpp/src/aztec3/utils/array.hpp @@ -56,6 +56,17 @@ template void array_push(std::array& arr, NT::fr con throw_or_abort("array_push cannot push to a full array"); }; +template void array_push(std::array& arr, T const& value) +{ + for (size_t i = 0; i < arr.size(); ++i) { + if (arr[i].is_empty()) { + arr[i] = value; + return; + } + } + throw_or_abort("array_push cannot push to a full array"); +}; + /** * Note: this assumes `0` always means 'not used', so be careful. If you actually want `0` to be counted, you'll need * something else. diff --git a/cpp/src/aztec3/utils/types/native_types.hpp b/cpp/src/aztec3/utils/types/native_types.hpp index e0b7a090..fad47c24 100644 --- a/cpp/src/aztec3/utils/types/native_types.hpp +++ b/cpp/src/aztec3/utils/types/native_types.hpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace aztec3::utils::types { @@ -63,6 +64,12 @@ struct NativeTypes { return crypto::pedersen_commitment::compress_native(inputs, hash_index); } + template static fr compress(std::array const& inputs, const size_t hash_index = 0) + { + std::vector inputs_vec(std::begin(inputs), std::end(inputs)); + return crypto::pedersen_commitment::compress_native(inputs_vec, hash_index); + } + static fr compress(const std::vector>& input_pairs) { return crypto::pedersen_commitment::compress_native(input_pairs); @@ -77,6 +84,10 @@ struct NativeTypes { { return crypto::pedersen_commitment::commit_native(input_pairs); } + + static byte_array blake2s(const byte_array& input) { return blake2::blake2s(input); } + + static byte_array blake3s(const byte_array& input) { return blake3::blake3s(input); } }; } // namespace aztec3::utils::types \ No newline at end of file From ce36128d6816a10bb657673a9d6a0b1277cdd690 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 29 Mar 2023 14:08:14 +0000 Subject: [PATCH 04/12] Fix `abis__hash_constructor`. --- cpp/src/aztec3/circuits/abis/c_bind.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/cpp/src/aztec3/circuits/abis/c_bind.cpp b/cpp/src/aztec3/circuits/abis/c_bind.cpp index 4d89c332..6923f73e 100644 --- a/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -6,6 +6,7 @@ #include "private_circuit_public_inputs.hpp" #include "tx_request.hpp" #include "tx_context.hpp" +#include "function_data.hpp" #include "function_leaf_preimage.hpp" #include "rollup/base/base_rollup_inputs.hpp" #include "rollup/base/base_rollup_public_inputs.hpp" @@ -15,12 +16,14 @@ #include #include +#include #include #include #include namespace { +using aztec3::circuits::abis::FunctionData; using aztec3::circuits::abis::FunctionLeafPreimage; using aztec3::circuits::abis::TxContext; using aztec3::circuits::abis::TxRequest; @@ -232,27 +235,30 @@ WASM_EXPORT void abis__compute_function_tree_root(uint8_t const* function_leaves * hash(function_signature_hash, args_hash, constructor_vk_hash) * Return the serialized results in the `output` buffer. * - * @param func_sig_hash_buf function signature field but as a buffer of bytes - * @param args_hash_buf constructor args hashed to a field but as a buffer of bytes + * @param function_data_buf function data struct but as a buffer of bytes + * @param args_buf constructor args (array of fields) but as a buffer of bytes * @param constructor_vk_hash_buf constructor vk hashed to a field but as a buffer of bytes * @param output buffer that will contain the output. The serialized constructor_vk_hash. */ -WASM_EXPORT void abis__hash_constructor(uint8_t const* func_sig_hash_buf, - uint8_t const* args_hash_buf, +WASM_EXPORT void abis__hash_constructor(uint8_t const* function_data_buf, + uint8_t const* args_buf, uint8_t const* constructor_vk_hash_buf, uint8_t* output) { - NT::fr func_sig_hash; - NT::fr args_hash; + FunctionData function_data; + std::array args; NT::fr constructor_vk_hash; using serialize::read; - read(func_sig_hash_buf, func_sig_hash); - read(args_hash_buf, args_hash); + read(function_data_buf, function_data); + read(args_buf, args); read(constructor_vk_hash_buf, constructor_vk_hash); + NT::fr function_data_hash = function_data.hash(); + NT::fr args_hash = NT::compress(args, aztec3::CONSTRUCTOR_ARGS); + std::vector inputs = { - func_sig_hash, + function_data_hash, args_hash, constructor_vk_hash, }; From 8d6ae5b4ea4a63262c4c96e624d55bfd5d88a6eb Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 29 Mar 2023 14:08:24 +0000 Subject: [PATCH 05/12] Contract deployment test wip. --- .../apps/function_execution_context.hpp | 1 + .../aztec3/circuits/apps/oracle_wrapper.hpp | 12 +++++ .../aztec3/circuits/kernel/private/.test.cpp | 44 ++++++++++++++----- .../private/native_private_kernel_circuit.cpp | 11 +++-- .../kernel/private/private_kernel_circuit.cpp | 18 +++++--- cpp/src/aztec3/constants.hpp | 1 + cpp/src/aztec3/oracle/oracle.hpp | 27 ++++++++++++ 7 files changed, 90 insertions(+), 24 deletions(-) diff --git a/cpp/src/aztec3/circuits/apps/function_execution_context.hpp b/cpp/src/aztec3/circuits/apps/function_execution_context.hpp index 35300d06..28f208f8 100644 --- a/cpp/src/aztec3/circuits/apps/function_execution_context.hpp +++ b/cpp/src/aztec3/circuits/apps/function_execution_context.hpp @@ -79,6 +79,7 @@ template class FunctionExecutionContext { , private_circuit_public_inputs(OptionalPrivateCircuitPublicInputs::create()) { private_circuit_public_inputs.call_context = oracle.get_call_context(); + private_circuit_public_inputs.contract_deployment_data = oracle.get_contract_deployment_data(); } void register_contract(Contract* contract) diff --git a/cpp/src/aztec3/circuits/apps/oracle_wrapper.hpp b/cpp/src/aztec3/circuits/apps/oracle_wrapper.hpp index ed0453a4..e716ea13 100644 --- a/cpp/src/aztec3/circuits/apps/oracle_wrapper.hpp +++ b/cpp/src/aztec3/circuits/apps/oracle_wrapper.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include @@ -12,6 +13,7 @@ namespace aztec3::circuits::apps { using NT = aztec3::utils::types::NativeTypes; using aztec3::circuits::abis::CallContext; +using aztec3::circuits::abis::ContractDeploymentData; using aztec3::oracle::NativeOracle; using aztec3::utils::types::CircuitTypes; @@ -60,6 +62,15 @@ template class OracleWrapperInterface { return *call_context; }; + ContractDeploymentData& get_contract_deployment_data() + { + if (contract_deployment_data) { + return *contract_deployment_data; + } + contract_deployment_data = native_oracle.get_contract_deployment_data().to_circuit_type(composer); + return *contract_deployment_data; + }; + address& get_msg_sender() { return get_call_context().msg_sender; }; address& get_this_contract_address() { return get_call_context().storage_contract_address; }; @@ -104,6 +115,7 @@ template class OracleWrapperInterface { private: std::optional> call_context; + std::optional> contract_deployment_data; std::optional msg_sender_private_key; void validate_msg_sender_private_key() diff --git a/cpp/src/aztec3/circuits/kernel/private/.test.cpp b/cpp/src/aztec3/circuits/kernel/private/.test.cpp index 80e84b7a..731fe7a7 100644 --- a/cpp/src/aztec3/circuits/kernel/private/.test.cpp +++ b/cpp/src/aztec3/circuits/kernel/private/.test.cpp @@ -469,9 +469,11 @@ TEST(private_kernel_tests, test_basic_contract_deployment) // Some private circuit proof (`constructor`, in this case) //*************************************************************************** - const NT::address new_contract_address = 12345; + // Set this to 0 and then fill it in with correct contract address + const NT::address new_contract_address = 0; // const NT::fr new_contract_leaf_index = 1; const NT::fr new_portal_contract_address = 23456; + const NT::fr contract_address_salt = 34567; const NT::fr msg_sender_private_key = 123456789; const NT::address msg_sender = @@ -496,8 +498,18 @@ TEST(private_kernel_tests, test_basic_contract_deployment) .is_contract_deployment = true, }; - NativeOracle constructor_oracle = - NativeOracle(db, new_contract_address, function_data, call_context, msg_sender_private_key); + std::shared_ptr constructor_vk = constructor_composer.compute_verification_key(); + auto constructor_vk_hash = stdlib::recursion::verification_key::compress_native(constructor_vk); + + ContractDeploymentData contract_deployment_data{ + .constructor_vk_hash = constructor_vk_hash, // TODO actually get this? + .function_tree_root = 0, // TODO actually get this? + .contract_address_salt = contract_address_salt, + .portal_contract_address = new_portal_contract_address, + }; + + NativeOracle constructor_oracle = NativeOracle( + db, new_contract_address, function_data, call_context, contract_deployment_data, msg_sender_private_key); OracleWrapper constructor_oracle_wrapper = OracleWrapper(constructor_composer, constructor_oracle); FunctionExecutionContext constructor_ctx(constructor_composer, constructor_oracle_wrapper); @@ -509,13 +521,8 @@ TEST(private_kernel_tests, test_basic_contract_deployment) OptionalPrivateCircuitPublicInputs opt_constructor_public_inputs = constructor(constructor_ctx, arg0, arg1, arg2); - ContractDeploymentData contract_deployment_data{ - .constructor_vk_hash = 0, // TODO actually get this? - .function_tree_root = 0, // TODO actually get this? - .contract_address_salt = 42, - .portal_contract_address = new_portal_contract_address, - }; - opt_constructor_public_inputs.contract_deployment_data = contract_deployment_data; + // Don't need this now: + // opt_constructor_public_inputs.contract_deployment_data = contract_deployment_data; PrivateCircuitPublicInputs constructor_public_inputs = opt_constructor_public_inputs.remove_optionality(); @@ -523,7 +530,16 @@ TEST(private_kernel_tests, test_basic_contract_deployment) NT::Proof constructor_proof = constructor_prover.construct_proof(); // info("\nconstructor_proof: ", constructor_proof.proof_data); - std::shared_ptr constructor_vk = constructor_composer.compute_verification_key(); + auto constructor_hash_real = + NT::compress({ function_data.hash(), + NT::compress(constructor_public_inputs.args, CONSTRUCTOR_ARGS), + constructor_vk_hash }, + CONSTRUCTOR); + auto contract_address_real = NT::compress({ msg_sender, + contract_deployment_data.contract_address_salt, + contract_deployment_data.function_tree_root, + constructor_hash_real }, + CONTRACT_ADDRESS); //*************************************************************************** // We can create a TxRequest from some of the above data. Users must sign a TxRequest in order to give permission @@ -624,7 +640,11 @@ TEST(private_kernel_tests, test_basic_contract_deployment) }, }; - private_kernel_circuit(private_kernel_composer, private_inputs); + auto private_kernel_circuit_public_inputs = private_kernel_circuit(private_kernel_composer, private_inputs); + + // Check contract address was correctly computed by the circuit + info("contract_address = ", contract_address_real); + // EXPECT_EQ(private_kernel_circuit_public_inputs.end.new_contracts[0].contract_address == contract_address_real); info("computed witness: ", private_kernel_composer.computed_witness); // info("witness: ", private_kernel_composer.witness); 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 e11a95b0..77a87b46 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 @@ -90,10 +90,11 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs auto private_call_vk_hash = stdlib::recursion::verification_key::compress_native(private_inputs.private_call.vk); - auto constructor_hash = NT::compress({ private_inputs.signed_tx_request.tx_request.function_data.hash(), - NT::compress(private_call_public_inputs.args), - private_call_vk_hash }, - CONSTRUCTOR); + auto constructor_hash = + NT::compress({ private_inputs.signed_tx_request.tx_request.function_data.hash(), + NT::compress(private_call_public_inputs.args, CONSTRUCTOR_ARGS), + private_call_vk_hash }, + CONSTRUCTOR); ASSERT(contract_deployment_data.constructor_vk_hash == private_call_vk_hash); @@ -109,7 +110,6 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs auto contract_address_nullifier = NT::fr::serialize_from_buffer(NT::blake3s(blake_input).data()); // push the contract address nullifier to nullifier vector - // TODO: correct this array_push(public_inputs.end.new_nullifiers, contract_address_nullifier); // Add new contract data if its a contract deployment function @@ -117,7 +117,6 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs portal_contract_address, contract_deployment_data.function_tree_root }; - // TODO: add array_push for general data type array_push, KERNEL_NEW_CONTRACTS_LENGTH>(public_inputs.end.new_contracts, native_new_contract_data); } diff --git a/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 73ad8bd8..23f444cf 100644 --- a/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -106,14 +106,18 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs { // contracts // 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; - is_contract_deployment.must_imply(storage_contract_address == CT::fr(0)); - (!is_contract_deployment).must_imply(storage_contract_address != CT::fr(0)); + is_contract_deployment.must_imply(storage_contract_address == CT::fr(0), + "storage_contract_address is not zero for contract deployment"); + (!is_contract_deployment) + .must_imply(storage_contract_address != CT::fr(0), + "storage_contract_address is zero for a private function"); auto private_call_vk_hash = private_inputs.private_call.vk->compress(); - auto constructor_hash = CT::compress({ private_inputs.signed_tx_request.tx_request.function_data.hash(), - CT::compress(private_call_public_inputs.args), - private_call_vk_hash }, - CONSTRUCTOR); + auto constructor_hash = + CT::compress({ private_inputs.signed_tx_request.tx_request.function_data.hash(), + CT::compress(private_call_public_inputs.args, CONSTRUCTOR_ARGS), + private_call_vk_hash }, + CONSTRUCTOR); contract_deployment_data.constructor_vk_hash.assert_equal( private_call_vk_hash, "constructor_vk_hash does not match private call vk hash"); @@ -125,6 +129,8 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs constructor_hash }, CONTRACT_ADDRESS); + info("circuit contract add = ", contract_address.get_value()); + // compute contract address nullifier auto blake_input = CT::byte_array(contract_address); auto contract_address_nullifier = CT::fr(CT::blake3s(blake_input)); diff --git a/cpp/src/aztec3/constants.hpp b/cpp/src/aztec3/constants.hpp index 1ece1e63..0a2d762d 100644 --- a/cpp/src/aztec3/constants.hpp +++ b/cpp/src/aztec3/constants.hpp @@ -64,6 +64,7 @@ enum GeneratorIndex { FUNCTION_LEAF, CONTRACT_DEPLOYMENT_DATA, CONSTRUCTOR, + CONSTRUCTOR_ARGS, CONTRACT_ADDRESS, CONTRACT_LEAF, CALL_CONTEXT, diff --git a/cpp/src/aztec3/oracle/oracle.hpp b/cpp/src/aztec3/oracle/oracle.hpp index 15dcbcc0..2cf94c78 100644 --- a/cpp/src/aztec3/oracle/oracle.hpp +++ b/cpp/src/aztec3/oracle/oracle.hpp @@ -4,6 +4,7 @@ #include #include +#include #include @@ -15,6 +16,7 @@ namespace aztec3::oracle { using aztec3::circuits::abis::CallContext; +using aztec3::circuits::abis::ContractDeploymentData; using aztec3::circuits::abis::FunctionData; using aztec3::circuits::apps::UTXOSLoadDatum; @@ -40,6 +42,20 @@ template class NativeOracleInterface { // , portal_contract_address(portal_contract_address) , msg_sender_private_key(msg_sender_private_key){}; + NativeOracleInterface(DB& db, + NT::address const& actual_contract_address, + FunctionData const& function_data, + CallContext const& call_context, + ContractDeploymentData const& contract_deployment_data, + std::optional const& msg_sender_private_key = std::nullopt) + : db(db) + , actual_contract_address(actual_contract_address) + , function_data(function_data) + , call_context(call_context) + , contract_deployment_data(contract_deployment_data) + // , portal_contract_address(portal_contract_address) + , msg_sender_private_key(msg_sender_private_key){}; + NT::fr get_msg_sender_private_key() { if (!msg_sender_private_key) { @@ -74,6 +90,15 @@ template class NativeOracleInterface { return call_context; }; + ContractDeploymentData get_contract_deployment_data() + { + if (contract_deployment_data_already_got) { + throw_or_abort("contract_deployment_data: " + already_got_error); + } + contract_deployment_data_already_got = true; + return contract_deployment_data; + }; + template UTXOSLoadDatum get_utxo_sload_datum(NT::grumpkin_point const storage_slot_point, NotePreimage const advice) @@ -109,6 +134,7 @@ template class NativeOracleInterface { FunctionData function_data; CallContext call_context; + ContractDeploymentData contract_deployment_data; // NT::fr portal_contract_address; std::optional msg_sender_private_key; @@ -116,6 +142,7 @@ template class NativeOracleInterface { bool actual_contract_address_already_got = false; bool function_data_already_got = false; bool call_context_already_got = false; + bool contract_deployment_data_already_got = false; // bool portal_contract_address_already_got = false; bool msg_sender_private_key_already_got = false; std::string already_got_error = "Your circuit has already accessed this value. Don't ask the oracle twice, since " From ae6ddf3e9abcbbc47a1d89b0651aa1bd6120ed02 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 29 Mar 2023 15:43:43 +0000 Subject: [PATCH 06/12] Fix contract dep test. Co-authored-by: Michael Connor --- .../circuits/abis/signed_tx_request.hpp | 5 +- .../aztec3/circuits/kernel/private/.test.cpp | 213 +++++++++++++++++- .../private/native_private_kernel_circuit.cpp | 4 +- .../kernel/private/private_kernel_circuit.cpp | 18 +- 4 files changed, 215 insertions(+), 25 deletions(-) diff --git a/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp b/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp index 37802556..28a4e4da 100644 --- a/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp +++ b/cpp/src/aztec3/circuits/abis/signed_tx_request.hpp @@ -19,15 +19,16 @@ template struct SignedTxRequest { TxRequest tx_request; Signature signature; - template SignedTxRequest> to_circuit_type(Composer& /*composer*/) const + template SignedTxRequest> to_circuit_type(Composer& composer) const { static_assert((std::is_same::value)); // Capture the composer: // auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(composer, e); }; - // auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; + auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(composer); }; SignedTxRequest> signed_tx_request; + signed_tx_request.tx_request = to_circuit_type(tx_request); // TODO: to_ct(signature) is yielding an error. // = { // to_circuit_type(tx_request), diff --git a/cpp/src/aztec3/circuits/kernel/private/.test.cpp b/cpp/src/aztec3/circuits/kernel/private/.test.cpp index 731fe7a7..1631a9ac 100644 --- a/cpp/src/aztec3/circuits/kernel/private/.test.cpp +++ b/cpp/src/aztec3/circuits/kernel/private/.test.cpp @@ -500,6 +500,7 @@ TEST(private_kernel_tests, test_basic_contract_deployment) std::shared_ptr constructor_vk = constructor_composer.compute_verification_key(); auto constructor_vk_hash = stdlib::recursion::verification_key::compress_native(constructor_vk); + info("testing_private_call_ck_hash = ", constructor_vk_hash); ContractDeploymentData contract_deployment_data{ .constructor_vk_hash = constructor_vk_hash, // TODO actually get this? @@ -518,11 +519,11 @@ TEST(private_kernel_tests, test_basic_contract_deployment) auto arg1 = NT::fr(1); auto arg2 = NT::fr(999); + info("constructor"); + info("-----------------------------"); OptionalPrivateCircuitPublicInputs opt_constructor_public_inputs = constructor(constructor_ctx, arg0, arg1, arg2); - - // Don't need this now: - // opt_constructor_public_inputs.contract_deployment_data = contract_deployment_data; + info("-----------------------------"); PrivateCircuitPublicInputs constructor_public_inputs = opt_constructor_public_inputs.remove_optionality(); @@ -530,16 +531,16 @@ TEST(private_kernel_tests, test_basic_contract_deployment) NT::Proof constructor_proof = constructor_prover.construct_proof(); // info("\nconstructor_proof: ", constructor_proof.proof_data); - auto constructor_hash_real = + auto expected_constructor_hash = NT::compress({ function_data.hash(), NT::compress(constructor_public_inputs.args, CONSTRUCTOR_ARGS), constructor_vk_hash }, CONSTRUCTOR); - auto contract_address_real = NT::compress({ msg_sender, - contract_deployment_data.contract_address_salt, - contract_deployment_data.function_tree_root, - constructor_hash_real }, - CONTRACT_ADDRESS); + auto expected_constructor_address = NT::compress({ msg_sender, + contract_deployment_data.contract_address_salt, + contract_deployment_data.function_tree_root, + expected_constructor_hash }, + CONTRACT_ADDRESS); //*************************************************************************** // We can create a TxRequest from some of the above data. Users must sign a TxRequest in order to give permission @@ -556,7 +557,7 @@ TEST(private_kernel_tests, test_basic_contract_deployment) TxContext{ .is_fee_payment_tx = false, .is_rebate_payment_tx = false, - .is_contract_deployment_tx = false, + .is_contract_deployment_tx = true, .contract_deployment_data = contract_deployment_data, }, .chain_id = 1, @@ -599,7 +600,10 @@ TEST(private_kernel_tests, test_basic_contract_deployment) mock_kernel_public_inputs.constants.tx_context = constructor_tx_request.tx_context; mock_kernel_public_inputs.is_private = true; + info("mock_kernel_circuit"); + info("-----------------------------"); mock_kernel_circuit(mock_kernel_composer, mock_kernel_public_inputs); + info("-----------------------------"); Prover mock_kernel_prover = mock_kernel_composer.create_prover(); NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); @@ -640,10 +644,14 @@ TEST(private_kernel_tests, test_basic_contract_deployment) }, }; + info("\nprivate_kernel_circuit"); + info("-----------------------------"); auto private_kernel_circuit_public_inputs = private_kernel_circuit(private_kernel_composer, private_inputs); + info("-----------------------------"); // Check contract address was correctly computed by the circuit - info("contract_address = ", contract_address_real); + info("testing_constructor_hash = ", expected_constructor_hash); + info("contract_address = ", expected_constructor_address); // EXPECT_EQ(private_kernel_circuit_public_inputs.end.new_contracts[0].contract_address == contract_address_real); info("computed witness: ", private_kernel_composer.computed_witness); @@ -658,6 +666,189 @@ TEST(private_kernel_tests, test_basic_contract_deployment) info("n: ", private_kernel_composer.num_gates); } +TEST(private_kernel_tests, test_native_basic_contract_deployment) +{ + //*************************************************************************** + // Some private circuit proof (`constructor`, in this case) + //*************************************************************************** + + // Set this to 0 and then fill it in with correct contract address + const NT::address new_contract_address = 0; + // const NT::fr new_contract_leaf_index = 1; + const NT::fr new_portal_contract_address = 23456; + const NT::fr contract_address_salt = 34567; + + const NT::fr msg_sender_private_key = 123456789; + const NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::address tx_origin = msg_sender; + + /** + * NOTE: this is a bit cheeky. We want to test the _native_ kernel circuit implementation. But I don't want to write + * a corresponding _native_ version of every 'app'. So let's just compute the circuit version of the app, and then + * convert it to native types, so that it can be fed into the kernel circuit. + * + */ + Composer constructor_composer = Composer("../barretenberg/cpp/srs_db/ignition"); + DB db; + + FunctionData function_data{ + .function_selector = 1, // TODO: deduce this from the contract, somehow. + .is_private = true, + .is_constructor = true, + }; + + CallContext call_context{ + .msg_sender = msg_sender, + .storage_contract_address = new_contract_address, + .tx_origin = msg_sender, + .is_delegate_call = false, + .is_static_call = false, + .is_contract_deployment = true, + }; + + std::shared_ptr constructor_vk = constructor_composer.compute_verification_key(); + auto constructor_vk_hash = stdlib::recursion::verification_key::compress_native(constructor_vk); + + ContractDeploymentData contract_deployment_data{ + .constructor_vk_hash = constructor_vk_hash, // TODO actually get this? + .function_tree_root = 0, // TODO actually get this? + .contract_address_salt = contract_address_salt, + .portal_contract_address = new_portal_contract_address, + }; + + NativeOracle constructor_oracle = NativeOracle( + db, new_contract_address, function_data, call_context, contract_deployment_data, msg_sender_private_key); + OracleWrapper constructor_oracle_wrapper = OracleWrapper(constructor_composer, constructor_oracle); + + FunctionExecutionContext constructor_ctx(constructor_composer, constructor_oracle_wrapper); + + auto arg0 = NT::fr(5); + auto arg1 = NT::fr(1); + auto arg2 = NT::fr(999); + + OptionalPrivateCircuitPublicInputs opt_constructor_public_inputs = + constructor(constructor_ctx, arg0, arg1, arg2); + + PrivateCircuitPublicInputs constructor_public_inputs = opt_constructor_public_inputs.remove_optionality(); + + Prover constructor_prover = constructor_composer.create_prover(); + NT::Proof constructor_proof = constructor_prover.construct_proof(); + + // auto constructor_hash_real = + // NT::compress({ function_data.hash(), + // NT::compress(constructor_public_inputs.args, CONSTRUCTOR_ARGS), + // constructor_vk_hash }, + // CONSTRUCTOR); + // auto contract_address_real = NT::compress({ msg_sender, + // contract_deployment_data.contract_address_salt, + // contract_deployment_data.function_tree_root, + // constructor_hash_real }, + // CONTRACT_ADDRESS); + + //*************************************************************************** + // We can create a TxRequest from some of the above data. Users must sign a TxRequest in order to give permission + // for a tx to take place - creating a SignedTxRequest. + //*************************************************************************** + + TxRequest constructor_tx_request = TxRequest{ + .from = tx_origin, + .to = new_contract_address, + .function_data = function_data, + .args = constructor_public_inputs.args, + .nonce = 0, + .tx_context = + TxContext{ + .is_fee_payment_tx = false, + .is_rebate_payment_tx = false, + .is_contract_deployment_tx = true, + .contract_deployment_data = contract_deployment_data, + }, + .chain_id = 1, + }; + + SignedTxRequest signed_constructor_tx_request = SignedTxRequest{ + .tx_request = constructor_tx_request, + + // .signature = TODO: need a method for signing a TxRequest. + }; + + //*************************************************************************** + // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the + // kernel circuit expects to verify some previous kernel circuit). + //*************************************************************************** + + Composer mock_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); + + // TODO: we have a choice to make: + // Either the `end` state of the mock kernel's public inputs can be set equal to the public call we _want_ to + // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore + // certain checks if we're handling the 'base case' of the recursion. + // I've chosen the former, for now. + const CallStackItem constructor_call_stack_item{ + .contract_address = constructor_tx_request.to, + + .function_data = constructor_tx_request.function_data, + + .public_inputs = constructor_public_inputs, + }; + + std::array initial_kernel_private_call_stack{}; + initial_kernel_private_call_stack[0] = constructor_call_stack_item.hash(); + + // Some test data: + auto mock_kernel_public_inputs = PublicInputs(); + mock_kernel_public_inputs.end.private_call_stack = initial_kernel_private_call_stack, + mock_kernel_public_inputs.constants.old_tree_roots.private_data_tree_root = + constructor_public_inputs.historic_private_data_tree_root; + mock_kernel_public_inputs.constants.tx_context = constructor_tx_request.tx_context; + mock_kernel_public_inputs.is_private = true; + + mock_kernel_circuit(mock_kernel_composer, mock_kernel_public_inputs); + + Prover mock_kernel_prover = mock_kernel_composer.create_prover(); + NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); + // info("\nmock_kernel_proof: ", mock_kernel_proof.proof_data); + + std::shared_ptr mock_kernel_vk = mock_kernel_composer.compute_verification_key(); + + //*************************************************************************** + // Now we can execute and prove the first kernel iteration, with all the data generated above: + // - app proof, public inputs, etc. + // - mock kernel proof, public inputs, etc. + //*************************************************************************** + + // NOTE: WE DON'T USE A COMPOSER HERE, SINCE WE WANT TO TEST THE `native_private_kernel_circuit` + // Composer private_kernel_composer = Composer("../barretenberg/cpp/srs_db/ignition"); + + PrivateInputs private_inputs = PrivateInputs{ + .signed_tx_request = signed_constructor_tx_request, + + .previous_kernel = + PreviousKernelData{ + .public_inputs = mock_kernel_public_inputs, + .proof = mock_kernel_proof, + .vk = mock_kernel_vk, + }, + + .private_call = + PrivateCallData{ + .call_stack_item = constructor_call_stack_item, + .private_call_stack_preimages = constructor_ctx.get_private_call_stack_items(), + + .proof = constructor_proof, + .vk = constructor_vk, + + // .function_leaf_membership_witness TODO + // .contract_leaf_membership_witness TODO + + .portal_contract_address = new_portal_contract_address, + }, + }; + + PublicInputs private_kernel_circuit_public_inputs = native_private_kernel_circuit(private_inputs); +} + TEST(private_kernel_tests, test_create_proof_cbinds) { //*************************************************************************** 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 77a87b46..7378f149 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 @@ -96,7 +96,9 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs private_call_vk_hash }, CONSTRUCTOR); - ASSERT(contract_deployment_data.constructor_vk_hash == private_call_vk_hash); + if (is_contract_deployment) { + ASSERT(contract_deployment_data.constructor_vk_hash == private_call_vk_hash); + } // compute the contract address auto contract_address = NT::compress({ deployer_address.to_field(), diff --git a/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 23f444cf..7e0f0ed0 100644 --- a/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -119,8 +119,8 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs private_call_vk_hash }, CONSTRUCTOR); - contract_deployment_data.constructor_vk_hash.assert_equal( - private_call_vk_hash, "constructor_vk_hash does not match private call vk hash"); + is_contract_deployment.must_imply(contract_deployment_data.constructor_vk_hash == private_call_vk_hash, + "constructor_vk_hash does not match private call vk hash"); // compute the contract address auto contract_address = CT::compress({ deployer_address.to_field(), @@ -129,8 +129,6 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs constructor_hash }, CONTRACT_ADDRESS); - info("circuit contract add = ", contract_address.get_value()); - // compute contract address nullifier auto blake_input = CT::byte_array(contract_address); auto contract_address_nullifier = CT::fr(CT::blake3s(blake_input)); @@ -139,13 +137,11 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs array_push(public_inputs.end.new_nullifiers, contract_address_nullifier); // Add new contract data if its a contract deployment function - auto native_new_contract_data = - NewContractData{ .contract_address = NT::address(contract_address.get_value()), - .portal_contract_address = NT::address(portal_contract_address.get_value()), - .function_tree_root = contract_deployment_data.function_tree_root.get_value() }; - - auto context = new_commitments[0].get_context(); - NewContractData new_contract_data = native_new_contract_data.to_circuit_type(*context); + NewContractData new_contract_data = NewContractData{ + .contract_address = contract_address, + .portal_contract_address = portal_contract_address, + .function_tree_root = contract_deployment_data.function_tree_root, + }; array_push, KERNEL_NEW_CONTRACTS_LENGTH>(public_inputs.end.new_contracts, new_contract_data); From 135e691c10a75801218b3b1963c9d7d41f659050 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 29 Mar 2023 16:03:11 +0000 Subject: [PATCH 07/12] WARNING: The private kernel circuit (at this point) works and all the tests work. BUT the contract deployement test fails when we verify the final proof. This is potentially because of a wire hanging somewhere that unsatisfying circuit. --- .../aztec3/circuits/kernel/private/.test.cpp | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/cpp/src/aztec3/circuits/kernel/private/.test.cpp b/cpp/src/aztec3/circuits/kernel/private/.test.cpp index 1631a9ac..42874541 100644 --- a/cpp/src/aztec3/circuits/kernel/private/.test.cpp +++ b/cpp/src/aztec3/circuits/kernel/private/.test.cpp @@ -500,7 +500,6 @@ TEST(private_kernel_tests, test_basic_contract_deployment) std::shared_ptr constructor_vk = constructor_composer.compute_verification_key(); auto constructor_vk_hash = stdlib::recursion::verification_key::compress_native(constructor_vk); - info("testing_private_call_ck_hash = ", constructor_vk_hash); ContractDeploymentData contract_deployment_data{ .constructor_vk_hash = constructor_vk_hash, // TODO actually get this? @@ -519,11 +518,8 @@ TEST(private_kernel_tests, test_basic_contract_deployment) auto arg1 = NT::fr(1); auto arg2 = NT::fr(999); - info("constructor"); - info("-----------------------------"); OptionalPrivateCircuitPublicInputs opt_constructor_public_inputs = constructor(constructor_ctx, arg0, arg1, arg2); - info("-----------------------------"); PrivateCircuitPublicInputs constructor_public_inputs = opt_constructor_public_inputs.remove_optionality(); @@ -536,11 +532,11 @@ TEST(private_kernel_tests, test_basic_contract_deployment) NT::compress(constructor_public_inputs.args, CONSTRUCTOR_ARGS), constructor_vk_hash }, CONSTRUCTOR); - auto expected_constructor_address = NT::compress({ msg_sender, - contract_deployment_data.contract_address_salt, - contract_deployment_data.function_tree_root, - expected_constructor_hash }, - CONTRACT_ADDRESS); + NT::fr expected_contract_address = NT::compress({ msg_sender, + contract_deployment_data.contract_address_salt, + contract_deployment_data.function_tree_root, + expected_constructor_hash }, + CONTRACT_ADDRESS); //*************************************************************************** // We can create a TxRequest from some of the above data. Users must sign a TxRequest in order to give permission @@ -600,10 +596,7 @@ TEST(private_kernel_tests, test_basic_contract_deployment) mock_kernel_public_inputs.constants.tx_context = constructor_tx_request.tx_context; mock_kernel_public_inputs.is_private = true; - info("mock_kernel_circuit"); - info("-----------------------------"); mock_kernel_circuit(mock_kernel_composer, mock_kernel_public_inputs); - info("-----------------------------"); Prover mock_kernel_prover = mock_kernel_composer.create_prover(); NT::Proof mock_kernel_proof = mock_kernel_prover.construct_proof(); @@ -644,15 +637,11 @@ TEST(private_kernel_tests, test_basic_contract_deployment) }, }; - info("\nprivate_kernel_circuit"); - info("-----------------------------"); auto private_kernel_circuit_public_inputs = private_kernel_circuit(private_kernel_composer, private_inputs); - info("-----------------------------"); // Check contract address was correctly computed by the circuit - info("testing_constructor_hash = ", expected_constructor_hash); - info("contract_address = ", expected_constructor_address); - // EXPECT_EQ(private_kernel_circuit_public_inputs.end.new_contracts[0].contract_address == contract_address_real); + EXPECT_EQ(private_kernel_circuit_public_inputs.end.new_contracts[0].contract_address.to_field(), + expected_contract_address); info("computed witness: ", private_kernel_composer.computed_witness); // info("witness: ", private_kernel_composer.witness); From b6f66cfa25e91fb8e49000091bb49a53e98edf83 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 29 Mar 2023 16:46:57 +0000 Subject: [PATCH 08/12] Fix c_bind test. --- cpp/src/aztec3/circuits/abis/c_bind.h | 11 +++----- cpp/src/aztec3/circuits/abis/c_bind.test.cpp | 29 ++++++++++++-------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/cpp/src/aztec3/circuits/abis/c_bind.h b/cpp/src/aztec3/circuits/abis/c_bind.h index b8827f33..af5fca1b 100644 --- a/cpp/src/aztec3/circuits/abis/c_bind.h +++ b/cpp/src/aztec3/circuits/abis/c_bind.h @@ -8,8 +8,7 @@ WASM_EXPORT void abis__hash_tx_request(uint8_t const* tx_request_buf, uint8_t* o WASM_EXPORT void abis__compute_function_selector(char const* func_sig_cstr, uint8_t* output); -WASM_EXPORT void abis__compute_function_leaf(uint8_t const* function_leaf_preimage_buf, - uint8_t* output); +WASM_EXPORT void abis__compute_function_leaf(uint8_t const* function_leaf_preimage_buf, uint8_t* output); WASM_EXPORT void abis__compute_function_tree_root(uint8_t const* function_leaves_buf, uint8_t num_leaves, @@ -17,8 +16,8 @@ WASM_EXPORT void abis__compute_function_tree_root(uint8_t const* function_leaves WASM_EXPORT void abis__hash_vk(uint8_t const* vk_data_buf, uint8_t* output); -WASM_EXPORT void abis__hash_constructor(uint8_t const* func_sig_hash_buf, - uint8_t const* args_hash_buf, +WASM_EXPORT void abis__hash_constructor(uint8_t const* func_data_buf, + uint8_t const* args_buf, uint8_t const* constructor_vk_hash_buf, uint8_t* output); @@ -28,7 +27,5 @@ WASM_EXPORT void abis__compute_contract_address(uint8_t const* deployer_address_ uint8_t const* constructor_hash_buf, uint8_t* output); -WASM_EXPORT void abis__compute_contract_leaf(uint8_t const* contract_leaf_preimage_buf, - uint8_t* output); - +WASM_EXPORT void abis__compute_contract_leaf(uint8_t const* contract_leaf_preimage_buf, uint8_t* output); } \ No newline at end of file diff --git a/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index 2be2cff1..f2c7ed09 100644 --- a/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -193,31 +193,38 @@ TEST(abi_tests, compute_function_tree_root) TEST(abi_tests, hash_constructor) { // Randomize required values - NT::fr func_sig_hash = NT::fr::random_element(); - NT::fr args_hash = NT::fr::random_element(); + FunctionData func_data = + FunctionData{ .function_selector = 10, .is_private = true, .is_constructor = false }; + + std::array args; + for (size_t i = 0; i < aztec3::ARGS_LENGTH; i++) { + args[i] = fr::random_element(); + } NT::fr constructor_vk_hash = NT::fr::random_element(); - // Serialize values to buffers - std::array func_sig_hash_buf = { 0 }; - std::array args_hash_buf = { 0 }; + // Write the function data and args to a buffer + std::vector func_data_buf; + write(func_data_buf, func_data); + + std::vector args_buf; + write(args_buf, args); + std::array constructor_vk_hash_buf = { 0 }; - NT::fr::serialize_to_buffer(func_sig_hash, func_sig_hash_buf.data()); - NT::fr::serialize_to_buffer(args_hash, args_hash_buf.data()); NT::fr::serialize_to_buffer(constructor_vk_hash, constructor_vk_hash_buf.data()); // create an output buffer for cbind hash results std::array output = { 0 }; // Make the c_bind call to hash the constructor values - abis__hash_constructor( - func_sig_hash_buf.data(), args_hash_buf.data(), constructor_vk_hash_buf.data(), output.data()); + abis__hash_constructor(func_data_buf.data(), args_buf.data(), constructor_vk_hash_buf.data(), output.data()); // Convert buffer to `fr` for comparison to in-test calculated hash NT::fr got_hash = NT::fr::serialize_from_buffer(output.data()); // Calculate the expected hash in-test - NT::fr expected_hash = - NT::compress({ func_sig_hash, args_hash, constructor_vk_hash }, aztec3::GeneratorIndex::CONSTRUCTOR); + NT::fr expected_hash = NT::compress( + { func_data.hash(), NT::compress(args, aztec3::GeneratorIndex::CONSTRUCTOR_ARGS), constructor_vk_hash }, + aztec3::GeneratorIndex::CONSTRUCTOR); // Confirm cbind output == expected hash EXPECT_EQ(got_hash, expected_hash); From 414cc0d656cbffc4c467375530e18f8dae83f35e Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 29 Mar 2023 17:49:53 +0000 Subject: [PATCH 09/12] Fix test. --- .../aztec3/circuits/kernel/private/private_kernel_circuit.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 7e0f0ed0..ad018071 100644 --- a/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -134,7 +134,9 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs auto contract_address_nullifier = CT::fr(CT::blake3s(blake_input)); // push the contract address nullifier to nullifier vector - array_push(public_inputs.end.new_nullifiers, contract_address_nullifier); + CT::fr conditional_contract_address_nullifier = + CT::fr::conditional_assign(is_contract_deployment, contract_address_nullifier, CT::fr(0)); + array_push(public_inputs.end.new_nullifiers, conditional_contract_address_nullifier); // Add new contract data if its a contract deployment function NewContractData new_contract_data = NewContractData{ From 0a587a4eba14017fa904430a5128377fad617978 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Wed, 29 Mar 2023 17:51:10 +0000 Subject: [PATCH 10/12] Fix native private kernel test. --- .../circuits/kernel/private/native_private_kernel_circuit.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 7378f149..6799ef7a 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 @@ -112,7 +112,9 @@ void update_end_values(PrivateInputs const& private_inputs, PublicInputs auto contract_address_nullifier = NT::fr::serialize_from_buffer(NT::blake3s(blake_input).data()); // push the contract address nullifier to nullifier vector - array_push(public_inputs.end.new_nullifiers, contract_address_nullifier); + if (is_contract_deployment) { + array_push(public_inputs.end.new_nullifiers, contract_address_nullifier); + } // Add new contract data if its a contract deployment function auto native_new_contract_data = NewContractData{ contract_address, From 769d66b0f16e4a81fed95900ad98b254e9852b53 Mon Sep 17 00:00:00 2001 From: Michael Connor Date: Thu, 30 Mar 2023 14:40:23 +0100 Subject: [PATCH 11/12] fix: contract_deployment test bug (#138) * fix: contract_deployment test bug * Fix native array to array push. --------- Co-authored-by: Suyash Bagad --- .../aztec3/circuits/kernel/private/.test.cpp | 96 +++++++++++++++---- cpp/src/aztec3/utils/array.hpp | 46 ++++----- 2 files changed, 96 insertions(+), 46 deletions(-) diff --git a/cpp/src/aztec3/circuits/kernel/private/.test.cpp b/cpp/src/aztec3/circuits/kernel/private/.test.cpp index 42874541..a5eee5a2 100644 --- a/cpp/src/aztec3/circuits/kernel/private/.test.cpp +++ b/cpp/src/aztec3/circuits/kernel/private/.test.cpp @@ -480,9 +480,6 @@ TEST(private_kernel_tests, test_basic_contract_deployment) NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); const NT::address tx_origin = msg_sender; - Composer constructor_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - DB db; - FunctionData function_data{ .function_selector = 1, // TODO: deduce this from the contract, somehow. .is_private = true, @@ -498,9 +495,48 @@ TEST(private_kernel_tests, test_basic_contract_deployment) .is_contract_deployment = true, }; - std::shared_ptr constructor_vk = constructor_composer.compute_verification_key(); + NT::fr arg0 = 5; + NT::fr arg1 = 1; + NT::fr arg2 = 999; + + Composer dummy_constructor_composer = Composer("../barretenberg/cpp/srs_db/ignition"); + { + // Dummmy invokation, in order to derive the vk of this circuit + + // We need to use _dummy_ contract_deployment_data first, because the _proper_ version of the + // contract_deployment_data will need to contain the constructor_vk_hash... but the constructor's vk can only be + // computed after the composer has composed the circuit! + ContractDeploymentData dummy_contract_deployment_data{ + .constructor_vk_hash = 0, // dummy + .function_tree_root = 0, // TODO actually get this? + .contract_address_salt = contract_address_salt, + .portal_contract_address = new_portal_contract_address, + }; + + DB dummy_db; + NativeOracle dummy_constructor_oracle = NativeOracle(dummy_db, + new_contract_address, + function_data, + call_context, + dummy_contract_deployment_data, + msg_sender_private_key); + OracleWrapper dummy_constructor_oracle_wrapper = + OracleWrapper(dummy_constructor_composer, dummy_constructor_oracle); + + FunctionExecutionContext dummy_constructor_ctx(dummy_constructor_composer, dummy_constructor_oracle_wrapper); + + constructor(dummy_constructor_ctx, arg0, arg1, arg2); + } + + // Now we can derive the vk: + std::shared_ptr constructor_vk = dummy_constructor_composer.compute_verification_key(); auto constructor_vk_hash = stdlib::recursion::verification_key::compress_native(constructor_vk); + // Now, we can proceed with the proper (non-dummy) invokation of our constructor circuit: + + Composer constructor_composer = Composer("../barretenberg/cpp/srs_db/ignition"); + DB db; + ContractDeploymentData contract_deployment_data{ .constructor_vk_hash = constructor_vk_hash, // TODO actually get this? .function_tree_root = 0, // TODO actually get this? @@ -514,10 +550,6 @@ TEST(private_kernel_tests, test_basic_contract_deployment) FunctionExecutionContext constructor_ctx(constructor_composer, constructor_oracle_wrapper); - auto arg0 = NT::fr(5); - auto arg1 = NT::fr(1); - auto arg2 = NT::fr(999); - OptionalPrivateCircuitPublicInputs opt_constructor_public_inputs = constructor(constructor_ctx, arg0, arg1, arg2); @@ -678,9 +710,6 @@ TEST(private_kernel_tests, test_native_basic_contract_deployment) * convert it to native types, so that it can be fed into the kernel circuit. * */ - Composer constructor_composer = Composer("../barretenberg/cpp/srs_db/ignition"); - DB db; - FunctionData function_data{ .function_selector = 1, // TODO: deduce this from the contract, somehow. .is_private = true, @@ -696,9 +725,48 @@ TEST(private_kernel_tests, test_native_basic_contract_deployment) .is_contract_deployment = true, }; - std::shared_ptr constructor_vk = constructor_composer.compute_verification_key(); + NT::fr arg0 = 5; + NT::fr arg1 = 1; + NT::fr arg2 = 999; + + Composer dummy_constructor_composer = Composer("../barretenberg/cpp/srs_db/ignition"); + { + // Dummmy invokation, in order to derive the vk of this circuit + + // We need to use _dummy_ contract_deployment_data first, because the _proper_ version of the + // contract_deployment_data will need to contain the constructor_vk_hash... but the constructor's vk can only be + // computed after the composer has composed the circuit! + ContractDeploymentData dummy_contract_deployment_data{ + .constructor_vk_hash = 0, // dummy + .function_tree_root = 0, // TODO actually get this? + .contract_address_salt = contract_address_salt, + .portal_contract_address = new_portal_contract_address, + }; + + DB dummy_db; + NativeOracle dummy_constructor_oracle = NativeOracle(dummy_db, + new_contract_address, + function_data, + call_context, + dummy_contract_deployment_data, + msg_sender_private_key); + OracleWrapper dummy_constructor_oracle_wrapper = + OracleWrapper(dummy_constructor_composer, dummy_constructor_oracle); + + FunctionExecutionContext dummy_constructor_ctx(dummy_constructor_composer, dummy_constructor_oracle_wrapper); + + constructor(dummy_constructor_ctx, arg0, arg1, arg2); + } + + // Now we can derive the vk: + std::shared_ptr constructor_vk = dummy_constructor_composer.compute_verification_key(); auto constructor_vk_hash = stdlib::recursion::verification_key::compress_native(constructor_vk); + // Now, we can proceed with the proper (non-dummy) invokation of our constructor circuit: + + Composer constructor_composer = Composer("../barretenberg/cpp/srs_db/ignition"); + DB db; + ContractDeploymentData contract_deployment_data{ .constructor_vk_hash = constructor_vk_hash, // TODO actually get this? .function_tree_root = 0, // TODO actually get this? @@ -712,10 +780,6 @@ TEST(private_kernel_tests, test_native_basic_contract_deployment) FunctionExecutionContext constructor_ctx(constructor_composer, constructor_oracle_wrapper); - auto arg0 = NT::fr(5); - auto arg1 = NT::fr(1); - auto arg2 = NT::fr(999); - OptionalPrivateCircuitPublicInputs opt_constructor_public_inputs = constructor(constructor_ctx, arg0, arg1, arg2); diff --git a/cpp/src/aztec3/utils/array.hpp b/cpp/src/aztec3/utils/array.hpp index ead442a6..dabb20b2 100644 --- a/cpp/src/aztec3/utils/array.hpp +++ b/cpp/src/aztec3/utils/array.hpp @@ -82,42 +82,28 @@ template NT::boolean is_array_empty(std::array const /** * Inserts the `source` array at the first zero-valued index of the `target` array. + * Ensures that all values after the first zero-valued index are zeros too. * Fails if the `source` array is too large vs the remaining capacity of the `target` array. - * TODO: this is an awful mess and should be improved! */ template void push_array_to_array(std::array const& source, std::array& target) { - // TODO: inefficient to get length this way within this function. Probably best to inline the checks that we need - // into the below loops directly. - NT::fr target_length = array_length(target); - NT::fr target_capacity = NT::fr(target.size()); - const NT::fr overflow_capacity = target_capacity + 1; - - // ASSERT(uint256_t(target_capacity.get_value()) + 1 > - // uint256_t(target_length.get_value()) + uint256_t(source_length.get_value())); - - NT::fr j_ct = 0; // circuit-type index for the inner loop - NT::fr next_target_index = target_length; - for (size_t i = 0; i < source.size(); ++i) { - auto& s = source[i]; - - // Triangular loop: - for (size_t j = i; j < target.size() - source.size() + i + 1; ++j) { - auto& t = target[j]; - - NT::boolean at_next_index = j_ct == next_target_index; - - t = at_next_index ? s : t; - - j_ct++; + // Check if the `source` array is too large vs the remaining capacity of the `target` array + size_t source_size = static_cast(uint256_t(array_length(source))); + size_t target_size = static_cast(uint256_t(array_length(target))); + ASSERT(source_size <= size_2 - target_size); + + // Ensure that there are no non-zero values in the `target` array after the first zero-valued index + for (size_t i = target_size; i < size_2; i++) { + ASSERT(target[i] == NT::fr(0)); + } + // Copy the non-zero elements of the `source` array to the `target` array at the first zero-valued index + auto zero_index = target_size; + for (size_t i = 0; i < size_1; i++) { + if (source[i] != NT::fr(0)) { + target[zero_index] = source[i]; + zero_index++; } - - next_target_index++; - - ASSERT(next_target_index != overflow_capacity); //"push_array_to_array target array capacity exceeded" - - j_ct = i + 1; } } From ece9a59b822fda1aaedc717034f0dcc22d8fcc13 Mon Sep 17 00:00:00 2001 From: Suyash Bagad Date: Thu, 30 Mar 2023 14:09:02 +0000 Subject: [PATCH 12/12] resolve bb issue. --- cpp/barretenberg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/barretenberg b/cpp/barretenberg index 71095d97..507473e7 160000 --- a/cpp/barretenberg +++ b/cpp/barretenberg @@ -1 +1 @@ -Subproject commit 71095d97adcbd6590a36a5acfc667cc7c0df7f8d +Subproject commit 507473e78261a9eaca185a6e8a2aa73bf753d8b1