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: Add support for unlimited width in ACIR #8960

Merged
merged 6 commits into from
Oct 3, 2024
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
33 changes: 31 additions & 2 deletions barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,33 @@ void build_constraints(Builder& builder,
gate_counter.track_diff(constraint_system.gates_per_opcode,
constraint_system.original_opcode_indices.quad_constraints.at(i));
}
// Oversize gates are a vector of mul_quad gates.
for (size_t i = 0; i < constraint_system.big_quad_constraints.size(); ++i) {
auto& big_constraint = constraint_system.big_quad_constraints.at(i);
fr next_w4_wire_value = fr(0);
// Define the 4th wire of these mul_quad gates, which is implicitly used by the previous gate.
for (size_t j = 0; j < big_constraint.size() - 1; ++j) {
if (j == 0) {
next_w4_wire_value = builder.get_variable(big_constraint[0].d);
} else {
uint32_t next_w4_wire = builder.add_variable(next_w4_wire_value);
big_constraint[j].d = next_w4_wire;
big_constraint[j].d_scaling = fr(-1);
}
builder.create_big_mul_add_gate(big_constraint[j], true);
next_w4_wire_value = builder.get_variable(big_constraint[j].a) * builder.get_variable(big_constraint[j].b) *
big_constraint[j].mul_scaling +
builder.get_variable(big_constraint[j].a) * big_constraint[j].a_scaling +
builder.get_variable(big_constraint[j].b) * big_constraint[j].b_scaling +
builder.get_variable(big_constraint[j].c) * big_constraint[j].c_scaling +
next_w4_wire_value * big_constraint[j].d_scaling + big_constraint[j].const_scaling;
next_w4_wire_value = -next_w4_wire_value;
}
uint32_t next_w4_wire = builder.add_variable(next_w4_wire_value);
big_constraint.back().d = next_w4_wire;
big_constraint.back().d_scaling = fr(-1);
builder.create_big_mul_add_gate(big_constraint.back(), false);
}

// Add logic constraint
for (size_t i = 0; i < constraint_system.logic_constraints.size(); ++i) {
Expand Down Expand Up @@ -492,12 +519,14 @@ MegaCircuitBuilder create_kernel_circuit(AcirFormat& constraint_system,
for (auto [constraint, queue_entry] :
zip_view(constraint_system.ivc_recursion_constraints, ivc.stdlib_verification_queue)) {

// Reconstruct complete proof indices from acir constraint data (in which proof is stripped of public inputs)
// Reconstruct complete proof indices from acir constraint data (in which proof is
// stripped of public inputs)
std::vector<uint32_t> complete_proof_indices =
ProofSurgeon::create_indices_for_reconstructed_proof(constraint.proof, constraint.public_inputs);
ASSERT(complete_proof_indices.size() == queue_entry.proof.size());

// Assert equality between the proof indices from the constraint data and those of the internal proof
// Assert equality between the proof indices from the constraint data and those of the
// internal proof
for (auto [proof_value, proof_idx] : zip_view(queue_entry.proof, complete_proof_indices)) {
circuit.assert_equal(proof_value.get_witness_index(), proof_idx);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,13 @@ struct AcirFormat {
// 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
// This could be a large vector so use slab allocator, we don't expect the blackbox implementations to be so large.
bb::SlabVector<PolyTripleConstraint> poly_triple_constraints;
// A standard ultra plonk arithmetic constraint, of width 4: q_Ma*b+q_A*a+q_B*b+q_C*c+q_d*d+q_const = 0
bb::SlabVector<bb::mul_quad_<bb::curve::BN254::ScalarField>> quad_constraints;
guipublic marked this conversation as resolved.
Show resolved Hide resolved
// A vector of vector of mul_quad gates (i.e arithmetic constraints of width 4)
// Each vector of gates represente a 'big' expression (a polynomial of degree 1 or 2 which does not fit inside one
// mul_gate) that has been splitted into multiple mul_gates, using w4_omega (the 4th wire of the next gate), to
// reduce the number of intermediate variables.
bb::SlabVector<std::vector<bb::mul_quad_<bb::curve::BN254::ScalarField>>> big_quad_constraints;
std::vector<BlockConstraint> block_constraints;

// Number of gates added to the circuit per original opcode.
Expand Down Expand Up @@ -153,6 +159,8 @@ struct AcirFormat {
avm_recursion_constraints,
ivc_recursion_constraints,
poly_triple_constraints,
quad_constraints,
big_quad_constraints,
block_constraints,
bigint_from_le_bytes_constraints,
bigint_to_le_bytes_constraints,
Expand Down
142 changes: 142 additions & 0 deletions barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ TEST_F(AcirFormatTests, TestASingleConstraintNoPubInputs)
.assert_equalities = {},
.poly_triple_constraints = { constraint },
.quad_constraints = {},
.big_quad_constraints = {},
.block_constraints = {},
.original_opcode_indices = create_empty_original_opcode_indices(),
};
Expand Down Expand Up @@ -191,6 +192,7 @@ TEST_F(AcirFormatTests, TestLogicGateFromNoirCircuit)
.assert_equalities = {},
.poly_triple_constraints = { expr_a, expr_b, expr_c, expr_d },
.quad_constraints = {},
.big_quad_constraints = {},
.block_constraints = {},
.original_opcode_indices = create_empty_original_opcode_indices(),
};
Expand Down Expand Up @@ -282,6 +284,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass)
.q_c = fr::neg_one(),
} },
.quad_constraints = {},
.big_quad_constraints = {},
.block_constraints = {},
.original_opcode_indices = create_empty_original_opcode_indices(),
};
Expand Down Expand Up @@ -390,6 +393,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange)
.q_c = fr::neg_one(),
} },
.quad_constraints = {},
.big_quad_constraints = {},
.block_constraints = {},
.original_opcode_indices = create_empty_original_opcode_indices(),
};
Expand Down Expand Up @@ -502,6 +506,7 @@ TEST_F(AcirFormatTests, TestVarKeccak)
.assert_equalities = {},
.poly_triple_constraints = { dummy },
.quad_constraints = {},
.big_quad_constraints = {},
.block_constraints = {},
.original_opcode_indices = create_empty_original_opcode_indices(),
};
Expand Down Expand Up @@ -583,6 +588,7 @@ TEST_F(AcirFormatTests, TestKeccakPermutation)
.assert_equalities = {},
.poly_triple_constraints = {},
.quad_constraints = {},
.big_quad_constraints = {},
.block_constraints = {},
.original_opcode_indices = create_empty_original_opcode_indices(),
};
Expand Down Expand Up @@ -659,6 +665,7 @@ TEST_F(AcirFormatTests, TestCollectsGateCounts)
.assert_equalities = {},
.poly_triple_constraints = { first_gate, second_gate },
.quad_constraints = {},
.big_quad_constraints = {},
.block_constraints = {},
.original_opcode_indices = create_empty_original_opcode_indices(),
};
Expand All @@ -669,3 +676,138 @@ TEST_F(AcirFormatTests, TestCollectsGateCounts)

