From fd2604f15c2cb158a972c1337a05e85968f9dfdf Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Thu, 4 May 2023 13:23:20 +0100 Subject: [PATCH] Move calldatahash to components (#462) * feat: add calldatahash from kernels component * fix: tidy * fix: address nit --- .../src/aztec3/circuits/rollup/base/.test.cpp | 38 ++------- .../src/aztec3/circuits/rollup/base/init.hpp | 1 + .../base/native_base_rollup_circuit.cpp | 78 +---------------- .../circuits/rollup/components/components.cpp | 83 +++++++++++++++++++ .../circuits/rollup/components/components.hpp | 1 + .../circuits/rollup/components/init.hpp | 1 + 6 files changed, 92 insertions(+), 110 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp index 038bb547fac..b4e01d50183 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp @@ -9,6 +9,7 @@ #include "aztec3/circuits/abis/public_data_read.hpp" #include "aztec3/circuits/abis/rollup/nullifier_leaf_preimage.hpp" #include "aztec3/circuits/kernel/private/utils.hpp" +#include "aztec3/circuits/rollup/components/components.hpp" #include "aztec3/circuits/rollup/test_utils/utils.hpp" #include "aztec3/constants.hpp" #include @@ -581,46 +582,24 @@ TEST_F(base_rollup_tests, native_calldata_hash) // Execute the base rollup circuit with nullifiers, commitments and a contract deployment. Then check the calldata // hash against the expected value. std::array, 2> kernel_data = { get_empty_kernel(), get_empty_kernel() }; - std::vector input_data = test_utils::utils::get_empty_calldata_leaf(); - // Update commitment and nullifierss in kernels and testing byte array. - // Commitments and nullifiers are 32 bytes long, so we can update them in the byte array by offsetting by 32 bytes - // for every insertion. As there are two kernels in every leaf, nullifiers are offset by 8 elements (8*32). To - // insert correctly, the insertions of values from the second kernel must be offset by 4*32 bytes (kernel_offset). - // Further offset by 32 per prior insertion (j*32), and then only update the last byte (31) with the new value. // Commitments inserted are [1,2,3,4,5,6,7,8]. Nullifiers inserted are [8,9,10,11,12,13,14,15] for (size_t i = 0; i < 2; ++i) { - auto kernel_offset = i * 4 * 32; for (size_t j = 0; j < 4; j++) { - auto const offset = static_cast(kernel_offset + j * 32 + 31); - input_data[offset] = static_cast(i * 4 + j + 1); kernel_data[i].public_inputs.end.new_commitments[j] = fr(i * 4 + j + 1); - input_data[static_cast(8 * 32 + offset)] = static_cast(i * 4 + j + 8); // NOLINT kernel_data[i].public_inputs.end.new_nullifiers[j] = fr(i * 4 + j + 8); } } // Add a contract deployment - NewContractData new_contract = { + NewContractData const new_contract = { .contract_address = fr(1), .portal_contract_address = fr(3), .function_tree_root = fr(2), }; - auto contract_leaf = crypto::pedersen_commitment::compress_native( - { new_contract.contract_address, new_contract.portal_contract_address, new_contract.function_tree_root }, - GeneratorIndex::CONTRACT_LEAF); kernel_data[0].public_inputs.end.new_contracts[0] = new_contract; - auto contract_leaf_buffer = contract_leaf.to_buffer(); - auto contract_address_buffer = new_contract.contract_address.to_field().to_buffer(); - auto portal_address_buffer = new_contract.portal_contract_address.to_field().to_buffer(); - // Insert the contract leaf and contract address into the byte array - for (uint8_t i = 0; i < 32; ++i) { - input_data[32 * 32 + i] = contract_leaf_buffer[i]; - input_data[34 * 32 + i] = contract_address_buffer[i]; - input_data[35 * 32 + i] = portal_address_buffer[i]; - } - auto hash = sha256::sha256(input_data); + std::array const expected_hash = components::compute_kernels_calldata_hash(kernel_data); DummyComposer composer = DummyComposer(); BaseRollupInputs inputs = base_rollup_inputs_from_kernels(kernel_data); @@ -628,17 +607,10 @@ TEST_F(base_rollup_tests, native_calldata_hash) aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(composer, inputs); // Take the two fields and stich them together to get the calldata hash. - std::array calldata_hash_fr = outputs.calldata_hash; - auto high_buffer = calldata_hash_fr[0].to_buffer(); - auto low_buffer = calldata_hash_fr[1].to_buffer(); + std::array const calldata_hash_fr = outputs.calldata_hash; - std::array calldata_hash; - for (uint8_t i = 0; i < 16; ++i) { - calldata_hash[i] = high_buffer[16 + i]; - calldata_hash[16 + i] = low_buffer[16 + i]; - } + ASSERT_EQ(expected_hash, calldata_hash_fr); - ASSERT_EQ(hash, calldata_hash); ASSERT_FALSE(composer.failed()); run_cbind(inputs, outputs); } diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/init.hpp b/circuits/cpp/src/aztec3/circuits/rollup/base/init.hpp index 37cc215eebe..10f8c1216b1 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/init.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/init.hpp @@ -2,6 +2,7 @@ #pragma once #include "aztec3/circuits/abis/append_only_tree_snapshot.hpp" +#include "aztec3/circuits/abis/previous_kernel_data.hpp" #include "aztec3/circuits/abis/rollup/base/base_or_merge_rollup_public_inputs.hpp" #include "aztec3/circuits/abis/rollup/base/base_rollup_inputs.hpp" #include "aztec3/circuits/abis/rollup/constant_rollup_data.hpp" diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index 73ebe59b312..832ac620214 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -126,82 +126,6 @@ NT::fr calculate_commitments_subtree(DummyComposer& composer, BaseRollupInputs c return commitments_tree.root(); } -std::array calculate_calldata_hash(BaseRollupInputs const& baseRollupInputs, - std::vector const& contract_leaves) -{ - // Compute calldata hashes - // Consist of 2 kernels - // 8 commitments (4 per kernel) -> 8 fields - // 8 nullifiers (4 per kernel) -> 8 fields - // 8 public state transitions (4 per kernel) -> 16 fields - // 2 contract deployments (1 per kernel) -> 6 fields - auto const number_of_inputs = (KERNEL_NEW_COMMITMENTS_LENGTH + KERNEL_NEW_NULLIFIERS_LENGTH + - STATE_TRANSITIONS_LENGTH * 2 + KERNEL_NEW_CONTRACTS_LENGTH * 3) * - 2; - std::array calldata_hash_inputs; - - for (size_t i = 0; i < 2; i++) { - auto new_commitments = baseRollupInputs.kernel_data[i].public_inputs.end.new_commitments; - auto new_nullifiers = baseRollupInputs.kernel_data[i].public_inputs.end.new_nullifiers; - auto state_transitions = baseRollupInputs.kernel_data[i].public_inputs.end.state_transitions; - - size_t offset = 0; - - for (size_t j = 0; j < KERNEL_NEW_COMMITMENTS_LENGTH; j++) { - calldata_hash_inputs[offset + i * KERNEL_NEW_COMMITMENTS_LENGTH + j] = new_commitments[j]; - } - offset += KERNEL_NEW_COMMITMENTS_LENGTH * 2; - - for (size_t j = 0; j < KERNEL_NEW_NULLIFIERS_LENGTH; j++) { - calldata_hash_inputs[offset + i * KERNEL_NEW_NULLIFIERS_LENGTH + j] = new_nullifiers[j]; - } - offset += KERNEL_NEW_NULLIFIERS_LENGTH * 2; - - for (size_t j = 0; j < STATE_TRANSITIONS_LENGTH; j++) { - calldata_hash_inputs[offset + i * STATE_TRANSITIONS_LENGTH * 2 + j * 2] = state_transitions[j].leaf_index; - calldata_hash_inputs[offset + i * STATE_TRANSITIONS_LENGTH * 2 + j * 2 + 1] = - state_transitions[j].new_value; - } - offset += STATE_TRANSITIONS_LENGTH * 2 * 2; - - calldata_hash_inputs[offset + i] = contract_leaves[i]; - offset += KERNEL_NEW_CONTRACTS_LENGTH * 2; - - auto new_contracts = baseRollupInputs.kernel_data[i].public_inputs.end.new_contracts; - calldata_hash_inputs[offset + i * 2] = new_contracts[0].contract_address; - calldata_hash_inputs[offset + i * 2 + 1] = new_contracts[0].portal_contract_address; - } - - constexpr auto num_bytes = calldata_hash_inputs.size() * 32; - std::array calldata_hash_inputs_bytes; - // Convert all into a buffer, then copy into the array, then hash - for (size_t i = 0; i < calldata_hash_inputs.size(); i++) { - auto as_bytes = calldata_hash_inputs[i].to_buffer(); - - auto offset = i * 32; - std::copy(as_bytes.begin(), as_bytes.end(), calldata_hash_inputs_bytes.begin() + offset); - } - - std::vector const calldata_hash_inputs_bytes_vec(calldata_hash_inputs_bytes.begin(), - calldata_hash_inputs_bytes.end()); - - auto h = sha256::sha256(calldata_hash_inputs_bytes_vec); - - // Split the hash into two fields, a high and a low - std::array buf_1; - std::array buf_2; - for (uint8_t i = 0; i < 16; i++) { - buf_1[i] = 0; - buf_1[16 + i] = h[i]; - buf_2[i] = 0; - buf_2[16 + i] = h[i + 16]; - } - auto high = fr::serialize_from_buffer(buf_1.data()); - auto low = fr::serialize_from_buffer(buf_2.data()); - - return std::array{ high, low }; -} - /** * @brief Check all of the provided commitments against the historical tree roots * @@ -576,7 +500,7 @@ BaseOrMergeRollupPublicInputs base_rollup_circuit(DummyComposer& composer, BaseR fr const end_public_data_tree_root = validate_and_process_public_state(composer, baseRollupInputs); // Calculate the overall calldata hash - std::array const calldata_hash = calculate_calldata_hash(baseRollupInputs, contract_leaves); + std::array const calldata_hash = components::compute_kernels_calldata_hash(baseRollupInputs.kernel_data); // Perform membership checks that the notes provided exist within the historic trees data perform_historical_private_data_tree_membership_checks(composer, baseRollupInputs); diff --git a/circuits/cpp/src/aztec3/circuits/rollup/components/components.cpp b/circuits/cpp/src/aztec3/circuits/rollup/components/components.cpp index 48d2b3d84c4..d18767dd490 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/components/components.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/components/components.cpp @@ -95,6 +95,89 @@ void assert_equal_constants(DummyComposer& composer, utils::CircuitErrorCode::CONSTANTS_MISMATCH); } +/** + * @brief Computes the calldata hash for a base rollup + * + * @param kernel_data - 2 kernels + * @return std::array + */ +std::array compute_kernels_calldata_hash(std::array, 2> kernel_data) +{ + // Compute calldata hashes + // Consist of 2 kernels + // 8 commitments (4 per kernel) -> 8 fields + // 8 nullifiers (4 per kernel) -> 8 fields + // 8 public state transitions (4 per kernel) -> 16 fields + // 2 contract deployments (1 per kernel) -> 6 fields + auto const number_of_inputs = (KERNEL_NEW_COMMITMENTS_LENGTH + KERNEL_NEW_NULLIFIERS_LENGTH + + STATE_TRANSITIONS_LENGTH * 2 + KERNEL_NEW_CONTRACTS_LENGTH * 3) * + 2; + std::array calldata_hash_inputs; + + for (size_t i = 0; i < 2; i++) { + auto new_commitments = kernel_data[i].public_inputs.end.new_commitments; + auto new_nullifiers = kernel_data[i].public_inputs.end.new_nullifiers; + auto state_transitions = kernel_data[i].public_inputs.end.state_transitions; + + size_t offset = 0; + + for (size_t j = 0; j < KERNEL_NEW_COMMITMENTS_LENGTH; j++) { + calldata_hash_inputs[offset + i * KERNEL_NEW_COMMITMENTS_LENGTH + j] = new_commitments[j]; + } + offset += KERNEL_NEW_COMMITMENTS_LENGTH * 2; + + for (size_t j = 0; j < KERNEL_NEW_NULLIFIERS_LENGTH; j++) { + calldata_hash_inputs[offset + i * KERNEL_NEW_NULLIFIERS_LENGTH + j] = new_nullifiers[j]; + } + offset += KERNEL_NEW_NULLIFIERS_LENGTH * 2; + + for (size_t j = 0; j < STATE_TRANSITIONS_LENGTH; j++) { + calldata_hash_inputs[offset + i * STATE_TRANSITIONS_LENGTH * 2 + j * 2] = state_transitions[j].leaf_index; + calldata_hash_inputs[offset + i * STATE_TRANSITIONS_LENGTH * 2 + j * 2 + 1] = + state_transitions[j].new_value; + } + offset += STATE_TRANSITIONS_LENGTH * 2 * 2; + + auto const contract_leaf = kernel_data[i].public_inputs.end.new_contracts[0]; + calldata_hash_inputs[offset + i] = contract_leaf.is_empty() ? NT::fr::zero() : contract_leaf.hash(); + + offset += KERNEL_NEW_CONTRACTS_LENGTH * 2; + + auto new_contracts = kernel_data[i].public_inputs.end.new_contracts; + calldata_hash_inputs[offset + i * 2] = new_contracts[0].contract_address; + calldata_hash_inputs[offset + i * 2 + 1] = new_contracts[0].portal_contract_address; + } + + constexpr auto num_bytes = calldata_hash_inputs.size() * 32; + std::array calldata_hash_inputs_bytes; + // Convert all into a buffer, then copy into the array, then hash + for (size_t i = 0; i < calldata_hash_inputs.size(); i++) { + auto as_bytes = calldata_hash_inputs[i].to_buffer(); + + auto offset = i * 32; + std::copy(as_bytes.begin(), as_bytes.end(), calldata_hash_inputs_bytes.begin() + offset); + } + + std::vector const calldata_hash_inputs_bytes_vec(calldata_hash_inputs_bytes.begin(), + calldata_hash_inputs_bytes.end()); + + auto h = sha256::sha256(calldata_hash_inputs_bytes_vec); + + // Split the hash into two fields, a high and a low + std::array buf_1; + std::array buf_2; + for (uint8_t i = 0; i < 16; i++) { + buf_1[i] = 0; + buf_1[16 + i] = h[i]; + buf_2[i] = 0; + buf_2[16 + i] = h[i + 16]; + } + auto high = fr::serialize_from_buffer(buf_1.data()); + auto low = fr::serialize_from_buffer(buf_2.data()); + + return std::array{ high, low }; +} + // Generates a 512 bit input from right and left 256 bit hashes. Then computes the sha256, and splits the hash into two // field elements, a high and a low that is returned. std::array compute_calldata_hash(std::array, 2> previous_rollup_data) diff --git a/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp b/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp index 42074456b1e..31f1015c048 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp @@ -9,6 +9,7 @@ using aztec3::circuits::root_from_sibling_path; namespace aztec3::circuits::rollup::components { NT::fr calculate_empty_tree_root(size_t depth); +std::array compute_kernels_calldata_hash(std::array, 2> kernel_data); std::array compute_calldata_hash(std::array, 2> previous_rollup_data); void assert_prev_rollups_follow_on_from_each_other(DummyComposer& composer, BaseOrMergeRollupPublicInputs const& left, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/components/init.hpp b/circuits/cpp/src/aztec3/circuits/rollup/components/init.hpp index 24e55ccbeb9..ace4a8668b3 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/components/init.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/components/init.hpp @@ -2,6 +2,7 @@ #pragma once #include "aztec3/circuits/abis/append_only_tree_snapshot.hpp" +#include "aztec3/circuits/abis/previous_kernel_data.hpp" #include "aztec3/circuits/abis/rollup/base/base_or_merge_rollup_public_inputs.hpp" #include "aztec3/circuits/abis/rollup/constant_rollup_data.hpp" #include "aztec3/circuits/abis/rollup/merge/merge_rollup_inputs.hpp"