Skip to content

Commit

Permalink
feat!: replace MerkleMembershipConstraint with`ComputeMerkleRootCon…
Browse files Browse the repository at this point in the history
…straint` (#385)

* feat: replace `MerkleMembershipConstraint` with`ComputeMerkleRootConstraint`

* Update acir_format.cpp
  • Loading branch information
TomAFrench authored Apr 27, 2023
1 parent 7cfe3f0 commit 74dbce5
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 53 deletions.
30 changes: 15 additions & 15 deletions cpp/src/barretenberg/dsl/acir_format/acir_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions cpp/src/barretenberg/dsl/acir_format/acir_format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -28,7 +28,7 @@ struct acir_format {
std::vector<Blake2sConstraint> blake2s_constraints;
std::vector<HashToFieldConstraint> hash_to_field_constraints;
std::vector<PedersenConstraint> pedersen_constraints;
std::vector<MerkleMembershipConstraint> merkle_membership_constraints;
std::vector<ComputeMerkleRootConstraint> 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<poly_triple> constraints;
Expand Down Expand Up @@ -60,7 +60,7 @@ template <typename B> 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);
Expand All @@ -78,7 +78,7 @@ template <typename B> 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);
Expand Down
8 changes: 4 additions & 4 deletions cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
};

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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<fr>
// 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
Expand All @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,30 @@

namespace acir_format {

struct MerkleMembershipConstraint {
struct ComputeMerkleRootConstraint {
std::vector<uint32_t> 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 <typename B> inline void read(B& buf, MerkleMembershipConstraint& constraint)
template <typename B> 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 <typename B> inline void write(B& buf, MerkleMembershipConstraint const& constraint)
template <typename B> 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);
Expand Down
41 changes: 32 additions & 9 deletions cpp/src/barretenberg/stdlib/merkle_tree/membership.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ namespace merkle_tree {

template <typename ComposerContext> using bit_vector = std::vector<bool_t<ComposerContext>>;
/**
* 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,
Expand All @@ -24,12 +23,11 @@ template <typename ComposerContext> using bit_vector = std::vector<bool_t<Compos
* @see Check full documentation: https://hackmd.io/2zyJc6QhRuugyH8D78Tbqg?view
*/
template <typename Composer>
bool_t<Composer> check_subtree_membership(field_t<Composer> const& root,
hash_path<Composer> const& hashes,
field_t<Composer> const& value,
bit_vector<Composer> const& index,
size_t at_height,
bool const is_updating_tree = false)
field_t<Composer> compute_subtree_root(hash_path<Composer> const& hashes,
field_t<Composer> const& value,
bit_vector<Composer> 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) {
Expand All @@ -46,7 +44,32 @@ bool_t<Composer> check_subtree_membership(field_t<Composer> const& root,
current = pedersen_hash<Composer>::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 <typename Composer>
bool_t<Composer> check_subtree_membership(field_t<Composer> const& root,
hash_path<Composer> const& hashes,
field_t<Composer> const& value,
bit_vector<Composer> 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);
}

/**
Expand Down

0 comments on commit 74dbce5

Please sign in to comment.