EXPECT_EQ(constraint_system.gates_per_opcode, std::vector<size_t>({ 2, 1 }));
}

TEST_F(AcirFormatTests, TestBigAdd)
{

WitnessVector witness_values;
witness_values.emplace_back(fr(0));

witness_values = {
fr(0), fr(1), fr(2), fr(3), fr(4), fr(5), fr(6), fr(7), fr(8), fr(9), fr(10), fr(11), fr(12), fr(13), fr(-91),
};

bb::mul_quad_<fr> quad1 = {
.a = 0,
.b = 1,
.c = 2,
.d = 3,
.mul_scaling = 0,
.a_scaling = fr::one(),
.b_scaling = fr::one(),
.c_scaling = fr::one(),
.d_scaling = fr::one(),
.const_scaling = fr(0),
};

bb::mul_quad_<fr> quad2 = {
.a = 4,
.b = 5,
.c = 6,
.d = 0,
.mul_scaling = 0,
.a_scaling = fr::one(),
.b_scaling = fr::one(),
.c_scaling = fr::one(),
.d_scaling = fr(0),
.const_scaling = fr(0),
};

bb::mul_quad_<fr> quad3 = {
.a = 7,
.b = 8,
.c = 9,
.d = 0,
.mul_scaling = 0,
.a_scaling = fr::one(),
.b_scaling = fr::one(),
.c_scaling = fr::one(),
.d_scaling = fr(0),
.const_scaling = fr(0),
};
bb::mul_quad_<fr> quad4 = {
.a = 10,
.b = 11,
.c = 12,
.d = 0,
.mul_scaling = 0,
.a_scaling = fr::one(),
.b_scaling = fr::one(),
.c_scaling = fr::one(),
.d_scaling = fr(0),
.const_scaling = fr(0),
};
bb::mul_quad_<fr> quad5 = {
.a = 13,
.b = 14,
.c = 0,
.d = 18,
.mul_scaling = 0,
.a_scaling = fr::one(),
.b_scaling = fr::one(),
.c_scaling = fr(0),
.d_scaling = fr(-1),
.const_scaling = fr(0),
};

auto res_x = fr(91);
auto assert_equal = poly_triple{
.a = 14,
.b = 0,
.c = 0,
.q_m = 0,
.q_l = fr::one(),
.q_r = 0,
.q_o = 0,
.q_c = res_x,
};
auto quad_constraint = { quad1, quad2, quad3, quad4, quad5 };
size_t num_variables = witness_values.size();
AcirFormat constraint_system{
.varnum = static_cast<uint32_t>(num_variables + 1),
.recursive = false,
.num_acir_opcodes = 1,
.public_inputs = {},
.logic_constraints = {},
.range_constraints = {},
.aes128_constraints = {},
.sha256_compression = {},
.schnorr_constraints = {},
.ecdsa_k1_constraints = {},
.ecdsa_r1_constraints = {},
.blake2s_constraints = {},
.blake3_constraints = {},
.keccak_constraints = {},
.keccak_permutations = {},
.pedersen_constraints = {},
.pedersen_hash_constraints = {},
.poseidon2_constraints = {},
.multi_scalar_mul_constraints = {},
.ec_add_constraints = {},
.recursion_constraints = {},
.honk_recursion_constraints = {},
.avm_recursion_constraints = {},
.ivc_recursion_constraints = {},
.bigint_from_le_bytes_constraints = {},
.bigint_to_le_bytes_constraints = {},
.bigint_operations = {},
.assert_equalities = {},
.poly_triple_constraints = { assert_equal },
.quad_constraints = {},
.big_quad_constraints = { quad_constraint },
.block_constraints = {},
.original_opcode_indices = create_empty_original_opcode_indices(),
};
mock_opcode_indices(constraint_system);

auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness_values);

auto composer = Composer();
auto prover = composer.create_prover(builder);

auto proof = prover.construct_proof();

EXPECT_TRUE(CircuitChecker::check(builder));
auto verifier = composer.create_verifier(builder);
EXPECT_EQ(verifier.verify_proof(proof), true);
}
Loading
Loading