Skip to content

Commit

Permalink
feat!: add support for ROM and RAM ACVM opcodes (#417)
Browse files Browse the repository at this point in the history
* *WIP* do not push

* Generate constraints for dynamic memory

* fix unit test: add missing block_constraint

* add unit test for dynamic memory

* missed one block constraint in ecdsa unit test

* trying a rebase

* remove comments
  • Loading branch information
guipublic authored May 12, 2023
1 parent ae44792 commit 697fabb
Show file tree
Hide file tree
Showing 8 changed files with 288 additions and 0 deletions.
25 changes: 25 additions & 0 deletions cpp/src/barretenberg/dsl/acir_format/acir_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ void create_circuit(Composer& composer, const acir_format& constraint_system)
for (const auto& constraint : constraint_system.hash_to_field_constraints) {
create_hash_to_field_constraints(composer, constraint);
}

// Add block constraints
for (const auto& constraint : constraint_system.block_constraints) {
create_block_constraints(composer, constraint);
}
}

Composer create_circuit(const acir_format& constraint_system,
Expand Down Expand Up @@ -172,6 +177,11 @@ Composer create_circuit(const acir_format& constraint_system,
create_hash_to_field_constraints(composer, constraint);
}

// Add block constraints
for (const auto& constraint : constraint_system.block_constraints) {
create_block_constraints(composer, constraint);
}

return composer;
}

Expand Down Expand Up @@ -261,6 +271,11 @@ Composer create_circuit_with_witness(const acir_format& constraint_system,
create_hash_to_field_constraints(composer, constraint);
}

// Add block constraints
for (const auto& constraint : constraint_system.block_constraints) {
create_block_constraints(composer, constraint);
}

return composer;
}
Composer create_circuit_with_witness(const acir_format& constraint_system, std::vector<fr> witness)
Expand Down Expand Up @@ -347,6 +362,11 @@ Composer create_circuit_with_witness(const acir_format& constraint_system, std::
create_hash_to_field_constraints(composer, constraint);
}

// Add block constraints
for (const auto& constraint : constraint_system.block_constraints) {
create_block_constraints(composer, constraint);
}

return composer;
}
void create_circuit_with_witness(Composer& composer, const acir_format& constraint_system, std::vector<fr> witness)
Expand Down Expand Up @@ -430,6 +450,11 @@ void create_circuit_with_witness(Composer& composer, const acir_format& constrai
for (const auto& constraint : constraint_system.hash_to_field_constraints) {
create_hash_to_field_constraints(composer, constraint);
}

// Add block constraints
for (const auto& constraint : constraint_system.block_constraints) {
create_block_constraints(composer, constraint);
}
}

} // namespace acir_format
4 changes: 4 additions & 0 deletions cpp/src/barretenberg/dsl/acir_format/acir_format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "schnorr_verify.hpp"
#include "ecdsa_secp256k1.hpp"
#include "compute_merkle_root_constraint.hpp"
#include "block_constraint.hpp"
#include "pedersen.hpp"
#include "hash_to_field.hpp"
#include "barretenberg/dsl/types.hpp"
Expand All @@ -31,6 +32,7 @@ struct acir_format {
std::vector<HashToFieldConstraint> hash_to_field_constraints;
std::vector<PedersenConstraint> pedersen_constraints;
std::vector<ComputeMerkleRootConstraint> compute_merkle_root_constraints;
std::vector<BlockConstraint> block_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 @@ -71,6 +73,7 @@ template <typename B> inline void read(B& buf, acir_format& data)
read(buf, data.hash_to_field_constraints);
read(buf, data.fixed_base_scalar_mul_constraints);
read(buf, data.constraints);
read(buf, data.block_constraints);
}

template <typename B> inline void write(B& buf, acir_format const& data)
Expand All @@ -90,6 +93,7 @@ template <typename B> inline void write(B& buf, acir_format const& data)
write(buf, data.hash_to_field_constraints);
write(buf, data.fixed_base_scalar_mul_constraints);
write(buf, data.constraints);
write(buf, data.block_constraints);
}

} // namespace acir_format
3 changes: 3 additions & 0 deletions cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ TEST(acir_format, test_logic_gate_from_noir_circuit)
.hash_to_field_constraints = {},
.pedersen_constraints = {},
.compute_merkle_root_constraints = {},
.block_constraints = {},
.constraints = { expr_a, expr_b, expr_c, expr_d },
};

