diff --git a/barretenberg/cpp/pil/avm/avm_main.pil b/barretenberg/cpp/pil/avm/avm_main.pil
index 473fe5b70fd..8fd09b8536c 100644
--- a/barretenberg/cpp/pil/avm/avm_main.pil
+++ b/barretenberg/cpp/pil/avm/avm_main.pil
@@ -192,6 +192,8 @@ namespace avm_main(256);
 
     // Inter-table Constraints
     
-    // TODO: tag_err {clk} IS avm_mem.m_tag_err {avm_mem.m_clk}
+    #[equiv_tag_err]
+    avm_mem.m_tag_err {avm_mem.m_clk} in tag_err {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}
diff --git a/barretenberg/cpp/pil/avm/toy_avm.pil b/barretenberg/cpp/pil/avm/toy_avm.pil
index 422ff4d1a0e..375c29d8ac6 100644
--- a/barretenberg/cpp/pil/avm/toy_avm.pil
+++ b/barretenberg/cpp/pil/avm/toy_avm.pil
@@ -8,10 +8,18 @@ namespace toy(256);
     pol commit set_2_column_1;
     pol commit set_2_column_2;
     
-    // This is a column based tuple lookup
+    // This is a column based tuple lookup, one selector
     #[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 };
 
+
+    // Column based lookup, two selectors
+    pol commit sparse_column_1, sparse_column_2;
+    pol commit sparse_lhs, sparse_rhs;
+
+    #[two_column_sparse_perm] // the name of the inverse
+    sparse_lhs { sparse_column_1 } is sparse_rhs { sparse_column_2 };
+
     // Relation not used -> we currently require a single relation for codegen
     q_tuple_set * (1 - q_tuple_set) = 0;
 
@@ -45,4 +53,11 @@ namespace toy(256);
     // Note - if no right hand side selector column is provided, then we will need to build the table ourselves
     // Note - we can also take advantage of pil creating the lookup columns for us here -> I may be able to do some codegen here !
     #[lookup_xor]
-    q_xor { xor_a, xor_b, xor_c } in q_xor_table { table_xor_a, table_xor_b, table_xor_c };
\ No newline at end of file
+    q_xor { xor_a, xor_b, xor_c } in q_xor_table { table_xor_a, table_xor_b, table_xor_c };
+
+    // Minimum repro testing multiple lookups
+    pol commit q_err, q_err_check;
+    pol commit clk, m_clk;
+
+    #[lookup_err]
+    q_err_check {m_clk} in q_err {clk};
diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp
index a43887cd19d..85f377b0afb 100644
--- a/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp
+++ b/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp
@@ -37,13 +37,13 @@ class AvmFlavor {
     using RelationSeparator = FF;
 
     static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 2;
-    static constexpr size_t NUM_WITNESS_ENTITIES = 69;
+    static constexpr size_t NUM_WITNESS_ENTITIES = 71;
     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 = 85;
+    static constexpr size_t NUM_ALL_ENTITIES = 87;
 
-    using Relations = std::tuple<Avm_vm::avm_mem<FF>, Avm_vm::avm_main<FF>, Avm_vm::avm_alu<FF>>;
+    using Relations = std::tuple<Avm_vm::avm_mem<FF>, Avm_vm::avm_alu<FF>, Avm_vm::avm_main<FF>>;
 
     static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length<Relations>();
 
@@ -145,7 +145,9 @@ class AvmFlavor {
                               avm_main_mem_idx_a,
                               avm_main_mem_idx_b,
                               avm_main_mem_idx_c,
-                              avm_main_last)
+                              avm_main_last,
+                              equiv_tag_err,
+                              equiv_tag_err_counts)
 
         RefVector<DataType> get_wires()
         {
@@ -217,7 +219,9 @@ class AvmFlavor {
                      avm_main_mem_idx_a,
                      avm_main_mem_idx_b,
                      avm_main_mem_idx_c,
-                     avm_main_last };
+                     avm_main_last,
+                     equiv_tag_err,
+                     equiv_tag_err_counts };
         };
         RefVector<DataType> get_sorted_polynomials() { return {}; };
     };
@@ -296,20 +300,22 @@ class AvmFlavor {
                               avm_main_mem_idx_b,
                               avm_main_mem_idx_c,
                               avm_main_last,
+                              equiv_tag_err,
+                              equiv_tag_err_counts,
                               avm_mem_m_rw_shift,
-                              avm_mem_m_tag_shift,
-                              avm_mem_m_val_shift,
                               avm_mem_m_addr_shift,
-                              avm_main_internal_return_ptr_shift,
-                              avm_main_pc_shift,
-                              avm_alu_alu_u16_r6_shift,
-                              avm_alu_alu_u16_r0_shift,
+                              avm_mem_m_val_shift,
+                              avm_mem_m_tag_shift,
                               avm_alu_alu_u16_r2_shift,
-                              avm_alu_alu_u16_r7_shift,
-                              avm_alu_alu_u16_r3_shift,
                               avm_alu_alu_u16_r1_shift,
                               avm_alu_alu_u16_r5_shift,
-                              avm_alu_alu_u16_r4_shift)
+                              avm_alu_alu_u16_r0_shift,
+                              avm_alu_alu_u16_r7_shift,
+                              avm_alu_alu_u16_r6_shift,
+                              avm_alu_alu_u16_r4_shift,
+                              avm_alu_alu_u16_r3_shift,
+                              avm_main_pc_shift,
+                              avm_main_internal_return_ptr_shift)
 
         RefVector<DataType> get_wires()
         {
@@ -384,20 +390,22 @@ class AvmFlavor {
                      avm_main_mem_idx_b,
                      avm_main_mem_idx_c,
                      avm_main_last,
+                     equiv_tag_err,
+                     equiv_tag_err_counts,
                      avm_mem_m_rw_shift,
-                     avm_mem_m_tag_shift,
-                     avm_mem_m_val_shift,
                      avm_mem_m_addr_shift,
-                     avm_main_internal_return_ptr_shift,
-                     avm_main_pc_shift,
-                     avm_alu_alu_u16_r6_shift,
-                     avm_alu_alu_u16_r0_shift,
+                     avm_mem_m_val_shift,
+                     avm_mem_m_tag_shift,
                      avm_alu_alu_u16_r2_shift,
-                     avm_alu_alu_u16_r7_shift,
-                     avm_alu_alu_u16_r3_shift,
                      avm_alu_alu_u16_r1_shift,
                      avm_alu_alu_u16_r5_shift,
-                     avm_alu_alu_u16_r4_shift };
+                     avm_alu_alu_u16_r0_shift,
+                     avm_alu_alu_u16_r7_shift,
+                     avm_alu_alu_u16_r6_shift,
+                     avm_alu_alu_u16_r4_shift,
+                     avm_alu_alu_u16_r3_shift,
+                     avm_main_pc_shift,
+                     avm_main_internal_return_ptr_shift };
         };
         RefVector<DataType> get_unshifted()
         {
@@ -471,41 +479,29 @@ class AvmFlavor {
                      avm_main_mem_idx_a,
                      avm_main_mem_idx_b,
                      avm_main_mem_idx_c,
-                     avm_main_last };
+                     avm_main_last,
+                     equiv_tag_err,
+                     equiv_tag_err_counts };
         };
         RefVector<DataType> get_to_be_shifted()
         {
-            return { avm_mem_m_rw,
-                     avm_mem_m_tag,
-                     avm_mem_m_val,
-                     avm_mem_m_addr,
-                     avm_main_internal_return_ptr,
-                     avm_main_pc,
-                     avm_alu_alu_u16_r6,
-                     avm_alu_alu_u16_r0,
-                     avm_alu_alu_u16_r2,
-                     avm_alu_alu_u16_r7,
-                     avm_alu_alu_u16_r3,
-                     avm_alu_alu_u16_r1,
-                     avm_alu_alu_u16_r5,
-                     avm_alu_alu_u16_r4 };
+            return { avm_mem_m_rw,       avm_mem_m_addr,
+                     avm_mem_m_val,      avm_mem_m_tag,
+                     avm_alu_alu_u16_r2, avm_alu_alu_u16_r1,
+                     avm_alu_alu_u16_r5, avm_alu_alu_u16_r0,
+                     avm_alu_alu_u16_r7, avm_alu_alu_u16_r6,
+                     avm_alu_alu_u16_r4, avm_alu_alu_u16_r3,
+                     avm_main_pc,        avm_main_internal_return_ptr };
         };
         RefVector<DataType> get_shifted()
         {
-            return { avm_mem_m_rw_shift,
-                     avm_mem_m_tag_shift,
-                     avm_mem_m_val_shift,
-                     avm_mem_m_addr_shift,
-                     avm_main_internal_return_ptr_shift,
-                     avm_main_pc_shift,
-                     avm_alu_alu_u16_r6_shift,
-                     avm_alu_alu_u16_r0_shift,
-                     avm_alu_alu_u16_r2_shift,
-                     avm_alu_alu_u16_r7_shift,
-                     avm_alu_alu_u16_r3_shift,
-                     avm_alu_alu_u16_r1_shift,
-                     avm_alu_alu_u16_r5_shift,
-                     avm_alu_alu_u16_r4_shift };
+            return { avm_mem_m_rw_shift,       avm_mem_m_addr_shift,
+                     avm_mem_m_val_shift,      avm_mem_m_tag_shift,
+                     avm_alu_alu_u16_r2_shift, avm_alu_alu_u16_r1_shift,
+                     avm_alu_alu_u16_r5_shift, avm_alu_alu_u16_r0_shift,
+                     avm_alu_alu_u16_r7_shift, avm_alu_alu_u16_r6_shift,
+                     avm_alu_alu_u16_r4_shift, avm_alu_alu_u16_r3_shift,
+                     avm_main_pc_shift,        avm_main_internal_return_ptr_shift };
         };
     };
 
@@ -518,20 +514,13 @@ class AvmFlavor {
 
         RefVector<DataType> get_to_be_shifted()
         {
-            return { avm_mem_m_rw,
-                     avm_mem_m_tag,
-                     avm_mem_m_val,
-                     avm_mem_m_addr,
-                     avm_main_internal_return_ptr,
-                     avm_main_pc,
-                     avm_alu_alu_u16_r6,
-                     avm_alu_alu_u16_r0,
-                     avm_alu_alu_u16_r2,
-                     avm_alu_alu_u16_r7,
-                     avm_alu_alu_u16_r3,
-                     avm_alu_alu_u16_r1,
-                     avm_alu_alu_u16_r5,
-                     avm_alu_alu_u16_r4 };
+            return { avm_mem_m_rw,       avm_mem_m_addr,
+                     avm_mem_m_val,      avm_mem_m_tag,
+                     avm_alu_alu_u16_r2, avm_alu_alu_u16_r1,
+                     avm_alu_alu_u16_r5, avm_alu_alu_u16_r0,
+                     avm_alu_alu_u16_r7, avm_alu_alu_u16_r6,
+                     avm_alu_alu_u16_r4, avm_alu_alu_u16_r3,
+                     avm_main_pc,        avm_main_internal_return_ptr };
         };
 
         // The plookup wires that store plookup read data.
@@ -679,6 +668,8 @@ class AvmFlavor {
             Base::avm_main_mem_idx_b = "AVM_MAIN_MEM_IDX_B";
             Base::avm_main_mem_idx_c = "AVM_MAIN_MEM_IDX_C";
             Base::avm_main_last = "AVM_MAIN_LAST";
+            Base::equiv_tag_err = "EQUIV_TAG_ERR";
+            Base::equiv_tag_err_counts = "EQUIV_TAG_ERR_COUNTS";
         };
     };
 
