diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 0e2e510f4..8f2c4d17f 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -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, @@ -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; } @@ -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 witness) @@ -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 witness) @@ -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 diff --git a/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp b/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp index a6e6a9534..cf14558c3 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp @@ -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" @@ -31,6 +32,7 @@ struct acir_format { std::vector hash_to_field_constraints; std::vector pedersen_constraints; std::vector compute_merkle_root_constraints; + std::vector 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 constraints; @@ -71,6 +73,7 @@ template 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 inline void write(B& buf, acir_format const& data) @@ -90,6 +93,7 @@ template 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 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 48debb4db..3c10153ce 100644 --- a/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp @@ -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 }, }; @@ -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, @@ -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, diff --git a/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp b/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp new file mode 100644 index 000000000..406574fa5 --- /dev/null +++ b/cpp/src/barretenberg/dsl/acir_format/block_constraint.cpp @@ -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 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 \ No newline at end of file diff --git a/cpp/src/barretenberg/dsl/acir_format/block_constraint.hpp b/cpp/src/barretenberg/dsl/acir_format/block_constraint.hpp new file mode 100644 index 000000000..7f0cc1f07 --- /dev/null +++ b/cpp/src/barretenberg/dsl/acir_format/block_constraint.hpp @@ -0,0 +1,62 @@ +#pragma once +#include +#include +#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 init; + std::vector trace; + BlockType type; +}; + +void create_block_constraints(Composer& composer, const BlockConstraint constraint); + +template 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 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 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(type); +} + +template inline void write(B& buf, BlockConstraint const& constraint) +{ + using serialize::write; + write(buf, constraint.init); + write(buf, constraint.trace); + write(buf, static_cast(constraint.type)); +} +} // namespace acir_format diff --git a/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp b/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp new file mode 100644 index 000000000..66ab73e84 --- /dev/null +++ b/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp @@ -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 +#include + +size_t generate_block_constraint(acir_format::BlockConstraint& constraint, std::vector& 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 witness_values; + size_t num_variables = generate_block_constraint(block, witness_values); + acir_format::acir_format constraint_system{ + .varnum = static_cast(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); +} diff --git a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp index 4e2e25174..60613b321 100644 --- a/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp +++ b/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp @@ -97,6 +97,7 @@ TEST(ECDSASecp256k1, TestECDSAConstraintSucceed) .hash_to_field_constraints = {}, .pedersen_constraints = {}, .compute_merkle_root_constraints = {}, + .block_constraints = {}, .constraints = {}, }; @@ -164,6 +165,7 @@ TEST(ECDSASecp256k1, TestECDSAConstraintFail) .hash_to_field_constraints = {}, .pedersen_constraints = {}, .compute_merkle_root_constraints = {}, + .block_constraints = {}, .constraints = {}, }; diff --git a/cpp/src/barretenberg/dsl/types.hpp b/cpp/src/barretenberg/dsl/types.hpp index edb590571..e5277faf2 100644 --- a/cpp/src/barretenberg/dsl/types.hpp +++ b/cpp/src/barretenberg/dsl/types.hpp @@ -19,6 +19,7 @@ #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/primitives/curves/secp256k1.hpp" #include "barretenberg/stdlib/primitives/memory/rom_table.hpp" +#include "barretenberg/stdlib/primitives/memory/ram_table.hpp" namespace acir_format { using Composer = plonk::UltraComposer; @@ -59,5 +60,6 @@ using schnorr_signature_bits_ct = proof_system::plonk::stdlib::schnorr::signatur // Ultra-composer specific typesv using rom_table_ct = proof_system::plonk::stdlib::rom_table; +using ram_table_ct = proof_system::plonk::stdlib::ram_table; } // namespace acir_format