diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 0f10fb87ed..dd12bae8b3 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -50,9 +50,9 @@ void create_circuit(Composer& composer, const acir_format& constraint_system) create_sha256_constraints(composer, constraint); } - // Add merkle membership constraints - for (const auto& constraint : constraint_system.merkle_membership_constraints) { - create_merkle_check_membership_constraint(composer, constraint); + // Add compute merkle root constraints + for (const auto& constraint : constraint_system.compute_merkle_root_constraints) { + create_compute_merkle_root_constraint(composer, constraint); } // Add schnorr constraints @@ -128,9 +128,9 @@ Composer create_circuit(const acir_format& constraint_system, create_sha256_constraints(composer, constraint); } - // Add merkle membership constraints - for (const auto& constraint : constraint_system.merkle_membership_constraints) { - create_merkle_check_membership_constraint(composer, constraint); + // Add compute merkle root constraints + for (const auto& constraint : constraint_system.compute_merkle_root_constraints) { + create_compute_merkle_root_constraint(composer, constraint); } // Add schnorr constraints @@ -212,9 +212,9 @@ Composer create_circuit_with_witness(const acir_format& constraint_system, create_sha256_constraints(composer, constraint); } - // Add merkle membership constraints - for (const auto& constraint : constraint_system.merkle_membership_constraints) { - create_merkle_check_membership_constraint(composer, constraint); + // Add compute merkle root constraints + for (const auto& constraint : constraint_system.compute_merkle_root_constraints) { + create_compute_merkle_root_constraint(composer, constraint); } // Add schnorr constraints @@ -293,9 +293,9 @@ Composer create_circuit_with_witness(const acir_format& constraint_system, std:: create_sha256_constraints(composer, constraint); } - // Add merkle membership constraints - for (const auto& constraint : constraint_system.merkle_membership_constraints) { - create_merkle_check_membership_constraint(composer, constraint); + // Add compute merkle root constraints + for (const auto& constraint : constraint_system.compute_merkle_root_constraints) { + create_compute_merkle_root_constraint(composer, constraint); } // Add schnorr constraints @@ -372,9 +372,9 @@ void create_circuit_with_witness(Composer& composer, const acir_format& constrai create_sha256_constraints(composer, constraint); } - // Add merkle membership constraints - for (const auto& constraint : constraint_system.merkle_membership_constraints) { - create_merkle_check_membership_constraint(composer, constraint); + // Add compute merkle root constraints + for (const auto& constraint : constraint_system.compute_merkle_root_constraints) { + create_compute_merkle_root_constraint(composer, constraint); } // Add schnorr constraints diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp index 0b326e922c..0f27040dbe 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp @@ -6,7 +6,7 @@ #include "fixed_base_scalar_mul.hpp" #include "schnorr_verify.hpp" #include "ecdsa_secp256k1.hpp" -#include "merkle_membership_constraint.hpp" +#include "compute_merkle_root_constraint.hpp" #include "pedersen.hpp" #include "hash_to_field.hpp" #include "barretenberg/dsl/types.hpp" @@ -28,7 +28,7 @@ struct acir_format { std::vector blake2s_constraints; std::vector hash_to_field_constraints; std::vector pedersen_constraints; - std::vector merkle_membership_constraints; + std::vector compute_merkle_root_constraints; // A standard plonk arithmetic constraint, as defined in the poly_triple struct, consists of selector values // for q_M,q_L,q_R,q_O,q_C and indices of three variables taking the role of left, right and output wire std::vector constraints; @@ -60,7 +60,7 @@ template inline void read(B& buf, acir_format& data) read(buf, data.logic_constraints); read(buf, data.range_constraints); read(buf, data.sha256_constraints); - read(buf, data.merkle_membership_constraints); + read(buf, data.compute_merkle_root_constraints); read(buf, data.schnorr_constraints); read(buf, data.ecdsa_constraints); read(buf, data.blake2s_constraints); @@ -78,7 +78,7 @@ template inline void write(B& buf, acir_format const& data) write(buf, data.logic_constraints); write(buf, data.range_constraints); write(buf, data.sha256_constraints); - write(buf, data.merkle_membership_constraints); + write(buf, data.compute_merkle_root_constraints); write(buf, data.schnorr_constraints); write(buf, data.ecdsa_constraints); write(buf, data.blake2s_constraints); diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp index 586a82b03d..6929864580 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp @@ -88,7 +88,7 @@ TEST(acir_format, test_logic_gate_from_noir_circuit) .blake2s_constraints = {}, .hash_to_field_constraints = {}, .pedersen_constraints = {}, - .merkle_membership_constraints = {}, + .compute_merkle_root_constraints = {}, .constraints = { expr_a, expr_b, expr_c, expr_d }, }; @@ -152,7 +152,7 @@ TEST(acir_format, test_schnorr_verify_pass) .blake2s_constraints = {}, .hash_to_field_constraints = {}, .pedersen_constraints = {}, - .merkle_membership_constraints = {}, + .compute_merkle_root_constraints = {}, .constraints = { poly_triple{ .a = schnorr_constraint.result, .b = schnorr_constraint.result, @@ -221,7 +221,7 @@ TEST(acir_format, test_schnorr_verify_small_range) .blake2s_constraints = {}, .hash_to_field_constraints = {}, .pedersen_constraints = {}, - .merkle_membership_constraints = {}, + .compute_merkle_root_constraints = {}, .constraints = { poly_triple{ .a = schnorr_constraint.result, .b = schnorr_constraint.result, @@ -249,4 +249,4 @@ TEST(acir_format, test_schnorr_verify_small_range) auto verifier = composer.create_ultra_with_keccak_verifier(); EXPECT_EQ(verifier.verify_proof(proof), true); -} \ No newline at end of file +} diff --git a/cpp/src/barretenberg/dsl/acir_format/merkle_membership_constraint.cpp b/cpp/src/barretenberg/dsl/acir_format/compute_merkle_root_constraint.cpp similarity index 67% rename from cpp/src/barretenberg/dsl/acir_format/merkle_membership_constraint.cpp rename to cpp/src/barretenberg/dsl/acir_format/compute_merkle_root_constraint.cpp index 780373f5be..74af03d4a3 100644 --- a/cpp/src/barretenberg/dsl/acir_format/merkle_membership_constraint.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/compute_merkle_root_constraint.cpp @@ -1,21 +1,18 @@ -#include "merkle_membership_constraint.hpp" +#include "compute_merkle_root_constraint.hpp" #include "barretenberg/stdlib/merkle_tree/membership.hpp" namespace acir_format { -void create_merkle_check_membership_constraint(Composer& composer, const MerkleMembershipConstraint& input) +void create_compute_merkle_root_constraint(Composer& composer, const ComputeMerkleRootConstraint& constraint) { // Convert value from a witness index into a field element. // This is the hash of the message. In Barretenberg, this would be input.value = hash_value(message) - field_ct leaf = field_ct::from_witness_index(&composer, input.leaf); + field_ct leaf = field_ct::from_witness_index(&composer, constraint.leaf); // Convert index from a witness index into a byte array - field_ct index_field = field_ct::from_witness_index(&composer, input.index); + field_ct index_field = field_ct::from_witness_index(&composer, constraint.index); auto index_bits = index_field.decompose_into_bits(); - // Convert root into a field_ct - field_ct root = field_ct::from_witness_index(&composer, input.root); - // We are given the HashPath as a Vec // We want to first convert it into a Vec<(fr, fr)> then cast this to hash_path // struct which requires the method create_witness_hashpath @@ -24,20 +21,21 @@ void create_merkle_check_membership_constraint(Composer& composer, const MerkleM // In Noir we accept a hash path that only contains one hash per tree level // It is ok to reuse the leaf as it will be overridden in check_subtree_membership when computing the current root // at each tree level - for (size_t i = 0; i < input.hash_path.size(); i++) { + for (size_t i = 0; i < constraint.hash_path.size(); i++) { if (!index_bits[i].get_value()) { field_ct left = leaf; - field_ct right = field_ct::from_witness_index(&composer, input.hash_path[i]); + field_ct right = field_ct::from_witness_index(&composer, constraint.hash_path[i]); hash_path.push_back(std::make_pair(left, right)); } else { - field_ct left = field_ct::from_witness_index(&composer, input.hash_path[i]); + field_ct left = field_ct::from_witness_index(&composer, constraint.hash_path[i]); field_ct right = leaf; hash_path.push_back(std::make_pair(left, right)); } } - auto exists = plonk::stdlib::merkle_tree::check_subtree_membership(root, hash_path, leaf, index_bits, 0); - composer.assert_equal_constant(exists.witness_index, fr::one()); + auto merkle_root = plonk::stdlib::merkle_tree::compute_subtree_root(hash_path, leaf, index_bits, 0); + + composer.assert_equal(merkle_root.witness_index, constraint.result); } } // namespace acir_format diff --git a/cpp/src/barretenberg/dsl/acir_format/merkle_membership_constraint.hpp b/cpp/src/barretenberg/dsl/acir_format/compute_merkle_root_constraint.hpp similarity index 56% rename from cpp/src/barretenberg/dsl/acir_format/merkle_membership_constraint.hpp rename to cpp/src/barretenberg/dsl/acir_format/compute_merkle_root_constraint.hpp index 25bfcd0404..036a58aad1 100644 --- a/cpp/src/barretenberg/dsl/acir_format/merkle_membership_constraint.hpp +++ b/cpp/src/barretenberg/dsl/acir_format/compute_merkle_root_constraint.hpp @@ -4,33 +4,30 @@ namespace acir_format { -struct MerkleMembershipConstraint { +struct ComputeMerkleRootConstraint { std::vector hash_path; // Vector of pairs of hashpaths. eg indices 0,1 denotes the pair (0,1) - uint32_t root; // Single field element -- field_t uint32_t leaf; // Single field element -- field_t - uint32_t result; // Single field element -- bool_t + uint32_t result; // Single field element -- field_t uint32_t index; - friend bool operator==(MerkleMembershipConstraint const& lhs, MerkleMembershipConstraint const& rhs) = default; + friend bool operator==(ComputeMerkleRootConstraint const& lhs, ComputeMerkleRootConstraint const& rhs) = default; }; -void create_merkle_check_membership_constraint(Composer& composer, const MerkleMembershipConstraint& input); +void create_compute_merkle_root_constraint(Composer& composer, const ComputeMerkleRootConstraint& input); -template inline void read(B& buf, MerkleMembershipConstraint& constraint) +template inline void read(B& buf, ComputeMerkleRootConstraint& constraint) { using serialize::read; read(buf, constraint.hash_path); - read(buf, constraint.root); read(buf, constraint.leaf); read(buf, constraint.result); read(buf, constraint.index); } -template inline void write(B& buf, MerkleMembershipConstraint const& constraint) +template inline void write(B& buf, ComputeMerkleRootConstraint const& constraint) { using serialize::write; write(buf, constraint.hash_path); - write(buf, constraint.root); write(buf, constraint.leaf); write(buf, constraint.result); write(buf, constraint.index); diff --git a/cpp/src/barretenberg/stdlib/merkle_tree/membership.hpp b/cpp/src/barretenberg/stdlib/merkle_tree/membership.hpp index 861d83091b..97b852242f 100644 --- a/cpp/src/barretenberg/stdlib/merkle_tree/membership.hpp +++ b/cpp/src/barretenberg/stdlib/merkle_tree/membership.hpp @@ -10,9 +10,8 @@ namespace merkle_tree { template using bit_vector = std::vector>; /** - * Checks if the subtree is correctly inserted at a specified index in a Merkle tree. + * Computes the new merkle root if the subtree is correctly inserted at a specified index in a Merkle tree. * - * @param root: The root of the latest state of the merkle tree, * @param hashes: The hash path from any leaf in the subtree to the root, it doesn't matter if this hash path is * computed before or after updating the tree, * @param value: The value of the subtree root, @@ -24,12 +23,11 @@ template using bit_vector = std::vector -bool_t check_subtree_membership(field_t const& root, - hash_path const& hashes, - field_t const& value, - bit_vector const& index, - size_t at_height, - bool const is_updating_tree = false) +field_t compute_subtree_root(hash_path const& hashes, + field_t const& value, + bit_vector const& index, + size_t at_height, + bool const is_updating_tree = false) { auto current = value; for (size_t i = at_height; i < hashes.size(); ++i) { @@ -46,7 +44,32 @@ bool_t check_subtree_membership(field_t const& root, current = pedersen_hash::hash_multiple({ left, right }, 0, is_updating_tree); } - return (current == root); + return current; +} + +/** + * Checks if the subtree is correctly inserted at a specified index in a Merkle tree. + * + * @param root: The root of the latest state of the merkle tree, + * @param hashes: The hash path from any leaf in the subtree to the root, it doesn't matter if this hash path is + * computed before or after updating the tree, + * @param value: The value of the subtree root, + * @param index: The index of any leaf in the subtree, + * @param at_height: The height of the subtree, + * @param is_updating_tree: set to true if we're updating the tree. + * @tparam Composer: type of composer. + * + * @see Check full documentation: https://hackmd.io/2zyJc6QhRuugyH8D78Tbqg?view + */ +template +bool_t check_subtree_membership(field_t const& root, + hash_path const& hashes, + field_t const& value, + bit_vector const& index, + size_t at_height, + bool const is_updating_tree = false) +{ + return (compute_subtree_root(hashes, value, index, at_height, is_updating_tree) == root); } /**