@@ -767,6 +758,8 @@ class AvmFlavor {
         Commitment avm_main_mem_idx_b;
         Commitment avm_main_mem_idx_c;
         Commitment avm_main_last;
+        Commitment equiv_tag_err;
+        Commitment equiv_tag_err_counts;
 
         std::vector<bb::Univariate<FF, BATCHED_RELATION_PARTIAL_LENGTH>> sumcheck_univariates;
         std::array<FF, NUM_ALL_ENTITIES> sumcheck_evaluations;
@@ -855,6 +848,8 @@ class AvmFlavor {
             avm_main_mem_idx_b = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
             avm_main_mem_idx_c = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
             avm_main_last = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            equiv_tag_err = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            equiv_tag_err_counts = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
 
             for (size_t i = 0; i < log_n; ++i) {
                 sumcheck_univariates.emplace_back(
@@ -947,6 +942,8 @@ class AvmFlavor {
             serialize_to_buffer<Commitment>(avm_main_mem_idx_b, Transcript::proof_data);
             serialize_to_buffer<Commitment>(avm_main_mem_idx_c, Transcript::proof_data);
             serialize_to_buffer<Commitment>(avm_main_last, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(equiv_tag_err, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(equiv_tag_err_counts, Transcript::proof_data);
 
             for (size_t i = 0; i < log_n; ++i) {
                 serialize_to_buffer(sumcheck_univariates[i], 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 c13b13f50a2..d13ff8df281 100644
--- a/barretenberg/cpp/src/barretenberg/flavor/generated/toy_flavor.hpp
+++ b/barretenberg/cpp/src/barretenberg/flavor/generated/toy_flavor.hpp
@@ -15,6 +15,7 @@
 #include "barretenberg/polynomials/polynomial.hpp"
 #include "barretenberg/relations/generated/toy/toy_avm.hpp"
 #include "barretenberg/relations/generated/toy/two_column_perm.hpp"
+#include "barretenberg/relations/generated/toy/two_column_sparse_perm.hpp"
 #include "barretenberg/transcript/transcript.hpp"
 
 namespace bb {
@@ -36,13 +37,14 @@ class ToyFlavor {
     using RelationSeparator = FF;
 
     static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 1;
-    static constexpr size_t NUM_WITNESS_ENTITIES = 16;
+    static constexpr size_t NUM_WITNESS_ENTITIES = 27;
     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 = 17;
+    static constexpr size_t NUM_ALL_ENTITIES = 28;
 
-    using Relations = std::tuple<Toy_vm::toy_avm<FF>, two_column_perm_relation<FF>>;
+    using Relations =
+        std::tuple<Toy_vm::toy_avm<FF>, two_column_perm_relation<FF>, two_column_sparse_perm_relation<FF>>;
 
     static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length<Relations>();
 
@@ -81,6 +83,10 @@ class ToyFlavor {
                               toy_set_1_column_2,
                               toy_set_2_column_1,
                               toy_set_2_column_2,
+                              toy_sparse_column_1,
+                              toy_sparse_column_2,
+                              toy_sparse_lhs,
+                              toy_sparse_rhs,
                               toy_xor_a,
                               toy_xor_b,
                               toy_xor_c,
@@ -89,16 +95,46 @@ class ToyFlavor {
                               toy_table_xor_c,
                               toy_q_xor,
                               toy_q_xor_table,
+                              toy_q_err,
+                              toy_q_err_check,
+                              toy_clk,
+                              toy_m_clk,
                               two_column_perm,
+                              two_column_sparse_perm,
                               lookup_xor,
-                              lookup_xor_counts)
+                              lookup_err,
+                              lookup_xor_counts,
+                              lookup_err_counts)
 
         RefVector<DataType> 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_xor_a,          toy_xor_b,          toy_xor_c,
-                     toy_table_xor_a,    toy_table_xor_b,    toy_table_xor_c,    toy_q_xor,
-                     toy_q_xor_table,    two_column_perm,    lookup_xor,         lookup_xor_counts };
+            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_sparse_column_1,
+                     toy_sparse_column_2,
+                     toy_sparse_lhs,
+                     toy_sparse_rhs,
+                     toy_xor_a,
+                     toy_xor_b,
+                     toy_xor_c,
+                     toy_table_xor_a,
+                     toy_table_xor_b,
+                     toy_table_xor_c,
+                     toy_q_xor,
+                     toy_q_xor_table,
+                     toy_q_err,
+                     toy_q_err_check,
+                     toy_clk,
+                     toy_m_clk,
+                     two_column_perm,
+                     two_column_sparse_perm,
+                     lookup_xor,
+                     lookup_err,
+                     lookup_xor_counts,
+                     lookup_err_counts };
         };
         RefVector<DataType> get_sorted_polynomials() { return {}; };
     };
@@ -112,6 +148,10 @@ class ToyFlavor {
                               toy_set_1_column_2,
                               toy_set_2_column_1,
                               toy_set_2_column_2,
+                              toy_sparse_column_1,
+                              toy_sparse_column_2,
+                              toy_sparse_lhs,
+                              toy_sparse_rhs,
                               toy_xor_a,
                               toy_xor_b,
                               toy_xor_c,
@@ -120,23 +160,42 @@ class ToyFlavor {
                               toy_table_xor_c,
                               toy_q_xor,
                               toy_q_xor_table,
+                              toy_q_err,
+                              toy_q_err_check,
+                              toy_clk,
+                              toy_m_clk,
                               two_column_perm,
+                              two_column_sparse_perm,
                               lookup_xor,
-                              lookup_xor_counts)
+                              lookup_err,
+                              lookup_xor_counts,
+                              lookup_err_counts)
 
         RefVector<DataType> 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_xor_a,        toy_xor_b,          toy_xor_c,          toy_table_xor_a,
-                     toy_table_xor_b,    toy_table_xor_c,  toy_q_xor,          toy_q_xor_table,    two_column_perm,
-                     lookup_xor,         lookup_xor_counts };
+            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_sparse_column_1, toy_sparse_column_2, toy_sparse_lhs,
+                     toy_sparse_rhs,      toy_xor_a,           toy_xor_b,
+                     toy_xor_c,           toy_table_xor_a,     toy_table_xor_b,
+                     toy_table_xor_c,     toy_q_xor,           toy_q_xor_table,
+                     toy_q_err,           toy_q_err_check,     toy_clk,
+                     toy_m_clk,           two_column_perm,     two_column_sparse_perm,
+                     lookup_xor,          lookup_err,          lookup_xor_counts,
+                     lookup_err_counts };
         };
         RefVector<DataType> 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_xor_a,        toy_xor_b,          toy_xor_c,          toy_table_xor_a,
-                     toy_table_xor_b,    toy_table_xor_c,  toy_q_xor,          toy_q_xor_table,    two_column_perm,
-                     lookup_xor,         lookup_xor_counts };
+            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_sparse_column_1, toy_sparse_column_2, toy_sparse_lhs,
+                     toy_sparse_rhs,      toy_xor_a,           toy_xor_b,
+                     toy_xor_c,           toy_table_xor_a,     toy_table_xor_b,
+                     toy_table_xor_c,     toy_q_xor,           toy_q_xor_table,
+                     toy_q_err,           toy_q_err_check,     toy_clk,
+                     toy_m_clk,           two_column_perm,     two_column_sparse_perm,
+                     lookup_xor,          lookup_err,          lookup_xor_counts,
+                     lookup_err_counts };
         };
         RefVector<DataType> get_to_be_shifted() { return {}; };
         RefVector<DataType> get_shifted() { return {}; };
@@ -231,6 +290,10 @@ class ToyFlavor {
             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_sparse_column_1 = "TOY_SPARSE_COLUMN_1";
+            Base::toy_sparse_column_2 = "TOY_SPARSE_COLUMN_2";
+            Base::toy_sparse_lhs = "TOY_SPARSE_LHS";
+            Base::toy_sparse_rhs = "TOY_SPARSE_RHS";
             Base::toy_xor_a = "TOY_XOR_A";
             Base::toy_xor_b = "TOY_XOR_B";
             Base::toy_xor_c = "TOY_XOR_C";
@@ -239,9 +302,16 @@ class ToyFlavor {
             Base::toy_table_xor_c = "TOY_TABLE_XOR_C";
             Base::toy_q_xor = "TOY_Q_XOR";
             Base::toy_q_xor_table = "TOY_Q_XOR_TABLE";
+            Base::toy_q_err = "TOY_Q_ERR";
+            Base::toy_q_err_check = "TOY_Q_ERR_CHECK";
+            Base::toy_clk = "TOY_CLK";
+            Base::toy_m_clk = "TOY_M_CLK";
             Base::two_column_perm = "TWO_COLUMN_PERM";
+            Base::two_column_sparse_perm = "TWO_COLUMN_SPARSE_PERM";
             Base::lookup_xor = "LOOKUP_XOR";
+            Base::lookup_err = "LOOKUP_ERR";
             Base::lookup_xor_counts = "LOOKUP_XOR_COUNTS";
+            Base::lookup_err_counts = "LOOKUP_ERR_COUNTS";
         };
     };
 
@@ -265,6 +335,10 @@ class ToyFlavor {
         Commitment toy_set_1_column_2;
         Commitment toy_set_2_column_1;
         Commitment toy_set_2_column_2;
+        Commitment toy_sparse_column_1;
+        Commitment toy_sparse_column_2;
+        Commitment toy_sparse_lhs;
+        Commitment toy_sparse_rhs;
         Commitment toy_xor_a;
         Commitment toy_xor_b;
         Commitment toy_xor_c;
@@ -273,9 +347,16 @@ class ToyFlavor {
         Commitment toy_table_xor_c;
         Commitment toy_q_xor;
         Commitment toy_q_xor_table;
+        Commitment toy_q_err;
+        Commitment toy_q_err_check;
+        Commitment toy_clk;
+        Commitment toy_m_clk;
         Commitment two_column_perm;
+        Commitment two_column_sparse_perm;
         Commitment lookup_xor;
+        Commitment lookup_err;
         Commitment lookup_xor_counts;
+        Commitment lookup_err_counts;
 
         std::vector<bb::Univariate<FF, BATCHED_RELATION_PARTIAL_LENGTH>> sumcheck_univariates;
         std::array<FF, NUM_ALL_ENTITIES> sumcheck_evaluations;
@@ -300,6 +381,10 @@ class ToyFlavor {
             toy_set_1_column_2 = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
             toy_set_2_column_1 = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
             toy_set_2_column_2 = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            toy_sparse_column_1 = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            toy_sparse_column_2 = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            toy_sparse_lhs = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            toy_sparse_rhs = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
             toy_xor_a = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
             toy_xor_b = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
             toy_xor_c = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
@@ -308,9 +393,16 @@ class ToyFlavor {
             toy_table_xor_c = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
             toy_q_xor = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
             toy_q_xor_table = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            toy_q_err = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            toy_q_err_check = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            toy_clk = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            toy_m_clk = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
             two_column_perm = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            two_column_sparse_perm = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
             lookup_xor = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            lookup_err = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
             lookup_xor_counts = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
+            lookup_err_counts = deserialize_from_buffer<Commitment>(Transcript::proof_data, num_frs_read);
 
             for (size_t i = 0; i < log_n; ++i) {
                 sumcheck_univariates.emplace_back(
@@ -339,6 +431,10 @@ class ToyFlavor {
             serialize_to_buffer<Commitment>(toy_set_1_column_2, Transcript::proof_data);
             serialize_to_buffer<Commitment>(toy_set_2_column_1, Transcript::proof_data);
             serialize_to_buffer<Commitment>(toy_set_2_column_2, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(toy_sparse_column_1, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(toy_sparse_column_2, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(toy_sparse_lhs, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(toy_sparse_rhs, Transcript::proof_data);
             serialize_to_buffer<Commitment>(toy_xor_a, Transcript::proof_data);
             serialize_to_buffer<Commitment>(toy_xor_b, Transcript::proof_data);
             serialize_to_buffer<Commitment>(toy_xor_c, Transcript::proof_data);
@@ -347,9 +443,16 @@ class ToyFlavor {
             serialize_to_buffer<Commitment>(toy_table_xor_c, Transcript::proof_data);
             serialize_to_buffer<Commitment>(toy_q_xor, Transcript::proof_data);
             serialize_to_buffer<Commitment>(toy_q_xor_table, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(toy_q_err, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(toy_q_err_check, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(toy_clk, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(toy_m_clk, Transcript::proof_data);
             serialize_to_buffer<Commitment>(two_column_perm, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(two_column_sparse_perm, Transcript::proof_data);
             serialize_to_buffer<Commitment>(lookup_xor, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(lookup_err, Transcript::proof_data);
             serialize_to_buffer<Commitment>(lookup_xor_counts, Transcript::proof_data);
+            serialize_to_buffer<Commitment>(lookup_err_counts, Transcript::proof_data);
 
             for (size_t i = 0; i < log_n; ++i) {
                 serialize_to_buffer(sumcheck_univariates[i], Transcript::proof_data);
diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp
index 59b53d25c61..f60a3310e83 100644
--- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp
+++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp
@@ -15,6 +15,7 @@
 #include "barretenberg/relations/generated/avm/avm_alu.hpp"
 #include "barretenberg/relations/generated/avm/avm_main.hpp"
 #include "barretenberg/relations/generated/avm/avm_mem.hpp"
+#include "barretenberg/relations/generated/avm/equiv_tag_err.hpp"
 
 namespace bb {
 
@@ -90,20 +91,22 @@ template <typename FF> struct AvmFullRow {
     FF avm_main_mem_idx_b{};
     FF avm_main_mem_idx_c{};
     FF avm_main_last{};
+    FF equiv_tag_err{};
+    FF equiv_tag_err_counts{};
     FF avm_mem_m_rw_shift{};
-    FF avm_mem_m_tag_shift{};
-    FF avm_mem_m_val_shift{};
     FF avm_mem_m_addr_shift{};
-    FF avm_main_internal_return_ptr_shift{};
-    FF avm_main_pc_shift{};
-    FF avm_alu_alu_u16_r6_shift{};
-    FF avm_alu_alu_u16_r0_shift{};
+    FF avm_mem_m_val_shift{};
+    FF avm_mem_m_tag_shift{};
     FF avm_alu_alu_u16_r2_shift{};
-    FF avm_alu_alu_u16_r7_shift{};
-    FF avm_alu_alu_u16_r3_shift{};
     FF avm_alu_alu_u16_r1_shift{};
     FF avm_alu_alu_u16_r5_shift{};
+    FF avm_alu_alu_u16_r0_shift{};
+    FF avm_alu_alu_u16_r7_shift{};
+    FF avm_alu_alu_u16_r6_shift{};
     FF avm_alu_alu_u16_r4_shift{};
+    FF avm_alu_alu_u16_r3_shift{};
+    FF avm_main_pc_shift{};
+    FF avm_main_internal_return_ptr_shift{};
 };
 
 class AvmCircuitBuilder {
@@ -116,8 +119,8 @@ class AvmCircuitBuilder {
     using Polynomial = Flavor::Polynomial;
     using ProverPolynomials = Flavor::ProverPolynomials;
 
-    static constexpr size_t num_fixed_columns = 85;
-    static constexpr size_t num_polys = 71;
+    static constexpr size_t num_fixed_columns = 87;
+    static constexpr size_t num_polys = 73;
     std::vector<Row> rows;
 
     void set_trace(std::vector<Row>&& trace) { rows = std::move(trace); }
@@ -204,22 +207,24 @@ class AvmCircuitBuilder {
             polys.avm_main_mem_idx_b[i] = rows[i].avm_main_mem_idx_b;
             polys.avm_main_mem_idx_c[i] = rows[i].avm_main_mem_idx_c;
             polys.avm_main_last[i] = rows[i].avm_main_last;
+            polys.equiv_tag_err[i] = rows[i].equiv_tag_err;
+            polys.equiv_tag_err_counts[i] = rows[i].equiv_tag_err_counts;
         }
 
         polys.avm_mem_m_rw_shift = Polynomial(polys.avm_mem_m_rw.shifted());
-        polys.avm_mem_m_tag_shift = Polynomial(polys.avm_mem_m_tag.shifted());
-        polys.avm_mem_m_val_shift = Polynomial(polys.avm_mem_m_val.shifted());
         polys.avm_mem_m_addr_shift = Polynomial(polys.avm_mem_m_addr.shifted());
-        polys.avm_main_internal_return_ptr_shift = Polynomial(polys.avm_main_internal_return_ptr.shifted());
-        polys.avm_main_pc_shift = Polynomial(polys.avm_main_pc.shifted());
-        polys.avm_alu_alu_u16_r6_shift = Polynomial(polys.avm_alu_alu_u16_r6.shifted());
-        polys.avm_alu_alu_u16_r0_shift = Polynomial(polys.avm_alu_alu_u16_r0.shifted());
+        polys.avm_mem_m_val_shift = Polynomial(polys.avm_mem_m_val.shifted());
+        polys.avm_mem_m_tag_shift = Polynomial(polys.avm_mem_m_tag.shifted());
         polys.avm_alu_alu_u16_r2_shift = Polynomial(polys.avm_alu_alu_u16_r2.shifted());
-        polys.avm_alu_alu_u16_r7_shift = Polynomial(polys.avm_alu_alu_u16_r7.shifted());
-        polys.avm_alu_alu_u16_r3_shift = Polynomial(polys.avm_alu_alu_u16_r3.shifted());
         polys.avm_alu_alu_u16_r1_shift = Polynomial(polys.avm_alu_alu_u16_r1.shifted());
         polys.avm_alu_alu_u16_r5_shift = Polynomial(polys.avm_alu_alu_u16_r5.shifted());
+        polys.avm_alu_alu_u16_r0_shift = Polynomial(polys.avm_alu_alu_u16_r0.shifted());
+        polys.avm_alu_alu_u16_r7_shift = Polynomial(polys.avm_alu_alu_u16_r7.shifted());
+        polys.avm_alu_alu_u16_r6_shift = Polynomial(polys.avm_alu_alu_u16_r6.shifted());
         polys.avm_alu_alu_u16_r4_shift = Polynomial(polys.avm_alu_alu_u16_r4.shifted());
+        polys.avm_alu_alu_u16_r3_shift = Polynomial(polys.avm_alu_alu_u16_r3.shifted());
+        polys.avm_main_pc_shift = Polynomial(polys.avm_main_pc.shifted());
+        polys.avm_main_internal_return_ptr_shift = Polynomial(polys.avm_main_internal_return_ptr.shifted());
 
         return polys;
     }
@@ -227,6 +232,19 @@ class AvmCircuitBuilder {
     [[maybe_unused]] bool check_circuit()
     {
 
+        const FF gamma = FF::random_element();
+        const FF beta = FF::random_element();
+        bb::RelationParameters<typename Flavor::FF> 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();
 
@@ -257,16 +275,41 @@ class AvmCircuitBuilder {
             return true;
         };
 
+        const auto evaluate_logderivative = [&]<typename LogDerivativeSettings>(const std::string& lookup_name) {
+            // Check the logderivative relation
+            bb::compute_logderivative_inverse<Flavor, LogDerivativeSettings>(polys, params, num_rows);
+
+            typename LogDerivativeSettings::SumcheckArrayOfValuesOverSubrelations lookup_result;
+
+            for (auto& r : lookup_result) {
+                r = 0;
+            }
+            for (size_t i = 0; i < num_rows; ++i) {
+                LogDerivativeSettings::accumulate(lookup_result, polys.get_row(i), params, 1);
+            }
+            for (auto r : lookup_result) {
+                if (r != 0) {
+                    info("Lookup ", lookup_name, " failed.");
+                    return false;
+                }
+            }
+            return true;
+        };
+
         if (!evaluate_relation.template operator()<Avm_vm::avm_mem<FF>>("avm_mem",
                                                                         Avm_vm::get_relation_label_avm_mem)) {
             return false;
         }
+        if (!evaluate_relation.template operator()<Avm_vm::avm_alu<FF>>("avm_alu",
+                                                                        Avm_vm::get_relation_label_avm_alu)) {
+            return false;
+        }
         if (!evaluate_relation.template operator()<Avm_vm::avm_main<FF>>("avm_main",
                                                                          Avm_vm::get_relation_label_avm_main)) {
             return false;
         }
-        if (!evaluate_relation.template operator()<Avm_vm::avm_alu<FF>>("avm_alu",
-                                                                        Avm_vm::get_relation_label_avm_alu)) {
+
+        if (!evaluate_logderivative.template operator()<equiv_tag_err_relation<FF>>("equiv_tag_err")) {
             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
index ca930d1b51e..f6c1a2fa2dd 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
@@ -12,9 +12,11 @@
 #include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp"
 
 #include "barretenberg/flavor/generated/toy_flavor.hpp"
+#include "barretenberg/relations/generated/toy/lookup_err.hpp"
 #include "barretenberg/relations/generated/toy/lookup_xor.hpp"
 #include "barretenberg/relations/generated/toy/toy_avm.hpp"
 #include "barretenberg/relations/generated/toy/two_column_perm.hpp"
+#include "barretenberg/relations/generated/toy/two_column_sparse_perm.hpp"
 
 namespace bb {
 
@@ -25,6 +27,10 @@ template <typename FF> struct ToyFullRow {
     FF toy_set_1_column_2{};
     FF toy_set_2_column_1{};
     FF toy_set_2_column_2{};
+    FF toy_sparse_column_1{};
+    FF toy_sparse_column_2{};
+    FF toy_sparse_lhs{};
+    FF toy_sparse_rhs{};
     FF toy_xor_a{};
     FF toy_xor_b{};
     FF toy_xor_c{};
@@ -33,9 +39,16 @@ template <typename FF> struct ToyFullRow {
     FF toy_table_xor_c{};
     FF toy_q_xor{};
     FF toy_q_xor_table{};
+    FF toy_q_err{};
+    FF toy_q_err_check{};
+    FF toy_clk{};
+    FF toy_m_clk{};
     FF two_column_perm{};
+    FF two_column_sparse_perm{};
     FF lookup_xor{};
+    FF lookup_err{};
     FF lookup_xor_counts{};
+    FF lookup_err_counts{};
 };
 
 class ToyCircuitBuilder {
@@ -48,8 +61,8 @@ class ToyCircuitBuilder {
     using Polynomial = Flavor::Polynomial;
     using ProverPolynomials = Flavor::ProverPolynomials;
 
-    static constexpr size_t num_fixed_columns = 17;
-    static constexpr size_t num_polys = 17;
+    static constexpr size_t num_fixed_columns = 28;
+    static constexpr size_t num_polys = 28;
     std::vector<Row> rows;
 
     void set_trace(std::vector<Row>&& trace) { rows = std::move(trace); }
@@ -71,6 +84,10 @@ class ToyCircuitBuilder {
             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_sparse_column_1[i] = rows[i].toy_sparse_column_1;
+            polys.toy_sparse_column_2[i] = rows[i].toy_sparse_column_2;
+            polys.toy_sparse_lhs[i] = rows[i].toy_sparse_lhs;
+            polys.toy_sparse_rhs[i] = rows[i].toy_sparse_rhs;
             polys.toy_xor_a[i] = rows[i].toy_xor_a;
             polys.toy_xor_b[i] = rows[i].toy_xor_b;
             polys.toy_xor_c[i] = rows[i].toy_xor_c;
@@ -79,9 +96,16 @@ class ToyCircuitBuilder {
             polys.toy_table_xor_c[i] = rows[i].toy_table_xor_c;
             polys.toy_q_xor[i] = rows[i].toy_q_xor;
             polys.toy_q_xor_table[i] = rows[i].toy_q_xor_table;
+            polys.toy_q_err[i] = rows[i].toy_q_err;
+            polys.toy_q_err_check[i] = rows[i].toy_q_err_check;
+            polys.toy_clk[i] = rows[i].toy_clk;
+            polys.toy_m_clk[i] = rows[i].toy_m_clk;
             polys.two_column_perm[i] = rows[i].two_column_perm;
+            polys.two_column_sparse_perm[i] = rows[i].two_column_sparse_perm;
             polys.lookup_xor[i] = rows[i].lookup_xor;
+            polys.lookup_err[i] = rows[i].lookup_err;
             polys.lookup_xor_counts[i] = rows[i].lookup_xor_counts;
+            polys.lookup_err_counts[i] = rows[i].lookup_err_counts;
         }
 
         return polys;
@@ -162,9 +186,16 @@ class ToyCircuitBuilder {
         if (!evaluate_logderivative.template operator()<two_column_perm_relation<FF>>("two_column_perm")) {
             return false;
         }
+        if (!evaluate_logderivative.template operator()<two_column_sparse_perm_relation<FF>>(
+                "two_column_sparse_perm")) {
+            return false;
+        }
         if (!evaluate_logderivative.template operator()<lookup_xor_relation<FF>>("lookup_xor")) {
             return false;
         }
+        if (!evaluate_logderivative.template operator()<lookup_err_relation<FF>>("lookup_err")) {
+            return false;
+        }
 
         return true;
     }
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 e20bbaf3a2f..4e1a77810af 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
@@ -115,3 +115,100 @@ TEST(ToyAVMCircuitBuilder, BaseCase)
     circuit_builder.rows[2].toy_xor_a = tmp;
     EXPECT_EQ(circuit_builder.check_circuit(), true);
 }
+
+/**
+ * @brief Investigate circuit builder / proving issue
+ *
+ */
+TEST(ToyAVMCircuitBuilder, MultiLookup)
+{
+    using FF = ToyFlavor::FF;
+    using Builder = ToyCircuitBuilder;
+    using Row = Builder::Row;
+    Builder circuit_builder;
+
+    const size_t circuit_size = 16;
+    std::vector<Row> rows;
+    // init empty rows
+    for (size_t i = 0; i < circuit_size; i++) {
+        Row row{};
+        rows.push_back(row);
+    }
+
+    // LOOKUPS
+    // Create clk mem access lookup table;
+    // We only want to turn on the mem write when clk is 1
+    Row& row_1 = rows[0];
+    row_1.toy_q_err = FF(1);
+    row_1.toy_clk = FF(1);
+    // Below we lookup two occurances, so our counts is 2
+    row_1.lookup_err_counts = FF(2);
+
+    // Set the mem read on two different rows, we will then lookup into the clk
+    row_1.toy_m_clk = FF(1);
+    row_1.toy_q_err_check = FF(1);
+
+    Row& row_3 = rows[2];
+    row_3.toy_m_clk = FF(1);
+    row_3.toy_q_err_check = FF(1);
+
+    // Check circuit passes
+    circuit_builder.set_trace(std::move(rows));
+    EXPECT_EQ(circuit_builder.check_circuit(), true);
+
+    // Turn off row_3 lookup selector, expect failure
+    circuit_builder.rows[2].toy_m_clk = FF(0);
+    EXPECT_EQ(circuit_builder.check_circuit(), false);
+}
+
+TEST(ToyAVMCircuitBuilder, EmptyLookups)
+{
+    using Builder = ToyCircuitBuilder;
+    using Row = Builder::Row;
+    Builder circuit_builder;
+
+    const size_t circuit_size = 16;
+    std::vector<Row> rows;
+    // init empty rows
+    for (size_t i = 0; i < circuit_size; i++) {
+        Row row{};
+        rows.push_back(row);
+    }
+
+    circuit_builder.set_trace(std::move(rows));
+    EXPECT_EQ(circuit_builder.check_circuit(), true);
+}
+
+TEST(ToyAVMCircuitBuilder, SparsePermutation)
+{
+    // Test sparse permutation, where the permutation check is not active on all rows
+    using FF = ToyFlavor::FF;
+    using Builder = ToyCircuitBuilder;
+    using Row = Builder::Row;
+    Builder circuit_builder;
+
+    const size_t circuit_size = 16;
+    std::vector<Row> rows;
+    // init empty rows
+    for (size_t i = 0; i < circuit_size; i++) {
+        Row row{};
+        rows.push_back(row);
+    }
+
+    // Activate lhs on row 1
+    Row& row_1 = rows[0];
+    row_1.toy_sparse_lhs = FF(1);
+    row_1.toy_sparse_column_1 = FF(420);
+
+    // Activate rhs on row 5
+    Row& row_5 = rows[4];
+    row_5.toy_sparse_rhs = FF(1);
+    row_5.toy_sparse_column_2 = FF(420);
+
+    circuit_builder.set_trace(std::move(rows));
+    EXPECT_EQ(circuit_builder.check_circuit(), true);
+
+    // Expect it to break after changing row5
+    circuit_builder.rows[4].toy_sparse_column_2 = FF(421);
+    EXPECT_EQ(circuit_builder.check_circuit(), false);
+}
\ No newline at end of file
diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp
index f46c80ce482..6257ec4d063 100644
--- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp
+++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp
@@ -7,41 +7,41 @@
 namespace bb::Avm_vm {
 
 template <typename FF> struct Avm_aluRow {
-    FF avm_alu_alu_u64_tag{};
-    FF avm_alu_alu_ic{};
-    FF avm_alu_alu_ia{};
-    FF avm_alu_alu_ff_tag{};
-    FF avm_alu_alu_u128_tag{};
     FF avm_alu_alu_u16_tag{};
-    FF avm_alu_alu_u16_r6_shift{};
-    FF avm_alu_alu_u8_tag{};
-    FF avm_alu_alu_u16_r0{};
-    FF avm_alu_alu_op_sub{};
-    FF avm_alu_alu_op_add{};
-    FF avm_alu_alu_u16_r0_shift{};
-    FF avm_alu_alu_u16_r2_shift{};
-    FF avm_alu_alu_u16_r7_shift{};
-    FF avm_alu_alu_u64_r0{};
+    FF avm_alu_alu_u16_r6{};
+    FF avm_alu_alu_ia{};
+    FF avm_alu_alu_ib{};
     FF avm_alu_alu_u16_r7{};
+    FF avm_alu_alu_u64_tag{};
+    FF avm_alu_alu_u16_r2_shift{};
+    FF avm_alu_alu_u8_r1{};
+    FF avm_alu_alu_op_eq_diff_inv{};
+    FF avm_alu_alu_u16_r3{};
+    FF avm_alu_alu_op_add{};
+    FF avm_alu_alu_op_not{};
+    FF avm_alu_alu_ff_tag{};
     FF avm_alu_alu_u8_r0{};
     FF avm_alu_alu_u16_r2{};
+    FF avm_alu_alu_u8_tag{};
+    FF avm_alu_alu_u16_r1{};
+    FF avm_alu_alu_u128_tag{};
     FF avm_alu_alu_op_eq{};
     FF avm_alu_alu_u16_r4{};
-    FF avm_alu_alu_op_eq_diff_inv{};
-    FF avm_alu_alu_ib{};
-    FF avm_alu_alu_u16_r1{};
-    FF avm_alu_alu_u8_r1{};
-    FF avm_alu_alu_op_mul{};
-    FF avm_alu_alu_u16_r6{};
-    FF avm_alu_alu_u16_r3_shift{};
-    FF avm_alu_alu_op_not{};
-    FF avm_alu_alu_u16_r5{};
-    FF avm_alu_alu_cf{};
+    FF avm_alu_alu_u16_r0{};
     FF avm_alu_alu_u16_r1_shift{};
     FF avm_alu_alu_u32_tag{};
-    FF avm_alu_alu_u16_r3{};
+    FF avm_alu_alu_op_sub{};
     FF avm_alu_alu_u16_r5_shift{};
+    FF avm_alu_alu_u16_r5{};
+    FF avm_alu_alu_u16_r0_shift{};
+    FF avm_alu_alu_u16_r7_shift{};
+    FF avm_alu_alu_cf{};
+    FF avm_alu_alu_u16_r6_shift{};
     FF avm_alu_alu_u16_r4_shift{};
+    FF avm_alu_alu_u16_r3_shift{};
+    FF avm_alu_alu_op_mul{};
+    FF avm_alu_alu_ic{};
+    FF avm_alu_alu_u64_r0{};
 };
 
 inline std::string get_relation_label_avm_alu(int index)
@@ -53,29 +53,29 @@ inline std::string get_relation_label_avm_alu(int index)
     case 7:
         return "ALU_ADD_SUB_2";
 
-    case 10:
-        return "ALU_MUL_COMMON_2";
-
-    case 14:
-        return "ALU_FF_NOT_XOR";
-
-    case 9:
-        return "ALU_MUL_COMMON_1";
+    case 16:
+        return "ALU_RES_IS_BOOL";
 
     case 13:
         return "ALU_MULTIPLICATION_OUT_U128";
 
-    case 8:
-        return "ALU_MULTIPLICATION_FF";
-
-    case 16:
-        return "ALU_RES_IS_BOOL";
-
     case 17:
         return "ALU_OP_EQ";
 
+    case 14:
+        return "ALU_FF_NOT_XOR";
+
     case 6:
         return "ALU_ADD_SUB_1";
+
+    case 8:
+        return "ALU_MULTIPLICATION_FF";
+
+    case 10:
+        return "ALU_MUL_COMMON_2";
+
+    case 9:
+        return "ALU_MUL_COMMON_1";
     }
     return std::to_string(index);
 }
diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp
index 40aef030283..1d93cbd92be 100644
--- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp
+++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp
@@ -7,63 +7,63 @@
 namespace bb::Avm_vm {
 
 template <typename FF> struct Avm_mainRow {
-    FF avm_main_op_err{};
-    FF avm_main_tag_err{};
-    FF avm_main_sel_op_mul{};
-    FF avm_main_mem_op_a{};
-    FF avm_main_mem_idx_a{};
-    FF avm_main_first{};
-    FF avm_main_sel_jump{};
-    FF avm_main_sel_internal_return{};
-    FF avm_main_rwa{};
-    FF avm_main_mem_op_c{};
-    FF avm_main_rwc{};
-    FF avm_main_internal_return_ptr_shift{};
-    FF avm_main_inv{};
+    FF avm_main_sel_op_eq{};
     FF avm_main_rwb{};
     FF avm_main_mem_idx_b{};
-    FF avm_main_sel_op_sub{};
-    FF avm_main_sel_halt{};
+    FF avm_main_sel_internal_call{};
+    FF avm_main_pc_shift{};
+    FF avm_main_rwa{};
+    FF avm_main_mem_op_b{};
+    FF avm_main_mem_idx_a{};
+    FF avm_main_inv{};
     FF avm_main_ia{};
-    FF avm_main_sel_op_div{};
-    FF avm_main_pc{};
-    FF avm_main_ib{};
-    FF avm_main_sel_op_not{};
+    FF avm_main_mem_op_a{};
+    FF avm_main_rwc{};
+    FF avm_main_tag_err{};
+    FF avm_main_sel_op_sub{};
     FF avm_main_internal_return_ptr{};
+    FF avm_main_sel_internal_return{};
     FF avm_main_sel_op_add{};
-    FF avm_main_mem_op_b{};
+    FF avm_main_sel_op_mul{};
+    FF avm_main_sel_halt{};
+    FF avm_main_mem_op_c{};
+    FF avm_main_sel_jump{};
+    FF avm_main_ib{};
     FF avm_main_ic{};
-    FF avm_main_sel_op_eq{};
-    FF avm_main_sel_internal_call{};
-    FF avm_main_pc_shift{};
+    FF avm_main_pc{};
+    FF avm_main_sel_op_div{};
+    FF avm_main_op_err{};
+    FF avm_main_internal_return_ptr_shift{};
+    FF avm_main_sel_op_not{};
+    FF avm_main_first{};
 };
 
 inline std::string get_relation_label_avm_main(int index)
 {
     switch (index) {
-    case 21:
-        return "SUBOP_DIVISION_FF";
-
-    case 38:
-        return "INTERNAL_RETURN_POINTER_CONSISTENCY";
-
     case 32:
         return "RETURN_POINTER_DECREMENT";
 
-    case 23:
-        return "SUBOP_DIVISION_ZERO_ERR2";
-
-    case 26:
-        return "RETURN_POINTER_INCREMENT";
+    case 22:
+        return "SUBOP_DIVISION_ZERO_ERR1";
 
     case 37:
         return "PC_INCREMENT";
 
-    case 22:
-        return "SUBOP_DIVISION_ZERO_ERR1";
-
     case 24:
         return "SUBOP_ERROR_RELEVANT_OP";
+
+    case 21:
+        return "SUBOP_DIVISION_FF";
+
+    case 23:
+        return "SUBOP_DIVISION_ZERO_ERR2";
+
+    case 38:
+        return "INTERNAL_RETURN_POINTER_CONSISTENCY";
+
+    case 26:
+        return "RETURN_POINTER_INCREMENT";
     }
     return std::to_string(index);
 }
diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp
index fe909be0a47..d3eea73c93c 100644
--- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp
+++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp
@@ -8,18 +8,18 @@ namespace bb::Avm_vm {
 
 template <typename FF> struct Avm_memRow {
     FF avm_mem_m_rw_shift{};
+    FF avm_mem_m_tag{};
+    FF avm_mem_m_tag_err{};
+    FF avm_mem_m_addr_shift{};
+    FF avm_mem_m_addr{};
+    FF avm_mem_m_one_min_inv{};
+    FF avm_mem_m_lastAccess{};
     FF avm_mem_m_rw{};
-    FF avm_mem_m_val{};
-    FF avm_mem_m_tag_shift{};
     FF avm_mem_m_val_shift{};
-    FF avm_mem_m_tag{};
     FF avm_mem_m_in_tag{};
+    FF avm_mem_m_val{};
+    FF avm_mem_m_tag_shift{};
     FF avm_mem_m_last{};
-    FF avm_mem_m_one_min_inv{};
-    FF avm_mem_m_addr_shift{};
-    FF avm_mem_m_lastAccess{};
-    FF avm_mem_m_tag_err{};
-    FF avm_mem_m_addr{};
 };
 
 inline std::string get_relation_label_avm_mem(int index)
@@ -28,15 +28,15 @@ inline std::string get_relation_label_avm_mem(int index)
     case 7:
         return "MEM_ZERO_INIT";
 
+    case 9:
+        return "MEM_IN_TAG_CONSISTENCY_2";
+
     case 4:
         return "MEM_LAST_ACCESS_DELIMITER";
 
     case 8:
         return "MEM_IN_TAG_CONSISTENCY_1";
 
-    case 9:
-        return "MEM_IN_TAG_CONSISTENCY_2";
-
     case 6:
         return "MEM_READ_WRITE_TAG_CONSISTENCY";
 
diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp
index d16fe0b41e1..8ac2f57eef6 100644
--- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp
+++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp
@@ -73,17 +73,19 @@
     [[maybe_unused]] auto avm_main_mem_idx_b = View(new_term.avm_main_mem_idx_b);                                      \
     [[maybe_unused]] auto avm_main_mem_idx_c = View(new_term.avm_main_mem_idx_c);                                      \
     [[maybe_unused]] auto avm_main_last = View(new_term.avm_main_last);                                                \
+    [[maybe_unused]] auto equiv_tag_err = View(new_term.equiv_tag_err);                                                \
+    [[maybe_unused]] auto equiv_tag_err_counts = View(new_term.equiv_tag_err_counts);                                  \
     [[maybe_unused]] auto avm_mem_m_rw_shift = View(new_term.avm_mem_m_rw_shift);                                      \
-    [[maybe_unused]] auto avm_mem_m_tag_shift = View(new_term.avm_mem_m_tag_shift);                                    \
-    [[maybe_unused]] auto avm_mem_m_val_shift = View(new_term.avm_mem_m_val_shift);                                    \
     [[maybe_unused]] auto avm_mem_m_addr_shift = View(new_term.avm_mem_m_addr_shift);                                  \
-    [[maybe_unused]] auto avm_main_internal_return_ptr_shift = View(new_term.avm_main_internal_return_ptr_shift);      \
-    [[maybe_unused]] auto avm_main_pc_shift = View(new_term.avm_main_pc_shift);                                        \
-    [[maybe_unused]] auto avm_alu_alu_u16_r6_shift = View(new_term.avm_alu_alu_u16_r6_shift);                          \
-    [[maybe_unused]] auto avm_alu_alu_u16_r0_shift = View(new_term.avm_alu_alu_u16_r0_shift);                          \
+    [[maybe_unused]] auto avm_mem_m_val_shift = View(new_term.avm_mem_m_val_shift);                                    \
+    [[maybe_unused]] auto avm_mem_m_tag_shift = View(new_term.avm_mem_m_tag_shift);                                    \
     [[maybe_unused]] auto avm_alu_alu_u16_r2_shift = View(new_term.avm_alu_alu_u16_r2_shift);                          \
-    [[maybe_unused]] auto avm_alu_alu_u16_r7_shift = View(new_term.avm_alu_alu_u16_r7_shift);                          \
-    [[maybe_unused]] auto avm_alu_alu_u16_r3_shift = View(new_term.avm_alu_alu_u16_r3_shift);                          \
     [[maybe_unused]] auto avm_alu_alu_u16_r1_shift = View(new_term.avm_alu_alu_u16_r1_shift);                          \
     [[maybe_unused]] auto avm_alu_alu_u16_r5_shift = View(new_term.avm_alu_alu_u16_r5_shift);                          \
-    [[maybe_unused]] auto avm_alu_alu_u16_r4_shift = View(new_term.avm_alu_alu_u16_r4_shift);
+    [[maybe_unused]] auto avm_alu_alu_u16_r0_shift = View(new_term.avm_alu_alu_u16_r0_shift);                          \
+    [[maybe_unused]] auto avm_alu_alu_u16_r7_shift = View(new_term.avm_alu_alu_u16_r7_shift);                          \
+    [[maybe_unused]] auto avm_alu_alu_u16_r6_shift = View(new_term.avm_alu_alu_u16_r6_shift);                          \
+    [[maybe_unused]] auto avm_alu_alu_u16_r4_shift = View(new_term.avm_alu_alu_u16_r4_shift);                          \
+    [[maybe_unused]] auto avm_alu_alu_u16_r3_shift = View(new_term.avm_alu_alu_u16_r3_shift);                          \
+    [[maybe_unused]] auto avm_main_pc_shift = View(new_term.avm_main_pc_shift);                                        \
+    [[maybe_unused]] auto avm_main_internal_return_ptr_shift = View(new_term.avm_main_internal_return_ptr_shift);
diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/equiv_tag_err.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/equiv_tag_err.hpp
new file mode 100644
index 00000000000..858ecfafa09
--- /dev/null
+++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/equiv_tag_err.hpp
@@ -0,0 +1,166 @@
+
+
+#pragma once
+
+#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp"
+
+#include <cstddef>
+#include <tuple>
+
+namespace bb {
+
+/**
+ * @brief This class contains an example of how to set LookupSettings classes used by the
+ * GenericLookupRelationImpl class to specify a scaled lookup
+ *
+ * @details To create your own lookup:
+ * 1) Create a copy of this class and rename it
+ * 2) Update all the values with the ones needed for your lookup
+ * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_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<GenericLookupRelation<ExampleXorLookupSettings,
+ * FF>>;)`
+ *
+ */
+class equiv_tag_err_lookup_settings {
+  public:
+    /**
+     * @brief The number of read terms (how many lookups we perform) in each row
+     *
+     */
+    static constexpr size_t READ_TERMS = 1;
+    /**
+     * @brief The number of write terms (how many additions to the lookup table we make) in each row
+     *
+     */
+    static constexpr size_t WRITE_TERMS = 1;
+
+    /**
+     * @brief The type of READ_TERM used for each read index (basic and scaled)
+     *
+     */
+    static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 };
+
+    /**
+     * @brief They type of WRITE_TERM used for each write index
+     *
+     */
+    static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 };
+
+    /**
+     * @brief How many values represent a single lookup object. This value is used by the automatic read term
+     * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a
+     * basic tuple
+     *
+     */
+    static constexpr size_t LOOKUP_TUPLE_SIZE = 1;
+
+    /**
+     * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed
+     *
+     */
+    static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 2;
+
+    /**
+     * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read
+     * terms, but will cause compilation error if not defined
+     *
+     */
+    static constexpr size_t READ_TERM_DEGREE = 0;
+
+    /**
+     * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write
+     * term, but will cause compilation error if not defined
+     *
+     */
+
+    static constexpr size_t WRITE_TERM_DEGREE = 0;
+
+    /**
+     * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index.
+     * Otherwise the value needs to be set to zero.
+     *
+     * @details If this is true then the lookup takes place in this row
+     *
+     */
+
+    template <typename AllEntities> static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in)
+    {
+        return (in.avm_mem_m_tag_err == 1 || in.avm_main_tag_err == 1);
+    }
+
+    /**
+     * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this
+     * row
+     *
+     * @tparam Accumulator Type specified by the lookup relation
+     * @tparam AllEntities Values/Univariates of all entities row
+     * @param in Value/Univariate of all entities at row/edge
+     * @return Accumulator
+     */
+
+    template <typename Accumulator, typename AllEntities>
+    static inline auto compute_inverse_exists(const AllEntities& in)
+    {
+        using View = typename Accumulator::View;
+        const auto is_operation = View(in.avm_mem_m_tag_err);
+        const auto is_table_entry = View(in.avm_main_tag_err);
+        return (is_operation + is_table_entry - is_operation * is_table_entry);
+    }
+
+    /**
+     * @brief Get all the entities for the lookup when need to update them
+     *
+     * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is
+     description for the current case:
+     The entities are returned as a tuple of references in the following order (this is for ):
+     * - The entity/polynomial used to store the product of the inverse values
+     * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up
+     * - READ_TERMS entities/polynomials that enable individual lookup operations
+     * - The entity/polynomial that enables adding an entry to the lookup table in this row
+     * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term
+     * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term
+     (scaled tuple)
+     * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple)
+     * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term
+     (scaled tuple)
+     * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table
+     *
+     * @return All the entities needed for the lookup
+     */
+
+    template <typename AllEntities> static inline auto get_const_entities(const AllEntities& in)
+    {
+
+        return std::forward_as_tuple(in.equiv_tag_err,
+                                     in.equiv_tag_err_counts,
+                                     in.avm_mem_m_tag_err,
+                                     in.avm_main_tag_err,
+                                     in.avm_mem_m_clk,
+                                     in.avm_main_clk);
+    }
+
+    /**
+     * @brief Get all the entities for the lookup when we only need to read them
+     * @details Same as in get_const_entities, but nonconst
+     *
+     * @return All the entities needed for the lookup
+     */
+
+    template <typename AllEntities> static inline auto get_nonconst_entities(AllEntities& in)
+    {
+
+        return std::forward_as_tuple(in.equiv_tag_err,
+                                     in.equiv_tag_err_counts,
+                                     in.avm_mem_m_tag_err,
+                                     in.avm_main_tag_err,
+                                     in.avm_mem_m_clk,
+                                     in.avm_main_clk);
+    }
+};
+
+template <typename FF_> using equiv_tag_err_relation = GenericLookupRelation<equiv_tag_err_lookup_settings, FF_>;
+template <typename FF_> using equiv_tag_err = GenericLookup<equiv_tag_err_lookup_settings, FF_>;
+
+} // namespace bb
diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/toy/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/toy/declare_views.hpp
index 98e120768ea..5b09589e950 100644
--- a/barretenberg/cpp/src/barretenberg/relations/generated/toy/declare_views.hpp
+++ b/barretenberg/cpp/src/barretenberg/relations/generated/toy/declare_views.hpp
@@ -8,6 +8,10 @@
     [[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_sparse_column_1 = View(new_term.toy_sparse_column_1);                                    \
+    [[maybe_unused]] auto toy_sparse_column_2 = View(new_term.toy_sparse_column_2);                                    \
+    [[maybe_unused]] auto toy_sparse_lhs = View(new_term.toy_sparse_lhs);                                              \
+    [[maybe_unused]] auto toy_sparse_rhs = View(new_term.toy_sparse_rhs);                                              \
     [[maybe_unused]] auto toy_xor_a = View(new_term.toy_xor_a);                                                        \
     [[maybe_unused]] auto toy_xor_b = View(new_term.toy_xor_b);                                                        \
     [[maybe_unused]] auto toy_xor_c = View(new_term.toy_xor_c);                                                        \
@@ -16,6 +20,13 @@
     [[maybe_unused]] auto toy_table_xor_c = View(new_term.toy_table_xor_c);                                            \
     [[maybe_unused]] auto toy_q_xor = View(new_term.toy_q_xor);                                                        \
     [[maybe_unused]] auto toy_q_xor_table = View(new_term.toy_q_xor_table);                                            \
+    [[maybe_unused]] auto toy_q_err = View(new_term.toy_q_err);                                                        \
+    [[maybe_unused]] auto toy_q_err_check = View(new_term.toy_q_err_check);                                            \
+    [[maybe_unused]] auto toy_clk = View(new_term.toy_clk);                                                            \
+    [[maybe_unused]] auto toy_m_clk = View(new_term.toy_m_clk);                                                        \
     [[maybe_unused]] auto two_column_perm = View(new_term.two_column_perm);                                            \
+    [[maybe_unused]] auto two_column_sparse_perm = View(new_term.two_column_sparse_perm);                              \
     [[maybe_unused]] auto lookup_xor = View(new_term.lookup_xor);                                                      \
-    [[maybe_unused]] auto lookup_xor_counts = View(new_term.lookup_xor_counts);
+    [[maybe_unused]] auto lookup_err = View(new_term.lookup_err);                                                      \
+    [[maybe_unused]] auto lookup_xor_counts = View(new_term.lookup_xor_counts);                                        \
+    [[maybe_unused]] auto lookup_err_counts = View(new_term.lookup_err_counts);
diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/toy/lookup_err.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/toy/lookup_err.hpp
new file mode 100644
index 00000000000..3cbb30d718f
--- /dev/null
+++ b/barretenberg/cpp/src/barretenberg/relations/generated/toy/lookup_err.hpp
@@ -0,0 +1,158 @@
+
+
+#pragma once
+
+#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp"
+
+#include <cstddef>
+#include <tuple>
+
+namespace bb {
+
+/**
+ * @brief This class contains an example of how to set LookupSettings classes used by the
+ * GenericLookupRelationImpl class to specify a scaled lookup
+ *
+ * @details To create your own lookup:
+ * 1) Create a copy of this class and rename it
+ * 2) Update all the values with the ones needed for your lookup
+ * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_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<GenericLookupRelation<ExampleXorLookupSettings,
+ * FF>>;)`
+ *
+ */
+class lookup_err_lookup_settings {
+  public:
+    /**
+     * @brief The number of read terms (how many lookups we perform) in each row
+     *
+     */
+    static constexpr size_t READ_TERMS = 1;
+    /**
+     * @brief The number of write terms (how many additions to the lookup table we make) in each row
+     *
+     */
+    static constexpr size_t WRITE_TERMS = 1;
+
+    /**
+     * @brief The type of READ_TERM used for each read index (basic and scaled)
+     *
+     */
+    static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 };
+
+    /**
+     * @brief They type of WRITE_TERM used for each write index
+     *
+     */
+    static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 };
+
+    /**
+     * @brief How many values represent a single lookup object. This value is used by the automatic read term
+     * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a
+     * basic tuple
+     *
+     */
+    static constexpr size_t LOOKUP_TUPLE_SIZE = 1;
+
+    /**
+     * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed
+     *
+     */
+    static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 2;
+
+    /**
+     * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read
+     * terms, but will cause compilation error if not defined
+     *
+     */
+    static constexpr size_t READ_TERM_DEGREE = 0;
+
+    /**
+     * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write
+     * term, but will cause compilation error if not defined
+     *
+     */
+
+    static constexpr size_t WRITE_TERM_DEGREE = 0;
+
+    /**
+     * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index.
+     * Otherwise the value needs to be set to zero.
+     *
+     * @details If this is true then the lookup takes place in this row
+     *
+     */
+
+    template <typename AllEntities> static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in)
+    {
+        return (in.toy_q_err_check == 1 || in.toy_q_err == 1);
+    }
+
+    /**
+     * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this
+     * row
+     *
+     * @tparam Accumulator Type specified by the lookup relation
+     * @tparam AllEntities Values/Univariates of all entities row
+     * @param in Value/Univariate of all entities at row/edge
+     * @return Accumulator
+     */
+
+    template <typename Accumulator, typename AllEntities>
+    static inline auto compute_inverse_exists(const AllEntities& in)
+    {
+        using View = typename Accumulator::View;
+        const auto is_operation = View(in.toy_q_err_check);
+        const auto is_table_entry = View(in.toy_q_err);
+        return (is_operation + is_table_entry - is_operation * is_table_entry);
+    }
+
+    /**
+     * @brief Get all the entities for the lookup when need to update them
+     *
+     * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is
+     description for the current case:
+     The entities are returned as a tuple of references in the following order (this is for ):
+     * - The entity/polynomial used to store the product of the inverse values
+     * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up
+     * - READ_TERMS entities/polynomials that enable individual lookup operations
+     * - The entity/polynomial that enables adding an entry to the lookup table in this row
+     * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term
+     * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term
+     (scaled tuple)
+     * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple)
+     * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term
+     (scaled tuple)
+     * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table
+     *
+     * @return All the entities needed for the lookup
+     */
+
+    template <typename AllEntities> static inline auto get_const_entities(const AllEntities& in)
+    {
+
+        return std::forward_as_tuple(
+            in.lookup_err, in.lookup_err_counts, in.toy_q_err_check, in.toy_q_err, in.toy_m_clk, in.toy_clk);
+    }
+
+    /**
+     * @brief Get all the entities for the lookup when we only need to read them
+     * @details Same as in get_const_entities, but nonconst
+     *
+     * @return All the entities needed for the lookup
+     */
+
+    template <typename AllEntities> static inline auto get_nonconst_entities(AllEntities& in)
+    {
+
+        return std::forward_as_tuple(
+            in.lookup_err, in.lookup_err_counts, in.toy_q_err_check, in.toy_q_err, in.toy_m_clk, in.toy_clk);
+    }
+};
+
+template <typename FF_> using lookup_err_relation = GenericLookupRelation<lookup_err_lookup_settings, FF_>;
+template <typename FF_> using lookup_err = GenericLookup<lookup_err_lookup_settings, FF_>;
+
+} // namespace bb
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
index c9eb36311cb..5b6220e7f50 100644
--- a/barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_perm.hpp
+++ b/barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_perm.hpp
@@ -23,7 +23,7 @@ class two_column_perm_permutation_settings {
 
     template <typename AllEntities> static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in)
     {
-        return (in.toy_q_tuple_set == 1);
+        return (in.toy_q_tuple_set == 1 || in.toy_q_tuple_set == 1);
     }
 
     /**
diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_sparse_perm.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_sparse_perm.hpp
new file mode 100644
index 00000000000..4ba979b2529
--- /dev/null
+++ b/barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_sparse_perm.hpp
@@ -0,0 +1,91 @@
+
+
+#pragma once
+
+#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp"
+
+#include <cstddef>
+#include <tuple>
+
+namespace bb {
+
+class two_column_sparse_perm_permutation_settings {
+  public:
+    // This constant defines how many columns are bundled together to form each set.
+    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 <typename AllEntities> static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in)
+    {
+        return (in.toy_sparse_lhs == 1 || in.toy_sparse_rhs == 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 <typename AllEntities> static inline auto get_const_entities(const AllEntities& in)
+    {
+
+        return std::forward_as_tuple(in.two_column_sparse_perm,
+                                     in.toy_sparse_lhs,
+                                     in.toy_sparse_lhs,
+                                     in.toy_sparse_rhs,
+                                     in.toy_sparse_column_1,
+                                     in.toy_sparse_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 <typename AllEntities> static inline auto get_nonconst_entities(AllEntities& in)
+    {
+
+        return std::forward_as_tuple(in.two_column_sparse_perm,
+                                     in.toy_sparse_lhs,
+                                     in.toy_sparse_lhs,
+                                     in.toy_sparse_rhs,
+                                     in.toy_sparse_column_1,
+                                     in.toy_sparse_column_2);
+    }
+};
+
+template <typename FF_>
+using two_column_sparse_perm_relation = GenericPermutationRelation<two_column_sparse_perm_permutation_settings, FF_>;
+template <typename FF_>
+using two_column_sparse_perm = GenericPermutation<two_column_sparse_perm_permutation_settings, FF_>;
+
+} // namespace bb
diff --git a/barretenberg/cpp/src/barretenberg/relations/generic_permutation/generic_permutation_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/generic_permutation/generic_permutation_relation.hpp
index 084132abfa3..a34290e7544 100644
--- a/barretenberg/cpp/src/barretenberg/relations/generic_permutation/generic_permutation_relation.hpp
+++ b/barretenberg/cpp/src/barretenberg/relations/generic_permutation/generic_permutation_relation.hpp
@@ -81,6 +81,7 @@ template <typename Settings, typename FF_> class GenericPermutationRelationImpl
 
     /**
      * @brief Get selector/wire switching on(1) or off(0) inverse computation
+     * We turn it on if either of the permutation contribution selectors are active
      *
      */
     template <typename Accumulator, typename AllEntities>
@@ -88,9 +89,16 @@ template <typename Settings, typename FF_> class GenericPermutationRelationImpl
     {
         using View = typename Accumulator::View;
 
-        // WIRE/SELECTOR enabling the permutation used in the sumcheck computation. This affects the first subrelation
-        return Accumulator(
-            View(std::get<ENABLE_INVERSE_CORRECTNESS_CHECK_POLYNOMIAL_INDEX>(Settings::get_const_entities(in))));
+        // WIRE/SELECTOR enabling the permutation used in the sumcheck computation. This affects the first
+        // subrelation
+        Accumulator const& first_set_enabled = Accumulator(
+            View(std::get<FIRST_PERMUTATION_SET_ENABLE_POLYNOMIAL_INDEX>(Settings::get_const_entities(in))));
+
+        Accumulator const& second_set_enabled = Accumulator(
+            View(std::get<SECOND_PERMUTATION_SET_ENABLE_POLYNOMIAL_INDEX>(Settings::get_const_entities(in))));
+
+        // This has the truth table of a logical OR
+        return (first_set_enabled + second_set_enabled - (first_set_enabled * second_set_enabled));
     }
 
     /**
diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.cpp
index 0d9f8495983..b0746af1d29 100644
--- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.cpp
+++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.cpp
@@ -1,4 +1,5 @@
 #include "avm_mem_trace.hpp"
+#include "barretenberg/vm/avm_trace/avm_common.hpp"
 
 namespace avm_trace {
 
@@ -84,6 +85,10 @@ void AvmMemTraceBuilder::load_mismatch_tag_in_mem_trace(uint32_t const m_clk,
                                                         AvmMemoryTag const m_tag)
 {
     FF one_min_inv = FF(1) - (FF(static_cast<uint32_t>(m_in_tag)) - FF(static_cast<uint32_t>(m_tag))).invert();
+
+    // Lookup counter hint, used for #[equiv_tag_err] lookup (joined on clk)
+    m_tag_err_lookup_counts[m_clk]++;
+
     mem_trace.emplace_back(MemoryTraceEntry{ .m_clk = m_clk,
                                              .m_sub_clk = m_sub_clk,
                                              .m_addr = m_addr,
diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.hpp
index 404c0ce7dc3..43adab419ea 100644
--- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.hpp
+++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.hpp
@@ -15,6 +15,10 @@ class AvmMemTraceBuilder {
     static const uint32_t SUB_CLK_STORE_B = 4;
     static const uint32_t SUB_CLK_STORE_C = 5;
 
+    // Keeps track of the number of times a mem tag err should appear in the trace
+    // clk -> count
+    std::map<uint32_t, uint32_t> m_tag_err_lookup_counts;
+
     struct MemoryTraceEntry {
         uint32_t m_clk{};
         uint32_t m_sub_clk{};
diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp
index 0de230ff0de..80d92bc98f8 100644
--- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp
+++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp
@@ -578,6 +578,20 @@ void AvmTraceBuilder::internal_return()
     internal_return_ptr--;
 }
 
+// Finalise Lookup Counts
+//
+// For log derivative lookups, we require a column that contains the number of times each lookup is consumed
+// As we build the trace, we keep track of the reads made in a mapping, so that they can be applied to the
+// counts column here
+//
+// NOTE: its coupled to pil - this is not the final iteration
+void AvmTraceBuilder::finalise_mem_trace_lookup_counts(std::map<uint32_t, uint32_t> const& tag_err_lookup_counts)
+{
+    for (auto const& [clk, count] : tag_err_lookup_counts) {
+        main_trace.at(clk).equiv_tag_err_counts = count;
+    }
+}
+
 /**
  * @brief Finalisation of the memory trace and incorporating it to the main trace.
  *        In particular, sorting the memory trace, setting .m_lastAccess and
@@ -594,6 +608,9 @@ std::vector<Row> AvmTraceBuilder::finalize()
     size_t main_trace_size = main_trace.size();
     size_t alu_trace_size = alu_trace.size();
 
+    // Get tag_err counts from the mem_trace_builder
+    this->finalise_mem_trace_lookup_counts(mem_trace_builder.m_tag_err_lookup_counts);
+
     // 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
diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp
index d205c98214d..d1d354aee06 100644
--- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp
+++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp
@@ -78,6 +78,8 @@ class AvmTraceBuilder {
     AvmMemTraceBuilder mem_trace_builder;
     AvmAluTraceBuilder alu_trace_builder;
 
+    void finalise_mem_trace_lookup_counts(std::map<uint32_t, uint32_t> const& tag_err_lookup_counts);
+
     uint32_t pc = 0;
     uint32_t internal_return_ptr = CALLSTACK_OFFSET;
     std::stack<uint32_t> internal_call_stack = {};
diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp
index 6229a31ad1b..7334d0af652 100644
--- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp
+++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp
@@ -170,6 +170,9 @@ bool AvmVerifier::verify_proof(const HonkProof& proof)
     commitments.avm_main_mem_idx_c =
         transcript->template receive_from_prover<Commitment>(commitment_labels.avm_main_mem_idx_c);
     commitments.avm_main_last = transcript->template receive_from_prover<Commitment>(commitment_labels.avm_main_last);
+    commitments.equiv_tag_err = transcript->template receive_from_prover<Commitment>(commitment_labels.equiv_tag_err);
+    commitments.equiv_tag_err_counts =
+        transcript->template receive_from_prover<Commitment>(commitment_labels.equiv_tag_err_counts);
 
     // Execute Sumcheck Verifier
     const size_t log_circuit_size = numeric::get_msb(circuit_size);
diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.cpp
index 43ae568ea6d..f30cd4207e4 100644
--- a/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.cpp
+++ b/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.cpp
@@ -61,6 +61,12 @@ bool ToyVerifier::verify_proof(const HonkProof& proof)
         transcript->template receive_from_prover<Commitment>(commitment_labels.toy_set_2_column_1);
     commitments.toy_set_2_column_2 =
         transcript->template receive_from_prover<Commitment>(commitment_labels.toy_set_2_column_2);
+    commitments.toy_sparse_column_1 =
+        transcript->template receive_from_prover<Commitment>(commitment_labels.toy_sparse_column_1);
+    commitments.toy_sparse_column_2 =
+        transcript->template receive_from_prover<Commitment>(commitment_labels.toy_sparse_column_2);
+    commitments.toy_sparse_lhs = transcript->template receive_from_prover<Commitment>(commitment_labels.toy_sparse_lhs);
+    commitments.toy_sparse_rhs = transcript->template receive_from_prover<Commitment>(commitment_labels.toy_sparse_rhs);
     commitments.toy_xor_a = transcript->template receive_from_prover<Commitment>(commitment_labels.toy_xor_a);
     commitments.toy_xor_b = transcript->template receive_from_prover<Commitment>(commitment_labels.toy_xor_b);
     commitments.toy_xor_c = transcript->template receive_from_prover<Commitment>(commitment_labels.toy_xor_c);
@@ -73,11 +79,21 @@ bool ToyVerifier::verify_proof(const HonkProof& proof)
     commitments.toy_q_xor = transcript->template receive_from_prover<Commitment>(commitment_labels.toy_q_xor);
     commitments.toy_q_xor_table =
         transcript->template receive_from_prover<Commitment>(commitment_labels.toy_q_xor_table);
+    commitments.toy_q_err = transcript->template receive_from_prover<Commitment>(commitment_labels.toy_q_err);
+    commitments.toy_q_err_check =
+        transcript->template receive_from_prover<Commitment>(commitment_labels.toy_q_err_check);
+    commitments.toy_clk = transcript->template receive_from_prover<Commitment>(commitment_labels.toy_clk);
+    commitments.toy_m_clk = transcript->template receive_from_prover<Commitment>(commitment_labels.toy_m_clk);
     commitments.two_column_perm =
         transcript->template receive_from_prover<Commitment>(commitment_labels.two_column_perm);
+    commitments.two_column_sparse_perm =
+        transcript->template receive_from_prover<Commitment>(commitment_labels.two_column_sparse_perm);
     commitments.lookup_xor = transcript->template receive_from_prover<Commitment>(commitment_labels.lookup_xor);
+    commitments.lookup_err = transcript->template receive_from_prover<Commitment>(commitment_labels.lookup_err);
     commitments.lookup_xor_counts =
         transcript->template receive_from_prover<Commitment>(commitment_labels.lookup_xor_counts);
+    commitments.lookup_err_counts =
+        transcript->template receive_from_prover<Commitment>(commitment_labels.lookup_err_counts);
 
     // Execute Sumcheck Verifier
     const size_t log_circuit_size = numeric::get_msb(circuit_size);
diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp
index 71178fbf277..2f4d24a261f 100644
--- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp
+++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp
@@ -1,6 +1,7 @@
 #include "avm_common.test.hpp"
 
 #include "barretenberg/numeric/uint128/uint128.hpp"
+#include "barretenberg/vm/avm_trace/avm_helper.hpp"
 
 using namespace bb;
 using namespace bb::numeric;
@@ -545,7 +546,7 @@ TEST_F(AvmArithmeticTestsU8, addition)
 
     //                             Memory layout:    [62,29,0,0,0,....]
     trace_builder.op_add(0, 1, 2, AvmMemoryTag::U8); // [62,29,91,0,0,....]
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_add(trace, FF(62), FF(29), FF(91), FF(0), FF(1), FF(2), AvmMemoryTag::U8);
@@ -553,6 +554,7 @@ TEST_F(AvmArithmeticTestsU8, addition)
     EXPECT_EQ(alu_row.avm_alu_alu_u8_tag, FF(1));
     EXPECT_EQ(alu_row.avm_alu_alu_cf, FF(0));
     EXPECT_EQ(alu_row.avm_alu_alu_u8_r0, FF(91));
+
     validate_trace_proof(std::move(trace));
 }
 
@@ -565,7 +567,7 @@ TEST_F(AvmArithmeticTestsU8, additionCarry)
 
     //                             Memory layout:    [159,100,0,0,0,....]
     trace_builder.op_add(0, 1, 2, AvmMemoryTag::U8); // [159,100,3,0,0,....]
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_add(trace, FF(159), FF(100), FF(3), FF(0), FF(1), FF(2), AvmMemoryTag::U8);
@@ -587,7 +589,7 @@ TEST_F(AvmArithmeticTestsU8, subtraction)
 
     //                             Memory layout:    [162,29,0,0,0,....]
     trace_builder.op_sub(0, 1, 2, AvmMemoryTag::U8); // [162,29,133,0,0,....]
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_sub(trace, FF(162), FF(29), FF(133), FF(0), FF(1), FF(2), AvmMemoryTag::U8);
@@ -609,7 +611,7 @@ TEST_F(AvmArithmeticTestsU8, subtractionCarry)
 
     //                             Memory layout:    [5,29,0,0,0,....]
     trace_builder.op_sub(0, 1, 2, AvmMemoryTag::U8); // [5,29,232,0,0,....]
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_sub(trace, FF(5), FF(29), FF(232), FF(0), FF(1), FF(2), AvmMemoryTag::U8);
@@ -637,7 +639,7 @@ TEST_F(AvmArithmeticTestsU8, multiplication)
     trace_builder.set(15, 1, AvmMemoryTag::U8);
 
     trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U8);
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row_index = common_validate_mul(trace, FF(13), FF(15), FF(195), FF(0), FF(1), FF(2), AvmMemoryTag::U8);
@@ -660,7 +662,7 @@ TEST_F(AvmArithmeticTestsU8, multiplicationOverflow)
     trace_builder.set(170, 1, AvmMemoryTag::U8);
 
     trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U8);
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row_index = common_validate_mul(trace, FF(200), FF(170), FF(208), FF(0), FF(1), FF(2), AvmMemoryTag::U8);
@@ -722,7 +724,7 @@ TEST_F(AvmArithmeticTestsU16, addition)
     trace_builder.set(33005, 546, AvmMemoryTag::U16);
 
     trace_builder.op_add(546, 119, 5, AvmMemoryTag::U16);
-    trace_builder.return_op(5, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row =
@@ -744,7 +746,7 @@ TEST_F(AvmArithmeticTestsU16, additionCarry)
     trace_builder.set(1000, 1, AvmMemoryTag::U16);
 
     trace_builder.op_add(1, 0, 0, AvmMemoryTag::U16);
-    trace_builder.return_op(0, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row =
@@ -766,7 +768,7 @@ TEST_F(AvmArithmeticTestsU16, subtraction)
     trace_builder.set(33005, 546, AvmMemoryTag::U16);
 
     trace_builder.op_sub(546, 119, 5, AvmMemoryTag::U16);
-    trace_builder.return_op(5, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row =
@@ -790,7 +792,7 @@ TEST_F(AvmArithmeticTestsU16, subtractionCarry)
     trace_builder.set(1000, 1, AvmMemoryTag::U16);
 
     trace_builder.op_sub(1, 0, 0, AvmMemoryTag::U16);
-    trace_builder.return_op(0, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row =
@@ -819,7 +821,7 @@ TEST_F(AvmArithmeticTestsU16, multiplication)
     trace_builder.set(245, 1, AvmMemoryTag::U16);
 
     trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U16);
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row_index =
@@ -844,7 +846,7 @@ TEST_F(AvmArithmeticTestsU16, multiplicationOverflow)
     trace_builder.set(1024, 1, AvmMemoryTag::U16);
 
     trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U16);
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row_index = common_validate_mul(trace, FF(512), FF(1024), FF(0), FF(0), FF(1), FF(2), AvmMemoryTag::U16);
@@ -908,7 +910,7 @@ TEST_F(AvmArithmeticTestsU32, addition)
     trace_builder.set(1234567891, 9, AvmMemoryTag::U32);
 
     trace_builder.op_add(8, 9, 0, AvmMemoryTag::U32);
-    trace_builder.return_op(0, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_add(
@@ -931,7 +933,7 @@ TEST_F(AvmArithmeticTestsU32, additionCarry)
     trace_builder.set(2293, 9, AvmMemoryTag::U32);
 
     trace_builder.op_add(8, 9, 0, AvmMemoryTag::U32);
-    trace_builder.return_op(0, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row =
@@ -953,7 +955,7 @@ TEST_F(AvmArithmeticTestsU32, subtraction)
     trace_builder.set(1234567891, 9, AvmMemoryTag::U32);
 
     trace_builder.op_sub(8, 9, 0, AvmMemoryTag::U32);
-    trace_builder.return_op(0, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_sub(
@@ -980,7 +982,7 @@ TEST_F(AvmArithmeticTestsU32, subtractionCarry)
     trace_builder.set(3210987654, 9, AvmMemoryTag::U32);
 
     trace_builder.op_sub(9, 8, 0, AvmMemoryTag::U32);
-    trace_builder.return_op(0, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_sub(
@@ -1011,7 +1013,7 @@ TEST_F(AvmArithmeticTestsU32, multiplication)
     trace_builder.set(11111, 1, AvmMemoryTag::U32);
 
     trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U32);
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row_index =
@@ -1040,7 +1042,7 @@ TEST_F(AvmArithmeticTestsU32, multiplicationOverflow)
     trace_builder.set(13 << 22, 1, AvmMemoryTag::U32);
 
     trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U32);
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row_index =
@@ -1113,7 +1115,7 @@ TEST_F(AvmArithmeticTestsU64, addition)
     trace_builder.set(b, 9, AvmMemoryTag::U64);
 
     trace_builder.op_add(8, 9, 9, AvmMemoryTag::U64);
-    trace_builder.return_op(9, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_add(trace, FF(a), FF(b), FF(c), FF(8), FF(9), FF(9), AvmMemoryTag::U64);
@@ -1143,7 +1145,7 @@ TEST_F(AvmArithmeticTestsU64, additionCarry)
     trace_builder.set(b, 1, AvmMemoryTag::U64);
 
     trace_builder.op_add(0, 1, 0, AvmMemoryTag::U64);
-    trace_builder.return_op(0, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_add(trace, FF(a), FF(b), FF(c), FF(0), FF(1), FF(0), AvmMemoryTag::U64);
@@ -1171,7 +1173,7 @@ TEST_F(AvmArithmeticTestsU64, subtraction)
     trace_builder.set(b, 9, AvmMemoryTag::U64);
 
     trace_builder.op_sub(8, 9, 9, AvmMemoryTag::U64);
-    trace_builder.return_op(9, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_sub(trace, FF(a), FF(b), FF(c), FF(8), FF(9), FF(9), AvmMemoryTag::U64);
@@ -1203,7 +1205,7 @@ TEST_F(AvmArithmeticTestsU64, subtractionCarry)
     trace_builder.set(b, 1, AvmMemoryTag::U64);
 
     trace_builder.op_sub(0, 1, 0, AvmMemoryTag::U64);
-    trace_builder.return_op(0, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_sub(trace, FF(a), FF(b), FF(c), FF(0), FF(1), FF(0), AvmMemoryTag::U64);
@@ -1231,7 +1233,7 @@ TEST_F(AvmArithmeticTestsU64, multiplication)
     trace_builder.set(555444333, 1, AvmMemoryTag::U64);
 
     trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U64);
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row_index = common_validate_mul(
@@ -1264,7 +1266,7 @@ TEST_F(AvmArithmeticTestsU64, multiplicationOverflow)
     trace_builder.set(b, 1, AvmMemoryTag::U64);
 
     trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U64);
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row_index = common_validate_mul(trace, FF(a), FF(b), FF(1), FF(0), FF(1), FF(2), AvmMemoryTag::U64);
@@ -1338,7 +1340,7 @@ TEST_F(AvmArithmeticTestsU128, addition)
     trace_builder.set(b, 9, AvmMemoryTag::U128);
 
     trace_builder.op_add(8, 9, 9, AvmMemoryTag::U128);
-    trace_builder.return_op(9, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_add(trace,
@@ -1378,7 +1380,7 @@ TEST_F(AvmArithmeticTestsU128, additionCarry)
     trace_builder.set(b, 9, AvmMemoryTag::U128);
 
     trace_builder.op_add(8, 9, 9, AvmMemoryTag::U128);
-    trace_builder.return_op(9, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_add(trace,
@@ -1417,7 +1419,7 @@ TEST_F(AvmArithmeticTestsU128, subtraction)
     trace_builder.set(b, 9, AvmMemoryTag::U128);
 
     trace_builder.op_sub(8, 9, 9, AvmMemoryTag::U128);
-    trace_builder.return_op(9, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_sub(trace,
@@ -1459,7 +1461,7 @@ TEST_F(AvmArithmeticTestsU128, subtractionCarry)
     trace_builder.set(b, 9, AvmMemoryTag::U128);
 
     trace_builder.op_sub(8, 9, 9, AvmMemoryTag::U128);
-    trace_builder.return_op(9, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_sub(trace,
@@ -1497,7 +1499,7 @@ TEST_F(AvmArithmeticTestsU128, multiplication)
     FF c{ uint256_t{ 0xA7DDA0BAE60CA3A5, 0x70289AEB0, 0, 0 } };
 
     trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U128);
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row_index = common_validate_mul(
@@ -1534,7 +1536,7 @@ TEST_F(AvmArithmeticTestsU128, multiplicationOverflow)
     trace_builder.set(b, 1, AvmMemoryTag::U128);
 
     trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U128);
-    trace_builder.return_op(2, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row_index = common_validate_mul(trace,
diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp
index 58760e5a6f6..3abc6645219 100644
--- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp
+++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp
@@ -117,7 +117,7 @@ TEST_F(AvmBitwiseTestsU8, BitwiseNot)
 {
     trace_builder.set(1, 0, AvmMemoryTag::U8);    // Memory Layout: [1,0,0,...]
     trace_builder.op_not(0, 1, AvmMemoryTag::U8); // [1,254,0,0,....]
-    trace_builder.return_op(1, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_op_not(trace, FF(1), FF(254), FF(0), FF(1), AvmMemoryTag::U8);
@@ -130,7 +130,7 @@ TEST_F(AvmBitwiseTestsU16, BitwiseNot)
 {
     trace_builder.set(512, 0, AvmMemoryTag::U16);  // Memory Layout: [512,0,0,...]
     trace_builder.op_not(0, 1, AvmMemoryTag::U16); // [512,65023,0,0,0,....]
-    trace_builder.return_op(1, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_op_not(trace, FF(512), FF(65'023), FF(0), FF(1), AvmMemoryTag::U16);
@@ -143,7 +143,7 @@ TEST_F(AvmBitwiseTestsU32, BitwiseNot)
 {
     trace_builder.set(131'072, 0, AvmMemoryTag::U32); // Memory Layout: [131072,0,0,...]
     trace_builder.op_not(0, 1, AvmMemoryTag::U32);    // [131072,4294836223,,0,0,....]
-    trace_builder.return_op(1, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row = common_validate_op_not(trace, FF(131'072), FF(4'294'836'223LLU), FF(0), FF(1), AvmMemoryTag::U32);
@@ -156,7 +156,7 @@ TEST_F(AvmBitwiseTestsU64, BitwiseNot)
 {
     trace_builder.set(0x100000000LLU, 0, AvmMemoryTag::U64); // Memory Layout: [8589934592,0,0,...]
     trace_builder.op_not(0, 1, AvmMemoryTag::U64);           // [8589934592,18446744069414584319,0,0,....]
-    trace_builder.return_op(1, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     auto alu_row =
@@ -172,7 +172,7 @@ TEST_F(AvmBitwiseTestsU128, BitwiseNot)
     uint128_t const a = uint128_t{ 0x4000000000000 } << 64;
     trace_builder.set(a, 0, AvmMemoryTag::U128);
     trace_builder.op_not(0, 1, AvmMemoryTag::U128);
-    trace_builder.return_op(1, 1);
+    trace_builder.return_op(0, 0);
     auto trace = trace_builder.finalize();
 
     uint128_t const res = (uint128_t{ 0xfffbffffffffffff } << 64) + uint128_t{ 0xffffffffffffffff };
diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp
index 9cf2a3b334e..756cc93d6ac 100644
--- a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp
+++ b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp
@@ -22,6 +22,8 @@ void validate_trace_proof(std::vector<Row>&& trace)
     auto verifier = composer.create_verifier(circuit_builder);
     bool verified = verifier.verify_proof(proof);
 
+    EXPECT_TRUE(verified);
+
     if (!verified) {
         avm_trace::log_avm_trace(circuit_builder.rows, 0, 10);
     }