Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: replace MerkleMembershipConstraint withComputeMerkleRootConstraint #385

Merged
merged 2 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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