Expand Down Expand Up @@ -156,6 +157,7 @@ TEST(acir_format, test_schnorr_verify_pass)
.hash_to_field_constraints = {},
.pedersen_constraints = {},
.compute_merkle_root_constraints = {},
.block_constraints = {},
.constraints = { poly_triple{
.a = schnorr_constraint.result,
.b = schnorr_constraint.result,
Expand Down Expand Up @@ -226,6 +228,7 @@ TEST(acir_format, test_schnorr_verify_small_range)
.hash_to_field_constraints = {},
.pedersen_constraints = {},
.compute_merkle_root_constraints = {},
.block_constraints = {},
.constraints = { poly_triple{
.a = schnorr_constraint.result,
.b = schnorr_constraint.result,
Expand Down
60 changes: 60 additions & 0 deletions cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "block_constraint.hpp"
#include "barretenberg/stdlib/primitives/memory/rom_table.hpp"
#include "barretenberg/stdlib/primitives/memory/ram_table.hpp"

using namespace proof_system::plonk;

namespace acir_format {
field_ct poly_to_field_ct(const poly_triple poly, Composer& composer)
{
ASSERT(poly.q_m == 0);
ASSERT(poly.q_r == 0);
ASSERT(poly.q_o == 0);
if (poly.q_l == 0) {
return field_ct(poly.q_c);
}
field_ct x = field_ct::from_witness_index(&composer, poly.a);
x.additive_constant = poly.q_c;
x.multiplicative_constant = poly.q_l;
return x;
}

void create_block_constraints(Composer& composer, const BlockConstraint constraint)
{
std::vector<field_ct> init;
for (auto i : constraint.init) {
field_ct value = poly_to_field_ct(i, composer);
init.push_back(value);
}

switch (constraint.type) {
case BlockType::ROM: {

rom_table_ct table(init);
for (auto& op : constraint.trace) {
ASSERT(op.access_type == 0);
field_ct value = poly_to_field_ct(op.value, composer);
field_ct index = poly_to_field_ct(op.index, composer);
value.assert_equal(table[index]);
}
} break;
case BlockType::RAM: {
ram_table_ct table(init);
for (auto& op : constraint.trace) {
field_ct value = poly_to_field_ct(op.value, composer);
field_ct index = poly_to_field_ct(op.index, composer);
if (op.access_type == 0) {
value.assert_equal(table.read(index));
} else {
ASSERT(op.access_type == 1);
table.write(index, value);
}
}
} break;
default:
ASSERT(false);
break;
}
}

} // namespace acir_format
62 changes: 62 additions & 0 deletions cpp/src/barretenberg/dsl/acir_format/block_constraint.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once
#include <cstdint>
#include <vector>
#include "barretenberg/plonk/composer/ultra_composer.hpp"
#include "barretenberg/stdlib/primitives/field/field.hpp"
#include "barretenberg/dsl/types.hpp"

namespace acir_format {

struct MemOp {
uint8_t access_type;
poly_triple index;
poly_triple value;
};

enum BlockType {
ROM = 0,
RAM = 1,
};

struct BlockConstraint {
std::vector<poly_triple> init;
std::vector<MemOp> trace;
BlockType type;
};

void create_block_constraints(Composer& composer, const BlockConstraint constraint);

template <typename B> inline void read(B& buf, MemOp& mem_op)
{
using serialize::read;
read(buf, mem_op.access_type);
read(buf, mem_op.index);
read(buf, mem_op.value);
}

template <typename B> inline void write(B& buf, MemOp const& mem_op)
{
using serialize::write;
write(buf, mem_op.access_type);
write(buf, mem_op.index);
write(buf, mem_op.value);
}

template <typename B> inline void read(B& buf, BlockConstraint& constraint)
{
using serialize::read;
read(buf, constraint.init);
read(buf, constraint.trace);
uint8_t type;
read(buf, type);
constraint.type = static_cast<BlockType>(type);
}

template <typename B> inline void write(B& buf, BlockConstraint const& constraint)
{
using serialize::write;
write(buf, constraint.init);
write(buf, constraint.trace);
write(buf, static_cast<uint8_t>(constraint.type));
}
} // namespace acir_format
130 changes: 130 additions & 0 deletions cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include "acir_format.hpp"
#include "block_constraint.hpp"
#include "barretenberg/plonk/proof_system/types/proof.hpp"
#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp"

#include <gtest/gtest.h>
#include <vector>

size_t generate_block_constraint(acir_format::BlockConstraint& constraint, std::vector<fr>& witness_values)
{
size_t witness_len = 1;
witness_values.emplace_back(1);
witness_len++;

fr two = fr::one() + fr::one();
poly_triple a0 = poly_triple{
.a = 1,
.b = 0,
.c = 0,
.q_m = 0,
.q_l = two,
.q_r = 0,
.q_o = 0,
.q_c = 0,
};
fr three = fr::one() + two;
poly_triple a1 = poly_triple{
.a = 0,
.b = 0,
.c = 0,
.q_m = 0,
.q_l = 0,
.q_r = 0,
.q_o = 0,
.q_c = three,
};
poly_triple r1 = poly_triple{
.a = 1,
.b = 0,
.c = 0,
.q_m = 0,
.q_l = fr::one(),
.q_r = 0,
.q_o = 0,
.q_c = fr::neg_one(),
};
poly_triple r2 = poly_triple{
.a = 1,
.b = 0,
.c = 0,
.q_m = 0,
.q_l = two,
.q_r = 0,
.q_o = 0,
.q_c = fr::neg_one(),
};
poly_triple y = poly_triple{
.a = 2,
.b = 0,
.c = 0,
.q_m = 0,
.q_l = fr::one(),
.q_r = 0,
.q_o = 0,
.q_c = 0,
};
witness_values.emplace_back(2);
witness_len++;
poly_triple z = poly_triple{
.a = 3,
.b = 0,
.c = 0,
.q_m = 0,
.q_l = fr::one(),
.q_r = 0,
.q_o = 0,
.q_c = 0,
};
witness_values.emplace_back(3);
witness_len++;
acir_format::MemOp op1 = acir_format::MemOp{
.access_type = 0,
.index = r1,
.value = y,
};
acir_format::MemOp op2 = acir_format::MemOp{
.access_type = 0,
.index = r2,
.value = z,
};
constraint = acir_format::BlockConstraint{
.init = { a0, a1 },
.trace = { op1, op2 },
.type = acir_format::BlockType::ROM,
};

return witness_len;
}

TEST(up_ram, TestBlockConstraint)
{
acir_format::BlockConstraint block;
std::vector<fr> witness_values;
size_t num_variables = generate_block_constraint(block, witness_values);
acir_format::acir_format constraint_system{
.varnum = static_cast<uint32_t>(num_variables),
.public_inputs = {},
.fixed_base_scalar_mul_constraints = {},
.logic_constraints = {},
.range_constraints = {},
.schnorr_constraints = {},
.ecdsa_constraints = {},
.sha256_constraints = {},
.blake2s_constraints = {},
.keccak_constraints = {},
.hash_to_field_constraints = {},
.pedersen_constraints = {},
.compute_merkle_root_constraints = {},
.block_constraints = { block },
.constraints = {},
};

auto composer = acir_format::create_circuit_with_witness(constraint_system, witness_values);

auto prover = composer.create_prover();

auto proof = prover.construct_proof();
auto verifier = composer.create_verifier();
EXPECT_EQ(verifier.verify_proof(proof), true);
}
2 changes: 2 additions & 0 deletions cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ TEST(ECDSASecp256k1, TestECDSAConstraintSucceed)
.hash_to_field_constraints = {},
.pedersen_constraints = {},
.compute_merkle_root_constraints = {},
.block_constraints = {},
.constraints = {},
};

Expand Down Expand Up @@ -164,6 +165,7 @@ TEST(ECDSASecp256k1, TestECDSAConstraintFail)
.hash_to_field_constraints = {},
.pedersen_constraints = {},
.compute_merkle_root_constraints = {},
.block_constraints = {},
.constraints = {},
};

Expand Down
Loading

0 comments on commit 697fabb

Please sign in to comment.