From a2a5f4d6ce6ec959b3caa71eeba7270ce4339fb5 Mon Sep 17 00:00:00 2001 From: Jean M <132435771+jeanmon@users.noreply.github.com> Date: Fri, 8 Dec 2023 17:57:08 +0100 Subject: [PATCH 1/8] feat(avm-mini): add sub, mul, div and error handling for finite fields (#3612) Resolves #3546 Resolves #3548 ### Description This PR introduces the following opcodes for the finite field type: - SUB: subtraction - MUL: multiplication - DIV: division For division, error is raised whenever the numerator is zero. A boolean column op_err was introduced for this purpose. --- barretenberg/cpp/pil/avm/avm_mini.pil | 71 ++++- barretenberg/cpp/pil/avm/avm_mini_opt.pil | 21 +- .../flavor/generated/AvmMini_flavor.hpp | 242 ++++++++-------- .../circuit_builder/AvmMini_trace.cpp | 267 ++++++++++++++---- .../circuit_builder/AvmMini_trace.hpp | 35 ++- .../generated/AvmMini_circuit_builder.hpp | 26 +- .../relations/generated/AvmMini/avm_mini.hpp | 115 +++++++- .../generated/AvmMini/declare_views.hpp | 11 +- .../relations/generated/AvmMini/mem_trace.hpp | 12 +- .../vm/generated/AvmMini_composer.cpp | 7 +- .../vm/generated/AvmMini_composer.test.cpp | 21 +- .../vm/generated/AvmMini_prover.cpp | 17 +- .../vm/generated/AvmMini_verifier.cpp | 11 +- 13 files changed, 608 insertions(+), 248 deletions(-) diff --git a/barretenberg/cpp/pil/avm/avm_mini.pil b/barretenberg/cpp/pil/avm/avm_mini.pil index f9b8f2fe23a..3bd9bc11b86 100644 --- a/barretenberg/cpp/pil/avm/avm_mini.pil +++ b/barretenberg/cpp/pil/avm/avm_mini.pil @@ -9,11 +9,25 @@ namespace avmMini(256); // only in first element of shifted polynomials. //===== TABLE SUBOP-TR ======================================================== - // Enum over sub operations - // 0: VOID - // 1: ADD - pol commit subop; - + // Boolean selectors for (sub-)operations. Only one operation is activated at + // a time. + + // ADD + pol commit sel_op_add; + // SUB + pol commit sel_op_sub; + // MUL + pol commit sel_op_mul; + // DIV + pol commit sel_op_div; + + // Error boolean flag pertaining to an operation + pol commit op_err; + + // A helper witness being the inverse of some value + // to show a non-zero equality + pol commit inv; + // Intermediate register values pol commit ia; pol commit ib; @@ -42,15 +56,56 @@ namespace avmMini(256); pol commit last; // Relations on type constraints - subop * (1 - subop) = 0; + + sel_op_add * (1 - sel_op_add) = 0; + sel_op_sub * (1 - sel_op_sub) = 0; + sel_op_mul * (1 - sel_op_mul) = 0; + sel_op_div * (1 - sel_op_div) = 0; + + op_err * (1 - op_err) = 0; + mem_op_a * (1 - mem_op_a) = 0; mem_op_b * (1 - mem_op_b) = 0; mem_op_c * (1 - mem_op_c) = 0; + rwa * (1 - rwa) = 0; rwb * (1 - rwb) = 0; rwc * (1 - rwc) = 0; // Relation for addition over the finite field - subop * (ia + ib - ic) = 0; + sel_op_add * (ia + ib - ic) = 0; - \ No newline at end of file + // Relation for subtraction over the finite field + sel_op_sub * (ia - ib - ic) = 0; + + // Relation for multiplication over the finite field + sel_op_mul * (ia * ib - ic) = 0; + + // Relation for division over the finite field + sel_op_div * (1 - op_err) * (ic * ib - ia) = 0; + + // When sel_op_div == 1, we want ib == 0 <==> op_err == 1 + // This can be achieved with the 2 following relations. + // inv is an extra witness to show that we can invert ib, i.e., inv = ib^(-1) + // If ib == 0, we have to set inv = 1 to satisfy the second relation. + sel_op_div * (ib * inv - 1 + op_err) = 0; + sel_op_div * op_err * (1 - inv) = 0; + + // op_err cannot be maliciously activated for a non-relevant + // operation selector, i.e., op_err == 1 ==> sel_op_div || sel_op_XXX || ... + // op_err * (sel_op_div + sel_op_XXX + ... - 1) == 0 + // Note that the above is even a stronger constraint, as it shows + // that exactly one sel_op_XXX must be true. + // At this time, we have only division producing an error. + op_err * (sel_op_div - 1) = 0; + + // TODO: constraint that we stop execution at the first error + // An error can only happen at the last sub-operation row. + + // OPEN/POTENTIAL OPTIMIZATION: Dedicated error per relevant operation? + // For the division, we could lower the degree from 4 to 3 + // (sel_op_div - op_div_err) * (ic * ib - ia) = 0; + // Same for the relations related to the error activation: + // (ib * inv - 1 + op_div_err) = 0 && op_err * (1 - inv) = 0 + // This works in combination with op_div_err * (sel_op_div - 1) = 0; + // Drawback is the need to paralllelize the latter. \ No newline at end of file diff --git a/barretenberg/cpp/pil/avm/avm_mini_opt.pil b/barretenberg/cpp/pil/avm/avm_mini_opt.pil index ffa516ca9ef..56019fb7197 100644 --- a/barretenberg/cpp/pil/avm/avm_mini_opt.pil +++ b/barretenberg/cpp/pil/avm/avm_mini_opt.pil @@ -12,7 +12,12 @@ namespace memTrace(256); namespace avmMini(256); col fixed clk(i) { i }; col fixed first = [1] + [0]*; - col witness subop; + col witness sel_op_add; + col witness sel_op_sub; + col witness sel_op_mul; + col witness sel_op_div; + col witness op_err; + col witness inv; col witness ia; col witness ib; col witness ic; @@ -26,11 +31,21 @@ namespace avmMini(256); col witness mem_idx_b; col witness mem_idx_c; col witness last; - (avmMini.subop * (1 - avmMini.subop)) = 0; + (avmMini.sel_op_add * (1 - avmMini.sel_op_add)) = 0; + (avmMini.sel_op_sub * (1 - avmMini.sel_op_sub)) = 0; + (avmMini.sel_op_mul * (1 - avmMini.sel_op_mul)) = 0; + (avmMini.sel_op_div * (1 - avmMini.sel_op_div)) = 0; + (avmMini.op_err * (1 - avmMini.op_err)) = 0; (avmMini.mem_op_a * (1 - avmMini.mem_op_a)) = 0; (avmMini.mem_op_b * (1 - avmMini.mem_op_b)) = 0; (avmMini.mem_op_c * (1 - avmMini.mem_op_c)) = 0; (avmMini.rwa * (1 - avmMini.rwa)) = 0; (avmMini.rwb * (1 - avmMini.rwb)) = 0; (avmMini.rwc * (1 - avmMini.rwc)) = 0; - (avmMini.subop * ((avmMini.ia + avmMini.ib) - avmMini.ic)) = 0; \ No newline at end of file + (avmMini.sel_op_add * ((avmMini.ia + avmMini.ib) - avmMini.ic)) = 0; + (avmMini.sel_op_sub * ((avmMini.ia - avmMini.ib) - avmMini.ic)) = 0; + (avmMini.sel_op_mul * ((avmMini.ia * avmMini.ib) - avmMini.ic)) = 0; + ((avmMini.sel_op_div * (1 - avmMini.op_err)) * ((avmMini.ic * avmMini.ib) - avmMini.ia)) = 0; + (avmMini.sel_op_div * (((avmMini.ib * avmMini.inv) - 1) + avmMini.op_err)) = 0; + ((avmMini.sel_op_div * avmMini.op_err) * (1 - avmMini.inv)) = 0; + (avmMini.op_err * (avmMini.sel_op_div - 1)) = 0; diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp index 718d61f3c89..c3b00281f70 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp @@ -34,11 +34,11 @@ class AvmMiniFlavor { using VerifierCommitmentKey = pcs::VerifierCommitmentKey; static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 2; - static constexpr size_t NUM_WITNESS_ENTITIES = 20; + static constexpr size_t NUM_WITNESS_ENTITIES = 25; static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted - static constexpr size_t NUM_ALL_ENTITIES = 25; + static constexpr size_t NUM_ALL_ENTITIES = 30; using Relations = std::tuple, AvmMini_vm::mem_trace>; @@ -65,14 +65,7 @@ class AvmMiniFlavor { DEFINE_FLAVOR_MEMBERS(DataType, avmMini_clk, avmMini_first) - RefVector get_selectors() - { - return { - avmMini_clk, - avmMini_first, - }; - }; - + RefVector get_selectors() { return { avmMini_clk, avmMini_first }; }; RefVector get_sigma_polynomials() { return {}; }; RefVector get_id_polynomials() { return {}; }; RefVector get_table_polynomials() { return {}; }; @@ -87,7 +80,12 @@ class AvmMiniFlavor { memTrace_m_val, memTrace_m_lastAccess, memTrace_m_rw, - avmMini_subop, + avmMini_sel_op_add, + avmMini_sel_op_sub, + avmMini_sel_op_mul, + avmMini_sel_op_div, + avmMini_op_err, + avmMini_inv, avmMini_ia, avmMini_ib, avmMini_ic, @@ -105,14 +103,13 @@ class AvmMiniFlavor { RefVector get_wires() { return { - memTrace_m_clk, memTrace_m_sub_clk, memTrace_m_addr, memTrace_m_val, memTrace_m_lastAccess, - memTrace_m_rw, avmMini_subop, avmMini_ia, avmMini_ib, avmMini_ic, - avmMini_mem_op_a, avmMini_mem_op_b, avmMini_mem_op_c, avmMini_rwa, avmMini_rwb, - avmMini_rwc, avmMini_mem_idx_a, avmMini_mem_idx_b, avmMini_mem_idx_c, avmMini_last, - + memTrace_m_clk, memTrace_m_sub_clk, memTrace_m_addr, memTrace_m_val, memTrace_m_lastAccess, + memTrace_m_rw, avmMini_sel_op_add, avmMini_sel_op_sub, avmMini_sel_op_mul, avmMini_sel_op_div, + avmMini_op_err, avmMini_inv, avmMini_ia, avmMini_ib, avmMini_ic, + avmMini_mem_op_a, avmMini_mem_op_b, avmMini_mem_op_c, avmMini_rwa, avmMini_rwb, + avmMini_rwc, avmMini_mem_idx_a, avmMini_mem_idx_b, avmMini_mem_idx_c, avmMini_last }; }; - RefVector get_sorted_polynomials() { return {}; }; }; @@ -127,7 +124,12 @@ class AvmMiniFlavor { memTrace_m_val, memTrace_m_lastAccess, memTrace_m_rw, - avmMini_subop, + avmMini_sel_op_add, + avmMini_sel_op_sub, + avmMini_sel_op_mul, + avmMini_sel_op_div, + avmMini_op_err, + avmMini_inv, avmMini_ia, avmMini_ib, avmMini_ic, @@ -142,88 +144,76 @@ class AvmMiniFlavor { avmMini_mem_idx_c, avmMini_last, memTrace_m_rw_shift, - memTrace_m_addr_shift, - memTrace_m_val_shift) + memTrace_m_val_shift, + memTrace_m_addr_shift) RefVector get_wires() { - return { - avmMini_clk, - avmMini_first, - memTrace_m_clk, - memTrace_m_sub_clk, - memTrace_m_addr, - memTrace_m_val, - memTrace_m_lastAccess, - memTrace_m_rw, - avmMini_subop, - avmMini_ia, - avmMini_ib, - avmMini_ic, - avmMini_mem_op_a, - avmMini_mem_op_b, - avmMini_mem_op_c, - avmMini_rwa, - avmMini_rwb, - avmMini_rwc, - avmMini_mem_idx_a, - avmMini_mem_idx_b, - avmMini_mem_idx_c, - avmMini_last, - memTrace_m_rw_shift, - memTrace_m_addr_shift, - memTrace_m_val_shift, - - }; + return { avmMini_clk, + avmMini_first, + memTrace_m_clk, + memTrace_m_sub_clk, + memTrace_m_addr, + memTrace_m_val, + memTrace_m_lastAccess, + memTrace_m_rw, + avmMini_sel_op_add, + avmMini_sel_op_sub, + avmMini_sel_op_mul, + avmMini_sel_op_div, + avmMini_op_err, + avmMini_inv, + avmMini_ia, + avmMini_ib, + avmMini_ic, + avmMini_mem_op_a, + avmMini_mem_op_b, + avmMini_mem_op_c, + avmMini_rwa, + avmMini_rwb, + avmMini_rwc, + avmMini_mem_idx_a, + avmMini_mem_idx_b, + avmMini_mem_idx_c, + avmMini_last, + memTrace_m_rw_shift, + memTrace_m_val_shift, + memTrace_m_addr_shift }; }; - RefVector get_unshifted() { - return { - avmMini_clk, - avmMini_first, - memTrace_m_clk, - memTrace_m_sub_clk, - memTrace_m_addr, - memTrace_m_val, - memTrace_m_lastAccess, - memTrace_m_rw, - avmMini_subop, - avmMini_ia, - avmMini_ib, - avmMini_ic, - avmMini_mem_op_a, - avmMini_mem_op_b, - avmMini_mem_op_c, - avmMini_rwa, - avmMini_rwb, - avmMini_rwc, - avmMini_mem_idx_a, - avmMini_mem_idx_b, - avmMini_mem_idx_c, - avmMini_last, - - }; - }; - - RefVector get_to_be_shifted() - { - return { - memTrace_m_rw, - memTrace_m_addr, - memTrace_m_val, - - }; + return { avmMini_clk, + avmMini_first, + memTrace_m_clk, + memTrace_m_sub_clk, + memTrace_m_addr, + memTrace_m_val, + memTrace_m_lastAccess, + memTrace_m_rw, + avmMini_sel_op_add, + avmMini_sel_op_sub, + avmMini_sel_op_mul, + avmMini_sel_op_div, + avmMini_op_err, + avmMini_inv, + avmMini_ia, + avmMini_ib, + avmMini_ic, + avmMini_mem_op_a, + avmMini_mem_op_b, + avmMini_mem_op_c, + avmMini_rwa, + avmMini_rwb, + avmMini_rwc, + avmMini_mem_idx_a, + avmMini_mem_idx_b, + avmMini_mem_idx_c, + avmMini_last }; }; - + RefVector get_to_be_shifted() { return { memTrace_m_rw, memTrace_m_val, memTrace_m_addr }; }; RefVector get_shifted() { - return { - memTrace_m_rw_shift, - memTrace_m_addr_shift, - memTrace_m_val_shift, - - }; + return { memTrace_m_rw_shift, memTrace_m_val_shift, memTrace_m_addr_shift }; }; }; @@ -296,28 +286,33 @@ class AvmMiniFlavor { CommitmentLabels() : AllEntities() { - Base::avmMini_clk = "avmMini_clk"; - Base::avmMini_first = "avmMini_first"; - Base::memTrace_m_clk = "memTrace_m_clk"; - Base::memTrace_m_sub_clk = "memTrace_m_sub_clk"; - Base::memTrace_m_addr = "memTrace_m_addr"; - Base::memTrace_m_val = "memTrace_m_val"; - Base::memTrace_m_lastAccess = "memTrace_m_lastAccess"; - Base::memTrace_m_rw = "memTrace_m_rw"; - Base::avmMini_subop = "avmMini_subop"; - Base::avmMini_ia = "avmMini_ia"; - Base::avmMini_ib = "avmMini_ib"; - Base::avmMini_ic = "avmMini_ic"; - Base::avmMini_mem_op_a = "avmMini_mem_op_a"; - Base::avmMini_mem_op_b = "avmMini_mem_op_b"; - Base::avmMini_mem_op_c = "avmMini_mem_op_c"; - Base::avmMini_rwa = "avmMini_rwa"; - Base::avmMini_rwb = "avmMini_rwb"; - Base::avmMini_rwc = "avmMini_rwc"; - Base::avmMini_mem_idx_a = "avmMini_mem_idx_a"; - Base::avmMini_mem_idx_b = "avmMini_mem_idx_b"; - Base::avmMini_mem_idx_c = "avmMini_mem_idx_c"; - Base::avmMini_last = "avmMini_last"; + Base::avmMini_clk = "AVMMINI_CLK"; + Base::avmMini_first = "AVMMINI_FIRST"; + Base::memTrace_m_clk = "MEMTRACE_M_CLK"; + Base::memTrace_m_sub_clk = "MEMTRACE_M_SUB_CLK"; + Base::memTrace_m_addr = "MEMTRACE_M_ADDR"; + Base::memTrace_m_val = "MEMTRACE_M_VAL"; + Base::memTrace_m_lastAccess = "MEMTRACE_M_LASTACCESS"; + Base::memTrace_m_rw = "MEMTRACE_M_RW"; + Base::avmMini_sel_op_add = "AVMMINI_SEL_OP_ADD"; + Base::avmMini_sel_op_sub = "AVMMINI_SEL_OP_SUB"; + Base::avmMini_sel_op_mul = "AVMMINI_SEL_OP_MUL"; + Base::avmMini_sel_op_div = "AVMMINI_SEL_OP_DIV"; + Base::avmMini_op_err = "AVMMINI_OP_ERR"; + Base::avmMini_inv = "AVMMINI_INV"; + Base::avmMini_ia = "AVMMINI_IA"; + Base::avmMini_ib = "AVMMINI_IB"; + Base::avmMini_ic = "AVMMINI_IC"; + Base::avmMini_mem_op_a = "AVMMINI_MEM_OP_A"; + Base::avmMini_mem_op_b = "AVMMINI_MEM_OP_B"; + Base::avmMini_mem_op_c = "AVMMINI_MEM_OP_C"; + Base::avmMini_rwa = "AVMMINI_RWA"; + Base::avmMini_rwb = "AVMMINI_RWB"; + Base::avmMini_rwc = "AVMMINI_RWC"; + Base::avmMini_mem_idx_a = "AVMMINI_MEM_IDX_A"; + Base::avmMini_mem_idx_b = "AVMMINI_MEM_IDX_B"; + Base::avmMini_mem_idx_c = "AVMMINI_MEM_IDX_C"; + Base::avmMini_last = "AVMMINI_LAST"; }; }; @@ -343,7 +338,12 @@ class AvmMiniFlavor { Commitment memTrace_m_val; Commitment memTrace_m_lastAccess; Commitment memTrace_m_rw; - Commitment avmMini_subop; + Commitment avmMini_sel_op_add; + Commitment avmMini_sel_op_sub; + Commitment avmMini_sel_op_mul; + Commitment avmMini_sel_op_div; + Commitment avmMini_op_err; + Commitment avmMini_inv; Commitment avmMini_ia; Commitment avmMini_ib; Commitment avmMini_ic; @@ -382,7 +382,12 @@ class AvmMiniFlavor { memTrace_m_val = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); memTrace_m_lastAccess = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); memTrace_m_rw = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); - avmMini_subop = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_sel_op_add = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_sel_op_sub = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_sel_op_mul = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_sel_op_div = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_op_err = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_inv = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_ia = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_ib = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_ic = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); @@ -425,7 +430,12 @@ class AvmMiniFlavor { serialize_to_buffer(memTrace_m_val, Transcript::proof_data); serialize_to_buffer(memTrace_m_lastAccess, Transcript::proof_data); serialize_to_buffer(memTrace_m_rw, Transcript::proof_data); - serialize_to_buffer(avmMini_subop, Transcript::proof_data); + serialize_to_buffer(avmMini_sel_op_add, Transcript::proof_data); + serialize_to_buffer(avmMini_sel_op_sub, Transcript::proof_data); + serialize_to_buffer(avmMini_sel_op_mul, Transcript::proof_data); + serialize_to_buffer(avmMini_sel_op_div, Transcript::proof_data); + serialize_to_buffer(avmMini_op_err, Transcript::proof_data); + serialize_to_buffer(avmMini_inv, Transcript::proof_data); serialize_to_buffer(avmMini_ia, Transcript::proof_data); serialize_to_buffer(avmMini_ib, Transcript::proof_data); serialize_to_buffer(avmMini_ic, Transcript::proof_data); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp index 01089a78395..8562a72c41c 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp @@ -94,7 +94,7 @@ void AvmMiniTraceBuilder::insertInMemTrace(uint32_t m_clk, uint32_t m_sub_clk, u */ void AvmMiniTraceBuilder::loadAInMemTrace(uint32_t addr, FF val) { - insertInMemTrace(static_cast(mainTrace.size()), SubClkLoadA, addr, val, false); + insertInMemTrace(static_cast(mainTrace.size()), SUB_CLK_LOAD_A, addr, val, false); } /** @@ -106,7 +106,7 @@ void AvmMiniTraceBuilder::loadAInMemTrace(uint32_t addr, FF val) */ void AvmMiniTraceBuilder::loadBInMemTrace(uint32_t addr, FF val) { - insertInMemTrace(static_cast(mainTrace.size()), SubClkLoadB, addr, val, false); + insertInMemTrace(static_cast(mainTrace.size()), SUB_CLK_LOAD_B, addr, val, false); } /** @@ -118,7 +118,7 @@ void AvmMiniTraceBuilder::loadBInMemTrace(uint32_t addr, FF val) */ void AvmMiniTraceBuilder::loadCInMemTrace(uint32_t addr, FF val) { - insertInMemTrace(static_cast(mainTrace.size()), SubClkLoadC, addr, val, false); + insertInMemTrace(static_cast(mainTrace.size()), SUB_CLK_LOAD_C, addr, val, false); } /** @@ -130,7 +130,7 @@ void AvmMiniTraceBuilder::loadCInMemTrace(uint32_t addr, FF val) */ void AvmMiniTraceBuilder::storeAInMemTrace(uint32_t addr, FF val) { - insertInMemTrace(static_cast(mainTrace.size()), SubClkStoreA, addr, val, true); + insertInMemTrace(static_cast(mainTrace.size()), SUB_CLK_STORE_A, addr, val, true); } /** @@ -142,7 +142,7 @@ void AvmMiniTraceBuilder::storeAInMemTrace(uint32_t addr, FF val) */ void AvmMiniTraceBuilder::storeBInMemTrace(uint32_t addr, FF val) { - insertInMemTrace(static_cast(mainTrace.size()), SubClkStoreB, addr, val, true); + insertInMemTrace(static_cast(mainTrace.size()), SUB_CLK_STORE_B, addr, val, true); } /** @@ -154,38 +154,38 @@ void AvmMiniTraceBuilder::storeBInMemTrace(uint32_t addr, FF val) */ void AvmMiniTraceBuilder::storeCInMemTrace(uint32_t addr, FF val) { - insertInMemTrace(static_cast(mainTrace.size()), SubClkStoreC, addr, val, true); + insertInMemTrace(static_cast(mainTrace.size()), SUB_CLK_STORE_C, addr, val, true); } /** * @brief Addition over finite field with direct memory access. * - * @param s0 An index in ffMemory pointing to the first operand of the addition. - * @param s1 An index in ffMemory pointing to the second operand of the addition. - * @param d0 An index in ffMemory pointing to the output of the addition. + * @param aOffset An index in ffMemory pointing to the first operand of the addition. + * @param bOffset An index in ffMemory pointing to the second operand of the addition. + * @param dstOffset An index in ffMemory pointing to the output of the addition. */ -void AvmMiniTraceBuilder::add(uint32_t s0, uint32_t s1, uint32_t d0) +void AvmMiniTraceBuilder::add(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset) { // a + b = c - FF a = ffMemory.at(s0); - FF b = ffMemory.at(s1); + FF a = ffMemory.at(aOffset); + FF b = ffMemory.at(bOffset); FF c = a + b; - ffMemory.at(d0) = c; + ffMemory.at(dstOffset) = c; auto clk = mainTrace.size(); // Loading into Ia - loadAInMemTrace(s0, a); + loadAInMemTrace(aOffset, a); // Loading into Ib - loadBInMemTrace(s1, b); + loadBInMemTrace(bOffset, b); // Storing from Ic - storeCInMemTrace(d0, c); + storeCInMemTrace(dstOffset, c); mainTrace.push_back(Row{ .avmMini_clk = clk, - .avmMini_subop = FF(1), + .avmMini_sel_op_add = FF(1), .avmMini_ia = a, .avmMini_ib = b, .avmMini_ic = c, @@ -193,15 +193,157 @@ void AvmMiniTraceBuilder::add(uint32_t s0, uint32_t s1, uint32_t d0) .avmMini_mem_op_b = FF(1), .avmMini_mem_op_c = FF(1), .avmMini_rwc = FF(1), - .avmMini_mem_idx_a = FF(s0), - .avmMini_mem_idx_b = FF(s1), - .avmMini_mem_idx_c = FF(d0), + .avmMini_mem_idx_a = FF(aOffset), + .avmMini_mem_idx_b = FF(bOffset), + .avmMini_mem_idx_c = FF(dstOffset), }); }; +/** + * @brief Subtraction over finite field with direct memory access. + * + * @param aOffset An index in ffMemory pointing to the first operand of the subtraction. + * @param bOffset An index in ffMemory pointing to the second operand of the subtraction. + * @param dstOffset An index in ffMemory pointing to the output of the subtraction. + */ +void AvmMiniTraceBuilder::sub(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset) +{ + // a - b = c + FF a = ffMemory.at(aOffset); + FF b = ffMemory.at(bOffset); + FF c = a - b; + ffMemory.at(dstOffset) = c; + + auto clk = mainTrace.size(); + + // Loading into Ia + loadAInMemTrace(aOffset, a); + + // Loading into Ib + loadBInMemTrace(bOffset, b); + + // Storing from Ic + storeCInMemTrace(dstOffset, c); + + mainTrace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_sel_op_sub = FF(1), + .avmMini_ia = a, + .avmMini_ib = b, + .avmMini_ic = c, + .avmMini_mem_op_a = FF(1), + .avmMini_mem_op_b = FF(1), + .avmMini_mem_op_c = FF(1), + .avmMini_rwc = FF(1), + .avmMini_mem_idx_a = FF(aOffset), + .avmMini_mem_idx_b = FF(bOffset), + .avmMini_mem_idx_c = FF(dstOffset), + }); +}; + +/** + * @brief Multiplication over finite field with direct memory access. + * + * @param aOffset An index in ffMemory pointing to the first operand of the multiplication. + * @param bOffset An index in ffMemory pointing to the second operand of the multiplication. + * @param dstOffset An index in ffMemory pointing to the output of the multiplication. + */ +void AvmMiniTraceBuilder::mul(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset) +{ + // a * b = c + FF a = ffMemory.at(aOffset); + FF b = ffMemory.at(bOffset); + FF c = a * b; + ffMemory.at(dstOffset) = c; + + auto clk = mainTrace.size(); + + // Loading into Ia + loadAInMemTrace(aOffset, a); + + // Loading into Ib + loadBInMemTrace(bOffset, b); + + // Storing from Ic + storeCInMemTrace(dstOffset, c); + + mainTrace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_sel_op_mul = FF(1), + .avmMini_ia = a, + .avmMini_ib = b, + .avmMini_ic = c, + .avmMini_mem_op_a = FF(1), + .avmMini_mem_op_b = FF(1), + .avmMini_mem_op_c = FF(1), + .avmMini_rwc = FF(1), + .avmMini_mem_idx_a = FF(aOffset), + .avmMini_mem_idx_b = FF(bOffset), + .avmMini_mem_idx_c = FF(dstOffset), + }); +} + +/** + * @brief Division over finite field with direct memory access. + * + * @param aOffset An index in ffMemory pointing to the first operand of the division. + * @param bOffset An index in ffMemory pointing to the second operand of the division. + * @param dstOffset An index in ffMemory pointing to the output of the division. + */ +void AvmMiniTraceBuilder::div(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset) +{ + // a * b^(-1) = c + FF a = ffMemory.at(aOffset); + FF b = ffMemory.at(bOffset); + FF c; + FF inv; + FF error; + + if (!b.is_zero()) { + + inv = b.invert(); + c = a * inv; + error = 0; + } else { + inv = 1; + c = 0; + error = 1; + } + + ffMemory.at(dstOffset) = c; + + auto clk = mainTrace.size(); + + // Loading into Ia + loadAInMemTrace(aOffset, a); + + // Loading into Ib + loadBInMemTrace(bOffset, b); + + // Storing from Ic + storeCInMemTrace(dstOffset, c); + + mainTrace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_sel_op_div = FF(1), + .avmMini_op_err = error, + .avmMini_inv = inv, + .avmMini_ia = a, + .avmMini_ib = b, + .avmMini_ic = c, + .avmMini_mem_op_a = FF(1), + .avmMini_mem_op_b = FF(1), + .avmMini_mem_op_c = FF(1), + .avmMini_rwc = FF(1), + .avmMini_mem_idx_a = FF(aOffset), + .avmMini_mem_idx_b = FF(bOffset), + .avmMini_mem_idx_c = FF(dstOffset), + }); +} + /** * @brief CALLDATACOPY opcode with direct memory access, i.e., - * M_F[d0:d0+s1] = M_calldata[s0:s0+s1] + * M[dstOffset:dstOffset+copySize] = calldata[cdOffset:cdOffset+copySize] * Simplified version with exclusively memory store operations and * values from M_calldata passed by an array and loaded into * intermediate registers. @@ -211,22 +353,26 @@ void AvmMiniTraceBuilder::add(uint32_t s0, uint32_t s1, uint32_t d0) * TODO: taking care of intermediate register values consistency and propagating their * values to the next row when not overwritten. * - * @param s0 The starting index of the region in calldata to be copied. - * @param s1 The number of finite field elements to be copied into memory. - * @param d0 The starting index of memory where calldata will be copied to. + * @param cdOffset The starting index of the region in calldata to be copied. + * @param copySize The number of finite field elements to be copied into memory. + * @param dstOffset The starting index of memory where calldata will be copied to. * @param callDataMem The vector containing calldata. */ -void AvmMiniTraceBuilder::callDataCopy(uint32_t s0, uint32_t s1, uint32_t d0, std::vector const& callDataMem) +void AvmMiniTraceBuilder::callDataCopy(uint32_t cdOffset, + uint32_t copySize, + uint32_t dstOffset, + std::vector const& callDataMem) { // We parallelize storing memory operations in chunk of 3, i.e., 1 per intermediate register. - // This offset points to the first storing operation (pertaining to intermediate register Ia). - // s0 + offset: Ia memory store operation - // s0 + offset + 1: Ib memory store operation - // s0 + offset + 2: Ic memory store operation + // The variable pos is an index pointing to the first storing operation (pertaining to intermediate + // register Ia) relative to cdOffset: + // cdOffset + pos: Ia memory store operation + // cdOffset + pos + 1: Ib memory store operation + // cdOffset + pos + 2: Ic memory store operation - uint32_t offset = 0; + uint32_t pos = 0; - while (offset < s1) { + while (pos < copySize) { FF ib(0); FF ic(0); uint32_t mem_op_b(0); @@ -237,19 +383,19 @@ void AvmMiniTraceBuilder::callDataCopy(uint32_t s0, uint32_t s1, uint32_t d0, st uint32_t rwc(0); auto clk = mainTrace.size(); - FF ia = callDataMem.at(s0 + offset); + FF ia = callDataMem.at(cdOffset + pos); uint32_t mem_op_a(1); - uint32_t mem_idx_a = d0 + offset; + uint32_t mem_idx_a = dstOffset + pos; uint32_t rwa = 1; // Storing from Ia ffMemory.at(mem_idx_a) = ia; storeAInMemTrace(mem_idx_a, ia); - if (s1 - offset > 1) { - ib = callDataMem.at(s0 + offset + 1); + if (copySize - pos > 1) { + ib = callDataMem.at(cdOffset + pos + 1); mem_op_b = 1; - mem_idx_b = d0 + offset + 1; + mem_idx_b = dstOffset + pos + 1; rwb = 1; // Storing from Ib @@ -257,10 +403,10 @@ void AvmMiniTraceBuilder::callDataCopy(uint32_t s0, uint32_t s1, uint32_t d0, st storeBInMemTrace(mem_idx_b, ib); } - if (s1 - offset > 2) { - ic = callDataMem.at(s0 + offset + 2); + if (copySize - pos > 2) { + ic = callDataMem.at(cdOffset + pos + 2); mem_op_c = 1; - mem_idx_c = d0 + offset + 2; + mem_idx_c = dstOffset + pos + 2; rwc = 1; // Storing from Ic @@ -284,39 +430,40 @@ void AvmMiniTraceBuilder::callDataCopy(uint32_t s0, uint32_t s1, uint32_t d0, st .avmMini_mem_idx_c = FF(mem_idx_c), }); - if (s1 - offset > 2) { // Guard to prevent overflow if s1 is close to uint32_t maximum value. - offset += 3; + if (copySize - pos > 2) { // Guard to prevent overflow if copySize is close to uint32_t maximum value. + pos += 3; } else { - offset = s1; + pos = copySize; } } } /** * @brief RETURN opcode with direct memory access, i.e., - * return M_F[s0:s0+s1] + * return(M[retOffset:retOffset+retSize]) * Simplified version with exclusively memory load operations into * intermediate registers and then values are copied to the returned vector. * TODO: Implement the indirect memory version (maybe not required) * TODO: taking care of flagging this row as the last one? Special STOP flag? * - * @param s0 The starting index of the memory region to be returned. - * @param s1 The number of elements to be returned. + * @param retOffset The starting index of the memory region to be returned. + * @param retSize The number of elements to be returned. * @return The returned memory region as a std::vector. */ -std::vector AvmMiniTraceBuilder::returnOP(uint32_t s0, uint32_t s1) +std::vector AvmMiniTraceBuilder::returnOP(uint32_t retOffset, uint32_t retSize) { // We parallelize loading memory operations in chunk of 3, i.e., 1 per intermediate register. - // This offset points to the first loading operation (pertaining to intermediate register Ia). - // s0 + offset: Ia memory load operation - // s0 + offset + 1: Ib memory load operation - // s0 + offset + 2: Ic memory load operation + // The variable pos is an index pointing to the first storing operation (pertaining to intermediate + // register Ia) relative to retOffset: + // retOffset + pos: Ia memory load operation + // retOffset + pos + 1: Ib memory load operation + // retOffset + pos + 2: Ic memory load operation - uint32_t offset = 0; + uint32_t pos = 0; std::vector returnMem; - while (offset < s1) { + while (pos < retSize) { FF ib(0); FF ic(0); uint32_t mem_op_b(0); @@ -326,16 +473,16 @@ std::vector AvmMiniTraceBuilder::returnOP(uint32_t s0, uint32_t s1) auto clk = mainTrace.size(); uint32_t mem_op_a(1); - uint32_t mem_idx_a = s0 + offset; + uint32_t mem_idx_a = retOffset + pos; FF ia = ffMemory.at(mem_idx_a); // Loading from Ia returnMem.push_back(ia); loadAInMemTrace(mem_idx_a, ia); - if (s1 - offset > 1) { + if (retSize - pos > 1) { mem_op_b = 1; - mem_idx_b = s0 + offset + 1; + mem_idx_b = retOffset + pos + 1; ib = ffMemory.at(mem_idx_b); // Loading from Ib @@ -343,9 +490,9 @@ std::vector AvmMiniTraceBuilder::returnOP(uint32_t s0, uint32_t s1) loadBInMemTrace(mem_idx_b, ib); } - if (s1 - offset > 2) { + if (retSize - pos > 2) { mem_op_c = 1; - mem_idx_c = s0 + offset + 2; + mem_idx_c = retOffset + pos + 2; ic = ffMemory.at(mem_idx_c); // Loading from Ic @@ -366,10 +513,10 @@ std::vector AvmMiniTraceBuilder::returnOP(uint32_t s0, uint32_t s1) .avmMini_mem_idx_c = FF(mem_idx_c), }); - if (s1 - offset > 2) { // Guard to prevent overflow if s1 is close to uint32_t maximum value. - offset += 3; + if (retSize - pos > 2) { // Guard to prevent overflow if retSize is close to uint32_t maximum value. + pos += 3; } else { - offset = s1; + pos = retSize; } } return returnMem; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp index 781d798cd6e..a4621c22e19 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp @@ -24,14 +24,14 @@ class AvmMiniTraceBuilder { public: // Number of rows static const size_t N = 256; - static const size_t MemSize = 1024; + static const size_t MEM_SIZE = 1024; - static const uint32_t SubClkLoadA = 0; - static const uint32_t SubClkLoadB = 1; - static const uint32_t SubClkLoadC = 2; - static const uint32_t SubClkStoreA = 3; - static const uint32_t SubClkStoreB = 4; - static const uint32_t SubClkStoreC = 5; + static const uint32_t SUB_CLK_LOAD_A = 0; + static const uint32_t SUB_CLK_LOAD_B = 1; + static const uint32_t SUB_CLK_LOAD_C = 2; + static const uint32_t SUB_CLK_STORE_A = 3; + static const uint32_t SUB_CLK_STORE_B = 4; + static const uint32_t SUB_CLK_STORE_C = 5; AvmMiniTraceBuilder(); @@ -42,15 +42,24 @@ class AvmMiniTraceBuilder { void reset(); // Addition over finite field with direct memory access. - void add(uint32_t s0, uint32_t s1, uint32_t d0); + void add(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset); + + // Subtraction over finite field with direct memory access. + void sub(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset); + + // Multiplication over finite field with direct memory access. + void mul(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset); + + // Division over finite field with direct memory access. + void div(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset); // CALLDATACOPY opcode with direct memory access, i.e., - // M_F[d0:d0+s1] = M_calldata[s0:s0+s1] - void callDataCopy(uint32_t s0, uint32_t s1, uint32_t d0, std::vector const& callDataMem); + // M[dstOffset:dstOffset+copySize] = calldata[cdOffset:cdOffset+copySize] + void callDataCopy(uint32_t cdOffset, uint32_t copySize, uint32_t dstOffset, std::vector const& callDataMem); // RETURN opcode with direct memory access, i.e., - // return M_F[s0:s0+s1] - std::vector returnOP(uint32_t s0, uint32_t s1); + // return(M[retOffset:retOffset+retSize]) + std::vector returnOP(uint32_t retOffset, uint32_t retSize); private: struct MemoryTraceEntry { @@ -63,7 +72,7 @@ class AvmMiniTraceBuilder { std::vector mainTrace; std::vector memTrace; // Entries will be sorted by m_clk, m_sub_clk after finalize(). - std::array ffMemory{}; // Memory table for finite field elements + std::array ffMemory{}; // Memory table for finite field elements // Used for simulation of memory table static bool compareMemEntries(const MemoryTraceEntry& left, const MemoryTraceEntry& right); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp index 77cae117e47..46cabaa1a0e 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp @@ -24,7 +24,12 @@ template struct AvmMiniFullRow { FF memTrace_m_val{}; FF memTrace_m_lastAccess{}; FF memTrace_m_rw{}; - FF avmMini_subop{}; + FF avmMini_sel_op_add{}; + FF avmMini_sel_op_sub{}; + FF avmMini_sel_op_mul{}; + FF avmMini_sel_op_div{}; + FF avmMini_op_err{}; + FF avmMini_inv{}; FF avmMini_ia{}; FF avmMini_ib{}; FF avmMini_ic{}; @@ -38,9 +43,9 @@ template struct AvmMiniFullRow { FF avmMini_mem_idx_b{}; FF avmMini_mem_idx_c{}; FF avmMini_last{}; - FF memTrace_m_addr_shift{}; FF memTrace_m_rw_shift{}; FF memTrace_m_val_shift{}; + FF memTrace_m_addr_shift{}; }; class AvmMiniCircuitBuilder { @@ -53,8 +58,8 @@ class AvmMiniCircuitBuilder { using Polynomial = Flavor::Polynomial; using AllPolynomials = Flavor::AllPolynomials; - static constexpr size_t num_fixed_columns = 25; - static constexpr size_t num_polys = 22; + static constexpr size_t num_fixed_columns = 30; + static constexpr size_t num_polys = 27; std::vector rows; void set_trace(std::vector&& trace) { rows = std::move(trace); } @@ -78,7 +83,12 @@ class AvmMiniCircuitBuilder { polys.memTrace_m_val[i] = rows[i].memTrace_m_val; polys.memTrace_m_lastAccess[i] = rows[i].memTrace_m_lastAccess; polys.memTrace_m_rw[i] = rows[i].memTrace_m_rw; - polys.avmMini_subop[i] = rows[i].avmMini_subop; + polys.avmMini_sel_op_add[i] = rows[i].avmMini_sel_op_add; + polys.avmMini_sel_op_sub[i] = rows[i].avmMini_sel_op_sub; + polys.avmMini_sel_op_mul[i] = rows[i].avmMini_sel_op_mul; + polys.avmMini_sel_op_div[i] = rows[i].avmMini_sel_op_div; + polys.avmMini_op_err[i] = rows[i].avmMini_op_err; + polys.avmMini_inv[i] = rows[i].avmMini_inv; polys.avmMini_ia[i] = rows[i].avmMini_ia; polys.avmMini_ib[i] = rows[i].avmMini_ib; polys.avmMini_ic[i] = rows[i].avmMini_ic; @@ -94,9 +104,9 @@ class AvmMiniCircuitBuilder { polys.avmMini_last[i] = rows[i].avmMini_last; } - polys.memTrace_m_addr_shift = Polynomial(polys.memTrace_m_addr.shifted()); polys.memTrace_m_rw_shift = Polynomial(polys.memTrace_m_rw.shifted()); polys.memTrace_m_val_shift = Polynomial(polys.memTrace_m_val.shifted()); + polys.memTrace_m_addr_shift = Polynomial(polys.memTrace_m_addr.shifted()); return polys; } @@ -131,10 +141,10 @@ class AvmMiniCircuitBuilder { return true; }; - if (!evaluate_relation.template operator()>("mem_trace")) { + if (!evaluate_relation.template operator()>("avm_mini")) { return false; } - if (!evaluate_relation.template operator()>("avm_mini")) { + if (!evaluate_relation.template operator()>("mem_trace")) { return false; } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp index 14909b98be3..5596bbc94cf 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp @@ -7,24 +7,29 @@ namespace proof_system::AvmMini_vm { template struct Avm_miniRow { - FF avmMini_rwc{}; - FF avmMini_rwa{}; FF avmMini_mem_op_b{}; FF avmMini_ib{}; - FF avmMini_rwb{}; - FF avmMini_subop{}; + FF avmMini_ic{}; + FF avmMini_sel_op_sub{}; FF avmMini_mem_op_c{}; + FF avmMini_op_err{}; FF avmMini_ia{}; - FF avmMini_ic{}; + FF avmMini_inv{}; + FF avmMini_sel_op_div{}; FF avmMini_mem_op_a{}; + FF avmMini_rwa{}; + FF avmMini_sel_op_mul{}; + FF avmMini_rwc{}; + FF avmMini_sel_op_add{}; + FF avmMini_rwb{}; }; template class avm_miniImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, 3, 3, 3, 3, 3, 3, 3, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4, 3, }; template @@ -38,7 +43,7 @@ template class avm_miniImpl { { DECLARE_VIEWS(0); - auto tmp = (avmMini_subop * (-avmMini_subop + FF(1))); + auto tmp = (avmMini_sel_op_add * (-avmMini_sel_op_add + FF(1))); tmp *= scaling_factor; std::get<0>(evals) += tmp; } @@ -46,7 +51,7 @@ template class avm_miniImpl { { DECLARE_VIEWS(1); - auto tmp = (avmMini_mem_op_a * (-avmMini_mem_op_a + FF(1))); + auto tmp = (avmMini_sel_op_sub * (-avmMini_sel_op_sub + FF(1))); tmp *= scaling_factor; std::get<1>(evals) += tmp; } @@ -54,7 +59,7 @@ template class avm_miniImpl { { DECLARE_VIEWS(2); - auto tmp = (avmMini_mem_op_b * (-avmMini_mem_op_b + FF(1))); + auto tmp = (avmMini_sel_op_mul * (-avmMini_sel_op_mul + FF(1))); tmp *= scaling_factor; std::get<2>(evals) += tmp; } @@ -62,7 +67,7 @@ template class avm_miniImpl { { DECLARE_VIEWS(3); - auto tmp = (avmMini_mem_op_c * (-avmMini_mem_op_c + FF(1))); + auto tmp = (avmMini_sel_op_div * (-avmMini_sel_op_div + FF(1))); tmp *= scaling_factor; std::get<3>(evals) += tmp; } @@ -70,7 +75,7 @@ template class avm_miniImpl { { DECLARE_VIEWS(4); - auto tmp = (avmMini_rwa * (-avmMini_rwa + FF(1))); + auto tmp = (avmMini_op_err * (-avmMini_op_err + FF(1))); tmp *= scaling_factor; std::get<4>(evals) += tmp; } @@ -78,7 +83,7 @@ template class avm_miniImpl { { DECLARE_VIEWS(5); - auto tmp = (avmMini_rwb * (-avmMini_rwb + FF(1))); + auto tmp = (avmMini_mem_op_a * (-avmMini_mem_op_a + FF(1))); tmp *= scaling_factor; std::get<5>(evals) += tmp; } @@ -86,7 +91,7 @@ template class avm_miniImpl { { DECLARE_VIEWS(6); - auto tmp = (avmMini_rwc * (-avmMini_rwc + FF(1))); + auto tmp = (avmMini_mem_op_b * (-avmMini_mem_op_b + FF(1))); tmp *= scaling_factor; std::get<6>(evals) += tmp; } @@ -94,10 +99,90 @@ template class avm_miniImpl { { DECLARE_VIEWS(7); - auto tmp = (avmMini_subop * ((avmMini_ia + avmMini_ib) - avmMini_ic)); + auto tmp = (avmMini_mem_op_c * (-avmMini_mem_op_c + FF(1))); tmp *= scaling_factor; std::get<7>(evals) += tmp; } + // Contribution 8 + { + DECLARE_VIEWS(8); + + auto tmp = (avmMini_rwa * (-avmMini_rwa + FF(1))); + tmp *= scaling_factor; + std::get<8>(evals) += tmp; + } + // Contribution 9 + { + DECLARE_VIEWS(9); + + auto tmp = (avmMini_rwb * (-avmMini_rwb + FF(1))); + tmp *= scaling_factor; + std::get<9>(evals) += tmp; + } + // Contribution 10 + { + DECLARE_VIEWS(10); + + auto tmp = (avmMini_rwc * (-avmMini_rwc + FF(1))); + tmp *= scaling_factor; + std::get<10>(evals) += tmp; + } + // Contribution 11 + { + DECLARE_VIEWS(11); + + auto tmp = (avmMini_sel_op_add * ((avmMini_ia + avmMini_ib) - avmMini_ic)); + tmp *= scaling_factor; + std::get<11>(evals) += tmp; + } + // Contribution 12 + { + DECLARE_VIEWS(12); + + auto tmp = (avmMini_sel_op_sub * ((avmMini_ia - avmMini_ib) - avmMini_ic)); + tmp *= scaling_factor; + std::get<12>(evals) += tmp; + } + // Contribution 13 + { + DECLARE_VIEWS(13); + + auto tmp = (avmMini_sel_op_mul * ((avmMini_ia * avmMini_ib) - avmMini_ic)); + tmp *= scaling_factor; + std::get<13>(evals) += tmp; + } + // Contribution 14 + { + DECLARE_VIEWS(14); + + auto tmp = ((avmMini_sel_op_div * (-avmMini_op_err + FF(1))) * ((avmMini_ic * avmMini_ib) - avmMini_ia)); + tmp *= scaling_factor; + std::get<14>(evals) += tmp; + } + // Contribution 15 + { + DECLARE_VIEWS(15); + + auto tmp = (avmMini_sel_op_div * (((avmMini_ib * avmMini_inv) - FF(1)) + avmMini_op_err)); + tmp *= scaling_factor; + std::get<15>(evals) += tmp; + } + // Contribution 16 + { + DECLARE_VIEWS(16); + + auto tmp = ((avmMini_sel_op_div * avmMini_op_err) * (-avmMini_inv + FF(1))); + tmp *= scaling_factor; + std::get<16>(evals) += tmp; + } + // Contribution 17 + { + DECLARE_VIEWS(17); + + auto tmp = (avmMini_op_err * (avmMini_sel_op_div - FF(1))); + tmp *= scaling_factor; + std::get<17>(evals) += tmp; + } } }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp index cad793a7b5f..b5d9a61651e 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp @@ -10,7 +10,12 @@ [[maybe_unused]] auto memTrace_m_val = View(new_term.memTrace_m_val); \ [[maybe_unused]] auto memTrace_m_lastAccess = View(new_term.memTrace_m_lastAccess); \ [[maybe_unused]] auto memTrace_m_rw = View(new_term.memTrace_m_rw); \ - [[maybe_unused]] auto avmMini_subop = View(new_term.avmMini_subop); \ + [[maybe_unused]] auto avmMini_sel_op_add = View(new_term.avmMini_sel_op_add); \ + [[maybe_unused]] auto avmMini_sel_op_sub = View(new_term.avmMini_sel_op_sub); \ + [[maybe_unused]] auto avmMini_sel_op_mul = View(new_term.avmMini_sel_op_mul); \ + [[maybe_unused]] auto avmMini_sel_op_div = View(new_term.avmMini_sel_op_div); \ + [[maybe_unused]] auto avmMini_op_err = View(new_term.avmMini_op_err); \ + [[maybe_unused]] auto avmMini_inv = View(new_term.avmMini_inv); \ [[maybe_unused]] auto avmMini_ia = View(new_term.avmMini_ia); \ [[maybe_unused]] auto avmMini_ib = View(new_term.avmMini_ib); \ [[maybe_unused]] auto avmMini_ic = View(new_term.avmMini_ic); \ @@ -24,6 +29,6 @@ [[maybe_unused]] auto avmMini_mem_idx_b = View(new_term.avmMini_mem_idx_b); \ [[maybe_unused]] auto avmMini_mem_idx_c = View(new_term.avmMini_mem_idx_c); \ [[maybe_unused]] auto avmMini_last = View(new_term.avmMini_last); \ - [[maybe_unused]] auto memTrace_m_addr_shift = View(new_term.memTrace_m_addr_shift); \ [[maybe_unused]] auto memTrace_m_rw_shift = View(new_term.memTrace_m_rw_shift); \ - [[maybe_unused]] auto memTrace_m_val_shift = View(new_term.memTrace_m_val_shift); + [[maybe_unused]] auto memTrace_m_val_shift = View(new_term.memTrace_m_val_shift); \ + [[maybe_unused]] auto memTrace_m_addr_shift = View(new_term.memTrace_m_addr_shift); diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp index 2a7960abd72..dde059dedc6 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp @@ -7,15 +7,15 @@ namespace proof_system::AvmMini_vm { template struct Mem_traceRow { - FF avmMini_last{}; + FF memTrace_m_rw_shift{}; + FF memTrace_m_lastAccess{}; FF memTrace_m_addr{}; - FF memTrace_m_val{}; + FF memTrace_m_val_shift{}; + FF memTrace_m_rw{}; FF avmMini_first{}; FF memTrace_m_addr_shift{}; - FF memTrace_m_rw{}; - FF memTrace_m_rw_shift{}; - FF memTrace_m_val_shift{}; - FF memTrace_m_lastAccess{}; + FF avmMini_last{}; + FF memTrace_m_val{}; }; template class mem_traceImpl { diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_composer.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_composer.cpp index 6b6bb8f5550..d07684fc3ec 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_composer.cpp @@ -25,7 +25,12 @@ void AvmMiniComposer::compute_witness(CircuitConstructor& circuit) proving_key->memTrace_m_val = polynomials.memTrace_m_val; proving_key->memTrace_m_lastAccess = polynomials.memTrace_m_lastAccess; proving_key->memTrace_m_rw = polynomials.memTrace_m_rw; - proving_key->avmMini_subop = polynomials.avmMini_subop; + proving_key->avmMini_sel_op_add = polynomials.avmMini_sel_op_add; + proving_key->avmMini_sel_op_sub = polynomials.avmMini_sel_op_sub; + proving_key->avmMini_sel_op_mul = polynomials.avmMini_sel_op_mul; + proving_key->avmMini_sel_op_div = polynomials.avmMini_sel_op_div; + proving_key->avmMini_op_err = polynomials.avmMini_op_err; + proving_key->avmMini_inv = polynomials.avmMini_inv; proving_key->avmMini_ia = polynomials.avmMini_ia; proving_key->avmMini_ib = polynomials.avmMini_ib; proving_key->avmMini_ic = polynomials.avmMini_ic; diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_composer.test.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_composer.test.cpp index 4429aec7357..daa17a2599f 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_composer.test.cpp @@ -35,29 +35,36 @@ TEST_F(AvmMiniTests, basic) trace_builder.callDataCopy(0, 3, 2, std::vector{ 45, 23, 12 }); - trace_builder.add(2, 3, 4); - trace_builder.add(4, 5, 5); - trace_builder.add(5, 5, 5); - trace_builder.add(5, 6, 7); + // Memory layout: [0,0,45,23,12,0,0,0,....] + trace_builder.add(2, 3, 4); // [0,0,45,23,68,0,0,0,....] + trace_builder.add(4, 5, 5); // [0,0,45,23,68,68,0,0,....] + trace_builder.add(5, 5, 5); // [0,0,45,23,68,136,0,0,....] + trace_builder.add(5, 6, 7); // [0,0,45,23,68,136,0,136,0....] + trace_builder.sub(7, 6, 8); // [0,0,45,23,68,136,0,136,136,0....] + trace_builder.mul(8, 8, 8); // [0,0,45,23,68,136,0,136,136^2,0....] + trace_builder.div(3, 5, 1); // [0,23*136^(-1),45,23,68,136,0,136,136^2,0....] + trace_builder.div(1, 1, 9); // [0,23*136^(-1),45,23,68,136,0,136,136^2,1,0....] + trace_builder.div(9, 0, 4); // [0,23*136^(-1),45,23,1/0,136,0,136,136^2,1,0....] Error: division by 0 trace_builder.returnOP(1, 8); auto trace = trace_builder.finalize(); circuit_builder.set_trace(std::move(trace)); - ASSERT_TRUE(circuit_builder.check_circuit()); + EXPECT_TRUE(circuit_builder.check_circuit()); auto composer = AvmMiniComposer(); auto prover = composer.create_prover(circuit_builder); auto proof = prover.construct_proof(); + auto verifier = composer.create_verifier(circuit_builder); bool verified = verifier.verify_proof(proof); - ASSERT_TRUE(verified); - if (!verified) { proof_system::log_avmMini_trace(circuit_builder.rows, 0, 10); } + + EXPECT_TRUE(verified); } } // namespace example_relation_honk_composer \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp index b7daa36ddb3..da10ff83a40 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp @@ -3,7 +3,6 @@ #include "AvmMini_prover.hpp" #include "barretenberg/commitment_schemes/claim.hpp" #include "barretenberg/commitment_schemes/commitment_key.hpp" -#include "barretenberg/honk/proof_system/logderivative_library.hpp" #include "barretenberg/honk/proof_system/permutation_library.hpp" #include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/polynomials/polynomial.hpp" @@ -30,7 +29,6 @@ AvmMiniProver::AvmMiniProver(std::shared_ptr input_key, , commitment_key(commitment_key) { // TODO: take every polynomial and assign it to the key!! - prover_polynomials.avmMini_clk = key->avmMini_clk; prover_polynomials.avmMini_first = key->avmMini_first; prover_polynomials.memTrace_m_clk = key->memTrace_m_clk; @@ -39,7 +37,12 @@ AvmMiniProver::AvmMiniProver(std::shared_ptr input_key, prover_polynomials.memTrace_m_val = key->memTrace_m_val; prover_polynomials.memTrace_m_lastAccess = key->memTrace_m_lastAccess; prover_polynomials.memTrace_m_rw = key->memTrace_m_rw; - prover_polynomials.avmMini_subop = key->avmMini_subop; + prover_polynomials.avmMini_sel_op_add = key->avmMini_sel_op_add; + prover_polynomials.avmMini_sel_op_sub = key->avmMini_sel_op_sub; + prover_polynomials.avmMini_sel_op_mul = key->avmMini_sel_op_mul; + prover_polynomials.avmMini_sel_op_div = key->avmMini_sel_op_div; + prover_polynomials.avmMini_op_err = key->avmMini_op_err; + prover_polynomials.avmMini_inv = key->avmMini_inv; prover_polynomials.avmMini_ia = key->avmMini_ia; prover_polynomials.avmMini_ib = key->avmMini_ib; prover_polynomials.avmMini_ic = key->avmMini_ic; @@ -54,15 +57,15 @@ AvmMiniProver::AvmMiniProver(std::shared_ptr input_key, prover_polynomials.avmMini_mem_idx_c = key->avmMini_mem_idx_c; prover_polynomials.avmMini_last = key->avmMini_last; - prover_polynomials.memTrace_m_addr = key->memTrace_m_addr; - prover_polynomials.memTrace_m_addr_shift = key->memTrace_m_addr.shifted(); - prover_polynomials.memTrace_m_rw = key->memTrace_m_rw; prover_polynomials.memTrace_m_rw_shift = key->memTrace_m_rw.shifted(); prover_polynomials.memTrace_m_val = key->memTrace_m_val; prover_polynomials.memTrace_m_val_shift = key->memTrace_m_val.shifted(); + prover_polynomials.memTrace_m_addr = key->memTrace_m_addr; + prover_polynomials.memTrace_m_addr_shift = key->memTrace_m_addr.shifted(); + // prover_polynomials.lookup_inverses = key->lookup_inverses; // key->z_perm = Polynomial(key->circuit_size); // prover_polynomials.z_perm = key->z_perm; @@ -130,7 +133,7 @@ plonk::proof& AvmMiniProver::export_proof() plonk::proof& AvmMiniProver::construct_proof() { - // Add circuit size public input size and public inputs to transcript-> + // Add circuit size public input size and public inputs to transcript. execute_preamble_round(); // Compute wire commitments diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp index b0b9da4ec44..4014eec57bb 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp @@ -64,7 +64,16 @@ bool AvmMiniVerifier::verify_proof(const plonk::proof& proof) commitments.memTrace_m_lastAccess = transcript->template receive_from_prover(commitment_labels.memTrace_m_lastAccess); commitments.memTrace_m_rw = transcript->template receive_from_prover(commitment_labels.memTrace_m_rw); - commitments.avmMini_subop = transcript->template receive_from_prover(commitment_labels.avmMini_subop); + commitments.avmMini_sel_op_add = + transcript->template receive_from_prover(commitment_labels.avmMini_sel_op_add); + commitments.avmMini_sel_op_sub = + transcript->template receive_from_prover(commitment_labels.avmMini_sel_op_sub); + commitments.avmMini_sel_op_mul = + transcript->template receive_from_prover(commitment_labels.avmMini_sel_op_mul); + commitments.avmMini_sel_op_div = + transcript->template receive_from_prover(commitment_labels.avmMini_sel_op_div); + commitments.avmMini_op_err = transcript->template receive_from_prover(commitment_labels.avmMini_op_err); + commitments.avmMini_inv = transcript->template receive_from_prover(commitment_labels.avmMini_inv); commitments.avmMini_ia = transcript->template receive_from_prover(commitment_labels.avmMini_ia); commitments.avmMini_ib = transcript->template receive_from_prover(commitment_labels.avmMini_ib); commitments.avmMini_ic = transcript->template receive_from_prover(commitment_labels.avmMini_ic); From 863ee5da79bdbc27febfbdf7f623c40f0ee3c5bd Mon Sep 17 00:00:00 2001 From: Jean M <132435771+jeanmon@users.noreply.github.com> Date: Mon, 11 Dec 2023 12:38:46 +0100 Subject: [PATCH 2/8] test(avm-mini): unit tests arithmetic for finite field type (#3633) Resolves #3632 ### Description A list of positive and negative unit tests for the arithmetic operations of finite field type. Each operation (add, sub, mul, div) is positively and negatively tested. --- .../vm/generated/AvmMini_composer.test.cpp | 70 --- .../vm/tests/AvmMini_arithmetic.test.cpp | 492 ++++++++++++++++++ 2 files changed, 492 insertions(+), 70 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_composer.test.cpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_composer.test.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_composer.test.cpp deleted file mode 100644 index daa17a2599f..00000000000 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_composer.test.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "barretenberg/vm/generated/AvmMini_composer.hpp" -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/flavor/generated/AvmMini_flavor.hpp" -#include "barretenberg/numeric/uint256/uint256.hpp" -#include "barretenberg/proof_system/circuit_builder/AvmMini_helper.hpp" -#include "barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp" -#include "barretenberg/sumcheck/sumcheck_round.hpp" -#include "barretenberg/vm/generated/AvmMini_prover.hpp" -#include "barretenberg/vm/generated/AvmMini_verifier.hpp" - -#include -#include -#include -#include -#include - -using namespace proof_system::honk; - -namespace example_relation_honk_composer { - -class AvmMiniTests : public ::testing::Test { - protected: - // TODO(640): The Standard Honk on Grumpkin test suite fails unless the SRS is initialised for every test. - void SetUp() override { barretenberg::srs::init_crs_factory("../srs_db/ignition"); }; -}; - -namespace { -auto& engine = numeric::random::get_debug_engine(); -} - -TEST_F(AvmMiniTests, basic) -{ - auto trace_builder = proof_system::AvmMiniTraceBuilder(); - auto circuit_builder = proof_system::AvmMiniCircuitBuilder(); - - trace_builder.callDataCopy(0, 3, 2, std::vector{ 45, 23, 12 }); - - // Memory layout: [0,0,45,23,12,0,0,0,....] - trace_builder.add(2, 3, 4); // [0,0,45,23,68,0,0,0,....] - trace_builder.add(4, 5, 5); // [0,0,45,23,68,68,0,0,....] - trace_builder.add(5, 5, 5); // [0,0,45,23,68,136,0,0,....] - trace_builder.add(5, 6, 7); // [0,0,45,23,68,136,0,136,0....] - trace_builder.sub(7, 6, 8); // [0,0,45,23,68,136,0,136,136,0....] - trace_builder.mul(8, 8, 8); // [0,0,45,23,68,136,0,136,136^2,0....] - trace_builder.div(3, 5, 1); // [0,23*136^(-1),45,23,68,136,0,136,136^2,0....] - trace_builder.div(1, 1, 9); // [0,23*136^(-1),45,23,68,136,0,136,136^2,1,0....] - trace_builder.div(9, 0, 4); // [0,23*136^(-1),45,23,1/0,136,0,136,136^2,1,0....] Error: division by 0 - - trace_builder.returnOP(1, 8); - - auto trace = trace_builder.finalize(); - circuit_builder.set_trace(std::move(trace)); - - EXPECT_TRUE(circuit_builder.check_circuit()); - - auto composer = AvmMiniComposer(); - auto prover = composer.create_prover(circuit_builder); - auto proof = prover.construct_proof(); - - auto verifier = composer.create_verifier(circuit_builder); - bool verified = verifier.verify_proof(proof); - - if (!verified) { - proof_system::log_avmMini_trace(circuit_builder.rows, 0, 10); - } - - EXPECT_TRUE(verified); -} - -} // namespace example_relation_honk_composer \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp new file mode 100644 index 00000000000..1a94d54816e --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp @@ -0,0 +1,492 @@ +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/flavor/generated/AvmMini_flavor.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" +#include "barretenberg/proof_system/circuit_builder/AvmMini_helper.hpp" +#include "barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp" +#include "barretenberg/sumcheck/sumcheck_round.hpp" +#include "barretenberg/vm/generated/AvmMini_composer.hpp" +#include "barretenberg/vm/generated/AvmMini_prover.hpp" +#include "barretenberg/vm/generated/AvmMini_verifier.hpp" + +#include +#include +#include +#include +#include + +using namespace proof_system; + +namespace tests_avm { + +class AvmMiniArithmeticTests : public ::testing::Test { + public: + AvmMiniTraceBuilder trace_builder; + + protected: + // TODO(640): The Standard Honk on Grumpkin test suite fails unless the SRS is initialised for every test. + void SetUp() override + { + barretenberg::srs::init_crs_factory("../srs_db/ignition"); + trace_builder = AvmMiniTraceBuilder(); // Clean instance for every run. + }; +}; + +class AvmMiniArithmeticNegativeTests : public AvmMiniArithmeticTests {}; + +// We add some helper functions in the anonymous namespace. +namespace { + +/** + * @brief Helper routine proving and verifying a proof based on the supplied trace + * + * @param trace The execution trace + */ +void validateTraceProof(std::vector&& trace) +{ + auto circuit_builder = AvmMiniCircuitBuilder(); + circuit_builder.set_trace(std::move(trace)); + + EXPECT_TRUE(circuit_builder.check_circuit()); + + auto composer = honk::AvmMiniComposer(); + auto prover = composer.create_prover(circuit_builder); + auto proof = prover.construct_proof(); + + auto verifier = composer.create_verifier(circuit_builder); + bool verified = verifier.verify_proof(proof); + + if (!verified) { + log_avmMini_trace(circuit_builder.rows, 0, 10); + } +}; + +/** + * @brief Helper routine for the negative tests. It mutates the output value of an operation + * located in the Ic intermediate register. The memory trace is adapted consistently. + * + * @param trace Execution trace + * @param selectRow Lambda serving to select the row in trace + * @param newValue The value that will be written in intermediate register Ic at the selected row. + */ +void mutateIcInTrace(std::vector& trace, std::function&& selectRow, FF const& newValue) +{ + // Find the first row matching the criteria defined by selectRow + auto row = std::ranges::find_if(trace.begin(), trace.end(), selectRow); + + // Check that we found one + EXPECT_TRUE(row != trace.end()); + + // Mutate the correct result in the main trace + row->avmMini_ic = newValue; + + // Adapt the memory trace to be consistent with the wrongly computed addition + auto const clk = row->avmMini_clk; + auto const addr = row->avmMini_mem_idx_c; + + // Find the relevant memory trace entry. + auto memRow = std::ranges::find_if(trace.begin(), trace.end(), [clk, addr](Row r) { + return r.memTrace_m_clk == clk && r.memTrace_m_addr == addr; + }); + + EXPECT_TRUE(memRow != trace.end()); + memRow->memTrace_m_val = newValue; +}; + +} // anonymous namespace + +/****************************************************************************** + * + * POSITIVE TESTS - Finite Field Type + * + ****************************************************************************** + * The positive tests aim at testing that a genuinely generated execution trace + * is correct, i.e., the evaluation is correct and the proof passes. + * Positive refers to the proof system and not that the arithmetic operation has valid + * operands. A division by zero needs to be handled by the AVM and needs to raise an error. + * This will be positively tested, i.e., that the error is correctly raised. + * + * We isolate each operation addition, subtraction, multiplication and division + * by having dedicated unit test for each of them. + * In any positive test, we also verify that the main trace contains + * a write memory operation for the intermediate register Ic at the + * correct address. This operation belongs to the same row as the arithmetic + * operation. + * + * Finding the row pertaining to the arithmetic operation is done through + * a scan of all rows and stopping at the first one with the corresponding + * operator selector. This mechanism is used with the hope that these unit tests + * will still correctly work along the development of the AVM. + ******************************************************************************/ + +// Test on basic addition over finite field type. +TEST_F(AvmMiniArithmeticTests, additionFF) +{ + trace_builder.callDataCopy(0, 3, 0, std::vector{ 37, 4, 11 }); + + // Memory layout: [37,4,11,0,0,0,....] + trace_builder.add(0, 1, 4); // [37,4,11,0,41,0,....] + trace_builder.returnOP(0, 5); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the addition selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_add == FF(1); }); + + // Check that the correct result is stored at the expected memory location. + EXPECT_TRUE(row != trace.end()); + EXPECT_EQ(row->avmMini_ic, FF(41)); + EXPECT_EQ(row->avmMini_mem_idx_c, FF(4)); + EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); + EXPECT_EQ(row->avmMini_rwc, FF(1)); + + validateTraceProof(std::move(trace)); +} + +// Test on basic subtraction over finite field type. +TEST_F(AvmMiniArithmeticTests, subtractionFF) +{ + trace_builder.callDataCopy(0, 3, 0, std::vector{ 8, 4, 17 }); + + // Memory layout: [8,4,17,0,0,0,....] + trace_builder.sub(2, 0, 1); // [8,9,17,0,0,0....] + trace_builder.returnOP(0, 3); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the subtraction selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_sub == FF(1); }); + + // Check that the correct result is stored at the expected memory location. + EXPECT_TRUE(row != trace.end()); + EXPECT_EQ(row->avmMini_ic, FF(9)); + EXPECT_EQ(row->avmMini_mem_idx_c, FF(1)); + EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); + EXPECT_EQ(row->avmMini_rwc, FF(1)); + + validateTraceProof(std::move(trace)); +} + +// Test on basic multiplication over finite field type. +TEST_F(AvmMiniArithmeticTests, multiplicationFF) +{ + trace_builder.callDataCopy(0, 3, 0, std::vector{ 5, 0, 20 }); + + // Memory layout: [5,0,20,0,0,0,....] + trace_builder.mul(2, 0, 1); // [5,100,20,0,0,0....] + trace_builder.returnOP(0, 3); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the multiplication selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_mul == FF(1); }); + + // Check that the correct result is stored at the expected memory location. + EXPECT_TRUE(row != trace.end()); + EXPECT_EQ(row->avmMini_ic, FF(100)); + EXPECT_EQ(row->avmMini_mem_idx_c, FF(1)); + EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); + EXPECT_EQ(row->avmMini_rwc, FF(1)); + + validateTraceProof(std::move(trace)); +} + +// Test on multiplication by zero over finite field type. +TEST_F(AvmMiniArithmeticTests, multiplicationByZeroFF) +{ + trace_builder.callDataCopy(0, 1, 0, std::vector{ 127 }); + + // Memory layout: [127,0,0,0,0,0,....] + trace_builder.mul(0, 1, 2); // [127,0,0,0,0,0....] + trace_builder.returnOP(0, 3); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the multiplication selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_mul == FF(1); }); + + // Check that the correct result is stored at the expected memory location. + EXPECT_TRUE(row != trace.end()); + EXPECT_EQ(row->avmMini_ic, FF(0)); + EXPECT_EQ(row->avmMini_mem_idx_c, FF(2)); + EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); + EXPECT_EQ(row->avmMini_rwc, FF(1)); + + validateTraceProof(std::move(trace)); +} + +// Test on basic division over finite field type. +TEST_F(AvmMiniArithmeticTests, divisionFF) +{ + trace_builder.callDataCopy(0, 2, 0, std::vector{ 15, 315 }); + + // Memory layout: [15,315,0,0,0,0,....] + trace_builder.div(1, 0, 2); // [15,315,21,0,0,0....] + trace_builder.returnOP(0, 3); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the division selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_div == FF(1); }); + + // Check that the correct result is stored at the expected memory location. + EXPECT_TRUE(row != trace.end()); + EXPECT_EQ(row->avmMini_ic, FF(21)); + EXPECT_EQ(row->avmMini_mem_idx_c, FF(2)); + EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); + EXPECT_EQ(row->avmMini_rwc, FF(1)); + + validateTraceProof(std::move(trace)); +} + +// Test on division with zero numerator over finite field type. +TEST_F(AvmMiniArithmeticTests, divisionNumeratorZeroFF) +{ + trace_builder.callDataCopy(0, 1, 0, std::vector{ 15 }); + + // Memory layout: [15,0,0,0,0,0,....] + trace_builder.div(1, 0, 0); // [0,0,0,0,0,0....] + trace_builder.returnOP(0, 3); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the division selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_div == FF(1); }); + + // Check that the correct result is stored at the expected memory location. + EXPECT_TRUE(row != trace.end()); + EXPECT_EQ(row->avmMini_ic, FF(0)); + EXPECT_EQ(row->avmMini_mem_idx_c, FF(0)); + EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); + EXPECT_EQ(row->avmMini_rwc, FF(1)); + + validateTraceProof(std::move(trace)); +} + +// Test on division by zero over finite field type. +// We check that the operator error flag is raised. +TEST_F(AvmMiniArithmeticTests, divisionByZeroErrorFF) +{ + trace_builder.callDataCopy(0, 1, 0, std::vector{ 15 }); + + // Memory layout: [15,0,0,0,0,0,....] + trace_builder.div(0, 1, 2); // [15,0,0,0,0,0....] + auto trace = trace_builder.finalize(); + + // Find the first row enabling the division selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_div == FF(1); }); + + // Check that the correct result is stored at the expected memory location. + EXPECT_TRUE(row != trace.end()); + EXPECT_EQ(row->avmMini_ic, FF(0)); + EXPECT_EQ(row->avmMini_mem_idx_c, FF(2)); + EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); + EXPECT_EQ(row->avmMini_rwc, FF(1)); + EXPECT_EQ(row->avmMini_op_err, FF(1)); + + validateTraceProof(std::move(trace)); +} + +// Testing an execution of the different arithmetic opcodes over finite field +// and finishing with a division by zero. The chosen combination is arbitrary. +// We only test that the proof can be correctly generated and verified. +// No check on the evaluation is performed here. +TEST_F(AvmMiniArithmeticTests, arithmeticFFWithError) +{ + trace_builder.callDataCopy(0, 3, 2, std::vector{ 45, 23, 12 }); + + // Memory layout: [0,0,45,23,12,0,0,0,....] + trace_builder.add(2, 3, 4); // [0,0,45,23,68,0,0,0,....] + trace_builder.add(4, 5, 5); // [0,0,45,23,68,68,0,0,....] + trace_builder.add(5, 5, 5); // [0,0,45,23,68,136,0,0,....] + trace_builder.add(5, 6, 7); // [0,0,45,23,68,136,0,136,0....] + trace_builder.sub(7, 6, 8); // [0,0,45,23,68,136,0,136,136,0....] + trace_builder.mul(8, 8, 8); // [0,0,45,23,68,136,0,136,136^2,0....] + trace_builder.div(3, 5, 1); // [0,23*136^(-1),45,23,68,136,0,136,136^2,0....] + trace_builder.div(1, 1, 9); // [0,23*136^(-1),45,23,68,136,0,136,136^2,1,0....] + trace_builder.div(9, 0, 4); // [0,23*136^(-1),45,23,1/0,136,0,136,136^2,1,0....] Error: division by 0 + + auto trace = trace_builder.finalize(); + validateTraceProof(std::move(trace)); +} + +/****************************************************************************** + * + * NEGATIVE TESTS - Finite Field Type + * + ****************************************************************************** + * The negative tests are the counterparts of the positive tests for which we want + * to test that a deviation of the prescribed behaviour of the VM will lead to + * an exception being raised while attempting to generate a proof. + * + * As for the positive tests, we isolate each operation addition, subtraction, multiplication + * and division by having dedicated unit test for each of them. + * A typical pattern is to wrongly mutate the result of the operation. The memory trace + * is consistently adapted so that the negative test is applying to the relation + * if the arithmetic operation and not the layout of the memory trace. + * + * Finding the row pertaining to the arithmetic operation is done through + * a scan of all rows and stopping at the first one with the corresponding + * operator selector. This mechanism is used with the hope that these unit tests + * will still correctly work along the development of the AVM. + ******************************************************************************/ + +// Test on basic incorrect addition over finite field type. +TEST_F(AvmMiniArithmeticNegativeTests, additionFF) +{ + trace_builder.callDataCopy(0, 3, 0, std::vector{ 37, 4, 11 }); + + // Memory layout: [37,4,11,0,0,0,....] + trace_builder.add(0, 1, 4); // [37,4,11,0,41,0,....] + trace_builder.returnOP(0, 5); + auto trace = trace_builder.finalize(); + + auto selectRow = [](Row r) { return r.avmMini_sel_op_add == FF(1); }; + mutateIcInTrace(trace, std::move(selectRow), FF(40)); + + // TODO: check that the expected sub-relation failed + EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); +} + +// Test on basic incorrect subtraction over finite field type. +TEST_F(AvmMiniArithmeticNegativeTests, subtractionFF) +{ + trace_builder.callDataCopy(0, 3, 0, std::vector{ 8, 4, 17 }); + + // Memory layout: [8,4,17,0,0,0,....] + trace_builder.sub(2, 0, 1); // [8,9,17,0,0,0....] + trace_builder.returnOP(0, 3); + auto trace = trace_builder.finalize(); + + auto selectRow = [](Row r) { return r.avmMini_sel_op_sub == FF(1); }; + mutateIcInTrace(trace, std::move(selectRow), FF(-9)); + + // TODO: check that the expected sub-relation failed + EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); +} + +// Test on basic incorrect multiplication over finite field type. +TEST_F(AvmMiniArithmeticNegativeTests, multiplicationFF) +{ + trace_builder.callDataCopy(0, 3, 0, std::vector{ 5, 0, 20 }); + + // Memory layout: [5,0,20,0,0,0,....] + trace_builder.mul(2, 0, 1); // [5,100,20,0,0,0....] + trace_builder.returnOP(0, 3); + auto trace = trace_builder.finalize(); + + auto selectRow = [](Row r) { return r.avmMini_sel_op_mul == FF(1); }; + mutateIcInTrace(trace, std::move(selectRow), FF(1000)); + + // TODO: check that the expected sub-relation failed + EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); +} + +// Test on basic incorrect division over finite field type. +TEST_F(AvmMiniArithmeticNegativeTests, divisionFF) +{ + trace_builder.callDataCopy(0, 2, 0, std::vector{ 15, 315 }); + + // Memory layout: [15,315,0,0,0,0,....] + trace_builder.div(1, 0, 2); // [15,315,21,0,0,0....] + trace_builder.returnOP(0, 3); + auto trace = trace_builder.finalize(); + + auto selectRow = [](Row r) { return r.avmMini_sel_op_div == FF(1); }; + mutateIcInTrace(trace, std::move(selectRow), FF(0)); + + // TODO: check that the expected sub-relation failed + EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); +} + +// Test where division is not by zero but an operation error is wrongly raised +// in the trace. +TEST_F(AvmMiniArithmeticNegativeTests, divisionNoZeroButErrorFF) +{ + trace_builder.callDataCopy(0, 2, 0, std::vector{ 15, 315 }); + + // Memory layout: [15,315,0,0,0,0,....] + trace_builder.div(1, 0, 2); // [15,315,21,0,0,0....] + trace_builder.returnOP(0, 3); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the division selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_div == FF(1); }); + + // Activate the operator error + row->avmMini_op_err = FF(1); + + // TODO: check that the expected sub-relation failed + EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); +} + +// Test with division by zero occurs and no error is raised (remove error flag) +TEST_F(AvmMiniArithmeticNegativeTests, divisionByZeroNoErrorFF) +{ + trace_builder.callDataCopy(0, 1, 0, std::vector{ 15 }); + + // Memory layout: [15,0,0,0,0,0,....] + trace_builder.div(0, 1, 2); // [15,0,0,0,0,0....] + auto trace = trace_builder.finalize(); + + // Find the first row enabling the division selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_div == FF(1); }); + + // Remove the operator error flag + row->avmMini_op_err = FF(0); + + // TODO: check that the expected sub-relation failed + EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); +} + +// Test that error flag cannot be raised for a non-relevant operation such as +// the addition, subtraction, multiplication. +TEST_F(AvmMiniArithmeticNegativeTests, operationWithErrorFlagFF) +{ + trace_builder.callDataCopy(0, 3, 0, std::vector{ 37, 4, 11 }); + + // Memory layout: [37,4,11,0,0,0,....] + trace_builder.add(0, 1, 4); // [37,4,11,0,41,0,....] + trace_builder.returnOP(0, 5); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the addition selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_add == FF(1); }); + + // Activate the operator error + row->avmMini_op_err = FF(1); + + // TODO: check that the expected sub-relation failed + EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); + + trace_builder.reset(); + + trace_builder.callDataCopy(0, 3, 0, std::vector{ 8, 4, 17 }); + + // Memory layout: [8,4,17,0,0,0,....] + trace_builder.sub(2, 0, 1); // [8,9,17,0,0,0....] + trace_builder.returnOP(0, 3); + trace = trace_builder.finalize(); + + // Find the first row enabling the subtraction selector + row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_sub == FF(1); }); + + // Activate the operator error + row->avmMini_op_err = FF(1); + + // TODO: check that the expected sub-relation failed + EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); + + trace_builder.reset(); + + trace_builder.callDataCopy(0, 3, 0, std::vector{ 5, 0, 20 }); + + // Memory layout: [5,0,20,0,0,0,....] + trace_builder.mul(2, 0, 1); // [5,100,20,0,0,0....] + trace_builder.returnOP(0, 3); + trace = trace_builder.finalize(); + + // Find the first row enabling the multiplication selector + row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_mul == FF(1); }); + + // Activate the operator error + row->avmMini_op_err = FF(1); + + // TODO: check that the expected sub-relation failed + EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); +} + +} // namespace tests_avm \ No newline at end of file From 79f84cd2225a46146935f76e7e0bc91bf85cbd05 Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 14 Dec 2023 11:18:35 +0000 Subject: [PATCH 3/8] feat(avm-main): pil -> permutations (#3650) Replacing the toy_avm with a pil version that defines a permutation in pil. ``` pol commit q_tuple_set; // Set 1 pol commit set_1_column_1; pol commit set_1_column_2; // Set 2 pol commit set_2_column_1; pol commit set_2_column_2; // This is a column based tuple permutation #[two_column_perm] // the name of the inverse polynomial q_tuple_set { set_1_column_1, set_1_column_2 } is { set_2_column_1, set_2_column_2 }; ``` Syntax is as shown. --- barretenberg/.gitignore | 3 +- barretenberg/cpp/pil/avm/toy_avm.pil | 20 + .../flavor/generated/AvmMini_flavor.hpp | 18 +- .../flavor/generated/Toy_flavor.hpp | 304 ++++++++++++++ .../cpp/src/barretenberg/flavor/toy_avm.hpp | 376 ------------------ .../proof_system/logderivative_library.hpp | 2 +- .../generated/AvmMini_circuit_builder.hpp | 12 +- .../generated/Toy_circuit_builder.hpp | 163 ++++++++ .../toy_avm/toy_avm_circuit_builder.hpp | 163 -------- .../toy_avm/toy_avm_circuit_builder.test.cpp | 47 ++- .../relations/generated/AvmMini/avm_mini.hpp | 60 +-- .../generated/AvmMini/declare_views.hpp | 6 +- .../relations/generated/AvmMini/mem_trace.hpp | 16 +- .../relations/generated/Toy/declare_views.hpp | 13 + .../relations/generated/Toy/toy_avm.hpp | 42 ++ .../generated/Toy/two_column_perm.hpp | 94 +++++ .../generic_permutation_relation.hpp | 10 +- .../toy_avm/generic_permutation_relation.cpp | 34 -- .../relations/toy_avm/relation_definer.hpp | 213 ---------- .../vm/generated/AvmMini_prover.cpp | 7 +- .../vm/generated/Toy_composer.cpp | 89 +++++ .../vm/generated/Toy_composer.hpp | 69 ++++ .../barretenberg/vm/generated/Toy_prover.cpp | 136 +++++++ .../barretenberg/vm/generated/Toy_prover.hpp | 62 +++ .../vm/generated/Toy_verifier.cpp | 99 +++++ .../vm/generated/Toy_verifier.hpp | 33 ++ 26 files changed, 1225 insertions(+), 866 deletions(-) create mode 100644 barretenberg/cpp/pil/avm/toy_avm.pil create mode 100644 barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/flavor/toy_avm.hpp create mode 100644 barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.hpp create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/Toy/declare_views.hpp create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/Toy/toy_avm.hpp create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/Toy/two_column_perm.hpp rename barretenberg/cpp/src/barretenberg/relations/{toy_avm => generic_permutation}/generic_permutation_relation.hpp (95%) delete mode 100644 barretenberg/cpp/src/barretenberg/relations/toy_avm/generic_permutation_relation.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/relations/toy_avm/relation_definer.hpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/Toy_composer.cpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/Toy_composer.hpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.hpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.hpp diff --git a/barretenberg/.gitignore b/barretenberg/.gitignore index 77989f790d4..f55585139fd 100644 --- a/barretenberg/.gitignore +++ b/barretenberg/.gitignore @@ -5,4 +5,5 @@ node_modules ts/dest .tsbuildinfo .idea -cmake-build-debug \ No newline at end of file +cmake-build-debug +*_opt.pil \ No newline at end of file diff --git a/barretenberg/cpp/pil/avm/toy_avm.pil b/barretenberg/cpp/pil/avm/toy_avm.pil new file mode 100644 index 00000000000..ed355016195 --- /dev/null +++ b/barretenberg/cpp/pil/avm/toy_avm.pil @@ -0,0 +1,20 @@ +namespace toy(256); + pol commit q_tuple_set; + + // Set 1 + pol commit set_1_column_1; + pol commit set_1_column_2; + // Set 2 + pol commit set_2_column_1; + pol commit set_2_column_2; + + // This is a column based tuple lookup + #[two_column_perm] // the name of the inverse + q_tuple_set { set_1_column_1, set_1_column_2 } is { set_2_column_1, set_2_column_2 }; + + // Relation not used -> we currently require a single relation for codegen + pol commit x; + x' - x = 0; + + // Also needs a fixed relation + pol fixed first = [1] + [0]*; \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp index c3b00281f70..c2b4e385c8f 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp @@ -7,6 +7,8 @@ #include "barretenberg/polynomials/barycentric.hpp" #include "barretenberg/polynomials/univariate.hpp" +#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" + #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/flavor/flavor_macros.hpp" #include "barretenberg/polynomials/evaluation_domain.hpp" @@ -40,7 +42,7 @@ class AvmMiniFlavor { // the unshifted and one for the shifted static constexpr size_t NUM_ALL_ENTITIES = 30; - using Relations = std::tuple, AvmMini_vm::mem_trace>; + using Relations = std::tuple, AvmMini_vm::avm_mini>; static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); @@ -144,8 +146,8 @@ class AvmMiniFlavor { avmMini_mem_idx_c, avmMini_last, memTrace_m_rw_shift, - memTrace_m_val_shift, - memTrace_m_addr_shift) + memTrace_m_addr_shift, + memTrace_m_val_shift) RefVector get_wires() { @@ -177,8 +179,8 @@ class AvmMiniFlavor { avmMini_mem_idx_c, avmMini_last, memTrace_m_rw_shift, - memTrace_m_val_shift, - memTrace_m_addr_shift }; + memTrace_m_addr_shift, + memTrace_m_val_shift }; }; RefVector get_unshifted() { @@ -210,10 +212,10 @@ class AvmMiniFlavor { avmMini_mem_idx_c, avmMini_last }; }; - RefVector get_to_be_shifted() { return { memTrace_m_rw, memTrace_m_val, memTrace_m_addr }; }; + RefVector get_to_be_shifted() { return { memTrace_m_rw, memTrace_m_addr, memTrace_m_val }; }; RefVector get_shifted() { - return { memTrace_m_rw_shift, memTrace_m_val_shift, memTrace_m_addr_shift }; + return { memTrace_m_rw_shift, memTrace_m_addr_shift, memTrace_m_val_shift }; }; }; @@ -467,4 +469,6 @@ class AvmMiniFlavor { }; } // namespace flavor + +namespace sumcheck {} } // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp new file mode 100644 index 00000000000..540d9107b82 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp @@ -0,0 +1,304 @@ + + +#pragma once +#include "../relation_definitions_fwd.hpp" +#include "barretenberg/commitment_schemes/kzg/kzg.hpp" +#include "barretenberg/ecc/curves/bn254/g1.hpp" +#include "barretenberg/polynomials/barycentric.hpp" +#include "barretenberg/polynomials/univariate.hpp" + +#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" + +#include "barretenberg/flavor/flavor.hpp" +#include "barretenberg/flavor/flavor_macros.hpp" +#include "barretenberg/polynomials/evaluation_domain.hpp" +#include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/relations/generated/Toy/toy_avm.hpp" +#include "barretenberg/relations/generated/Toy/two_column_perm.hpp" +#include "barretenberg/transcript/transcript.hpp" + +namespace proof_system::honk { +namespace flavor { + +class ToyFlavor { + public: + using Curve = curve::BN254; + using G1 = Curve::Group; + using PCS = pcs::kzg::KZG; + + using FF = G1::subgroup_field; + using Polynomial = barretenberg::Polynomial; + using PolynomialHandle = std::span; + using GroupElement = G1::element; + using Commitment = G1::affine_element; + using CommitmentHandle = G1::affine_element; + using CommitmentKey = pcs::CommitmentKey; + using VerifierCommitmentKey = pcs::VerifierCommitmentKey; + + static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 1; + static constexpr size_t NUM_WITNESS_ENTITIES = 7; + static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; + // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for + // the unshifted and one for the shifted + static constexpr size_t NUM_ALL_ENTITIES = 9; + + using Relations = std::tuple, sumcheck::two_column_perm_relation>; + + static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); + + // BATCHED_RELATION_PARTIAL_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` + // random polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation + // length = 3 + static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1; + static constexpr size_t NUM_RELATIONS = std::tuple_size::value; + + template + using ProtogalaxyTupleOfTuplesOfUnivariates = + decltype(create_protogalaxy_tuple_of_tuples_of_univariates()); + using SumcheckTupleOfTuplesOfUnivariates = decltype(create_sumcheck_tuple_of_tuples_of_univariates()); + using TupleOfArraysOfValues = decltype(create_tuple_of_arrays_of_values()); + + static constexpr bool has_zero_row = true; + + private: + template class PrecomputedEntities : public PrecomputedEntitiesBase { + public: + using DataType = DataType_; + + DEFINE_FLAVOR_MEMBERS(DataType, toy_first) + + RefVector get_selectors() { return { toy_first }; }; + RefVector get_sigma_polynomials() { return {}; }; + RefVector get_id_polynomials() { return {}; }; + RefVector get_table_polynomials() { return {}; }; + }; + + template class WitnessEntities { + public: + DEFINE_FLAVOR_MEMBERS(DataType, + toy_q_tuple_set, + toy_set_1_column_1, + toy_set_1_column_2, + toy_set_2_column_1, + toy_set_2_column_2, + toy_x, + two_column_perm) + + RefVector get_wires() + { + return { toy_q_tuple_set, toy_set_1_column_1, toy_set_1_column_2, toy_set_2_column_1, toy_set_2_column_2, + toy_x, two_column_perm }; + }; + RefVector get_sorted_polynomials() { return {}; }; + }; + + template class AllEntities { + public: + DEFINE_FLAVOR_MEMBERS(DataType, + toy_first, + toy_q_tuple_set, + toy_set_1_column_1, + toy_set_1_column_2, + toy_set_2_column_1, + toy_set_2_column_2, + toy_x, + two_column_perm, + toy_x_shift) + + RefVector get_wires() + { + return { toy_first, toy_q_tuple_set, toy_set_1_column_1, toy_set_1_column_2, toy_set_2_column_1, + toy_set_2_column_2, toy_x, two_column_perm, toy_x_shift }; + }; + RefVector get_unshifted() + { + return { toy_first, toy_q_tuple_set, toy_set_1_column_1, toy_set_1_column_2, toy_set_2_column_1, + toy_set_2_column_2, toy_x, two_column_perm }; + }; + RefVector get_to_be_shifted() { return { toy_x }; }; + RefVector get_shifted() { return { toy_x_shift }; }; + }; + + public: + class ProvingKey : public ProvingKey_, WitnessEntities> { + public: + // Expose constructors on the base class + using Base = ProvingKey_, WitnessEntities>; + using Base::Base; + + // The plookup wires that store plookup read data. + std::array get_table_column_wires() { return {}; }; + }; + + using VerificationKey = VerificationKey_>; + + using ProverPolynomials = AllEntities; + + using FoldedPolynomials = AllEntities>; + + class AllValues : public AllEntities { + public: + using Base = AllEntities; + using Base::Base; + }; + + class AllPolynomials : public AllEntities { + public: + [[nodiscard]] size_t get_polynomial_size() const { return this->toy_q_tuple_set.size(); } + [[nodiscard]] AllValues get_row(const size_t row_idx) const + { + AllValues result; + for (auto [result_field, polynomial] : zip_view(result.get_all(), get_all())) { + result_field = polynomial[row_idx]; + } + return result; + } + }; + + using RowPolynomials = AllEntities; + + class PartiallyEvaluatedMultivariates : public AllEntities { + public: + PartiallyEvaluatedMultivariates() = default; + PartiallyEvaluatedMultivariates(const size_t circuit_size) + { + // Storage is only needed after the first partial evaluation, hence polynomials of size (n / 2) + for (auto& poly : get_all()) { + poly = Polynomial(circuit_size / 2); + } + } + }; + + /** + * @brief A container for univariates used during Protogalaxy folding and sumcheck. + * @details During folding and sumcheck, the prover evaluates the relations on these univariates. + */ + template using ProverUnivariates = AllEntities>; + + /** + * @brief A container for univariates produced during the hot loop in sumcheck. + */ + using ExtendedEdges = ProverUnivariates; + + class CommitmentLabels : public AllEntities { + private: + using Base = AllEntities; + + public: + CommitmentLabels() + : AllEntities() + { + Base::toy_first = "TOY_FIRST"; + Base::toy_q_tuple_set = "TOY_Q_TUPLE_SET"; + Base::toy_set_1_column_1 = "TOY_SET_1_COLUMN_1"; + Base::toy_set_1_column_2 = "TOY_SET_1_COLUMN_2"; + Base::toy_set_2_column_1 = "TOY_SET_2_COLUMN_1"; + Base::toy_set_2_column_2 = "TOY_SET_2_COLUMN_2"; + Base::toy_x = "TOY_X"; + Base::two_column_perm = "TWO_COLUMN_PERM"; + }; + }; + + class VerifierCommitments : public AllEntities { + private: + using Base = AllEntities; + + public: + VerifierCommitments(const std::shared_ptr& verification_key) + { + toy_first = verification_key->toy_first; + } + }; + + class Transcript : public BaseTranscript { + public: + uint32_t circuit_size; + + Commitment toy_q_tuple_set; + Commitment toy_set_1_column_1; + Commitment toy_set_1_column_2; + Commitment toy_set_2_column_1; + Commitment toy_set_2_column_2; + Commitment toy_x; + Commitment two_column_perm; + + std::vector> sumcheck_univariates; + std::array sumcheck_evaluations; + std::vector zm_cq_comms; + Commitment zm_cq_comm; + Commitment zm_pi_comm; + + Transcript() = default; + + Transcript(const std::vector& proof) + : BaseTranscript(proof) + {} + + void deserialize_full_transcript() + { + size_t num_bytes_read = 0; + circuit_size = deserialize_from_buffer(proof_data, num_bytes_read); + size_t log_n = numeric::get_msb(circuit_size); + + toy_q_tuple_set = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_set_1_column_1 = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_set_1_column_2 = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_set_2_column_1 = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_set_2_column_2 = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + toy_x = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + two_column_perm = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + + for (size_t i = 0; i < log_n; ++i) { + sumcheck_univariates.emplace_back( + deserialize_from_buffer>( + Transcript::proof_data, num_bytes_read)); + } + sumcheck_evaluations = + deserialize_from_buffer>(Transcript::proof_data, num_bytes_read); + for (size_t i = 0; i < log_n; ++i) { + zm_cq_comms.push_back(deserialize_from_buffer(proof_data, num_bytes_read)); + } + zm_cq_comm = deserialize_from_buffer(proof_data, num_bytes_read); + zm_pi_comm = deserialize_from_buffer(proof_data, num_bytes_read); + } + + void serialize_full_transcript() + { + size_t old_proof_length = proof_data.size(); + Transcript::proof_data.clear(); + size_t log_n = numeric::get_msb(circuit_size); + + serialize_to_buffer(circuit_size, Transcript::proof_data); + + serialize_to_buffer(toy_q_tuple_set, Transcript::proof_data); + serialize_to_buffer(toy_set_1_column_1, Transcript::proof_data); + serialize_to_buffer(toy_set_1_column_2, Transcript::proof_data); + serialize_to_buffer(toy_set_2_column_1, Transcript::proof_data); + serialize_to_buffer(toy_set_2_column_2, Transcript::proof_data); + serialize_to_buffer(toy_x, Transcript::proof_data); + serialize_to_buffer(two_column_perm, Transcript::proof_data); + + for (size_t i = 0; i < log_n; ++i) { + serialize_to_buffer(sumcheck_univariates[i], Transcript::proof_data); + } + serialize_to_buffer(sumcheck_evaluations, Transcript::proof_data); + for (size_t i = 0; i < log_n; ++i) { + serialize_to_buffer(zm_cq_comms[i], proof_data); + } + serialize_to_buffer(zm_cq_comm, proof_data); + serialize_to_buffer(zm_pi_comm, proof_data); + + // sanity check to make sure we generate the same length of proof as before. + ASSERT(proof_data.size() == old_proof_length); + } + }; +}; + +} // namespace flavor + +namespace sumcheck { + +DECLARE_SUMCHECK_RELATION_CLASS(two_column_perm, flavor::ToyFlavor); + +} +} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/flavor/toy_avm.hpp b/barretenberg/cpp/src/barretenberg/flavor/toy_avm.hpp deleted file mode 100644 index ba0c7c2b465..00000000000 --- a/barretenberg/cpp/src/barretenberg/flavor/toy_avm.hpp +++ /dev/null @@ -1,376 +0,0 @@ -#pragma once -#include "barretenberg/commitment_schemes/commitment_key.hpp" -#include "barretenberg/commitment_schemes/kzg/kzg.hpp" -#include "barretenberg/ecc/curves/bn254/bn254.hpp" -#include "barretenberg/flavor/flavor.hpp" -#include "barretenberg/flavor/flavor_macros.hpp" -#include "barretenberg/polynomials/univariate.hpp" -#include "barretenberg/relations/relation_parameters.hpp" -#include "barretenberg/relations/relation_types.hpp" -#include "barretenberg/relations/toy_avm/generic_permutation_relation.hpp" -#include "barretenberg/relations/toy_avm/relation_definer.hpp" -#include "relation_definitions_fwd.hpp" -#include -#include -#include -#include -#include -#include - -// NOLINTBEGIN(cppcoreguidelines-avoid-const-or-ref-data-members) - -namespace proof_system::honk { -namespace flavor { - -/** - * @brief This class provides an example flavor for using GenericPermutationRelations with various settings to make - * integrating those mechanisms into AVM easier - * - */ -class ToyAVM { - public: - using Curve = curve::BN254; - using FF = Curve::ScalarField; - using GroupElement = Curve::Element; - using Commitment = Curve::AffineElement; - using CommitmentHandle = Curve::AffineElement; - using PCS = pcs::kzg::KZG; - using Polynomial = barretenberg::Polynomial; - using PolynomialHandle = std::span; - using CommitmentKey = pcs::CommitmentKey; - using VerifierCommitmentKey = pcs::VerifierCommitmentKey; - - // The number of wires is 5. The set of tuples (permutation_set_column_1,permutation_set_column_2) should be - // equivalent to (permutation_set_column_3, permutation_set_column_4) and the self_permutation_column contains 2 - // subsets which are permutations of each other - static constexpr size_t NUM_WIRES = 5; - - // The number of multivariate polynomials on which a sumcheck prover sumcheck operates (including shifts). We often - // need containers of this size to hold related data, so we choose a name more agnostic than `NUM_POLYNOMIALS`. - // Note: this number does not include the individual sorted list polynomials. - static constexpr size_t NUM_ALL_ENTITIES = 12; - // The number of polynomials precomputed to describe a circuit and to aid a prover in constructing a satisfying - // assignment of witnesses. We again choose a neutral name. - static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 5; - // The total number of witness entities not including shifts. - static constexpr size_t NUM_WITNESS_ENTITIES = 7; - - // define the tuple of Relations that comprise the Sumcheck relation - using Relations = std::tuple>; - - static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); - - // BATCHED_RELATION_PARTIAL_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` - // random polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation - // length = 3 - static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1; - static constexpr size_t NUM_RELATIONS = std::tuple_size::value; - - // Instantiate the BarycentricData needed to extend each Relation Univariate - - // define the containers for storing the contributions from each relation in Sumcheck - using SumcheckTupleOfTuplesOfUnivariates = decltype(create_sumcheck_tuple_of_tuples_of_univariates()); - using TupleOfArraysOfValues = decltype(create_tuple_of_arrays_of_values()); - - private: - /** - * @brief A base class labelling precomputed entities and (ordered) subsets of interest. - * @details Used to build the proving key and verification key. - */ - template class PrecomputedEntities : public PrecomputedEntitiesBase { - public: - using DataType = DataType_; - DEFINE_FLAVOR_MEMBERS(DataType, - lagrange_first, // column 0 - enable_tuple_set_permutation, // column 1 - enable_single_column_permutation, // column 2 - enable_first_set_permutation, // column 3 - enable_second_set_permutation) // column 4 - - RefVector get_selectors() - { - return { lagrange_first, - enable_tuple_set_permutation, - enable_single_column_permutation, - enable_first_set_permutation, - enable_second_set_permutation }; - }; - RefVector get_sigma_polynomials() { return {}; }; - RefVector get_id_polynomials() { return {}; }; - RefVector get_table_polynomials() { return {}; }; - }; - - /** - * @brief Container for all witness polynomials used/constructed by the prover. - * @details Shifts are not included here since they do not occupy their own memory. - */ - - template class WitnessEntities { - public: - DEFINE_FLAVOR_MEMBERS(DataType, - permutation_set_column_1, // Column 0 - permutation_set_column_2, // Column 1 - permutation_set_column_3, // Column 2 - permutation_set_column_4, // Column 3 - self_permutation_column, // Column 4 - tuple_permutation_inverses, // Column 5 - single_permutation_inverses) // Column 6 - - RefVector get_wires() - { - return { permutation_set_column_1, - permutation_set_column_2, - permutation_set_column_3, - permutation_set_column_4, - self_permutation_column }; - }; - }; - - /** - * @brief A base class labelling all entities (for instance, all of the polynomials used by the prover during - * sumcheck) in this Honk variant along with particular subsets of interest - * @details Used to build containers for: the prover's polynomial during sumcheck; the sumcheck's folded - * polynomials; the univariates consturcted during during sumcheck; the evaluations produced by sumcheck. - * - * Symbolically we have: AllEntities = PrecomputedEntities + WitnessEntities + "ShiftedEntities". It could be - * implemented as such, but we have this now. - */ - - template class AllEntities { - public: - DEFINE_FLAVOR_MEMBERS(DataType, - lagrange_first, // Column 0 - enable_tuple_set_permutation, // Column 1 - enable_single_column_permutation, // Column 2 - enable_first_set_permutation, // Column 3 - enable_second_set_permutation, // Column 4 - permutation_set_column_1, // Column 5 - permutation_set_column_2, // Column 6 - permutation_set_column_3, // Column 7 - permutation_set_column_4, // Column 8 - self_permutation_column, // Column 9 - tuple_permutation_inverses, // Column 10 - single_permutation_inverses) // Column 11 - - RefVector get_wires() - { - return { - permutation_set_column_1, permutation_set_column_2, permutation_set_column_3, permutation_set_column_4 - }; - }; - RefVector get_unshifted() - { - return { lagrange_first, - enable_tuple_set_permutation, - enable_single_column_permutation, - enable_first_set_permutation, - enable_second_set_permutation, - permutation_set_column_1, - permutation_set_column_2, - permutation_set_column_3, - permutation_set_column_4, - self_permutation_column, - tuple_permutation_inverses, - single_permutation_inverses }; - }; - RefVector get_to_be_shifted() { return {}; }; - RefVector get_shifted() { return {}; }; - }; - - public: - /** - * @brief The proving key is responsible for storing the polynomials used by the prover. - * @note TODO(Cody): Maybe multiple inheritance is the right thing here. In that case, nothing should eve inherit - * from ProvingKey. - */ - class ProvingKey : public ProvingKey_, WitnessEntities> { - public: - // Expose constructors on the base class - using Base = ProvingKey_, WitnessEntities>; - using Base::Base; - - // The plookup wires that store plookup read data. - std::array get_table_column_wires() { return {}; }; - }; - - /** - * @brief The verification key is responsible for storing the the commitments to the precomputed (non-witnessk) - * polynomials used by the verifier. - * - * @note Note the discrepancy with what sort of data is stored here vs in the proving key. We may want to resolve - * that, and split out separate PrecomputedPolynomials/Commitments data for clarity but also for portability of our - * circuits. - */ - using VerificationKey = VerificationKey_>; - - /** - * @brief A field element for each entity of the flavor. These entities represent the prover polynomials evaluated - * at one point. - */ - class AllValues : public AllEntities { - public: - using Base = AllEntities; - using Base::Base; - }; - - /** - * @brief An owning container of polynomials. - * @warning When this was introduced it broke some of our design principles. - * - Execution trace builders don't handle "polynomials" because the interpretation of the execution trace - * columns as polynomials is a detail of the proving system, and trace builders are (sometimes in practice, - * always in principle) reusable for different proving protocols (e.g., Plonk and Honk). - * - Polynomial storage is handled by key classes. Polynomials aren't moved, but are accessed elsewhere by - * std::spans. - * - * We will consider revising this data model: TODO(https://github.com/AztecProtocol/barretenberg/issues/743) - */ - class AllPolynomials : public AllEntities { - public: - [[nodiscard]] size_t get_polynomial_size() const { return this->lagrange_first.size(); } - AllValues get_row(const size_t row_idx) const - { - AllValues result; - for (auto [result_field, polynomial] : zip_view(result.get_all(), this->get_all())) { - result_field = polynomial[row_idx]; - } - return result; - } - }; - /** - * @brief A container for polynomials handles; only stores spans. - */ - class ProverPolynomials : public AllEntities { - public: - [[nodiscard]] size_t get_polynomial_size() const { return enable_tuple_set_permutation.size(); } - [[nodiscard]] AllValues get_row(const size_t row_idx) const - { - AllValues result; - for (auto [result_field, polynomial] : zip_view(result.get_all(), get_all())) { - result_field = polynomial[row_idx]; - } - return result; - } - }; - - /** - * @brief A container for storing the partially evaluated multivariates produced by sumcheck. - */ - class PartiallyEvaluatedMultivariates : public AllEntities { - - public: - PartiallyEvaluatedMultivariates() = default; - PartiallyEvaluatedMultivariates(const size_t circuit_size) - { - // Storage is only needed after the first partial evaluation, hence polynomials of size (n / 2) - for (auto& poly : this->get_all()) { - poly = Polynomial(circuit_size / 2); - } - } - }; - /** - * @brief A container for univariates used during Protogalaxy folding and sumcheck. - * @details During folding and sumcheck, the prover evaluates the relations on these univariates. - */ - template using ProverUnivariates = AllEntities>; - - /** - * @brief A container for univariates produced during the hot loop in sumcheck. - */ - using ExtendedEdges = ProverUnivariates; - - /** - * @brief A container for the witness commitments. - */ - - using WitnessCommitments = WitnessEntities; - - /** - * @brief A container for commitment labels. - * @note It's debatable whether this should inherit from AllEntities. since most entries are not strictly needed. It - * has, however, been useful during debugging to have these labels available. - * - */ - class CommitmentLabels : public AllEntities { - private: - using Base = AllEntities; - - public: - CommitmentLabels() - : AllEntities() - { - Base::permutation_set_column_1 = "PERMUTATION_SET_COLUMN_1"; - Base::permutation_set_column_2 = "PERMUTATION_SET_COLUMN_2"; - Base::permutation_set_column_3 = "PERMUTATION_SET_COLUMN_3"; - Base::permutation_set_column_4 = "PERMUTATION_SET_COLUMN_4"; - Base::self_permutation_column = "SELF_PERMUTATION_COLUMN"; - Base::tuple_permutation_inverses = "TUPLE_PERMUTATION_INVERSES"; - Base::single_permutation_inverses = "SINGLE_PERMUTATION_INVERSES"; - // The ones beginning with "__" are only used for debugging - Base::lagrange_first = "__LAGRANGE_FIRST"; - Base::enable_tuple_set_permutation = "__ENABLE_SET_PERMUTATION"; - Base::enable_single_column_permutation = "__ENABLE_SINGLE_COLUMN_PERMUTATION"; - Base::enable_first_set_permutation = "__ENABLE_FIRST_SET_PERMUTATION"; - Base::enable_second_set_permutation = "__ENABLE_SECOND_SET_PERMUTATION"; - }; - }; - - class VerifierCommitments : public AllEntities { - - public: - VerifierCommitments(const std::shared_ptr& verification_key) - { - lagrange_first = verification_key->lagrange_first; - enable_tuple_set_permutation = verification_key->enable_tuple_set_permutation; - enable_single_column_permutation = verification_key->enable_single_column_permutation; - enable_first_set_permutation = verification_key->enable_first_set_permutation; - enable_second_set_permutation = verification_key->enable_second_set_permutation; - } - }; - - /** - * @brief Derived class that defines proof structure for ECCVM proofs, as well as supporting functions. - * - */ - class Transcript : public BaseTranscript { - public: - uint32_t circuit_size; - Commitment column_0_comm; - Commitment column_1_comm; - Commitment permutation_inverses_comm; - std::vector> sumcheck_univariates; - std::array sumcheck_evaluations; - - std::vector zm_cq_comms; - Commitment zm_cq_comm; - Commitment zm_pi_comm; - - Transcript() = default; - - Transcript(const std::vector& proof) - : BaseTranscript(proof) - {} - - void deserialize_full_transcript() - { - // TODO. Codepath is dead for now, because there is no composer - abort(); - // take current proof and put them into the struct - } - - void serialize_full_transcript() - { - // TODO. Codepath is dead for now, because there is no composer - abort(); - } - }; -}; - -// NOLINTEND(cppcoreguidelines-avoid-const-or-ref-data-members) - -} // namespace flavor -namespace sumcheck { - -DECLARE_IMPLEMENTATIONS_FOR_ALL_SETTINGS(GenericPermutationRelationImpl, flavor::ToyAVM) - -} // namespace sumcheck -} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/logderivative_library.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/logderivative_library.hpp index 4a86cf74075..b4dff8157ba 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/logderivative_library.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/logderivative_library.hpp @@ -6,7 +6,7 @@ namespace proof_system::honk::logderivative_library { /** * @brief Compute the inverse polynomial I(X) required for logderivative lookups * * - * @details + * details * Inverse may be defined in terms of its values on X_i = 0,1,...,n-1 as Z_perm[0] = 1 and for i = 1:n-1 * 1 1 * Inverse[i] = ∏ -------------------------- * ∏' -------------------------- diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp index 46cabaa1a0e..8470c2f7b5c 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp @@ -3,9 +3,12 @@ // AUTOGENERATED FILE #pragma once +#include "barretenberg/common/constexpr_utils.hpp" #include "barretenberg/common/throw_or_abort.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/honk/proof_system/logderivative_library.hpp" #include "barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp" +#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" #include "barretenberg/flavor/generated/AvmMini_flavor.hpp" #include "barretenberg/relations/generated/AvmMini/avm_mini.hpp" @@ -44,8 +47,8 @@ template struct AvmMiniFullRow { FF avmMini_mem_idx_c{}; FF avmMini_last{}; FF memTrace_m_rw_shift{}; - FF memTrace_m_val_shift{}; FF memTrace_m_addr_shift{}; + FF memTrace_m_val_shift{}; }; class AvmMiniCircuitBuilder { @@ -105,14 +108,15 @@ class AvmMiniCircuitBuilder { } polys.memTrace_m_rw_shift = Polynomial(polys.memTrace_m_rw.shifted()); - polys.memTrace_m_val_shift = Polynomial(polys.memTrace_m_val.shifted()); polys.memTrace_m_addr_shift = Polynomial(polys.memTrace_m_addr.shifted()); + polys.memTrace_m_val_shift = Polynomial(polys.memTrace_m_val.shifted()); return polys; } [[maybe_unused]] bool check_circuit() { + auto polys = compute_polynomials(); const size_t num_rows = polys.get_polynomial_size(); @@ -141,10 +145,10 @@ class AvmMiniCircuitBuilder { return true; }; - if (!evaluate_relation.template operator()>("avm_mini")) { + if (!evaluate_relation.template operator()>("mem_trace")) { return false; } - if (!evaluate_relation.template operator()>("mem_trace")) { + if (!evaluate_relation.template operator()>("avm_mini")) { return false; } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp new file mode 100644 index 00000000000..fade5a864e9 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp @@ -0,0 +1,163 @@ + + +// AUTOGENERATED FILE +#pragma once + +#include "barretenberg/common/constexpr_utils.hpp" +#include "barretenberg/common/throw_or_abort.hpp" +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/honk/proof_system/logderivative_library.hpp" +#include "barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp" +#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" + +#include "barretenberg/flavor/generated/Toy_flavor.hpp" +#include "barretenberg/relations/generated/Toy/toy_avm.hpp" +#include "barretenberg/relations/generated/Toy/two_column_perm.hpp" + +using namespace barretenberg; + +namespace proof_system { + +template struct ToyFullRow { + FF toy_first{}; + FF toy_q_tuple_set{}; + FF toy_set_1_column_1{}; + FF toy_set_1_column_2{}; + FF toy_set_2_column_1{}; + FF toy_set_2_column_2{}; + FF toy_x{}; + FF two_column_perm{}; + FF toy_x_shift{}; +}; + +class ToyCircuitBuilder { + public: + using Flavor = proof_system::honk::flavor::ToyFlavor; + using FF = Flavor::FF; + using Row = ToyFullRow; + + // TODO: template + using Polynomial = Flavor::Polynomial; + using AllPolynomials = Flavor::AllPolynomials; + + static constexpr size_t num_fixed_columns = 9; + static constexpr size_t num_polys = 8; + std::vector rows; + + void set_trace(std::vector&& trace) { rows = std::move(trace); } + + AllPolynomials compute_polynomials() + { + const auto num_rows = get_circuit_subgroup_size(); + AllPolynomials polys; + + // Allocate mem for each column + for (auto& poly : polys.get_all()) { + poly = Polynomial(num_rows); + } + + for (size_t i = 0; i < rows.size(); i++) { + polys.toy_first[i] = rows[i].toy_first; + polys.toy_q_tuple_set[i] = rows[i].toy_q_tuple_set; + polys.toy_set_1_column_1[i] = rows[i].toy_set_1_column_1; + polys.toy_set_1_column_2[i] = rows[i].toy_set_1_column_2; + polys.toy_set_2_column_1[i] = rows[i].toy_set_2_column_1; + polys.toy_set_2_column_2[i] = rows[i].toy_set_2_column_2; + polys.toy_x[i] = rows[i].toy_x; + polys.two_column_perm[i] = rows[i].two_column_perm; + } + + polys.toy_x_shift = Polynomial(polys.toy_x.shifted()); + + return polys; + } + + [[maybe_unused]] bool check_circuit() + { + + const FF gamma = FF::random_element(); + const FF beta = FF::random_element(); + proof_system::RelationParameters params{ + .eta = 0, + .beta = beta, + .gamma = gamma, + .public_input_delta = 0, + .lookup_grand_product_delta = 0, + .beta_sqr = 0, + .beta_cube = 0, + .eccvm_set_permutation_delta = 0, + }; + + auto polys = compute_polynomials(); + const size_t num_rows = polys.get_polynomial_size(); + + const auto evaluate_relation = [&](const std::string& relation_name) { + typename Relation::SumcheckArrayOfValuesOverSubrelations result; + for (auto& r : result) { + r = 0; + } + constexpr size_t NUM_SUBRELATIONS = result.size(); + + for (size_t i = 0; i < num_rows; ++i) { + Relation::accumulate(result, polys.get_row(i), {}, 1); + + bool x = true; + for (size_t j = 0; j < NUM_SUBRELATIONS; ++j) { + if (result[j] != 0) { + throw_or_abort( + format("Relation ", relation_name, ", subrelation index ", j, " failed at row ", i)); + x = false; + } + } + if (!x) { + return false; + } + } + return true; + }; + + const auto evaluate_permutation = [&](const std::string& permutation_name) { + // Check the tuple permutation relation + proof_system::honk::logderivative_library::compute_logderivative_inverse( + polys, params, num_rows); + + typename PermutationSettings::SumcheckArrayOfValuesOverSubrelations permutation_result; + + for (auto& r : permutation_result) { + r = 0; + } + for (size_t i = 0; i < num_rows; ++i) { + PermutationSettings::accumulate(permutation_result, polys.get_row(i), params, 1); + } + for (auto r : permutation_result) { + if (r != 0) { + info("Tuple", permutation_name, "failed."); + return false; + } + } + return true; + }; + + if (!evaluate_relation.template operator()>("toy_avm")) { + return false; + } + + if (!evaluate_permutation.template operator()>( + "two_column_perm")) { + return false; + } + + return true; + } + + [[nodiscard]] size_t get_num_gates() const { return rows.size(); } + + [[nodiscard]] size_t get_circuit_subgroup_size() const + { + const size_t num_rows = get_num_gates(); + const auto num_rows_log2 = static_cast(numeric::get_msb64(num_rows)); + size_t num_rows_pow2 = 1UL << (num_rows_log2 + (1UL << num_rows_log2 == num_rows ? 0 : 1)); + return num_rows_pow2; + } +}; +} // namespace proof_system diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.hpp deleted file mode 100644 index 659187b4131..00000000000 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.hpp +++ /dev/null @@ -1,163 +0,0 @@ -/** - * @file avm_template_circuit_builder.hpp - * @author Rumata888 - * @brief A circuit builder for the AVM toy version used to showcase permutation and lookup mechanisms for PIL - * - */ -#pragma once - -#include "barretenberg/common/constexpr_utils.hpp" -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/flavor/toy_avm.hpp" -#include "barretenberg/honk/proof_system/logderivative_library.hpp" -#include "barretenberg/relations/relation_parameters.hpp" -#include "barretenberg/relations/toy_avm/generic_permutation_relation.hpp" - -namespace proof_system { - -/** - * @brief Circuit builder for the ToyAVM that is used to explain generic permutation settings - * - * @tparam Flavor - */ -template class ToyAVMCircuitBuilder { - public: - using FF = typename Flavor::FF; - using Polynomial = typename Flavor::Polynomial; - - static constexpr size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - static constexpr size_t NUM_WIRES = Flavor::NUM_WIRES; - - using AllPolynomials = typename Flavor::AllPolynomials; - size_t num_gates = 0; - std::array, NUM_WIRES> wires; - ToyAVMCircuitBuilder() = default; - - void add_row(const std::array row) - { - for (size_t i = 0; i < NUM_WIRES; i++) { - wires[i].emplace_back(row[i]); - } - num_gates = wires[0].size(); - } - - /** - * @brief Compute the AVM Template flavor polynomial data required to generate a proof - * - * @return AllPolynomials - */ - AllPolynomials compute_polynomials() - { - - const auto num_gates_log2 = static_cast(numeric::get_msb64(num_gates)); - size_t num_gates_pow2 = 1UL << (num_gates_log2 + (1UL << num_gates_log2 == num_gates ? 0 : 1)); - - AllPolynomials polys; - for (auto& poly : polys.get_all()) { - poly = Polynomial(num_gates_pow2); - } - - polys.lagrange_first[0] = 1; - - for (size_t i = 0; i < num_gates; ++i) { - // Fill out the witness polynomials - polys.permutation_set_column_1[i] = wires[0][i]; - polys.permutation_set_column_2[i] = wires[1][i]; - polys.permutation_set_column_3[i] = wires[2][i]; - polys.permutation_set_column_4[i] = wires[3][i]; - polys.self_permutation_column[i] = wires[4][i]; - // By default the permutation is over all rows where we place data - polys.enable_tuple_set_permutation[i] = 1; - // The same column permutation alternates between even and odd values - polys.enable_single_column_permutation[i] = 1; - polys.enable_first_set_permutation[i] = i & 1; - polys.enable_second_set_permutation[i] = 1 - (i & 1); - } - return polys; - } - - /** - * @brief Check that the circuit is correct (proof should work) - * - */ - bool check_circuit() - { - // using FirstPermutationRelation = typename std::tuple_element_t<0, Flavor::Relations>; - // For now only gamma and beta are used - const FF gamma = FF::random_element(); - const FF beta = FF::random_element(); - proof_system::RelationParameters params{ - .eta = 0, - .beta = beta, - .gamma = gamma, - .public_input_delta = 0, - .lookup_grand_product_delta = 0, - .beta_sqr = 0, - .beta_cube = 0, - .eccvm_set_permutation_delta = 0, - }; - - // Compute polynomial values - auto polynomials = compute_polynomials(); - const size_t num_rows = polynomials.get_polynomial_size(); - - // Check the tuple permutation relation - proof_system::honk::logderivative_library::compute_logderivative_inverse< - Flavor, - honk::sumcheck::GenericPermutationRelation>( - polynomials, params, num_rows); - - using PermutationRelation = - honk::sumcheck::GenericPermutationRelation; - typename honk::sumcheck::GenericPermutationRelation::SumcheckArrayOfValuesOverSubrelations - permutation_result; - for (auto& r : permutation_result) { - r = 0; - } - for (size_t i = 0; i < num_rows; ++i) { - PermutationRelation::accumulate(permutation_result, polynomials.get_row(i), params, 1); - } - for (auto r : permutation_result) { - if (r != 0) { - info("Tuple GenericPermutationRelation failed."); - return false; - } - } - // Check the single permutation relation - proof_system::honk::logderivative_library::compute_logderivative_inverse< - Flavor, - honk::sumcheck::GenericPermutationRelation>( - polynomials, params, num_rows); - - using SameWirePermutationRelation = - honk::sumcheck::GenericPermutationRelation; - typename honk::sumcheck::GenericPermutationRelation::SumcheckArrayOfValuesOverSubrelations - second_permutation_result; - for (auto& r : second_permutation_result) { - r = 0; - } - for (size_t i = 0; i < num_rows; ++i) { - SameWirePermutationRelation::accumulate(second_permutation_result, polynomials.get_row(i), params, 1); - } - for (auto r : second_permutation_result) { - if (r != 0) { - info("Same wire GenericPermutationRelation failed."); - return false; - } - } - return true; - } - - [[nodiscard]] size_t get_num_gates() const { return num_gates; } - - [[nodiscard]] size_t get_circuit_subgroup_size(const size_t num_rows) const - { - - const auto num_rows_log2 = static_cast(numeric::get_msb64(num_rows)); - size_t num_rows_pow2 = 1UL << (num_rows_log2 + (1UL << num_rows_log2 == num_rows ? 0 : 1)); - return num_rows_pow2; - } -}; -} // namespace proof_system diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.test.cpp index 62b2e4d83c3..09750e93df3 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.test.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.test.cpp @@ -1,5 +1,8 @@ -#include "toy_avm_circuit_builder.hpp" +#include "../generated/Toy_circuit_builder.hpp" #include "barretenberg/crypto/generators/generator_data.hpp" +#include "barretenberg/flavor/generated/Toy_flavor.hpp" +#include "barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp" + #include using namespace barretenberg; @@ -17,54 +20,54 @@ namespace toy_avm_circuit_builder_tests { TEST(ToyAVMCircuitBuilder, BaseCase) { - using FF = proof_system::honk::flavor::ToyAVM::FF; + using FF = proof_system::honk::flavor::ToyFlavor::FF; + using Builder = proof_system::ToyCircuitBuilder; + using Row = Builder::Row; + Builder circuit_builder; + const size_t circuit_size = 16; - proof_system::ToyAVMCircuitBuilder circuit_builder; + std::vector rows; // Sample 2*16 random elements for the tuple permutation example - std::vector column_0; - std::vector column_1; for (size_t i = 0; i < circuit_size; i++) { - column_0.emplace_back(FF::random_element()); - column_1.emplace_back(FF::random_element()); - } - - // Sample 8 random elements for the single column permutation - std::vector column_2; - for (size_t i = 0; i < circuit_size / 2; i++) { - column_2.emplace_back(FF::random_element()); + Row row{ + .toy_q_tuple_set = 1, + .toy_set_1_column_1 = FF::random_element(), + .toy_set_1_column_2 = FF::random_element(), + }; + rows.push_back(row); } for (size_t i = 0; i < circuit_size; i++) { // We put the same tuple of values in the first 2 wires and in the next 2 to at different rows // We also put the same value in the self_permutation column in 2 consecutive rows - circuit_builder.add_row({ column_0[i], column_1[i], column_0[15 - i], column_1[15 - i], column_2[i / 2] }); + Row& front_row = rows[i]; + Row& back_row = rows[circuit_size - (i + 1)]; + + back_row.toy_set_2_column_1 = front_row.toy_set_1_column_1; + back_row.toy_set_2_column_2 = front_row.toy_set_1_column_2; } // Test that permutations with correct values work + circuit_builder.set_trace(std::move(rows)); bool result = circuit_builder.check_circuit(); EXPECT_EQ(result, true); // Store value temporarily - FF tmp = circuit_builder.wires[0][5]; + FF tmp = circuit_builder.rows[5].toy_set_1_column_1; // Replace one of the values in a tuple permutation column with a random one, breaking the permutation - circuit_builder.wires[0][5] = FF::random_element(); + circuit_builder.rows[5].toy_set_1_column_1 = FF::random_element(); // Check that it fails result = circuit_builder.check_circuit(); EXPECT_EQ(result, false); // Restore value - circuit_builder.wires[0][5] = tmp; + circuit_builder.rows[5].toy_set_1_column_1 = tmp; // Check circuit passes result = circuit_builder.check_circuit(); EXPECT_EQ(result, true); - - // Break single-column permutation - circuit_builder.wires[circuit_builder.wires.size() - 1][0] = FF::random_element(); - result = circuit_builder.check_circuit(); - EXPECT_EQ(result, false); } } // namespace toy_avm_circuit_builder_tests \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp index 5596bbc94cf..bb4a3242ae0 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp @@ -7,21 +7,21 @@ namespace proof_system::AvmMini_vm { template struct Avm_miniRow { - FF avmMini_mem_op_b{}; - FF avmMini_ib{}; - FF avmMini_ic{}; - FF avmMini_sel_op_sub{}; - FF avmMini_mem_op_c{}; - FF avmMini_op_err{}; - FF avmMini_ia{}; - FF avmMini_inv{}; FF avmMini_sel_op_div{}; - FF avmMini_mem_op_a{}; + FF avmMini_ia{}; FF avmMini_rwa{}; + FF avmMini_sel_op_sub{}; + FF avmMini_rwb{}; + FF avmMini_ic{}; + FF avmMini_inv{}; + FF avmMini_sel_op_add{}; + FF avmMini_op_err{}; FF avmMini_sel_op_mul{}; FF avmMini_rwc{}; - FF avmMini_sel_op_add{}; - FF avmMini_rwb{}; + FF avmMini_ib{}; + FF avmMini_mem_op_b{}; + FF avmMini_mem_op_a{}; + FF avmMini_mem_op_c{}; }; template class avm_miniImpl { @@ -29,7 +29,7 @@ template class avm_miniImpl { using FF = FF_; static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 3, }; template @@ -41,7 +41,7 @@ template class avm_miniImpl { // Contribution 0 { - DECLARE_VIEWS(0); + AvmMini_DECLARE_VIEWS(0); auto tmp = (avmMini_sel_op_add * (-avmMini_sel_op_add + FF(1))); tmp *= scaling_factor; @@ -49,7 +49,7 @@ template class avm_miniImpl { } // Contribution 1 { - DECLARE_VIEWS(1); + AvmMini_DECLARE_VIEWS(1); auto tmp = (avmMini_sel_op_sub * (-avmMini_sel_op_sub + FF(1))); tmp *= scaling_factor; @@ -57,7 +57,7 @@ template class avm_miniImpl { } // Contribution 2 { - DECLARE_VIEWS(2); + AvmMini_DECLARE_VIEWS(2); auto tmp = (avmMini_sel_op_mul * (-avmMini_sel_op_mul + FF(1))); tmp *= scaling_factor; @@ -65,7 +65,7 @@ template class avm_miniImpl { } // Contribution 3 { - DECLARE_VIEWS(3); + AvmMini_DECLARE_VIEWS(3); auto tmp = (avmMini_sel_op_div * (-avmMini_sel_op_div + FF(1))); tmp *= scaling_factor; @@ -73,7 +73,7 @@ template class avm_miniImpl { } // Contribution 4 { - DECLARE_VIEWS(4); + AvmMini_DECLARE_VIEWS(4); auto tmp = (avmMini_op_err * (-avmMini_op_err + FF(1))); tmp *= scaling_factor; @@ -81,7 +81,7 @@ template class avm_miniImpl { } // Contribution 5 { - DECLARE_VIEWS(5); + AvmMini_DECLARE_VIEWS(5); auto tmp = (avmMini_mem_op_a * (-avmMini_mem_op_a + FF(1))); tmp *= scaling_factor; @@ -89,7 +89,7 @@ template class avm_miniImpl { } // Contribution 6 { - DECLARE_VIEWS(6); + AvmMini_DECLARE_VIEWS(6); auto tmp = (avmMini_mem_op_b * (-avmMini_mem_op_b + FF(1))); tmp *= scaling_factor; @@ -97,7 +97,7 @@ template class avm_miniImpl { } // Contribution 7 { - DECLARE_VIEWS(7); + AvmMini_DECLARE_VIEWS(7); auto tmp = (avmMini_mem_op_c * (-avmMini_mem_op_c + FF(1))); tmp *= scaling_factor; @@ -105,7 +105,7 @@ template class avm_miniImpl { } // Contribution 8 { - DECLARE_VIEWS(8); + AvmMini_DECLARE_VIEWS(8); auto tmp = (avmMini_rwa * (-avmMini_rwa + FF(1))); tmp *= scaling_factor; @@ -113,7 +113,7 @@ template class avm_miniImpl { } // Contribution 9 { - DECLARE_VIEWS(9); + AvmMini_DECLARE_VIEWS(9); auto tmp = (avmMini_rwb * (-avmMini_rwb + FF(1))); tmp *= scaling_factor; @@ -121,7 +121,7 @@ template class avm_miniImpl { } // Contribution 10 { - DECLARE_VIEWS(10); + AvmMini_DECLARE_VIEWS(10); auto tmp = (avmMini_rwc * (-avmMini_rwc + FF(1))); tmp *= scaling_factor; @@ -129,7 +129,7 @@ template class avm_miniImpl { } // Contribution 11 { - DECLARE_VIEWS(11); + AvmMini_DECLARE_VIEWS(11); auto tmp = (avmMini_sel_op_add * ((avmMini_ia + avmMini_ib) - avmMini_ic)); tmp *= scaling_factor; @@ -137,7 +137,7 @@ template class avm_miniImpl { } // Contribution 12 { - DECLARE_VIEWS(12); + AvmMini_DECLARE_VIEWS(12); auto tmp = (avmMini_sel_op_sub * ((avmMini_ia - avmMini_ib) - avmMini_ic)); tmp *= scaling_factor; @@ -145,7 +145,7 @@ template class avm_miniImpl { } // Contribution 13 { - DECLARE_VIEWS(13); + AvmMini_DECLARE_VIEWS(13); auto tmp = (avmMini_sel_op_mul * ((avmMini_ia * avmMini_ib) - avmMini_ic)); tmp *= scaling_factor; @@ -153,7 +153,7 @@ template class avm_miniImpl { } // Contribution 14 { - DECLARE_VIEWS(14); + AvmMini_DECLARE_VIEWS(14); auto tmp = ((avmMini_sel_op_div * (-avmMini_op_err + FF(1))) * ((avmMini_ic * avmMini_ib) - avmMini_ia)); tmp *= scaling_factor; @@ -161,7 +161,7 @@ template class avm_miniImpl { } // Contribution 15 { - DECLARE_VIEWS(15); + AvmMini_DECLARE_VIEWS(15); auto tmp = (avmMini_sel_op_div * (((avmMini_ib * avmMini_inv) - FF(1)) + avmMini_op_err)); tmp *= scaling_factor; @@ -169,7 +169,7 @@ template class avm_miniImpl { } // Contribution 16 { - DECLARE_VIEWS(16); + AvmMini_DECLARE_VIEWS(16); auto tmp = ((avmMini_sel_op_div * avmMini_op_err) * (-avmMini_inv + FF(1))); tmp *= scaling_factor; @@ -177,7 +177,7 @@ template class avm_miniImpl { } // Contribution 17 { - DECLARE_VIEWS(17); + AvmMini_DECLARE_VIEWS(17); auto tmp = (avmMini_op_err * (avmMini_sel_op_div - FF(1))); tmp *= scaling_factor; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp index b5d9a61651e..e2abc409ea4 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp @@ -1,5 +1,5 @@ -#define DECLARE_VIEWS(index) \ +#define AvmMini_DECLARE_VIEWS(index) \ using Accumulator = typename std::tuple_element::type; \ using View = typename Accumulator::View; \ [[maybe_unused]] auto avmMini_clk = View(new_term.avmMini_clk); \ @@ -30,5 +30,5 @@ [[maybe_unused]] auto avmMini_mem_idx_c = View(new_term.avmMini_mem_idx_c); \ [[maybe_unused]] auto avmMini_last = View(new_term.avmMini_last); \ [[maybe_unused]] auto memTrace_m_rw_shift = View(new_term.memTrace_m_rw_shift); \ - [[maybe_unused]] auto memTrace_m_val_shift = View(new_term.memTrace_m_val_shift); \ - [[maybe_unused]] auto memTrace_m_addr_shift = View(new_term.memTrace_m_addr_shift); + [[maybe_unused]] auto memTrace_m_addr_shift = View(new_term.memTrace_m_addr_shift); \ + [[maybe_unused]] auto memTrace_m_val_shift = View(new_term.memTrace_m_val_shift); diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp index dde059dedc6..7bfb1b223cd 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp @@ -8,14 +8,14 @@ namespace proof_system::AvmMini_vm { template struct Mem_traceRow { FF memTrace_m_rw_shift{}; - FF memTrace_m_lastAccess{}; + FF memTrace_m_addr_shift{}; + FF memTrace_m_val{}; FF memTrace_m_addr{}; - FF memTrace_m_val_shift{}; FF memTrace_m_rw{}; FF avmMini_first{}; - FF memTrace_m_addr_shift{}; + FF memTrace_m_lastAccess{}; FF avmMini_last{}; - FF memTrace_m_val{}; + FF memTrace_m_val_shift{}; }; template class mem_traceImpl { @@ -38,7 +38,7 @@ template class mem_traceImpl { // Contribution 0 { - DECLARE_VIEWS(0); + AvmMini_DECLARE_VIEWS(0); auto tmp = (memTrace_m_lastAccess * (-memTrace_m_lastAccess + FF(1))); tmp *= scaling_factor; @@ -46,7 +46,7 @@ template class mem_traceImpl { } // Contribution 1 { - DECLARE_VIEWS(1); + AvmMini_DECLARE_VIEWS(1); auto tmp = (memTrace_m_rw * (-memTrace_m_rw + FF(1))); tmp *= scaling_factor; @@ -54,7 +54,7 @@ template class mem_traceImpl { } // Contribution 2 { - DECLARE_VIEWS(2); + AvmMini_DECLARE_VIEWS(2); auto tmp = (((-avmMini_first + FF(1)) * (-memTrace_m_lastAccess + FF(1))) * (memTrace_m_addr_shift - memTrace_m_addr)); @@ -63,7 +63,7 @@ template class mem_traceImpl { } // Contribution 3 { - DECLARE_VIEWS(3); + AvmMini_DECLARE_VIEWS(3); auto tmp = (((((-avmMini_first + FF(1)) * (-avmMini_last + FF(1))) * (-memTrace_m_lastAccess + FF(1))) * (-memTrace_m_rw_shift + FF(1))) * diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/Toy/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/declare_views.hpp new file mode 100644 index 00000000000..18b7ec1d45e --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/declare_views.hpp @@ -0,0 +1,13 @@ + +#define Toy_DECLARE_VIEWS(index) \ + using Accumulator = typename std::tuple_element::type; \ + using View = typename Accumulator::View; \ + [[maybe_unused]] auto toy_first = View(new_term.toy_first); \ + [[maybe_unused]] auto toy_q_tuple_set = View(new_term.toy_q_tuple_set); \ + [[maybe_unused]] auto toy_set_1_column_1 = View(new_term.toy_set_1_column_1); \ + [[maybe_unused]] auto toy_set_1_column_2 = View(new_term.toy_set_1_column_2); \ + [[maybe_unused]] auto toy_set_2_column_1 = View(new_term.toy_set_2_column_1); \ + [[maybe_unused]] auto toy_set_2_column_2 = View(new_term.toy_set_2_column_2); \ + [[maybe_unused]] auto toy_x = View(new_term.toy_x); \ + [[maybe_unused]] auto two_column_perm = View(new_term.two_column_perm); \ + [[maybe_unused]] auto toy_x_shift = View(new_term.toy_x_shift); diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/Toy/toy_avm.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/toy_avm.hpp new file mode 100644 index 00000000000..40eb15cb6b3 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/toy_avm.hpp @@ -0,0 +1,42 @@ + +#pragma once +#include "../../relation_parameters.hpp" +#include "../../relation_types.hpp" +#include "./declare_views.hpp" + +namespace proof_system::Toy_vm { + +template struct Toy_avmRow { + FF toy_x_shift{}; + FF toy_x{}; +}; + +template class toy_avmImpl { + public: + using FF = FF_; + + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 2, + }; + + template + void static accumulate(ContainerOverSubrelations& evals, + const AllEntities& new_term, + [[maybe_unused]] const RelationParameters&, + [[maybe_unused]] const FF& scaling_factor) + { + + // Contribution 0 + { + Toy_DECLARE_VIEWS(0); + + auto tmp = (toy_x_shift - toy_x); + tmp *= scaling_factor; + std::get<0>(evals) += tmp; + } + } +}; + +template using toy_avm = Relation>; + +} // namespace proof_system::Toy_vm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/Toy/two_column_perm.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/two_column_perm.hpp new file mode 100644 index 00000000000..29d31482d9c --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/two_column_perm.hpp @@ -0,0 +1,94 @@ + + +#pragma once + +#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" + +#include +#include + +namespace proof_system::honk::sumcheck { + +class two_column_perm_permutation_settings { + public: + // This constant defines how many columns are bundled together to form each set. + constexpr static size_t COLUMNS_PER_SET = 2; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial at this index. Otherwise the + * value needs to be set to zero. + * + * @details If this is true then permutation takes place in this row + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.toy_q_tuple_set == 1); + } + + /** + * @brief Get all the entities for the permutation when we don't need to update them + * + * @details The entities are returned as a tuple of references in the following order: + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of + * the inverse polynomial + * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum + * subrelation + * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum + * subrelation + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) + * + * @return All the entities needed for the permutation + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.two_column_perm, + in.toy_q_tuple_set, + in.toy_q_tuple_set, + in.toy_q_tuple_set, + in.toy_set_1_column_1, + in.toy_set_1_column_2, + in.toy_set_2_column_1, + in.toy_set_2_column_2); + } + + /** + * @brief Get all the entities for the permutation when need to update them + * + * @details The entities are returned as a tuple of references in the following order: + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of + * the inverse polynomial + * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum + * subrelation + * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum + * subrelation + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) + * + * @return All the entities needed for the permutation + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.two_column_perm, + in.toy_q_tuple_set, + in.toy_q_tuple_set, + in.toy_q_tuple_set, + in.toy_set_1_column_1, + in.toy_set_1_column_2, + in.toy_set_2_column_1, + in.toy_set_2_column_2); + } +}; + +template +using two_column_perm_relation = GenericPermutationRelation; +template using two_column_perm = GenericPermutation; + +} // namespace proof_system::honk::sumcheck diff --git a/barretenberg/cpp/src/barretenberg/relations/toy_avm/generic_permutation_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/generic_permutation/generic_permutation_relation.hpp similarity index 95% rename from barretenberg/cpp/src/barretenberg/relations/toy_avm/generic_permutation_relation.hpp rename to barretenberg/cpp/src/barretenberg/relations/generic_permutation/generic_permutation_relation.hpp index d4246a423f5..b0b917885f4 100644 --- a/barretenberg/cpp/src/barretenberg/relations/toy_avm/generic_permutation_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generic_permutation/generic_permutation_relation.hpp @@ -10,6 +10,7 @@ #include #include "barretenberg/common/constexpr_utils.hpp" +#include "barretenberg/honk/proof_system/logderivative_library.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/relations/relation_types.hpp" @@ -201,10 +202,17 @@ template class GenericPermutationRelationImpl static void accumulate(ContainerOverSubrelations& accumulator, const AllEntities& in, const Parameters& params, - const FF& scaling_factor); + const FF& scaling_factor) + { + logderivative_library::accumulate_logderivative_permutation_subrelation_contributions< + FF, + GenericPermutationRelationImpl>(accumulator, in, params, scaling_factor); + } }; template using GenericPermutationRelation = Relation>; +template using GenericPermutation = GenericPermutationRelationImpl; + } // namespace proof_system::honk::sumcheck diff --git a/barretenberg/cpp/src/barretenberg/relations/toy_avm/generic_permutation_relation.cpp b/barretenberg/cpp/src/barretenberg/relations/toy_avm/generic_permutation_relation.cpp deleted file mode 100644 index 1822c388c4e..00000000000 --- a/barretenberg/cpp/src/barretenberg/relations/toy_avm/generic_permutation_relation.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "generic_permutation_relation.hpp" -#include "barretenberg/flavor/relation_definitions_fwd.hpp" -#include "barretenberg/flavor/toy_avm.hpp" -#include "barretenberg/honk/proof_system/logderivative_library.hpp" -#include "relation_definer.hpp" - -namespace proof_system::honk::sumcheck { - -/** - * @brief Expression for generic log-derivative-based set permutation. - * @param accumulator transformed to `evals + C(in(X)...)*scaling_factor` - * @param in an std::array containing the fully extended Accumulator edges. - * @param relation_params contains beta, gamma, and public_input_delta, .... - * @param scaling_factor optional term to scale the evaluation before adding to evals. - */ -template -template -void GenericPermutationRelationImpl::accumulate(ContainerOverSubrelations& accumulator, - const AllEntities& in, - const Parameters& params, - const FF& scaling_factor) -{ - logderivative_library::accumulate_logderivative_permutation_subrelation_contributions< - FF, - GenericPermutationRelationImpl>(accumulator, in, params, scaling_factor); -} - -// template class GenericPermutationRelationImpl; -// template -// using GenericPermutationRelationExampleSettingsImpl = GenericPermutationRelationImpl; DEFINE_SUMCHECK_RELATION_CLASS(GenericPermutationRelationExampleSettingsImpl, flavor::AVMTemplate); - -DEFINE_IMPLEMENTATIONS_FOR_ALL_SETTINGS(GenericPermutationRelationImpl, flavor::ToyAVM); -} // namespace proof_system::honk::sumcheck diff --git a/barretenberg/cpp/src/barretenberg/relations/toy_avm/relation_definer.hpp b/barretenberg/cpp/src/barretenberg/relations/toy_avm/relation_definer.hpp deleted file mode 100644 index 4771c1260b7..00000000000 --- a/barretenberg/cpp/src/barretenberg/relations/toy_avm/relation_definer.hpp +++ /dev/null @@ -1,213 +0,0 @@ -/** - * @file relation_definer.hpp - * @author Rumata888 - * @brief This file contains settings for the General Permutation Relation implementations and (in the future) Lookup - * implementations - * - */ -#pragma once -#include -#include -namespace proof_system::honk::sumcheck { - -/** - * @brief This class contains an example of how to set PermutationSettings classes used by the - * GenericPermutationRelationImpl class to specify a concrete permutation - * - * @details To create your own permutation: - * 1) Create a copy of this class and rename it - * 2) Update all the values with the ones needed for your permutation - * 3) Update "DECLARE_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to include the new - * settings - * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` - * using Relations = std::tuple>;)` - * - */ -class ExampleTuplePermutationSettings { - public: - // This constant defines how many columns are bundled together to form each set. For example, in this case we are - // bundling tuples of (permutation_set_column_1, permutation_set_column_2) to be a permutation of - // (permutation_set_column_3,permutation_set_column_4). As the tuple has 2 elements, set the value to 2 - constexpr static size_t COLUMNS_PER_SET = 2; - - /** - * @brief If this method returns true on a row of values, then the inverse polynomial at this index. Otherwise the - * value needs to be set to zero. - * - * @details If this is true then permutation takes place in this row - * - */ - template static inline bool inverse_polynomial_is_computed_at_row(const AllEntities& in) - { - return (in.enable_tuple_set_permutation == 1); - } - - /** - * @brief Get all the entities for the permutation when we don't need to update them - * - * @details The entities are returned as a tuple of references in the following order: - * - The entity/polynomial used to store the product of the inverse values - * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of - * the inverse polynomial - * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum - * subrelation - * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum - * subrelation - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) - * - * @return All the entities needed for the permutation - */ - template static inline auto get_const_entities(const AllEntities& in) - { - - return std::forward_as_tuple( - in.tuple_permutation_inverses, /* The polynomial containing the inverse product*/ - in.enable_tuple_set_permutation, /* The polynomial enabling the product check subrelation */ - in.enable_tuple_set_permutation, /* Enables adding first set to the sum */ - in.enable_tuple_set_permutation, /* Enables adding second set to the sum */ - in.permutation_set_column_3, /* The first entry in the first set tuple */ - in.permutation_set_column_4, /* The second entry in the first set tuple */ - in.permutation_set_column_1, /* The first entry in the second set tuple */ - in.permutation_set_column_2); /* The second entry in the second set tuple */ - } - - /** - * @brief Get all the entities for the permutation when need to update them - * - * @details The entities are returned as a tuple of references in the following order: - * - The entity/polynomial used to store the product of the inverse values - * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of - * the inverse polynomial - * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum - * subrelation - * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum - * subrelation - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) - * - * @return All the entities needed for the permutation - */ - template static inline auto get_nonconst_entities(AllEntities& in) - { - return std::forward_as_tuple( - in.tuple_permutation_inverses, /* The polynomial containing the inverse product*/ - in.enable_tuple_set_permutation, /* The polynomial enabling the product check subrelation */ - in.enable_tuple_set_permutation, /* Enables adding first set to the sum */ - in.enable_tuple_set_permutation, /* Enables adding second set to the sum */ - in.permutation_set_column_3, /* The first entry in the first set tuple */ - in.permutation_set_column_4, /* The second entry in the first set tuple */ - in.permutation_set_column_1, /* The first entry in the second set tuple */ - in.permutation_set_column_2); /* The second entry in the second set tuple */ - } -}; - -/** - * @brief This class contains an example of how to set PermutationSettings classes used by the - * GenericPermutationRelationImpl class to specify a concrete permutation - * - * @details To create your own permutation: - * 1) Create a copy of this class and rename it - * 2) Update all the values with the ones needed for your permutation - * 3) Update "DECLARE_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to include the new - * settings - * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` - * using Relations = std::tuple>;)` - * - */ -class ExampleSameWirePermutationSettings { - public: - // This constant defines how many columns are bundled together to form each set. For example, in this case we are - // permuting entries in the column with itself (self_permutation_column), so we choose just one - constexpr static size_t COLUMNS_PER_SET = 1; - - /** - * @brief If this method returns true on a row of values, then the inverse polynomial at this index. Otherwise the - * value needs to be set to zero. - * - * @details If this is true then permutation takes place in this row - * - */ - template static inline bool inverse_polynomial_is_computed_at_row(const AllEntities& in) - { - return (in.enable_single_column_permutation == 1); - } - - /** - * @brief Get all the entities for the permutation when we don't need to update them - * - * @details The entities are returned as a tuple of references in the following order: - * - The entity/polynomial used to store the product of the inverse values - * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of - * the inverse polynomial - * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum - * subrelation - * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum - * subrelation - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) - * - * @return All the entities needed for the permutation - */ - template static inline auto get_const_entities(const AllEntities& in) - { - - return std::forward_as_tuple( - in.single_permutation_inverses, /* The polynomial containing the inverse product*/ - in.enable_single_column_permutation, /* The polynomial enabling the product check subrelation */ - in.enable_first_set_permutation, /* Enables adding first set to the sum */ - in.enable_second_set_permutation, /* Enables adding second set to the sum */ - in.self_permutation_column, /* The first set column */ - in.self_permutation_column /* The second set column which in this case is the same as the first set column - */ - ); - } - - /** - * @brief Get all the entities for the permutation when need to update them - * - * @details The entities are returned as a tuple of references in the following order: - * - The entity/polynomial used to store the product of the inverse values - * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of - * the inverse polynomial - * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum - * subrelation - * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum - * subrelation - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) - * - * @return All the entities needed for the permutation - */ - template static inline auto get_nonconst_entities(AllEntities& in) - { - return std::forward_as_tuple( - in.single_permutation_inverses, /* The polynomial containing the inverse product*/ - in.enable_single_column_permutation, /* The polynomial enabling the product check subrelation */ - in.enable_first_set_permutation, /* Enables adding first set to the sum */ - in.enable_second_set_permutation, /* Enables adding second set to the sum */ - in.self_permutation_column, /* The first set column */ - in.self_permutation_column /* The second set column which in this case is the same as the first set column - */ - ); - } -}; - -#define DEFINE_IMPLEMENTATIONS_FOR_SETTINGS(RelationImplementation, flavor, Settings) \ - template class RelationImplementation; \ - template using RelationImplementation##Settings = RelationImplementation; \ - DEFINE_SUMCHECK_RELATION_CLASS(RelationImplementation##Settings, flavor); - -#define DEFINE_IMPLEMENTATIONS_FOR_ALL_SETTINGS(RelationImplementation, flavor) \ - DEFINE_IMPLEMENTATIONS_FOR_SETTINGS(RelationImplementation, flavor, ExampleTuplePermutationSettings); \ - DEFINE_IMPLEMENTATIONS_FOR_SETTINGS(RelationImplementation, flavor, ExampleSameWirePermutationSettings); - -#define DECLARE_IMPLEMENTATIONS_FOR_SETTINGS(RelationImplementation, flavor, Settings) \ - extern template class RelationImplementation; \ - template using RelationImplementation##Settings = RelationImplementation; \ - DECLARE_SUMCHECK_RELATION_CLASS(RelationImplementation##Settings, flavor); - -#define DECLARE_IMPLEMENTATIONS_FOR_ALL_SETTINGS(RelationImplementation, flavor) \ - DECLARE_IMPLEMENTATIONS_FOR_SETTINGS(RelationImplementation, flavor, ExampleTuplePermutationSettings); \ - DECLARE_IMPLEMENTATIONS_FOR_SETTINGS(RelationImplementation, flavor, ExampleSameWirePermutationSettings); -} // namespace proof_system::honk::sumcheck \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp index da10ff83a40..86a691495c0 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp @@ -3,6 +3,7 @@ #include "AvmMini_prover.hpp" #include "barretenberg/commitment_schemes/claim.hpp" #include "barretenberg/commitment_schemes/commitment_key.hpp" +#include "barretenberg/honk/proof_system/logderivative_library.hpp" #include "barretenberg/honk/proof_system/permutation_library.hpp" #include "barretenberg/honk/proof_system/power_polynomial.hpp" #include "barretenberg/polynomials/polynomial.hpp" @@ -60,12 +61,12 @@ AvmMiniProver::AvmMiniProver(std::shared_ptr input_key, prover_polynomials.memTrace_m_rw = key->memTrace_m_rw; prover_polynomials.memTrace_m_rw_shift = key->memTrace_m_rw.shifted(); - prover_polynomials.memTrace_m_val = key->memTrace_m_val; - prover_polynomials.memTrace_m_val_shift = key->memTrace_m_val.shifted(); - prover_polynomials.memTrace_m_addr = key->memTrace_m_addr; prover_polynomials.memTrace_m_addr_shift = key->memTrace_m_addr.shifted(); + prover_polynomials.memTrace_m_val = key->memTrace_m_val; + prover_polynomials.memTrace_m_val_shift = key->memTrace_m_val.shifted(); + // prover_polynomials.lookup_inverses = key->lookup_inverses; // key->z_perm = Polynomial(key->circuit_size); // prover_polynomials.z_perm = key->z_perm; diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_composer.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_composer.cpp new file mode 100644 index 00000000000..4d2ec73e118 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_composer.cpp @@ -0,0 +1,89 @@ + + +#include "./Toy_composer.hpp" +#include "barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp" +#include "barretenberg/proof_system/composer/composer_lib.hpp" +#include "barretenberg/proof_system/composer/permutation_lib.hpp" +#include "barretenberg/vm/generated/Toy_verifier.hpp" + +namespace proof_system::honk { + +using Flavor = honk::flavor::ToyFlavor; +void ToyComposer::compute_witness(CircuitConstructor& circuit) +{ + if (computed_witness) { + return; + } + + auto polynomials = circuit.compute_polynomials(); + + proving_key->toy_first = polynomials.toy_first; + proving_key->toy_q_tuple_set = polynomials.toy_q_tuple_set; + proving_key->toy_set_1_column_1 = polynomials.toy_set_1_column_1; + proving_key->toy_set_1_column_2 = polynomials.toy_set_1_column_2; + proving_key->toy_set_2_column_1 = polynomials.toy_set_2_column_1; + proving_key->toy_set_2_column_2 = polynomials.toy_set_2_column_2; + proving_key->toy_x = polynomials.toy_x; + proving_key->two_column_perm = polynomials.two_column_perm; + + computed_witness = true; +} + +ToyProver ToyComposer::create_prover(CircuitConstructor& circuit_constructor) +{ + compute_proving_key(circuit_constructor); + compute_witness(circuit_constructor); + compute_commitment_key(circuit_constructor.get_circuit_subgroup_size()); + + ToyProver output_state(proving_key, commitment_key); + + return output_state; +} + +ToyVerifier ToyComposer::create_verifier(CircuitConstructor& circuit_constructor) +{ + auto verification_key = compute_verification_key(circuit_constructor); + + ToyVerifier output_state(verification_key); + + auto pcs_verification_key = std::make_unique(verification_key->circuit_size, crs_factory_); + + output_state.pcs_verification_key = std::move(pcs_verification_key); + + return output_state; +} + +std::shared_ptr ToyComposer::compute_proving_key(CircuitConstructor& circuit_constructor) +{ + if (proving_key) { + return proving_key; + } + + // Initialize proving_key + { + const size_t subgroup_size = circuit_constructor.get_circuit_subgroup_size(); + proving_key = std::make_shared(subgroup_size, 0); + } + + proving_key->contains_recursive_proof = false; + + return proving_key; +} + +std::shared_ptr ToyComposer::compute_verification_key(CircuitConstructor& circuit_constructor) +{ + if (verification_key) { + return verification_key; + } + + if (!proving_key) { + compute_proving_key(circuit_constructor); + } + + verification_key = + std::make_shared(proving_key->circuit_size, proving_key->num_public_inputs); + + return verification_key; +} + +} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_composer.hpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_composer.hpp new file mode 100644 index 00000000000..ad7877b7073 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_composer.hpp @@ -0,0 +1,69 @@ + + +#pragma once + +#include "barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp" +#include "barretenberg/proof_system/composer/composer_lib.hpp" +#include "barretenberg/srs/global_crs.hpp" +#include "barretenberg/vm/generated/Toy_prover.hpp" +#include "barretenberg/vm/generated/Toy_verifier.hpp" + +namespace proof_system::honk { +class ToyComposer { + public: + using Flavor = honk::flavor::ToyFlavor; + using CircuitConstructor = ToyCircuitBuilder; + using ProvingKey = Flavor::ProvingKey; + using VerificationKey = Flavor::VerificationKey; + using PCS = Flavor::PCS; + using CommitmentKey = Flavor::CommitmentKey; + using VerifierCommitmentKey = Flavor::VerifierCommitmentKey; + + // TODO: which of these will we really need + static constexpr std::string_view NAME_STRING = "Toy"; + static constexpr size_t NUM_RESERVED_GATES = 0; + static constexpr size_t NUM_WIRES = Flavor::NUM_WIRES; + + std::shared_ptr proving_key; + std::shared_ptr verification_key; + + // The crs_factory holds the path to the srs and exposes methods to extract the srs elements + std::shared_ptr> crs_factory_; + + // The commitment key is passed to the prover but also used herein to compute the verfication key commitments + std::shared_ptr commitment_key; + + std::vector recursive_proof_public_input_indices; + bool contains_recursive_proof = false; + bool computed_witness = false; + + ToyComposer() { crs_factory_ = barretenberg::srs::get_crs_factory(); } + + ToyComposer(std::shared_ptr p_key, std::shared_ptr v_key) + : proving_key(std::move(p_key)) + , verification_key(std::move(v_key)) + {} + + ToyComposer(ToyComposer&& other) noexcept = default; + ToyComposer(ToyComposer const& other) noexcept = default; + ToyComposer& operator=(ToyComposer&& other) noexcept = default; + ToyComposer& operator=(ToyComposer const& other) noexcept = default; + ~ToyComposer() = default; + + std::shared_ptr compute_proving_key(CircuitConstructor& circuit_constructor); + std::shared_ptr compute_verification_key(CircuitConstructor& circuit_constructor); + + void compute_witness(CircuitConstructor& circuit_constructor); + + ToyProver create_prover(CircuitConstructor& circuit_constructor); + ToyVerifier create_verifier(CircuitConstructor& circuit_constructor); + + void add_table_column_selector_poly_to_proving_key(barretenberg::polynomial& small, const std::string& tag); + + void compute_commitment_key(size_t circuit_size) + { + commitment_key = std::make_shared(circuit_size, crs_factory_); + }; +}; + +} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp new file mode 100644 index 00000000000..3d7738d13ef --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp @@ -0,0 +1,136 @@ + + +#include "Toy_prover.hpp" +#include "barretenberg/commitment_schemes/claim.hpp" +#include "barretenberg/commitment_schemes/commitment_key.hpp" +#include "barretenberg/honk/proof_system/logderivative_library.hpp" +#include "barretenberg/honk/proof_system/permutation_library.hpp" +#include "barretenberg/honk/proof_system/power_polynomial.hpp" +#include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/proof_system/library/grand_product_library.hpp" +#include "barretenberg/relations/lookup_relation.hpp" +#include "barretenberg/relations/permutation_relation.hpp" +#include "barretenberg/sumcheck/sumcheck.hpp" + +namespace proof_system::honk { + +using Flavor = honk::flavor::ToyFlavor; + +/** + * Create ToyProver from proving key, witness and manifest. + * + * @param input_key Proving key. + * @param input_manifest Input manifest + * + * @tparam settings Settings class. + * */ +ToyProver::ToyProver(std::shared_ptr input_key, std::shared_ptr commitment_key) + : key(input_key) + , commitment_key(commitment_key) +{ + // TODO: take every polynomial and assign it to the key!! + prover_polynomials.toy_first = key->toy_first; + prover_polynomials.toy_q_tuple_set = key->toy_q_tuple_set; + prover_polynomials.toy_set_1_column_1 = key->toy_set_1_column_1; + prover_polynomials.toy_set_1_column_2 = key->toy_set_1_column_2; + prover_polynomials.toy_set_2_column_1 = key->toy_set_2_column_1; + prover_polynomials.toy_set_2_column_2 = key->toy_set_2_column_2; + prover_polynomials.toy_x = key->toy_x; + prover_polynomials.two_column_perm = key->two_column_perm; + + prover_polynomials.toy_x = key->toy_x; + prover_polynomials.toy_x_shift = key->toy_x.shifted(); + + // prover_polynomials.lookup_inverses = key->lookup_inverses; + // key->z_perm = Polynomial(key->circuit_size); + // prover_polynomials.z_perm = key->z_perm; +} + +/** + * @brief Add circuit size, public input size, and public inputs to transcript + * + */ +void ToyProver::execute_preamble_round() +{ + const auto circuit_size = static_cast(key->circuit_size); + + transcript->send_to_verifier("circuit_size", circuit_size); +} + +/** + * @brief Compute commitments to the first three wires + * + */ +void ToyProver::execute_wire_commitments_round() +{ + auto wire_polys = key->get_wires(); + auto labels = commitment_labels.get_wires(); + for (size_t idx = 0; idx < wire_polys.size(); ++idx) { + transcript->send_to_verifier(labels[idx], commitment_key->commit(wire_polys[idx])); + } +} + +/** + * @brief Run Sumcheck resulting in u = (u_1,...,u_d) challenges and all evaluations at u being calculated. + * + */ +void ToyProver::execute_relation_check_rounds() +{ + using Sumcheck = sumcheck::SumcheckProver; + + auto sumcheck = Sumcheck(key->circuit_size, transcript); + auto alpha = transcript->get_challenge("alpha"); + + sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha); +} + +/** + * @brief Execute the ZeroMorph protocol to prove the multilinear evaluations produced by Sumcheck + * @details See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the unrolled protocol. + * + * */ +void ToyProver::execute_zeromorph_rounds() +{ + ZeroMorph::prove(prover_polynomials.get_unshifted(), + prover_polynomials.get_to_be_shifted(), + sumcheck_output.claimed_evaluations.get_unshifted(), + sumcheck_output.claimed_evaluations.get_shifted(), + sumcheck_output.challenge, + commitment_key, + transcript); +} + +plonk::proof& ToyProver::export_proof() +{ + proof.proof_data = transcript->proof_data; + return proof; +} + +plonk::proof& ToyProver::construct_proof() +{ + // Add circuit size public input size and public inputs to transcript. + execute_preamble_round(); + + // Compute wire commitments + execute_wire_commitments_round(); + + // TODO: not implemented for codegen just yet + // Compute sorted list accumulator and commitment + // execute_log_derivative_commitments_round(); + + // Fiat-Shamir: bbeta & gamma + // Compute grand product(s) and commitments. + // execute_grand_product_computation_round(); + + // Fiat-Shamir: alpha + // Run sumcheck subprotocol. + execute_relation_check_rounds(); + + // Fiat-Shamir: rho, y, x, z + // Execute Zeromorph multilinear PCS + execute_zeromorph_rounds(); + + return export_proof(); +} + +} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.hpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.hpp new file mode 100644 index 00000000000..bfd4db05ba6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.hpp @@ -0,0 +1,62 @@ + + +#pragma once +#include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" +#include "barretenberg/flavor/generated/Toy_flavor.hpp" +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/relations/relation_parameters.hpp" +#include "barretenberg/sumcheck/sumcheck_output.hpp" +#include "barretenberg/transcript/transcript.hpp" + +namespace proof_system::honk { + +class ToyProver { + + using Flavor = honk::flavor::ToyFlavor; + using FF = Flavor::FF; + using PCS = Flavor::PCS; + using PCSCommitmentKey = Flavor::CommitmentKey; + using ProvingKey = Flavor::ProvingKey; + using Polynomial = Flavor::Polynomial; + using ProverPolynomials = Flavor::ProverPolynomials; + using CommitmentLabels = Flavor::CommitmentLabels; + using Curve = Flavor::Curve; + using Transcript = Flavor::Transcript; + + public: + explicit ToyProver(std::shared_ptr input_key, std::shared_ptr commitment_key); + + void execute_preamble_round(); + void execute_wire_commitments_round(); + void execute_relation_check_rounds(); + void execute_zeromorph_rounds(); + + plonk::proof& export_proof(); + plonk::proof& construct_proof(); + + std::shared_ptr transcript = std::make_shared(); + + std::vector public_inputs; + + proof_system::RelationParameters relation_parameters; + + std::shared_ptr key; + + // Container for spans of all polynomials required by the prover (i.e. all multivariates evaluated by Sumcheck). + ProverPolynomials prover_polynomials; + + CommitmentLabels commitment_labels; + + Polynomial quotient_W; + + sumcheck::SumcheckOutput sumcheck_output; + + std::shared_ptr commitment_key; + + using ZeroMorph = pcs::zeromorph::ZeroMorphProver_; + + private: + plonk::proof proof; +}; + +} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp new file mode 100644 index 00000000000..e92eb206f29 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp @@ -0,0 +1,99 @@ + + +#include "./Toy_verifier.hpp" +#include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" +#include "barretenberg/honk/proof_system/power_polynomial.hpp" +#include "barretenberg/numeric/bitop/get_msb.hpp" +#include "barretenberg/transcript/transcript.hpp" + +using namespace barretenberg; +using namespace proof_system::honk::sumcheck; + +namespace proof_system::honk { +ToyVerifier::ToyVerifier(std::shared_ptr verifier_key) + : key(verifier_key) +{} + +ToyVerifier::ToyVerifier(ToyVerifier&& other) noexcept + : key(std::move(other.key)) + , pcs_verification_key(std::move(other.pcs_verification_key)) +{} + +ToyVerifier& ToyVerifier::operator=(ToyVerifier&& other) noexcept +{ + key = other.key; + pcs_verification_key = (std::move(other.pcs_verification_key)); + commitments.clear(); + return *this; +} + +/** + * @brief This function verifies an Toy Honk proof for given program settings. + * + */ +bool ToyVerifier::verify_proof(const plonk::proof& proof) +{ + using Flavor = honk::flavor::ToyFlavor; + using FF = Flavor::FF; + using Commitment = Flavor::Commitment; + // using Curve = Flavor::Curve; + // using ZeroMorph = pcs::zeromorph::ZeroMorphVerifier_; + using VerifierCommitments = Flavor::VerifierCommitments; + using CommitmentLabels = Flavor::CommitmentLabels; + + RelationParameters relation_parameters; + + transcript = std::make_shared(proof.proof_data); + + VerifierCommitments commitments{ key }; + CommitmentLabels commitment_labels; + + const auto circuit_size = transcript->template receive_from_prover("circuit_size"); + + if (circuit_size != key->circuit_size) { + return false; + } + + // Get commitments to VM wires + commitments.toy_q_tuple_set = + transcript->template receive_from_prover(commitment_labels.toy_q_tuple_set); + commitments.toy_set_1_column_1 = + transcript->template receive_from_prover(commitment_labels.toy_set_1_column_1); + commitments.toy_set_1_column_2 = + transcript->template receive_from_prover(commitment_labels.toy_set_1_column_2); + commitments.toy_set_2_column_1 = + transcript->template receive_from_prover(commitment_labels.toy_set_2_column_1); + commitments.toy_set_2_column_2 = + transcript->template receive_from_prover(commitment_labels.toy_set_2_column_2); + commitments.toy_x = transcript->template receive_from_prover(commitment_labels.toy_x); + commitments.two_column_perm = + transcript->template receive_from_prover(commitment_labels.two_column_perm); + + // Execute Sumcheck Verifier + auto sumcheck = SumcheckVerifier(circuit_size); + + auto alpha = transcript->get_challenge("alpha"); + auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = + sumcheck.verify(relation_parameters, alpha, transcript); + + // If Sumcheck did not verify, return false + if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { + return false; + } + + // Execute ZeroMorph rounds. See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the + // unrolled protocol. + // NOTE: temporarily disabled - facing integration issues + // auto pairing_points = ZeroMorph::verify(commitments.get_unshifted(), + // commitments.get_to_be_shifted(), + // claimed_evaluations.get_unshifted(), + // claimed_evaluations.get_shifted(), + // multivariate_challenge, + // transcript); + + // auto verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); + // return sumcheck_verified.value() && verified; + return sumcheck_verified.value(); +} + +} // namespace proof_system::honk diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.hpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.hpp new file mode 100644 index 00000000000..30b5e78e5c8 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.hpp @@ -0,0 +1,33 @@ + + +#pragma once +#include "barretenberg/flavor/generated/Toy_flavor.hpp" +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/sumcheck/sumcheck.hpp" + +namespace proof_system::honk { +class ToyVerifier { + using Flavor = honk::flavor::ToyFlavor; + using FF = Flavor::FF; + using Commitment = Flavor::Commitment; + using VerificationKey = Flavor::VerificationKey; + using VerifierCommitmentKey = Flavor::VerifierCommitmentKey; + using Transcript = Flavor::Transcript; + + public: + explicit ToyVerifier(std::shared_ptr verifier_key = nullptr); + ToyVerifier(ToyVerifier&& other) noexcept; + ToyVerifier(const ToyVerifier& other) = delete; + + ToyVerifier& operator=(const ToyVerifier& other) = delete; + ToyVerifier& operator=(ToyVerifier&& other) noexcept; + + bool verify_proof(const plonk::proof& proof); + + std::shared_ptr key; + std::map commitments; + std::shared_ptr pcs_verification_key; + std::shared_ptr transcript; +}; + +} // namespace proof_system::honk From 253627333ffaaf09cb3b5f63143532f79cf44378 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 18 Dec 2023 18:05:04 +0000 Subject: [PATCH 4/8] fix: update toy to new master --- .../flavor/generated/Toy_flavor.hpp | 30 ++++++++++++++----- .../generated/Toy_circuit_builder.hpp | 8 ++--- .../barretenberg/vm/generated/Toy_prover.cpp | 25 +++++++--------- 3 files changed, 36 insertions(+), 27 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp index 540d9107b82..cb73871810b 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp @@ -126,14 +126,14 @@ class ToyFlavor { using Base = ProvingKey_, WitnessEntities>; using Base::Base; + RefVector get_to_be_shifted() { return { toy_x }; }; + // The plookup wires that store plookup read data. std::array get_table_column_wires() { return {}; }; }; using VerificationKey = VerificationKey_>; - using ProverPolynomials = AllEntities; - using FoldedPolynomials = AllEntities>; class AllValues : public AllEntities { @@ -142,21 +142,35 @@ class ToyFlavor { using Base::Base; }; - class AllPolynomials : public AllEntities { + using RowPolynomials = AllEntities; + + /** + * @brief A container for the prover polynomials handles. + */ + class ProverPolynomials : public AllEntities { public: - [[nodiscard]] size_t get_polynomial_size() const { return this->toy_q_tuple_set.size(); } - [[nodiscard]] AllValues get_row(const size_t row_idx) const + // Define all operations as default, except move construction/assignment + ProverPolynomials() = default; + ProverPolynomials& operator=(const ProverPolynomials&) = delete; + ProverPolynomials(const ProverPolynomials& o) = delete; + ProverPolynomials(ProverPolynomials&& o) noexcept = default; + ProverPolynomials& operator=(ProverPolynomials&& o) noexcept = default; + ~ProverPolynomials() = default; + [[nodiscard]] size_t get_polynomial_size() const { return toy_first.size(); } + /** + * @brief Returns the evaluations of all prover polynomials at one point on the boolean hypercube, which + * represents one row in the execution trace. + */ + [[nodiscard]] AllValues get_row(size_t row_idx) const { AllValues result; - for (auto [result_field, polynomial] : zip_view(result.get_all(), get_all())) { + for (auto [result_field, polynomial] : zip_view(result.get_all(), this->get_all())) { result_field = polynomial[row_idx]; } return result; } }; - using RowPolynomials = AllEntities; - class PartiallyEvaluatedMultivariates : public AllEntities { public: PartiallyEvaluatedMultivariates() = default; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp index fade5a864e9..bba7cf3268a 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp @@ -38,7 +38,7 @@ class ToyCircuitBuilder { // TODO: template using Polynomial = Flavor::Polynomial; - using AllPolynomials = Flavor::AllPolynomials; + using ProverPolynomials = Flavor::ProverPolynomials; static constexpr size_t num_fixed_columns = 9; static constexpr size_t num_polys = 8; @@ -46,10 +46,10 @@ class ToyCircuitBuilder { void set_trace(std::vector&& trace) { rows = std::move(trace); } - AllPolynomials compute_polynomials() + ProverPolynomials compute_polynomials() { const auto num_rows = get_circuit_subgroup_size(); - AllPolynomials polys; + ProverPolynomials polys; // Allocate mem for each column for (auto& poly : polys.get_all()) { @@ -88,7 +88,7 @@ class ToyCircuitBuilder { .eccvm_set_permutation_delta = 0, }; - auto polys = compute_polynomials(); + ProverPolynomials polys = compute_polynomials(); const size_t num_rows = polys.get_polynomial_size(); const auto evaluate_relation = [&](const std::string& relation_name) { diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp index 3d7738d13ef..3d74e03f688 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp @@ -29,21 +29,16 @@ ToyProver::ToyProver(std::shared_ptr input_key, std::shared_ , commitment_key(commitment_key) { // TODO: take every polynomial and assign it to the key!! - prover_polynomials.toy_first = key->toy_first; - prover_polynomials.toy_q_tuple_set = key->toy_q_tuple_set; - prover_polynomials.toy_set_1_column_1 = key->toy_set_1_column_1; - prover_polynomials.toy_set_1_column_2 = key->toy_set_1_column_2; - prover_polynomials.toy_set_2_column_1 = key->toy_set_2_column_1; - prover_polynomials.toy_set_2_column_2 = key->toy_set_2_column_2; - prover_polynomials.toy_x = key->toy_x; - prover_polynomials.two_column_perm = key->two_column_perm; - - prover_polynomials.toy_x = key->toy_x; - prover_polynomials.toy_x_shift = key->toy_x.shifted(); - - // prover_polynomials.lookup_inverses = key->lookup_inverses; - // key->z_perm = Polynomial(key->circuit_size); - // prover_polynomials.z_perm = key->z_perm; + for (auto [prover_poly, key_poly] : zip_view(prover_polynomials.get_unshifted(), key->get_all())) { + ASSERT(proof_system::flavor_get_label(prover_polynomials, prover_poly) == + proof_system::flavor_get_label(*key, key_poly)); + prover_poly = key_poly.share(); + } + for (auto [prover_poly, key_poly] : zip_view(prover_polynomials.get_shifted(), key->get_to_be_shifted())) { + ASSERT(proof_system::flavor_get_label(prover_polynomials, prover_poly) == + proof_system::flavor_get_label(*key, key_poly) + "_shift"); + prover_poly = key_poly.shifted(); + } } /** From 1b6e2b45180d3ed28430b8d630609d5a173fb206 Mon Sep 17 00:00:00 2001 From: Jean M <132435771+jeanmon@users.noreply.github.com> Date: Tue, 19 Dec 2023 15:33:10 +0100 Subject: [PATCH 5/8] feat(avm): VM circuit handles tagged memory (#3725) Resolves #3644 --- barretenberg/cpp/pil/avm/avm_mini.pil | 41 ++- barretenberg/cpp/pil/avm/avm_mini_opt.pil | 21 +- barretenberg/cpp/pil/avm/mem_trace.pil | 77 +++- .../flavor/generated/AvmMini_flavor.hpp | 127 +++++-- .../circuit_builder/AvmMini_helper.cpp | 17 +- .../circuit_builder/AvmMini_trace.cpp | 334 +++++++++--------- .../circuit_builder/AvmMini_trace.hpp | 49 +-- .../generated/AvmMini_circuit_builder.hpp | 43 ++- .../relations/generated/AvmMini/avm_mini.hpp | 106 ++++-- .../generated/AvmMini/declare_views.hpp | 12 +- .../relations/generated/AvmMini/mem_trace.hpp | 107 +++++- .../vm/generated/AvmMini_verifier.cpp | 12 + .../vm/tests/AvmMini_arithmetic.test.cpp | 226 ++++++------ .../vm/tests/AvmMini_memory.test.cpp | 252 +++++++++++++ .../barretenberg/vm/tests/helpers.test.cpp | 69 ++++ .../barretenberg/vm/tests/helpers.test.hpp | 19 + 16 files changed, 1109 insertions(+), 403 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp diff --git a/barretenberg/cpp/pil/avm/avm_mini.pil b/barretenberg/cpp/pil/avm/avm_mini.pil index 3bd9bc11b86..1fca367bf95 100644 --- a/barretenberg/cpp/pil/avm/avm_mini.pil +++ b/barretenberg/cpp/pil/avm/avm_mini.pil @@ -21,8 +21,12 @@ namespace avmMini(256); // DIV pol commit sel_op_div; - // Error boolean flag pertaining to an operation - pol commit op_err; + // Instruction memory tag (0: uninitialized, 1: u8, 2: u16, 3: u32, 4: u64, 5: u128, 6:field) + pol commit in_tag; + + // Errors + pol commit op_err; // Boolean flag pertaining to an operation error + pol commit tag_err; // Boolean flag (foreign key to memTrace.m_tag_err) // A helper witness being the inverse of some value // to show a non-zero equality @@ -49,8 +53,8 @@ namespace avmMini(256); pol commit mem_idx_a; pol commit mem_idx_b; pol commit mem_idx_c; - - + + // Track the last line of the execution trace. It does NOT correspond to the last row of the whole table // of size N. As this depends on the supplied bytecode, this polynomial cannot be constant. pol commit last; @@ -63,6 +67,7 @@ namespace avmMini(256); sel_op_div * (1 - sel_op_div) = 0; op_err * (1 - op_err) = 0; + tag_err * (1 - tag_err) = 0; // Potential optimization (boolean constraint derivation from equivalence check to memTrace)? mem_op_a * (1 - mem_op_a) = 0; mem_op_b * (1 - mem_op_b) = 0; @@ -72,23 +77,38 @@ namespace avmMini(256); rwb * (1 - rwb) = 0; rwc * (1 - rwc) = 0; + // TODO: Constrain rwa, rwb, rwc to u32 type and 0 <= in_tag <= 6 + + // Set intermediate registers to 0 whenever tag_err occurs + tag_err * ia = 0; + tag_err * ib = 0; + tag_err * ic = 0; + // Relation for addition over the finite field + #[SUBOP_ADDITION_FF] sel_op_add * (ia + ib - ic) = 0; // Relation for subtraction over the finite field + #[SUBOP_SUBTRACTION_FF] sel_op_sub * (ia - ib - ic) = 0; // Relation for multiplication over the finite field + #[SUBOP_MULTIPLICATION_FF] sel_op_mul * (ia * ib - ic) = 0; // Relation for division over the finite field + // If tag_err == 1 in a division, then ib == 0 and op_err == 1. + #[SUBOP_DIVISION_FF] sel_op_div * (1 - op_err) * (ic * ib - ia) = 0; // When sel_op_div == 1, we want ib == 0 <==> op_err == 1 // This can be achieved with the 2 following relations. // inv is an extra witness to show that we can invert ib, i.e., inv = ib^(-1) - // If ib == 0, we have to set inv = 1 to satisfy the second relation. + // If ib == 0, we have to set inv = 1 to satisfy the second relation, + // because op_err == 1 from the first relation. + #[SUBOP_DIVISION_ZERO_ERR1] sel_op_div * (ib * inv - 1 + op_err) = 0; + #[SUBOP_DIVISION_ZERO_ERR2] sel_op_div * op_err * (1 - inv) = 0; // op_err cannot be maliciously activated for a non-relevant @@ -97,9 +117,10 @@ namespace avmMini(256); // Note that the above is even a stronger constraint, as it shows // that exactly one sel_op_XXX must be true. // At this time, we have only division producing an error. + #[SUBOP_ERROR_RELEVANT_OP] op_err * (sel_op_div - 1) = 0; - // TODO: constraint that we stop execution at the first error + // TODO: constraint that we stop execution at the first error (tag_err or op_err) // An error can only happen at the last sub-operation row. // OPEN/POTENTIAL OPTIMIZATION: Dedicated error per relevant operation? @@ -108,4 +129,10 @@ namespace avmMini(256); // Same for the relations related to the error activation: // (ib * inv - 1 + op_div_err) = 0 && op_err * (1 - inv) = 0 // This works in combination with op_div_err * (sel_op_div - 1) = 0; - // Drawback is the need to paralllelize the latter. \ No newline at end of file + // Drawback is the need to paralllelize the latter. + + // Inter-table Constraints + + // TODO: tag_err {clk} IS memTrace.m_tag_err {memTrace.m_clk} + // TODO: Map memory trace with intermediate register values whenever there is no tag error, sthg like: + // mem_op_a * (1 - tag_err) {mem_idx_a, clk, ia, rwa} IS m_sub_clk == 0 && 1 - m_tag_err {m_addr, m_clk, m_val, m_rw} \ No newline at end of file diff --git a/barretenberg/cpp/pil/avm/avm_mini_opt.pil b/barretenberg/cpp/pil/avm/avm_mini_opt.pil index 56019fb7197..f3a75411a99 100644 --- a/barretenberg/cpp/pil/avm/avm_mini_opt.pil +++ b/barretenberg/cpp/pil/avm/avm_mini_opt.pil @@ -2,13 +2,24 @@ namespace memTrace(256); col witness m_clk; col witness m_sub_clk; col witness m_addr; + col witness m_tag; col witness m_val; col witness m_lastAccess; + col witness m_last; col witness m_rw; + col witness m_in_tag; + col witness m_tag_err; + col witness m_one_min_inv; (memTrace.m_lastAccess * (1 - memTrace.m_lastAccess)) = 0; + (memTrace.m_last * (1 - memTrace.m_last)) = 0; (memTrace.m_rw * (1 - memTrace.m_rw)) = 0; - (((1 - avmMini.first) * (1 - memTrace.m_lastAccess)) * (memTrace.m_addr' - memTrace.m_addr)) = 0; - (((((1 - avmMini.first) * (1 - avmMini.last)) * (1 - memTrace.m_lastAccess)) * (1 - memTrace.m_rw')) * (memTrace.m_val' - memTrace.m_val)) = 0; + (memTrace.m_tag_err * (1 - memTrace.m_tag_err)) = 0; + ((1 - memTrace.m_lastAccess) * (memTrace.m_addr' - memTrace.m_addr)) = 0; + (((1 - memTrace.m_lastAccess) * (1 - memTrace.m_rw')) * (memTrace.m_val' - memTrace.m_val)) = 0; + (((1 - memTrace.m_lastAccess) * (1 - memTrace.m_rw')) * (memTrace.m_tag' - memTrace.m_tag)) = 0; + ((memTrace.m_lastAccess * (1 - memTrace.m_rw')) * memTrace.m_val') = 0; + ((memTrace.m_in_tag - memTrace.m_tag) * (1 - memTrace.m_one_min_inv)) = memTrace.m_tag_err; + ((1 - memTrace.m_tag_err) * memTrace.m_one_min_inv) = 0; namespace avmMini(256); col fixed clk(i) { i }; col fixed first = [1] + [0]*; @@ -16,7 +27,9 @@ namespace avmMini(256); col witness sel_op_sub; col witness sel_op_mul; col witness sel_op_div; + col witness in_tag; col witness op_err; + col witness tag_err; col witness inv; col witness ia; col witness ib; @@ -36,12 +49,16 @@ namespace avmMini(256); (avmMini.sel_op_mul * (1 - avmMini.sel_op_mul)) = 0; (avmMini.sel_op_div * (1 - avmMini.sel_op_div)) = 0; (avmMini.op_err * (1 - avmMini.op_err)) = 0; + (avmMini.tag_err * (1 - avmMini.tag_err)) = 0; (avmMini.mem_op_a * (1 - avmMini.mem_op_a)) = 0; (avmMini.mem_op_b * (1 - avmMini.mem_op_b)) = 0; (avmMini.mem_op_c * (1 - avmMini.mem_op_c)) = 0; (avmMini.rwa * (1 - avmMini.rwa)) = 0; (avmMini.rwb * (1 - avmMini.rwb)) = 0; (avmMini.rwc * (1 - avmMini.rwc)) = 0; + (avmMini.tag_err * avmMini.ia) = 0; + (avmMini.tag_err * avmMini.ib) = 0; + (avmMini.tag_err * avmMini.ic) = 0; (avmMini.sel_op_add * ((avmMini.ia + avmMini.ib) - avmMini.ic)) = 0; (avmMini.sel_op_sub * ((avmMini.ia - avmMini.ib) - avmMini.ic)) = 0; (avmMini.sel_op_mul * ((avmMini.ia * avmMini.ib) - avmMini.ic)) = 0; diff --git a/barretenberg/cpp/pil/avm/mem_trace.pil b/barretenberg/cpp/pil/avm/mem_trace.pil index 38cc0813d2c..33a8a20ad06 100644 --- a/barretenberg/cpp/pil/avm/mem_trace.pil +++ b/barretenberg/cpp/pil/avm/mem_trace.pil @@ -7,29 +7,50 @@ namespace memTrace(256); pol commit m_clk; pol commit m_sub_clk; pol commit m_addr; + pol commit m_tag; // Memory tag (0: uninitialized, 1: u8, 2: u16, 3: u32, 4: u64, 5: u128, 6:field) pol commit m_val; pol commit m_lastAccess; // Boolean (1 when this row is the last of a given address) + pol commit m_last; // Boolean indicating the last row of the memory trace (not execution trace) pol commit m_rw; // Enum: 0 (read), 1 (write) - + + pol commit m_in_tag; // Instruction memory tag ("foreign key" pointing to avmMini.in_tag) + + // Error columns + pol commit m_tag_err; // Boolean (1 if m_in_tag != m_tag is detected) + + // Helper columns + pol commit m_one_min_inv; // Extra value to prove m_in_tag != m_tag with error handling + // Type constraints m_lastAccess * (1 - m_lastAccess) = 0; + m_last * (1 - m_last) = 0; m_rw * (1 - m_rw) = 0; - + m_tag_err * (1 - m_tag_err) = 0; + + // TODO: m_addr is u32 and 0 <= m_tag <= 6 + // (m_in_tag will be constrained through inclusion check to main trace) + + // Remark: m_lastAccess == 1 on first row and therefore any relation with the + // multiplicative term (1 - m_lastAccess) implicitly includes (1 - avmMini.first) + // Similarly, this includes (1 - m_last) as well. + // m_lastAccess == 0 ==> m_addr' == m_addr - (1 - avmMini.first) * (1 - m_lastAccess) * (m_addr' - m_addr) = 0; + // Optimization: We removed the term (1 - avmMini.first) + #[MEM_LAST_ACCESS_DELIMITER] + (1 - m_lastAccess) * (m_addr' - m_addr) = 0; // We need: m_lastAccess == 1 ==> m_addr' > m_addr // The above implies: m_addr' == m_addr ==> m_lastAccess == 0 // This condition does not apply on the last row. // clk + 1 used as an expression for positive integers // TODO: Uncomment when lookups are supported - // (1 - first) * (1 - last) * m_lastAccess { (m_addr' - m_addr) } in clk + 1; // Gated inclusion check. Is it supported? + // (1 - first) * (1 - m_last) * m_lastAccess { (m_addr' - m_addr) } in clk + 1; // Gated inclusion check. Is it supported? // TODO: following constraint // m_addr' == m_addr && m_clk == m_clk' ==> m_sub_clk' - m_sub_clk > 0 - // Can be enforced with (1 - first) * (1 - last) * (1 - m_lastAccess) { 6 * (m_clk' - m_clk) + m_sub_clk' - m_sub_clk } in clk + 1 + // Can be enforced with (1 - first) * (1 - m_lastAccess) { 6 * (m_clk' - m_clk) + m_sub_clk' - m_sub_clk } in clk + 1 - // Alternatively to the above, one could require + // Alternatively to the above, one could require // that m_addr' - m_addr is 0 or 1 (needs to add placeholders m_addr values): // (m_addr' - m_addr) * (m_addr' - m_addr) - (m_addr' - m_addr) = 0; // if m_addr' - m_addr is 0 or 1, the following is equiv. to m_lastAccess @@ -40,8 +61,46 @@ namespace memTrace(256); // Note: in barretenberg, a shifted polynomial will be 0 on the last row (shift is not cyclic) // Note2: in barretenberg, if a poynomial is shifted, its non-shifted equivalent must be 0 on the first row - (1 - avmMini.first) * (1 - avmMini.last) * (1 - m_lastAccess) * (1 - m_rw') * (m_val' - m_val) = 0; + // Optimization: We removed the term (1 - avmMini.first) and (1 - m_last) + #[MEM_READ_WRITE_VAL_CONSISTENCY] + (1 - m_lastAccess) * (1 - m_rw') * (m_val' - m_val) = 0; - // TODO: Constraint the first load from a given adress has value 0. (Consistency of memory initialization.) + // m_lastAccess == 0 && m_rw' == 0 ==> m_tag == m_tag' + // Optimization: We removed the term (1 - avmMini.first) and (1 - m_last) + #[MEM_READ_WRITE_TAG_CONSISTENCY] + (1 - m_lastAccess) * (1 - m_rw') * (m_tag' - m_tag) = 0; + + // Constrain that the first load from a given address has value 0. (Consistency of memory initialization.) + // We do not constrain that the m_tag == 0 as the 0 value is compatible with any memory type. + // If we set m_lastAccess = 1 on the first row, we can enforce this (should be ok as long as we do not shift m_lastAccess): + #[MEM_ZERO_INIT] + m_lastAccess * (1 - m_rw') * m_val' = 0; + + // Memory tag consistency check + // We want to prove that m_in_tag == m_tag <==> m_tag_err == 0 + // We want to show that we can invert (m_in_tag - m_tag) when m_tag_err == 1, + // i.e., m_tag_err == 1 ==> m_in_tag != m_tag + // For this purpose, we need an extra column to store a witness + // which can be used to show that (m_in_tag - m_tag) is invertible (non-zero). + // We re-use the same zero (non)-equality technique as in SUBOP_DIVISION_ZERO_ERR1/2 applied + // to (m_in_tag - m_tag) by replacing m_tag_err by 1 - m_tag_err because here + // the equality to zero is not an error. Another modification + // consists in storing 1 - (m_in_tag - m_tag)^(-1) in the extra witness column + // instead of (m_in_tag - m_tag)^(-1) as this allows to store zero by default (i.e., when m_tag_err == 0). + // The new column m_one_min_inv is set to 1 - (m_in_tag - m_tag)^(-1) when m_tag_err == 1 + // but must be set to 0 when tags are matching and m_tag_err = 0 + #[MEM_IN_TAG_CONSISTENCY_1] + (m_in_tag - m_tag) * (1 - m_one_min_inv) - m_tag_err = 0; + #[MEM_IN_TAG_CONSISTENCY_2] + (1 - m_tag_err) * m_one_min_inv = 0; + + // Correctness of two above checks MEM_IN_TAG_CONSISTENCY_1/2: + // m_in_tag == m_tag ==> m_tag_err == 0 (first relation) + // m_tag_err == 0 ==> m_one_min_inv == 0 by second relation. First relation ==> m_in_tag - m_tag == 0 + // TODO: when introducing load/store as sub-operations, we will have to add consistency of intermediate - // register values ia, ib, ic \ No newline at end of file + // register values ia, ib, ic + + // Inter-table Constraints + + // TODO: {m_clk, m_in_tag} IN {avmMini.clk, avmMini.in_tag} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp index 99b7f32f207..f986f97f168 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp @@ -36,11 +36,11 @@ class AvmMiniFlavor { using VerifierCommitmentKey = pcs::VerifierCommitmentKey; static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 2; - static constexpr size_t NUM_WITNESS_ENTITIES = 25; + static constexpr size_t NUM_WITNESS_ENTITIES = 32; static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted - static constexpr size_t NUM_ALL_ENTITIES = 30; + static constexpr size_t NUM_ALL_ENTITIES = 38; using Relations = std::tuple, AvmMini_vm::avm_mini>; @@ -79,14 +79,21 @@ class AvmMiniFlavor { memTrace_m_clk, memTrace_m_sub_clk, memTrace_m_addr, + memTrace_m_tag, memTrace_m_val, memTrace_m_lastAccess, + memTrace_m_last, memTrace_m_rw, + memTrace_m_in_tag, + memTrace_m_tag_err, + memTrace_m_one_min_inv, avmMini_sel_op_add, avmMini_sel_op_sub, avmMini_sel_op_mul, avmMini_sel_op_div, + avmMini_in_tag, avmMini_op_err, + avmMini_tag_err, avmMini_inv, avmMini_ia, avmMini_ib, @@ -104,13 +111,38 @@ class AvmMiniFlavor { RefVector get_wires() { - return { - memTrace_m_clk, memTrace_m_sub_clk, memTrace_m_addr, memTrace_m_val, memTrace_m_lastAccess, - memTrace_m_rw, avmMini_sel_op_add, avmMini_sel_op_sub, avmMini_sel_op_mul, avmMini_sel_op_div, - avmMini_op_err, avmMini_inv, avmMini_ia, avmMini_ib, avmMini_ic, - avmMini_mem_op_a, avmMini_mem_op_b, avmMini_mem_op_c, avmMini_rwa, avmMini_rwb, - avmMini_rwc, avmMini_mem_idx_a, avmMini_mem_idx_b, avmMini_mem_idx_c, avmMini_last - }; + return { memTrace_m_clk, + memTrace_m_sub_clk, + memTrace_m_addr, + memTrace_m_tag, + memTrace_m_val, + memTrace_m_lastAccess, + memTrace_m_last, + memTrace_m_rw, + memTrace_m_in_tag, + memTrace_m_tag_err, + memTrace_m_one_min_inv, + avmMini_sel_op_add, + avmMini_sel_op_sub, + avmMini_sel_op_mul, + avmMini_sel_op_div, + avmMini_in_tag, + avmMini_op_err, + avmMini_tag_err, + avmMini_inv, + avmMini_ia, + avmMini_ib, + avmMini_ic, + avmMini_mem_op_a, + avmMini_mem_op_b, + avmMini_mem_op_c, + avmMini_rwa, + avmMini_rwb, + avmMini_rwc, + avmMini_mem_idx_a, + avmMini_mem_idx_b, + avmMini_mem_idx_c, + avmMini_last }; }; RefVector get_sorted_polynomials() { return {}; }; }; @@ -123,14 +155,21 @@ class AvmMiniFlavor { memTrace_m_clk, memTrace_m_sub_clk, memTrace_m_addr, + memTrace_m_tag, memTrace_m_val, memTrace_m_lastAccess, + memTrace_m_last, memTrace_m_rw, + memTrace_m_in_tag, + memTrace_m_tag_err, + memTrace_m_one_min_inv, avmMini_sel_op_add, avmMini_sel_op_sub, avmMini_sel_op_mul, avmMini_sel_op_div, + avmMini_in_tag, avmMini_op_err, + avmMini_tag_err, avmMini_inv, avmMini_ia, avmMini_ib, @@ -145,9 +184,10 @@ class AvmMiniFlavor { avmMini_mem_idx_b, avmMini_mem_idx_c, avmMini_last, - memTrace_m_rw_shift, + memTrace_m_val_shift, memTrace_m_addr_shift, - memTrace_m_val_shift) + memTrace_m_rw_shift, + memTrace_m_tag_shift) RefVector get_wires() { @@ -156,14 +196,21 @@ class AvmMiniFlavor { memTrace_m_clk, memTrace_m_sub_clk, memTrace_m_addr, + memTrace_m_tag, memTrace_m_val, memTrace_m_lastAccess, + memTrace_m_last, memTrace_m_rw, + memTrace_m_in_tag, + memTrace_m_tag_err, + memTrace_m_one_min_inv, avmMini_sel_op_add, avmMini_sel_op_sub, avmMini_sel_op_mul, avmMini_sel_op_div, + avmMini_in_tag, avmMini_op_err, + avmMini_tag_err, avmMini_inv, avmMini_ia, avmMini_ib, @@ -178,9 +225,10 @@ class AvmMiniFlavor { avmMini_mem_idx_b, avmMini_mem_idx_c, avmMini_last, - memTrace_m_rw_shift, + memTrace_m_val_shift, memTrace_m_addr_shift, - memTrace_m_val_shift }; + memTrace_m_rw_shift, + memTrace_m_tag_shift }; }; RefVector get_unshifted() { @@ -189,14 +237,21 @@ class AvmMiniFlavor { memTrace_m_clk, memTrace_m_sub_clk, memTrace_m_addr, + memTrace_m_tag, memTrace_m_val, memTrace_m_lastAccess, + memTrace_m_last, memTrace_m_rw, + memTrace_m_in_tag, + memTrace_m_tag_err, + memTrace_m_one_min_inv, avmMini_sel_op_add, avmMini_sel_op_sub, avmMini_sel_op_mul, avmMini_sel_op_div, + avmMini_in_tag, avmMini_op_err, + avmMini_tag_err, avmMini_inv, avmMini_ia, avmMini_ib, @@ -212,10 +267,13 @@ class AvmMiniFlavor { avmMini_mem_idx_c, avmMini_last }; }; - RefVector get_to_be_shifted() { return { memTrace_m_rw, memTrace_m_addr, memTrace_m_val }; }; + RefVector get_to_be_shifted() + { + return { memTrace_m_val, memTrace_m_addr, memTrace_m_rw, memTrace_m_tag }; + }; RefVector get_shifted() { - return { memTrace_m_rw_shift, memTrace_m_addr_shift, memTrace_m_val_shift }; + return { memTrace_m_val_shift, memTrace_m_addr_shift, memTrace_m_rw_shift, memTrace_m_tag_shift }; }; }; @@ -228,13 +286,9 @@ class AvmMiniFlavor { RefVector get_to_be_shifted() { - return { - memTrace_m_rw, - memTrace_m_addr, - memTrace_m_val, - - }; + return { memTrace_m_val, memTrace_m_addr, memTrace_m_rw, memTrace_m_tag }; }; + // The plookup wires that store plookup read data. std::array get_table_column_wires() { return {}; }; }; @@ -261,7 +315,7 @@ class AvmMiniFlavor { ProverPolynomials(ProverPolynomials&& o) noexcept = default; ProverPolynomials& operator=(ProverPolynomials&& o) noexcept = default; ~ProverPolynomials() = default; - [[nodiscard]] size_t get_polynomial_size() const { return avmMini_clk.size(); } + [[nodiscard]] size_t get_polynomial_size() const { return memTrace_m_clk.size(); } /** * @brief Returns the evaluations of all prover polynomials at one point on the boolean hypercube, which * represents one row in the execution trace. @@ -275,6 +329,7 @@ class AvmMiniFlavor { return result; } }; + using RowPolynomials = AllEntities; class PartiallyEvaluatedMultivariates : public AllEntities { @@ -313,14 +368,21 @@ class AvmMiniFlavor { Base::memTrace_m_clk = "MEMTRACE_M_CLK"; Base::memTrace_m_sub_clk = "MEMTRACE_M_SUB_CLK"; Base::memTrace_m_addr = "MEMTRACE_M_ADDR"; + Base::memTrace_m_tag = "MEMTRACE_M_TAG"; Base::memTrace_m_val = "MEMTRACE_M_VAL"; Base::memTrace_m_lastAccess = "MEMTRACE_M_LASTACCESS"; + Base::memTrace_m_last = "MEMTRACE_M_LAST"; Base::memTrace_m_rw = "MEMTRACE_M_RW"; + Base::memTrace_m_in_tag = "MEMTRACE_M_IN_TAG"; + Base::memTrace_m_tag_err = "MEMTRACE_M_TAG_ERR"; + Base::memTrace_m_one_min_inv = "MEMTRACE_M_ONE_MIN_INV"; Base::avmMini_sel_op_add = "AVMMINI_SEL_OP_ADD"; Base::avmMini_sel_op_sub = "AVMMINI_SEL_OP_SUB"; Base::avmMini_sel_op_mul = "AVMMINI_SEL_OP_MUL"; Base::avmMini_sel_op_div = "AVMMINI_SEL_OP_DIV"; + Base::avmMini_in_tag = "AVMMINI_IN_TAG"; Base::avmMini_op_err = "AVMMINI_OP_ERR"; + Base::avmMini_tag_err = "AVMMINI_TAG_ERR"; Base::avmMini_inv = "AVMMINI_INV"; Base::avmMini_ia = "AVMMINI_IA"; Base::avmMini_ib = "AVMMINI_IB"; @@ -357,14 +419,21 @@ class AvmMiniFlavor { Commitment memTrace_m_clk; Commitment memTrace_m_sub_clk; Commitment memTrace_m_addr; + Commitment memTrace_m_tag; Commitment memTrace_m_val; Commitment memTrace_m_lastAccess; + Commitment memTrace_m_last; Commitment memTrace_m_rw; + Commitment memTrace_m_in_tag; + Commitment memTrace_m_tag_err; + Commitment memTrace_m_one_min_inv; Commitment avmMini_sel_op_add; Commitment avmMini_sel_op_sub; Commitment avmMini_sel_op_mul; Commitment avmMini_sel_op_div; + Commitment avmMini_in_tag; Commitment avmMini_op_err; + Commitment avmMini_tag_err; Commitment avmMini_inv; Commitment avmMini_ia; Commitment avmMini_ib; @@ -401,14 +470,21 @@ class AvmMiniFlavor { memTrace_m_clk = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); memTrace_m_sub_clk = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); memTrace_m_addr = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + memTrace_m_tag = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); memTrace_m_val = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); memTrace_m_lastAccess = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + memTrace_m_last = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); memTrace_m_rw = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + memTrace_m_in_tag = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + memTrace_m_tag_err = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + memTrace_m_one_min_inv = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_sel_op_add = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_sel_op_sub = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_sel_op_mul = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_sel_op_div = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_in_tag = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_op_err = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_tag_err = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_inv = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_ia = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_ib = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); @@ -449,14 +525,21 @@ class AvmMiniFlavor { serialize_to_buffer(memTrace_m_clk, Transcript::proof_data); serialize_to_buffer(memTrace_m_sub_clk, Transcript::proof_data); serialize_to_buffer(memTrace_m_addr, Transcript::proof_data); + serialize_to_buffer(memTrace_m_tag, Transcript::proof_data); serialize_to_buffer(memTrace_m_val, Transcript::proof_data); serialize_to_buffer(memTrace_m_lastAccess, Transcript::proof_data); + serialize_to_buffer(memTrace_m_last, Transcript::proof_data); serialize_to_buffer(memTrace_m_rw, Transcript::proof_data); + serialize_to_buffer(memTrace_m_in_tag, Transcript::proof_data); + serialize_to_buffer(memTrace_m_tag_err, Transcript::proof_data); + serialize_to_buffer(memTrace_m_one_min_inv, Transcript::proof_data); serialize_to_buffer(avmMini_sel_op_add, Transcript::proof_data); serialize_to_buffer(avmMini_sel_op_sub, Transcript::proof_data); serialize_to_buffer(avmMini_sel_op_mul, Transcript::proof_data); serialize_to_buffer(avmMini_sel_op_div, Transcript::proof_data); + serialize_to_buffer(avmMini_in_tag, Transcript::proof_data); serialize_to_buffer(avmMini_op_err, Transcript::proof_data); + serialize_to_buffer(avmMini_tag_err, Transcript::proof_data); serialize_to_buffer(avmMini_inv, Transcript::proof_data); serialize_to_buffer(avmMini_ia, Transcript::proof_data); serialize_to_buffer(avmMini_ib, Transcript::proof_data); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.cpp index 401ad709c43..e3ee39cff93 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.cpp @@ -23,13 +23,25 @@ void log_avmMini_trace(std::vector const& trace, size_t beg, size_t end) info("== ROW ", i); info("================================================================================"); + info("=======MEMORY TRACE============================================================="); info("m_addr: ", trace.at(i).memTrace_m_addr); info("m_clk: ", trace.at(i).memTrace_m_clk); info("m_sub_clk: ", trace.at(i).memTrace_m_sub_clk); info("m_val: ", trace.at(i).memTrace_m_val); - info("m_lastAccess: ", trace.at(i).memTrace_m_lastAccess); info("m_rw: ", trace.at(i).memTrace_m_rw); + info("m_tag: ", trace.at(i).memTrace_m_tag); + info("m_in_tag: ", trace.at(i).memTrace_m_in_tag); + info("m_tag_err: ", trace.at(i).memTrace_m_tag_err); + info("m_one_min_inv:", trace.at(i).memTrace_m_one_min_inv); + + info("m_lastAccess: ", trace.at(i).memTrace_m_lastAccess); + info("m_last: ", trace.at(i).memTrace_m_last); info("m_val_shift: ", trace.at(i).memTrace_m_val_shift); + + info("=======MAIN TRACE==============================================================="); + info("ia: ", trace.at(i).avmMini_ia); + info("ib: ", trace.at(i).avmMini_ib); + info("ic: ", trace.at(i).avmMini_ic); info("first: ", trace.at(i).avmMini_first); info("last: ", trace.at(i).avmMini_last); @@ -37,19 +49,16 @@ void log_avmMini_trace(std::vector const& trace, size_t beg, size_t end) info("clk: ", trace.at(i).avmMini_clk); info("mem_op_a: ", trace.at(i).avmMini_mem_op_a); info("mem_idx_a: ", trace.at(i).avmMini_mem_idx_a); - info("ia: ", trace.at(i).avmMini_ia); info("rwa: ", trace.at(i).avmMini_rwa); info("=======MEM_OP_B================================================================="); info("mem_op_b: ", trace.at(i).avmMini_mem_op_b); info("mem_idx_b: ", trace.at(i).avmMini_mem_idx_b); - info("ib: ", trace.at(i).avmMini_ib); info("rwb: ", trace.at(i).avmMini_rwb); info("=======MEM_OP_C================================================================="); info("mem_op_c: ", trace.at(i).avmMini_mem_op_c); info("mem_idx_c: ", trace.at(i).avmMini_mem_idx_c); - info("ic: ", trace.at(i).avmMini_ic); info("rwc: ", trace.at(i).avmMini_rwc); info("\n"); } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp index 8562a72c41c..fd4c46ffef5 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp @@ -31,7 +31,7 @@ void AvmMiniTraceBuilder::reset() { mainTrace.clear(); memTrace.clear(); - ffMemory.fill(FF(0)); + memory.fill(FF(0)); } /** @@ -68,127 +68,135 @@ bool AvmMiniTraceBuilder::compareMemEntries(const MemoryTraceEntry& left, const * @param m_sub_clk Sub-clock used to order load/store sub operations * @param m_addr Address pertaining to the memory operation * @param m_val Value (FF) pertaining to the memory operation + * @param m_in_tag Memory tag pertaining to the instruction * @param m_rw Boolean telling whether it is a load (false) or store operation (true). */ -void AvmMiniTraceBuilder::insertInMemTrace(uint32_t m_clk, uint32_t m_sub_clk, uint32_t m_addr, FF m_val, bool m_rw) +void AvmMiniTraceBuilder::insertInMemTrace( + uint32_t m_clk, uint32_t m_sub_clk, uint32_t m_addr, FF m_val, AvmMemoryTag m_in_tag, bool m_rw) { memTrace.emplace_back(MemoryTraceEntry{ .m_clk = m_clk, .m_sub_clk = m_sub_clk, .m_addr = m_addr, .m_val = m_val, + .m_tag = m_in_tag, + .m_in_tag = m_in_tag, .m_rw = m_rw, }); } -// Memory operations need to be performed before the addition of the corresponding row in -// ainTrace, otherwise the m_clk value will be wrong.This applies to : loadAInMemTrace, loadBInMemTrace, -// loadCInMemTrace -// storeAInMemTrace, storeBInMemTrace, storeCInMemTrace -/** - * @brief Add a memory trace entry corresponding to a memory load into the intermediate - * register Ia. - * - * @param addr The memory address - * @param val The value to be loaded - */ -void AvmMiniTraceBuilder::loadAInMemTrace(uint32_t addr, FF val) +void AvmMiniTraceBuilder::loadMismatchTagInMemTrace( + uint32_t m_clk, uint32_t m_sub_clk, uint32_t m_addr, FF m_val, AvmMemoryTag m_in_tag, AvmMemoryTag m_tag) { - insertInMemTrace(static_cast(mainTrace.size()), SUB_CLK_LOAD_A, addr, val, false); + FF one_min_inv = FF(1) - (FF(static_cast(m_in_tag)) - FF(static_cast(m_tag))).invert(); + memTrace.emplace_back(MemoryTraceEntry{ .m_clk = m_clk, + .m_sub_clk = m_sub_clk, + .m_addr = m_addr, + .m_val = m_val, + .m_tag = m_tag, + .m_in_tag = m_in_tag, + .m_tag_err = true, + .m_one_min_inv = one_min_inv }); } -/** - * @brief Add a memory trace entry corresponding to a memory load into the intermediate - * register Ib. - * - * @param addr The memory address - * @param val The value to be loaded - */ -void AvmMiniTraceBuilder::loadBInMemTrace(uint32_t addr, FF val) -{ - insertInMemTrace(static_cast(mainTrace.size()), SUB_CLK_LOAD_B, addr, val, false); -} +// Memory operations need to be performed before the addition of the corresponding row in +// MainTrace, otherwise the m_clk value will be wrong. This applies to loadInMemTrace and +// storeInMemTrace. /** * @brief Add a memory trace entry corresponding to a memory load into the intermediate - * register Ic. + * passed register. * + * @param intermReg The intermediate register * @param addr The memory address * @param val The value to be loaded + * @param m_in_tag The memory tag of the instruction */ -void AvmMiniTraceBuilder::loadCInMemTrace(uint32_t addr, FF val) +bool AvmMiniTraceBuilder::loadInMemTrace(IntermRegister intermReg, uint32_t addr, FF val, AvmMemoryTag m_in_tag) { - insertInMemTrace(static_cast(mainTrace.size()), SUB_CLK_LOAD_C, addr, val, false); -} + uint32_t sub_clk = 0; + switch (intermReg) { + case IntermRegister::ia: + sub_clk = SUB_CLK_LOAD_A; + break; + case IntermRegister::ib: + sub_clk = SUB_CLK_LOAD_B; + break; + case IntermRegister::ic: + sub_clk = SUB_CLK_LOAD_C; + break; + } -/** - * @brief Add a memory trace entry corresponding to a memory store from the intermediate - * register Ia. - * - * @param addr The memory address - * @param val The value to be stored - */ -void AvmMiniTraceBuilder::storeAInMemTrace(uint32_t addr, FF val) -{ - insertInMemTrace(static_cast(mainTrace.size()), SUB_CLK_STORE_A, addr, val, true); -} + auto m_tag = memoryTag.at(addr); + if (m_tag == AvmMemoryTag::u0 || m_tag == m_in_tag) { + insertInMemTrace(static_cast(mainTrace.size()), sub_clk, addr, val, m_in_tag, false); + return true; + } -/** - * @brief Add a memory trace entry corresponding to a memory store from the intermediate - * register Ib. - * - * @param addr The memory address - * @param val The value to be stored - */ -void AvmMiniTraceBuilder::storeBInMemTrace(uint32_t addr, FF val) -{ - insertInMemTrace(static_cast(mainTrace.size()), SUB_CLK_STORE_B, addr, val, true); + // Handle memory tag inconsistency + loadMismatchTagInMemTrace(static_cast(mainTrace.size()), sub_clk, addr, val, m_in_tag, m_tag); + return false; } /** * @brief Add a memory trace entry corresponding to a memory store from the intermediate - * register Ic. + * register. * + * @param intermReg The intermediate register * @param addr The memory address * @param val The value to be stored + * @param m_in_tag The memory tag of the instruction */ -void AvmMiniTraceBuilder::storeCInMemTrace(uint32_t addr, FF val) +void AvmMiniTraceBuilder::storeInMemTrace(IntermRegister intermReg, uint32_t addr, FF val, AvmMemoryTag m_in_tag) { - insertInMemTrace(static_cast(mainTrace.size()), SUB_CLK_STORE_C, addr, val, true); + uint32_t sub_clk = 0; + switch (intermReg) { + case IntermRegister::ia: + sub_clk = SUB_CLK_STORE_A; + break; + case IntermRegister::ib: + sub_clk = SUB_CLK_STORE_B; + break; + case IntermRegister::ic: + sub_clk = SUB_CLK_STORE_C; + break; + } + + insertInMemTrace(static_cast(mainTrace.size()), sub_clk, addr, val, m_in_tag, true); } -/** - * @brief Addition over finite field with direct memory access. +/** TODO: Implement for non finite field types + * @brief Addition with direct memory access. * - * @param aOffset An index in ffMemory pointing to the first operand of the addition. - * @param bOffset An index in ffMemory pointing to the second operand of the addition. - * @param dstOffset An index in ffMemory pointing to the output of the addition. + * @param aOffset An index in memory pointing to the first operand of the addition. + * @param bOffset An index in memory pointing to the second operand of the addition. + * @param dstOffset An index in memory pointing to the output of the addition. + * @param inTag The instruction memory tag of the operands. */ -void AvmMiniTraceBuilder::add(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset) +void AvmMiniTraceBuilder::add(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag) { // a + b = c - FF a = ffMemory.at(aOffset); - FF b = ffMemory.at(bOffset); + FF a = memory.at(aOffset); + FF b = memory.at(bOffset); FF c = a + b; - ffMemory.at(dstOffset) = c; - - auto clk = mainTrace.size(); + memory.at(dstOffset) = c; + memoryTag.at(dstOffset) = inTag; - // Loading into Ia - loadAInMemTrace(aOffset, a); + // Loading into Ia, Ib and storing into Ic + bool tagMatch = loadInMemTrace(IntermRegister::ia, aOffset, a, inTag); + tagMatch = loadInMemTrace(IntermRegister::ib, bOffset, b, inTag) && tagMatch; + storeInMemTrace(IntermRegister::ic, dstOffset, c, inTag); - // Loading into Ib - loadBInMemTrace(bOffset, b); - - // Storing from Ic - storeCInMemTrace(dstOffset, c); + auto clk = mainTrace.size(); mainTrace.push_back(Row{ .avmMini_clk = clk, .avmMini_sel_op_add = FF(1), - .avmMini_ia = a, - .avmMini_ib = b, - .avmMini_ic = c, + .avmMini_in_tag = FF(static_cast(inTag)), + .avmMini_tag_err = FF(static_cast(!tagMatch)), + .avmMini_ia = tagMatch ? a : FF(0), + .avmMini_ib = tagMatch ? b : FF(0), + .avmMini_ic = tagMatch ? c : FF(0), .avmMini_mem_op_a = FF(1), .avmMini_mem_op_b = FF(1), .avmMini_mem_op_c = FF(1), @@ -199,38 +207,38 @@ void AvmMiniTraceBuilder::add(uint32_t aOffset, uint32_t bOffset, uint32_t dstOf }); }; -/** - * @brief Subtraction over finite field with direct memory access. +/** TODO: Implement for non finite field types + * @brief Subtraction with direct memory access. * - * @param aOffset An index in ffMemory pointing to the first operand of the subtraction. - * @param bOffset An index in ffMemory pointing to the second operand of the subtraction. - * @param dstOffset An index in ffMemory pointing to the output of the subtraction. + * @param aOffset An index in memory pointing to the first operand of the subtraction. + * @param bOffset An index in memory pointing to the second operand of the subtraction. + * @param dstOffset An index in memory pointing to the output of the subtraction. + * @param inTag The instruction memory tag of the operands. */ -void AvmMiniTraceBuilder::sub(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset) +void AvmMiniTraceBuilder::sub(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag) { // a - b = c - FF a = ffMemory.at(aOffset); - FF b = ffMemory.at(bOffset); + FF a = memory.at(aOffset); + FF b = memory.at(bOffset); FF c = a - b; - ffMemory.at(dstOffset) = c; + memory.at(dstOffset) = c; + memoryTag.at(dstOffset) = inTag; - auto clk = mainTrace.size(); - - // Loading into Ia - loadAInMemTrace(aOffset, a); + // Loading into Ia, Ib and storing into Ic + bool tagMatch = loadInMemTrace(IntermRegister::ia, aOffset, a, inTag); + tagMatch = loadInMemTrace(IntermRegister::ib, bOffset, b, inTag) && tagMatch; + storeInMemTrace(IntermRegister::ic, dstOffset, c, inTag); - // Loading into Ib - loadBInMemTrace(bOffset, b); - - // Storing from Ic - storeCInMemTrace(dstOffset, c); + auto clk = mainTrace.size(); mainTrace.push_back(Row{ .avmMini_clk = clk, .avmMini_sel_op_sub = FF(1), - .avmMini_ia = a, - .avmMini_ib = b, - .avmMini_ic = c, + .avmMini_in_tag = FF(static_cast(inTag)), + .avmMini_tag_err = FF(static_cast(!tagMatch)), + .avmMini_ia = tagMatch ? a : FF(0), + .avmMini_ib = tagMatch ? b : FF(0), + .avmMini_ic = tagMatch ? c : FF(0), .avmMini_mem_op_a = FF(1), .avmMini_mem_op_b = FF(1), .avmMini_mem_op_c = FF(1), @@ -241,38 +249,38 @@ void AvmMiniTraceBuilder::sub(uint32_t aOffset, uint32_t bOffset, uint32_t dstOf }); }; -/** - * @brief Multiplication over finite field with direct memory access. +/** TODO: Implement for non finite field types + * @brief Multiplication with direct memory access. * - * @param aOffset An index in ffMemory pointing to the first operand of the multiplication. - * @param bOffset An index in ffMemory pointing to the second operand of the multiplication. - * @param dstOffset An index in ffMemory pointing to the output of the multiplication. + * @param aOffset An index in memory pointing to the first operand of the multiplication. + * @param bOffset An index in memory pointing to the second operand of the multiplication. + * @param dstOffset An index in memory pointing to the output of the multiplication. + * @param inTag The instruction memory tag of the operands. */ -void AvmMiniTraceBuilder::mul(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset) +void AvmMiniTraceBuilder::mul(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag) { // a * b = c - FF a = ffMemory.at(aOffset); - FF b = ffMemory.at(bOffset); + FF a = memory.at(aOffset); + FF b = memory.at(bOffset); FF c = a * b; - ffMemory.at(dstOffset) = c; - - auto clk = mainTrace.size(); + memory.at(dstOffset) = c; + memoryTag.at(dstOffset) = inTag; - // Loading into Ia - loadAInMemTrace(aOffset, a); + // Loading into Ia, Ib and storing into Ic + bool tagMatch = loadInMemTrace(IntermRegister::ia, aOffset, a, inTag); + tagMatch = loadInMemTrace(IntermRegister::ib, bOffset, b, inTag) && tagMatch; + storeInMemTrace(IntermRegister::ic, dstOffset, c, inTag); - // Loading into Ib - loadBInMemTrace(bOffset, b); - - // Storing from Ic - storeCInMemTrace(dstOffset, c); + auto clk = mainTrace.size(); mainTrace.push_back(Row{ .avmMini_clk = clk, .avmMini_sel_op_mul = FF(1), - .avmMini_ia = a, - .avmMini_ib = b, - .avmMini_ic = c, + .avmMini_in_tag = FF(static_cast(inTag)), + .avmMini_tag_err = FF(static_cast(!tagMatch)), + .avmMini_ia = tagMatch ? a : FF(0), + .avmMini_ib = tagMatch ? b : FF(0), + .avmMini_ic = tagMatch ? c : FF(0), .avmMini_mem_op_a = FF(1), .avmMini_mem_op_b = FF(1), .avmMini_mem_op_c = FF(1), @@ -283,18 +291,19 @@ void AvmMiniTraceBuilder::mul(uint32_t aOffset, uint32_t bOffset, uint32_t dstOf }); } -/** - * @brief Division over finite field with direct memory access. +/** TODO: Implement for non finite field types + * @brief Division with direct memory access. * - * @param aOffset An index in ffMemory pointing to the first operand of the division. - * @param bOffset An index in ffMemory pointing to the second operand of the division. - * @param dstOffset An index in ffMemory pointing to the output of the division. + * @param aOffset An index in memory pointing to the first operand of the division. + * @param bOffset An index in memory pointing to the second operand of the division. + * @param dstOffset An index in memory pointing to the output of the division. + * @param inTag The instruction memory tag of the operands. */ -void AvmMiniTraceBuilder::div(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset) +void AvmMiniTraceBuilder::div(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag) { // a * b^(-1) = c - FF a = ffMemory.at(aOffset); - FF b = ffMemory.at(bOffset); + FF a = memory.at(aOffset); + FF b = memory.at(bOffset); FF c; FF inv; FF error; @@ -310,27 +319,26 @@ void AvmMiniTraceBuilder::div(uint32_t aOffset, uint32_t bOffset, uint32_t dstOf error = 1; } - ffMemory.at(dstOffset) = c; + memory.at(dstOffset) = c; + memoryTag.at(dstOffset) = inTag; - auto clk = mainTrace.size(); + // Loading into Ia, Ib and storing into Ic + bool tagMatch = loadInMemTrace(IntermRegister::ia, aOffset, a, inTag); + tagMatch = loadInMemTrace(IntermRegister::ib, bOffset, b, inTag) && tagMatch; + storeInMemTrace(IntermRegister::ic, dstOffset, c, inTag); - // Loading into Ia - loadAInMemTrace(aOffset, a); - - // Loading into Ib - loadBInMemTrace(bOffset, b); - - // Storing from Ic - storeCInMemTrace(dstOffset, c); + auto clk = mainTrace.size(); mainTrace.push_back(Row{ .avmMini_clk = clk, .avmMini_sel_op_div = FF(1), - .avmMini_op_err = error, - .avmMini_inv = inv, - .avmMini_ia = a, - .avmMini_ib = b, - .avmMini_ic = c, + .avmMini_in_tag = FF(static_cast(inTag)), + .avmMini_op_err = tagMatch ? error : FF(1), + .avmMini_tag_err = FF(static_cast(!tagMatch)), + .avmMini_inv = tagMatch ? inv : FF(1), + .avmMini_ia = tagMatch ? a : FF(0), + .avmMini_ib = tagMatch ? b : FF(0), + .avmMini_ic = tagMatch ? c : FF(0), .avmMini_mem_op_a = FF(1), .avmMini_mem_op_b = FF(1), .avmMini_mem_op_c = FF(1), @@ -389,8 +397,9 @@ void AvmMiniTraceBuilder::callDataCopy(uint32_t cdOffset, uint32_t rwa = 1; // Storing from Ia - ffMemory.at(mem_idx_a) = ia; - storeAInMemTrace(mem_idx_a, ia); + memory.at(mem_idx_a) = ia; + memoryTag.at(mem_idx_a) = AvmMemoryTag::ff; + storeInMemTrace(IntermRegister::ia, mem_idx_a, ia, AvmMemoryTag::ff); if (copySize - pos > 1) { ib = callDataMem.at(cdOffset + pos + 1); @@ -399,8 +408,9 @@ void AvmMiniTraceBuilder::callDataCopy(uint32_t cdOffset, rwb = 1; // Storing from Ib - ffMemory.at(mem_idx_b) = ib; - storeBInMemTrace(mem_idx_b, ib); + memory.at(mem_idx_b) = ib; + memoryTag.at(mem_idx_b) = AvmMemoryTag::ff; + storeInMemTrace(IntermRegister::ib, mem_idx_b, ib, AvmMemoryTag::ff); } if (copySize - pos > 2) { @@ -410,12 +420,14 @@ void AvmMiniTraceBuilder::callDataCopy(uint32_t cdOffset, rwc = 1; // Storing from Ic - ffMemory.at(mem_idx_c) = ic; - storeCInMemTrace(mem_idx_c, ic); + memory.at(mem_idx_c) = ic; + memoryTag.at(mem_idx_c) = AvmMemoryTag::ff; + storeInMemTrace(IntermRegister::ic, mem_idx_c, ic, AvmMemoryTag::ff); } mainTrace.push_back(Row{ .avmMini_clk = clk, + .avmMini_in_tag = FF(static_cast(AvmMemoryTag::ff)), .avmMini_ia = ia, .avmMini_ib = ib, .avmMini_ic = ic, @@ -474,34 +486,35 @@ std::vector AvmMiniTraceBuilder::returnOP(uint32_t retOffset, uint32_t retSi uint32_t mem_op_a(1); uint32_t mem_idx_a = retOffset + pos; - FF ia = ffMemory.at(mem_idx_a); + FF ia = memory.at(mem_idx_a); // Loading from Ia returnMem.push_back(ia); - loadAInMemTrace(mem_idx_a, ia); + loadInMemTrace(IntermRegister::ia, mem_idx_a, ia, AvmMemoryTag::ff); if (retSize - pos > 1) { mem_op_b = 1; mem_idx_b = retOffset + pos + 1; - ib = ffMemory.at(mem_idx_b); + ib = memory.at(mem_idx_b); // Loading from Ib returnMem.push_back(ib); - loadBInMemTrace(mem_idx_b, ib); + loadInMemTrace(IntermRegister::ib, mem_idx_b, ib, AvmMemoryTag::ff); } if (retSize - pos > 2) { mem_op_c = 1; mem_idx_c = retOffset + pos + 2; - ic = ffMemory.at(mem_idx_c); + ic = memory.at(mem_idx_c); // Loading from Ic returnMem.push_back(ic); - loadCInMemTrace(mem_idx_c, ic); + loadInMemTrace(IntermRegister::ic, mem_idx_c, ic, AvmMemoryTag::ff); } mainTrace.push_back(Row{ .avmMini_clk = clk, + .avmMini_in_tag = FF(static_cast(AvmMemoryTag::ff)), .avmMini_ia = ia, .avmMini_ib = ib, .avmMini_ic = ic, @@ -523,12 +536,13 @@ std::vector AvmMiniTraceBuilder::returnOP(uint32_t retOffset, uint32_t retSi } /** - * @brief Helper to initialize ffMemory. (Testing purpose mostly.) + * @brief Helper to initialize memory. (Testing purpose mostly.) * */ -void AvmMiniTraceBuilder::setFFMem(size_t idx, FF el) +void AvmMiniTraceBuilder::setFFMem(size_t idx, FF el, AvmMemoryTag tag) { - ffMemory.at(idx) = el; + memory.at(idx) = el; + memoryTag.at(idx) = tag; }; /** @@ -559,8 +573,7 @@ std::vector AvmMiniTraceBuilder::finalize() mainTrace.push_back(Row{}); } - size_t lastIndex = (memTraceSize > mainTraceSize) ? memTraceSize - 1 : mainTraceSize - 1; - mainTrace.at(lastIndex).avmMini_last = FF(1); + mainTrace.at(mainTraceSize - 1).avmMini_last = FF(1); for (size_t i = 0; i < memTraceSize; i++) { auto const& src = memTrace.at(i); @@ -571,17 +584,22 @@ std::vector AvmMiniTraceBuilder::finalize() dest.memTrace_m_addr = FF(src.m_addr); dest.memTrace_m_val = src.m_val; dest.memTrace_m_rw = FF(static_cast(src.m_rw)); + dest.memTrace_m_in_tag = FF(static_cast(src.m_in_tag)); + dest.memTrace_m_tag = FF(static_cast(src.m_tag)); + dest.memTrace_m_tag_err = FF(static_cast(src.m_tag_err)); + dest.memTrace_m_one_min_inv = src.m_one_min_inv; if (i + 1 < memTraceSize) { auto const& next = memTrace.at(i + 1); dest.memTrace_m_lastAccess = FF(static_cast(src.m_addr != next.m_addr)); } else { dest.memTrace_m_lastAccess = FF(1); + dest.memTrace_m_last = FF(1); } } // Adding extra row for the shifted values at the top of the execution trace. - Row first_row = Row{ .avmMini_first = 1 }; + Row first_row = Row{ .avmMini_first = FF(1), .memTrace_m_lastAccess = FF(1) }; mainTrace.insert(mainTrace.begin(), first_row); return std::move(mainTrace); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp index a4621c22e19..5f5f7e8353d 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp @@ -15,6 +15,9 @@ using Row = proof_system::AvmMiniFullRow; namespace proof_system { +enum class IntermRegister : uint32_t { ia = 0, ib = 1, ic = 2 }; +enum class AvmMemoryTag : uint32_t { u0 = 0, u8 = 1, u16 = 2, u32 = 3, u64 = 4, u128 = 5, ff = 6 }; + // This is the internal context that we keep along the lifecycle of bytecode execution // to iteratively build the whole trace. This is effectively performing witness generation. // At the end of circuit building, mainTrace can be moved to AvmMiniCircuitBuilder by calling @@ -36,22 +39,22 @@ class AvmMiniTraceBuilder { AvmMiniTraceBuilder(); // Temporary helper to initialize memory. - void setFFMem(size_t idx, FF el); + void setFFMem(size_t idx, FF el, AvmMemoryTag tag); std::vector finalize(); void reset(); - // Addition over finite field with direct memory access. - void add(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset); + // Addition with direct memory access. + void add(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag); - // Subtraction over finite field with direct memory access. - void sub(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset); + // Subtraction with direct memory access. + void sub(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag); - // Multiplication over finite field with direct memory access. - void mul(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset); + // Multiplication with direct memory access. + void mul(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag); - // Division over finite field with direct memory access. - void div(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset); + // Division with direct memory access. + void div(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag); // CALLDATACOPY opcode with direct memory access, i.e., // M[dstOffset:dstOffset+copySize] = calldata[cdOffset:cdOffset+copySize] @@ -66,22 +69,26 @@ class AvmMiniTraceBuilder { uint32_t m_clk; uint32_t m_sub_clk; uint32_t m_addr; - FF m_val; - bool m_rw; + FF m_val{}; + AvmMemoryTag m_tag; + AvmMemoryTag m_in_tag; + bool m_rw = false; + bool m_tag_err = false; + FF m_one_min_inv{}; }; std::vector mainTrace; - std::vector memTrace; // Entries will be sorted by m_clk, m_sub_clk after finalize(). - std::array ffMemory{}; // Memory table for finite field elements - // Used for simulation of memory table + std::vector memTrace; // Entries will be sorted by m_clk, m_sub_clk after finalize(). + std::array memory{}; // Memory table (used for simulation) + std::array memoryTag{}; // The tag of the corresponding memory + // entry (aligned with the memory array). static bool compareMemEntries(const MemoryTraceEntry& left, const MemoryTraceEntry& right); - void insertInMemTrace(uint32_t m_clk, uint32_t m_sub_clk, uint32_t m_addr, FF m_val, bool m_rw); - void loadAInMemTrace(uint32_t addr, FF val); - void loadBInMemTrace(uint32_t addr, FF val); - void loadCInMemTrace(uint32_t addr, FF val); - void storeAInMemTrace(uint32_t addr, FF val); - void storeBInMemTrace(uint32_t addr, FF val); - void storeCInMemTrace(uint32_t addr, FF val); + void insertInMemTrace( + uint32_t m_clk, uint32_t m_sub_clk, uint32_t m_addr, FF m_val, AvmMemoryTag m_in_tag, bool m_rw); + void loadMismatchTagInMemTrace( + uint32_t m_clk, uint32_t m_sub_clk, uint32_t m_addr, FF m_val, AvmMemoryTag m_in_tag, AvmMemoryTag m_tag); + bool loadInMemTrace(IntermRegister intermReg, uint32_t addr, FF val, AvmMemoryTag m_in_tag); + void storeInMemTrace(IntermRegister intermReg, uint32_t addr, FF val, AvmMemoryTag m_in_tag); }; } // namespace proof_system diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp index fbcba45b8f5..02aaed70a5a 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp @@ -24,14 +24,21 @@ template struct AvmMiniFullRow { FF memTrace_m_clk{}; FF memTrace_m_sub_clk{}; FF memTrace_m_addr{}; + FF memTrace_m_tag{}; FF memTrace_m_val{}; FF memTrace_m_lastAccess{}; + FF memTrace_m_last{}; FF memTrace_m_rw{}; + FF memTrace_m_in_tag{}; + FF memTrace_m_tag_err{}; + FF memTrace_m_one_min_inv{}; FF avmMini_sel_op_add{}; FF avmMini_sel_op_sub{}; FF avmMini_sel_op_mul{}; FF avmMini_sel_op_div{}; + FF avmMini_in_tag{}; FF avmMini_op_err{}; + FF avmMini_tag_err{}; FF avmMini_inv{}; FF avmMini_ia{}; FF avmMini_ib{}; @@ -46,9 +53,10 @@ template struct AvmMiniFullRow { FF avmMini_mem_idx_b{}; FF avmMini_mem_idx_c{}; FF avmMini_last{}; - FF memTrace_m_rw_shift{}; - FF memTrace_m_addr_shift{}; FF memTrace_m_val_shift{}; + FF memTrace_m_addr_shift{}; + FF memTrace_m_rw_shift{}; + FF memTrace_m_tag_shift{}; }; class AvmMiniCircuitBuilder { @@ -61,8 +69,8 @@ class AvmMiniCircuitBuilder { using Polynomial = Flavor::Polynomial; using ProverPolynomials = Flavor::ProverPolynomials; - static constexpr size_t num_fixed_columns = 30; - static constexpr size_t num_polys = 27; + static constexpr size_t num_fixed_columns = 38; + static constexpr size_t num_polys = 34; std::vector rows; void set_trace(std::vector&& trace) { rows = std::move(trace); } @@ -83,14 +91,21 @@ class AvmMiniCircuitBuilder { polys.memTrace_m_clk[i] = rows[i].memTrace_m_clk; polys.memTrace_m_sub_clk[i] = rows[i].memTrace_m_sub_clk; polys.memTrace_m_addr[i] = rows[i].memTrace_m_addr; + polys.memTrace_m_tag[i] = rows[i].memTrace_m_tag; polys.memTrace_m_val[i] = rows[i].memTrace_m_val; polys.memTrace_m_lastAccess[i] = rows[i].memTrace_m_lastAccess; + polys.memTrace_m_last[i] = rows[i].memTrace_m_last; polys.memTrace_m_rw[i] = rows[i].memTrace_m_rw; + polys.memTrace_m_in_tag[i] = rows[i].memTrace_m_in_tag; + polys.memTrace_m_tag_err[i] = rows[i].memTrace_m_tag_err; + polys.memTrace_m_one_min_inv[i] = rows[i].memTrace_m_one_min_inv; polys.avmMini_sel_op_add[i] = rows[i].avmMini_sel_op_add; polys.avmMini_sel_op_sub[i] = rows[i].avmMini_sel_op_sub; polys.avmMini_sel_op_mul[i] = rows[i].avmMini_sel_op_mul; polys.avmMini_sel_op_div[i] = rows[i].avmMini_sel_op_div; + polys.avmMini_in_tag[i] = rows[i].avmMini_in_tag; polys.avmMini_op_err[i] = rows[i].avmMini_op_err; + polys.avmMini_tag_err[i] = rows[i].avmMini_tag_err; polys.avmMini_inv[i] = rows[i].avmMini_inv; polys.avmMini_ia[i] = rows[i].avmMini_ia; polys.avmMini_ib[i] = rows[i].avmMini_ib; @@ -107,19 +122,22 @@ class AvmMiniCircuitBuilder { polys.avmMini_last[i] = rows[i].avmMini_last; } - polys.memTrace_m_rw_shift = Polynomial(polys.memTrace_m_rw.shifted()); - polys.memTrace_m_addr_shift = Polynomial(polys.memTrace_m_addr.shifted()); polys.memTrace_m_val_shift = Polynomial(polys.memTrace_m_val.shifted()); + polys.memTrace_m_addr_shift = Polynomial(polys.memTrace_m_addr.shifted()); + polys.memTrace_m_rw_shift = Polynomial(polys.memTrace_m_rw.shifted()); + polys.memTrace_m_tag_shift = Polynomial(polys.memTrace_m_tag.shifted()); return polys; } [[maybe_unused]] bool check_circuit() { - ProverPolynomials polys = compute_polynomials(); + + auto polys = compute_polynomials(); const size_t num_rows = polys.get_polynomial_size(); - const auto evaluate_relation = [&](const std::string& relation_name) { + const auto evaluate_relation = [&](const std::string& relation_name, + std::string (*debug_label)(int)) { typename Relation::SumcheckArrayOfValuesOverSubrelations result; for (auto& r : result) { r = 0; @@ -132,8 +150,9 @@ class AvmMiniCircuitBuilder { bool x = true; for (size_t j = 0; j < NUM_SUBRELATIONS; ++j) { if (result[j] != 0) { + std::string row_name = debug_label(static_cast(j)); throw_or_abort( - format("Relation ", relation_name, ", subrelation index ", j, " failed at row ", i)); + format("Relation ", relation_name, ", subrelation index ", row_name, " failed at row ", i)); x = false; } } @@ -144,10 +163,12 @@ class AvmMiniCircuitBuilder { return true; }; - if (!evaluate_relation.template operator()>("mem_trace")) { + if (!evaluate_relation.template operator()>( + "mem_trace", AvmMini_vm::get_relation_label_mem_trace)) { return false; } - if (!evaluate_relation.template operator()>("avm_mini")) { + if (!evaluate_relation.template operator()>("avm_mini", + AvmMini_vm::get_relation_label_avm_mini)) { return false; } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp index bb4a3242ae0..d590365b76a 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp @@ -7,29 +7,57 @@ namespace proof_system::AvmMini_vm { template struct Avm_miniRow { - FF avmMini_sel_op_div{}; - FF avmMini_ia{}; - FF avmMini_rwa{}; FF avmMini_sel_op_sub{}; - FF avmMini_rwb{}; + FF avmMini_rwa{}; FF avmMini_ic{}; - FF avmMini_inv{}; - FF avmMini_sel_op_add{}; FF avmMini_op_err{}; + FF avmMini_rwb{}; + FF avmMini_ia{}; + FF avmMini_inv{}; + FF avmMini_sel_op_div{}; + FF avmMini_tag_err{}; FF avmMini_sel_op_mul{}; + FF avmMini_sel_op_add{}; + FF avmMini_mem_op_c{}; FF avmMini_rwc{}; FF avmMini_ib{}; - FF avmMini_mem_op_b{}; FF avmMini_mem_op_a{}; - FF avmMini_mem_op_c{}; + FF avmMini_mem_op_b{}; }; +inline std::string get_relation_label_avm_mini(int index) +{ + switch (index) { + case 18: + return "SUBOP_DIVISION_FF"; + + case 17: + return "SUBOP_MULTIPLICATION_FF"; + + case 16: + return "SUBOP_SUBTRACTION_FF"; + + case 19: + return "SUBOP_DIVISION_ZERO_ERR1"; + + case 20: + return "SUBOP_DIVISION_ZERO_ERR2"; + + case 21: + return "SUBOP_ERROR_RELEVANT_OP"; + + case 15: + return "SUBOP_ADDITION_FF"; + } + return std::to_string(index); +} + template class avm_miniImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 3, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4, 3, }; template @@ -83,7 +111,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(5); - auto tmp = (avmMini_mem_op_a * (-avmMini_mem_op_a + FF(1))); + auto tmp = (avmMini_tag_err * (-avmMini_tag_err + FF(1))); tmp *= scaling_factor; std::get<5>(evals) += tmp; } @@ -91,7 +119,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(6); - auto tmp = (avmMini_mem_op_b * (-avmMini_mem_op_b + FF(1))); + auto tmp = (avmMini_mem_op_a * (-avmMini_mem_op_a + FF(1))); tmp *= scaling_factor; std::get<6>(evals) += tmp; } @@ -99,7 +127,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(7); - auto tmp = (avmMini_mem_op_c * (-avmMini_mem_op_c + FF(1))); + auto tmp = (avmMini_mem_op_b * (-avmMini_mem_op_b + FF(1))); tmp *= scaling_factor; std::get<7>(evals) += tmp; } @@ -107,7 +135,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(8); - auto tmp = (avmMini_rwa * (-avmMini_rwa + FF(1))); + auto tmp = (avmMini_mem_op_c * (-avmMini_mem_op_c + FF(1))); tmp *= scaling_factor; std::get<8>(evals) += tmp; } @@ -115,7 +143,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(9); - auto tmp = (avmMini_rwb * (-avmMini_rwb + FF(1))); + auto tmp = (avmMini_rwa * (-avmMini_rwa + FF(1))); tmp *= scaling_factor; std::get<9>(evals) += tmp; } @@ -123,7 +151,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(10); - auto tmp = (avmMini_rwc * (-avmMini_rwc + FF(1))); + auto tmp = (avmMini_rwb * (-avmMini_rwb + FF(1))); tmp *= scaling_factor; std::get<10>(evals) += tmp; } @@ -131,7 +159,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(11); - auto tmp = (avmMini_sel_op_add * ((avmMini_ia + avmMini_ib) - avmMini_ic)); + auto tmp = (avmMini_rwc * (-avmMini_rwc + FF(1))); tmp *= scaling_factor; std::get<11>(evals) += tmp; } @@ -139,7 +167,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(12); - auto tmp = (avmMini_sel_op_sub * ((avmMini_ia - avmMini_ib) - avmMini_ic)); + auto tmp = (avmMini_tag_err * avmMini_ia); tmp *= scaling_factor; std::get<12>(evals) += tmp; } @@ -147,7 +175,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(13); - auto tmp = (avmMini_sel_op_mul * ((avmMini_ia * avmMini_ib) - avmMini_ic)); + auto tmp = (avmMini_tag_err * avmMini_ib); tmp *= scaling_factor; std::get<13>(evals) += tmp; } @@ -155,7 +183,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(14); - auto tmp = ((avmMini_sel_op_div * (-avmMini_op_err + FF(1))) * ((avmMini_ic * avmMini_ib) - avmMini_ia)); + auto tmp = (avmMini_tag_err * avmMini_ic); tmp *= scaling_factor; std::get<14>(evals) += tmp; } @@ -163,7 +191,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(15); - auto tmp = (avmMini_sel_op_div * (((avmMini_ib * avmMini_inv) - FF(1)) + avmMini_op_err)); + auto tmp = (avmMini_sel_op_add * ((avmMini_ia + avmMini_ib) - avmMini_ic)); tmp *= scaling_factor; std::get<15>(evals) += tmp; } @@ -171,7 +199,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(16); - auto tmp = ((avmMini_sel_op_div * avmMini_op_err) * (-avmMini_inv + FF(1))); + auto tmp = (avmMini_sel_op_sub * ((avmMini_ia - avmMini_ib) - avmMini_ic)); tmp *= scaling_factor; std::get<16>(evals) += tmp; } @@ -179,10 +207,42 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(17); - auto tmp = (avmMini_op_err * (avmMini_sel_op_div - FF(1))); + auto tmp = (avmMini_sel_op_mul * ((avmMini_ia * avmMini_ib) - avmMini_ic)); tmp *= scaling_factor; std::get<17>(evals) += tmp; } + // Contribution 18 + { + AvmMini_DECLARE_VIEWS(18); + + auto tmp = ((avmMini_sel_op_div * (-avmMini_op_err + FF(1))) * ((avmMini_ic * avmMini_ib) - avmMini_ia)); + tmp *= scaling_factor; + std::get<18>(evals) += tmp; + } + // Contribution 19 + { + AvmMini_DECLARE_VIEWS(19); + + auto tmp = (avmMini_sel_op_div * (((avmMini_ib * avmMini_inv) - FF(1)) + avmMini_op_err)); + tmp *= scaling_factor; + std::get<19>(evals) += tmp; + } + // Contribution 20 + { + AvmMini_DECLARE_VIEWS(20); + + auto tmp = ((avmMini_sel_op_div * avmMini_op_err) * (-avmMini_inv + FF(1))); + tmp *= scaling_factor; + std::get<20>(evals) += tmp; + } + // Contribution 21 + { + AvmMini_DECLARE_VIEWS(21); + + auto tmp = (avmMini_op_err * (avmMini_sel_op_div - FF(1))); + tmp *= scaling_factor; + std::get<21>(evals) += tmp; + } } }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp index e2abc409ea4..9d23bb0f8f1 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp @@ -7,14 +7,21 @@ [[maybe_unused]] auto memTrace_m_clk = View(new_term.memTrace_m_clk); \ [[maybe_unused]] auto memTrace_m_sub_clk = View(new_term.memTrace_m_sub_clk); \ [[maybe_unused]] auto memTrace_m_addr = View(new_term.memTrace_m_addr); \ + [[maybe_unused]] auto memTrace_m_tag = View(new_term.memTrace_m_tag); \ [[maybe_unused]] auto memTrace_m_val = View(new_term.memTrace_m_val); \ [[maybe_unused]] auto memTrace_m_lastAccess = View(new_term.memTrace_m_lastAccess); \ + [[maybe_unused]] auto memTrace_m_last = View(new_term.memTrace_m_last); \ [[maybe_unused]] auto memTrace_m_rw = View(new_term.memTrace_m_rw); \ + [[maybe_unused]] auto memTrace_m_in_tag = View(new_term.memTrace_m_in_tag); \ + [[maybe_unused]] auto memTrace_m_tag_err = View(new_term.memTrace_m_tag_err); \ + [[maybe_unused]] auto memTrace_m_one_min_inv = View(new_term.memTrace_m_one_min_inv); \ [[maybe_unused]] auto avmMini_sel_op_add = View(new_term.avmMini_sel_op_add); \ [[maybe_unused]] auto avmMini_sel_op_sub = View(new_term.avmMini_sel_op_sub); \ [[maybe_unused]] auto avmMini_sel_op_mul = View(new_term.avmMini_sel_op_mul); \ [[maybe_unused]] auto avmMini_sel_op_div = View(new_term.avmMini_sel_op_div); \ + [[maybe_unused]] auto avmMini_in_tag = View(new_term.avmMini_in_tag); \ [[maybe_unused]] auto avmMini_op_err = View(new_term.avmMini_op_err); \ + [[maybe_unused]] auto avmMini_tag_err = View(new_term.avmMini_tag_err); \ [[maybe_unused]] auto avmMini_inv = View(new_term.avmMini_inv); \ [[maybe_unused]] auto avmMini_ia = View(new_term.avmMini_ia); \ [[maybe_unused]] auto avmMini_ib = View(new_term.avmMini_ib); \ @@ -29,6 +36,7 @@ [[maybe_unused]] auto avmMini_mem_idx_b = View(new_term.avmMini_mem_idx_b); \ [[maybe_unused]] auto avmMini_mem_idx_c = View(new_term.avmMini_mem_idx_c); \ [[maybe_unused]] auto avmMini_last = View(new_term.avmMini_last); \ - [[maybe_unused]] auto memTrace_m_rw_shift = View(new_term.memTrace_m_rw_shift); \ + [[maybe_unused]] auto memTrace_m_val_shift = View(new_term.memTrace_m_val_shift); \ [[maybe_unused]] auto memTrace_m_addr_shift = View(new_term.memTrace_m_addr_shift); \ - [[maybe_unused]] auto memTrace_m_val_shift = View(new_term.memTrace_m_val_shift); + [[maybe_unused]] auto memTrace_m_rw_shift = View(new_term.memTrace_m_rw_shift); \ + [[maybe_unused]] auto memTrace_m_tag_shift = View(new_term.memTrace_m_tag_shift); diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp index 7bfb1b223cd..9880acfa631 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp @@ -7,26 +7,51 @@ namespace proof_system::AvmMini_vm { template struct Mem_traceRow { - FF memTrace_m_rw_shift{}; + FF memTrace_m_rw{}; + FF memTrace_m_addr{}; + FF memTrace_m_val_shift{}; + FF memTrace_m_last{}; + FF memTrace_m_tag_err{}; FF memTrace_m_addr_shift{}; FF memTrace_m_val{}; - FF memTrace_m_addr{}; - FF memTrace_m_rw{}; - FF avmMini_first{}; FF memTrace_m_lastAccess{}; - FF avmMini_last{}; - FF memTrace_m_val_shift{}; + FF memTrace_m_tag{}; + FF memTrace_m_in_tag{}; + FF memTrace_m_rw_shift{}; + FF memTrace_m_one_min_inv{}; + FF memTrace_m_tag_shift{}; }; +inline std::string get_relation_label_mem_trace(int index) +{ + switch (index) { + case 4: + return "MEM_LAST_ACCESS_DELIMITER"; + + case 6: + return "MEM_READ_WRITE_TAG_CONSISTENCY"; + + case 9: + return "MEM_IN_TAG_CONSISTENCY_2"; + + case 5: + return "MEM_READ_WRITE_VAL_CONSISTENCY"; + + case 7: + return "MEM_ZERO_INIT"; + + case 8: + return "MEM_IN_TAG_CONSISTENCY_1"; + } + return std::to_string(index); +} + template class mem_traceImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, - 3, - 4, - 6, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, }; template @@ -48,7 +73,7 @@ template class mem_traceImpl { { AvmMini_DECLARE_VIEWS(1); - auto tmp = (memTrace_m_rw * (-memTrace_m_rw + FF(1))); + auto tmp = (memTrace_m_last * (-memTrace_m_last + FF(1))); tmp *= scaling_factor; std::get<1>(evals) += tmp; } @@ -56,8 +81,7 @@ template class mem_traceImpl { { AvmMini_DECLARE_VIEWS(2); - auto tmp = (((-avmMini_first + FF(1)) * (-memTrace_m_lastAccess + FF(1))) * - (memTrace_m_addr_shift - memTrace_m_addr)); + auto tmp = (memTrace_m_rw * (-memTrace_m_rw + FF(1))); tmp *= scaling_factor; std::get<2>(evals) += tmp; } @@ -65,12 +89,61 @@ template class mem_traceImpl { { AvmMini_DECLARE_VIEWS(3); - auto tmp = (((((-avmMini_first + FF(1)) * (-avmMini_last + FF(1))) * (-memTrace_m_lastAccess + FF(1))) * - (-memTrace_m_rw_shift + FF(1))) * - (memTrace_m_val_shift - memTrace_m_val)); + auto tmp = (memTrace_m_tag_err * (-memTrace_m_tag_err + FF(1))); tmp *= scaling_factor; std::get<3>(evals) += tmp; } + // Contribution 4 + { + AvmMini_DECLARE_VIEWS(4); + + auto tmp = ((-memTrace_m_lastAccess + FF(1)) * (memTrace_m_addr_shift - memTrace_m_addr)); + tmp *= scaling_factor; + std::get<4>(evals) += tmp; + } + // Contribution 5 + { + AvmMini_DECLARE_VIEWS(5); + + auto tmp = (((-memTrace_m_lastAccess + FF(1)) * (-memTrace_m_rw_shift + FF(1))) * + (memTrace_m_val_shift - memTrace_m_val)); + tmp *= scaling_factor; + std::get<5>(evals) += tmp; + } + // Contribution 6 + { + AvmMini_DECLARE_VIEWS(6); + + auto tmp = (((-memTrace_m_lastAccess + FF(1)) * (-memTrace_m_rw_shift + FF(1))) * + (memTrace_m_tag_shift - memTrace_m_tag)); + tmp *= scaling_factor; + std::get<6>(evals) += tmp; + } + // Contribution 7 + { + AvmMini_DECLARE_VIEWS(7); + + auto tmp = ((memTrace_m_lastAccess * (-memTrace_m_rw_shift + FF(1))) * memTrace_m_val_shift); + tmp *= scaling_factor; + std::get<7>(evals) += tmp; + } + // Contribution 8 + { + AvmMini_DECLARE_VIEWS(8); + + auto tmp = + (((memTrace_m_in_tag - memTrace_m_tag) * (-memTrace_m_one_min_inv + FF(1))) - memTrace_m_tag_err); + tmp *= scaling_factor; + std::get<8>(evals) += tmp; + } + // Contribution 9 + { + AvmMini_DECLARE_VIEWS(9); + + auto tmp = ((-memTrace_m_tag_err + FF(1)) * memTrace_m_one_min_inv); + tmp *= scaling_factor; + std::get<9>(evals) += tmp; + } } }; diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp index 4014eec57bb..ff07a075419 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp @@ -60,10 +60,19 @@ bool AvmMiniVerifier::verify_proof(const plonk::proof& proof) transcript->template receive_from_prover(commitment_labels.memTrace_m_sub_clk); commitments.memTrace_m_addr = transcript->template receive_from_prover(commitment_labels.memTrace_m_addr); + commitments.memTrace_m_tag = transcript->template receive_from_prover(commitment_labels.memTrace_m_tag); commitments.memTrace_m_val = transcript->template receive_from_prover(commitment_labels.memTrace_m_val); commitments.memTrace_m_lastAccess = transcript->template receive_from_prover(commitment_labels.memTrace_m_lastAccess); + commitments.memTrace_m_last = + transcript->template receive_from_prover(commitment_labels.memTrace_m_last); commitments.memTrace_m_rw = transcript->template receive_from_prover(commitment_labels.memTrace_m_rw); + commitments.memTrace_m_in_tag = + transcript->template receive_from_prover(commitment_labels.memTrace_m_in_tag); + commitments.memTrace_m_tag_err = + transcript->template receive_from_prover(commitment_labels.memTrace_m_tag_err); + commitments.memTrace_m_one_min_inv = + transcript->template receive_from_prover(commitment_labels.memTrace_m_one_min_inv); commitments.avmMini_sel_op_add = transcript->template receive_from_prover(commitment_labels.avmMini_sel_op_add); commitments.avmMini_sel_op_sub = @@ -72,7 +81,10 @@ bool AvmMiniVerifier::verify_proof(const plonk::proof& proof) transcript->template receive_from_prover(commitment_labels.avmMini_sel_op_mul); commitments.avmMini_sel_op_div = transcript->template receive_from_prover(commitment_labels.avmMini_sel_op_div); + commitments.avmMini_in_tag = transcript->template receive_from_prover(commitment_labels.avmMini_in_tag); commitments.avmMini_op_err = transcript->template receive_from_prover(commitment_labels.avmMini_op_err); + commitments.avmMini_tag_err = + transcript->template receive_from_prover(commitment_labels.avmMini_tag_err); commitments.avmMini_inv = transcript->template receive_from_prover(commitment_labels.avmMini_inv); commitments.avmMini_ia = transcript->template receive_from_prover(commitment_labels.avmMini_ia); commitments.avmMini_ib = transcript->template receive_from_prover(commitment_labels.avmMini_ib); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp index 1a94d54816e..ad7b4342469 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp @@ -7,6 +7,7 @@ #include "barretenberg/vm/generated/AvmMini_composer.hpp" #include "barretenberg/vm/generated/AvmMini_prover.hpp" #include "barretenberg/vm/generated/AvmMini_verifier.hpp" +#include "helpers.test.hpp" #include #include @@ -33,67 +34,6 @@ class AvmMiniArithmeticTests : public ::testing::Test { class AvmMiniArithmeticNegativeTests : public AvmMiniArithmeticTests {}; -// We add some helper functions in the anonymous namespace. -namespace { - -/** - * @brief Helper routine proving and verifying a proof based on the supplied trace - * - * @param trace The execution trace - */ -void validateTraceProof(std::vector&& trace) -{ - auto circuit_builder = AvmMiniCircuitBuilder(); - circuit_builder.set_trace(std::move(trace)); - - EXPECT_TRUE(circuit_builder.check_circuit()); - - auto composer = honk::AvmMiniComposer(); - auto prover = composer.create_prover(circuit_builder); - auto proof = prover.construct_proof(); - - auto verifier = composer.create_verifier(circuit_builder); - bool verified = verifier.verify_proof(proof); - - if (!verified) { - log_avmMini_trace(circuit_builder.rows, 0, 10); - } -}; - -/** - * @brief Helper routine for the negative tests. It mutates the output value of an operation - * located in the Ic intermediate register. The memory trace is adapted consistently. - * - * @param trace Execution trace - * @param selectRow Lambda serving to select the row in trace - * @param newValue The value that will be written in intermediate register Ic at the selected row. - */ -void mutateIcInTrace(std::vector& trace, std::function&& selectRow, FF const& newValue) -{ - // Find the first row matching the criteria defined by selectRow - auto row = std::ranges::find_if(trace.begin(), trace.end(), selectRow); - - // Check that we found one - EXPECT_TRUE(row != trace.end()); - - // Mutate the correct result in the main trace - row->avmMini_ic = newValue; - - // Adapt the memory trace to be consistent with the wrongly computed addition - auto const clk = row->avmMini_clk; - auto const addr = row->avmMini_mem_idx_c; - - // Find the relevant memory trace entry. - auto memRow = std::ranges::find_if(trace.begin(), trace.end(), [clk, addr](Row r) { - return r.memTrace_m_clk == clk && r.memTrace_m_addr == addr; - }); - - EXPECT_TRUE(memRow != trace.end()); - memRow->memTrace_m_val = newValue; -}; - -} // anonymous namespace - /****************************************************************************** * * POSITIVE TESTS - Finite Field Type @@ -123,8 +63,8 @@ TEST_F(AvmMiniArithmeticTests, additionFF) { trace_builder.callDataCopy(0, 3, 0, std::vector{ 37, 4, 11 }); - // Memory layout: [37,4,11,0,0,0,....] - trace_builder.add(0, 1, 4); // [37,4,11,0,41,0,....] + // Memory layout: [37,4,11,0,0,0,....] + trace_builder.add(0, 1, 4, AvmMemoryTag::ff); // [37,4,11,0,41,0,....] trace_builder.returnOP(0, 5); auto trace = trace_builder.finalize(); @@ -146,8 +86,8 @@ TEST_F(AvmMiniArithmeticTests, subtractionFF) { trace_builder.callDataCopy(0, 3, 0, std::vector{ 8, 4, 17 }); - // Memory layout: [8,4,17,0,0,0,....] - trace_builder.sub(2, 0, 1); // [8,9,17,0,0,0....] + // Memory layout: [8,4,17,0,0,0,....] + trace_builder.sub(2, 0, 1, AvmMemoryTag::ff); // [8,9,17,0,0,0....] trace_builder.returnOP(0, 3); auto trace = trace_builder.finalize(); @@ -169,8 +109,8 @@ TEST_F(AvmMiniArithmeticTests, multiplicationFF) { trace_builder.callDataCopy(0, 3, 0, std::vector{ 5, 0, 20 }); - // Memory layout: [5,0,20,0,0,0,....] - trace_builder.mul(2, 0, 1); // [5,100,20,0,0,0....] + // Memory layout: [5,0,20,0,0,0,....] + trace_builder.mul(2, 0, 1, AvmMemoryTag::ff); // [5,100,20,0,0,0....] trace_builder.returnOP(0, 3); auto trace = trace_builder.finalize(); @@ -192,8 +132,8 @@ TEST_F(AvmMiniArithmeticTests, multiplicationByZeroFF) { trace_builder.callDataCopy(0, 1, 0, std::vector{ 127 }); - // Memory layout: [127,0,0,0,0,0,....] - trace_builder.mul(0, 1, 2); // [127,0,0,0,0,0....] + // Memory layout: [127,0,0,0,0,0,....] + trace_builder.mul(0, 1, 2, AvmMemoryTag::ff); // [127,0,0,0,0,0....] trace_builder.returnOP(0, 3); auto trace = trace_builder.finalize(); @@ -215,8 +155,8 @@ TEST_F(AvmMiniArithmeticTests, divisionFF) { trace_builder.callDataCopy(0, 2, 0, std::vector{ 15, 315 }); - // Memory layout: [15,315,0,0,0,0,....] - trace_builder.div(1, 0, 2); // [15,315,21,0,0,0....] + // Memory layout: [15,315,0,0,0,0,....] + trace_builder.div(1, 0, 2, AvmMemoryTag::ff); // [15,315,21,0,0,0....] trace_builder.returnOP(0, 3); auto trace = trace_builder.finalize(); @@ -238,8 +178,8 @@ TEST_F(AvmMiniArithmeticTests, divisionNumeratorZeroFF) { trace_builder.callDataCopy(0, 1, 0, std::vector{ 15 }); - // Memory layout: [15,0,0,0,0,0,....] - trace_builder.div(1, 0, 0); // [0,0,0,0,0,0....] + // Memory layout: [15,0,0,0,0,0,....] + trace_builder.div(1, 0, 0, AvmMemoryTag::ff); // [0,0,0,0,0,0....] trace_builder.returnOP(0, 3); auto trace = trace_builder.finalize(); @@ -262,8 +202,30 @@ TEST_F(AvmMiniArithmeticTests, divisionByZeroErrorFF) { trace_builder.callDataCopy(0, 1, 0, std::vector{ 15 }); - // Memory layout: [15,0,0,0,0,0,....] - trace_builder.div(0, 1, 2); // [15,0,0,0,0,0....] + // Memory layout: [15,0,0,0,0,0,....] + trace_builder.div(0, 1, 2, AvmMemoryTag::ff); // [15,0,0,0,0,0....] + auto trace = trace_builder.finalize(); + + // Find the first row enabling the division selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_div == FF(1); }); + + // Check that the correct result is stored at the expected memory location. + EXPECT_TRUE(row != trace.end()); + EXPECT_EQ(row->avmMini_ic, FF(0)); + EXPECT_EQ(row->avmMini_mem_idx_c, FF(2)); + EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); + EXPECT_EQ(row->avmMini_rwc, FF(1)); + EXPECT_EQ(row->avmMini_op_err, FF(1)); + + validateTraceProof(std::move(trace)); +} + +// Test on division of zero by zero over finite field type. +// We check that the operator error flag is raised. +TEST_F(AvmMiniArithmeticTests, divisionZeroByZeroErrorFF) +{ + // Memory layout: [0,0,0,0,0,0,....] + trace_builder.div(0, 1, 2, AvmMemoryTag::ff); // [0,0,0,0,0,0....] auto trace = trace_builder.finalize(); // Find the first row enabling the division selector @@ -288,16 +250,17 @@ TEST_F(AvmMiniArithmeticTests, arithmeticFFWithError) { trace_builder.callDataCopy(0, 3, 2, std::vector{ 45, 23, 12 }); - // Memory layout: [0,0,45,23,12,0,0,0,....] - trace_builder.add(2, 3, 4); // [0,0,45,23,68,0,0,0,....] - trace_builder.add(4, 5, 5); // [0,0,45,23,68,68,0,0,....] - trace_builder.add(5, 5, 5); // [0,0,45,23,68,136,0,0,....] - trace_builder.add(5, 6, 7); // [0,0,45,23,68,136,0,136,0....] - trace_builder.sub(7, 6, 8); // [0,0,45,23,68,136,0,136,136,0....] - trace_builder.mul(8, 8, 8); // [0,0,45,23,68,136,0,136,136^2,0....] - trace_builder.div(3, 5, 1); // [0,23*136^(-1),45,23,68,136,0,136,136^2,0....] - trace_builder.div(1, 1, 9); // [0,23*136^(-1),45,23,68,136,0,136,136^2,1,0....] - trace_builder.div(9, 0, 4); // [0,23*136^(-1),45,23,1/0,136,0,136,136^2,1,0....] Error: division by 0 + // Memory layout: [0,0,45,23,12,0,0,0,....] + trace_builder.add(2, 3, 4, AvmMemoryTag::ff); // [0,0,45,23,68,0,0,0,....] + trace_builder.add(4, 5, 5, AvmMemoryTag::ff); // [0,0,45,23,68,68,0,0,....] + trace_builder.add(5, 5, 5, AvmMemoryTag::ff); // [0,0,45,23,68,136,0,0,....] + trace_builder.add(5, 6, 7, AvmMemoryTag::ff); // [0,0,45,23,68,136,0,136,0....] + trace_builder.sub(7, 6, 8, AvmMemoryTag::ff); // [0,0,45,23,68,136,0,136,136,0....] + trace_builder.mul(8, 8, 8, AvmMemoryTag::ff); // [0,0,45,23,68,136,0,136,136^2,0....] + trace_builder.div(3, 5, 1, AvmMemoryTag::ff); // [0,23*136^(-1),45,23,68,136,0,136,136^2,0....] + trace_builder.div(1, 1, 9, AvmMemoryTag::ff); // [0,23*136^(-1),45,23,68,136,0,136,136^2,1,0....] + trace_builder.div( + 9, 0, 4, AvmMemoryTag::ff); // [0,23*136^(-1),45,23,1/0,136,0,136,136^2,1,0....] Error: division by 0 auto trace = trace_builder.finalize(); validateTraceProof(std::move(trace)); @@ -329,16 +292,14 @@ TEST_F(AvmMiniArithmeticNegativeTests, additionFF) { trace_builder.callDataCopy(0, 3, 0, std::vector{ 37, 4, 11 }); - // Memory layout: [37,4,11,0,0,0,....] - trace_builder.add(0, 1, 4); // [37,4,11,0,41,0,....] - trace_builder.returnOP(0, 5); + // Memory layout: [37,4,11,0,0,0,....] + trace_builder.add(0, 1, 4, AvmMemoryTag::ff); // [37,4,11,0,41,0,....] auto trace = trace_builder.finalize(); auto selectRow = [](Row r) { return r.avmMini_sel_op_add == FF(1); }; mutateIcInTrace(trace, std::move(selectRow), FF(40)); - // TODO: check that the expected sub-relation failed - EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_ADDITION_FF"); } // Test on basic incorrect subtraction over finite field type. @@ -346,16 +307,14 @@ TEST_F(AvmMiniArithmeticNegativeTests, subtractionFF) { trace_builder.callDataCopy(0, 3, 0, std::vector{ 8, 4, 17 }); - // Memory layout: [8,4,17,0,0,0,....] - trace_builder.sub(2, 0, 1); // [8,9,17,0,0,0....] - trace_builder.returnOP(0, 3); + // Memory layout: [8,4,17,0,0,0,....] + trace_builder.sub(2, 0, 1, AvmMemoryTag::ff); // [8,9,17,0,0,0....] auto trace = trace_builder.finalize(); auto selectRow = [](Row r) { return r.avmMini_sel_op_sub == FF(1); }; mutateIcInTrace(trace, std::move(selectRow), FF(-9)); - // TODO: check that the expected sub-relation failed - EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_SUBTRACTION_FF"); } // Test on basic incorrect multiplication over finite field type. @@ -363,16 +322,14 @@ TEST_F(AvmMiniArithmeticNegativeTests, multiplicationFF) { trace_builder.callDataCopy(0, 3, 0, std::vector{ 5, 0, 20 }); - // Memory layout: [5,0,20,0,0,0,....] - trace_builder.mul(2, 0, 1); // [5,100,20,0,0,0....] - trace_builder.returnOP(0, 3); + // Memory layout: [5,0,20,0,0,0,....] + trace_builder.mul(2, 0, 1, AvmMemoryTag::ff); // [5,100,20,0,0,0....] auto trace = trace_builder.finalize(); auto selectRow = [](Row r) { return r.avmMini_sel_op_mul == FF(1); }; mutateIcInTrace(trace, std::move(selectRow), FF(1000)); - // TODO: check that the expected sub-relation failed - EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_MULTIPLICATION_FF"); } // Test on basic incorrect division over finite field type. @@ -380,16 +337,14 @@ TEST_F(AvmMiniArithmeticNegativeTests, divisionFF) { trace_builder.callDataCopy(0, 2, 0, std::vector{ 15, 315 }); - // Memory layout: [15,315,0,0,0,0,....] - trace_builder.div(1, 0, 2); // [15,315,21,0,0,0....] - trace_builder.returnOP(0, 3); + // Memory layout: [15,315,0,0,0,0,....] + trace_builder.div(1, 0, 2, AvmMemoryTag::ff); // [15,315,21,0,0,0....] auto trace = trace_builder.finalize(); auto selectRow = [](Row r) { return r.avmMini_sel_op_div == FF(1); }; mutateIcInTrace(trace, std::move(selectRow), FF(0)); - // TODO: check that the expected sub-relation failed - EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_DIVISION_FF"); } // Test where division is not by zero but an operation error is wrongly raised @@ -398,19 +353,24 @@ TEST_F(AvmMiniArithmeticNegativeTests, divisionNoZeroButErrorFF) { trace_builder.callDataCopy(0, 2, 0, std::vector{ 15, 315 }); - // Memory layout: [15,315,0,0,0,0,....] - trace_builder.div(1, 0, 2); // [15,315,21,0,0,0....] - trace_builder.returnOP(0, 3); + // Memory layout: [15,315,0,0,0,0,....] + trace_builder.div(1, 0, 2, AvmMemoryTag::ff); // [15,315,21,0,0,0....] auto trace = trace_builder.finalize(); // Find the first row enabling the division selector auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_div == FF(1); }); + size_t const index = static_cast(row - trace.begin()); + // Activate the operator error - row->avmMini_op_err = FF(1); + trace[index].avmMini_op_err = FF(1); + auto trace2 = trace; - // TODO: check that the expected sub-relation failed - EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_DIVISION_ZERO_ERR1"); + + // Even more malicious, one makes the first relation passes by setting the inverse to zero. + trace2[index].avmMini_inv = FF(0); + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace2)), "SUBOP_DIVISION_ZERO_ERR2"); } // Test with division by zero occurs and no error is raised (remove error flag) @@ -418,8 +378,24 @@ TEST_F(AvmMiniArithmeticNegativeTests, divisionByZeroNoErrorFF) { trace_builder.callDataCopy(0, 1, 0, std::vector{ 15 }); - // Memory layout: [15,0,0,0,0,0,....] - trace_builder.div(0, 1, 2); // [15,0,0,0,0,0....] + // Memory layout: [15,0,0,0,0,0,....] + trace_builder.div(0, 1, 2, AvmMemoryTag::ff); // [15,0,0,0,0,0....] + auto trace = trace_builder.finalize(); + + // Find the first row enabling the division selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_div == FF(1); }); + + // Remove the operator error flag + row->avmMini_op_err = FF(0); + + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_DIVISION_FF"); +} + +// Test with division of zero by zero occurs and no error is raised (remove error flag) +TEST_F(AvmMiniArithmeticNegativeTests, divisionZeroByZeroNoErrorFF) +{ + // Memory layout: [0,0,0,0,0,0,....] + trace_builder.div(0, 1, 2, AvmMemoryTag::ff); // [0,0,0,0,0,0....] auto trace = trace_builder.finalize(); // Find the first row enabling the division selector @@ -428,8 +404,7 @@ TEST_F(AvmMiniArithmeticNegativeTests, divisionByZeroNoErrorFF) // Remove the operator error flag row->avmMini_op_err = FF(0); - // TODO: check that the expected sub-relation failed - EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_DIVISION_ZERO_ERR1"); } // Test that error flag cannot be raised for a non-relevant operation such as @@ -438,8 +413,8 @@ TEST_F(AvmMiniArithmeticNegativeTests, operationWithErrorFlagFF) { trace_builder.callDataCopy(0, 3, 0, std::vector{ 37, 4, 11 }); - // Memory layout: [37,4,11,0,0,0,....] - trace_builder.add(0, 1, 4); // [37,4,11,0,41,0,....] + // Memory layout: [37,4,11,0,0,0,....] + trace_builder.add(0, 1, 4, AvmMemoryTag::ff); // [37,4,11,0,41,0,....] trace_builder.returnOP(0, 5); auto trace = trace_builder.finalize(); @@ -449,15 +424,14 @@ TEST_F(AvmMiniArithmeticNegativeTests, operationWithErrorFlagFF) // Activate the operator error row->avmMini_op_err = FF(1); - // TODO: check that the expected sub-relation failed - EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_ERROR_RELEVANT_OP"); trace_builder.reset(); trace_builder.callDataCopy(0, 3, 0, std::vector{ 8, 4, 17 }); - // Memory layout: [8,4,17,0,0,0,....] - trace_builder.sub(2, 0, 1); // [8,9,17,0,0,0....] + // Memory layout: [8,4,17,0,0,0,....] + trace_builder.sub(2, 0, 1, AvmMemoryTag::ff); // [8,9,17,0,0,0....] trace_builder.returnOP(0, 3); trace = trace_builder.finalize(); @@ -467,15 +441,14 @@ TEST_F(AvmMiniArithmeticNegativeTests, operationWithErrorFlagFF) // Activate the operator error row->avmMini_op_err = FF(1); - // TODO: check that the expected sub-relation failed - EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_ERROR_RELEVANT_OP"); trace_builder.reset(); trace_builder.callDataCopy(0, 3, 0, std::vector{ 5, 0, 20 }); - // Memory layout: [5,0,20,0,0,0,....] - trace_builder.mul(2, 0, 1); // [5,100,20,0,0,0....] + // Memory layout: [5,0,20,0,0,0,....] + trace_builder.mul(2, 0, 1, AvmMemoryTag::ff); // [5,100,20,0,0,0....] trace_builder.returnOP(0, 3); trace = trace_builder.finalize(); @@ -485,8 +458,7 @@ TEST_F(AvmMiniArithmeticNegativeTests, operationWithErrorFlagFF) // Activate the operator error row->avmMini_op_err = FF(1); - // TODO: check that the expected sub-relation failed - EXPECT_ANY_THROW(validateTraceProof(std::move(trace))); + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_ERROR_RELEVANT_OP"); } } // namespace tests_avm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp new file mode 100644 index 00000000000..31c3355a5ee --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp @@ -0,0 +1,252 @@ +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/flavor/generated/AvmMini_flavor.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" +#include "barretenberg/proof_system/circuit_builder/AvmMini_helper.hpp" +#include "barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp" +#include "barretenberg/sumcheck/sumcheck_round.hpp" +#include "barretenberg/vm/generated/AvmMini_composer.hpp" +#include "barretenberg/vm/generated/AvmMini_prover.hpp" +#include "barretenberg/vm/generated/AvmMini_verifier.hpp" +#include "helpers.test.hpp" + +#include +#include +#include +#include +#include + +using namespace proof_system; + +namespace tests_avm { + +class AvmMiniMemoryTests : public ::testing::Test { + public: + AvmMiniTraceBuilder trace_builder; + + protected: + // TODO(640): The Standard Honk on Grumpkin test suite fails unless the SRS is initialised for every test. + void SetUp() override + { + barretenberg::srs::init_crs_factory("../srs_db/ignition"); + trace_builder = AvmMiniTraceBuilder(); // Clean instance for every run. + }; +}; + +/****************************************************************************** + * + * MEMORY TESTS + * + ****************************************************************************** + * This test suite focuses on non-trivial memory-related tests which are + * not implicitly covered by other tests such as AvmMiniArithmeticTests. + * + * For instance, tests on checking error conditions related to memory or + * violation of memory-related relations in malicious/malformed execution + * trace is the focus. + ******************************************************************************/ + +// Testing an operation with a mismatched memory tag. +// The proof must pass and we check that the AVM error is raised. +TEST_F(AvmMiniMemoryTests, mismatchedTag) +{ + trace_builder.callDataCopy(0, 2, 0, std::vector{ 98, 12 }); + + trace_builder.add(0, 1, 4, AvmMemoryTag::u8); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the addition selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_add == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + + // All intermediate registers should be set to zero. + EXPECT_EQ(row->avmMini_ia, FF(0)); + EXPECT_EQ(row->avmMini_ib, FF(0)); + EXPECT_EQ(row->avmMini_ic, FF(0)); + + auto clk = row->avmMini_clk; + + // Find the memory trace position corresponding to the add sub-operation of register ia. + row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { + return r.memTrace_m_clk == clk && r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_A; + }); + + EXPECT_TRUE(row != trace.end()); + + EXPECT_EQ(row->memTrace_m_tag_err, FF(1)); // Error is raised + EXPECT_EQ(row->memTrace_m_in_tag, FF(static_cast(AvmMemoryTag::u8))); + EXPECT_EQ(row->memTrace_m_tag, FF(static_cast(AvmMemoryTag::ff))); + + // Find the memory trace position corresponding to the add sub-operation of register ib. + row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { + return r.memTrace_m_clk == clk && r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_B; + }); + + EXPECT_TRUE(row != trace.end()); + + EXPECT_EQ(row->memTrace_m_tag_err, FF(1)); // Error is raised + EXPECT_EQ(row->memTrace_m_in_tag, FF(static_cast(AvmMemoryTag::u8))); + EXPECT_EQ(row->memTrace_m_tag, FF(static_cast(AvmMemoryTag::ff))); + + validateTraceProof(std::move(trace)); +} + +// Testing violation that m_lastAccess is a delimiter for two different addresses +// in the memory trace +TEST_F(AvmMiniMemoryTests, mLastAccessViolation) +{ + trace_builder.callDataCopy(0, 2, 0, std::vector{ 4, 9 }); + + // Memory layout: [4,9,0,0,0,0,....] + trace_builder.sub(1, 0, 2, AvmMemoryTag::u8); // [4,9,5,0,0,0.....] + auto trace = trace_builder.finalize(); + + // Find the row with subtraction operation + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_sub == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + auto clk = row->avmMini_clk; + + // Find the row for memory trace with last memory entry for address 1 (read for subtraction) + row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { + return r.memTrace_m_clk == clk && r.memTrace_m_addr == FF(1) && + r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_A; + }); + + EXPECT_TRUE(row != trace.end()); + + row->memTrace_m_lastAccess = FF(0); + + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "MEM_LAST_ACCESS_DELIMITER"); +} + +// Testing violation that a memory read operation must read the same value which was +// written into memory +TEST_F(AvmMiniMemoryTests, readWriteConsistencyValViolation) +{ + trace_builder.callDataCopy(0, 2, 0, std::vector{ 4, 9 }); + + // Memory layout: [4,9,0,0,0,0,....] + trace_builder.mul(1, 0, 2, AvmMemoryTag::u8); // [4,9,36,0,0,0.....] + trace_builder.returnOP(2, 1); // Return single memory word at position 2 (36) + auto trace = trace_builder.finalize(); + + // Find the row with multiplication operation + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_mul == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + auto clk = row->avmMini_clk + 1; // return operation is just after the multiplication + + // Find the row for memory trace with last memory entry for address 2 (read for multiplication) + row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { + return r.memTrace_m_clk == clk && r.memTrace_m_addr == FF(2) && + r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_A; + }); + + EXPECT_TRUE(row != trace.end()); + + row->memTrace_m_val = FF(35); + + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "MEM_READ_WRITE_VAL_CONSISTENCY"); +} + +// Testing violation that memory read operation must read the same tag which was +// written into memory +TEST_F(AvmMiniMemoryTests, readWriteConsistencyTagViolation) +{ + trace_builder.callDataCopy(0, 2, 0, std::vector{ 4, 9 }); + + // Memory layout: [4,9,0,0,0,0,....] + trace_builder.mul(1, 0, 2, AvmMemoryTag::u8); // [4,9,36,0,0,0.....] + trace_builder.returnOP(2, 1); // Return single memory word at position 2 (36) + auto trace = trace_builder.finalize(); + + // Find the row with multiplication operation + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_mul == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + auto clk = row->avmMini_clk + 1; // return operation is just after the multiplication + + // Find the row for memory trace with last memory entry for address 2 (read for multiplication) + row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { + return r.memTrace_m_clk == clk && r.memTrace_m_addr == FF(2) && + r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_A; + }); + + EXPECT_TRUE(row != trace.end()); + + row->memTrace_m_tag = static_cast(AvmMemoryTag::u16); + + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "MEM_READ_WRITE_TAG_CONSISTENCY"); +} + +// Testing violation that a memory read at uninitialized location must have value 0. +TEST_F(AvmMiniMemoryTests, readUninitializedMemoryViolation) +{ + trace_builder.returnOP(1, 1); // Return single memory word at position 1 + auto trace = trace_builder.finalize(); + + trace[1].memTrace_m_val = 9; + + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "MEM_ZERO_INIT"); +} + +// Testing violation that an operation with a mismatched memory tag +// must raise a VM error. +TEST_F(AvmMiniMemoryTests, mismatchedTagErrorViolation) +{ + trace_builder.callDataCopy(0, 2, 0, std::vector{ 98, 12 }); + + trace_builder.sub(0, 1, 4, AvmMemoryTag::u8); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the subtraction selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_sub == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + + auto clk = row->avmMini_clk; + + // Find the memory trace position corresponding to the subtraction sub-operation of register ia. + row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { + return r.memTrace_m_clk == clk && r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_A; + }); + + row->memTrace_m_tag_err = FF(0); + auto index = static_cast(row - trace.begin()); + auto trace2 = trace; + + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "MEM_IN_TAG_CONSISTENCY_1"); + + // More sophisticated attempt by adapting witness "on_min_inv" to make pass the above constraint + trace2[index].memTrace_m_one_min_inv = FF(1); + + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace2)), "MEM_IN_TAG_CONSISTENCY_2"); +} + +// Testing violation that an operation with a consistent memory tag +// must not set a VM error. +TEST_F(AvmMiniMemoryTests, consistentTagNoErrorViolation) +{ + trace_builder.callDataCopy(0, 2, 0, std::vector{ 84, 7 }); + + trace_builder.div(0, 1, 4, AvmMemoryTag::ff); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the division selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_div == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + + auto clk = row->avmMini_clk; + + // Find the memory trace position corresponding to the div sub-operation of register ia. + row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { + return r.memTrace_m_clk == clk && r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_A; + }); + + row->memTrace_m_tag_err = FF(1); + + EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "MEM_IN_TAG_CONSISTENCY_1"); +} +} // namespace tests_avm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp new file mode 100644 index 00000000000..9cfb6fe7a17 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp @@ -0,0 +1,69 @@ +#include "barretenberg/vm/tests/helpers.test.hpp" +#include "barretenberg/flavor/generated/AvmMini_flavor.hpp" +#include "barretenberg/proof_system/circuit_builder/AvmMini_helper.hpp" +#include "barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp" +#include "barretenberg/vm/generated/AvmMini_composer.hpp" +#include "barretenberg/vm/generated/AvmMini_prover.hpp" +#include "barretenberg/vm/generated/AvmMini_verifier.hpp" +#include + +namespace tests_avm { +using namespace proof_system; + +/** + * @brief Helper routine proving and verifying a proof based on the supplied trace + * + * @param trace The execution trace + */ +void validateTraceProof(std::vector&& trace) +{ + auto circuit_builder = AvmMiniCircuitBuilder(); + circuit_builder.set_trace(std::move(trace)); + + EXPECT_TRUE(circuit_builder.check_circuit()); + + auto composer = honk::AvmMiniComposer(); + auto prover = composer.create_prover(circuit_builder); + auto proof = prover.construct_proof(); + + auto verifier = composer.create_verifier(circuit_builder); + bool verified = verifier.verify_proof(proof); + + if (!verified) { + log_avmMini_trace(circuit_builder.rows, 0, 10); + } +}; + +/** + * @brief Helper routine for the negative tests. It mutates the output value of an operation + * located in the Ic intermediate register. The memory trace is adapted consistently. + * + * @param trace Execution trace + * @param selectRow Lambda serving to select the row in trace + * @param newValue The value that will be written in intermediate register Ic at the selected row. + */ +void mutateIcInTrace(std::vector& trace, std::function&& selectRow, FF const& newValue) +{ + // Find the first row matching the criteria defined by selectRow + auto row = std::ranges::find_if(trace.begin(), trace.end(), selectRow); + + // Check that we found one + EXPECT_TRUE(row != trace.end()); + + // Mutate the correct result in the main trace + row->avmMini_ic = newValue; + + // Adapt the memory trace to be consistent with the wrongly computed addition + auto const clk = row->avmMini_clk; + auto const addr = row->avmMini_mem_idx_c; + + // Find the relevant memory trace entry. + auto memRow = std::ranges::find_if(trace.begin(), trace.end(), [clk, addr](Row r) { + return r.memTrace_m_clk == clk && r.memTrace_m_addr == addr; + }); + + EXPECT_TRUE(memRow != trace.end()); + memRow->memTrace_m_val = newValue; +}; + +} // namespace tests_avm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp new file mode 100644 index 00000000000..36732908f89 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp" + +#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage) \ + try { \ + code; \ + FAIL() << "An exception was expected"; \ + } catch (const std::exception& e) { \ + std::string message = e.what(); \ + EXPECT_TRUE(message.find(expectedMessage) != std::string::npos); \ + } + +namespace tests_avm { + +void validateTraceProof(std::vector&& trace); +void mutateIcInTrace(std::vector& trace, std::function&& selectRow, FF const& newValue); + +} // namespace tests_avm \ No newline at end of file From d9d0b13d1994617053c976a845dbed82d99fcb2f Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 19 Dec 2023 17:36:42 +0000 Subject: [PATCH 6/8] feat(avm-mini): call and return opcodes (#3704) closes: https://github.com/AztecProtocol/aztec-packages/issues/3697 --- barretenberg/cpp/pil/avm/avm_mini.pil | 57 +++- .../flavor/generated/AvmMini_flavor.hpp | 78 +++++- .../flavor/generated/Toy_flavor.hpp | 4 +- .../circuit_builder/AvmMini_helper.cpp | 76 +++--- .../circuit_builder/AvmMini_trace.cpp | 112 +++++++- .../circuit_builder/AvmMini_trace.hpp | 17 ++ .../generated/AvmMini_circuit_builder.hpp | 34 ++- .../generated/Toy_circuit_builder.hpp | 11 +- .../relations/generated/AvmMini/avm_mini.hpp | 228 +++++++++++++--- .../generated/AvmMini/declare_views.hpp | 11 +- .../relations/generated/AvmMini/mem_trace.hpp | 34 +-- .../relations/generated/Toy/toy_avm.hpp | 8 +- .../vm/generated/AvmMini_verifier.cpp | 9 + .../vm/generated/Toy_composer.cpp | 12 +- .../barretenberg/vm/generated/Toy_prover.cpp | 1 - .../vm/tests/AvmMini_arithmetic.test.cpp | 5 + .../vm/tests/AvmMini_control_flow.test.cpp | 253 ++++++++++++++++++ .../vm/tests/AvmMini_memory.test.cpp | 4 + 18 files changed, 821 insertions(+), 133 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp diff --git a/barretenberg/cpp/pil/avm/avm_mini.pil b/barretenberg/cpp/pil/avm/avm_mini.pil index 1fca367bf95..b2e10e30cca 100644 --- a/barretenberg/cpp/pil/avm/avm_mini.pil +++ b/barretenberg/cpp/pil/avm/avm_mini.pil @@ -7,6 +7,18 @@ namespace avmMini(256); pol constant clk(i) { i }; pol constant first = [1] + [0]*; // Used mostly to toggle off the first row consisting // only in first element of shifted polynomials. + + //===== CONTROL FLOW ========================================================== + // Program counter + pol commit pc; + // Return Pointer + pol commit internal_return_ptr; + + pol commit sel_internal_call; + pol commit sel_internal_return; + + // Halt program execution + pol commit sel_halt; //===== TABLE SUBOP-TR ======================================================== // Boolean selectors for (sub-)operations. Only one operation is activated at @@ -66,6 +78,10 @@ namespace avmMini(256); sel_op_mul * (1 - sel_op_mul) = 0; sel_op_div * (1 - sel_op_div) = 0; + sel_internal_call * (1 - sel_internal_call) = 0; + sel_internal_return * (1 - sel_internal_return) = 0; + sel_halt * (1 - sel_halt) = 0; + op_err * (1 - op_err) = 0; tag_err * (1 - tag_err) = 0; // Potential optimization (boolean constraint derivation from equivalence check to memTrace)? @@ -131,8 +147,47 @@ namespace avmMini(256); // This works in combination with op_div_err * (sel_op_div - 1) = 0; // Drawback is the need to paralllelize the latter. + + //===== CALL_RETURN ======================================================== + // The program counter in the next row should be equal to the value loaded from the ia register + // This implies that a load from memory must occur at the same time + // Imply that we must load the return location into mem_idx_a + + #[RETURN_POINTER_INCREMENT] + sel_internal_call * ( internal_return_ptr' - ( internal_return_ptr + 1)) = 0; + sel_internal_call * ( internal_return_ptr - mem_idx_a) = 0; + sel_internal_call * ((pc + 1) - ia) = 0; + + // TODO(md): Below relations may be removed through sub-op table lookup + sel_internal_call * (rwa - 1) = 0; + sel_internal_call * (mem_op_a - 1) = 0; + + // We must load the memory pointer to be the internal_return_ptr + #[RETURN_POINTER_DECREMENT] + sel_internal_return * ( internal_return_ptr' - ( internal_return_ptr - 1)) = 0; + sel_internal_return * ( (internal_return_ptr - 1) - mem_idx_a) = 0; + sel_internal_return * (pc' - ia) = 0; + + // TODO(md): Below relations may be removed through sub-op table lookup + sel_internal_return * rwa = 0; + sel_internal_return * (mem_op_a - 1) = 0; + + //===== CONTROL_FLOW_CONSISTENCY ============================================ + pol CONTROL_FLOW_SELECTORS = (first + sel_internal_call + sel_internal_return + sel_halt); + pol OPCODE_SELECTORS = (sel_op_add + sel_op_sub + sel_op_div + sel_op_mul); + + // Program counter must increment if not jumping or returning + #[PC_INCREMENT] + (1 - first) * (1 - sel_halt) * OPCODE_SELECTORS * (pc' - (pc + 1)) = 0; + + // first == 0 && sel_internal_call == 0 && sel_internal_return == 0 && sel_halt == 0 ==> internal_return_ptr == internal_return_ptr' + #[INTERNAL_RETURN_POINTER_CONSISTENCY] + (1 - CONTROL_FLOW_SELECTORS) * (internal_return_ptr' - internal_return_ptr) = 0; + + // TODO: we want to set an initial number for the reserved memory of the jump pointer + // Inter-table Constraints // TODO: tag_err {clk} IS memTrace.m_tag_err {memTrace.m_clk} // TODO: Map memory trace with intermediate register values whenever there is no tag error, sthg like: - // mem_op_a * (1 - tag_err) {mem_idx_a, clk, ia, rwa} IS m_sub_clk == 0 && 1 - m_tag_err {m_addr, m_clk, m_val, m_rw} \ No newline at end of file + // mem_op_a * (1 - tag_err) {mem_idx_a, clk, ia, rwa} IS m_sub_clk == 0 && 1 - m_tag_err {m_addr, m_clk, m_val, m_rw} diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp index f986f97f168..d9b5edb8c61 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp @@ -36,13 +36,13 @@ class AvmMiniFlavor { using VerifierCommitmentKey = pcs::VerifierCommitmentKey; static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 2; - static constexpr size_t NUM_WITNESS_ENTITIES = 32; + static constexpr size_t NUM_WITNESS_ENTITIES = 37; static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted - static constexpr size_t NUM_ALL_ENTITIES = 38; + static constexpr size_t NUM_ALL_ENTITIES = 45; - using Relations = std::tuple, AvmMini_vm::avm_mini>; + using Relations = std::tuple, AvmMini_vm::mem_trace>; static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); @@ -87,6 +87,11 @@ class AvmMiniFlavor { memTrace_m_in_tag, memTrace_m_tag_err, memTrace_m_one_min_inv, + avmMini_pc, + avmMini_internal_return_ptr, + avmMini_sel_internal_call, + avmMini_sel_internal_return, + avmMini_sel_halt, avmMini_sel_op_add, avmMini_sel_op_sub, avmMini_sel_op_mul, @@ -122,6 +127,11 @@ class AvmMiniFlavor { memTrace_m_in_tag, memTrace_m_tag_err, memTrace_m_one_min_inv, + avmMini_pc, + avmMini_internal_return_ptr, + avmMini_sel_internal_call, + avmMini_sel_internal_return, + avmMini_sel_halt, avmMini_sel_op_add, avmMini_sel_op_sub, avmMini_sel_op_mul, @@ -163,6 +173,11 @@ class AvmMiniFlavor { memTrace_m_in_tag, memTrace_m_tag_err, memTrace_m_one_min_inv, + avmMini_pc, + avmMini_internal_return_ptr, + avmMini_sel_internal_call, + avmMini_sel_internal_return, + avmMini_sel_halt, avmMini_sel_op_add, avmMini_sel_op_sub, avmMini_sel_op_mul, @@ -184,10 +199,12 @@ class AvmMiniFlavor { avmMini_mem_idx_b, avmMini_mem_idx_c, avmMini_last, + avmMini_internal_return_ptr_shift, + avmMini_pc_shift, + memTrace_m_tag_shift, memTrace_m_val_shift, - memTrace_m_addr_shift, memTrace_m_rw_shift, - memTrace_m_tag_shift) + memTrace_m_addr_shift) RefVector get_wires() { @@ -204,6 +221,11 @@ class AvmMiniFlavor { memTrace_m_in_tag, memTrace_m_tag_err, memTrace_m_one_min_inv, + avmMini_pc, + avmMini_internal_return_ptr, + avmMini_sel_internal_call, + avmMini_sel_internal_return, + avmMini_sel_halt, avmMini_sel_op_add, avmMini_sel_op_sub, avmMini_sel_op_mul, @@ -225,10 +247,12 @@ class AvmMiniFlavor { avmMini_mem_idx_b, avmMini_mem_idx_c, avmMini_last, + avmMini_internal_return_ptr_shift, + avmMini_pc_shift, + memTrace_m_tag_shift, memTrace_m_val_shift, - memTrace_m_addr_shift, memTrace_m_rw_shift, - memTrace_m_tag_shift }; + memTrace_m_addr_shift }; }; RefVector get_unshifted() { @@ -245,6 +269,11 @@ class AvmMiniFlavor { memTrace_m_in_tag, memTrace_m_tag_err, memTrace_m_one_min_inv, + avmMini_pc, + avmMini_internal_return_ptr, + avmMini_sel_internal_call, + avmMini_sel_internal_return, + avmMini_sel_halt, avmMini_sel_op_add, avmMini_sel_op_sub, avmMini_sel_op_mul, @@ -269,11 +298,18 @@ class AvmMiniFlavor { }; RefVector get_to_be_shifted() { - return { memTrace_m_val, memTrace_m_addr, memTrace_m_rw, memTrace_m_tag }; + return { + avmMini_internal_return_ptr, avmMini_pc, memTrace_m_tag, memTrace_m_val, memTrace_m_rw, memTrace_m_addr + }; }; RefVector get_shifted() { - return { memTrace_m_val_shift, memTrace_m_addr_shift, memTrace_m_rw_shift, memTrace_m_tag_shift }; + return { avmMini_internal_return_ptr_shift, + avmMini_pc_shift, + memTrace_m_tag_shift, + memTrace_m_val_shift, + memTrace_m_rw_shift, + memTrace_m_addr_shift }; }; }; @@ -286,7 +322,9 @@ class AvmMiniFlavor { RefVector get_to_be_shifted() { - return { memTrace_m_val, memTrace_m_addr, memTrace_m_rw, memTrace_m_tag }; + return { + avmMini_internal_return_ptr, avmMini_pc, memTrace_m_tag, memTrace_m_val, memTrace_m_rw, memTrace_m_addr + }; }; // The plookup wires that store plookup read data. @@ -376,6 +414,11 @@ class AvmMiniFlavor { Base::memTrace_m_in_tag = "MEMTRACE_M_IN_TAG"; Base::memTrace_m_tag_err = "MEMTRACE_M_TAG_ERR"; Base::memTrace_m_one_min_inv = "MEMTRACE_M_ONE_MIN_INV"; + Base::avmMini_pc = "AVMMINI_PC"; + Base::avmMini_internal_return_ptr = "AVMMINI_INTERNAL_RETURN_PTR"; + Base::avmMini_sel_internal_call = "AVMMINI_SEL_INTERNAL_CALL"; + Base::avmMini_sel_internal_return = "AVMMINI_SEL_INTERNAL_RETURN"; + Base::avmMini_sel_halt = "AVMMINI_SEL_HALT"; Base::avmMini_sel_op_add = "AVMMINI_SEL_OP_ADD"; Base::avmMini_sel_op_sub = "AVMMINI_SEL_OP_SUB"; Base::avmMini_sel_op_mul = "AVMMINI_SEL_OP_MUL"; @@ -427,6 +470,11 @@ class AvmMiniFlavor { Commitment memTrace_m_in_tag; Commitment memTrace_m_tag_err; Commitment memTrace_m_one_min_inv; + Commitment avmMini_pc; + Commitment avmMini_internal_return_ptr; + Commitment avmMini_sel_internal_call; + Commitment avmMini_sel_internal_return; + Commitment avmMini_sel_halt; Commitment avmMini_sel_op_add; Commitment avmMini_sel_op_sub; Commitment avmMini_sel_op_mul; @@ -478,6 +526,11 @@ class AvmMiniFlavor { memTrace_m_in_tag = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); memTrace_m_tag_err = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); memTrace_m_one_min_inv = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_pc = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_internal_return_ptr = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_sel_internal_call = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_sel_internal_return = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_sel_halt = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_sel_op_add = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_sel_op_sub = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_sel_op_mul = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); @@ -533,6 +586,11 @@ class AvmMiniFlavor { serialize_to_buffer(memTrace_m_in_tag, Transcript::proof_data); serialize_to_buffer(memTrace_m_tag_err, Transcript::proof_data); serialize_to_buffer(memTrace_m_one_min_inv, Transcript::proof_data); + serialize_to_buffer(avmMini_pc, Transcript::proof_data); + serialize_to_buffer(avmMini_internal_return_ptr, Transcript::proof_data); + serialize_to_buffer(avmMini_sel_internal_call, Transcript::proof_data); + serialize_to_buffer(avmMini_sel_internal_return, Transcript::proof_data); + serialize_to_buffer(avmMini_sel_halt, Transcript::proof_data); serialize_to_buffer(avmMini_sel_op_add, Transcript::proof_data); serialize_to_buffer(avmMini_sel_op_sub, Transcript::proof_data); serialize_to_buffer(avmMini_sel_op_mul, Transcript::proof_data); diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp index cb73871810b..312dfa7cf94 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp @@ -142,8 +142,6 @@ class ToyFlavor { using Base::Base; }; - using RowPolynomials = AllEntities; - /** * @brief A container for the prover polynomials handles. */ @@ -156,7 +154,7 @@ class ToyFlavor { ProverPolynomials(ProverPolynomials&& o) noexcept = default; ProverPolynomials& operator=(ProverPolynomials&& o) noexcept = default; ~ProverPolynomials() = default; - [[nodiscard]] size_t get_polynomial_size() const { return toy_first.size(); } + [[nodiscard]] size_t get_polynomial_size() const { return toy_q_tuple_set.size(); } /** * @brief Returns the evaluations of all prover polynomials at one point on the boolean hypercube, which * represents one row in the execution trace. diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.cpp index e3ee39cff93..60d92a168cc 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.cpp @@ -19,47 +19,53 @@ void log_avmMini_trace(std::vector const& trace, size_t beg, size_t end) info("Built circuit with ", trace.size(), " rows"); for (size_t i = beg; i < end; i++) { - info("================================================================================"); - info("== ROW ", i); - info("================================================================================"); + info("====================================================================================="); + info("== ROW ", i); + info("====================================================================================="); - info("=======MEMORY TRACE============================================================="); - info("m_addr: ", trace.at(i).memTrace_m_addr); - info("m_clk: ", trace.at(i).memTrace_m_clk); - info("m_sub_clk: ", trace.at(i).memTrace_m_sub_clk); - info("m_val: ", trace.at(i).memTrace_m_val); - info("m_rw: ", trace.at(i).memTrace_m_rw); - info("m_tag: ", trace.at(i).memTrace_m_tag); - info("m_in_tag: ", trace.at(i).memTrace_m_in_tag); - info("m_tag_err: ", trace.at(i).memTrace_m_tag_err); - info("m_one_min_inv:", trace.at(i).memTrace_m_one_min_inv); + info("=======MEMORY TRACE=================================================================="); + info("m_addr: ", trace.at(i).memTrace_m_addr); + info("m_clk: ", trace.at(i).memTrace_m_clk); + info("m_sub_clk: ", trace.at(i).memTrace_m_sub_clk); + info("m_val: ", trace.at(i).memTrace_m_val); + info("m_rw: ", trace.at(i).memTrace_m_rw); + info("m_tag: ", trace.at(i).memTrace_m_tag); + info("m_in_tag: ", trace.at(i).memTrace_m_in_tag); + info("m_tag_err: ", trace.at(i).memTrace_m_tag_err); + info("m_one_min_inv: ", trace.at(i).memTrace_m_one_min_inv); - info("m_lastAccess: ", trace.at(i).memTrace_m_lastAccess); - info("m_last: ", trace.at(i).memTrace_m_last); - info("m_val_shift: ", trace.at(i).memTrace_m_val_shift); + info("m_lastAccess: ", trace.at(i).memTrace_m_lastAccess); + info("m_last: ", trace.at(i).memTrace_m_last); + info("m_val_shift: ", trace.at(i).memTrace_m_val_shift); - info("=======MAIN TRACE==============================================================="); - info("ia: ", trace.at(i).avmMini_ia); - info("ib: ", trace.at(i).avmMini_ib); - info("ic: ", trace.at(i).avmMini_ic); - info("first: ", trace.at(i).avmMini_first); - info("last: ", trace.at(i).avmMini_last); + info("=======CONTROL_FLOW==================================================================="); + info("pc: ", trace.at(i).avmMini_pc); + info("internal_call: ", trace.at(i).avmMini_sel_internal_call); + info("internal_return: ", trace.at(i).avmMini_sel_internal_return); + info("internal_return_ptr:", trace.at(i).avmMini_internal_return_ptr); - info("=======MEM_OP_A================================================================="); - info("clk: ", trace.at(i).avmMini_clk); - info("mem_op_a: ", trace.at(i).avmMini_mem_op_a); - info("mem_idx_a: ", trace.at(i).avmMini_mem_idx_a); - info("rwa: ", trace.at(i).avmMini_rwa); + info("=======MAIN TRACE===================================================================="); + info("ia: ", trace.at(i).avmMini_ia); + info("ib: ", trace.at(i).avmMini_ib); + info("ic: ", trace.at(i).avmMini_ic); + info("first: ", trace.at(i).avmMini_first); + info("last: ", trace.at(i).avmMini_last); - info("=======MEM_OP_B================================================================="); - info("mem_op_b: ", trace.at(i).avmMini_mem_op_b); - info("mem_idx_b: ", trace.at(i).avmMini_mem_idx_b); - info("rwb: ", trace.at(i).avmMini_rwb); + info("=======MEM_OP_A======================================================================"); + info("clk: ", trace.at(i).avmMini_clk); + info("mem_op_a: ", trace.at(i).avmMini_mem_op_a); + info("mem_idx_a: ", trace.at(i).avmMini_mem_idx_a); + info("rwa: ", trace.at(i).avmMini_rwa); - info("=======MEM_OP_C================================================================="); - info("mem_op_c: ", trace.at(i).avmMini_mem_op_c); - info("mem_idx_c: ", trace.at(i).avmMini_mem_idx_c); - info("rwc: ", trace.at(i).avmMini_rwc); + info("=======MEM_OP_B======================================================================"); + info("mem_op_b: ", trace.at(i).avmMini_mem_op_b); + info("mem_idx_b: ", trace.at(i).avmMini_mem_idx_b); + info("rwb: ", trace.at(i).avmMini_rwb); + + info("=======MEM_OP_C======================================================================"); + info("mem_op_c: ", trace.at(i).avmMini_mem_op_c); + info("mem_idx_c: ", trace.at(i).avmMini_mem_idx_c); + info("rwc: ", trace.at(i).avmMini_rwc); info("\n"); } } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp index fd4c46ffef5..9c6721160f8 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp @@ -191,6 +191,8 @@ void AvmMiniTraceBuilder::add(uint32_t aOffset, uint32_t bOffset, uint32_t dstOf mainTrace.push_back(Row{ .avmMini_clk = clk, + .avmMini_pc = FF(pc++), + .avmMini_internal_return_ptr = FF(internal_return_ptr), .avmMini_sel_op_add = FF(1), .avmMini_in_tag = FF(static_cast(inTag)), .avmMini_tag_err = FF(static_cast(!tagMatch)), @@ -233,6 +235,8 @@ void AvmMiniTraceBuilder::sub(uint32_t aOffset, uint32_t bOffset, uint32_t dstOf mainTrace.push_back(Row{ .avmMini_clk = clk, + .avmMini_pc = FF(pc++), + .avmMini_internal_return_ptr = FF(internal_return_ptr), .avmMini_sel_op_sub = FF(1), .avmMini_in_tag = FF(static_cast(inTag)), .avmMini_tag_err = FF(static_cast(!tagMatch)), @@ -275,6 +279,8 @@ void AvmMiniTraceBuilder::mul(uint32_t aOffset, uint32_t bOffset, uint32_t dstOf mainTrace.push_back(Row{ .avmMini_clk = clk, + .avmMini_pc = FF(pc++), + .avmMini_internal_return_ptr = FF(internal_return_ptr), .avmMini_sel_op_mul = FF(1), .avmMini_in_tag = FF(static_cast(inTag)), .avmMini_tag_err = FF(static_cast(!tagMatch)), @@ -331,6 +337,8 @@ void AvmMiniTraceBuilder::div(uint32_t aOffset, uint32_t bOffset, uint32_t dstOf mainTrace.push_back(Row{ .avmMini_clk = clk, + .avmMini_pc = FF(pc++), + .avmMini_internal_return_ptr = FF(internal_return_ptr), .avmMini_sel_op_div = FF(1), .avmMini_in_tag = FF(static_cast(inTag)), .avmMini_op_err = tagMatch ? error : FF(1), @@ -427,6 +435,8 @@ void AvmMiniTraceBuilder::callDataCopy(uint32_t cdOffset, mainTrace.push_back(Row{ .avmMini_clk = clk, + .avmMini_pc = FF(pc++), + .avmMini_internal_return_ptr = FF(internal_return_ptr), .avmMini_in_tag = FF(static_cast(AvmMemoryTag::ff)), .avmMini_ia = ia, .avmMini_ib = ib, @@ -514,6 +524,9 @@ std::vector AvmMiniTraceBuilder::returnOP(uint32_t retOffset, uint32_t retSi mainTrace.push_back(Row{ .avmMini_clk = clk, + .avmMini_pc = FF(pc), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_halt = FF(1), .avmMini_in_tag = FF(static_cast(AvmMemoryTag::ff)), .avmMini_ia = ia, .avmMini_ib = ib, @@ -536,7 +549,104 @@ std::vector AvmMiniTraceBuilder::returnOP(uint32_t retOffset, uint32_t retSi } /** - * @brief Helper to initialize memory. (Testing purpose mostly.) + * @brief HALT opcode + * This opcode effectively stops program execution, and is used in the relation that + * ensures the program counter increments on each opcode. + * i.e.ythe program counter should freeze and the halt flag is set to 1. + */ +void AvmMiniTraceBuilder::halt() +{ + auto clk = mainTrace.size(); + + mainTrace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = FF(pc), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_halt = FF(1), + }); +} + +/** + * @brief INTERNAL_CALL OPCODE + * This opcode effectively jumps to a new `jmpDest` and stores the return program counter + * (current program counter + 1) onto a call stack. + * This function must: + * - Set the next program counter to the provided `jmpDest`. + * - Store the current `pc` + 1 onto the call stack (emulated in memory) + * - Increment the return stack pointer (a pointer to where the call stack is in memory) + * + * Note: We use intermediate register to perform memory storage operations. + * + * @param jmpDest - The destination to jump to + */ +void AvmMiniTraceBuilder::internal_call(uint32_t jmpDest) +{ + auto clk = mainTrace.size(); + + // We store the next instruction as the return location + uint32_t stored_pc = pc + 1; + internal_call_stack.push(stored_pc); + + // Add the return location to the memory trace + storeInMemTrace(IntermRegister::ia, internal_return_ptr, FF(stored_pc), AvmMemoryTag::ff); + memory.at(internal_return_ptr) = stored_pc; + + mainTrace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = FF(pc), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_internal_call = FF(1), + .avmMini_ia = stored_pc, + .avmMini_mem_op_a = FF(1), + .avmMini_rwa = FF(1), + .avmMini_mem_idx_a = FF(internal_return_ptr), + }); + + // Adjust parameters for the next row + pc = jmpDest; + internal_return_ptr++; +} + +/** + * @brief INTERNAL_RETURN OPCODE + * The opcode returns from an internal call. + * This function must: + * - Read the return location from the internal_return_ptr + * - Set the next program counter to the return location + * - Decrement the return stack pointer + * + * TODO(https://github.com/AztecProtocol/aztec-packages/issues/3740): This function MUST come after a call instruction. + */ +void AvmMiniTraceBuilder::internal_return() +{ + auto clk = mainTrace.size(); + + // Internal return pointer is decremented + FF a = memory.at(internal_return_ptr - 1); + + // We want to load the value pointed by the internal pointer + loadInMemTrace(IntermRegister::ia, internal_return_ptr - 1, FF(a), AvmMemoryTag::ff); + + mainTrace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = pc, + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_internal_return = FF(1), + .avmMini_ia = a, + .avmMini_mem_op_a = FF(1), + .avmMini_rwa = FF(0), + .avmMini_mem_idx_a = FF(internal_return_ptr - 1), + }); + + // We want the next row to be the one pointed by jmpDest + // The next pc should be from the top of the internal call stack + 1 + pc = internal_call_stack.top(); + internal_call_stack.pop(); + internal_return_ptr--; +} + +/** + * @brief Helper to initialize ffMemory. (Testing purpose mostly.) * */ void AvmMiniTraceBuilder::setFFMem(size_t idx, FF el, AvmMemoryTag tag) diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp index 5f5f7e8353d..f7dd66f3b3e 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include "barretenberg/common/throw_or_abort.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp" @@ -28,6 +30,7 @@ class AvmMiniTraceBuilder { // Number of rows static const size_t N = 256; static const size_t MEM_SIZE = 1024; + static const size_t CALLSTACK_OFFSET = 896; // TODO(md): Temporary reserved area 896 - 1024 static const uint32_t SUB_CLK_LOAD_A = 0; static const uint32_t SUB_CLK_LOAD_B = 1; @@ -56,6 +59,16 @@ class AvmMiniTraceBuilder { // Division with direct memory access. void div(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag); + // Jump to a given program counter. + // TODO(md): this program counter MUST be an operand to the OPCODE. + void internal_call(uint32_t jmpDest); + + // Return from a jump. + void internal_return(); + + // Halt -> stop program execution. + void halt(); + // CALLDATACOPY opcode with direct memory access, i.e., // M[dstOffset:dstOffset+copySize] = calldata[cdOffset:cdOffset+copySize] void callDataCopy(uint32_t cdOffset, uint32_t copySize, uint32_t dstOffset, std::vector const& callDataMem); @@ -83,6 +96,10 @@ class AvmMiniTraceBuilder { std::array memoryTag{}; // The tag of the corresponding memory // entry (aligned with the memory array). + uint32_t pc = 0; + uint32_t internal_return_ptr = CALLSTACK_OFFSET; + std::stack internal_call_stack = {}; + static bool compareMemEntries(const MemoryTraceEntry& left, const MemoryTraceEntry& right); void insertInMemTrace( uint32_t m_clk, uint32_t m_sub_clk, uint32_t m_addr, FF m_val, AvmMemoryTag m_in_tag, bool m_rw); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp index 02aaed70a5a..a41fb694b9c 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp @@ -32,6 +32,11 @@ template struct AvmMiniFullRow { FF memTrace_m_in_tag{}; FF memTrace_m_tag_err{}; FF memTrace_m_one_min_inv{}; + FF avmMini_pc{}; + FF avmMini_internal_return_ptr{}; + FF avmMini_sel_internal_call{}; + FF avmMini_sel_internal_return{}; + FF avmMini_sel_halt{}; FF avmMini_sel_op_add{}; FF avmMini_sel_op_sub{}; FF avmMini_sel_op_mul{}; @@ -53,10 +58,12 @@ template struct AvmMiniFullRow { FF avmMini_mem_idx_b{}; FF avmMini_mem_idx_c{}; FF avmMini_last{}; + FF avmMini_internal_return_ptr_shift{}; + FF avmMini_pc_shift{}; + FF memTrace_m_tag_shift{}; FF memTrace_m_val_shift{}; - FF memTrace_m_addr_shift{}; FF memTrace_m_rw_shift{}; - FF memTrace_m_tag_shift{}; + FF memTrace_m_addr_shift{}; }; class AvmMiniCircuitBuilder { @@ -69,8 +76,8 @@ class AvmMiniCircuitBuilder { using Polynomial = Flavor::Polynomial; using ProverPolynomials = Flavor::ProverPolynomials; - static constexpr size_t num_fixed_columns = 38; - static constexpr size_t num_polys = 34; + static constexpr size_t num_fixed_columns = 45; + static constexpr size_t num_polys = 39; std::vector rows; void set_trace(std::vector&& trace) { rows = std::move(trace); } @@ -99,6 +106,11 @@ class AvmMiniCircuitBuilder { polys.memTrace_m_in_tag[i] = rows[i].memTrace_m_in_tag; polys.memTrace_m_tag_err[i] = rows[i].memTrace_m_tag_err; polys.memTrace_m_one_min_inv[i] = rows[i].memTrace_m_one_min_inv; + polys.avmMini_pc[i] = rows[i].avmMini_pc; + polys.avmMini_internal_return_ptr[i] = rows[i].avmMini_internal_return_ptr; + polys.avmMini_sel_internal_call[i] = rows[i].avmMini_sel_internal_call; + polys.avmMini_sel_internal_return[i] = rows[i].avmMini_sel_internal_return; + polys.avmMini_sel_halt[i] = rows[i].avmMini_sel_halt; polys.avmMini_sel_op_add[i] = rows[i].avmMini_sel_op_add; polys.avmMini_sel_op_sub[i] = rows[i].avmMini_sel_op_sub; polys.avmMini_sel_op_mul[i] = rows[i].avmMini_sel_op_mul; @@ -122,10 +134,12 @@ class AvmMiniCircuitBuilder { polys.avmMini_last[i] = rows[i].avmMini_last; } + polys.avmMini_internal_return_ptr_shift = Polynomial(polys.avmMini_internal_return_ptr.shifted()); + polys.avmMini_pc_shift = Polynomial(polys.avmMini_pc.shifted()); + polys.memTrace_m_tag_shift = Polynomial(polys.memTrace_m_tag.shifted()); polys.memTrace_m_val_shift = Polynomial(polys.memTrace_m_val.shifted()); - polys.memTrace_m_addr_shift = Polynomial(polys.memTrace_m_addr.shifted()); polys.memTrace_m_rw_shift = Polynomial(polys.memTrace_m_rw.shifted()); - polys.memTrace_m_tag_shift = Polynomial(polys.memTrace_m_tag.shifted()); + polys.memTrace_m_addr_shift = Polynomial(polys.memTrace_m_addr.shifted()); return polys; } @@ -163,14 +177,14 @@ class AvmMiniCircuitBuilder { return true; }; - if (!evaluate_relation.template operator()>( - "mem_trace", AvmMini_vm::get_relation_label_mem_trace)) { - return false; - } if (!evaluate_relation.template operator()>("avm_mini", AvmMini_vm::get_relation_label_avm_mini)) { return false; } + if (!evaluate_relation.template operator()>( + "mem_trace", AvmMini_vm::get_relation_label_mem_trace)) { + return false; + } return true; } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp index bba7cf3268a..e8d337389a5 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/Toy_circuit_builder.hpp @@ -91,7 +91,8 @@ class ToyCircuitBuilder { ProverPolynomials polys = compute_polynomials(); const size_t num_rows = polys.get_polynomial_size(); - const auto evaluate_relation = [&](const std::string& relation_name) { + const auto evaluate_relation = [&](const std::string& relation_name, + std::string (*debug_label)(int)) { typename Relation::SumcheckArrayOfValuesOverSubrelations result; for (auto& r : result) { r = 0; @@ -104,8 +105,9 @@ class ToyCircuitBuilder { bool x = true; for (size_t j = 0; j < NUM_SUBRELATIONS; ++j) { if (result[j] != 0) { + std::string row_name = debug_label(static_cast(j)); throw_or_abort( - format("Relation ", relation_name, ", subrelation index ", j, " failed at row ", i)); + format("Relation ", relation_name, ", subrelation index ", row_name, " failed at row ", i)); x = false; } } @@ -131,14 +133,15 @@ class ToyCircuitBuilder { } for (auto r : permutation_result) { if (r != 0) { - info("Tuple", permutation_name, "failed."); + info("Tuple ", permutation_name, " failed."); return false; } } return true; }; - if (!evaluate_relation.template operator()>("toy_avm")) { + if (!evaluate_relation.template operator()>("toy_avm", + Toy_vm::get_relation_label_toy_avm)) { return false; } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp index d590365b76a..46d9a5bc9e9 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp @@ -7,46 +7,67 @@ namespace proof_system::AvmMini_vm { template struct Avm_miniRow { - FF avmMini_sel_op_sub{}; FF avmMini_rwa{}; + FF avmMini_sel_op_div{}; + FF avmMini_inv{}; + FF avmMini_internal_return_ptr{}; + FF avmMini_sel_internal_call{}; FF avmMini_ic{}; - FF avmMini_op_err{}; FF avmMini_rwb{}; - FF avmMini_ia{}; - FF avmMini_inv{}; - FF avmMini_sel_op_div{}; - FF avmMini_tag_err{}; - FF avmMini_sel_op_mul{}; + FF avmMini_sel_halt{}; FF avmMini_sel_op_add{}; - FF avmMini_mem_op_c{}; + FF avmMini_mem_op_b{}; + FF avmMini_op_err{}; FF avmMini_rwc{}; FF avmMini_ib{}; + FF avmMini_mem_idx_a{}; + FF avmMini_sel_op_sub{}; + FF avmMini_sel_op_mul{}; + FF avmMini_ia{}; + FF avmMini_internal_return_ptr_shift{}; + FF avmMini_pc{}; + FF avmMini_pc_shift{}; + FF avmMini_tag_err{}; + FF avmMini_mem_op_c{}; FF avmMini_mem_op_a{}; - FF avmMini_mem_op_b{}; + FF avmMini_sel_internal_return{}; + FF avmMini_first{}; }; inline std::string get_relation_label_avm_mini(int index) { switch (index) { - case 18: - return "SUBOP_DIVISION_FF"; - - case 17: + case 20: return "SUBOP_MULTIPLICATION_FF"; - case 16: - return "SUBOP_SUBTRACTION_FF"; - - case 19: + case 22: return "SUBOP_DIVISION_ZERO_ERR1"; - case 20: + case 23: return "SUBOP_DIVISION_ZERO_ERR2"; - case 21: + case 24: return "SUBOP_ERROR_RELEVANT_OP"; - case 15: + case 25: + return "RETURN_POINTER_INCREMENT"; + + case 30: + return "RETURN_POINTER_DECREMENT"; + + case 35: + return "PC_INCREMENT"; + + case 19: + return "SUBOP_SUBTRACTION_FF"; + + case 21: + return "SUBOP_DIVISION_FF"; + + case 36: + return "INTERNAL_RETURN_POINTER_CONSISTENCY"; + + case 18: return "SUBOP_ADDITION_FF"; } return std::to_string(index); @@ -56,8 +77,8 @@ template class avm_miniImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4, 3, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, }; template @@ -103,7 +124,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(4); - auto tmp = (avmMini_op_err * (-avmMini_op_err + FF(1))); + auto tmp = (avmMini_sel_internal_call * (-avmMini_sel_internal_call + FF(1))); tmp *= scaling_factor; std::get<4>(evals) += tmp; } @@ -111,7 +132,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(5); - auto tmp = (avmMini_tag_err * (-avmMini_tag_err + FF(1))); + auto tmp = (avmMini_sel_internal_return * (-avmMini_sel_internal_return + FF(1))); tmp *= scaling_factor; std::get<5>(evals) += tmp; } @@ -119,7 +140,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(6); - auto tmp = (avmMini_mem_op_a * (-avmMini_mem_op_a + FF(1))); + auto tmp = (avmMini_sel_halt * (-avmMini_sel_halt + FF(1))); tmp *= scaling_factor; std::get<6>(evals) += tmp; } @@ -127,7 +148,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(7); - auto tmp = (avmMini_mem_op_b * (-avmMini_mem_op_b + FF(1))); + auto tmp = (avmMini_op_err * (-avmMini_op_err + FF(1))); tmp *= scaling_factor; std::get<7>(evals) += tmp; } @@ -135,7 +156,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(8); - auto tmp = (avmMini_mem_op_c * (-avmMini_mem_op_c + FF(1))); + auto tmp = (avmMini_tag_err * (-avmMini_tag_err + FF(1))); tmp *= scaling_factor; std::get<8>(evals) += tmp; } @@ -143,7 +164,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(9); - auto tmp = (avmMini_rwa * (-avmMini_rwa + FF(1))); + auto tmp = (avmMini_mem_op_a * (-avmMini_mem_op_a + FF(1))); tmp *= scaling_factor; std::get<9>(evals) += tmp; } @@ -151,7 +172,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(10); - auto tmp = (avmMini_rwb * (-avmMini_rwb + FF(1))); + auto tmp = (avmMini_mem_op_b * (-avmMini_mem_op_b + FF(1))); tmp *= scaling_factor; std::get<10>(evals) += tmp; } @@ -159,7 +180,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(11); - auto tmp = (avmMini_rwc * (-avmMini_rwc + FF(1))); + auto tmp = (avmMini_mem_op_c * (-avmMini_mem_op_c + FF(1))); tmp *= scaling_factor; std::get<11>(evals) += tmp; } @@ -167,7 +188,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(12); - auto tmp = (avmMini_tag_err * avmMini_ia); + auto tmp = (avmMini_rwa * (-avmMini_rwa + FF(1))); tmp *= scaling_factor; std::get<12>(evals) += tmp; } @@ -175,7 +196,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(13); - auto tmp = (avmMini_tag_err * avmMini_ib); + auto tmp = (avmMini_rwb * (-avmMini_rwb + FF(1))); tmp *= scaling_factor; std::get<13>(evals) += tmp; } @@ -183,7 +204,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(14); - auto tmp = (avmMini_tag_err * avmMini_ic); + auto tmp = (avmMini_rwc * (-avmMini_rwc + FF(1))); tmp *= scaling_factor; std::get<14>(evals) += tmp; } @@ -191,7 +212,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(15); - auto tmp = (avmMini_sel_op_add * ((avmMini_ia + avmMini_ib) - avmMini_ic)); + auto tmp = (avmMini_tag_err * avmMini_ia); tmp *= scaling_factor; std::get<15>(evals) += tmp; } @@ -199,7 +220,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(16); - auto tmp = (avmMini_sel_op_sub * ((avmMini_ia - avmMini_ib) - avmMini_ic)); + auto tmp = (avmMini_tag_err * avmMini_ib); tmp *= scaling_factor; std::get<16>(evals) += tmp; } @@ -207,7 +228,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(17); - auto tmp = (avmMini_sel_op_mul * ((avmMini_ia * avmMini_ib) - avmMini_ic)); + auto tmp = (avmMini_tag_err * avmMini_ic); tmp *= scaling_factor; std::get<17>(evals) += tmp; } @@ -215,7 +236,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(18); - auto tmp = ((avmMini_sel_op_div * (-avmMini_op_err + FF(1))) * ((avmMini_ic * avmMini_ib) - avmMini_ia)); + auto tmp = (avmMini_sel_op_add * ((avmMini_ia + avmMini_ib) - avmMini_ic)); tmp *= scaling_factor; std::get<18>(evals) += tmp; } @@ -223,7 +244,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(19); - auto tmp = (avmMini_sel_op_div * (((avmMini_ib * avmMini_inv) - FF(1)) + avmMini_op_err)); + auto tmp = (avmMini_sel_op_sub * ((avmMini_ia - avmMini_ib) - avmMini_ic)); tmp *= scaling_factor; std::get<19>(evals) += tmp; } @@ -231,7 +252,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(20); - auto tmp = ((avmMini_sel_op_div * avmMini_op_err) * (-avmMini_inv + FF(1))); + auto tmp = (avmMini_sel_op_mul * ((avmMini_ia * avmMini_ib) - avmMini_ic)); tmp *= scaling_factor; std::get<20>(evals) += tmp; } @@ -239,10 +260,137 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(21); - auto tmp = (avmMini_op_err * (avmMini_sel_op_div - FF(1))); + auto tmp = ((avmMini_sel_op_div * (-avmMini_op_err + FF(1))) * ((avmMini_ic * avmMini_ib) - avmMini_ia)); tmp *= scaling_factor; std::get<21>(evals) += tmp; } + // Contribution 22 + { + AvmMini_DECLARE_VIEWS(22); + + auto tmp = (avmMini_sel_op_div * (((avmMini_ib * avmMini_inv) - FF(1)) + avmMini_op_err)); + tmp *= scaling_factor; + std::get<22>(evals) += tmp; + } + // Contribution 23 + { + AvmMini_DECLARE_VIEWS(23); + + auto tmp = ((avmMini_sel_op_div * avmMini_op_err) * (-avmMini_inv + FF(1))); + tmp *= scaling_factor; + std::get<23>(evals) += tmp; + } + // Contribution 24 + { + AvmMini_DECLARE_VIEWS(24); + + auto tmp = (avmMini_op_err * (avmMini_sel_op_div - FF(1))); + tmp *= scaling_factor; + std::get<24>(evals) += tmp; + } + // Contribution 25 + { + AvmMini_DECLARE_VIEWS(25); + + auto tmp = (avmMini_sel_internal_call * + (avmMini_internal_return_ptr_shift - (avmMini_internal_return_ptr + FF(1)))); + tmp *= scaling_factor; + std::get<25>(evals) += tmp; + } + // Contribution 26 + { + AvmMini_DECLARE_VIEWS(26); + + auto tmp = (avmMini_sel_internal_call * (avmMini_internal_return_ptr - avmMini_mem_idx_a)); + tmp *= scaling_factor; + std::get<26>(evals) += tmp; + } + // Contribution 27 + { + AvmMini_DECLARE_VIEWS(27); + + auto tmp = (avmMini_sel_internal_call * ((avmMini_pc + FF(1)) - avmMini_ia)); + tmp *= scaling_factor; + std::get<27>(evals) += tmp; + } + // Contribution 28 + { + AvmMini_DECLARE_VIEWS(28); + + auto tmp = (avmMini_sel_internal_call * (avmMini_rwa - FF(1))); + tmp *= scaling_factor; + std::get<28>(evals) += tmp; + } + // Contribution 29 + { + AvmMini_DECLARE_VIEWS(29); + + auto tmp = (avmMini_sel_internal_call * (avmMini_mem_op_a - FF(1))); + tmp *= scaling_factor; + std::get<29>(evals) += tmp; + } + // Contribution 30 + { + AvmMini_DECLARE_VIEWS(30); + + auto tmp = (avmMini_sel_internal_return * + (avmMini_internal_return_ptr_shift - (avmMini_internal_return_ptr - FF(1)))); + tmp *= scaling_factor; + std::get<30>(evals) += tmp; + } + // Contribution 31 + { + AvmMini_DECLARE_VIEWS(31); + + auto tmp = (avmMini_sel_internal_return * ((avmMini_internal_return_ptr - FF(1)) - avmMini_mem_idx_a)); + tmp *= scaling_factor; + std::get<31>(evals) += tmp; + } + // Contribution 32 + { + AvmMini_DECLARE_VIEWS(32); + + auto tmp = (avmMini_sel_internal_return * (avmMini_pc_shift - avmMini_ia)); + tmp *= scaling_factor; + std::get<32>(evals) += tmp; + } + // Contribution 33 + { + AvmMini_DECLARE_VIEWS(33); + + auto tmp = (avmMini_sel_internal_return * avmMini_rwa); + tmp *= scaling_factor; + std::get<33>(evals) += tmp; + } + // Contribution 34 + { + AvmMini_DECLARE_VIEWS(34); + + auto tmp = (avmMini_sel_internal_return * (avmMini_mem_op_a - FF(1))); + tmp *= scaling_factor; + std::get<34>(evals) += tmp; + } + // Contribution 35 + { + AvmMini_DECLARE_VIEWS(35); + + auto tmp = ((((-avmMini_first + FF(1)) * (-avmMini_sel_halt + FF(1))) * + (((avmMini_sel_op_add + avmMini_sel_op_sub) + avmMini_sel_op_div) + avmMini_sel_op_mul)) * + (avmMini_pc_shift - (avmMini_pc + FF(1)))); + tmp *= scaling_factor; + std::get<35>(evals) += tmp; + } + // Contribution 36 + { + AvmMini_DECLARE_VIEWS(36); + + auto tmp = + ((-(((avmMini_first + avmMini_sel_internal_call) + avmMini_sel_internal_return) + avmMini_sel_halt) + + FF(1)) * + (avmMini_internal_return_ptr_shift - avmMini_internal_return_ptr)); + tmp *= scaling_factor; + std::get<36>(evals) += tmp; + } } }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp index 9d23bb0f8f1..0c711d83429 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp @@ -15,6 +15,11 @@ [[maybe_unused]] auto memTrace_m_in_tag = View(new_term.memTrace_m_in_tag); \ [[maybe_unused]] auto memTrace_m_tag_err = View(new_term.memTrace_m_tag_err); \ [[maybe_unused]] auto memTrace_m_one_min_inv = View(new_term.memTrace_m_one_min_inv); \ + [[maybe_unused]] auto avmMini_pc = View(new_term.avmMini_pc); \ + [[maybe_unused]] auto avmMini_internal_return_ptr = View(new_term.avmMini_internal_return_ptr); \ + [[maybe_unused]] auto avmMini_sel_internal_call = View(new_term.avmMini_sel_internal_call); \ + [[maybe_unused]] auto avmMini_sel_internal_return = View(new_term.avmMini_sel_internal_return); \ + [[maybe_unused]] auto avmMini_sel_halt = View(new_term.avmMini_sel_halt); \ [[maybe_unused]] auto avmMini_sel_op_add = View(new_term.avmMini_sel_op_add); \ [[maybe_unused]] auto avmMini_sel_op_sub = View(new_term.avmMini_sel_op_sub); \ [[maybe_unused]] auto avmMini_sel_op_mul = View(new_term.avmMini_sel_op_mul); \ @@ -36,7 +41,9 @@ [[maybe_unused]] auto avmMini_mem_idx_b = View(new_term.avmMini_mem_idx_b); \ [[maybe_unused]] auto avmMini_mem_idx_c = View(new_term.avmMini_mem_idx_c); \ [[maybe_unused]] auto avmMini_last = View(new_term.avmMini_last); \ + [[maybe_unused]] auto avmMini_internal_return_ptr_shift = View(new_term.avmMini_internal_return_ptr_shift); \ + [[maybe_unused]] auto avmMini_pc_shift = View(new_term.avmMini_pc_shift); \ + [[maybe_unused]] auto memTrace_m_tag_shift = View(new_term.memTrace_m_tag_shift); \ [[maybe_unused]] auto memTrace_m_val_shift = View(new_term.memTrace_m_val_shift); \ - [[maybe_unused]] auto memTrace_m_addr_shift = View(new_term.memTrace_m_addr_shift); \ [[maybe_unused]] auto memTrace_m_rw_shift = View(new_term.memTrace_m_rw_shift); \ - [[maybe_unused]] auto memTrace_m_tag_shift = View(new_term.memTrace_m_tag_shift); + [[maybe_unused]] auto memTrace_m_addr_shift = View(new_term.memTrace_m_addr_shift); diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp index 9880acfa631..2adc17baf9f 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp @@ -7,41 +7,41 @@ namespace proof_system::AvmMini_vm { template struct Mem_traceRow { + FF memTrace_m_tag_shift{}; + FF memTrace_m_tag{}; FF memTrace_m_rw{}; - FF memTrace_m_addr{}; - FF memTrace_m_val_shift{}; + FF memTrace_m_lastAccess{}; FF memTrace_m_last{}; FF memTrace_m_tag_err{}; - FF memTrace_m_addr_shift{}; FF memTrace_m_val{}; - FF memTrace_m_lastAccess{}; - FF memTrace_m_tag{}; - FF memTrace_m_in_tag{}; - FF memTrace_m_rw_shift{}; FF memTrace_m_one_min_inv{}; - FF memTrace_m_tag_shift{}; + FF memTrace_m_val_shift{}; + FF memTrace_m_addr{}; + FF memTrace_m_rw_shift{}; + FF memTrace_m_addr_shift{}; + FF memTrace_m_in_tag{}; }; inline std::string get_relation_label_mem_trace(int index) { switch (index) { - case 4: - return "MEM_LAST_ACCESS_DELIMITER"; - - case 6: - return "MEM_READ_WRITE_TAG_CONSISTENCY"; - - case 9: - return "MEM_IN_TAG_CONSISTENCY_2"; - case 5: return "MEM_READ_WRITE_VAL_CONSISTENCY"; case 7: return "MEM_ZERO_INIT"; + case 9: + return "MEM_IN_TAG_CONSISTENCY_2"; + case 8: return "MEM_IN_TAG_CONSISTENCY_1"; + + case 4: + return "MEM_LAST_ACCESS_DELIMITER"; + + case 6: + return "MEM_READ_WRITE_TAG_CONSISTENCY"; } return std::to_string(index); } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/Toy/toy_avm.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/toy_avm.hpp index 40eb15cb6b3..4364cb843ae 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/Toy/toy_avm.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/Toy/toy_avm.hpp @@ -7,10 +7,16 @@ namespace proof_system::Toy_vm { template struct Toy_avmRow { - FF toy_x_shift{}; FF toy_x{}; + FF toy_x_shift{}; }; +inline std::string get_relation_label_toy_avm(int index) +{ + switch (index) {} + return std::to_string(index); +} + template class toy_avmImpl { public: using FF = FF_; diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp index ff07a075419..5673710fa24 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp @@ -73,6 +73,15 @@ bool AvmMiniVerifier::verify_proof(const plonk::proof& proof) transcript->template receive_from_prover(commitment_labels.memTrace_m_tag_err); commitments.memTrace_m_one_min_inv = transcript->template receive_from_prover(commitment_labels.memTrace_m_one_min_inv); + commitments.avmMini_pc = transcript->template receive_from_prover(commitment_labels.avmMini_pc); + commitments.avmMini_internal_return_ptr = + transcript->template receive_from_prover(commitment_labels.avmMini_internal_return_ptr); + commitments.avmMini_sel_internal_call = + transcript->template receive_from_prover(commitment_labels.avmMini_sel_internal_call); + commitments.avmMini_sel_internal_return = + transcript->template receive_from_prover(commitment_labels.avmMini_sel_internal_return); + commitments.avmMini_sel_halt = + transcript->template receive_from_prover(commitment_labels.avmMini_sel_halt); commitments.avmMini_sel_op_add = transcript->template receive_from_prover(commitment_labels.avmMini_sel_op_add); commitments.avmMini_sel_op_sub = diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_composer.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_composer.cpp index 4d2ec73e118..c74903fb635 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_composer.cpp @@ -17,14 +17,10 @@ void ToyComposer::compute_witness(CircuitConstructor& circuit) auto polynomials = circuit.compute_polynomials(); - proving_key->toy_first = polynomials.toy_first; - proving_key->toy_q_tuple_set = polynomials.toy_q_tuple_set; - proving_key->toy_set_1_column_1 = polynomials.toy_set_1_column_1; - proving_key->toy_set_1_column_2 = polynomials.toy_set_1_column_2; - proving_key->toy_set_2_column_1 = polynomials.toy_set_2_column_1; - proving_key->toy_set_2_column_2 = polynomials.toy_set_2_column_2; - proving_key->toy_x = polynomials.toy_x; - proving_key->two_column_perm = polynomials.two_column_perm; + for (auto [key_poly, prover_poly] : zip_view(proving_key->get_all(), polynomials.get_unshifted())) { + ASSERT(flavor_get_label(*proving_key, key_poly) == flavor_get_label(polynomials, prover_poly)); + key_poly = prover_poly; + } computed_witness = true; } diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp index 3d74e03f688..a29c274d1e4 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp @@ -28,7 +28,6 @@ ToyProver::ToyProver(std::shared_ptr input_key, std::shared_ : key(input_key) , commitment_key(commitment_key) { - // TODO: take every polynomial and assign it to the key!! for (auto [prover_poly, key_poly] : zip_view(prover_polynomials.get_unshifted(), key->get_all())) { ASSERT(proof_system::flavor_get_label(prover_polynomials, prover_poly) == proof_system::flavor_get_label(*key, key_poly)); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp index ad7b4342469..a75e798292c 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp @@ -61,6 +61,7 @@ class AvmMiniArithmeticNegativeTests : public AvmMiniArithmeticTests {}; // Test on basic addition over finite field type. TEST_F(AvmMiniArithmeticTests, additionFF) { + // trace_builder trace_builder.callDataCopy(0, 3, 0, std::vector{ 37, 4, 11 }); // Memory layout: [37,4,11,0,0,0,....] @@ -204,6 +205,7 @@ TEST_F(AvmMiniArithmeticTests, divisionByZeroErrorFF) // Memory layout: [15,0,0,0,0,0,....] trace_builder.div(0, 1, 2, AvmMemoryTag::ff); // [15,0,0,0,0,0....] + trace_builder.halt(); auto trace = trace_builder.finalize(); // Find the first row enabling the division selector @@ -226,6 +228,7 @@ TEST_F(AvmMiniArithmeticTests, divisionZeroByZeroErrorFF) { // Memory layout: [0,0,0,0,0,0,....] trace_builder.div(0, 1, 2, AvmMemoryTag::ff); // [0,0,0,0,0,0....] + trace_builder.halt(); auto trace = trace_builder.finalize(); // Find the first row enabling the division selector @@ -261,6 +264,7 @@ TEST_F(AvmMiniArithmeticTests, arithmeticFFWithError) trace_builder.div(1, 1, 9, AvmMemoryTag::ff); // [0,23*136^(-1),45,23,68,136,0,136,136^2,1,0....] trace_builder.div( 9, 0, 4, AvmMemoryTag::ff); // [0,23*136^(-1),45,23,1/0,136,0,136,136^2,1,0....] Error: division by 0 + trace_builder.halt(); auto trace = trace_builder.finalize(); validateTraceProof(std::move(trace)); @@ -380,6 +384,7 @@ TEST_F(AvmMiniArithmeticNegativeTests, divisionByZeroNoErrorFF) // Memory layout: [15,0,0,0,0,0,....] trace_builder.div(0, 1, 2, AvmMemoryTag::ff); // [15,0,0,0,0,0....] + trace_builder.halt(); auto trace = trace_builder.finalize(); // Find the first row enabling the division selector diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp new file mode 100644 index 00000000000..376f7ed1e5f --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp @@ -0,0 +1,253 @@ +#include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/flavor/generated/AvmMini_flavor.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" +#include "barretenberg/proof_system/circuit_builder/AvmMini_helper.hpp" +#include "barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp" +#include "barretenberg/vm/generated/AvmMini_composer.hpp" +#include "barretenberg/vm/generated/AvmMini_prover.hpp" +#include "barretenberg/vm/generated/AvmMini_verifier.hpp" +#include "helpers.test.hpp" + +#include +#include +#include +#include +#include + +using namespace proof_system; + +namespace tests_avm { + +class AvmMiniControlFlowTests : public ::testing::Test { + public: + AvmMiniTraceBuilder trace_builder; + + protected: + // TODO(640): The Standard Honk on Grumpkin test suite fails unless the SRS is initialised for every test. + void SetUp() override + { + barretenberg::srs::init_crs_factory("../srs_db/ignition"); + trace_builder = AvmMiniTraceBuilder(); // Clean instance for every run. + }; +}; + +/****************************************************************************** + * + * POSITIVE TESTS - Control Flow + * + *****************************************************************************/ + +TEST_F(AvmMiniControlFlowTests, simpleCall) +{ + uint32_t const CALL_ADDRESS = 4; + + // trace_builder for the following operation + // pc opcode + // 0 INTERNAL_CALL(pc=4) + // 4 HALT + trace_builder.internal_call(CALL_ADDRESS); + trace_builder.halt(); + + auto trace = trace_builder.finalize(); + + // Check call + { + auto call_row = std::ranges::find_if( + trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_internal_call == FF(1); }); + EXPECT_TRUE(call_row != trace.end()); + EXPECT_EQ(call_row->avmMini_pc, FF(0)); + EXPECT_EQ(call_row->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET)); + EXPECT_EQ(call_row->avmMini_ia, FF(1)); + EXPECT_EQ(call_row->avmMini_mem_idx_a, + FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET)); // Store the return address (0) in memory + } + + // Check halt + { + auto halt_row = + std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_halt == FF(1); }); + + // Check that the correct result is stored at the expected memory location. + EXPECT_TRUE(halt_row != trace.end()); + EXPECT_EQ(halt_row->avmMini_pc, FF(CALL_ADDRESS)); + EXPECT_EQ(halt_row->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 1)); + } + validateTraceProof(std::move(trace)); +} + +TEST_F(AvmMiniControlFlowTests, simpleCallAndReturn) +{ + uint32_t const CALL_ADDRESS = 20; + uint32_t const RETURN_ADDRESS = 1; + // trace_builder for the following operation + // pc opcode + // 0 INTERNAL_CALL(pc=20) + // 20 INTERNAL_RETURN + // 1 HALT + trace_builder.internal_call(CALL_ADDRESS); + trace_builder.internal_return(); + trace_builder.halt(); + + auto trace = trace_builder.finalize(); + + // Check call + { + auto call_row = std::ranges::find_if( + trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_internal_call == FF(1); }); + EXPECT_TRUE(call_row != trace.end()); + EXPECT_EQ(call_row->avmMini_pc, FF(0)); + EXPECT_EQ(call_row->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET)); + EXPECT_EQ(call_row->avmMini_ia, FF(1)); + EXPECT_EQ(call_row->avmMini_mem_idx_a, + FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET)); // Store the return address (0) in memory + } + + // Check return + { + auto return_row = std::ranges::find_if( + trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_internal_return == FF(1); }); + + // Check that the correct result is stored at the expected memory location. + EXPECT_TRUE(return_row != trace.end()); + EXPECT_EQ(return_row->avmMini_pc, FF(CALL_ADDRESS)); + EXPECT_EQ(return_row->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 1)); + } + + // Check halt + { + auto halt_row = + std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_halt == FF(1); }); + + EXPECT_TRUE(halt_row != trace.end()); + EXPECT_EQ(halt_row->avmMini_pc, FF(RETURN_ADDRESS)); + } + + validateTraceProof(std::move(trace)); +} + +TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns) +{ + uint32_t const CALL_ADDRESS_1 = 420; + uint32_t const CALL_ADDRESS_2 = 69; + uint32_t const CALL_ADDRESS_3 = 1337; + uint32_t const CALL_ADDRESS_4 = 4; + + // trace_builder for the following operation + // pc opcode + // 0 INTERNAL_CALL(pc=420) + // 420 INTERNAL_CALL(pc=69) + // 69 INTERNAL_CALL(pc=1337) + // 1337 INTERNAL_RETURN + // 70 INTERNAL_CALL(pc=4) + // 4 INTERNAL_RETURN + // 71 INTERNAL_RETURN + // 421 INTERNAL_RETURN + // 1 HALT + trace_builder.internal_call(CALL_ADDRESS_1); + trace_builder.internal_call(CALL_ADDRESS_2); + trace_builder.internal_call(CALL_ADDRESS_3); + trace_builder.internal_return(); + trace_builder.internal_call(CALL_ADDRESS_4); + trace_builder.internal_return(); + trace_builder.internal_return(); + trace_builder.internal_return(); + trace_builder.halt(); + + auto trace = trace_builder.finalize(); + + // Check call 1 + { + auto call_1 = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { + return r.avmMini_sel_internal_call == FF(1) && r.avmMini_ia == FF(1); + }); + EXPECT_TRUE(call_1 != trace.end()); + EXPECT_EQ(call_1->avmMini_pc, FF(0)); + EXPECT_EQ(call_1->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET)); + EXPECT_EQ(call_1->avmMini_mem_idx_a, + FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET)); // Store the return address (0) in memory + } + + // Call 2 + { + auto call_2 = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { + return r.avmMini_sel_internal_call == FF(1) && r.avmMini_pc == FF(CALL_ADDRESS_1); + }); + EXPECT_TRUE(call_2 != trace.end()); + EXPECT_EQ(call_2->avmMini_ia, FF(CALL_ADDRESS_1 + 1)); + EXPECT_EQ(call_2->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 1)); + EXPECT_EQ(call_2->avmMini_mem_idx_a, + FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 1)); // Store the return address (0) in memory + } + + // Call 3 + { + auto call_3 = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { + return r.avmMini_sel_internal_call == FF(1) && r.avmMini_pc == FF(CALL_ADDRESS_2); + }); + EXPECT_TRUE(call_3 != trace.end()); + EXPECT_EQ(call_3->avmMini_ia, FF(CALL_ADDRESS_2 + 1)); + EXPECT_EQ(call_3->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 2)); + EXPECT_EQ(call_3->avmMini_mem_idx_a, + FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 2)); // Store the return address (0) in memory + } + + // Return 1 + { + auto return_1 = std::ranges::find_if( + trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_internal_return == FF(1); }); + EXPECT_TRUE(return_1 != trace.end()); + EXPECT_EQ(return_1->avmMini_pc, FF(CALL_ADDRESS_3)); + EXPECT_EQ(return_1->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 3)); + } + + // Call 4 + { + auto call_4 = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { + return r.avmMini_sel_internal_call == FF(1) && r.avmMini_pc == FF(CALL_ADDRESS_2 + 1); + }); + EXPECT_TRUE(call_4 != trace.end()); + EXPECT_EQ(call_4->avmMini_ia, FF(CALL_ADDRESS_2 + 2)); + EXPECT_EQ(call_4->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 2)); + EXPECT_EQ(call_4->avmMini_mem_idx_a, + FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 2)); // Store the return address (0) in memory + } + + // Return 2 + { + auto return_2 = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { + return r.avmMini_sel_internal_return == FF(1) && r.avmMini_pc == FF(CALL_ADDRESS_4); + }); + EXPECT_TRUE(return_2 != trace.end()); + EXPECT_EQ(return_2->avmMini_ia, FF(CALL_ADDRESS_2 + 2)); + EXPECT_EQ(return_2->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 3)); + } + + // Return 3 + { + auto return_3 = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { + return r.avmMini_sel_internal_return == FF(1) && r.avmMini_pc == FF(CALL_ADDRESS_2 + 2); + }); + EXPECT_TRUE(return_3 != trace.end()); + EXPECT_EQ(return_3->avmMini_ia, FF(CALL_ADDRESS_1 + 1)); + EXPECT_EQ(return_3->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 2)); + } + + // Return 4 + { + auto return_4 = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { + return r.avmMini_sel_internal_return == FF(1) && r.avmMini_pc == FF(CALL_ADDRESS_1 + 1); + }); + EXPECT_TRUE(return_4 != trace.end()); + EXPECT_EQ(return_4->avmMini_ia, FF(1)); + EXPECT_EQ(return_4->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 1)); + } + + // Halt row + auto halt_row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_halt == FF(1); }); + + EXPECT_TRUE(halt_row != trace.end()); + EXPECT_EQ(halt_row->avmMini_pc, FF(1)); + + validateTraceProof(std::move(trace)); +} +} // namespace tests_avm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp index 31c3355a5ee..893216fb71e 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp @@ -52,6 +52,7 @@ TEST_F(AvmMiniMemoryTests, mismatchedTag) trace_builder.callDataCopy(0, 2, 0, std::vector{ 98, 12 }); trace_builder.add(0, 1, 4, AvmMemoryTag::u8); + trace_builder.halt(); auto trace = trace_builder.finalize(); // Find the first row enabling the addition selector @@ -99,6 +100,7 @@ TEST_F(AvmMiniMemoryTests, mLastAccessViolation) // Memory layout: [4,9,0,0,0,0,....] trace_builder.sub(1, 0, 2, AvmMemoryTag::u8); // [4,9,5,0,0,0.....] + trace_builder.halt(); auto trace = trace_builder.finalize(); // Find the row with subtraction operation @@ -198,6 +200,7 @@ TEST_F(AvmMiniMemoryTests, mismatchedTagErrorViolation) trace_builder.callDataCopy(0, 2, 0, std::vector{ 98, 12 }); trace_builder.sub(0, 1, 4, AvmMemoryTag::u8); + trace_builder.halt(); auto trace = trace_builder.finalize(); // Find the first row enabling the subtraction selector @@ -231,6 +234,7 @@ TEST_F(AvmMiniMemoryTests, consistentTagNoErrorViolation) trace_builder.callDataCopy(0, 2, 0, std::vector{ 84, 7 }); trace_builder.div(0, 1, 4, AvmMemoryTag::ff); + trace_builder.halt(); auto trace = trace_builder.finalize(); // Find the first row enabling the division selector From 66d3111ecb5f6620a993e9213c2eaebb876df7b3 Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:45:48 +0000 Subject: [PATCH 7/8] feat(avm): add standalone jump opcode (#3781) - Add missing check that program counter advanced in call opcode ( oops ) - Moved return storing to intermediate register b - jump dest goes on register a - Implement trivial jump opcode ( subset of call ) --- barretenberg/cpp/pil/avm/avm_mini.pil | 39 ++-- barretenberg/cpp/pil/avm/avm_mini_opt.pil | 68 ------- .../flavor/generated/AvmMini_flavor.hpp | 49 ++--- .../circuit_builder/AvmMini_trace.cpp | 35 +++- .../circuit_builder/AvmMini_trace.hpp | 3 + .../generated/AvmMini_circuit_builder.hpp | 30 +-- .../relations/generated/AvmMini/avm_mini.hpp | 177 ++++++++++-------- .../generated/AvmMini/declare_views.hpp | 9 +- .../relations/generated/AvmMini/mem_trace.hpp | 30 +-- .../vm/generated/AvmMini_verifier.cpp | 2 + .../vm/tests/AvmMini_control_flow.test.cpp | 78 ++++++-- 11 files changed, 289 insertions(+), 231 deletions(-) delete mode 100644 barretenberg/cpp/pil/avm/avm_mini_opt.pil diff --git a/barretenberg/cpp/pil/avm/avm_mini.pil b/barretenberg/cpp/pil/avm/avm_mini.pil index b2e10e30cca..cd3fb8f29e4 100644 --- a/barretenberg/cpp/pil/avm/avm_mini.pil +++ b/barretenberg/cpp/pil/avm/avm_mini.pil @@ -16,6 +16,7 @@ namespace avmMini(256); pol commit sel_internal_call; pol commit sel_internal_return; + pol commit sel_jump; // Halt program execution pol commit sel_halt; @@ -80,6 +81,7 @@ namespace avmMini(256); sel_internal_call * (1 - sel_internal_call) = 0; sel_internal_return * (1 - sel_internal_return) = 0; + sel_jump * (1 - sel_jump) = 0; sel_halt * (1 - sel_halt) = 0; op_err * (1 - op_err) = 0; @@ -147,25 +149,32 @@ namespace avmMini(256); // This works in combination with op_div_err * (sel_op_div - 1) = 0; // Drawback is the need to paralllelize the latter. + //===== CONTROL FLOW ======================================================= + //===== JUMP =============================================================== + sel_jump * (pc' - ia) = 0; - //===== CALL_RETURN ======================================================== - // The program counter in the next row should be equal to the value loaded from the ia register - // This implies that a load from memory must occur at the same time - // Imply that we must load the return location into mem_idx_a + //===== INTERNAL_CALL ====================================================== + // - The program counter in the next row should be equal to the value loaded from the ia register + // - We then write the return location (pc + 1) into the call stack (in memory) #[RETURN_POINTER_INCREMENT] - sel_internal_call * ( internal_return_ptr' - ( internal_return_ptr + 1)) = 0; - sel_internal_call * ( internal_return_ptr - mem_idx_a) = 0; - sel_internal_call * ((pc + 1) - ia) = 0; - + sel_internal_call * (internal_return_ptr' - (internal_return_ptr + 1)) = 0; + sel_internal_call * (internal_return_ptr - mem_idx_b) = 0; + sel_internal_call * (pc' - ia) = 0; + sel_internal_call * ((pc + 1) - ib) = 0; + // TODO(md): Below relations may be removed through sub-op table lookup - sel_internal_call * (rwa - 1) = 0; - sel_internal_call * (mem_op_a - 1) = 0; + sel_internal_call * (rwb - 1) = 0; + sel_internal_call * (mem_op_b - 1) = 0; - // We must load the memory pointer to be the internal_return_ptr + //===== INTERNAL_RETURN =================================================== + // - We load the memory pointer to be the internal_return_ptr + // - Constrain then next program counter to be the loaded value + // - decrement the internal_return_ptr + #[RETURN_POINTER_DECREMENT] - sel_internal_return * ( internal_return_ptr' - ( internal_return_ptr - 1)) = 0; - sel_internal_return * ( (internal_return_ptr - 1) - mem_idx_a) = 0; + sel_internal_return * (internal_return_ptr' - (internal_return_ptr - 1)) = 0; + sel_internal_return * ((internal_return_ptr - 1) - mem_idx_a) = 0; sel_internal_return * (pc' - ia) = 0; // TODO(md): Below relations may be removed through sub-op table lookup @@ -173,7 +182,7 @@ namespace avmMini(256); sel_internal_return * (mem_op_a - 1) = 0; //===== CONTROL_FLOW_CONSISTENCY ============================================ - pol CONTROL_FLOW_SELECTORS = (first + sel_internal_call + sel_internal_return + sel_halt); + pol INTERNAL_CALL_STACK_SELECTORS = (first + sel_internal_call + sel_internal_return + sel_halt); pol OPCODE_SELECTORS = (sel_op_add + sel_op_sub + sel_op_div + sel_op_mul); // Program counter must increment if not jumping or returning @@ -182,7 +191,7 @@ namespace avmMini(256); // first == 0 && sel_internal_call == 0 && sel_internal_return == 0 && sel_halt == 0 ==> internal_return_ptr == internal_return_ptr' #[INTERNAL_RETURN_POINTER_CONSISTENCY] - (1 - CONTROL_FLOW_SELECTORS) * (internal_return_ptr' - internal_return_ptr) = 0; + (1 - INTERNAL_CALL_STACK_SELECTORS) * (internal_return_ptr' - internal_return_ptr) = 0; // TODO: we want to set an initial number for the reserved memory of the jump pointer diff --git a/barretenberg/cpp/pil/avm/avm_mini_opt.pil b/barretenberg/cpp/pil/avm/avm_mini_opt.pil deleted file mode 100644 index f3a75411a99..00000000000 --- a/barretenberg/cpp/pil/avm/avm_mini_opt.pil +++ /dev/null @@ -1,68 +0,0 @@ -namespace memTrace(256); - col witness m_clk; - col witness m_sub_clk; - col witness m_addr; - col witness m_tag; - col witness m_val; - col witness m_lastAccess; - col witness m_last; - col witness m_rw; - col witness m_in_tag; - col witness m_tag_err; - col witness m_one_min_inv; - (memTrace.m_lastAccess * (1 - memTrace.m_lastAccess)) = 0; - (memTrace.m_last * (1 - memTrace.m_last)) = 0; - (memTrace.m_rw * (1 - memTrace.m_rw)) = 0; - (memTrace.m_tag_err * (1 - memTrace.m_tag_err)) = 0; - ((1 - memTrace.m_lastAccess) * (memTrace.m_addr' - memTrace.m_addr)) = 0; - (((1 - memTrace.m_lastAccess) * (1 - memTrace.m_rw')) * (memTrace.m_val' - memTrace.m_val)) = 0; - (((1 - memTrace.m_lastAccess) * (1 - memTrace.m_rw')) * (memTrace.m_tag' - memTrace.m_tag)) = 0; - ((memTrace.m_lastAccess * (1 - memTrace.m_rw')) * memTrace.m_val') = 0; - ((memTrace.m_in_tag - memTrace.m_tag) * (1 - memTrace.m_one_min_inv)) = memTrace.m_tag_err; - ((1 - memTrace.m_tag_err) * memTrace.m_one_min_inv) = 0; -namespace avmMini(256); - col fixed clk(i) { i }; - col fixed first = [1] + [0]*; - col witness sel_op_add; - col witness sel_op_sub; - col witness sel_op_mul; - col witness sel_op_div; - col witness in_tag; - col witness op_err; - col witness tag_err; - col witness inv; - col witness ia; - col witness ib; - col witness ic; - col witness mem_op_a; - col witness mem_op_b; - col witness mem_op_c; - col witness rwa; - col witness rwb; - col witness rwc; - col witness mem_idx_a; - col witness mem_idx_b; - col witness mem_idx_c; - col witness last; - (avmMini.sel_op_add * (1 - avmMini.sel_op_add)) = 0; - (avmMini.sel_op_sub * (1 - avmMini.sel_op_sub)) = 0; - (avmMini.sel_op_mul * (1 - avmMini.sel_op_mul)) = 0; - (avmMini.sel_op_div * (1 - avmMini.sel_op_div)) = 0; - (avmMini.op_err * (1 - avmMini.op_err)) = 0; - (avmMini.tag_err * (1 - avmMini.tag_err)) = 0; - (avmMini.mem_op_a * (1 - avmMini.mem_op_a)) = 0; - (avmMini.mem_op_b * (1 - avmMini.mem_op_b)) = 0; - (avmMini.mem_op_c * (1 - avmMini.mem_op_c)) = 0; - (avmMini.rwa * (1 - avmMini.rwa)) = 0; - (avmMini.rwb * (1 - avmMini.rwb)) = 0; - (avmMini.rwc * (1 - avmMini.rwc)) = 0; - (avmMini.tag_err * avmMini.ia) = 0; - (avmMini.tag_err * avmMini.ib) = 0; - (avmMini.tag_err * avmMini.ic) = 0; - (avmMini.sel_op_add * ((avmMini.ia + avmMini.ib) - avmMini.ic)) = 0; - (avmMini.sel_op_sub * ((avmMini.ia - avmMini.ib) - avmMini.ic)) = 0; - (avmMini.sel_op_mul * ((avmMini.ia * avmMini.ib) - avmMini.ic)) = 0; - ((avmMini.sel_op_div * (1 - avmMini.op_err)) * ((avmMini.ic * avmMini.ib) - avmMini.ia)) = 0; - (avmMini.sel_op_div * (((avmMini.ib * avmMini.inv) - 1) + avmMini.op_err)) = 0; - ((avmMini.sel_op_div * avmMini.op_err) * (1 - avmMini.inv)) = 0; - (avmMini.op_err * (avmMini.sel_op_div - 1)) = 0; diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp index d9b5edb8c61..9240275729e 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp @@ -36,13 +36,13 @@ class AvmMiniFlavor { using VerifierCommitmentKey = pcs::VerifierCommitmentKey; static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 2; - static constexpr size_t NUM_WITNESS_ENTITIES = 37; + static constexpr size_t NUM_WITNESS_ENTITIES = 38; static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted - static constexpr size_t NUM_ALL_ENTITIES = 45; + static constexpr size_t NUM_ALL_ENTITIES = 46; - using Relations = std::tuple, AvmMini_vm::mem_trace>; + using Relations = std::tuple, AvmMini_vm::avm_mini>; static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); @@ -91,6 +91,7 @@ class AvmMiniFlavor { avmMini_internal_return_ptr, avmMini_sel_internal_call, avmMini_sel_internal_return, + avmMini_sel_jump, avmMini_sel_halt, avmMini_sel_op_add, avmMini_sel_op_sub, @@ -131,6 +132,7 @@ class AvmMiniFlavor { avmMini_internal_return_ptr, avmMini_sel_internal_call, avmMini_sel_internal_return, + avmMini_sel_jump, avmMini_sel_halt, avmMini_sel_op_add, avmMini_sel_op_sub, @@ -177,6 +179,7 @@ class AvmMiniFlavor { avmMini_internal_return_ptr, avmMini_sel_internal_call, avmMini_sel_internal_return, + avmMini_sel_jump, avmMini_sel_halt, avmMini_sel_op_add, avmMini_sel_op_sub, @@ -199,12 +202,12 @@ class AvmMiniFlavor { avmMini_mem_idx_b, avmMini_mem_idx_c, avmMini_last, - avmMini_internal_return_ptr_shift, - avmMini_pc_shift, - memTrace_m_tag_shift, memTrace_m_val_shift, + memTrace_m_addr_shift, + memTrace_m_tag_shift, memTrace_m_rw_shift, - memTrace_m_addr_shift) + avmMini_internal_return_ptr_shift, + avmMini_pc_shift) RefVector get_wires() { @@ -225,6 +228,7 @@ class AvmMiniFlavor { avmMini_internal_return_ptr, avmMini_sel_internal_call, avmMini_sel_internal_return, + avmMini_sel_jump, avmMini_sel_halt, avmMini_sel_op_add, avmMini_sel_op_sub, @@ -247,12 +251,12 @@ class AvmMiniFlavor { avmMini_mem_idx_b, avmMini_mem_idx_c, avmMini_last, - avmMini_internal_return_ptr_shift, - avmMini_pc_shift, - memTrace_m_tag_shift, memTrace_m_val_shift, + memTrace_m_addr_shift, + memTrace_m_tag_shift, memTrace_m_rw_shift, - memTrace_m_addr_shift }; + avmMini_internal_return_ptr_shift, + avmMini_pc_shift }; }; RefVector get_unshifted() { @@ -273,6 +277,7 @@ class AvmMiniFlavor { avmMini_internal_return_ptr, avmMini_sel_internal_call, avmMini_sel_internal_return, + avmMini_sel_jump, avmMini_sel_halt, avmMini_sel_op_add, avmMini_sel_op_sub, @@ -298,18 +303,17 @@ class AvmMiniFlavor { }; RefVector get_to_be_shifted() { - return { - avmMini_internal_return_ptr, avmMini_pc, memTrace_m_tag, memTrace_m_val, memTrace_m_rw, memTrace_m_addr - }; + return { memTrace_m_val, memTrace_m_addr, memTrace_m_tag, memTrace_m_rw, avmMini_internal_return_ptr, + avmMini_pc }; }; RefVector get_shifted() { - return { avmMini_internal_return_ptr_shift, - avmMini_pc_shift, + return { memTrace_m_val_shift, + memTrace_m_addr_shift, memTrace_m_tag_shift, - memTrace_m_val_shift, memTrace_m_rw_shift, - memTrace_m_addr_shift }; + avmMini_internal_return_ptr_shift, + avmMini_pc_shift }; }; }; @@ -322,9 +326,8 @@ class AvmMiniFlavor { RefVector get_to_be_shifted() { - return { - avmMini_internal_return_ptr, avmMini_pc, memTrace_m_tag, memTrace_m_val, memTrace_m_rw, memTrace_m_addr - }; + return { memTrace_m_val, memTrace_m_addr, memTrace_m_tag, memTrace_m_rw, avmMini_internal_return_ptr, + avmMini_pc }; }; // The plookup wires that store plookup read data. @@ -418,6 +421,7 @@ class AvmMiniFlavor { Base::avmMini_internal_return_ptr = "AVMMINI_INTERNAL_RETURN_PTR"; Base::avmMini_sel_internal_call = "AVMMINI_SEL_INTERNAL_CALL"; Base::avmMini_sel_internal_return = "AVMMINI_SEL_INTERNAL_RETURN"; + Base::avmMini_sel_jump = "AVMMINI_SEL_JUMP"; Base::avmMini_sel_halt = "AVMMINI_SEL_HALT"; Base::avmMini_sel_op_add = "AVMMINI_SEL_OP_ADD"; Base::avmMini_sel_op_sub = "AVMMINI_SEL_OP_SUB"; @@ -474,6 +478,7 @@ class AvmMiniFlavor { Commitment avmMini_internal_return_ptr; Commitment avmMini_sel_internal_call; Commitment avmMini_sel_internal_return; + Commitment avmMini_sel_jump; Commitment avmMini_sel_halt; Commitment avmMini_sel_op_add; Commitment avmMini_sel_op_sub; @@ -530,6 +535,7 @@ class AvmMiniFlavor { avmMini_internal_return_ptr = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_sel_internal_call = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_sel_internal_return = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); + avmMini_sel_jump = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_sel_halt = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_sel_op_add = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); avmMini_sel_op_sub = deserialize_from_buffer(Transcript::proof_data, num_bytes_read); @@ -590,6 +596,7 @@ class AvmMiniFlavor { serialize_to_buffer(avmMini_internal_return_ptr, Transcript::proof_data); serialize_to_buffer(avmMini_sel_internal_call, Transcript::proof_data); serialize_to_buffer(avmMini_sel_internal_return, Transcript::proof_data); + serialize_to_buffer(avmMini_sel_jump, Transcript::proof_data); serialize_to_buffer(avmMini_sel_halt, Transcript::proof_data); serialize_to_buffer(avmMini_sel_op_add, Transcript::proof_data); serialize_to_buffer(avmMini_sel_op_sub, Transcript::proof_data); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp index 9c6721160f8..308724f2e16 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp @@ -566,6 +566,30 @@ void AvmMiniTraceBuilder::halt() }); } +/** + * @brief JUMP OPCODE + * Jumps to a new `jmpDest` + * This function must: + * - Set the next program counter to the provided `jmpDest`. + * + * @param jmpDest - The destination to jump to + */ +void AvmMiniTraceBuilder::jump(uint32_t jmpDest) +{ + auto clk = mainTrace.size(); + + mainTrace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = FF(pc), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_jump = FF(1), + .avmMini_ia = FF(jmpDest), + }); + + // Adjust parameters for the next row + pc = jmpDest; +} + /** * @brief INTERNAL_CALL OPCODE * This opcode effectively jumps to a new `jmpDest` and stores the return program counter @@ -588,7 +612,7 @@ void AvmMiniTraceBuilder::internal_call(uint32_t jmpDest) internal_call_stack.push(stored_pc); // Add the return location to the memory trace - storeInMemTrace(IntermRegister::ia, internal_return_ptr, FF(stored_pc), AvmMemoryTag::ff); + storeInMemTrace(IntermRegister::ib, internal_return_ptr, FF(stored_pc), AvmMemoryTag::ff); memory.at(internal_return_ptr) = stored_pc; mainTrace.push_back(Row{ @@ -596,10 +620,11 @@ void AvmMiniTraceBuilder::internal_call(uint32_t jmpDest) .avmMini_pc = FF(pc), .avmMini_internal_return_ptr = FF(internal_return_ptr), .avmMini_sel_internal_call = FF(1), - .avmMini_ia = stored_pc, - .avmMini_mem_op_a = FF(1), - .avmMini_rwa = FF(1), - .avmMini_mem_idx_a = FF(internal_return_ptr), + .avmMini_ia = FF(jmpDest), + .avmMini_ib = stored_pc, + .avmMini_mem_op_b = FF(1), + .avmMini_rwb = FF(1), + .avmMini_mem_idx_b = FF(internal_return_ptr), }); // Adjust parameters for the next row diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp index f7dd66f3b3e..0185d76cf97 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp @@ -60,6 +60,9 @@ class AvmMiniTraceBuilder { void div(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag); // Jump to a given program counter. + void jump(uint32_t jmpDest); + + // Jump to a given program counter; storing the return location on a call stack. // TODO(md): this program counter MUST be an operand to the OPCODE. void internal_call(uint32_t jmpDest); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp index a41fb694b9c..bd32d969d15 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp @@ -36,6 +36,7 @@ template struct AvmMiniFullRow { FF avmMini_internal_return_ptr{}; FF avmMini_sel_internal_call{}; FF avmMini_sel_internal_return{}; + FF avmMini_sel_jump{}; FF avmMini_sel_halt{}; FF avmMini_sel_op_add{}; FF avmMini_sel_op_sub{}; @@ -58,12 +59,12 @@ template struct AvmMiniFullRow { FF avmMini_mem_idx_b{}; FF avmMini_mem_idx_c{}; FF avmMini_last{}; - FF avmMini_internal_return_ptr_shift{}; - FF avmMini_pc_shift{}; - FF memTrace_m_tag_shift{}; FF memTrace_m_val_shift{}; - FF memTrace_m_rw_shift{}; FF memTrace_m_addr_shift{}; + FF memTrace_m_tag_shift{}; + FF memTrace_m_rw_shift{}; + FF avmMini_internal_return_ptr_shift{}; + FF avmMini_pc_shift{}; }; class AvmMiniCircuitBuilder { @@ -76,8 +77,8 @@ class AvmMiniCircuitBuilder { using Polynomial = Flavor::Polynomial; using ProverPolynomials = Flavor::ProverPolynomials; - static constexpr size_t num_fixed_columns = 45; - static constexpr size_t num_polys = 39; + static constexpr size_t num_fixed_columns = 46; + static constexpr size_t num_polys = 40; std::vector rows; void set_trace(std::vector&& trace) { rows = std::move(trace); } @@ -110,6 +111,7 @@ class AvmMiniCircuitBuilder { polys.avmMini_internal_return_ptr[i] = rows[i].avmMini_internal_return_ptr; polys.avmMini_sel_internal_call[i] = rows[i].avmMini_sel_internal_call; polys.avmMini_sel_internal_return[i] = rows[i].avmMini_sel_internal_return; + polys.avmMini_sel_jump[i] = rows[i].avmMini_sel_jump; polys.avmMini_sel_halt[i] = rows[i].avmMini_sel_halt; polys.avmMini_sel_op_add[i] = rows[i].avmMini_sel_op_add; polys.avmMini_sel_op_sub[i] = rows[i].avmMini_sel_op_sub; @@ -134,12 +136,12 @@ class AvmMiniCircuitBuilder { polys.avmMini_last[i] = rows[i].avmMini_last; } - polys.avmMini_internal_return_ptr_shift = Polynomial(polys.avmMini_internal_return_ptr.shifted()); - polys.avmMini_pc_shift = Polynomial(polys.avmMini_pc.shifted()); - polys.memTrace_m_tag_shift = Polynomial(polys.memTrace_m_tag.shifted()); polys.memTrace_m_val_shift = Polynomial(polys.memTrace_m_val.shifted()); - polys.memTrace_m_rw_shift = Polynomial(polys.memTrace_m_rw.shifted()); polys.memTrace_m_addr_shift = Polynomial(polys.memTrace_m_addr.shifted()); + polys.memTrace_m_tag_shift = Polynomial(polys.memTrace_m_tag.shifted()); + polys.memTrace_m_rw_shift = Polynomial(polys.memTrace_m_rw.shifted()); + polys.avmMini_internal_return_ptr_shift = Polynomial(polys.avmMini_internal_return_ptr.shifted()); + polys.avmMini_pc_shift = Polynomial(polys.avmMini_pc.shifted()); return polys; } @@ -177,14 +179,14 @@ class AvmMiniCircuitBuilder { return true; }; - if (!evaluate_relation.template operator()>("avm_mini", - AvmMini_vm::get_relation_label_avm_mini)) { - return false; - } if (!evaluate_relation.template operator()>( "mem_trace", AvmMini_vm::get_relation_label_mem_trace)) { return false; } + if (!evaluate_relation.template operator()>("avm_mini", + AvmMini_vm::get_relation_label_avm_mini)) { + return false; + } return true; } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp index 46d9a5bc9e9..7ad4452af56 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/avm_mini.hpp @@ -7,68 +7,70 @@ namespace proof_system::AvmMini_vm { template struct Avm_miniRow { + FF avmMini_first{}; + FF avmMini_sel_jump{}; + FF avmMini_internal_return_ptr_shift{}; + FF avmMini_pc{}; + FF avmMini_tag_err{}; + FF avmMini_mem_idx_a{}; + FF avmMini_sel_op_add{}; + FF avmMini_rwb{}; + FF avmMini_rwc{}; + FF avmMini_sel_internal_return{}; FF avmMini_rwa{}; - FF avmMini_sel_op_div{}; FF avmMini_inv{}; - FF avmMini_internal_return_ptr{}; FF avmMini_sel_internal_call{}; - FF avmMini_ic{}; - FF avmMini_rwb{}; - FF avmMini_sel_halt{}; - FF avmMini_sel_op_add{}; - FF avmMini_mem_op_b{}; FF avmMini_op_err{}; - FF avmMini_rwc{}; - FF avmMini_ib{}; - FF avmMini_mem_idx_a{}; - FF avmMini_sel_op_sub{}; + FF avmMini_pc_shift{}; FF avmMini_sel_op_mul{}; + FF avmMini_sel_op_div{}; + FF avmMini_sel_op_sub{}; + FF avmMini_mem_op_b{}; + FF avmMini_sel_halt{}; FF avmMini_ia{}; - FF avmMini_internal_return_ptr_shift{}; - FF avmMini_pc{}; - FF avmMini_pc_shift{}; - FF avmMini_tag_err{}; - FF avmMini_mem_op_c{}; FF avmMini_mem_op_a{}; - FF avmMini_sel_internal_return{}; - FF avmMini_first{}; + FF avmMini_ic{}; + FF avmMini_ib{}; + FF avmMini_internal_return_ptr{}; + FF avmMini_mem_op_c{}; + FF avmMini_mem_idx_b{}; }; inline std::string get_relation_label_avm_mini(int index) { switch (index) { + case 24: + return "SUBOP_DIVISION_ZERO_ERR2"; + case 20: - return "SUBOP_MULTIPLICATION_FF"; + return "SUBOP_SUBTRACTION_FF"; + + case 38: + return "PC_INCREMENT"; case 22: - return "SUBOP_DIVISION_ZERO_ERR1"; + return "SUBOP_DIVISION_FF"; case 23: - return "SUBOP_DIVISION_ZERO_ERR2"; - - case 24: - return "SUBOP_ERROR_RELEVANT_OP"; - - case 25: - return "RETURN_POINTER_INCREMENT"; - - case 30: - return "RETURN_POINTER_DECREMENT"; + return "SUBOP_DIVISION_ZERO_ERR1"; - case 35: - return "PC_INCREMENT"; + case 21: + return "SUBOP_MULTIPLICATION_FF"; case 19: - return "SUBOP_SUBTRACTION_FF"; + return "SUBOP_ADDITION_FF"; - case 21: - return "SUBOP_DIVISION_FF"; + case 33: + return "RETURN_POINTER_DECREMENT"; - case 36: + case 39: return "INTERNAL_RETURN_POINTER_CONSISTENCY"; - case 18: - return "SUBOP_ADDITION_FF"; + case 25: + return "SUBOP_ERROR_RELEVANT_OP"; + + case 27: + return "RETURN_POINTER_INCREMENT"; } return std::to_string(index); } @@ -77,8 +79,9 @@ template class avm_miniImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 4, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, }; template @@ -140,7 +143,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(6); - auto tmp = (avmMini_sel_halt * (-avmMini_sel_halt + FF(1))); + auto tmp = (avmMini_sel_jump * (-avmMini_sel_jump + FF(1))); tmp *= scaling_factor; std::get<6>(evals) += tmp; } @@ -148,7 +151,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(7); - auto tmp = (avmMini_op_err * (-avmMini_op_err + FF(1))); + auto tmp = (avmMini_sel_halt * (-avmMini_sel_halt + FF(1))); tmp *= scaling_factor; std::get<7>(evals) += tmp; } @@ -156,7 +159,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(8); - auto tmp = (avmMini_tag_err * (-avmMini_tag_err + FF(1))); + auto tmp = (avmMini_op_err * (-avmMini_op_err + FF(1))); tmp *= scaling_factor; std::get<8>(evals) += tmp; } @@ -164,7 +167,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(9); - auto tmp = (avmMini_mem_op_a * (-avmMini_mem_op_a + FF(1))); + auto tmp = (avmMini_tag_err * (-avmMini_tag_err + FF(1))); tmp *= scaling_factor; std::get<9>(evals) += tmp; } @@ -172,7 +175,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(10); - auto tmp = (avmMini_mem_op_b * (-avmMini_mem_op_b + FF(1))); + auto tmp = (avmMini_mem_op_a * (-avmMini_mem_op_a + FF(1))); tmp *= scaling_factor; std::get<10>(evals) += tmp; } @@ -180,7 +183,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(11); - auto tmp = (avmMini_mem_op_c * (-avmMini_mem_op_c + FF(1))); + auto tmp = (avmMini_mem_op_b * (-avmMini_mem_op_b + FF(1))); tmp *= scaling_factor; std::get<11>(evals) += tmp; } @@ -188,7 +191,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(12); - auto tmp = (avmMini_rwa * (-avmMini_rwa + FF(1))); + auto tmp = (avmMini_mem_op_c * (-avmMini_mem_op_c + FF(1))); tmp *= scaling_factor; std::get<12>(evals) += tmp; } @@ -196,7 +199,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(13); - auto tmp = (avmMini_rwb * (-avmMini_rwb + FF(1))); + auto tmp = (avmMini_rwa * (-avmMini_rwa + FF(1))); tmp *= scaling_factor; std::get<13>(evals) += tmp; } @@ -204,7 +207,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(14); - auto tmp = (avmMini_rwc * (-avmMini_rwc + FF(1))); + auto tmp = (avmMini_rwb * (-avmMini_rwb + FF(1))); tmp *= scaling_factor; std::get<14>(evals) += tmp; } @@ -212,7 +215,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(15); - auto tmp = (avmMini_tag_err * avmMini_ia); + auto tmp = (avmMini_rwc * (-avmMini_rwc + FF(1))); tmp *= scaling_factor; std::get<15>(evals) += tmp; } @@ -220,7 +223,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(16); - auto tmp = (avmMini_tag_err * avmMini_ib); + auto tmp = (avmMini_tag_err * avmMini_ia); tmp *= scaling_factor; std::get<16>(evals) += tmp; } @@ -228,7 +231,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(17); - auto tmp = (avmMini_tag_err * avmMini_ic); + auto tmp = (avmMini_tag_err * avmMini_ib); tmp *= scaling_factor; std::get<17>(evals) += tmp; } @@ -236,7 +239,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(18); - auto tmp = (avmMini_sel_op_add * ((avmMini_ia + avmMini_ib) - avmMini_ic)); + auto tmp = (avmMini_tag_err * avmMini_ic); tmp *= scaling_factor; std::get<18>(evals) += tmp; } @@ -244,7 +247,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(19); - auto tmp = (avmMini_sel_op_sub * ((avmMini_ia - avmMini_ib) - avmMini_ic)); + auto tmp = (avmMini_sel_op_add * ((avmMini_ia + avmMini_ib) - avmMini_ic)); tmp *= scaling_factor; std::get<19>(evals) += tmp; } @@ -252,7 +255,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(20); - auto tmp = (avmMini_sel_op_mul * ((avmMini_ia * avmMini_ib) - avmMini_ic)); + auto tmp = (avmMini_sel_op_sub * ((avmMini_ia - avmMini_ib) - avmMini_ic)); tmp *= scaling_factor; std::get<20>(evals) += tmp; } @@ -260,7 +263,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(21); - auto tmp = ((avmMini_sel_op_div * (-avmMini_op_err + FF(1))) * ((avmMini_ic * avmMini_ib) - avmMini_ia)); + auto tmp = (avmMini_sel_op_mul * ((avmMini_ia * avmMini_ib) - avmMini_ic)); tmp *= scaling_factor; std::get<21>(evals) += tmp; } @@ -268,7 +271,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(22); - auto tmp = (avmMini_sel_op_div * (((avmMini_ib * avmMini_inv) - FF(1)) + avmMini_op_err)); + auto tmp = ((avmMini_sel_op_div * (-avmMini_op_err + FF(1))) * ((avmMini_ic * avmMini_ib) - avmMini_ia)); tmp *= scaling_factor; std::get<22>(evals) += tmp; } @@ -276,7 +279,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(23); - auto tmp = ((avmMini_sel_op_div * avmMini_op_err) * (-avmMini_inv + FF(1))); + auto tmp = (avmMini_sel_op_div * (((avmMini_ib * avmMini_inv) - FF(1)) + avmMini_op_err)); tmp *= scaling_factor; std::get<23>(evals) += tmp; } @@ -284,7 +287,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(24); - auto tmp = (avmMini_op_err * (avmMini_sel_op_div - FF(1))); + auto tmp = ((avmMini_sel_op_div * avmMini_op_err) * (-avmMini_inv + FF(1))); tmp *= scaling_factor; std::get<24>(evals) += tmp; } @@ -292,8 +295,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(25); - auto tmp = (avmMini_sel_internal_call * - (avmMini_internal_return_ptr_shift - (avmMini_internal_return_ptr + FF(1)))); + auto tmp = (avmMini_op_err * (avmMini_sel_op_div - FF(1))); tmp *= scaling_factor; std::get<25>(evals) += tmp; } @@ -301,7 +303,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(26); - auto tmp = (avmMini_sel_internal_call * (avmMini_internal_return_ptr - avmMini_mem_idx_a)); + auto tmp = (avmMini_sel_jump * (avmMini_pc_shift - avmMini_ia)); tmp *= scaling_factor; std::get<26>(evals) += tmp; } @@ -309,7 +311,8 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(27); - auto tmp = (avmMini_sel_internal_call * ((avmMini_pc + FF(1)) - avmMini_ia)); + auto tmp = (avmMini_sel_internal_call * + (avmMini_internal_return_ptr_shift - (avmMini_internal_return_ptr + FF(1)))); tmp *= scaling_factor; std::get<27>(evals) += tmp; } @@ -317,7 +320,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(28); - auto tmp = (avmMini_sel_internal_call * (avmMini_rwa - FF(1))); + auto tmp = (avmMini_sel_internal_call * (avmMini_internal_return_ptr - avmMini_mem_idx_b)); tmp *= scaling_factor; std::get<28>(evals) += tmp; } @@ -325,7 +328,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(29); - auto tmp = (avmMini_sel_internal_call * (avmMini_mem_op_a - FF(1))); + auto tmp = (avmMini_sel_internal_call * (avmMini_pc_shift - avmMini_ia)); tmp *= scaling_factor; std::get<29>(evals) += tmp; } @@ -333,8 +336,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(30); - auto tmp = (avmMini_sel_internal_return * - (avmMini_internal_return_ptr_shift - (avmMini_internal_return_ptr - FF(1)))); + auto tmp = (avmMini_sel_internal_call * ((avmMini_pc + FF(1)) - avmMini_ib)); tmp *= scaling_factor; std::get<30>(evals) += tmp; } @@ -342,7 +344,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(31); - auto tmp = (avmMini_sel_internal_return * ((avmMini_internal_return_ptr - FF(1)) - avmMini_mem_idx_a)); + auto tmp = (avmMini_sel_internal_call * (avmMini_rwb - FF(1))); tmp *= scaling_factor; std::get<31>(evals) += tmp; } @@ -350,7 +352,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(32); - auto tmp = (avmMini_sel_internal_return * (avmMini_pc_shift - avmMini_ia)); + auto tmp = (avmMini_sel_internal_call * (avmMini_mem_op_b - FF(1))); tmp *= scaling_factor; std::get<32>(evals) += tmp; } @@ -358,7 +360,8 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(33); - auto tmp = (avmMini_sel_internal_return * avmMini_rwa); + auto tmp = (avmMini_sel_internal_return * + (avmMini_internal_return_ptr_shift - (avmMini_internal_return_ptr - FF(1)))); tmp *= scaling_factor; std::get<33>(evals) += tmp; } @@ -366,7 +369,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(34); - auto tmp = (avmMini_sel_internal_return * (avmMini_mem_op_a - FF(1))); + auto tmp = (avmMini_sel_internal_return * ((avmMini_internal_return_ptr - FF(1)) - avmMini_mem_idx_a)); tmp *= scaling_factor; std::get<34>(evals) += tmp; } @@ -374,9 +377,7 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(35); - auto tmp = ((((-avmMini_first + FF(1)) * (-avmMini_sel_halt + FF(1))) * - (((avmMini_sel_op_add + avmMini_sel_op_sub) + avmMini_sel_op_div) + avmMini_sel_op_mul)) * - (avmMini_pc_shift - (avmMini_pc + FF(1)))); + auto tmp = (avmMini_sel_internal_return * (avmMini_pc_shift - avmMini_ia)); tmp *= scaling_factor; std::get<35>(evals) += tmp; } @@ -384,12 +385,38 @@ template class avm_miniImpl { { AvmMini_DECLARE_VIEWS(36); + auto tmp = (avmMini_sel_internal_return * avmMini_rwa); + tmp *= scaling_factor; + std::get<36>(evals) += tmp; + } + // Contribution 37 + { + AvmMini_DECLARE_VIEWS(37); + + auto tmp = (avmMini_sel_internal_return * (avmMini_mem_op_a - FF(1))); + tmp *= scaling_factor; + std::get<37>(evals) += tmp; + } + // Contribution 38 + { + AvmMini_DECLARE_VIEWS(38); + + auto tmp = ((((-avmMini_first + FF(1)) * (-avmMini_sel_halt + FF(1))) * + (((avmMini_sel_op_add + avmMini_sel_op_sub) + avmMini_sel_op_div) + avmMini_sel_op_mul)) * + (avmMini_pc_shift - (avmMini_pc + FF(1)))); + tmp *= scaling_factor; + std::get<38>(evals) += tmp; + } + // Contribution 39 + { + AvmMini_DECLARE_VIEWS(39); + auto tmp = ((-(((avmMini_first + avmMini_sel_internal_call) + avmMini_sel_internal_return) + avmMini_sel_halt) + FF(1)) * (avmMini_internal_return_ptr_shift - avmMini_internal_return_ptr)); tmp *= scaling_factor; - std::get<36>(evals) += tmp; + std::get<39>(evals) += tmp; } } }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp index 0c711d83429..2bd134b6298 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/declare_views.hpp @@ -19,6 +19,7 @@ [[maybe_unused]] auto avmMini_internal_return_ptr = View(new_term.avmMini_internal_return_ptr); \ [[maybe_unused]] auto avmMini_sel_internal_call = View(new_term.avmMini_sel_internal_call); \ [[maybe_unused]] auto avmMini_sel_internal_return = View(new_term.avmMini_sel_internal_return); \ + [[maybe_unused]] auto avmMini_sel_jump = View(new_term.avmMini_sel_jump); \ [[maybe_unused]] auto avmMini_sel_halt = View(new_term.avmMini_sel_halt); \ [[maybe_unused]] auto avmMini_sel_op_add = View(new_term.avmMini_sel_op_add); \ [[maybe_unused]] auto avmMini_sel_op_sub = View(new_term.avmMini_sel_op_sub); \ @@ -41,9 +42,9 @@ [[maybe_unused]] auto avmMini_mem_idx_b = View(new_term.avmMini_mem_idx_b); \ [[maybe_unused]] auto avmMini_mem_idx_c = View(new_term.avmMini_mem_idx_c); \ [[maybe_unused]] auto avmMini_last = View(new_term.avmMini_last); \ - [[maybe_unused]] auto avmMini_internal_return_ptr_shift = View(new_term.avmMini_internal_return_ptr_shift); \ - [[maybe_unused]] auto avmMini_pc_shift = View(new_term.avmMini_pc_shift); \ - [[maybe_unused]] auto memTrace_m_tag_shift = View(new_term.memTrace_m_tag_shift); \ [[maybe_unused]] auto memTrace_m_val_shift = View(new_term.memTrace_m_val_shift); \ + [[maybe_unused]] auto memTrace_m_addr_shift = View(new_term.memTrace_m_addr_shift); \ + [[maybe_unused]] auto memTrace_m_tag_shift = View(new_term.memTrace_m_tag_shift); \ [[maybe_unused]] auto memTrace_m_rw_shift = View(new_term.memTrace_m_rw_shift); \ - [[maybe_unused]] auto memTrace_m_addr_shift = View(new_term.memTrace_m_addr_shift); + [[maybe_unused]] auto avmMini_internal_return_ptr_shift = View(new_term.avmMini_internal_return_ptr_shift); \ + [[maybe_unused]] auto avmMini_pc_shift = View(new_term.avmMini_pc_shift); diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp index 2adc17baf9f..ef96061a9ca 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/AvmMini/mem_trace.hpp @@ -7,32 +7,29 @@ namespace proof_system::AvmMini_vm { template struct Mem_traceRow { - FF memTrace_m_tag_shift{}; - FF memTrace_m_tag{}; - FF memTrace_m_rw{}; - FF memTrace_m_lastAccess{}; FF memTrace_m_last{}; + FF memTrace_m_val_shift{}; + FF memTrace_m_rw{}; FF memTrace_m_tag_err{}; + FF memTrace_m_addr_shift{}; + FF memTrace_m_lastAccess{}; + FF memTrace_m_tag_shift{}; + FF memTrace_m_tag{}; FF memTrace_m_val{}; - FF memTrace_m_one_min_inv{}; - FF memTrace_m_val_shift{}; - FF memTrace_m_addr{}; FF memTrace_m_rw_shift{}; - FF memTrace_m_addr_shift{}; FF memTrace_m_in_tag{}; + FF memTrace_m_addr{}; + FF memTrace_m_one_min_inv{}; }; inline std::string get_relation_label_mem_trace(int index) { switch (index) { - case 5: - return "MEM_READ_WRITE_VAL_CONSISTENCY"; - case 7: return "MEM_ZERO_INIT"; - case 9: - return "MEM_IN_TAG_CONSISTENCY_2"; + case 6: + return "MEM_READ_WRITE_TAG_CONSISTENCY"; case 8: return "MEM_IN_TAG_CONSISTENCY_1"; @@ -40,8 +37,11 @@ inline std::string get_relation_label_mem_trace(int index) case 4: return "MEM_LAST_ACCESS_DELIMITER"; - case 6: - return "MEM_READ_WRITE_TAG_CONSISTENCY"; + case 5: + return "MEM_READ_WRITE_VAL_CONSISTENCY"; + + case 9: + return "MEM_IN_TAG_CONSISTENCY_2"; } return std::to_string(index); } diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp index 5673710fa24..f0b102ede71 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp @@ -80,6 +80,8 @@ bool AvmMiniVerifier::verify_proof(const plonk::proof& proof) transcript->template receive_from_prover(commitment_labels.avmMini_sel_internal_call); commitments.avmMini_sel_internal_return = transcript->template receive_from_prover(commitment_labels.avmMini_sel_internal_return); + commitments.avmMini_sel_jump = + transcript->template receive_from_prover(commitment_labels.avmMini_sel_jump); commitments.avmMini_sel_halt = transcript->template receive_from_prover(commitment_labels.avmMini_sel_halt); commitments.avmMini_sel_op_add = diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp index 376f7ed1e5f..c771ad6eaf6 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp @@ -56,9 +56,10 @@ TEST_F(AvmMiniControlFlowTests, simpleCall) trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_internal_call == FF(1); }); EXPECT_TRUE(call_row != trace.end()); EXPECT_EQ(call_row->avmMini_pc, FF(0)); + EXPECT_EQ(call_row->avmMini_ia, FF(CALL_ADDRESS)); EXPECT_EQ(call_row->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET)); - EXPECT_EQ(call_row->avmMini_ia, FF(1)); - EXPECT_EQ(call_row->avmMini_mem_idx_a, + EXPECT_EQ(call_row->avmMini_ib, FF(1)); + EXPECT_EQ(call_row->avmMini_mem_idx_b, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET)); // Store the return address (0) in memory } @@ -75,6 +76,39 @@ TEST_F(AvmMiniControlFlowTests, simpleCall) validateTraceProof(std::move(trace)); } +TEST_F(AvmMiniControlFlowTests, simpleJump) +{ + uint32_t const JUMP_ADDRESS = 4; + + // trace_builder for the following operation + // pc opcode + // 0 JUMP(pc=4) + // 4 HALT + trace_builder.jump(JUMP_ADDRESS); + trace_builder.halt(); + + auto trace = trace_builder.finalize(); + + // Check jump + { + auto call_row = + std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_jump == FF(1); }); + EXPECT_TRUE(call_row != trace.end()); + EXPECT_EQ(call_row->avmMini_pc, FF(0)); + EXPECT_EQ(call_row->avmMini_ia, FF(JUMP_ADDRESS)); + } + + // Check halt + { + auto halt_row = + std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_halt == FF(1); }); + + EXPECT_TRUE(halt_row != trace.end()); + EXPECT_EQ(halt_row->avmMini_pc, FF(JUMP_ADDRESS)); + } + validateTraceProof(std::move(trace)); +} + TEST_F(AvmMiniControlFlowTests, simpleCallAndReturn) { uint32_t const CALL_ADDRESS = 20; @@ -97,8 +131,8 @@ TEST_F(AvmMiniControlFlowTests, simpleCallAndReturn) EXPECT_TRUE(call_row != trace.end()); EXPECT_EQ(call_row->avmMini_pc, FF(0)); EXPECT_EQ(call_row->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET)); - EXPECT_EQ(call_row->avmMini_ia, FF(1)); - EXPECT_EQ(call_row->avmMini_mem_idx_a, + EXPECT_EQ(call_row->avmMini_ib, FF(1)); + EXPECT_EQ(call_row->avmMini_mem_idx_b, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET)); // Store the return address (0) in memory } @@ -132,6 +166,8 @@ TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns) uint32_t const CALL_ADDRESS_3 = 1337; uint32_t const CALL_ADDRESS_4 = 4; + uint32_t const JUMP_ADDRESS_1 = 22; + // trace_builder for the following operation // pc opcode // 0 INTERNAL_CALL(pc=420) @@ -140,7 +176,8 @@ TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns) // 1337 INTERNAL_RETURN // 70 INTERNAL_CALL(pc=4) // 4 INTERNAL_RETURN - // 71 INTERNAL_RETURN + // 71 JUMP(pc=22) + // 22 INTERNAL_RETURN // 421 INTERNAL_RETURN // 1 HALT trace_builder.internal_call(CALL_ADDRESS_1); @@ -149,6 +186,7 @@ TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns) trace_builder.internal_return(); trace_builder.internal_call(CALL_ADDRESS_4); trace_builder.internal_return(); + trace_builder.jump(JUMP_ADDRESS_1); trace_builder.internal_return(); trace_builder.internal_return(); trace_builder.halt(); @@ -158,12 +196,13 @@ TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns) // Check call 1 { auto call_1 = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { - return r.avmMini_sel_internal_call == FF(1) && r.avmMini_ia == FF(1); + return r.avmMini_sel_internal_call == FF(1) && r.avmMini_ib == FF(1); }); EXPECT_TRUE(call_1 != trace.end()); EXPECT_EQ(call_1->avmMini_pc, FF(0)); + EXPECT_EQ(call_1->avmMini_ia, FF(CALL_ADDRESS_1)); EXPECT_EQ(call_1->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET)); - EXPECT_EQ(call_1->avmMini_mem_idx_a, + EXPECT_EQ(call_1->avmMini_mem_idx_b, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET)); // Store the return address (0) in memory } @@ -173,9 +212,10 @@ TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns) return r.avmMini_sel_internal_call == FF(1) && r.avmMini_pc == FF(CALL_ADDRESS_1); }); EXPECT_TRUE(call_2 != trace.end()); - EXPECT_EQ(call_2->avmMini_ia, FF(CALL_ADDRESS_1 + 1)); + EXPECT_EQ(call_2->avmMini_ib, FF(CALL_ADDRESS_1 + 1)); + EXPECT_EQ(call_2->avmMini_ia, FF(CALL_ADDRESS_2)); EXPECT_EQ(call_2->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 1)); - EXPECT_EQ(call_2->avmMini_mem_idx_a, + EXPECT_EQ(call_2->avmMini_mem_idx_b, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 1)); // Store the return address (0) in memory } @@ -185,9 +225,9 @@ TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns) return r.avmMini_sel_internal_call == FF(1) && r.avmMini_pc == FF(CALL_ADDRESS_2); }); EXPECT_TRUE(call_3 != trace.end()); - EXPECT_EQ(call_3->avmMini_ia, FF(CALL_ADDRESS_2 + 1)); + EXPECT_EQ(call_3->avmMini_ib, FF(CALL_ADDRESS_2 + 1)); EXPECT_EQ(call_3->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 2)); - EXPECT_EQ(call_3->avmMini_mem_idx_a, + EXPECT_EQ(call_3->avmMini_mem_idx_b, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 2)); // Store the return address (0) in memory } @@ -206,9 +246,9 @@ TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns) return r.avmMini_sel_internal_call == FF(1) && r.avmMini_pc == FF(CALL_ADDRESS_2 + 1); }); EXPECT_TRUE(call_4 != trace.end()); - EXPECT_EQ(call_4->avmMini_ia, FF(CALL_ADDRESS_2 + 2)); + EXPECT_EQ(call_4->avmMini_ib, FF(CALL_ADDRESS_2 + 2)); EXPECT_EQ(call_4->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 2)); - EXPECT_EQ(call_4->avmMini_mem_idx_a, + EXPECT_EQ(call_4->avmMini_mem_idx_b, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 2)); // Store the return address (0) in memory } @@ -222,10 +262,20 @@ TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns) EXPECT_EQ(return_2->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 3)); } + // Jump 1 + { + auto jump_1 = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { + return r.avmMini_sel_jump == FF(1) && r.avmMini_pc == FF(CALL_ADDRESS_2 + 2); + }); + EXPECT_TRUE(jump_1 != trace.end()); + EXPECT_EQ(jump_1->avmMini_ia, FF(JUMP_ADDRESS_1)); + EXPECT_EQ(jump_1->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 2)); + } + // Return 3 { auto return_3 = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { - return r.avmMini_sel_internal_return == FF(1) && r.avmMini_pc == FF(CALL_ADDRESS_2 + 2); + return r.avmMini_sel_internal_return == FF(1) && r.avmMini_pc == FF(JUMP_ADDRESS_1); }); EXPECT_TRUE(return_3 != trace.end()); EXPECT_EQ(return_3->avmMini_ia, FF(CALL_ADDRESS_1 + 1)); From 56c34ca637dfb96a061482f81c6ec596dd2476e5 Mon Sep 17 00:00:00 2001 From: Jean M <132435771+jeanmon@users.noreply.github.com> Date: Fri, 5 Jan 2024 11:34:35 +0100 Subject: [PATCH 8/8] refactor(avm): avm memory trace building (#3835) Resolves #3834 Moving all AVM memory related trace building functions into a dedicated class. Furthermore, all AVM related trace files were moved into a dedicated folder in vm. The following files: - AvmMini_common.hpp - AvmMini_helper.cpp - AvmMini_helper.hpp - AvmMini_mem_trace.cpp - AvmMini_mem_trace.hpp - AvmMini_trace.cpp - AvmMini_trace.hpp were moved from barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ to barretenberg/cpp/src/barretenberg/vm/avm_trace/ Finally, the namespace for these files were migrating from proof_system to avm_trace. --- .../circuit_builder/AvmMini_trace.cpp | 743 ------------------ .../circuit_builder/AvmMini_trace.hpp | 114 --- .../avm_trace/AvmMini_common.hpp} | 14 +- .../avm_trace}/AvmMini_helper.cpp | 11 +- .../vm/avm_trace/AvmMini_helper.hpp | 9 + .../vm/avm_trace/AvmMini_mem_trace.cpp | 244 ++++++ .../vm/avm_trace/AvmMini_mem_trace.hpp | 68 ++ .../vm/avm_trace/AvmMini_trace.cpp | 597 ++++++++++++++ .../vm/avm_trace/AvmMini_trace.hpp | 71 ++ .../vm/tests/AvmMini_arithmetic.test.cpp | 118 ++- .../vm/tests/AvmMini_control_flow.test.cpp | 17 +- .../vm/tests/AvmMini_memory.test.cpp | 58 +- .../barretenberg/vm/tests/helpers.test.cpp | 22 +- .../barretenberg/vm/tests/helpers.test.hpp | 6 +- 14 files changed, 1100 insertions(+), 992 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp rename barretenberg/cpp/src/barretenberg/{proof_system/circuit_builder/AvmMini_helper.hpp => vm/avm_trace/AvmMini_common.hpp} (54%) rename barretenberg/cpp/src/barretenberg/{proof_system/circuit_builder => vm/avm_trace}/AvmMini_helper.cpp (91%) create mode 100644 barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_helper.hpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_mem_trace.cpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_mem_trace.hpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.cpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.hpp diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp deleted file mode 100644 index 308724f2e16..00000000000 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.cpp +++ /dev/null @@ -1,743 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "./AvmMini_trace.hpp" -#include "./generated/AvmMini_circuit_builder.hpp" - -namespace proof_system { - -/** - * @brief Constructor of a trace builder of AVM. Only serves to set the capacity of the - * underlying traces. - */ -AvmMiniTraceBuilder::AvmMiniTraceBuilder() -{ - mainTrace.reserve(N); - memTrace.reserve(N); -} - -/** - * @brief Resetting the internal state so that a new trace can be rebuilt using the same object. - * - */ -void AvmMiniTraceBuilder::reset() -{ - mainTrace.clear(); - memTrace.clear(); - memory.fill(FF(0)); -} - -/** - * @brief A comparator on MemoryTraceEntry to be used by sorting algorithm. - * - */ -bool AvmMiniTraceBuilder::compareMemEntries(const MemoryTraceEntry& left, const MemoryTraceEntry& right) -{ - if (left.m_addr < right.m_addr) { - return true; - } - - if (left.m_addr > right.m_addr) { - return false; - } - - if (left.m_clk < right.m_clk) { - return true; - } - - if (left.m_clk > right.m_clk) { - return false; - } - - // No safeguard in case they are equal. The caller should ensure this property. - // Otherwise, relation will not be satisfied. - return left.m_sub_clk < right.m_sub_clk; -} - -/** - * @brief A method to insert a row/entry in the memory trace. - * - * @param m_clk Main clock - * @param m_sub_clk Sub-clock used to order load/store sub operations - * @param m_addr Address pertaining to the memory operation - * @param m_val Value (FF) pertaining to the memory operation - * @param m_in_tag Memory tag pertaining to the instruction - * @param m_rw Boolean telling whether it is a load (false) or store operation (true). - */ -void AvmMiniTraceBuilder::insertInMemTrace( - uint32_t m_clk, uint32_t m_sub_clk, uint32_t m_addr, FF m_val, AvmMemoryTag m_in_tag, bool m_rw) -{ - memTrace.emplace_back(MemoryTraceEntry{ - .m_clk = m_clk, - .m_sub_clk = m_sub_clk, - .m_addr = m_addr, - .m_val = m_val, - .m_tag = m_in_tag, - .m_in_tag = m_in_tag, - .m_rw = m_rw, - }); -} - -void AvmMiniTraceBuilder::loadMismatchTagInMemTrace( - uint32_t m_clk, uint32_t m_sub_clk, uint32_t m_addr, FF m_val, AvmMemoryTag m_in_tag, AvmMemoryTag m_tag) -{ - FF one_min_inv = FF(1) - (FF(static_cast(m_in_tag)) - FF(static_cast(m_tag))).invert(); - memTrace.emplace_back(MemoryTraceEntry{ .m_clk = m_clk, - .m_sub_clk = m_sub_clk, - .m_addr = m_addr, - .m_val = m_val, - .m_tag = m_tag, - .m_in_tag = m_in_tag, - .m_tag_err = true, - .m_one_min_inv = one_min_inv }); -} - -// Memory operations need to be performed before the addition of the corresponding row in -// MainTrace, otherwise the m_clk value will be wrong. This applies to loadInMemTrace and -// storeInMemTrace. - -/** - * @brief Add a memory trace entry corresponding to a memory load into the intermediate - * passed register. - * - * @param intermReg The intermediate register - * @param addr The memory address - * @param val The value to be loaded - * @param m_in_tag The memory tag of the instruction - */ -bool AvmMiniTraceBuilder::loadInMemTrace(IntermRegister intermReg, uint32_t addr, FF val, AvmMemoryTag m_in_tag) -{ - uint32_t sub_clk = 0; - switch (intermReg) { - case IntermRegister::ia: - sub_clk = SUB_CLK_LOAD_A; - break; - case IntermRegister::ib: - sub_clk = SUB_CLK_LOAD_B; - break; - case IntermRegister::ic: - sub_clk = SUB_CLK_LOAD_C; - break; - } - - auto m_tag = memoryTag.at(addr); - if (m_tag == AvmMemoryTag::u0 || m_tag == m_in_tag) { - insertInMemTrace(static_cast(mainTrace.size()), sub_clk, addr, val, m_in_tag, false); - return true; - } - - // Handle memory tag inconsistency - loadMismatchTagInMemTrace(static_cast(mainTrace.size()), sub_clk, addr, val, m_in_tag, m_tag); - return false; -} - -/** - * @brief Add a memory trace entry corresponding to a memory store from the intermediate - * register. - * - * @param intermReg The intermediate register - * @param addr The memory address - * @param val The value to be stored - * @param m_in_tag The memory tag of the instruction - */ -void AvmMiniTraceBuilder::storeInMemTrace(IntermRegister intermReg, uint32_t addr, FF val, AvmMemoryTag m_in_tag) -{ - uint32_t sub_clk = 0; - switch (intermReg) { - case IntermRegister::ia: - sub_clk = SUB_CLK_STORE_A; - break; - case IntermRegister::ib: - sub_clk = SUB_CLK_STORE_B; - break; - case IntermRegister::ic: - sub_clk = SUB_CLK_STORE_C; - break; - } - - insertInMemTrace(static_cast(mainTrace.size()), sub_clk, addr, val, m_in_tag, true); -} - -/** TODO: Implement for non finite field types - * @brief Addition with direct memory access. - * - * @param aOffset An index in memory pointing to the first operand of the addition. - * @param bOffset An index in memory pointing to the second operand of the addition. - * @param dstOffset An index in memory pointing to the output of the addition. - * @param inTag The instruction memory tag of the operands. - */ -void AvmMiniTraceBuilder::add(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag) -{ - // a + b = c - FF a = memory.at(aOffset); - FF b = memory.at(bOffset); - FF c = a + b; - memory.at(dstOffset) = c; - memoryTag.at(dstOffset) = inTag; - - // Loading into Ia, Ib and storing into Ic - bool tagMatch = loadInMemTrace(IntermRegister::ia, aOffset, a, inTag); - tagMatch = loadInMemTrace(IntermRegister::ib, bOffset, b, inTag) && tagMatch; - storeInMemTrace(IntermRegister::ic, dstOffset, c, inTag); - - auto clk = mainTrace.size(); - - mainTrace.push_back(Row{ - .avmMini_clk = clk, - .avmMini_pc = FF(pc++), - .avmMini_internal_return_ptr = FF(internal_return_ptr), - .avmMini_sel_op_add = FF(1), - .avmMini_in_tag = FF(static_cast(inTag)), - .avmMini_tag_err = FF(static_cast(!tagMatch)), - .avmMini_ia = tagMatch ? a : FF(0), - .avmMini_ib = tagMatch ? b : FF(0), - .avmMini_ic = tagMatch ? c : FF(0), - .avmMini_mem_op_a = FF(1), - .avmMini_mem_op_b = FF(1), - .avmMini_mem_op_c = FF(1), - .avmMini_rwc = FF(1), - .avmMini_mem_idx_a = FF(aOffset), - .avmMini_mem_idx_b = FF(bOffset), - .avmMini_mem_idx_c = FF(dstOffset), - }); -}; - -/** TODO: Implement for non finite field types - * @brief Subtraction with direct memory access. - * - * @param aOffset An index in memory pointing to the first operand of the subtraction. - * @param bOffset An index in memory pointing to the second operand of the subtraction. - * @param dstOffset An index in memory pointing to the output of the subtraction. - * @param inTag The instruction memory tag of the operands. - */ -void AvmMiniTraceBuilder::sub(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag) -{ - // a - b = c - FF a = memory.at(aOffset); - FF b = memory.at(bOffset); - FF c = a - b; - memory.at(dstOffset) = c; - memoryTag.at(dstOffset) = inTag; - - // Loading into Ia, Ib and storing into Ic - bool tagMatch = loadInMemTrace(IntermRegister::ia, aOffset, a, inTag); - tagMatch = loadInMemTrace(IntermRegister::ib, bOffset, b, inTag) && tagMatch; - storeInMemTrace(IntermRegister::ic, dstOffset, c, inTag); - - auto clk = mainTrace.size(); - - mainTrace.push_back(Row{ - .avmMini_clk = clk, - .avmMini_pc = FF(pc++), - .avmMini_internal_return_ptr = FF(internal_return_ptr), - .avmMini_sel_op_sub = FF(1), - .avmMini_in_tag = FF(static_cast(inTag)), - .avmMini_tag_err = FF(static_cast(!tagMatch)), - .avmMini_ia = tagMatch ? a : FF(0), - .avmMini_ib = tagMatch ? b : FF(0), - .avmMini_ic = tagMatch ? c : FF(0), - .avmMini_mem_op_a = FF(1), - .avmMini_mem_op_b = FF(1), - .avmMini_mem_op_c = FF(1), - .avmMini_rwc = FF(1), - .avmMini_mem_idx_a = FF(aOffset), - .avmMini_mem_idx_b = FF(bOffset), - .avmMini_mem_idx_c = FF(dstOffset), - }); -}; - -/** TODO: Implement for non finite field types - * @brief Multiplication with direct memory access. - * - * @param aOffset An index in memory pointing to the first operand of the multiplication. - * @param bOffset An index in memory pointing to the second operand of the multiplication. - * @param dstOffset An index in memory pointing to the output of the multiplication. - * @param inTag The instruction memory tag of the operands. - */ -void AvmMiniTraceBuilder::mul(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag) -{ - // a * b = c - FF a = memory.at(aOffset); - FF b = memory.at(bOffset); - FF c = a * b; - memory.at(dstOffset) = c; - memoryTag.at(dstOffset) = inTag; - - // Loading into Ia, Ib and storing into Ic - bool tagMatch = loadInMemTrace(IntermRegister::ia, aOffset, a, inTag); - tagMatch = loadInMemTrace(IntermRegister::ib, bOffset, b, inTag) && tagMatch; - storeInMemTrace(IntermRegister::ic, dstOffset, c, inTag); - - auto clk = mainTrace.size(); - - mainTrace.push_back(Row{ - .avmMini_clk = clk, - .avmMini_pc = FF(pc++), - .avmMini_internal_return_ptr = FF(internal_return_ptr), - .avmMini_sel_op_mul = FF(1), - .avmMini_in_tag = FF(static_cast(inTag)), - .avmMini_tag_err = FF(static_cast(!tagMatch)), - .avmMini_ia = tagMatch ? a : FF(0), - .avmMini_ib = tagMatch ? b : FF(0), - .avmMini_ic = tagMatch ? c : FF(0), - .avmMini_mem_op_a = FF(1), - .avmMini_mem_op_b = FF(1), - .avmMini_mem_op_c = FF(1), - .avmMini_rwc = FF(1), - .avmMini_mem_idx_a = FF(aOffset), - .avmMini_mem_idx_b = FF(bOffset), - .avmMini_mem_idx_c = FF(dstOffset), - }); -} - -/** TODO: Implement for non finite field types - * @brief Division with direct memory access. - * - * @param aOffset An index in memory pointing to the first operand of the division. - * @param bOffset An index in memory pointing to the second operand of the division. - * @param dstOffset An index in memory pointing to the output of the division. - * @param inTag The instruction memory tag of the operands. - */ -void AvmMiniTraceBuilder::div(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag) -{ - // a * b^(-1) = c - FF a = memory.at(aOffset); - FF b = memory.at(bOffset); - FF c; - FF inv; - FF error; - - if (!b.is_zero()) { - - inv = b.invert(); - c = a * inv; - error = 0; - } else { - inv = 1; - c = 0; - error = 1; - } - - memory.at(dstOffset) = c; - memoryTag.at(dstOffset) = inTag; - - // Loading into Ia, Ib and storing into Ic - bool tagMatch = loadInMemTrace(IntermRegister::ia, aOffset, a, inTag); - tagMatch = loadInMemTrace(IntermRegister::ib, bOffset, b, inTag) && tagMatch; - storeInMemTrace(IntermRegister::ic, dstOffset, c, inTag); - - auto clk = mainTrace.size(); - - mainTrace.push_back(Row{ - .avmMini_clk = clk, - .avmMini_pc = FF(pc++), - .avmMini_internal_return_ptr = FF(internal_return_ptr), - .avmMini_sel_op_div = FF(1), - .avmMini_in_tag = FF(static_cast(inTag)), - .avmMini_op_err = tagMatch ? error : FF(1), - .avmMini_tag_err = FF(static_cast(!tagMatch)), - .avmMini_inv = tagMatch ? inv : FF(1), - .avmMini_ia = tagMatch ? a : FF(0), - .avmMini_ib = tagMatch ? b : FF(0), - .avmMini_ic = tagMatch ? c : FF(0), - .avmMini_mem_op_a = FF(1), - .avmMini_mem_op_b = FF(1), - .avmMini_mem_op_c = FF(1), - .avmMini_rwc = FF(1), - .avmMini_mem_idx_a = FF(aOffset), - .avmMini_mem_idx_b = FF(bOffset), - .avmMini_mem_idx_c = FF(dstOffset), - }); -} - -/** - * @brief CALLDATACOPY opcode with direct memory access, i.e., - * M[dstOffset:dstOffset+copySize] = calldata[cdOffset:cdOffset+copySize] - * Simplified version with exclusively memory store operations and - * values from M_calldata passed by an array and loaded into - * intermediate registers. - * Assume that caller passes callDataMem which is large enough so that - * no out-of-bound memory issues occur. - * TODO: Implement the indirect memory version (maybe not required) - * TODO: taking care of intermediate register values consistency and propagating their - * values to the next row when not overwritten. - * - * @param cdOffset The starting index of the region in calldata to be copied. - * @param copySize The number of finite field elements to be copied into memory. - * @param dstOffset The starting index of memory where calldata will be copied to. - * @param callDataMem The vector containing calldata. - */ -void AvmMiniTraceBuilder::callDataCopy(uint32_t cdOffset, - uint32_t copySize, - uint32_t dstOffset, - std::vector const& callDataMem) -{ - // We parallelize storing memory operations in chunk of 3, i.e., 1 per intermediate register. - // The variable pos is an index pointing to the first storing operation (pertaining to intermediate - // register Ia) relative to cdOffset: - // cdOffset + pos: Ia memory store operation - // cdOffset + pos + 1: Ib memory store operation - // cdOffset + pos + 2: Ic memory store operation - - uint32_t pos = 0; - - while (pos < copySize) { - FF ib(0); - FF ic(0); - uint32_t mem_op_b(0); - uint32_t mem_op_c(0); - uint32_t mem_idx_b(0); - uint32_t mem_idx_c(0); - uint32_t rwb(0); - uint32_t rwc(0); - auto clk = mainTrace.size(); - - FF ia = callDataMem.at(cdOffset + pos); - uint32_t mem_op_a(1); - uint32_t mem_idx_a = dstOffset + pos; - uint32_t rwa = 1; - - // Storing from Ia - memory.at(mem_idx_a) = ia; - memoryTag.at(mem_idx_a) = AvmMemoryTag::ff; - storeInMemTrace(IntermRegister::ia, mem_idx_a, ia, AvmMemoryTag::ff); - - if (copySize - pos > 1) { - ib = callDataMem.at(cdOffset + pos + 1); - mem_op_b = 1; - mem_idx_b = dstOffset + pos + 1; - rwb = 1; - - // Storing from Ib - memory.at(mem_idx_b) = ib; - memoryTag.at(mem_idx_b) = AvmMemoryTag::ff; - storeInMemTrace(IntermRegister::ib, mem_idx_b, ib, AvmMemoryTag::ff); - } - - if (copySize - pos > 2) { - ic = callDataMem.at(cdOffset + pos + 2); - mem_op_c = 1; - mem_idx_c = dstOffset + pos + 2; - rwc = 1; - - // Storing from Ic - memory.at(mem_idx_c) = ic; - memoryTag.at(mem_idx_c) = AvmMemoryTag::ff; - storeInMemTrace(IntermRegister::ic, mem_idx_c, ic, AvmMemoryTag::ff); - } - - mainTrace.push_back(Row{ - .avmMini_clk = clk, - .avmMini_pc = FF(pc++), - .avmMini_internal_return_ptr = FF(internal_return_ptr), - .avmMini_in_tag = FF(static_cast(AvmMemoryTag::ff)), - .avmMini_ia = ia, - .avmMini_ib = ib, - .avmMini_ic = ic, - .avmMini_mem_op_a = FF(mem_op_a), - .avmMini_mem_op_b = FF(mem_op_b), - .avmMini_mem_op_c = FF(mem_op_c), - .avmMini_rwa = FF(rwa), - .avmMini_rwb = FF(rwb), - .avmMini_rwc = FF(rwc), - .avmMini_mem_idx_a = FF(mem_idx_a), - .avmMini_mem_idx_b = FF(mem_idx_b), - .avmMini_mem_idx_c = FF(mem_idx_c), - }); - - if (copySize - pos > 2) { // Guard to prevent overflow if copySize is close to uint32_t maximum value. - pos += 3; - } else { - pos = copySize; - } - } -} - -/** - * @brief RETURN opcode with direct memory access, i.e., - * return(M[retOffset:retOffset+retSize]) - * Simplified version with exclusively memory load operations into - * intermediate registers and then values are copied to the returned vector. - * TODO: Implement the indirect memory version (maybe not required) - * TODO: taking care of flagging this row as the last one? Special STOP flag? - * - * @param retOffset The starting index of the memory region to be returned. - * @param retSize The number of elements to be returned. - * @return The returned memory region as a std::vector. - */ - -std::vector AvmMiniTraceBuilder::returnOP(uint32_t retOffset, uint32_t retSize) -{ - // We parallelize loading memory operations in chunk of 3, i.e., 1 per intermediate register. - // The variable pos is an index pointing to the first storing operation (pertaining to intermediate - // register Ia) relative to retOffset: - // retOffset + pos: Ia memory load operation - // retOffset + pos + 1: Ib memory load operation - // retOffset + pos + 2: Ic memory load operation - - uint32_t pos = 0; - std::vector returnMem; - - while (pos < retSize) { - FF ib(0); - FF ic(0); - uint32_t mem_op_b(0); - uint32_t mem_op_c(0); - uint32_t mem_idx_b(0); - uint32_t mem_idx_c(0); - auto clk = mainTrace.size(); - - uint32_t mem_op_a(1); - uint32_t mem_idx_a = retOffset + pos; - FF ia = memory.at(mem_idx_a); - - // Loading from Ia - returnMem.push_back(ia); - loadInMemTrace(IntermRegister::ia, mem_idx_a, ia, AvmMemoryTag::ff); - - if (retSize - pos > 1) { - mem_op_b = 1; - mem_idx_b = retOffset + pos + 1; - ib = memory.at(mem_idx_b); - - // Loading from Ib - returnMem.push_back(ib); - loadInMemTrace(IntermRegister::ib, mem_idx_b, ib, AvmMemoryTag::ff); - } - - if (retSize - pos > 2) { - mem_op_c = 1; - mem_idx_c = retOffset + pos + 2; - ic = memory.at(mem_idx_c); - - // Loading from Ic - returnMem.push_back(ic); - loadInMemTrace(IntermRegister::ic, mem_idx_c, ic, AvmMemoryTag::ff); - } - - mainTrace.push_back(Row{ - .avmMini_clk = clk, - .avmMini_pc = FF(pc), - .avmMini_internal_return_ptr = FF(internal_return_ptr), - .avmMini_sel_halt = FF(1), - .avmMini_in_tag = FF(static_cast(AvmMemoryTag::ff)), - .avmMini_ia = ia, - .avmMini_ib = ib, - .avmMini_ic = ic, - .avmMini_mem_op_a = FF(mem_op_a), - .avmMini_mem_op_b = FF(mem_op_b), - .avmMini_mem_op_c = FF(mem_op_c), - .avmMini_mem_idx_a = FF(mem_idx_a), - .avmMini_mem_idx_b = FF(mem_idx_b), - .avmMini_mem_idx_c = FF(mem_idx_c), - }); - - if (retSize - pos > 2) { // Guard to prevent overflow if retSize is close to uint32_t maximum value. - pos += 3; - } else { - pos = retSize; - } - } - return returnMem; -} - -/** - * @brief HALT opcode - * This opcode effectively stops program execution, and is used in the relation that - * ensures the program counter increments on each opcode. - * i.e.ythe program counter should freeze and the halt flag is set to 1. - */ -void AvmMiniTraceBuilder::halt() -{ - auto clk = mainTrace.size(); - - mainTrace.push_back(Row{ - .avmMini_clk = clk, - .avmMini_pc = FF(pc), - .avmMini_internal_return_ptr = FF(internal_return_ptr), - .avmMini_sel_halt = FF(1), - }); -} - -/** - * @brief JUMP OPCODE - * Jumps to a new `jmpDest` - * This function must: - * - Set the next program counter to the provided `jmpDest`. - * - * @param jmpDest - The destination to jump to - */ -void AvmMiniTraceBuilder::jump(uint32_t jmpDest) -{ - auto clk = mainTrace.size(); - - mainTrace.push_back(Row{ - .avmMini_clk = clk, - .avmMini_pc = FF(pc), - .avmMini_internal_return_ptr = FF(internal_return_ptr), - .avmMini_sel_jump = FF(1), - .avmMini_ia = FF(jmpDest), - }); - - // Adjust parameters for the next row - pc = jmpDest; -} - -/** - * @brief INTERNAL_CALL OPCODE - * This opcode effectively jumps to a new `jmpDest` and stores the return program counter - * (current program counter + 1) onto a call stack. - * This function must: - * - Set the next program counter to the provided `jmpDest`. - * - Store the current `pc` + 1 onto the call stack (emulated in memory) - * - Increment the return stack pointer (a pointer to where the call stack is in memory) - * - * Note: We use intermediate register to perform memory storage operations. - * - * @param jmpDest - The destination to jump to - */ -void AvmMiniTraceBuilder::internal_call(uint32_t jmpDest) -{ - auto clk = mainTrace.size(); - - // We store the next instruction as the return location - uint32_t stored_pc = pc + 1; - internal_call_stack.push(stored_pc); - - // Add the return location to the memory trace - storeInMemTrace(IntermRegister::ib, internal_return_ptr, FF(stored_pc), AvmMemoryTag::ff); - memory.at(internal_return_ptr) = stored_pc; - - mainTrace.push_back(Row{ - .avmMini_clk = clk, - .avmMini_pc = FF(pc), - .avmMini_internal_return_ptr = FF(internal_return_ptr), - .avmMini_sel_internal_call = FF(1), - .avmMini_ia = FF(jmpDest), - .avmMini_ib = stored_pc, - .avmMini_mem_op_b = FF(1), - .avmMini_rwb = FF(1), - .avmMini_mem_idx_b = FF(internal_return_ptr), - }); - - // Adjust parameters for the next row - pc = jmpDest; - internal_return_ptr++; -} - -/** - * @brief INTERNAL_RETURN OPCODE - * The opcode returns from an internal call. - * This function must: - * - Read the return location from the internal_return_ptr - * - Set the next program counter to the return location - * - Decrement the return stack pointer - * - * TODO(https://github.com/AztecProtocol/aztec-packages/issues/3740): This function MUST come after a call instruction. - */ -void AvmMiniTraceBuilder::internal_return() -{ - auto clk = mainTrace.size(); - - // Internal return pointer is decremented - FF a = memory.at(internal_return_ptr - 1); - - // We want to load the value pointed by the internal pointer - loadInMemTrace(IntermRegister::ia, internal_return_ptr - 1, FF(a), AvmMemoryTag::ff); - - mainTrace.push_back(Row{ - .avmMini_clk = clk, - .avmMini_pc = pc, - .avmMini_internal_return_ptr = FF(internal_return_ptr), - .avmMini_sel_internal_return = FF(1), - .avmMini_ia = a, - .avmMini_mem_op_a = FF(1), - .avmMini_rwa = FF(0), - .avmMini_mem_idx_a = FF(internal_return_ptr - 1), - }); - - // We want the next row to be the one pointed by jmpDest - // The next pc should be from the top of the internal call stack + 1 - pc = internal_call_stack.top(); - internal_call_stack.pop(); - internal_return_ptr--; -} - -/** - * @brief Helper to initialize ffMemory. (Testing purpose mostly.) - * - */ -void AvmMiniTraceBuilder::setFFMem(size_t idx, FF el, AvmMemoryTag tag) -{ - memory.at(idx) = el; - memoryTag.at(idx) = tag; -}; - -/** - * @brief Finalisation of the memory trace and incorporating it to the main trace. - * In particular, sorting the memory trace, setting .m_lastAccess and - * adding shifted values (first row). The main trace is moved at the end of - * this call. - * - * @return The main trace - */ -std::vector AvmMiniTraceBuilder::finalize() -{ - size_t memTraceSize = memTrace.size(); - size_t mainTraceSize = mainTrace.size(); - - // TODO: We will have to handle this through error handling and not an assertion - // Smaller than N because we have to add an extra initial row to support shifted - // elements - assert(memTraceSize < N); - assert(mainTraceSize < N); - - // Sort memTrace - std::sort(memTrace.begin(), memTrace.end(), compareMemEntries); - - // Fill the rest with zeros. - size_t zeroRowsNum = N - mainTraceSize - 1; - while (zeroRowsNum-- > 0) { - mainTrace.push_back(Row{}); - } - - mainTrace.at(mainTraceSize - 1).avmMini_last = FF(1); - - for (size_t i = 0; i < memTraceSize; i++) { - auto const& src = memTrace.at(i); - auto& dest = mainTrace.at(i); - - dest.memTrace_m_clk = FF(src.m_clk); - dest.memTrace_m_sub_clk = FF(src.m_sub_clk); - dest.memTrace_m_addr = FF(src.m_addr); - dest.memTrace_m_val = src.m_val; - dest.memTrace_m_rw = FF(static_cast(src.m_rw)); - dest.memTrace_m_in_tag = FF(static_cast(src.m_in_tag)); - dest.memTrace_m_tag = FF(static_cast(src.m_tag)); - dest.memTrace_m_tag_err = FF(static_cast(src.m_tag_err)); - dest.memTrace_m_one_min_inv = src.m_one_min_inv; - - if (i + 1 < memTraceSize) { - auto const& next = memTrace.at(i + 1); - dest.memTrace_m_lastAccess = FF(static_cast(src.m_addr != next.m_addr)); - } else { - dest.memTrace_m_lastAccess = FF(1); - dest.memTrace_m_last = FF(1); - } - } - - // Adding extra row for the shifted values at the top of the execution trace. - Row first_row = Row{ .avmMini_first = FF(1), .memTrace_m_lastAccess = FF(1) }; - mainTrace.insert(mainTrace.begin(), first_row); - - return std::move(mainTrace); -} - -} // namespace proof_system \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp deleted file mode 100644 index 0185d76cf97..00000000000 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp +++ /dev/null @@ -1,114 +0,0 @@ -#pragma once - -#include - -#include "barretenberg/common/throw_or_abort.hpp" -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp" -#include "barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp" - -#include "barretenberg/flavor/generated/AvmMini_flavor.hpp" - -#include "barretenberg/relations/generated/AvmMini/avm_mini.hpp" - -using Flavor = proof_system::honk::flavor::AvmMiniFlavor; -using FF = Flavor::FF; -using Row = proof_system::AvmMiniFullRow; - -namespace proof_system { - -enum class IntermRegister : uint32_t { ia = 0, ib = 1, ic = 2 }; -enum class AvmMemoryTag : uint32_t { u0 = 0, u8 = 1, u16 = 2, u32 = 3, u64 = 4, u128 = 5, ff = 6 }; - -// This is the internal context that we keep along the lifecycle of bytecode execution -// to iteratively build the whole trace. This is effectively performing witness generation. -// At the end of circuit building, mainTrace can be moved to AvmMiniCircuitBuilder by calling -// AvmMiniCircuitBuilder::set_trace(rows). -class AvmMiniTraceBuilder { - - public: - // Number of rows - static const size_t N = 256; - static const size_t MEM_SIZE = 1024; - static const size_t CALLSTACK_OFFSET = 896; // TODO(md): Temporary reserved area 896 - 1024 - - static const uint32_t SUB_CLK_LOAD_A = 0; - static const uint32_t SUB_CLK_LOAD_B = 1; - static const uint32_t SUB_CLK_LOAD_C = 2; - static const uint32_t SUB_CLK_STORE_A = 3; - static const uint32_t SUB_CLK_STORE_B = 4; - static const uint32_t SUB_CLK_STORE_C = 5; - - AvmMiniTraceBuilder(); - - // Temporary helper to initialize memory. - void setFFMem(size_t idx, FF el, AvmMemoryTag tag); - - std::vector finalize(); - void reset(); - - // Addition with direct memory access. - void add(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag); - - // Subtraction with direct memory access. - void sub(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag); - - // Multiplication with direct memory access. - void mul(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag); - - // Division with direct memory access. - void div(uint32_t aOffset, uint32_t bOffset, uint32_t dstOffset, AvmMemoryTag inTag); - - // Jump to a given program counter. - void jump(uint32_t jmpDest); - - // Jump to a given program counter; storing the return location on a call stack. - // TODO(md): this program counter MUST be an operand to the OPCODE. - void internal_call(uint32_t jmpDest); - - // Return from a jump. - void internal_return(); - - // Halt -> stop program execution. - void halt(); - - // CALLDATACOPY opcode with direct memory access, i.e., - // M[dstOffset:dstOffset+copySize] = calldata[cdOffset:cdOffset+copySize] - void callDataCopy(uint32_t cdOffset, uint32_t copySize, uint32_t dstOffset, std::vector const& callDataMem); - - // RETURN opcode with direct memory access, i.e., - // return(M[retOffset:retOffset+retSize]) - std::vector returnOP(uint32_t retOffset, uint32_t retSize); - - private: - struct MemoryTraceEntry { - uint32_t m_clk; - uint32_t m_sub_clk; - uint32_t m_addr; - FF m_val{}; - AvmMemoryTag m_tag; - AvmMemoryTag m_in_tag; - bool m_rw = false; - bool m_tag_err = false; - FF m_one_min_inv{}; - }; - - std::vector mainTrace; - std::vector memTrace; // Entries will be sorted by m_clk, m_sub_clk after finalize(). - std::array memory{}; // Memory table (used for simulation) - std::array memoryTag{}; // The tag of the corresponding memory - // entry (aligned with the memory array). - - uint32_t pc = 0; - uint32_t internal_return_ptr = CALLSTACK_OFFSET; - std::stack internal_call_stack = {}; - - static bool compareMemEntries(const MemoryTraceEntry& left, const MemoryTraceEntry& right); - void insertInMemTrace( - uint32_t m_clk, uint32_t m_sub_clk, uint32_t m_addr, FF m_val, AvmMemoryTag m_in_tag, bool m_rw); - void loadMismatchTagInMemTrace( - uint32_t m_clk, uint32_t m_sub_clk, uint32_t m_addr, FF m_val, AvmMemoryTag m_in_tag, AvmMemoryTag m_tag); - bool loadInMemTrace(IntermRegister intermReg, uint32_t addr, FF val, AvmMemoryTag m_in_tag); - void storeInMemTrace(IntermRegister intermReg, uint32_t addr, FF val, AvmMemoryTag m_in_tag); -}; -} // namespace proof_system diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_common.hpp similarity index 54% rename from barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.hpp rename to barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_common.hpp index 491d597fa26..b925d5e01c2 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_common.hpp @@ -1,17 +1,17 @@ #pragma once -#include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp" - -#include "barretenberg/flavor/generated/AvmMini_flavor.hpp" #include "barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp" -namespace proof_system { - using Flavor = proof_system::honk::flavor::AvmMiniFlavor; using FF = Flavor::FF; using Row = proof_system::AvmMiniFullRow; -void log_avmMini_trace(std::vector const& trace, size_t beg, size_t end); +namespace avm_trace { + +// Number of rows +static const size_t AVM_TRACE_SIZE = 256; +enum class IntermRegister : uint32_t { ia = 0, ib = 1, ic = 2 }; +enum class AvmMemoryTag : uint32_t { u0 = 0, u8 = 1, u16 = 2, u32 = 3, u64 = 4, u128 = 5, ff = 6 }; -} // namespace proof_system \ No newline at end of file +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_helper.cpp similarity index 91% rename from barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.cpp rename to barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_helper.cpp index 60d92a168cc..207485ac63d 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/AvmMini_helper.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_helper.cpp @@ -1,11 +1,6 @@ -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp" +#include "AvmMini_helper.hpp" -#include "./AvmMini_helper.hpp" -#include "barretenberg/flavor/generated/AvmMini_flavor.hpp" -#include "barretenberg/relations/generated/AvmMini/avm_mini.hpp" - -namespace proof_system { +namespace avm_trace { /** * @brief Routine to log some slice of a trace of the AVM. Used to debug or in some unit tests. @@ -70,4 +65,4 @@ void log_avmMini_trace(std::vector const& trace, size_t beg, size_t end) } } -} // namespace proof_system \ No newline at end of file +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_helper.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_helper.hpp new file mode 100644 index 00000000000..eda2b5c89a6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_helper.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "AvmMini_common.hpp" + +namespace avm_trace { + +void log_avmMini_trace(std::vector const& trace, size_t beg, size_t end); + +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_mem_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_mem_trace.cpp new file mode 100644 index 00000000000..f55d7e9d8b6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_mem_trace.cpp @@ -0,0 +1,244 @@ +#include "AvmMini_mem_trace.hpp" + +namespace avm_trace { + +/** + * @brief Constructor of a memory trace builder of AVM. Only serves to set the capacity of the + * underlying traces. + */ +AvmMiniMemTraceBuilder::AvmMiniMemTraceBuilder() +{ + mem_trace.reserve(AVM_TRACE_SIZE); +} + +/** + * @brief Resetting the internal state so that a new memory trace can be rebuilt using the same object. + * + */ +void AvmMiniMemTraceBuilder::reset() +{ + mem_trace.clear(); + memory.fill(FF(0)); +} + +/** + * @brief A comparator on MemoryTraceEntry to be used by sorting algorithm. We sort first by + * ascending address (m_addr), then by clock (m_clk) and finally sub-clock (m_sub_clk). + * + * @param left The left hand side memory trace entry + * @param right The right hand side memory trace entry + * + * @return A boolean indicating whether left member is smaller than right member. + */ +bool AvmMiniMemTraceBuilder::compare_mem_entries(const MemoryTraceEntry& left, const MemoryTraceEntry& right) +{ + if (left.m_addr < right.m_addr) { + return true; + } + + if (left.m_addr > right.m_addr) { + return false; + } + + if (left.m_clk < right.m_clk) { + return true; + } + + if (left.m_clk > right.m_clk) { + return false; + } + + // No safeguard in case they are equal. The caller should ensure this property. + // Otherwise, relation will not be satisfied. + return left.m_sub_clk < right.m_sub_clk; +} + +/** + * @brief Prepare the memory trace to be incorporated into the main trace. + * + * @return The memory trace (which is moved). + */ +std::vector AvmMiniMemTraceBuilder::finalize() +{ + // Sort memTrace + std::sort(mem_trace.begin(), mem_trace.end(), compare_mem_entries); + return std::move(mem_trace); +} + +/** + * @brief A method to insert a row/entry in the memory trace. + * + * @param m_clk Main clock + * @param m_sub_clk Sub-clock used to order load/store sub operations + * @param m_addr Address pertaining to the memory operation + * @param m_val Value (FF) pertaining to the memory operation + * @param m_in_tag Memory tag pertaining to the instruction + * @param m_rw Boolean telling whether it is a load (false) or store operation (true). + */ +void AvmMiniMemTraceBuilder::insert_in_mem_trace(uint32_t const m_clk, + uint32_t const m_sub_clk, + uint32_t const m_addr, + FF const& m_val, + AvmMemoryTag const m_in_tag, + bool const m_rw) +{ + mem_trace.emplace_back(MemoryTraceEntry{ + .m_clk = m_clk, + .m_sub_clk = m_sub_clk, + .m_addr = m_addr, + .m_val = m_val, + .m_tag = m_in_tag, + .m_in_tag = m_in_tag, + .m_rw = m_rw, + }); +} + +// Memory operations need to be performed before the addition of the corresponding row in +// MainTrace, otherwise the m_clk value will be wrong. This applies to loadInMemTrace and +// storeInMemTrace. + +/** + * @brief Add a memory trace entry for a load with a memory tag mismatching the instruction + * memory tag. + * + * @param m_clk Main clock + * @param m_sub_clk Sub-clock used to order load/store sub operations + * @param m_addr Address pertaining to the memory operation + * @param m_val Value (FF) pertaining to the memory operation + * @param m_in_tag Memory tag pertaining to the instruction + * @param m_tag Memory tag pertaining to the address + */ +void AvmMiniMemTraceBuilder::load_mismatch_tag_in_mem_trace(uint32_t const m_clk, + uint32_t const m_sub_clk, + uint32_t const m_addr, + FF const& m_val, + AvmMemoryTag const m_in_tag, + AvmMemoryTag const m_tag) +{ + FF one_min_inv = FF(1) - (FF(static_cast(m_in_tag)) - FF(static_cast(m_tag))).invert(); + mem_trace.emplace_back(MemoryTraceEntry{ .m_clk = m_clk, + .m_sub_clk = m_sub_clk, + .m_addr = m_addr, + .m_val = m_val, + .m_tag = m_tag, + .m_in_tag = m_in_tag, + .m_tag_err = true, + .m_one_min_inv = one_min_inv }); +} + +/** + * @brief Add a memory trace entry corresponding to a memory load into the intermediate + * passed register. + * + * @param clk The main clock + * @param interm_reg The intermediate register + * @param addr The memory address + * @param val The value to be loaded + * @param m_in_tag The memory tag of the instruction + * + * @return A boolean indicating that memory tag matches (resp. does not match) the + * instruction tag. Set to false in case of a mismatch. + */ +bool AvmMiniMemTraceBuilder::load_in_mem_trace( + uint32_t clk, IntermRegister interm_reg, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag) +{ + uint32_t sub_clk = 0; + switch (interm_reg) { + case IntermRegister::ia: + sub_clk = SUB_CLK_LOAD_A; + break; + case IntermRegister::ib: + sub_clk = SUB_CLK_LOAD_B; + break; + case IntermRegister::ic: + sub_clk = SUB_CLK_LOAD_C; + break; + } + + auto m_tag = memory_tag.at(addr); + if (m_tag == AvmMemoryTag::u0 || m_tag == m_in_tag) { + insert_in_mem_trace(clk, sub_clk, addr, val, m_in_tag, false); + return true; + } + + // Handle memory tag inconsistency + load_mismatch_tag_in_mem_trace(clk, sub_clk, addr, val, m_in_tag, m_tag); + return false; +} + +/** + * @brief Add a memory trace entry corresponding to a memory store from the intermediate + * register. + * + * @param clk The main clock + * @param interm_reg The intermediate register + * @param addr The memory address + * @param val The value to be stored + * @param m_in_tag The memory tag of the instruction + */ +void AvmMiniMemTraceBuilder::store_in_mem_trace( + uint32_t clk, IntermRegister interm_reg, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag) +{ + uint32_t sub_clk = 0; + switch (interm_reg) { + case IntermRegister::ia: + sub_clk = SUB_CLK_STORE_A; + break; + case IntermRegister::ib: + sub_clk = SUB_CLK_STORE_B; + break; + case IntermRegister::ic: + sub_clk = SUB_CLK_STORE_C; + break; + } + + insert_in_mem_trace(clk, sub_clk, addr, val, m_in_tag, true); +} + +/** + * @brief Handle a read memory operation and load the corresponding value to the + * supplied intermediate register. A memory trace entry for the load operation + * is added. + * + * @param clk Main clock + * @param interm_reg Intermediate register where we load the value + * @param addr Memory address to be read and loaded + * @param m_in_tag Memory instruction tag + * + * @return Result of the read operation containing the value and a boolean telling + * potential mismatch between instruction tag and memory tag of the address. + */ +AvmMiniMemTraceBuilder::MemRead AvmMiniMemTraceBuilder::read_and_load_from_memory(uint32_t const clk, + IntermRegister const interm_reg, + uint32_t const addr, + AvmMemoryTag const m_in_tag) +{ + FF val = memory.at(addr); + bool tagMatch = load_in_mem_trace(clk, interm_reg, addr, val, m_in_tag); + + return MemRead{ + .tag_match = tagMatch, + .val = val, + }; +} + +/** + * @brief Handle a write memory operation and store the supplied value into memory + * at the supplied address. A memory trace entry for the write operation + * is added. + * + * @param clk Main clock + * @param interm_reg Intermediate register where we write the value + * @param addr Memory address to be written to + * @param val Value to be written into memory + * @param m_in_tag Memory instruction tag + */ +void AvmMiniMemTraceBuilder::write_into_memory( + uint32_t const clk, IntermRegister interm_reg, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag) +{ + memory.at(addr) = val; + memory_tag.at(addr) = m_in_tag; + store_in_mem_trace(clk, interm_reg, addr, val, m_in_tag); +} + +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_mem_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_mem_trace.hpp new file mode 100644 index 00000000000..6a06dcee1fb --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_mem_trace.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include "AvmMini_common.hpp" + +namespace avm_trace { + +class AvmMiniMemTraceBuilder { + + public: + static const size_t MEM_SIZE = 1024; + static const uint32_t SUB_CLK_LOAD_A = 0; + static const uint32_t SUB_CLK_LOAD_B = 1; + static const uint32_t SUB_CLK_LOAD_C = 2; + static const uint32_t SUB_CLK_STORE_A = 3; + static const uint32_t SUB_CLK_STORE_B = 4; + static const uint32_t SUB_CLK_STORE_C = 5; + + struct MemoryTraceEntry { + uint32_t m_clk; + uint32_t m_sub_clk; + uint32_t m_addr; + FF m_val{}; + AvmMemoryTag m_tag; + AvmMemoryTag m_in_tag; + bool m_rw = false; + bool m_tag_err = false; + FF m_one_min_inv{}; + }; + + // Structure to return value and tag matching boolean after a memory read. + struct MemRead { + bool tag_match; + FF val; + }; + + AvmMiniMemTraceBuilder(); + + void reset(); + + std::vector finalize(); + + MemRead read_and_load_from_memory(uint32_t clk, IntermRegister interm_reg, uint32_t addr, AvmMemoryTag m_in_tag); + void write_into_memory( + uint32_t clk, IntermRegister interm_reg, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag); + + private: + std::vector mem_trace; // Entries will be sorted by m_clk, m_sub_clk after finalize(). + std::array memory{}; // Memory table (used for simulation) + std::array memory_tag{}; // The tag of the corresponding memory + // entry (aligned with the memory array). + + static bool compare_mem_entries(const MemoryTraceEntry& left, const MemoryTraceEntry& right); + + void insert_in_mem_trace( + uint32_t m_clk, uint32_t m_sub_clk, uint32_t m_addr, FF const& m_val, AvmMemoryTag m_in_tag, bool m_rw); + void load_mismatch_tag_in_mem_trace(uint32_t m_clk, + uint32_t m_sub_clk, + uint32_t m_addr, + FF const& m_val, + AvmMemoryTag m_in_tag, + AvmMemoryTag m_tag); + + bool load_in_mem_trace( + uint32_t clk, IntermRegister interm_reg, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag); + void store_in_mem_trace( + uint32_t clk, IntermRegister interm_reg, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag); +}; +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.cpp new file mode 100644 index 00000000000..c38a615560f --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.cpp @@ -0,0 +1,597 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "AvmMini_trace.hpp" + +namespace avm_trace { + +/** + * @brief Constructor of a trace builder of AVM. Only serves to set the capacity of the + * underlying traces. + */ +AvmMiniTraceBuilder::AvmMiniTraceBuilder() +{ + main_trace.reserve(AVM_TRACE_SIZE); +} + +/** + * @brief Resetting the internal state so that a new trace can be rebuilt using the same object. + * + */ +void AvmMiniTraceBuilder::reset() +{ + main_trace.clear(); + mem_trace_builder.reset(); +} + +/** TODO: Implement for non finite field types + * @brief Addition with direct memory access. + * + * @param a_offset An index in memory pointing to the first operand of the addition. + * @param b_offset An index in memory pointing to the second operand of the addition. + * @param dst_offset An index in memory pointing to the output of the addition. + * @param in_tag The instruction memory tag of the operands. + */ +void AvmMiniTraceBuilder::add(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +{ + auto clk = static_cast(main_trace.size()); + + // Reading from memory and loading into ia resp. ib. + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::ia, a_offset, in_tag); + auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::ib, b_offset, in_tag); + bool tag_match = read_a.tag_match && read_b.tag_match; + + // a + b = c + FF a = read_a.val; + FF b = read_b.val; + FF c = a + b; + + // Write into memory value c from intermediate register ic. + mem_trace_builder.write_into_memory(clk, IntermRegister::ic, dst_offset, c, in_tag); + + main_trace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = FF(pc++), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_op_add = FF(1), + .avmMini_in_tag = FF(static_cast(in_tag)), + .avmMini_tag_err = FF(static_cast(!tag_match)), + .avmMini_ia = tag_match ? a : FF(0), + .avmMini_ib = tag_match ? b : FF(0), + .avmMini_ic = tag_match ? c : FF(0), + .avmMini_mem_op_a = FF(1), + .avmMini_mem_op_b = FF(1), + .avmMini_mem_op_c = FF(1), + .avmMini_rwc = FF(1), + .avmMini_mem_idx_a = FF(a_offset), + .avmMini_mem_idx_b = FF(b_offset), + .avmMini_mem_idx_c = FF(dst_offset), + }); +}; + +/** TODO: Implement for non finite field types + * @brief Subtraction with direct memory access. + * + * @param a_offset An index in memory pointing to the first operand of the subtraction. + * @param b_offset An index in memory pointing to the second operand of the subtraction. + * @param dst_offset An index in memory pointing to the output of the subtraction. + * @param in_tag The instruction memory tag of the operands. + */ +void AvmMiniTraceBuilder::sub(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +{ + auto clk = static_cast(main_trace.size()); + + // Reading from memory and loading into ia resp. ib. + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::ia, a_offset, in_tag); + auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::ib, b_offset, in_tag); + bool tag_match = read_a.tag_match && read_b.tag_match; + + // a - b = c + FF a = read_a.val; + FF b = read_b.val; + FF c = a - b; + + // Write into memory value c from intermediate register ic. + mem_trace_builder.write_into_memory(clk, IntermRegister::ic, dst_offset, c, in_tag); + + main_trace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = FF(pc++), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_op_sub = FF(1), + .avmMini_in_tag = FF(static_cast(in_tag)), + .avmMini_tag_err = FF(static_cast(!tag_match)), + .avmMini_ia = tag_match ? a : FF(0), + .avmMini_ib = tag_match ? b : FF(0), + .avmMini_ic = tag_match ? c : FF(0), + .avmMini_mem_op_a = FF(1), + .avmMini_mem_op_b = FF(1), + .avmMini_mem_op_c = FF(1), + .avmMini_rwc = FF(1), + .avmMini_mem_idx_a = FF(a_offset), + .avmMini_mem_idx_b = FF(b_offset), + .avmMini_mem_idx_c = FF(dst_offset), + }); +}; + +/** TODO: Implement for non finite field types + * @brief Multiplication with direct memory access. + * + * @param a_offset An index in memory pointing to the first operand of the multiplication. + * @param b_offset An index in memory pointing to the second operand of the multiplication. + * @param dst_offset An index in memory pointing to the output of the multiplication. + * @param in_tag The instruction memory tag of the operands. + */ +void AvmMiniTraceBuilder::mul(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +{ + auto clk = static_cast(main_trace.size()); + + // Reading from memory and loading into ia resp. ib. + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::ia, a_offset, in_tag); + auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::ib, b_offset, in_tag); + bool tag_match = read_a.tag_match && read_b.tag_match; + + // a * b = c + FF a = read_a.val; + FF b = read_b.val; + FF c = a * b; + + // Write into memory value c from intermediate register ic. + mem_trace_builder.write_into_memory(clk, IntermRegister::ic, dst_offset, c, in_tag); + + main_trace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = FF(pc++), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_op_mul = FF(1), + .avmMini_in_tag = FF(static_cast(in_tag)), + .avmMini_tag_err = FF(static_cast(!tag_match)), + .avmMini_ia = tag_match ? a : FF(0), + .avmMini_ib = tag_match ? b : FF(0), + .avmMini_ic = tag_match ? c : FF(0), + .avmMini_mem_op_a = FF(1), + .avmMini_mem_op_b = FF(1), + .avmMini_mem_op_c = FF(1), + .avmMini_rwc = FF(1), + .avmMini_mem_idx_a = FF(a_offset), + .avmMini_mem_idx_b = FF(b_offset), + .avmMini_mem_idx_c = FF(dst_offset), + }); +} + +/** TODO: Implement for non finite field types + * @brief Division with direct memory access. + * + * @param a_offset An index in memory pointing to the first operand of the division. + * @param b_offset An index in memory pointing to the second operand of the division. + * @param dst_offset An index in memory pointing to the output of the division. + * @param in_tag The instruction memory tag of the operands. + */ +void AvmMiniTraceBuilder::div(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +{ + auto clk = static_cast(main_trace.size()); + + // Reading from memory and loading into ia resp. ib. + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::ia, a_offset, in_tag); + auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::ib, b_offset, in_tag); + bool tag_match = read_a.tag_match && read_b.tag_match; + + // a * b^(-1) = c + FF a = read_a.val; + FF b = read_b.val; + FF c; + FF inv; + FF error; + + if (!b.is_zero()) { + + inv = b.invert(); + c = a * inv; + error = 0; + } else { + inv = 1; + c = 0; + error = 1; + } + + // Write into memory value c from intermediate register ic. + mem_trace_builder.write_into_memory(clk, IntermRegister::ic, dst_offset, c, in_tag); + + main_trace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = FF(pc++), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_op_div = FF(1), + .avmMini_in_tag = FF(static_cast(in_tag)), + .avmMini_op_err = tag_match ? error : FF(1), + .avmMini_tag_err = FF(static_cast(!tag_match)), + .avmMini_inv = tag_match ? inv : FF(1), + .avmMini_ia = tag_match ? a : FF(0), + .avmMini_ib = tag_match ? b : FF(0), + .avmMini_ic = tag_match ? c : FF(0), + .avmMini_mem_op_a = FF(1), + .avmMini_mem_op_b = FF(1), + .avmMini_mem_op_c = FF(1), + .avmMini_rwc = FF(1), + .avmMini_mem_idx_a = FF(a_offset), + .avmMini_mem_idx_b = FF(b_offset), + .avmMini_mem_idx_c = FF(dst_offset), + }); +} + +/** + * @brief CALLDATACOPY opcode with direct memory access, i.e., + * M[dst_offset:dst_offset+copy_size] = calldata[cd_offset:cd_offset+copy_size] + * Simplified version with exclusively memory store operations and + * values from M_calldata passed by an array and loaded into + * intermediate registers. + * Assume that caller passes call_data_mem which is large enough so that + * no out-of-bound memory issues occur. + * TODO: Implement the indirect memory version (maybe not required) + * TODO: taking care of intermediate register values consistency and propagating their + * values to the next row when not overwritten. + * + * @param cd_offset The starting index of the region in calldata to be copied. + * @param copy_size The number of finite field elements to be copied into memory. + * @param dst_offset The starting index of memory where calldata will be copied to. + * @param call_data_mem The vector containing calldata. + */ +void AvmMiniTraceBuilder::call_data_copy(uint32_t cd_offset, + uint32_t copy_size, + uint32_t dst_offset, + std::vector const& call_data_mem) +{ + // We parallelize storing memory operations in chunk of 3, i.e., 1 per intermediate register. + // The variable pos is an index pointing to the first storing operation (pertaining to intermediate + // register Ia) relative to cd_offset: + // cd_offset + pos: Ia memory store operation + // cd_offset + pos + 1: Ib memory store operation + // cd_offset + pos + 2: Ic memory store operation + + uint32_t pos = 0; + + while (pos < copy_size) { + FF ib(0); + FF ic(0); + uint32_t mem_op_b(0); + uint32_t mem_op_c(0); + uint32_t mem_idx_b(0); + uint32_t mem_idx_c(0); + uint32_t rwb(0); + uint32_t rwc(0); + auto clk = static_cast(main_trace.size()); + + FF ia = call_data_mem.at(cd_offset + pos); + uint32_t mem_op_a(1); + uint32_t mem_idx_a = dst_offset + pos; + uint32_t rwa = 1; + + // Storing from Ia + mem_trace_builder.write_into_memory(clk, IntermRegister::ia, mem_idx_a, ia, AvmMemoryTag::ff); + + if (copy_size - pos > 1) { + ib = call_data_mem.at(cd_offset + pos + 1); + mem_op_b = 1; + mem_idx_b = dst_offset + pos + 1; + rwb = 1; + + // Storing from Ib + mem_trace_builder.write_into_memory(clk, IntermRegister::ib, mem_idx_b, ib, AvmMemoryTag::ff); + } + + if (copy_size - pos > 2) { + ic = call_data_mem.at(cd_offset + pos + 2); + mem_op_c = 1; + mem_idx_c = dst_offset + pos + 2; + rwc = 1; + + // Storing from Ic + mem_trace_builder.write_into_memory(clk, IntermRegister::ic, mem_idx_c, ic, AvmMemoryTag::ff); + } + + main_trace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = FF(pc++), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_in_tag = FF(static_cast(AvmMemoryTag::ff)), + .avmMini_ia = ia, + .avmMini_ib = ib, + .avmMini_ic = ic, + .avmMini_mem_op_a = FF(mem_op_a), + .avmMini_mem_op_b = FF(mem_op_b), + .avmMini_mem_op_c = FF(mem_op_c), + .avmMini_rwa = FF(rwa), + .avmMini_rwb = FF(rwb), + .avmMini_rwc = FF(rwc), + .avmMini_mem_idx_a = FF(mem_idx_a), + .avmMini_mem_idx_b = FF(mem_idx_b), + .avmMini_mem_idx_c = FF(mem_idx_c), + }); + + if (copy_size - pos > 2) { // Guard to prevent overflow if copy_size is close to uint32_t maximum value. + pos += 3; + } else { + pos = copy_size; + } + } +} + +/** + * @brief RETURN opcode with direct memory access, i.e., + * return(M[ret_offset:ret_offset+ret_size]) + * Simplified version with exclusively memory load operations into + * intermediate registers and then values are copied to the returned vector. + * TODO: Implement the indirect memory version (maybe not required) + * TODO: taking care of flagging this row as the last one? Special STOP flag? + * + * @param ret_offset The starting index of the memory region to be returned. + * @param ret_size The number of elements to be returned. + * @return The returned memory region as a std::vector. + */ + +std::vector AvmMiniTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_size) +{ + // We parallelize loading memory operations in chunk of 3, i.e., 1 per intermediate register. + // The variable pos is an index pointing to the first storing operation (pertaining to intermediate + // register Ia) relative to ret_offset: + // ret_offset + pos: Ia memory load operation + // ret_offset + pos + 1: Ib memory load operation + // ret_offset + pos + 2: Ic memory load operation + + uint32_t pos = 0; + std::vector returnMem; + + while (pos < ret_size) { + FF ib(0); + FF ic(0); + uint32_t mem_op_b(0); + uint32_t mem_op_c(0); + uint32_t mem_idx_b(0); + uint32_t mem_idx_c(0); + auto clk = static_cast(main_trace.size()); + + uint32_t mem_op_a(1); + uint32_t mem_idx_a = ret_offset + pos; + + // Reading and loading to Ia + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::ia, mem_idx_a, AvmMemoryTag::ff); + FF ia = read_a.val; + returnMem.push_back(ia); + + if (ret_size - pos > 1) { + mem_op_b = 1; + mem_idx_b = ret_offset + pos + 1; + + // Reading and loading to Ib + auto read_b = + mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::ib, mem_idx_b, AvmMemoryTag::ff); + FF ib = read_b.val; + returnMem.push_back(ib); + } + + if (ret_size - pos > 2) { + mem_op_c = 1; + mem_idx_c = ret_offset + pos + 2; + + // Reading and loading to Ic + auto read_c = + mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::ic, mem_idx_c, AvmMemoryTag::ff); + FF ic = read_c.val; + returnMem.push_back(ic); + } + + main_trace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = FF(pc), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_halt = FF(1), + .avmMini_in_tag = FF(static_cast(AvmMemoryTag::ff)), + .avmMini_ia = ia, + .avmMini_ib = ib, + .avmMini_ic = ic, + .avmMini_mem_op_a = FF(mem_op_a), + .avmMini_mem_op_b = FF(mem_op_b), + .avmMini_mem_op_c = FF(mem_op_c), + .avmMini_mem_idx_a = FF(mem_idx_a), + .avmMini_mem_idx_b = FF(mem_idx_b), + .avmMini_mem_idx_c = FF(mem_idx_c), + }); + + if (ret_size - pos > 2) { // Guard to prevent overflow if ret_size is close to uint32_t maximum value. + pos += 3; + } else { + pos = ret_size; + } + } + return returnMem; +} + +/** + * @brief HALT opcode + * This opcode effectively stops program execution, and is used in the relation that + * ensures the program counter increments on each opcode. + * i.e.ythe program counter should freeze and the halt flag is set to 1. + */ +void AvmMiniTraceBuilder::halt() +{ + auto clk = main_trace.size(); + + main_trace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = FF(pc), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_halt = FF(1), + }); +} + +/** + * @brief JUMP OPCODE + * Jumps to a new `jmp_dest` + * This function must: + * - Set the next program counter to the provided `jmp_dest`. + * + * @param jmp_dest - The destination to jump to + */ +void AvmMiniTraceBuilder::jump(uint32_t jmp_dest) +{ + auto clk = main_trace.size(); + + main_trace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = FF(pc), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_jump = FF(1), + .avmMini_ia = FF(jmp_dest), + }); + + // Adjust parameters for the next row + pc = jmp_dest; +} + +/** + * @brief INTERNAL_CALL OPCODE + * This opcode effectively jumps to a new `jmp_dest` and stores the return program counter + * (current program counter + 1) onto a call stack. + * This function must: + * - Set the next program counter to the provided `jmp_dest`. + * - Store the current `pc` + 1 onto the call stack (emulated in memory) + * - Increment the return stack pointer (a pointer to where the call stack is in memory) + * + * Note: We use intermediate register to perform memory storage operations. + * + * @param jmp_dest - The destination to jump to + */ +void AvmMiniTraceBuilder::internal_call(uint32_t jmp_dest) +{ + auto clk = static_cast(main_trace.size()); + + // We store the next instruction as the return location + uint32_t stored_pc = pc + 1; + internal_call_stack.push(stored_pc); + + // Add the return location to the memory trace + mem_trace_builder.write_into_memory(clk, IntermRegister::ib, internal_return_ptr, FF(stored_pc), AvmMemoryTag::ff); + + main_trace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = FF(pc), + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_internal_call = FF(1), + .avmMini_ia = FF(jmp_dest), + .avmMini_ib = stored_pc, + .avmMini_mem_op_b = FF(1), + .avmMini_rwb = FF(1), + .avmMini_mem_idx_b = FF(internal_return_ptr), + }); + + // Adjust parameters for the next row + pc = jmp_dest; + internal_return_ptr++; +} + +/** + * @brief INTERNAL_RETURN OPCODE + * The opcode returns from an internal call. + * This function must: + * - Read the return location from the internal_return_ptr + * - Set the next program counter to the return location + * - Decrement the return stack pointer + * + * TODO(https://github.com/AztecProtocol/aztec-packages/issues/3740): This function MUST come after a call instruction. + */ +void AvmMiniTraceBuilder::internal_return() +{ + auto clk = static_cast(main_trace.size()); + + // Internal return pointer is decremented + // We want to load the value pointed by the internal pointer + auto read_a = + mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::ia, internal_return_ptr - 1, AvmMemoryTag::ff); + + main_trace.push_back(Row{ + .avmMini_clk = clk, + .avmMini_pc = pc, + .avmMini_internal_return_ptr = FF(internal_return_ptr), + .avmMini_sel_internal_return = FF(1), + .avmMini_ia = read_a.val, + .avmMini_mem_op_a = FF(1), + .avmMini_rwa = FF(0), + .avmMini_mem_idx_a = FF(internal_return_ptr - 1), + }); + + // We want the next row to be the one pointed by jmp_dest + // The next pc should be from the top of the internal call stack + 1 + pc = internal_call_stack.top(); + internal_call_stack.pop(); + internal_return_ptr--; +} + +/** + * @brief Finalisation of the memory trace and incorporating it to the main trace. + * In particular, sorting the memory trace, setting .m_lastAccess and + * adding shifted values (first row). The main trace is moved at the end of + * this call. + * + * @return The main trace + */ +std::vector AvmMiniTraceBuilder::finalize() +{ + auto mem_trace = mem_trace_builder.finalize(); + size_t mem_trace_size = mem_trace.size(); + size_t main_trace_size = main_trace.size(); + + // TODO: We will have to handle this through error handling and not an assertion + // Smaller than N because we have to add an extra initial row to support shifted + // elements + assert(mem_trace_size < AVM_TRACE_SIZE); + assert(main_trace_size < AVM_TRACE_SIZE); + + // Fill the rest with zeros. + size_t zero_rows_num = AVM_TRACE_SIZE - main_trace_size - 1; + while (zero_rows_num-- > 0) { + main_trace.push_back(Row{}); + } + + main_trace.at(main_trace_size - 1).avmMini_last = FF(1); + + for (size_t i = 0; i < mem_trace_size; i++) { + auto const& src = mem_trace.at(i); + auto& dest = main_trace.at(i); + + dest.memTrace_m_clk = FF(src.m_clk); + dest.memTrace_m_sub_clk = FF(src.m_sub_clk); + dest.memTrace_m_addr = FF(src.m_addr); + dest.memTrace_m_val = src.m_val; + dest.memTrace_m_rw = FF(static_cast(src.m_rw)); + dest.memTrace_m_in_tag = FF(static_cast(src.m_in_tag)); + dest.memTrace_m_tag = FF(static_cast(src.m_tag)); + dest.memTrace_m_tag_err = FF(static_cast(src.m_tag_err)); + dest.memTrace_m_one_min_inv = src.m_one_min_inv; + + if (i + 1 < mem_trace_size) { + auto const& next = mem_trace.at(i + 1); + dest.memTrace_m_lastAccess = FF(static_cast(src.m_addr != next.m_addr)); + } else { + dest.memTrace_m_lastAccess = FF(1); + dest.memTrace_m_last = FF(1); + } + } + + // Adding extra row for the shifted values at the top of the execution trace. + Row first_row = Row{ .avmMini_first = FF(1), .memTrace_m_lastAccess = FF(1) }; + main_trace.insert(main_trace.begin(), first_row); + + auto trace = std::move(main_trace); + reset(); + + return trace; +} + +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.hpp new file mode 100644 index 00000000000..ef8e51b65bf --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include + +#include "AvmMini_common.hpp" +#include "AvmMini_mem_trace.hpp" +#include "barretenberg/common/throw_or_abort.hpp" + +#include "barretenberg/relations/generated/AvmMini/avm_mini.hpp" + +namespace avm_trace { + +// This is the internal context that we keep along the lifecycle of bytecode execution +// to iteratively build the whole trace. This is effectively performing witness generation. +// At the end of circuit building, mainTrace can be moved to AvmMiniCircuitBuilder by calling +// AvmMiniCircuitBuilder::set_trace(rows). +class AvmMiniTraceBuilder { + + public: + static const size_t CALLSTACK_OFFSET = 896; // TODO(md): Temporary reserved area 896 - 1024 + + AvmMiniTraceBuilder(); + + std::vector finalize(); + void reset(); + + // Addition with direct memory access. + void add(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + + // Subtraction with direct memory access. + void sub(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + + // Multiplication with direct memory access. + void mul(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + + // Division with direct memory access. + void div(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + + // Jump to a given program counter. + void jump(uint32_t jmp_dest); + + // Jump to a given program counter; storing the return location on a call stack. + // TODO(md): this program counter MUST be an operand to the OPCODE. + void internal_call(uint32_t jmp_dest); + + // Return from a jump. + void internal_return(); + + // Halt -> stop program execution. + void halt(); + + // CALLDATACOPY opcode with direct memory access, i.e., + // M[dst_offset:dst_offset+copy_size] = calldata[cd_offset:cd_offset+copy_size] + void call_data_copy(uint32_t cd_offset, + uint32_t copy_size, + uint32_t dst_offset, + std::vector const& call_data_mem); + + // RETURN opcode with direct memory access, i.e., + // return(M[ret_offset:ret_offset+ret_size]) + std::vector return_op(uint32_t ret_offset, uint32_t ret_size); + + private: + std::vector main_trace; + AvmMiniMemTraceBuilder mem_trace_builder; + + uint32_t pc = 0; + uint32_t internal_return_ptr = CALLSTACK_OFFSET; + std::stack internal_call_stack = {}; +}; +} // namespace avm_trace diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp index a75e798292c..c8f61b2dc59 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_arithmetic.test.cpp @@ -1,9 +1,4 @@ -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/flavor/generated/AvmMini_flavor.hpp" -#include "barretenberg/numeric/uint256/uint256.hpp" -#include "barretenberg/proof_system/circuit_builder/AvmMini_helper.hpp" -#include "barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp" -#include "barretenberg/sumcheck/sumcheck_round.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_helper.hpp" #include "barretenberg/vm/generated/AvmMini_composer.hpp" #include "barretenberg/vm/generated/AvmMini_prover.hpp" #include "barretenberg/vm/generated/AvmMini_verifier.hpp" @@ -15,9 +10,8 @@ #include #include -using namespace proof_system; - namespace tests_avm { +using namespace avm_trace; class AvmMiniArithmeticTests : public ::testing::Test { public: @@ -62,11 +56,11 @@ class AvmMiniArithmeticNegativeTests : public AvmMiniArithmeticTests {}; TEST_F(AvmMiniArithmeticTests, additionFF) { // trace_builder - trace_builder.callDataCopy(0, 3, 0, std::vector{ 37, 4, 11 }); + trace_builder.call_data_copy(0, 3, 0, std::vector{ 37, 4, 11 }); // Memory layout: [37,4,11,0,0,0,....] trace_builder.add(0, 1, 4, AvmMemoryTag::ff); // [37,4,11,0,41,0,....] - trace_builder.returnOP(0, 5); + trace_builder.return_op(0, 5); auto trace = trace_builder.finalize(); // Find the first row enabling the addition selector @@ -79,17 +73,17 @@ TEST_F(AvmMiniArithmeticTests, additionFF) EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); EXPECT_EQ(row->avmMini_rwc, FF(1)); - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } // Test on basic subtraction over finite field type. TEST_F(AvmMiniArithmeticTests, subtractionFF) { - trace_builder.callDataCopy(0, 3, 0, std::vector{ 8, 4, 17 }); + trace_builder.call_data_copy(0, 3, 0, std::vector{ 8, 4, 17 }); // Memory layout: [8,4,17,0,0,0,....] trace_builder.sub(2, 0, 1, AvmMemoryTag::ff); // [8,9,17,0,0,0....] - trace_builder.returnOP(0, 3); + trace_builder.return_op(0, 3); auto trace = trace_builder.finalize(); // Find the first row enabling the subtraction selector @@ -102,17 +96,17 @@ TEST_F(AvmMiniArithmeticTests, subtractionFF) EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); EXPECT_EQ(row->avmMini_rwc, FF(1)); - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } // Test on basic multiplication over finite field type. TEST_F(AvmMiniArithmeticTests, multiplicationFF) { - trace_builder.callDataCopy(0, 3, 0, std::vector{ 5, 0, 20 }); + trace_builder.call_data_copy(0, 3, 0, std::vector{ 5, 0, 20 }); // Memory layout: [5,0,20,0,0,0,....] trace_builder.mul(2, 0, 1, AvmMemoryTag::ff); // [5,100,20,0,0,0....] - trace_builder.returnOP(0, 3); + trace_builder.return_op(0, 3); auto trace = trace_builder.finalize(); // Find the first row enabling the multiplication selector @@ -125,17 +119,17 @@ TEST_F(AvmMiniArithmeticTests, multiplicationFF) EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); EXPECT_EQ(row->avmMini_rwc, FF(1)); - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } // Test on multiplication by zero over finite field type. TEST_F(AvmMiniArithmeticTests, multiplicationByZeroFF) { - trace_builder.callDataCopy(0, 1, 0, std::vector{ 127 }); + trace_builder.call_data_copy(0, 1, 0, std::vector{ 127 }); // Memory layout: [127,0,0,0,0,0,....] trace_builder.mul(0, 1, 2, AvmMemoryTag::ff); // [127,0,0,0,0,0....] - trace_builder.returnOP(0, 3); + trace_builder.return_op(0, 3); auto trace = trace_builder.finalize(); // Find the first row enabling the multiplication selector @@ -148,17 +142,17 @@ TEST_F(AvmMiniArithmeticTests, multiplicationByZeroFF) EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); EXPECT_EQ(row->avmMini_rwc, FF(1)); - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } // Test on basic division over finite field type. TEST_F(AvmMiniArithmeticTests, divisionFF) { - trace_builder.callDataCopy(0, 2, 0, std::vector{ 15, 315 }); + trace_builder.call_data_copy(0, 2, 0, std::vector{ 15, 315 }); // Memory layout: [15,315,0,0,0,0,....] trace_builder.div(1, 0, 2, AvmMemoryTag::ff); // [15,315,21,0,0,0....] - trace_builder.returnOP(0, 3); + trace_builder.return_op(0, 3); auto trace = trace_builder.finalize(); // Find the first row enabling the division selector @@ -171,17 +165,17 @@ TEST_F(AvmMiniArithmeticTests, divisionFF) EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); EXPECT_EQ(row->avmMini_rwc, FF(1)); - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } // Test on division with zero numerator over finite field type. TEST_F(AvmMiniArithmeticTests, divisionNumeratorZeroFF) { - trace_builder.callDataCopy(0, 1, 0, std::vector{ 15 }); + trace_builder.call_data_copy(0, 1, 0, std::vector{ 15 }); // Memory layout: [15,0,0,0,0,0,....] trace_builder.div(1, 0, 0, AvmMemoryTag::ff); // [0,0,0,0,0,0....] - trace_builder.returnOP(0, 3); + trace_builder.return_op(0, 3); auto trace = trace_builder.finalize(); // Find the first row enabling the division selector @@ -194,14 +188,14 @@ TEST_F(AvmMiniArithmeticTests, divisionNumeratorZeroFF) EXPECT_EQ(row->avmMini_mem_op_c, FF(1)); EXPECT_EQ(row->avmMini_rwc, FF(1)); - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } // Test on division by zero over finite field type. // We check that the operator error flag is raised. TEST_F(AvmMiniArithmeticTests, divisionByZeroErrorFF) { - trace_builder.callDataCopy(0, 1, 0, std::vector{ 15 }); + trace_builder.call_data_copy(0, 1, 0, std::vector{ 15 }); // Memory layout: [15,0,0,0,0,0,....] trace_builder.div(0, 1, 2, AvmMemoryTag::ff); // [15,0,0,0,0,0....] @@ -219,7 +213,7 @@ TEST_F(AvmMiniArithmeticTests, divisionByZeroErrorFF) EXPECT_EQ(row->avmMini_rwc, FF(1)); EXPECT_EQ(row->avmMini_op_err, FF(1)); - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } // Test on division of zero by zero over finite field type. @@ -242,7 +236,7 @@ TEST_F(AvmMiniArithmeticTests, divisionZeroByZeroErrorFF) EXPECT_EQ(row->avmMini_rwc, FF(1)); EXPECT_EQ(row->avmMini_op_err, FF(1)); - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } // Testing an execution of the different arithmetic opcodes over finite field @@ -251,7 +245,7 @@ TEST_F(AvmMiniArithmeticTests, divisionZeroByZeroErrorFF) // No check on the evaluation is performed here. TEST_F(AvmMiniArithmeticTests, arithmeticFFWithError) { - trace_builder.callDataCopy(0, 3, 2, std::vector{ 45, 23, 12 }); + trace_builder.call_data_copy(0, 3, 2, std::vector{ 45, 23, 12 }); // Memory layout: [0,0,45,23,12,0,0,0,....] trace_builder.add(2, 3, 4, AvmMemoryTag::ff); // [0,0,45,23,68,0,0,0,....] @@ -267,7 +261,7 @@ TEST_F(AvmMiniArithmeticTests, arithmeticFFWithError) trace_builder.halt(); auto trace = trace_builder.finalize(); - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } /****************************************************************************** @@ -294,68 +288,68 @@ TEST_F(AvmMiniArithmeticTests, arithmeticFFWithError) // Test on basic incorrect addition over finite field type. TEST_F(AvmMiniArithmeticNegativeTests, additionFF) { - trace_builder.callDataCopy(0, 3, 0, std::vector{ 37, 4, 11 }); + trace_builder.call_data_copy(0, 3, 0, std::vector{ 37, 4, 11 }); // Memory layout: [37,4,11,0,0,0,....] trace_builder.add(0, 1, 4, AvmMemoryTag::ff); // [37,4,11,0,41,0,....] auto trace = trace_builder.finalize(); - auto selectRow = [](Row r) { return r.avmMini_sel_op_add == FF(1); }; - mutateIcInTrace(trace, std::move(selectRow), FF(40)); + auto select_row = [](Row r) { return r.avmMini_sel_op_add == FF(1); }; + mutate_ic_in_trace(trace, std::move(select_row), FF(40)); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_ADDITION_FF"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "SUBOP_ADDITION_FF"); } // Test on basic incorrect subtraction over finite field type. TEST_F(AvmMiniArithmeticNegativeTests, subtractionFF) { - trace_builder.callDataCopy(0, 3, 0, std::vector{ 8, 4, 17 }); + trace_builder.call_data_copy(0, 3, 0, std::vector{ 8, 4, 17 }); // Memory layout: [8,4,17,0,0,0,....] trace_builder.sub(2, 0, 1, AvmMemoryTag::ff); // [8,9,17,0,0,0....] auto trace = trace_builder.finalize(); - auto selectRow = [](Row r) { return r.avmMini_sel_op_sub == FF(1); }; - mutateIcInTrace(trace, std::move(selectRow), FF(-9)); + auto select_row = [](Row r) { return r.avmMini_sel_op_sub == FF(1); }; + mutate_ic_in_trace(trace, std::move(select_row), FF(-9)); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_SUBTRACTION_FF"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "SUBOP_SUBTRACTION_FF"); } // Test on basic incorrect multiplication over finite field type. TEST_F(AvmMiniArithmeticNegativeTests, multiplicationFF) { - trace_builder.callDataCopy(0, 3, 0, std::vector{ 5, 0, 20 }); + trace_builder.call_data_copy(0, 3, 0, std::vector{ 5, 0, 20 }); // Memory layout: [5,0,20,0,0,0,....] trace_builder.mul(2, 0, 1, AvmMemoryTag::ff); // [5,100,20,0,0,0....] auto trace = trace_builder.finalize(); - auto selectRow = [](Row r) { return r.avmMini_sel_op_mul == FF(1); }; - mutateIcInTrace(trace, std::move(selectRow), FF(1000)); + auto select_row = [](Row r) { return r.avmMini_sel_op_mul == FF(1); }; + mutate_ic_in_trace(trace, std::move(select_row), FF(1000)); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_MULTIPLICATION_FF"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "SUBOP_MULTIPLICATION_FF"); } // Test on basic incorrect division over finite field type. TEST_F(AvmMiniArithmeticNegativeTests, divisionFF) { - trace_builder.callDataCopy(0, 2, 0, std::vector{ 15, 315 }); + trace_builder.call_data_copy(0, 2, 0, std::vector{ 15, 315 }); // Memory layout: [15,315,0,0,0,0,....] trace_builder.div(1, 0, 2, AvmMemoryTag::ff); // [15,315,21,0,0,0....] auto trace = trace_builder.finalize(); - auto selectRow = [](Row r) { return r.avmMini_sel_op_div == FF(1); }; - mutateIcInTrace(trace, std::move(selectRow), FF(0)); + auto select_row = [](Row r) { return r.avmMini_sel_op_div == FF(1); }; + mutate_ic_in_trace(trace, std::move(select_row), FF(0)); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_DIVISION_FF"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "SUBOP_DIVISION_FF"); } // Test where division is not by zero but an operation error is wrongly raised // in the trace. TEST_F(AvmMiniArithmeticNegativeTests, divisionNoZeroButErrorFF) { - trace_builder.callDataCopy(0, 2, 0, std::vector{ 15, 315 }); + trace_builder.call_data_copy(0, 2, 0, std::vector{ 15, 315 }); // Memory layout: [15,315,0,0,0,0,....] trace_builder.div(1, 0, 2, AvmMemoryTag::ff); // [15,315,21,0,0,0....] @@ -370,17 +364,17 @@ TEST_F(AvmMiniArithmeticNegativeTests, divisionNoZeroButErrorFF) trace[index].avmMini_op_err = FF(1); auto trace2 = trace; - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_DIVISION_ZERO_ERR1"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "SUBOP_DIVISION_ZERO_ERR1"); // Even more malicious, one makes the first relation passes by setting the inverse to zero. trace2[index].avmMini_inv = FF(0); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace2)), "SUBOP_DIVISION_ZERO_ERR2"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace2)), "SUBOP_DIVISION_ZERO_ERR2"); } // Test with division by zero occurs and no error is raised (remove error flag) TEST_F(AvmMiniArithmeticNegativeTests, divisionByZeroNoErrorFF) { - trace_builder.callDataCopy(0, 1, 0, std::vector{ 15 }); + trace_builder.call_data_copy(0, 1, 0, std::vector{ 15 }); // Memory layout: [15,0,0,0,0,0,....] trace_builder.div(0, 1, 2, AvmMemoryTag::ff); // [15,0,0,0,0,0....] @@ -393,7 +387,7 @@ TEST_F(AvmMiniArithmeticNegativeTests, divisionByZeroNoErrorFF) // Remove the operator error flag row->avmMini_op_err = FF(0); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_DIVISION_FF"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "SUBOP_DIVISION_FF"); } // Test with division of zero by zero occurs and no error is raised (remove error flag) @@ -409,18 +403,18 @@ TEST_F(AvmMiniArithmeticNegativeTests, divisionZeroByZeroNoErrorFF) // Remove the operator error flag row->avmMini_op_err = FF(0); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_DIVISION_ZERO_ERR1"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "SUBOP_DIVISION_ZERO_ERR1"); } // Test that error flag cannot be raised for a non-relevant operation such as // the addition, subtraction, multiplication. TEST_F(AvmMiniArithmeticNegativeTests, operationWithErrorFlagFF) { - trace_builder.callDataCopy(0, 3, 0, std::vector{ 37, 4, 11 }); + trace_builder.call_data_copy(0, 3, 0, std::vector{ 37, 4, 11 }); // Memory layout: [37,4,11,0,0,0,....] trace_builder.add(0, 1, 4, AvmMemoryTag::ff); // [37,4,11,0,41,0,....] - trace_builder.returnOP(0, 5); + trace_builder.return_op(0, 5); auto trace = trace_builder.finalize(); // Find the first row enabling the addition selector @@ -429,15 +423,15 @@ TEST_F(AvmMiniArithmeticNegativeTests, operationWithErrorFlagFF) // Activate the operator error row->avmMini_op_err = FF(1); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_ERROR_RELEVANT_OP"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "SUBOP_ERROR_RELEVANT_OP"); trace_builder.reset(); - trace_builder.callDataCopy(0, 3, 0, std::vector{ 8, 4, 17 }); + trace_builder.call_data_copy(0, 3, 0, std::vector{ 8, 4, 17 }); // Memory layout: [8,4,17,0,0,0,....] trace_builder.sub(2, 0, 1, AvmMemoryTag::ff); // [8,9,17,0,0,0....] - trace_builder.returnOP(0, 3); + trace_builder.return_op(0, 3); trace = trace_builder.finalize(); // Find the first row enabling the subtraction selector @@ -446,15 +440,15 @@ TEST_F(AvmMiniArithmeticNegativeTests, operationWithErrorFlagFF) // Activate the operator error row->avmMini_op_err = FF(1); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_ERROR_RELEVANT_OP"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "SUBOP_ERROR_RELEVANT_OP"); trace_builder.reset(); - trace_builder.callDataCopy(0, 3, 0, std::vector{ 5, 0, 20 }); + trace_builder.call_data_copy(0, 3, 0, std::vector{ 5, 0, 20 }); // Memory layout: [5,0,20,0,0,0,....] trace_builder.mul(2, 0, 1, AvmMemoryTag::ff); // [5,100,20,0,0,0....] - trace_builder.returnOP(0, 3); + trace_builder.return_op(0, 3); trace = trace_builder.finalize(); // Find the first row enabling the multiplication selector @@ -463,7 +457,7 @@ TEST_F(AvmMiniArithmeticNegativeTests, operationWithErrorFlagFF) // Activate the operator error row->avmMini_op_err = FF(1); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "SUBOP_ERROR_RELEVANT_OP"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "SUBOP_ERROR_RELEVANT_OP"); } } // namespace tests_avm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp index c771ad6eaf6..36673853057 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_control_flow.test.cpp @@ -1,8 +1,4 @@ -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/flavor/generated/AvmMini_flavor.hpp" -#include "barretenberg/numeric/uint256/uint256.hpp" -#include "barretenberg/proof_system/circuit_builder/AvmMini_helper.hpp" -#include "barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_helper.hpp" #include "barretenberg/vm/generated/AvmMini_composer.hpp" #include "barretenberg/vm/generated/AvmMini_prover.hpp" #include "barretenberg/vm/generated/AvmMini_verifier.hpp" @@ -14,9 +10,8 @@ #include #include -using namespace proof_system; - namespace tests_avm { +using namespace avm_trace; class AvmMiniControlFlowTests : public ::testing::Test { public: @@ -73,7 +68,7 @@ TEST_F(AvmMiniControlFlowTests, simpleCall) EXPECT_EQ(halt_row->avmMini_pc, FF(CALL_ADDRESS)); EXPECT_EQ(halt_row->avmMini_internal_return_ptr, FF(AvmMiniTraceBuilder::CALLSTACK_OFFSET + 1)); } - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } TEST_F(AvmMiniControlFlowTests, simpleJump) @@ -106,7 +101,7 @@ TEST_F(AvmMiniControlFlowTests, simpleJump) EXPECT_TRUE(halt_row != trace.end()); EXPECT_EQ(halt_row->avmMini_pc, FF(JUMP_ADDRESS)); } - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } TEST_F(AvmMiniControlFlowTests, simpleCallAndReturn) @@ -156,7 +151,7 @@ TEST_F(AvmMiniControlFlowTests, simpleCallAndReturn) EXPECT_EQ(halt_row->avmMini_pc, FF(RETURN_ADDRESS)); } - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns) @@ -298,6 +293,6 @@ TEST_F(AvmMiniControlFlowTests, multipleCallsAndReturns) EXPECT_TRUE(halt_row != trace.end()); EXPECT_EQ(halt_row->avmMini_pc, FF(1)); - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } } // namespace tests_avm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp index 893216fb71e..e3798357e15 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_memory.test.cpp @@ -1,9 +1,4 @@ -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/flavor/generated/AvmMini_flavor.hpp" -#include "barretenberg/numeric/uint256/uint256.hpp" -#include "barretenberg/proof_system/circuit_builder/AvmMini_helper.hpp" -#include "barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp" -#include "barretenberg/sumcheck/sumcheck_round.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_helper.hpp" #include "barretenberg/vm/generated/AvmMini_composer.hpp" #include "barretenberg/vm/generated/AvmMini_prover.hpp" #include "barretenberg/vm/generated/AvmMini_verifier.hpp" @@ -15,9 +10,8 @@ #include #include -using namespace proof_system; - namespace tests_avm { +using namespace avm_trace; class AvmMiniMemoryTests : public ::testing::Test { public: @@ -49,7 +43,7 @@ class AvmMiniMemoryTests : public ::testing::Test { // The proof must pass and we check that the AVM error is raised. TEST_F(AvmMiniMemoryTests, mismatchedTag) { - trace_builder.callDataCopy(0, 2, 0, std::vector{ 98, 12 }); + trace_builder.call_data_copy(0, 2, 0, std::vector{ 98, 12 }); trace_builder.add(0, 1, 4, AvmMemoryTag::u8); trace_builder.halt(); @@ -69,7 +63,7 @@ TEST_F(AvmMiniMemoryTests, mismatchedTag) // Find the memory trace position corresponding to the add sub-operation of register ia. row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { - return r.memTrace_m_clk == clk && r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_A; + return r.memTrace_m_clk == clk && r.memTrace_m_sub_clk == AvmMiniMemTraceBuilder::SUB_CLK_LOAD_A; }); EXPECT_TRUE(row != trace.end()); @@ -80,7 +74,7 @@ TEST_F(AvmMiniMemoryTests, mismatchedTag) // Find the memory trace position corresponding to the add sub-operation of register ib. row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { - return r.memTrace_m_clk == clk && r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_B; + return r.memTrace_m_clk == clk && r.memTrace_m_sub_clk == AvmMiniMemTraceBuilder::SUB_CLK_LOAD_B; }); EXPECT_TRUE(row != trace.end()); @@ -89,14 +83,14 @@ TEST_F(AvmMiniMemoryTests, mismatchedTag) EXPECT_EQ(row->memTrace_m_in_tag, FF(static_cast(AvmMemoryTag::u8))); EXPECT_EQ(row->memTrace_m_tag, FF(static_cast(AvmMemoryTag::ff))); - validateTraceProof(std::move(trace)); + validate_trace_proof(std::move(trace)); } // Testing violation that m_lastAccess is a delimiter for two different addresses // in the memory trace TEST_F(AvmMiniMemoryTests, mLastAccessViolation) { - trace_builder.callDataCopy(0, 2, 0, std::vector{ 4, 9 }); + trace_builder.call_data_copy(0, 2, 0, std::vector{ 4, 9 }); // Memory layout: [4,9,0,0,0,0,....] trace_builder.sub(1, 0, 2, AvmMemoryTag::u8); // [4,9,5,0,0,0.....] @@ -112,25 +106,25 @@ TEST_F(AvmMiniMemoryTests, mLastAccessViolation) // Find the row for memory trace with last memory entry for address 1 (read for subtraction) row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { return r.memTrace_m_clk == clk && r.memTrace_m_addr == FF(1) && - r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_A; + r.memTrace_m_sub_clk == AvmMiniMemTraceBuilder::SUB_CLK_LOAD_A; }); EXPECT_TRUE(row != trace.end()); row->memTrace_m_lastAccess = FF(0); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "MEM_LAST_ACCESS_DELIMITER"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "MEM_LAST_ACCESS_DELIMITER"); } // Testing violation that a memory read operation must read the same value which was // written into memory TEST_F(AvmMiniMemoryTests, readWriteConsistencyValViolation) { - trace_builder.callDataCopy(0, 2, 0, std::vector{ 4, 9 }); + trace_builder.call_data_copy(0, 2, 0, std::vector{ 4, 9 }); // Memory layout: [4,9,0,0,0,0,....] trace_builder.mul(1, 0, 2, AvmMemoryTag::u8); // [4,9,36,0,0,0.....] - trace_builder.returnOP(2, 1); // Return single memory word at position 2 (36) + trace_builder.return_op(2, 1); // Return single memory word at position 2 (36) auto trace = trace_builder.finalize(); // Find the row with multiplication operation @@ -142,25 +136,25 @@ TEST_F(AvmMiniMemoryTests, readWriteConsistencyValViolation) // Find the row for memory trace with last memory entry for address 2 (read for multiplication) row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { return r.memTrace_m_clk == clk && r.memTrace_m_addr == FF(2) && - r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_A; + r.memTrace_m_sub_clk == AvmMiniMemTraceBuilder::SUB_CLK_LOAD_A; }); EXPECT_TRUE(row != trace.end()); row->memTrace_m_val = FF(35); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "MEM_READ_WRITE_VAL_CONSISTENCY"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "MEM_READ_WRITE_VAL_CONSISTENCY"); } // Testing violation that memory read operation must read the same tag which was // written into memory TEST_F(AvmMiniMemoryTests, readWriteConsistencyTagViolation) { - trace_builder.callDataCopy(0, 2, 0, std::vector{ 4, 9 }); + trace_builder.call_data_copy(0, 2, 0, std::vector{ 4, 9 }); // Memory layout: [4,9,0,0,0,0,....] trace_builder.mul(1, 0, 2, AvmMemoryTag::u8); // [4,9,36,0,0,0.....] - trace_builder.returnOP(2, 1); // Return single memory word at position 2 (36) + trace_builder.return_op(2, 1); // Return single memory word at position 2 (36) auto trace = trace_builder.finalize(); // Find the row with multiplication operation @@ -172,32 +166,32 @@ TEST_F(AvmMiniMemoryTests, readWriteConsistencyTagViolation) // Find the row for memory trace with last memory entry for address 2 (read for multiplication) row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { return r.memTrace_m_clk == clk && r.memTrace_m_addr == FF(2) && - r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_A; + r.memTrace_m_sub_clk == AvmMiniMemTraceBuilder::SUB_CLK_LOAD_A; }); EXPECT_TRUE(row != trace.end()); row->memTrace_m_tag = static_cast(AvmMemoryTag::u16); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "MEM_READ_WRITE_TAG_CONSISTENCY"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "MEM_READ_WRITE_TAG_CONSISTENCY"); } // Testing violation that a memory read at uninitialized location must have value 0. TEST_F(AvmMiniMemoryTests, readUninitializedMemoryViolation) { - trace_builder.returnOP(1, 1); // Return single memory word at position 1 + trace_builder.return_op(1, 1); // Return single memory word at position 1 auto trace = trace_builder.finalize(); trace[1].memTrace_m_val = 9; - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "MEM_ZERO_INIT"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "MEM_ZERO_INIT"); } // Testing violation that an operation with a mismatched memory tag // must raise a VM error. TEST_F(AvmMiniMemoryTests, mismatchedTagErrorViolation) { - trace_builder.callDataCopy(0, 2, 0, std::vector{ 98, 12 }); + trace_builder.call_data_copy(0, 2, 0, std::vector{ 98, 12 }); trace_builder.sub(0, 1, 4, AvmMemoryTag::u8); trace_builder.halt(); @@ -212,26 +206,26 @@ TEST_F(AvmMiniMemoryTests, mismatchedTagErrorViolation) // Find the memory trace position corresponding to the subtraction sub-operation of register ia. row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { - return r.memTrace_m_clk == clk && r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_A; + return r.memTrace_m_clk == clk && r.memTrace_m_sub_clk == AvmMiniMemTraceBuilder::SUB_CLK_LOAD_A; }); row->memTrace_m_tag_err = FF(0); auto index = static_cast(row - trace.begin()); auto trace2 = trace; - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "MEM_IN_TAG_CONSISTENCY_1"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "MEM_IN_TAG_CONSISTENCY_1"); // More sophisticated attempt by adapting witness "on_min_inv" to make pass the above constraint trace2[index].memTrace_m_one_min_inv = FF(1); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace2)), "MEM_IN_TAG_CONSISTENCY_2"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace2)), "MEM_IN_TAG_CONSISTENCY_2"); } // Testing violation that an operation with a consistent memory tag // must not set a VM error. TEST_F(AvmMiniMemoryTests, consistentTagNoErrorViolation) { - trace_builder.callDataCopy(0, 2, 0, std::vector{ 84, 7 }); + trace_builder.call_data_copy(0, 2, 0, std::vector{ 84, 7 }); trace_builder.div(0, 1, 4, AvmMemoryTag::ff); trace_builder.halt(); @@ -246,11 +240,11 @@ TEST_F(AvmMiniMemoryTests, consistentTagNoErrorViolation) // Find the memory trace position corresponding to the div sub-operation of register ia. row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { - return r.memTrace_m_clk == clk && r.memTrace_m_sub_clk == AvmMiniTraceBuilder::SUB_CLK_LOAD_A; + return r.memTrace_m_clk == clk && r.memTrace_m_sub_clk == AvmMiniMemTraceBuilder::SUB_CLK_LOAD_A; }); row->memTrace_m_tag_err = FF(1); - EXPECT_THROW_WITH_MESSAGE(validateTraceProof(std::move(trace)), "MEM_IN_TAG_CONSISTENCY_1"); + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "MEM_IN_TAG_CONSISTENCY_1"); } } // namespace tests_avm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp index 9cfb6fe7a17..2a761b69a47 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp @@ -1,28 +1,26 @@ -#include "barretenberg/vm/tests/helpers.test.hpp" -#include "barretenberg/flavor/generated/AvmMini_flavor.hpp" -#include "barretenberg/proof_system/circuit_builder/AvmMini_helper.hpp" -#include "barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp" +#include "helpers.test.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_helper.hpp" #include "barretenberg/vm/generated/AvmMini_composer.hpp" #include "barretenberg/vm/generated/AvmMini_prover.hpp" #include "barretenberg/vm/generated/AvmMini_verifier.hpp" #include namespace tests_avm { -using namespace proof_system; +using namespace avm_trace; /** * @brief Helper routine proving and verifying a proof based on the supplied trace * * @param trace The execution trace */ -void validateTraceProof(std::vector&& trace) +void validate_trace_proof(std::vector&& trace) { - auto circuit_builder = AvmMiniCircuitBuilder(); + auto circuit_builder = proof_system::AvmMiniCircuitBuilder(); circuit_builder.set_trace(std::move(trace)); EXPECT_TRUE(circuit_builder.check_circuit()); - auto composer = honk::AvmMiniComposer(); + auto composer = proof_system::honk::AvmMiniComposer(); auto prover = composer.create_prover(circuit_builder); auto proof = prover.construct_proof(); @@ -42,7 +40,7 @@ void validateTraceProof(std::vector&& trace) * @param selectRow Lambda serving to select the row in trace * @param newValue The value that will be written in intermediate register Ic at the selected row. */ -void mutateIcInTrace(std::vector& trace, std::function&& selectRow, FF const& newValue) +void mutate_ic_in_trace(std::vector& trace, std::function&& selectRow, FF const& newValue) { // Find the first row matching the criteria defined by selectRow auto row = std::ranges::find_if(trace.begin(), trace.end(), selectRow); @@ -58,12 +56,12 @@ void mutateIcInTrace(std::vector& trace, std::function&& selectR auto const addr = row->avmMini_mem_idx_c; // Find the relevant memory trace entry. - auto memRow = std::ranges::find_if(trace.begin(), trace.end(), [clk, addr](Row r) { + auto mem_row = std::ranges::find_if(trace.begin(), trace.end(), [clk, addr](Row r) { return r.memTrace_m_clk == clk && r.memTrace_m_addr == addr; }); - EXPECT_TRUE(memRow != trace.end()); - memRow->memTrace_m_val = newValue; + EXPECT_TRUE(mem_row != trace.end()); + mem_row->memTrace_m_val = newValue; }; } // namespace tests_avm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp index 36732908f89..145eb171457 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp @@ -1,6 +1,6 @@ #pragma once -#include "barretenberg/proof_system/circuit_builder/AvmMini_trace.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_trace.hpp" #define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage) \ try { \ @@ -13,7 +13,7 @@ namespace tests_avm { -void validateTraceProof(std::vector&& trace); -void mutateIcInTrace(std::vector& trace, std::function&& selectRow, FF const& newValue); +void validate_trace_proof(std::vector&& trace); +void mutate_ic_in_trace(std::vector& trace, std::function&& selectRow, FF const& newValue); } // namespace tests_avm \ No newline at end of file