diff --git a/barretenberg/cpp/bootstrap.sh b/barretenberg/cpp/bootstrap.sh index 8b6168b82290..d9c1735eee83 100755 --- a/barretenberg/cpp/bootstrap.sh +++ b/barretenberg/cpp/bootstrap.sh @@ -248,9 +248,13 @@ function test_cmds_native { local prefix=$hash # A little extra resource for these tests. # IPARecursiveTests fails with 2 threads. - if [[ "$test" =~ ^(AcirAvmRecursionConstraint|ChonkKernelCapacity|AvmRecursiveTests|IPARecursiveTests|HonkRecursionConstraintTest) ]]; then + if [[ "$test" =~ ^(AcirAvmRecursionConstraint|ChonkKernelCapacity|AvmRecursiveTests|IPARecursiveTests|HonkRecursionConstraintTest|ChonkRecursionConstraintTest) ]]; then prefix="$prefix:CPUS=4:MEM=8g" fi + # These tests routinely take 400-600s in debug builds; bump from the 600s default. + if [[ "$test" =~ ^(HonkRecursionConstraintTest|ChonkRecursionConstraintTest) ]]; then + prefix="$prefix:TIMEOUT=900s" + fi echo -e "$prefix barretenberg/cpp/scripts/run_test.sh $bin_name $test" done || (echo "Failed to list tests in $bin" && exit 1) done diff --git a/barretenberg/cpp/scripts/test_chonk_standalone_vks_havent_changed.sh b/barretenberg/cpp/scripts/test_chonk_standalone_vks_havent_changed.sh index d36494156b27..8797f2a56079 100755 --- a/barretenberg/cpp/scripts/test_chonk_standalone_vks_havent_changed.sh +++ b/barretenberg/cpp/scripts/test_chonk_standalone_vks_havent_changed.sh @@ -21,7 +21,7 @@ script_path="$root/barretenberg/cpp/scripts/test_chonk_standalone_vks_havent_cha # - Generate a hash for versioning: sha256sum bb-chonk-inputs.tar.gz # - Upload the compressed results: aws s3 cp bb-chonk-inputs.tar.gz s3://aztec-ci-artifacts/protocol/bb-chonk-inputs-[hash(0:8)].tar.gz # Note: In case of the "Test suite failed to run ... Unexpected token 'with' " error, need to run: docker pull aztecprotocol/build:3.0 -pinned_short_hash="33a01e19" +pinned_short_hash="50947760" pinned_chonk_inputs_url="https://aztec-ci-artifacts.s3.us-east-2.amazonaws.com/protocol/bb-chonk-inputs-${pinned_short_hash}.tar.gz" function update_pinned_hash_in_script { diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp index 81e93b837ff6..0da24c2cc41f 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp @@ -91,7 +91,10 @@ template class KZG { quotient_commitment, GroupElement::one(builder) }; std::vector scalars = { one, claim.opening_pair.challenge, -claim.opening_pair.evaluation }; - P_0 = GroupElement::batch_mul(commitments, scalars); + + // Compute C + r*[W]_1 + (-v)*[1]_1 as a batch_mul, no need of edge case handling since we don't expect the + // points to be linearly dependent. + P_0 = GroupElement::batch_mul(commitments, scalars, /*max_num_bits=*/0, /*with_edgecases=*/false); } else { P_0 = claim.commitment; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 7f01ea9f37ee..654c099be139 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -517,19 +517,12 @@ template class ShpleminiVerifier_ { } // Erase the duplicate entries (higher-index range first to preserve lower indices) - auto erase_range = [&](size_t duplicate_start, size_t original_start, size_t count) { + // Each erase shifts elements down, so duplicate_start always points to the next duplicate; + // the original at original_start + i is unaffected since we erase higher-index ranges first. + // Commitment equality (original == duplicate) is verified by per-flavor + // RepeatedCommitmentsIndicesCorrect tests rather than at runtime here. + auto erase_range = [&](size_t duplicate_start, [[maybe_unused]] size_t original_start, size_t count) { for (size_t i = 0; i < count; ++i) { - // Verify the commitment being erased matches its original (native only). - // Each erase shifts elements down, so duplicate_start always points to the - // next duplicate; the original at original_start + i is unaffected since - // we erase higher-index ranges first. - if constexpr (!Curve::is_stdlib_type) { - if (commitments[duplicate_start] != commitments[original_start + i]) { - throw_or_abort("remove_repeated_commitments: commitment mismatch at duplicate index " + - std::to_string(duplicate_start) + " vs original index " + - std::to_string(original_start + i)); - } - } scalars.erase(scalars.begin() + static_cast(duplicate_start)); commitments.erase(commitments.begin() + static_cast(duplicate_start)); } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/gate_count_constants.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/gate_count_constants.hpp index 1daf3fa3d135..faad18e4cda0 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/gate_count_constants.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/gate_count_constants.hpp @@ -55,7 +55,7 @@ template inline constexpr size_t ASSERT_EQUALITY = ZERO_GATE // Honk Recursion Constants // ======================================== -inline constexpr size_t ROOT_ROLLUP_GATE_COUNT = 12904885; +inline constexpr size_t ROOT_ROLLUP_GATE_COUNT = 12904895; template constexpr std::tuple HONK_RECURSION_CONSTANTS( @@ -67,40 +67,40 @@ constexpr std::tuple HONK_RECURSION_CONSTANTS( if constexpr (std::is_same_v>) { switch (mode) { case PredicateTestCase::ConstantTrue: - return std::make_tuple(681762, 0); + return std::make_tuple(681767, 0); case PredicateTestCase::WitnessTrue: case PredicateTestCase::WitnessFalse: - return std::make_tuple(682819, 0); + return std::make_tuple(682824, 0); } } else if constexpr (std::is_same_v>) { switch (mode) { case PredicateTestCase::ConstantTrue: - return std::make_tuple(703917, 0); + return std::make_tuple(703922, 0); case PredicateTestCase::WitnessTrue: case PredicateTestCase::WitnessFalse: - return std::make_tuple(705070, 0); + return std::make_tuple(705075, 0); } } else if constexpr (std::is_same_v>) { switch (mode) { case PredicateTestCase::ConstantTrue: - return std::make_tuple(20909, 73); + return std::make_tuple(20914, 73); case PredicateTestCase::WitnessTrue: case PredicateTestCase::WitnessFalse: - return std::make_tuple(21966, 73); + return std::make_tuple(21971, 73); } } else if constexpr (std::is_same_v>) { switch (mode) { case PredicateTestCase::ConstantTrue: - return std::make_tuple(25476, 77); + return std::make_tuple(25481, 77); case PredicateTestCase::WitnessTrue: case PredicateTestCase::WitnessFalse: - return std::make_tuple(26629, 77); + return std::make_tuple(26634, 77); } } else if constexpr (std::is_same_v>) { if (mode != PredicateTestCase::ConstantTrue) { bb::assert_failure("Unhandled mode in MegaZKRecursiveFlavor."); } - return std::make_tuple(781910, 0); + return std::make_tuple(781915, 0); } else { bb::assert_failure("Unhandled recursive flavor."); } @@ -113,7 +113,7 @@ constexpr std::tuple HONK_RECURSION_CONSTANTS( // ======================================== // Gate count for Chonk recursive verification (Ultra with RollupIO) -inline constexpr size_t CHONK_RECURSION_GATES = 1491408; +inline constexpr size_t CHONK_RECURSION_GATES = 1491593; // ======================================== // Hypernova Recursion Constants @@ -123,22 +123,22 @@ inline constexpr size_t CHONK_RECURSION_GATES = 1491408; inline constexpr size_t MSM_ROWS_OFFSET = 2; // Init kernel gate counts (verifies OINK proof) -inline constexpr size_t INIT_KERNEL_GATE_COUNT = 25027; +inline constexpr size_t INIT_KERNEL_GATE_COUNT = 25032; inline constexpr size_t INIT_KERNEL_ECC_ROWS = 848 + MSM_ROWS_OFFSET; inline constexpr size_t INIT_KERNEL_ULTRA_OPS = 89; // Inner kernel gate counts (verifies HN proof for previous kernel + HN for app) -inline constexpr size_t INNER_KERNEL_GATE_COUNT_HN = 60487; +inline constexpr size_t INNER_KERNEL_GATE_COUNT_HN = 60497; inline constexpr size_t INNER_KERNEL_ECC_ROWS = 1700 + MSM_ROWS_OFFSET; inline constexpr size_t INNER_KERNEL_ULTRA_OPS = 179; // Tail kernel gate counts (verifies HN_TAIL proof) -inline constexpr size_t TAIL_KERNEL_GATE_COUNT = 32868; +inline constexpr size_t TAIL_KERNEL_GATE_COUNT = 32873; inline constexpr size_t TAIL_KERNEL_ECC_ROWS = 914 + MSM_ROWS_OFFSET; inline constexpr size_t TAIL_KERNEL_ULTRA_OPS = 96; // Hiding kernel gate counts (verifies HN_FINAL proof) -inline constexpr size_t HIDING_KERNEL_GATE_COUNT = 36265; +inline constexpr size_t HIDING_KERNEL_GATE_COUNT = 36270; inline constexpr size_t HIDING_KERNEL_ECC_ROWS = 1407 + MSM_ROWS_OFFSET; inline constexpr size_t HIDING_KERNEL_ULTRA_OPS = 127; @@ -147,7 +147,7 @@ inline constexpr size_t HIDING_KERNEL_ULTRA_OPS = 127; // ======================================== // Gate count for ECCVM recursive verifier (Ultra-arithmetized) -inline constexpr size_t ECCVM_RECURSIVE_VERIFIER_GATE_COUNT = 224162; +inline constexpr size_t ECCVM_RECURSIVE_VERIFIER_GATE_COUNT = 224336; // ======================================== // Goblin AVM Recursive Verifier Constants diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.cpp index 83b66882f4ba..b8522cd06852 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.cpp @@ -23,6 +23,15 @@ void create_logic_gate(Builder& builder, field_ct right = to_field_ct(b, builder); field_ct computed_result = bb::stdlib::logic::create_logic_constraint(left, right, num_bits, is_xor_gate); + + // In write-VK mode the result witness holds a dummy zero. In certain cases, the computed result is non-zero so the + // assert_equal would spuriously fail. Patch the witness value so the downstream assertion sees the correct value. + // Eg. for an XOR gate, if the inputs are constants such that the result is a non-zero constant, the assert_equal + // will fail in write-VK mode since the result witness is initialized to zero. + if (builder.is_write_vk_mode()) { + builder.set_variable(result, computed_result.get_value()); + } + field_ct acir_result = field_ct::from_witness_index(&builder, result); computed_result.assert_equal(acir_result); } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.test.cpp index 10b1b2c69229..96a408e13879 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/logic_constraint.test.cpp @@ -73,8 +73,8 @@ class LogicConstraintTestingFunctions { return WitnessOrConstant::from_index(input_index); }; - bb::fr lhs = FF(static_cast(1) << num_bits - 1); // All bits from 0 to num_bits-1 are set - bb::fr rhs = FF(static_cast(1) << num_bits - 1); // All bits from 0 to num_bits-1 are set + bb::fr lhs = FF((static_cast(1) << num_bits) - 1); // All bits from 0 to num_bits-1 are set + bb::fr rhs = FF((static_cast(1) << num_bits) - 1); // All bits from 0 to num_bits-1 are set bb::fr result = is_xor_gate ? (static_cast(lhs) ^ static_cast(rhs)) : (static_cast(lhs) & static_cast(rhs)); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp index 24fd53118bdc..91986df09c47 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp @@ -198,7 +198,7 @@ function equal(Fr a, Fr b) pure returns (bool) { uint256 constant CONST_PROOF_SIZE_LOG_N = 25; -uint256 constant NUMBER_OF_SUBRELATIONS = 28; +uint256 constant NUMBER_OF_SUBRELATIONS = 29; uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8; uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9; uint256 constant NUMBER_OF_ENTITIES = 41; @@ -870,6 +870,12 @@ library RelationsLib { Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * wire(p, WIRE.Z_PERM_SHIFT)) * domainSep; evals[3] = acc; } + + // Contribution 4: z_perm initialization check (lagrange_first * z_perm = 0) + { + Fr acc = (wire(p, WIRE.LAGRANGE_FIRST) * wire(p, WIRE.Z_PERM)) * domainSep; + evals[4] = acc; + } } function accumulateLogDerivativeLookupRelation( @@ -919,9 +925,9 @@ library RelationsLib { Fr read_tag_boolean_relation = read_tag * read_tag - read_tag; - evals[4] = accumulatorNone; - evals[5] = accumulatorOne; - evals[6] = read_tag_boolean_relation * domainSep; + evals[5] = accumulatorNone; + evals[6] = accumulatorOne; + evals[7] = read_tag_boolean_relation * domainSep; } function accumulateDeltaRangeRelation( @@ -947,7 +953,7 @@ library RelationsLib { acc = acc * (delta_1 + minus_three); acc = acc * wire(p, WIRE.Q_RANGE); acc = acc * domainSep; - evals[7] = acc; + evals[8] = acc; } // Contribution 7 @@ -958,7 +964,7 @@ library RelationsLib { acc = acc * (delta_2 + minus_three); acc = acc * wire(p, WIRE.Q_RANGE); acc = acc * domainSep; - evals[8] = acc; + evals[9] = acc; } // Contribution 8 @@ -969,7 +975,7 @@ library RelationsLib { acc = acc * (delta_3 + minus_three); acc = acc * wire(p, WIRE.Q_RANGE); acc = acc * domainSep; - evals[9] = acc; + evals[10] = acc; } // Contribution 9 @@ -980,7 +986,7 @@ library RelationsLib { acc = acc * (delta_4 + minus_three); acc = acc * wire(p, WIRE.Q_RANGE); acc = acc * domainSep; - evals[10] = acc; + evals[11] = acc; } } @@ -1015,7 +1021,7 @@ library RelationsLib { x_add_identity = x_add_identity * x_diff * x_diff; x_add_identity = x_add_identity - y2_sqr - y1_sqr + y1y2 + y1y2; - evals[11] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); + evals[12] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); } // Contribution 11 point addition, x-coordinate check @@ -1024,7 +1030,7 @@ library RelationsLib { Fr y1_plus_y3 = ep.y_1 + ep.y_3; Fr y_diff = ep.y_2 * q_sign - ep.y_1; Fr y_add_identity = y1_plus_y3 * x_diff + (ep.x_3 - ep.x_1) * y_diff; - evals[12] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); + evals[13] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); } // Contribution 10 point doubling, x-coordinate check @@ -1040,7 +1046,7 @@ library RelationsLib { ep.x_double_identity = (ep.x_3 + ep.x_1 + ep.x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9; Fr acc = ep.x_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; - evals[11] = evals[11] + acc; + evals[12] = evals[12] + acc; } // Contribution 11 point doubling, y-coordinate check @@ -1048,7 +1054,7 @@ library RelationsLib { { Fr x1_sqr_mul_3 = (ep.x_1 + ep.x_1 + ep.x_1) * ep.x_1; Fr y_double_identity = x1_sqr_mul_3 * (ep.x_1 - ep.x_3) - (ep.y_1 + ep.y_1) * (ep.y_1 + ep.y_3); - evals[12] = evals[12] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; + evals[13] = evals[13] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; } } @@ -1135,9 +1141,9 @@ library RelationsLib { ap.adjacent_values_match_if_adjacent_indices_match = (ap.index_delta * MINUS_ONE + ONE) * ap.record_delta; // deg 2 - evals[14] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) + evals[15] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 - evals[15] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) + evals[16] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 ap.ROM_consistency_check_identity = ap.memory_record_check * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7 @@ -1184,10 +1190,10 @@ library RelationsLib { ap.next_gate_access_type * ap.next_gate_access_type - ap.next_gate_access_type; // Putting it all together... - evals[16] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation + evals[17] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 - evals[17] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 - evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 + evals[18] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 + evals[19] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_O)); // deg 3 or 9 @@ -1218,7 +1224,7 @@ library RelationsLib { // (deg 3 or 9) + (deg 4) + (deg 3) ap.memory_identity = ap.memory_identity * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 10 - evals[13] = ap.memory_identity; + evals[14] = ap.memory_identity; } function accumulateNnfRelation( @@ -1294,7 +1300,7 @@ library RelationsLib { ap.nnf_identity = non_native_field_identity + limb_accumulator_identity; ap.nnf_identity = ap.nnf_identity * (wire(p, WIRE.Q_NNF) * domainSep); - evals[19] = ap.nnf_identity; + evals[20] = ap.nnf_identity; } function accumulatePoseidonExternalRelation( @@ -1330,13 +1336,13 @@ library RelationsLib { ep.v3 = ep.t2 + ep.v4; // u_1 + 3u_2 + 5u_3 + 7u_4 ep.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_EXTERNAL) * domainSep; - evals[20] = evals[20] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT)); + evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT)); - evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT)); + evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT)); - evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT)); + evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT)); - evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT)); + evals[24] = evals[24] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT)); } function accumulatePoseidonInternalRelation( @@ -1368,16 +1374,16 @@ library RelationsLib { ip.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_INTERNAL) * domainSep; ip.v1 = ip.u1 * INTERNAL_MATRIX_DIAGONAL[0] + ip.u_sum; - evals[24] = evals[24] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT)); + evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT)); ip.v2 = ip.u2 * INTERNAL_MATRIX_DIAGONAL[1] + ip.u_sum; - evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT)); + evals[26] = evals[26] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT)); ip.v3 = ip.u3 * INTERNAL_MATRIX_DIAGONAL[2] + ip.u_sum; - evals[26] = evals[26] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT)); + evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT)); ip.v4 = ip.u4 * INTERNAL_MATRIX_DIAGONAL[3] + ip.u_sum; - evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT)); + evals[28] = evals[28] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT)); } // Batch subrelation evaluations using precomputed powers of alpha diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_optimized_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_optimized_contract.hpp index aa04b1fa054e..c736d98bbe93 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_optimized_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_optimized_contract.hpp @@ -15,7 +15,7 @@ inline std::string generate_memory_offsets(int log_n) { const int BATCHED_RELATION_PARTIAL_LENGTH = 8; - const int NUMBER_OF_SUBRELATIONS = 28; + const int NUMBER_OF_SUBRELATIONS = 29; const int NUMBER_OF_ALPHAS = NUMBER_OF_SUBRELATIONS - 1; const int START_POINTER = 0x1000; const int BARYCENTRIC_DOMAIN_SIZE = 8; @@ -397,7 +397,7 @@ interface IVerifier { -uint256 constant NUMBER_OF_SUBRELATIONS = 28; +uint256 constant NUMBER_OF_SUBRELATIONS = 29; uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8; uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9; uint256 constant NUMBER_OF_ENTITIES = 41; @@ -870,7 +870,7 @@ contract HonkVerifier is IVerifier { // Compute powers of alpha: alpha^2, alpha^3, ..., alpha^26 let alpha_off_set := ALPHA_CHALLENGE_1 - for {} lt(alpha_off_set, add(ALPHA_CHALLENGE_26, 0x20)) {} { + for {} lt(alpha_off_set, add(ALPHA_CHALLENGE_27, 0x20)) {} { let prev_alpha := mload(sub(alpha_off_set, 0x20)) mstore(alpha_off_set, mulmod(prev_alpha, alpha, p)) alpha_off_set := add(alpha_off_set, 0x20) @@ -1624,6 +1624,16 @@ contract HonkVerifier is IVerifier { ) mstore(SUBRELATION_EVAL_3_LOC, acc) } + + // Contribution 4: z_perm initialization (lagrange_first * z_perm = 0) + { + let acc := mulmod( + mulmod(mload(LAGRANGE_FIRST_EVAL_LOC), mload(Z_PERM_EVAL_LOC), p), + mload(POW_PARTIAL_EVALUATION_LOC), + p + ) + mstore(SUBRELATION_EVAL_4_LOC, acc) + } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ @@ -1687,9 +1697,9 @@ contract HonkVerifier is IVerifier { let read_tag_boolean_relation := mulmod(read_tag, addmod(read_tag, sub(p, 1), p), p) read_tag_boolean_relation := mulmod(read_tag_boolean_relation, mload(POW_PARTIAL_EVALUATION_LOC), p) - mstore(SUBRELATION_EVAL_4_LOC, accumulator_none) - mstore(SUBRELATION_EVAL_5_LOC, accumulator_one) - mstore(SUBRELATION_EVAL_6_LOC, read_tag_boolean_relation) + mstore(SUBRELATION_EVAL_5_LOC, accumulator_none) + mstore(SUBRELATION_EVAL_6_LOC, accumulator_one) + mstore(SUBRELATION_EVAL_7_LOC, read_tag_boolean_relation) } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ @@ -1712,7 +1722,7 @@ contract HonkVerifier is IVerifier { acc := mulmod(acc, addmod(delta_1, minus_three, p), p) acc := mulmod(acc, mload(QRANGE_EVAL_LOC), p) acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p) - mstore(SUBRELATION_EVAL_7_LOC, acc) + mstore(SUBRELATION_EVAL_8_LOC, acc) } { @@ -1722,7 +1732,7 @@ contract HonkVerifier is IVerifier { acc := mulmod(acc, addmod(delta_2, minus_three, p), p) acc := mulmod(acc, mload(QRANGE_EVAL_LOC), p) acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p) - mstore(SUBRELATION_EVAL_8_LOC, acc) + mstore(SUBRELATION_EVAL_9_LOC, acc) } { @@ -1732,7 +1742,7 @@ contract HonkVerifier is IVerifier { acc := mulmod(acc, addmod(delta_3, minus_three, p), p) acc := mulmod(acc, mload(QRANGE_EVAL_LOC), p) acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p) - mstore(SUBRELATION_EVAL_9_LOC, acc) + mstore(SUBRELATION_EVAL_10_LOC, acc) } { @@ -1742,7 +1752,7 @@ contract HonkVerifier is IVerifier { acc := mulmod(acc, addmod(delta_4, minus_three, p), p) acc := mulmod(acc, mload(QRANGE_EVAL_LOC), p) acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p) - mstore(SUBRELATION_EVAL_10_LOC, acc) + mstore(SUBRELATION_EVAL_11_LOC, acc) } } @@ -1767,7 +1777,7 @@ contract HonkVerifier is IVerifier { let eval := mulmod(x_add_identity, mload(POW_PARTIAL_EVALUATION_LOC), p) eval := mulmod(eval, mload(QELLIPTIC_EVAL_LOC), p) eval := mulmod(eval, addmod(1, sub(p, mload(EC_Q_IS_DOUBLE)), p), p) - mstore(SUBRELATION_EVAL_11_LOC, eval) + mstore(SUBRELATION_EVAL_12_LOC, eval) } { @@ -1784,7 +1794,7 @@ contract HonkVerifier is IVerifier { let eval := mulmod(y_add_identity, mload(POW_PARTIAL_EVALUATION_LOC), p) eval := mulmod(eval, mload(QELLIPTIC_EVAL_LOC), p) eval := mulmod(eval, addmod(1, sub(p, mload(EC_Q_IS_DOUBLE)), p), p) - mstore(SUBRELATION_EVAL_12_LOC, eval) + mstore(SUBRELATION_EVAL_13_LOC, eval) } { @@ -1800,10 +1810,10 @@ contract HonkVerifier is IVerifier { let acc := mulmod(ep_x_double_identity, mload(POW_PARTIAL_EVALUATION_LOC), p) acc := mulmod(mulmod(acc, mload(QELLIPTIC_EVAL_LOC), p), mload(EC_Q_IS_DOUBLE), p) - acc := addmod(acc, mload(SUBRELATION_EVAL_11_LOC), p) + acc := addmod(acc, mload(SUBRELATION_EVAL_12_LOC), p) // Add to existing contribution - and double check that numbers here - mstore(SUBRELATION_EVAL_11_LOC, acc) + mstore(SUBRELATION_EVAL_12_LOC, acc) } { @@ -1826,10 +1836,10 @@ contract HonkVerifier is IVerifier { let acc := mulmod(y_double_identity, mload(POW_PARTIAL_EVALUATION_LOC), p) acc := mulmod(mulmod(acc, mload(QELLIPTIC_EVAL_LOC), p), mload(EC_Q_IS_DOUBLE), p) - acc := addmod(acc, mload(SUBRELATION_EVAL_12_LOC), p) + acc := addmod(acc, mload(SUBRELATION_EVAL_13_LOC), p) // Add to existing contribution - and double check that numbers here - mstore(SUBRELATION_EVAL_12_LOC, acc) + mstore(SUBRELATION_EVAL_13_LOC, acc) } } @@ -1936,7 +1946,7 @@ contract HonkVerifier is IVerifier { mulmod(record_delta, addmod(1, sub(p, index_delta), p), p) mstore( - SUBRELATION_EVAL_14_LOC, + SUBRELATION_EVAL_15_LOC, mulmod( adjacent_values_match_if_adjacent_indices_match, mulmod( @@ -1954,7 +1964,7 @@ contract HonkVerifier is IVerifier { // ROM_CONSISTENCY_CHECK_2 mstore( - SUBRELATION_EVAL_15_LOC, + SUBRELATION_EVAL_16_LOC, mulmod( index_is_monotonically_increasing, mulmod( @@ -2050,7 +2060,7 @@ contract HonkVerifier is IVerifier { ) mstore( - SUBRELATION_EVAL_16_LOC, + SUBRELATION_EVAL_17_LOC, mulmod( adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation, scaled_activation_selector, @@ -2059,12 +2069,12 @@ contract HonkVerifier is IVerifier { ) mstore( - SUBRELATION_EVAL_17_LOC, + SUBRELATION_EVAL_18_LOC, mulmod(index_is_monotonically_increasing, scaled_activation_selector, p) ) mstore( - SUBRELATION_EVAL_18_LOC, + SUBRELATION_EVAL_19_LOC, mulmod(next_gate_access_type_is_boolean, scaled_activation_selector, p) ) @@ -2121,7 +2131,7 @@ contract HonkVerifier is IVerifier { mulmod(mload(QMEMORY_EVAL_LOC), mload(POW_PARTIAL_EVALUATION_LOC), p), p ) - mstore(SUBRELATION_EVAL_13_LOC, memory_identity) + mstore(SUBRELATION_EVAL_14_LOC, memory_identity) } } } @@ -2268,7 +2278,7 @@ contract HonkVerifier is IVerifier { p ) - mstore(SUBRELATION_EVAL_19_LOC, nnf_identity) + mstore(SUBRELATION_EVAL_20_LOC, nnf_identity) } /* @@ -2321,22 +2331,22 @@ contract HonkVerifier is IVerifier { mulmod(mload(QPOSEIDON2_EXTERNAL_EVAL_LOC), mload(POW_PARTIAL_EVALUATION_LOC), p) mstore( - SUBRELATION_EVAL_20_LOC, + SUBRELATION_EVAL_21_LOC, mulmod(q_pos_by_scaling, addmod(v1, sub(p, mload(W1_SHIFT_EVAL_LOC)), p), p) ) mstore( - SUBRELATION_EVAL_21_LOC, + SUBRELATION_EVAL_22_LOC, mulmod(q_pos_by_scaling, addmod(v2, sub(p, mload(W2_SHIFT_EVAL_LOC)), p), p) ) mstore( - SUBRELATION_EVAL_22_LOC, + SUBRELATION_EVAL_23_LOC, mulmod(q_pos_by_scaling, addmod(v3, sub(p, mload(W3_SHIFT_EVAL_LOC)), p), p) ) mstore( - SUBRELATION_EVAL_23_LOC, + SUBRELATION_EVAL_24_LOC, mulmod(q_pos_by_scaling, addmod(v4, sub(p, mload(W4_SHIFT_EVAL_LOC)), p), p) ) } @@ -2364,25 +2374,25 @@ contract HonkVerifier is IVerifier { let v1 := addmod(mulmod(u1, POS_INTERNAL_MATRIX_D_0, p), u_sum, p) mstore( - SUBRELATION_EVAL_24_LOC, + SUBRELATION_EVAL_25_LOC, mulmod(q_pos_by_scaling, addmod(v1, sub(p, mload(W1_SHIFT_EVAL_LOC)), p), p) ) let v2 := addmod(mulmod(u2, POS_INTERNAL_MATRIX_D_1, p), u_sum, p) mstore( - SUBRELATION_EVAL_25_LOC, + SUBRELATION_EVAL_26_LOC, mulmod(q_pos_by_scaling, addmod(v2, sub(p, mload(W2_SHIFT_EVAL_LOC)), p), p) ) let v3 := addmod(mulmod(u3, POS_INTERNAL_MATRIX_D_2, p), u_sum, p) mstore( - SUBRELATION_EVAL_26_LOC, + SUBRELATION_EVAL_27_LOC, mulmod(q_pos_by_scaling, addmod(v3, sub(p, mload(W3_SHIFT_EVAL_LOC)), p), p) ) let v4 := addmod(mulmod(u4, POS_INTERNAL_MATRIX_D_3, p), u_sum, p) mstore( - SUBRELATION_EVAL_27_LOC, + SUBRELATION_EVAL_28_LOC, mulmod(q_pos_by_scaling, addmod(v4, sub(p, mload(W4_SHIFT_EVAL_LOC)), p), p) ) } @@ -2531,6 +2541,11 @@ contract HonkVerifier is IVerifier { mulmod(mload(SUBRELATION_EVAL_27_LOC), mload(ALPHA_CHALLENGE_26), p), p ) + accumulator := addmod( + accumulator, + mulmod(mload(SUBRELATION_EVAL_28_LOC), mload(ALPHA_CHALLENGE_27), p), + p + ) let sumcheck_valid := eq(accumulator, mload(FINAL_ROUND_TARGET_LOC)) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp index 0721e888c4dd..45330e978986 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp @@ -198,7 +198,7 @@ function equal(Fr a, Fr b) pure returns (bool) { uint256 constant CONST_PROOF_SIZE_LOG_N = 25; -uint256 constant NUMBER_OF_SUBRELATIONS = 28; +uint256 constant NUMBER_OF_SUBRELATIONS = 29; uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8; uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9; uint256 constant NUMBER_OF_ENTITIES = 41; @@ -926,6 +926,12 @@ library RelationsLib { Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * wire(p, WIRE.Z_PERM_SHIFT)) * domainSep; evals[3] = acc; } + + // Contribution 4: z_perm initialization check (lagrange_first * z_perm = 0) + { + Fr acc = (wire(p, WIRE.LAGRANGE_FIRST) * wire(p, WIRE.Z_PERM)) * domainSep; + evals[4] = acc; + } } function accumulateLogDerivativeLookupRelation( @@ -975,9 +981,9 @@ library RelationsLib { Fr read_tag_boolean_relation = read_tag * read_tag - read_tag; - evals[4] = accumulatorNone; - evals[5] = accumulatorOne; - evals[6] = read_tag_boolean_relation * domainSep; + evals[5] = accumulatorNone; + evals[6] = accumulatorOne; + evals[7] = read_tag_boolean_relation * domainSep; } function accumulateDeltaRangeRelation( @@ -1003,7 +1009,7 @@ library RelationsLib { acc = acc * (delta_1 + minus_three); acc = acc * wire(p, WIRE.Q_RANGE); acc = acc * domainSep; - evals[7] = acc; + evals[8] = acc; } // Contribution 7 @@ -1014,7 +1020,7 @@ library RelationsLib { acc = acc * (delta_2 + minus_three); acc = acc * wire(p, WIRE.Q_RANGE); acc = acc * domainSep; - evals[8] = acc; + evals[9] = acc; } // Contribution 8 @@ -1025,7 +1031,7 @@ library RelationsLib { acc = acc * (delta_3 + minus_three); acc = acc * wire(p, WIRE.Q_RANGE); acc = acc * domainSep; - evals[9] = acc; + evals[10] = acc; } // Contribution 9 @@ -1036,7 +1042,7 @@ library RelationsLib { acc = acc * (delta_4 + minus_three); acc = acc * wire(p, WIRE.Q_RANGE); acc = acc * domainSep; - evals[10] = acc; + evals[11] = acc; } } @@ -1071,7 +1077,7 @@ library RelationsLib { x_add_identity = x_add_identity * x_diff * x_diff; x_add_identity = x_add_identity - y2_sqr - y1_sqr + y1y2 + y1y2; - evals[11] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); + evals[12] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); } // Contribution 11 point addition, x-coordinate check @@ -1080,7 +1086,7 @@ library RelationsLib { Fr y1_plus_y3 = ep.y_1 + ep.y_3; Fr y_diff = ep.y_2 * q_sign - ep.y_1; Fr y_add_identity = y1_plus_y3 * x_diff + (ep.x_3 - ep.x_1) * y_diff; - evals[12] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); + evals[13] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); } // Contribution 10 point doubling, x-coordinate check @@ -1096,7 +1102,7 @@ library RelationsLib { ep.x_double_identity = (ep.x_3 + ep.x_1 + ep.x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9; Fr acc = ep.x_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; - evals[11] = evals[11] + acc; + evals[12] = evals[12] + acc; } // Contribution 11 point doubling, y-coordinate check @@ -1104,7 +1110,7 @@ library RelationsLib { { Fr x1_sqr_mul_3 = (ep.x_1 + ep.x_1 + ep.x_1) * ep.x_1; Fr y_double_identity = x1_sqr_mul_3 * (ep.x_1 - ep.x_3) - (ep.y_1 + ep.y_1) * (ep.y_1 + ep.y_3); - evals[12] = evals[12] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; + evals[13] = evals[13] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; } } @@ -1191,9 +1197,9 @@ library RelationsLib { ap.adjacent_values_match_if_adjacent_indices_match = (ap.index_delta * MINUS_ONE + ONE) * ap.record_delta; // deg 2 - evals[14] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) + evals[15] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 - evals[15] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) + evals[16] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 ap.ROM_consistency_check_identity = ap.memory_record_check * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7 @@ -1240,10 +1246,10 @@ library RelationsLib { ap.next_gate_access_type * ap.next_gate_access_type - ap.next_gate_access_type; // Putting it all together... - evals[16] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation + evals[17] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 - evals[17] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 - evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 + evals[18] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 + evals[19] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_O)); // deg 3 or 9 @@ -1274,7 +1280,7 @@ library RelationsLib { // (deg 3 or 9) + (deg 4) + (deg 3) ap.memory_identity = ap.memory_identity * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 10 - evals[13] = ap.memory_identity; + evals[14] = ap.memory_identity; } function accumulateNnfRelation( @@ -1350,7 +1356,7 @@ library RelationsLib { ap.nnf_identity = non_native_field_identity + limb_accumulator_identity; ap.nnf_identity = ap.nnf_identity * (wire(p, WIRE.Q_NNF) * domainSep); - evals[19] = ap.nnf_identity; + evals[20] = ap.nnf_identity; } function accumulatePoseidonExternalRelation( @@ -1386,13 +1392,13 @@ library RelationsLib { ep.v3 = ep.t2 + ep.v4; // u_1 + 3u_2 + 5u_3 + 7u_4 ep.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_EXTERNAL) * domainSep; - evals[20] = evals[20] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT)); + evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT)); - evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT)); + evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT)); - evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT)); + evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT)); - evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT)); + evals[24] = evals[24] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT)); } function accumulatePoseidonInternalRelation( @@ -1424,16 +1430,16 @@ library RelationsLib { ip.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_INTERNAL) * domainSep; ip.v1 = ip.u1 * INTERNAL_MATRIX_DIAGONAL[0] + ip.u_sum; - evals[24] = evals[24] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT)); + evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT)); ip.v2 = ip.u2 * INTERNAL_MATRIX_DIAGONAL[1] + ip.u_sum; - evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT)); + evals[26] = evals[26] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT)); ip.v3 = ip.u3 * INTERNAL_MATRIX_DIAGONAL[2] + ip.u_sum; - evals[26] = evals[26] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT)); + evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT)); ip.v4 = ip.u4 * INTERNAL_MATRIX_DIAGONAL[3] + ip.u_sum; - evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT)); + evals[28] = evals[28] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT)); } // Batch subrelation evaluations using precomputed powers of alpha diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp index 7a0a1298f452..fdbb7508dfa8 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp @@ -629,14 +629,14 @@ template struct alignas(32) field { BB_INLINE static field asm_sqr_with_coarse_reduction(const field& a) noexcept; BB_INLINE static field asm_add_with_coarse_reduction(const field& a, const field& b) noexcept; BB_INLINE static field asm_sub_with_coarse_reduction(const field& a, const field& b) noexcept; - BB_INLINE static void asm_self_mul_with_coarse_reduction(const field& a, const field& b) noexcept; - BB_INLINE static void asm_self_sqr_with_coarse_reduction(const field& a) noexcept; - BB_INLINE static void asm_self_add_with_coarse_reduction(const field& a, const field& b) noexcept; - BB_INLINE static void asm_self_sub_with_coarse_reduction(const field& a, const field& b) noexcept; + BB_INLINE static void asm_self_mul_with_coarse_reduction(field& a, const field& b) noexcept; + BB_INLINE static void asm_self_sqr_with_coarse_reduction(field& a) noexcept; + BB_INLINE static void asm_self_add_with_coarse_reduction(field& a, const field& b) noexcept; + BB_INLINE static void asm_self_sub_with_coarse_reduction(field& a, const field& b) noexcept; BB_INLINE static void asm_conditional_negate(field& r, uint64_t predicate) noexcept; BB_INLINE static field asm_reduce_once(const field& a) noexcept; - BB_INLINE static void asm_self_reduce_once(const field& a) noexcept; + BB_INLINE static void asm_self_reduce_once(field& a) noexcept; static constexpr uint64_t zero_reference = 0x00ULL; #endif constexpr field tonelli_shanks_sqrt() const noexcept; diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl_x64.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl_x64.hpp index 1ae46ef8acd3..9af0bf5f653f 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl_x64.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl_x64.hpp @@ -46,7 +46,7 @@ template field field::asm_mul_with_coarse_reduction(const field& return r; } -template void field::asm_self_mul_with_coarse_reduction(const field& a, const field& b) noexcept +template void field::asm_self_mul_with_coarse_reduction(field& a, const field& b) noexcept { constexpr uint64_t r_inv = T::r_inv; constexpr uint64_t modulus_0 = modulus.data[0]; @@ -141,7 +141,7 @@ template field field::asm_sqr_with_coarse_reduction(const field& return r; } -template void field::asm_self_sqr_with_coarse_reduction(const field& a) noexcept +template void field::asm_self_sqr_with_coarse_reduction(field& a) noexcept { constexpr uint64_t r_inv = T::r_inv; constexpr uint64_t modulus_0 = modulus.data[0]; @@ -227,7 +227,7 @@ template field field::asm_add_with_coarse_reduction(const field& return r; } -template void field::asm_self_add_with_coarse_reduction(const field& a, const field& b) noexcept +template void field::asm_self_add_with_coarse_reduction(field& a, const field& b) noexcept { constexpr uint64_t twice_not_modulus_0 = twice_not_modulus.data[0]; constexpr uint64_t twice_not_modulus_1 = twice_not_modulus.data[1]; @@ -277,7 +277,7 @@ template field field::asm_sub_with_coarse_reduction(const field& return r; } -template void field::asm_self_sub_with_coarse_reduction(const field& a, const field& b) noexcept +template void field::asm_self_sub_with_coarse_reduction(field& a, const field& b) noexcept { constexpr uint64_t twice_modulus_0 = twice_modulus.data[0]; constexpr uint64_t twice_modulus_1 = twice_modulus.data[1]; @@ -353,7 +353,7 @@ template field field::asm_reduce_once(const field& a) noexcept return r; } -template void field::asm_self_reduce_once(const field& a) noexcept +template void field::asm_self_reduce_once(field& a) noexcept { constexpr uint64_t not_modulus_0 = not_modulus.data[0]; constexpr uint64_t not_modulus_1 = not_modulus.data[1]; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm.test.cpp index 6be40ddd3d63..ee42bbabd9d6 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm.test.cpp @@ -559,3 +559,42 @@ TEST_F(ECCVMTests, MaskingTailCommitments) EXPECT_NE(naive, structured.wire_comms[i]) << "Wire " << i << " commitment should be masked"; } } + +/** + * @brief Verify that REPEATED_COMMITMENTS indices correctly pair to-be-shifted and shifted commitments. + * @details Mirrors the Shplemini commitment vector construction: [Q, unshifted_comms..., to_be_shifted_comms...], + * then applies offset = HasZK ? 2 : 1, and checks commitments[original_start + offset + i] == + * commitments[duplicate_start + offset + i]. This is a one-time substitute for the runtime BB_ASSERTs + * in remove_repeated_commitments. + */ +TEST_F(ECCVMTests, RepeatedCommitmentsIndicesCorrect) +{ + ECCVMCircuitBuilder builder = generate_circuit(&engine); + auto pk = std::make_shared(builder); + pk->commitment_key = ECCVMFlavor::CommitmentKey(pk->circuit_size); + + auto unshifted = pk->polynomials.get_unshifted(); + auto to_be_shifted = pk->polynomials.get_to_be_shifted(); + + constexpr auto repeated = ECCVMFlavor::REPEATED_COMMITMENTS; + ASSERT_EQ(to_be_shifted.size(), repeated.first.count); + + // Build the commitment vector exactly as Shplemini does: [Q, unshifted..., to_be_shifted...] + const auto& ck = pk->commitment_key; + std::vector commitments; + commitments.push_back(ECCVMFlavor::Commitment::one()); // dummy Q + for (auto& poly : unshifted) { + commitments.push_back(ck.commit(poly)); + } + for (auto& poly : to_be_shifted) { + commitments.push_back(ck.commit(poly)); + } + + // Same offset logic as remove_repeated_commitments + constexpr size_t offset = ECCVMFlavor::HasZK ? 2 : 1; + for (size_t i = 0; i < repeated.first.count; i++) { + EXPECT_EQ(commitments[repeated.first.original_start + offset + i], + commitments[repeated.first.duplicate_start + offset + i]) + << "REPEATED_COMMITMENTS commitment mismatch at index " << i; + } +} diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp index d518e24aa6a1..0a59e35ba7df 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp @@ -86,14 +86,34 @@ class ECCVMFlavor { static constexpr size_t NUM_SHIFTED_ENTITIES = 26; // The number of entities in DerivedWitnessEntities that are not going to be shifted. static constexpr size_t NUM_DERIVED_WITNESS_ENTITIES_NON_SHIFTED = 1; - // A container to be fed to ShpleminiVerifier to avoid redundant scalar muls, the first number is the index of the - // first witness to be shifted. + // Indices into the Shplemini commitments vector that identify which "to-be-shifted" witness commitments in the + // unshifted block are duplicated in the shifted block, so their scalar muls can be merged. + // + // Shplemini's remove_repeated_commitments uses offset = HasZK ? 2 : 1. For ECCVM (HasZK=true), offset=2 + // accounts for the Shplonk:Q commitment and the gemini_masking_poly that precede the Precomputed+Witness + // block in the commitments vector. The indices below are therefore relative to the start of + // {PrecomputedEntities + WitnessEntities} (i.e. they exclude MaskingEntities, which is covered by the offset). + // + // original_start: index of the first to-be-shifted entity within {Precomputed + Witness} + // = NUM_PRECOMPUTED + NUM_WIRE_NON_SHIFTED (= NUM_WITNESS - NUM_DERIVED_NON_SHIFTED - NUM_SHIFTED) + // duplicate_start: index where the shifted copies begin = NUM_PRECOMPUTED + NUM_WITNESS + static constexpr size_t NUM_WIRE_NON_SHIFTED = + NUM_WITNESS_ENTITIES - NUM_DERIVED_WITNESS_ENTITIES_NON_SHIFTED - NUM_SHIFTED_ENTITIES; static constexpr RepeatedCommitmentsData REPEATED_COMMITMENTS = - RepeatedCommitmentsData(NUM_PRECOMPUTED_ENTITIES + NUM_WITNESS_ENTITIES - - NUM_DERIVED_WITNESS_ENTITIES_NON_SHIFTED - NUM_SHIFTED_ENTITIES, + RepeatedCommitmentsData(NUM_PRECOMPUTED_ENTITIES + NUM_WIRE_NON_SHIFTED, NUM_PRECOMPUTED_ENTITIES + NUM_WITNESS_ENTITIES, NUM_SHIFTED_ENTITIES); + // Pin entity counts and REPEATED_COMMITMENTS indices so that any layout change triggers a compile error. + // The to-be-shifted witnesses must form a contiguous block starting at NUM_WIRE_NON_SHIFTED within WitnessEntities. + static_assert(NUM_WIRE_NON_SHIFTED == 60, "WireNonShiftedEntities size changed — update REPEATED_COMMITMENTS"); + static_assert(NUM_MASKING_POLYNOMIALS == 1, "MaskingEntities size changed — review REPEATED_COMMITMENTS offset"); + static_assert(REPEATED_COMMITMENTS.first.original_start == 64, + "REPEATED_COMMITMENTS original_start changed — verify Shplemini offset convention"); + static_assert(REPEATED_COMMITMENTS.first.duplicate_start == 91, + "REPEATED_COMMITMENTS duplicate_start changed — verify Shplemini offset convention"); + static_assert(REPEATED_COMMITMENTS.first.count == 26, "REPEATED_COMMITMENTS count changed"); + using GrandProductRelations = std::tuple>; // define the tuple of Relations that comprise the Sumcheck relation template @@ -1029,7 +1049,7 @@ class ECCVMFlavor { // 4: We also force that `transcript_op==0`. return (polynomials.z_perm[edge_idx] == polynomials.z_perm_shift[edge_idx]) && (polynomials.z_perm[edge_idx + 1] == polynomials.z_perm_shift[edge_idx + 1]) && - (polynomials.lagrange_last[edge_idx] == 0 && polynomials.lagrange_last[edge_idx + 1]) == 0 && + (polynomials.lagrange_last[edge_idx] == 0 && polynomials.lagrange_last[edge_idx + 1] == 0) && (polynomials.msm_transition[edge_idx] == 0 && polynomials.msm_transition[edge_idx + 1] == 0) && (polynomials.transcript_mul[edge_idx] == 0 && polynomials.transcript_mul[edge_idx + 1] == 0) && (polynomials.transcript_op[edge_idx] == 0 && polynomials.transcript_op[edge_idx + 1] == 0); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_relation_corruption.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_relation_corruption.test.cpp index 96004f8fb6a6..9baf1f3fb599 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_relation_corruption.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_relation_corruption.test.cpp @@ -376,3 +376,61 @@ TEST_F(ECCVMRelationCorruptionTests, TranscriptNoOpRowRejectsAccumulatorNotEmpty "the row following a no-op"; EXPECT_TRUE(failures.contains(22)) << "Subrelation 22 (accumulator_infinity) should catch the corruption"; } + +/** + * @brief Test that z_perm must be zero at the lagrange_first row. + * + * @details The set relation grand product relies on z_perm[0] = 0 so that (z_perm + lagrange_first) + * evaluates to 1 at the first row. Sub-relation Z_PERM_INIT (lagrange_first * z_perm = 0) enforces this. + * + * We cross-check the lagrange_first position two ways: + * 1. Structurally: z_perm.start_index() - 1 (the zero row before the shiftable region) + * 2. By scanning the lagrange_first polynomial for its non-zero entry + */ +TEST_F(ECCVMRelationCorruptionTests, SetRelationFailsOnZPermNonZeroAtFirstRow) +{ + auto polynomials = build_valid_eccvm_msm_state(); + auto params = compute_full_relation_params(polynomials); + + // Baseline: set relation passes + auto baseline = RelationChecker::check>(polynomials, params, "ECCVMSetRelation"); + EXPECT_TRUE(baseline.empty()) << "Baseline set relation should pass"; + + // Derive expected lagrange_first position from z_perm shiftable structure + ASSERT_TRUE(polynomials.z_perm.is_shiftable()); + size_t structural_first_row = polynomials.z_perm.start_index() - 1; + + // Independently scan lagrange_first for its non-zero entry + const auto& lagrange_first = polynomials.lagrange_first; + size_t scanned_first_row = 0; + bool found = false; + for (size_t i = lagrange_first.start_index(); i < lagrange_first.end_index(); ++i) { + if (lagrange_first[i] != FF(0)) { + scanned_first_row = i; + found = true; + break; + } + } + ASSERT_TRUE(found) << "lagrange_first has no non-zero entry"; + ASSERT_EQ(structural_first_row, scanned_first_row) + << "lagrange_first position doesn't match z_perm shiftable structure"; + + const size_t first_row = scanned_first_row; + + // Expand to full polynomials so we can write at index 0 + polynomials.z_perm = polynomials.z_perm.full(); + polynomials.z_perm_shift = polynomials.z_perm_shift.full(); + + ASSERT_EQ(polynomials.z_perm[first_row], FF(0)); + + // Tamper: set z_perm to non-zero where lagrange_first is active + polynomials.z_perm.at(first_row) = FF(1); + + auto failures = RelationChecker::check>( + polynomials, params, "ECCVMSetRelation - After setting z_perm != 0 at lagrange_first"); + EXPECT_FALSE(failures.empty()) << "Set relation should fail after z_perm init corruption"; + EXPECT_TRUE(failures.contains(ECCVMSetRelationImpl::Z_PERM_INIT)) + << "Sub-relation Z_PERM_INIT should catch the corruption"; + EXPECT_EQ(failures.at(ECCVMSetRelationImpl::Z_PERM_INIT), first_row) + << "Failure should be at lagrange_first row"; +} diff --git a/barretenberg/cpp/src/barretenberg/eccvm/precomputed_tables_builder.hpp b/barretenberg/cpp/src/barretenberg/eccvm/precomputed_tables_builder.hpp index 1057d1506af4..fc5ba7341f00 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/precomputed_tables_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/precomputed_tables_builder.hpp @@ -116,7 +116,7 @@ class ECCVMPointTablePrecomputationBuilder { row.pc = entry.pc; if (last_row) { - BB_ASSERT(scalar_sum - entry.wnaf_skew, entry.scalar); + BB_ASSERT_EQ(scalar_sum - entry.wnaf_skew, entry.scalar); } // the last element of the `precomputed_table` field of a `ScalarMul` is the double of the point. row.precompute_double = entry.precomputed_table[bb::eccvm::POINT_TABLE_SIZE]; diff --git a/barretenberg/cpp/src/barretenberg/polynomials/backing_memory.hpp b/barretenberg/cpp/src/barretenberg/polynomials/backing_memory.hpp index 2d9f92713100..36f827664ca8 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/backing_memory.hpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/backing_memory.hpp @@ -159,7 +159,7 @@ template struct BackingMemory { std::string filename = temp_dir / ("poly-mmap-" + std::to_string(getpid()) + "-" + std::to_string(id)); - int fd = open(filename.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0644); + int fd = open(filename.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_EXCL, 0600); if (fd < 0) { current_storage_usage.fetch_sub(required_bytes); return false; @@ -172,7 +172,7 @@ template struct BackingMemory { return false; } - void* addr = mmap(nullptr, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + void* addr = mmap(nullptr, file_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) { close(fd); std::filesystem::remove(filename); diff --git a/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.cpp b/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.cpp index e72d63752dd7..c8ba8a34cb9d 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.cpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.cpp @@ -212,6 +212,9 @@ template Fr compute_sum(const Fr* src, const size_t n) // This function computes the polynomial (x - a)(x - b)(x - c)... given n distinct roots (a, b, c, ...). template void compute_linear_polynomial_product(const Fr* roots, Fr* dest, const size_t n) { + if (n == 0) { + return; + } auto scratch_space_ptr = get_scratch_space(n); auto scratch_space = scratch_space_ptr.get(); diff --git a/barretenberg/cpp/src/barretenberg/polynomials/univariate_coefficient_basis.hpp b/barretenberg/cpp/src/barretenberg/polynomials/univariate_coefficient_basis.hpp index 4f78475368d9..217244046c8e 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/univariate_coefficient_basis.hpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/univariate_coefficient_basis.hpp @@ -43,11 +43,14 @@ template class UnivariateCoef using value_type = Fr; // used to get the type of the elements consistently with std::array /** - * @brief coefficients is a length-3 array with the following representation: + * @brief Storage for polynomial coefficients (always 3 elements for uniform layout). * @details This class represents a polynomial P(X) = a0 + a1.X + a2.X^2 - * We define `coefficients[0] = a0` and `coefficients[1] = a1` - * If LENGTH == 2 AND `has_a0_plus_a1 = true` then `coefficients[2] = a0 + a1` - * If LENGTH == 3 then `coefficients[2] = a2` + * `coefficients[0] = a0`, `coefficients[1] = a1`. + * The meaning of `coefficients[2]` depends on the template parameters: + * - LENGTH == 2 AND has_a0_plus_a1 == true: coefficients[2] = a0 + a1 + * (precomputed for Karatsuba multiplication; NOT a polynomial coefficient) + * - LENGTH == 2 AND has_a0_plus_a1 == false: coefficients[2] is unused + * - LENGTH == 3: coefficients[2] = a2 */ std::array coefficients; diff --git a/barretenberg/cpp/src/barretenberg/relations/PERMUTATION_ARGUMENT_README.md b/barretenberg/cpp/src/barretenberg/relations/PERMUTATION_ARGUMENT_README.md index d659ac3ba1be..e00b162d6a40 100644 --- a/barretenberg/cpp/src/barretenberg/relations/PERMUTATION_ARGUMENT_README.md +++ b/barretenberg/cpp/src/barretenberg/relations/PERMUTATION_ARGUMENT_README.md @@ -87,6 +87,16 @@ $$ This ensures the grand product "closes". +### The Initialization Constraint (Subrelation 2) + +At the first row (where $L_0 = 1$), we require: + +$$ +L_0 \cdot Z_{\text{perm}} = 0 +$$ + +This explicitly enforces $Z_{\text{perm}}(0) = 0$, which is necessary for the grand product to start at $1$ (via the $Z_{\text{perm}} + L_0$ term in the recurrence). + ## The Generalized Permutation Argument: Tags and Multiset Equality The generalized permutation argument extends the basic copy-constraint mechanism to also enforce **multiset equality** between tagged sets of values. diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp index bba0bfa71dda..30486e28c99e 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp @@ -30,12 +30,14 @@ template class ECCVMSetRelationImpl { enum SubrelationIndex : size_t { GRAND_PRODUCT = 0, LEFT_SHIFTABLE = 1, + Z_PERM_INIT = 2, NUM_SUBRELATIONS, }; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ 22, // grand product construction sub-relation - 3 // left-shiftable polynomial sub-relation + 3, // left-shiftable polynomial sub-relation + 3 // z_perm initialization sub-relation }; static_assert(NUM_SUBRELATIONS == SUBRELATION_PARTIAL_LENGTHS.size()); // prover optimization to allow for skipping the computation of sub-relations at certain points in sumcheck. diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation_impl.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation_impl.hpp index 22b8c0a9c903..bbed4bb5457f 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation_impl.hpp @@ -501,5 +501,13 @@ void ECCVMSetRelationImpl::accumulate(ContainerOverSubrelations& accumulator // Contribution (2) std::get(accumulator) += lagrange_last_short * z_perm_shift_short * scaling_factor; + + // Contribution (3): Enforce z_perm starts at 0. The grand product initialization relies on + // z_perm[0] = 0 so that (z_perm + lagrange_first) evaluates to 1 at the first row. + using InitAccumulator = std::tuple_element_t; + using InitView = typename InitAccumulator::View; + const auto& lagrange_first_init = InitView(in.lagrange_first); + const auto& z_perm_init = InitView(in.z_perm); + std::get(accumulator) += lagrange_first_init * z_perm_init * scaling_factor; } } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/permutation_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/permutation_relation.hpp index eee4de6d8c7f..05bdee9e30f1 100644 --- a/barretenberg/cpp/src/barretenberg/relations/permutation_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/permutation_relation.hpp @@ -21,12 +21,15 @@ namespace bb { \left[ (w_1(\vec X) + \sigma_1(\vec X) \cdot \beta + \gamma) \cdot (w_2(\vec X) + \sigma_2(\vec X) \cdot \beta + \gamma) \cdot (w_3(\vec X) + \sigma_3 (\vec X) \cdot \beta + \gamma) \cdot (w_4 (\vec X) + \sigma_4(\vec X) \cdot \beta + \gamma)\right] &\ = 0 \f} and \f{align}{ L_{\text{last}}(\vec X)\cdot Z_{\text{perm, shifted}}(\vec X) = 0 \f} + and \f{align}{ L_{0}(\vec X)\cdot Z_{\text{perm}}(\vec X) = 0 \f} Here, \f$ \vec X = (X_0,\ldots, X_{d-1})\f$, and \f$L_{\text{last}}\f$ is "Lagrange last", i.e., the indicator function on the boolean hypercube which is 1 at the point whose corresponding index is the last row of the circuit where the wire polynomails (`w_l`, `w_r`, `w_o`, and `w_4`) take non-zero values. - + The third sub-relation enforces that \f$Z_{\text{perm}}\f$ is zero at the first row. The grand product + construction relies on this: the term \f$(Z_{\text{perm}} + L_0)\f$ evaluates to \f$1\f$ at the first row only + when \f$Z_{\text{perm}}(0) = 0\f$. * @tparam FF_ * @note `z_perm[1] == 1`. if `idx` is the unique index such that `lagrange_last[idx] == 1`, then `z_perm[y] == 0` for @@ -37,9 +40,10 @@ template class UltraPermutationRelationImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ 6, // grand product construction sub-relation - 3 // left-shiftable polynomial sub-relation + 3, // left-shiftable polynomial sub-relation + 3 // z_perm initialization sub-relation }; /** @@ -199,6 +203,12 @@ template class UltraPermutationRelationImpl { using ShortAccumulator = std::tuple_element_t<1, ContainerOverSubrelations>; std::get<1>(accumulators) += ShortAccumulator((lagrange_last_m * z_perm_shift_m) * scaling_factor); + + // Contribution (3): Enforce z_perm starts at 0. The grand product initialization relies on + // z_perm[0] = 0 so that (z_perm + L_first) evaluates to 1 at the first row. + // Without this constraint, a cheating prover could set z_perm[0] to a non-zero value. + using InitAccumulator = std::tuple_element_t<2, ContainerOverSubrelations>; + std::get<2>(accumulators) += InitAccumulator((lagrange_first_m * z_perm_m) * scaling_factor); }; }; diff --git a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation.hpp index 63661a8861fe..41d8bf4b5d64 100644 --- a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation.hpp @@ -15,9 +15,10 @@ template class TranslatorPermutationRelationImpl { // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 7; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ 7, // grand product construction sub-relation - 3 // left-shiftable polynomial sub-relation + 3, // left-shiftable polynomial sub-relation + 3 // z_perm initialization sub-relation }; /** @@ -86,9 +87,10 @@ template class TranslatorPermutationRelationImpl { /** * @brief Compute contribution of the goblin translator permutation relation for a given edge (internal function) * - * @details There are 2 relations associated with enforcing the set permutation relation - * This file handles the relation that confirms faithful calculation of the grand - * product polynomial Z_perm. + * @details There are 3 sub-relations associated with enforcing the set permutation relation. + * Sub-relation 0 confirms faithful calculation of the grand product polynomial Z_perm. + * Sub-relation 1 enforces Z_perm_shift = 0 at lagrange_last (grand product closure). + * Sub-relation 2 enforces Z_perm = 0 at lagrange_first (grand product initialization). * * C(in(X)...) = * ( z_perm(X) + lagrange_first(X) )*P(X) diff --git a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation_impl.hpp b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation_impl.hpp index 8718091ddca0..2baa7df8bf3e 100644 --- a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation_impl.hpp @@ -12,9 +12,10 @@ namespace bb { /** * @brief Compute contribution of the goblin translator permutation relation for a given edge (internal function) * - * @details There are 2 relations associated with enforcing the set permutation relation - * This file handles the relation that confirms faithful calculation of the grand - * product polynomial Z_perm. + * @details There are 3 sub-relations associated with enforcing the set permutation relation. + * Sub-relation 0 confirms faithful calculation of the grand product polynomial Z_perm. + * Sub-relation 1 enforces Z_perm_shift = 0 at lagrange_last (grand product closure). + * Sub-relation 2 enforces Z_perm = 0 at lagrange_first (grand product initialization). * * C(in(X)...) = * ( z_perm(X) + lagrange_first(X) )*P(X) @@ -70,5 +71,17 @@ void TranslatorPermutationRelationImpl::accumulate(ContainerOverSubrelations // Contribution (2) std::get<1>(accumulators) += (lagrange_last * z_perm_shift) * scaling_factor; }(); + + [&]() { + using Accumulator = std::tuple_element_t<2, ContainerOverSubrelations>; + using View = typename Accumulator::View; + + const auto z_perm = View(in.z_perm); + const auto lagrange_first = View(in.lagrange_first); + + // Contribution (3): Enforce z_perm starts at 0. The grand product initialization relies on + // z_perm[0] = 0 so that (z_perm + lagrange_first) evaluates to 1 at the first row. + std::get<2>(accumulators) += (lagrange_first * z_perm) * scaling_factor; + }(); }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_relation_consistency.test.cpp b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_relation_consistency.test.cpp index 2cdef5a95c7e..452fc82725aa 100644 --- a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_relation_consistency.test.cpp +++ b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_relation_consistency.test.cpp @@ -106,6 +106,10 @@ TEST_F(TranslatorRelationConsistency, PermutationRelation) auto contribution_2 = z_perm_shift * lagrange_last; expected_values[1] = contribution_2; + // (Contribution 3) + auto contribution_3 = lagrange_first * z_perm; + expected_values[2] = contribution_3; + validate_relation_execution(expected_values, input_elements, parameters); }; run_test(/*random_inputs=*/false); diff --git a/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp b/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp index d1739dc43d6f..57b606e70123 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp +++ b/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp @@ -225,6 +225,10 @@ TEST_F(UltraRelationConsistency, UltraPermutationRelation) auto contribution_2 = z_perm_shift * lagrange_last; expected_values[1] = contribution_2; + // Contribution 3 + auto contribution_3 = lagrange_first * z_perm; + expected_values[2] = contribution_3; + validate_relation_execution(expected_values, input_elements, parameters); }; run_test(/*random_inputs=*/false); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp b/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp index c5d9190c810a..b3a18f9db4ef 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa_impl.hpp @@ -134,7 +134,8 @@ bool_t ecdsa_verify_signature(const stdlib::byte_array& hashed if ((corrected_public_key.get_value().x == Curve::GroupNative::affine_one.x) && (!builder->failed())) { builder->failure("ECDSA input validation: the public key is equal to plus or minus the generator point."); } - result = G1::batch_mul({ G1::one(builder), corrected_public_key }, { u1, u2 }); + result = G1::batch_mul( + { G1::one(builder), corrected_public_key }, { u1, u2 }, /*max_num_bits=*/0, /*with_edgecases=*/false); } // Step 7. diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp index 991a13e2945a..b488aada59d6 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp @@ -1472,6 +1472,57 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result, true); } + // Test byte_array constructor with boundary values: 0, 1, p-1, and values >= p. + static void test_byte_array_constructor_boundary_values() + { + // Helper: convert a uint256_t to a 32-byte big-endian vector (same layout as fq_native::serialize_to_buffer) + const auto to_bytes = [](uint256_t v) { + std::vector buf(32, 0); + for (int i = 31; i >= 0; --i) { + buf[static_cast(i)] = static_cast(v.data[0] & 0xff); + v >>= 8; + } + return buf; + }; + + const uint256_t p = fq_ct::modulus; + + struct TestCase { + uint256_t value; + bool expect_less_than_p; // whether value < p + }; + + // Boundary values: 0, 1, p-1 (all valid); p (invalid — equals modulus) + // Nibble-boundary values: 0x0f...f (all low nibbles set), 0x10...0 (carry into high nibble) + const std::vector cases = { + { uint256_t(0), true }, + { uint256_t(1), true }, + { p - 1, true }, + // Nibble boundary: value whose split byte is 0x0f (lo nibble=0xf, hi nibble=0) + { uint256_t(0x0f) << (7 * 8), true }, // byte 7 from the right = overlap byte for limb0/limb1 + // Nibble boundary: value whose split byte is 0xf0 (lo nibble=0, hi nibble=0xf) + { uint256_t(0xf0) << (7 * 8), true }, + // p itself — a bigfield constructed from p bytes will have value == p, which is >= p + { p, false }, + }; + + for (const auto& tc : cases) { + auto builder = Builder(); + byte_array_ct arr(&builder, to_bytes(tc.value)); + fq_ct el(arr); + + // Check that the reconstructed value matches + EXPECT_EQ(el.get_value().lo, tc.value); + + // Verify is_less_than agrees with our expectation + auto cmp = el.is_less_than(p); + cmp.assert_equal(stdlib::bool_t(tc.expect_less_than_p)); + + EXPECT_TRUE(CircuitChecker::check(builder)); + EXPECT_FALSE(builder.failed()); + } + } + // This check tests if elements are reduced to fit quotient into range proof static void test_quotient_completeness() { @@ -2508,6 +2559,10 @@ TYPED_TEST(stdlib_bigfield, byte_array_constructors) { TestFixture::test_byte_array_constructors(); } +TYPED_TEST(stdlib_bigfield, byte_array_constructor_boundary_values) +{ + TestFixture::test_byte_array_constructor_boundary_values(); +} TYPED_TEST(stdlib_bigfield, quotient_completeness_regression) { TestFixture::test_quotient_completeness(); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp index 73f910b64290..cb5ee16bb524 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp @@ -70,7 +70,6 @@ bigfield::bigfield(const field_t& low_bits_in, decompose_non_native_field_double_width_limb(context, low_bits_in.get_witness_index()); limb_0.witness_index = limb_witnesses[0]; limb_1.witness_index = limb_witnesses[1]; - field_t::evaluate_linear_identity(low_bits_in, -limb_0, -limb_1 * shift_1, field_t(0)); } else { uint256_t slice_0 = uint256_t(low_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); uint256_t slice_1 = uint256_t(low_bits_in.additive_constant).slice(NUM_LIMB_BITS, 2 * NUM_LIMB_BITS); @@ -97,7 +96,6 @@ bigfield::bigfield(const field_t& low_bits_in, context, high_bits_in.get_witness_index(), static_cast(num_high_limb_bits)); limb_2.witness_index = limb_witnesses[0]; limb_3.witness_index = limb_witnesses[1]; - field_t::evaluate_linear_identity(high_bits_in, -limb_2, -limb_3 * shift_1, field_t(0)); } else { uint256_t slice_2 = uint256_t(high_bits_in.additive_constant).slice(0, NUM_LIMB_BITS); uint256_t slice_3 = uint256_t(high_bits_in.additive_constant).slice(NUM_LIMB_BITS, num_high_limb_bits); @@ -2263,13 +2261,6 @@ void bigfield::unsafe_evaluate_multiply_add(const bigfield& input_le uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); - if (max_lo_bits < (2 * NUM_LIMB_BITS)) { - carry_lo_msb = 0; - } - if (max_hi_bits < (2 * NUM_LIMB_BITS)) { - carry_hi_msb = 0; - } - // The custom bigfield multiplication gate requires inputs are witnesses. // If we're using constant values, instantiate them as circuit variables // @@ -2717,13 +2708,6 @@ void bigfield::unsafe_evaluate_multiple_multiply_add(const std::vect uint64_t carry_lo_msb = max_lo_bits - (2 * NUM_LIMB_BITS); uint64_t carry_hi_msb = max_hi_bits - (2 * NUM_LIMB_BITS); - if (max_lo_bits < (2 * NUM_LIMB_BITS)) { - carry_lo_msb = 0; - } - if (max_hi_bits < (2 * NUM_LIMB_BITS)) { - carry_hi_msb = 0; - } - // if both the hi and lo output limbs have less than 70 bits, we can use our custom // limb accumulation gate (accumulates 2 field elements, each composed of 5 14-bit limbs, in 3 gates) if (carry_lo_msb <= 70 && carry_hi_msb <= 70) { @@ -2863,9 +2847,7 @@ std::pair bigfield::compute_partial_schoolbook /** * @brief Decompose a single witness into two limbs, range constrained to NUM_LIMB_BITS (68) and - * num_limb_bits - NUM_LIMB_BITS, respectively. - * - * @details Doesn't create gates constraining the limbs to each other. + * num_limb_bits - NUM_LIMB_BITS, respectively, and constrain low + hi * 2^NUM_LIMB_BITS == original. * * @param ctx The circuit context * @param limb_idx The index of the limb that will be decomposed @@ -2893,6 +2875,12 @@ std::array bigfield::decompose_non_native_field_double_ ctx->range_constrain_two_limbs( low_idx, hi_idx, lo_bits, hi_bits, "decompose_non_native_field_double_width_limb: limbs too large"); + // Constrain: original == low + hi * 2^NUM_LIMB_BITS + field_t original = field_t::from_witness_index(ctx, limb_idx); + field_t lo_field = field_t::from_witness_index(ctx, low_idx); + field_t hi_field = field_t::from_witness_index(ctx, hi_idx); + field_t::evaluate_linear_identity(original, -lo_field, -hi_field * shift_1, field_t(0)); + return std::array{ low_idx, hi_idx }; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp index 7011c5026541..29beed45d588 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp @@ -358,7 +358,7 @@ template class element { static element batch_mul(const std::vector& points, const std::vector& scalars, const size_t max_num_bits = 0, - const bool with_edgecases = false); + const bool with_edgecases = true); template ::value>> static element secp256k1_ecdsa_mul(const element& pubkey, const Fr& u1, const Fr& u2); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp index 21925abf6586..38f6989ff73f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp @@ -1386,12 +1386,11 @@ template class stdlib_biggroup : public testing::Test { points.emplace_back(point); } - // If with_edgecases = true, should handle linearly dependent points correctly + // Since with_edgecases = true by default, should handle linearly dependent points correctly // (offset generator is now a free witness sampled inside batch_mul) element_ct c = element_ct::batch_mul(points, scalars, - /*max_num_bits*/ 128, - /*with_edgecases*/ true); + /*max_num_bits*/ 128); element input_e = (element(input_P_a) * scalar_a); element input_f = (element(input_P_b) * scalar_b); element input_g = (element(input_P_c) * scalar_c); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_impl.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_impl.hpp index 8dd2addc79af..229f34f60f9b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_impl.hpp @@ -1099,7 +1099,7 @@ element element::batch_mul_internal(const std::vecto * @param _points * @param _scalars * @param max_num_bits The max of the bit lengths of the scalars. - * @param with_edgecases Use when points are linearly dependent. Randomises them. + * @param with_edgecases Use when points are linearly dependent. Randomises them. Set to true by default. * @return element (canonical form) */ template diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.cpp index 850ab550ad94..549b1383c97d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.cpp @@ -36,6 +36,12 @@ void databus::bus_vector::set_values(const std::vector& entri context->append_to_bus_vector(bus_idx, entries.back().get_witness_index()); } length = entries.size(); + + // Preserve tags to restore them in future reads (following the ROM/RAM pattern) + _tags.resize(entries_in.size()); + for (size_t i = 0; i < length; ++i) { + _tags[i] = entries_in[i].get_origin_tag(); + } } template @@ -45,7 +51,9 @@ field_t databus::bus_vector::operator[](const field_pt& index) // Ensure the read is valid auto raw_index = static_cast(uint256_t(index.get_value()).data[0]); if (raw_index >= length) { + // Set a failure when the index is out of bounds. Return early to avoid OOB vector access. context->failure("bus_vector: access out of bounds"); + return field_pt::from_witness_index(context, context->zero_idx()); } // The read index must be a witness; if constant, add it as a constant variable @@ -58,7 +66,13 @@ field_t databus::bus_vector::operator[](const field_pt& index) // Read from the bus vector at the specified index. Creates a single read gate uint32_t output_idx = context->read_bus_vector(bus_idx, index_witness_idx); - return field_pt::from_witness_index(context, output_idx); + auto result = field_pt::from_witness_index(context, output_idx); + + // If the index is legitimate, restore the tag (following the ROM/RAM pattern) + if (raw_index < length) { + result.set_origin_tag(_tags[raw_index]); + } + return result; } template class databus; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.hpp index d3ce5fa20593..92e6f3bdaa32 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/databus/databus.hpp @@ -52,6 +52,7 @@ template class databus { private: mutable std::vector entries; // bus vector entries + std::vector _tags; // origin tags for each entry (restored on read) size_t length = 0; BusId bus_idx; // Idx of column in bus mutable Builder* context = nullptr; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp index fa25cca7e73e..dc2890ee1bcf 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp @@ -565,6 +565,7 @@ template class field_t { bool predicate_witness = uint256_t(a.get_value()) < uint256_t(b.get_value()); bool_t predicate(witness_t(ctx, predicate_witness)); + predicate.set_origin_tag(OriginTag(a.get_origin_tag(), b.get_origin_tag())); field_t predicate_valid = b.add_two(-(a) + range_constant - 1, -field_t(predicate) * range_constant); predicate_valid.create_range_constraint(num_bits); return predicate; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp index 0c93fd4d2b99..2d4a13800a60 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp @@ -1435,6 +1435,14 @@ template class stdlib_field : public testing::Test { #ifndef NDEBUG EXPECT_THROW(q + q, std::runtime_error); #endif + + // ranged_less_than: check tag behavior + auto rlt_a = field_ct(witness_ct(&builder, uint256_t(50))); + auto rlt_b = field_ct(witness_ct(&builder, uint256_t(100))); + rlt_a.set_origin_tag(submitted_value_origin_tag); + rlt_b.set_origin_tag(challenge_origin_tag); + auto rlt_result = rlt_a.template ranged_less_than<8>(rlt_b); + EXPECT_EQ(rlt_result.get_origin_tag(), first_two_merged_tag); } void test_validate_context() diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.hpp index dd9d274508c7..6ae8a9f9d44c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.hpp @@ -54,7 +54,9 @@ template class StdlibCodec { // All challenges must be circuit witnesses. BB_ASSERT(builder); BB_ASSERT(!challenge.is_constant()); - return T(challenge, fr::from_witness_index(builder, builder->zero_idx())); + auto high_limb = fr::from_witness_index(builder, builder->zero_idx()); + high_limb.set_origin_tag(challenge.get_origin_tag()); + return T(challenge, high_limb); } } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_utils.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_utils.cpp index 6a2fd44efb88..eaacec72c803 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_utils.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_utils.cpp @@ -22,6 +22,11 @@ void validate_split_in_field_unsafe(const field_t& lo, const uint256_t r_lo = field_modulus.slice(0, lo_bits); const uint256_t r_hi = field_modulus.slice(lo_bits, field_modulus.get_msb() + 1); + // Precondition: r_lo must be nonzero. If r_lo == 0, the borrow logic below breaks. + // The fields of our concern (bn254 Fr/Fq, secp256k1 Fq) have nonzero low bits, so this + // precondition holds for all current uses. + BB_ASSERT(r_lo != 0, "validate_split_in_field_unsafe: low bits of modulus are zero, borrow logic is unsound"); + // Algorithm: Validate lo + hi * 2^lo_bits < field_modulus using borrow logic // // We want: value < modulus, i.e., value <= modulus - 1 diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_utils.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_utils.hpp index 3ee78cca7048..1c327f0f0888 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_utils.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_utils.hpp @@ -43,6 +43,9 @@ std::pair, field_t> split_unique(const field_t logic::create_logic_constraint( Builder* ctx = b.get_context(); uint256_t a_native(a.get_value()); field_pt a_witness = field_pt::from_witness_index(ctx, ctx->put_constant_variable(a_native)); + a_witness.set_origin_tag(a.get_origin_tag()); return create_logic_constraint(a_witness, b, num_bits, is_xor_gate, get_chunk); } @@ -65,10 +66,11 @@ field_t logic::create_logic_constraint( Builder* ctx = a.get_context(); uint256_t b_native(b.get_value()); field_pt b_witness = field_pt::from_witness_index(ctx, ctx->put_constant_variable(b_native)); + b_witness.set_origin_tag(b.get_origin_tag()); return create_logic_constraint(a, b_witness, num_bits, is_xor_gate, get_chunk); } - Builder* ctx = a.get_context(); + Builder* ctx = validate_context(a.get_context(), b.get_context()); // We slice the input values into 32-bit chunks, and then use a multi-table lookup to compute the AND or XOR // of each chunk. Since we perform the lookup from 32-bit multi-tables, the lookup operation implicitly enforces a @@ -111,6 +113,7 @@ field_t logic::create_logic_constraint( a.assert_equal(a_accumulator, "stdlib logic: failed to reconstruct left operand"); b.assert_equal(b_accumulator, "stdlib logic: failed to reconstruct right operand"); + res.set_origin_tag(OriginTag(a.get_origin_tag(), b.get_origin_tag())); return res; } template class logic; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.test.cpp index e7d4dd568300..6d8bb4e2a923 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.test.cpp @@ -143,3 +143,101 @@ TYPED_TEST(LogicTest, DifferentWitnessSameResult) bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } + +TYPED_TEST(LogicTest, OriginTagConsistency) +{ + STDLIB_TYPE_ALIASES + auto builder = Builder(); + + const size_t parent_id = 0; + const auto tag_a = OriginTag(parent_id, /*round_id=*/0, /*is_submitted=*/true); + const auto tag_b = OriginTag(parent_id, /*round_id=*/0, /*is_submitted=*/false); + const auto merged_tag = OriginTag(tag_a, tag_b); + + uint256_t a_val = 0x0f; + uint256_t b_val = 0xa3; + + // Witness-witness path + field_ct x = witness_ct(&builder, a_val); + field_ct y = witness_ct(&builder, b_val); + x.set_origin_tag(tag_a); + y.set_origin_tag(tag_b); + field_ct and_result = stdlib::logic::create_logic_constraint(x, y, 8, false); + EXPECT_EQ(and_result.get_origin_tag(), merged_tag); + + field_ct xor_result = stdlib::logic::create_logic_constraint(x, y, 8, true); + EXPECT_EQ(xor_result.get_origin_tag(), merged_tag); + + // Constant-witness path (left constant) + field_ct x_const(&builder, a_val); + x_const.set_origin_tag(tag_a); + field_ct and_result_lc = stdlib::logic::create_logic_constraint(x_const, y, 8, false); + EXPECT_EQ(and_result_lc.get_origin_tag(), merged_tag); + + // Constant-witness path (right constant) + field_ct y_const(&builder, b_val); + y_const.set_origin_tag(tag_b); + field_ct and_result_rc = stdlib::logic::create_logic_constraint(x, y_const, 8, false); + EXPECT_EQ(and_result_rc.get_origin_tag(), merged_tag); +} + +// Regression test: OriginTag must propagate through all logic constraint paths. +TYPED_TEST(LogicTest, OriginTagPropagation) +{ + STDLIB_TYPE_ALIASES + STANDARD_TESTING_TAGS + + auto builder = Builder(); + uint256_t a_val = 0xAB; + uint256_t b_val = 0xCD; + + // Both witnesses + { + field_ct x = witness_ct(&builder, a_val); + field_ct y = witness_ct(&builder, b_val); + x.set_origin_tag(submitted_value_origin_tag); + y.set_origin_tag(challenge_origin_tag); + + field_ct and_result = stdlib::logic::create_logic_constraint(x, y, 8, false); + field_ct xor_result = stdlib::logic::create_logic_constraint(x, y, 8, true); + + EXPECT_EQ(and_result.get_origin_tag(), first_two_merged_tag); + EXPECT_EQ(xor_result.get_origin_tag(), first_two_merged_tag); + } + + // Left constant, right witness + { + field_ct x_const(&builder, a_val); + field_ct y = witness_ct(&builder, b_val); + x_const.set_origin_tag(submitted_value_origin_tag); + y.set_origin_tag(challenge_origin_tag); + + field_ct result = stdlib::logic::create_logic_constraint(x_const, y, 8, false); + EXPECT_EQ(result.get_origin_tag(), first_two_merged_tag); + } + + // Right constant, left witness + { + field_ct x = witness_ct(&builder, a_val); + field_ct y_const(&builder, b_val); + x.set_origin_tag(submitted_value_origin_tag); + y_const.set_origin_tag(challenge_origin_tag); + + field_ct result = stdlib::logic::create_logic_constraint(x, y_const, 8, false); + EXPECT_EQ(result.get_origin_tag(), first_two_merged_tag); + } + + // Both constants + { + field_ct x_const(&builder, a_val); + field_ct y_const(&builder, b_val); + x_const.set_origin_tag(submitted_value_origin_tag); + y_const.set_origin_tag(challenge_origin_tag); + + field_ct result = stdlib::logic::create_logic_constraint(x_const, y_const, 8, false); + EXPECT_EQ(result.get_origin_tag(), first_two_merged_tag); + } + + bool result = CircuitChecker::check(builder); + EXPECT_EQ(result, true); +} diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/ram_table.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/ram_table.cpp index 1c6d3e403fc8..9d1a29e7103b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/ram_table.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/ram_table.cpp @@ -180,9 +180,9 @@ template field_t ram_table::read(const fiel const auto native_index = uint256_t(index.get_value()); if (native_index >= length) { - // set a failure when the index is out of bounds. another error will be thrown when we try to call - // `read_RAM_array`. + // Set a failure when the index is out of bounds. Return early to avoid OOB vector access. context->failure("ram_table: RAM array access out of bounds"); + return field_pt::from_witness_index(context, context->zero_idx()); } if (!check_indices_initialized()) { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/rom_table.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/rom_table.cpp index e6fbf9a5486c..6efe0cb06a56 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/rom_table.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/rom_table.cpp @@ -178,7 +178,9 @@ template field_t rom_table::operator[](cons const auto native_index = uint256_t(index.get_value()); if (native_index >= length) { + // Set a failure when the index is out of bounds. Return early to avoid OOB vector access. context->failure("rom_table: ROM array access out of bounds"); + return field_pt::from_witness_index(context, context->zero_idx()); } uint32_t output_idx = context->read_ROM_array(rom_id, index.get_witness_index()); @@ -188,7 +190,6 @@ template field_t rom_table::operator[](cons // If the index is legitimate, restore the tag if (native_index < length) { - element.set_origin_tag(_tags[cast_index]); } return element; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/rom_table.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/rom_table.test.cpp index 30fcebc646d7..f42d8900f89d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/rom_table.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/rom_table.test.cpp @@ -167,3 +167,28 @@ TEST(RomTable, OobConstantIndexDoesNotCrashRegression) EXPECT_TRUE(builder.failed()); } + +/** + * @brief Regression: OOB witness-index read must soft-fail without OOB vector access. + */ +TEST(RomTable, OobWitnessIndexDoesNotCrashRegression) +{ + using Builder = UltraCircuitBuilder; + using field_ct = stdlib::field_t; + using witness_ct = stdlib::witness_t; + using rom_table_ct = stdlib::rom_table; + + Builder builder; + + std::vector table_values; + table_values.emplace_back(witness_ct(&builder, bb::fr(1))); + table_values.emplace_back(witness_ct(&builder, bb::fr(2))); + table_values.emplace_back(witness_ct(&builder, bb::fr(3))); + rom_table_ct table(table_values); + + // OOB witness index — should soft-fail, not crash + field_ct oob_index = witness_ct(&builder, bb::fr(100000000)); + table[oob_index]; + + EXPECT_TRUE(builder.failed()); +} diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/twin_rom_table.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/twin_rom_table.cpp index 6788a77a3252..57c783c8ba59 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/twin_rom_table.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/twin_rom_table.cpp @@ -150,7 +150,10 @@ std::array, 2> twin_rom_table::operator[](const field_ initialize_table(); if (uint256_t(index.get_value()) >= length) { + // Set a failure when the index is out of bounds. Return early to avoid OOB vector access. context->failure("twin_rom_table: ROM array access out of bounds"); + return { field_pt::from_witness_index(context, context->zero_idx()), + field_pt::from_witness_index(context, context->zero_idx()) }; } auto output_indices = context->read_ROM_array_pair(rom_id, index.get_witness_index()); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.cpp index 057e9f056e9e..22d6781a251f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.cpp @@ -54,6 +54,7 @@ plookup::ReadData> plookup_read::get_lookup_accumulato const auto accumulator_witnesses = ctx->create_gates_from_plookup_accumulators(id, lookup_data, lhs_index, key_b_witness); + const auto merged_tag = OriginTag(key_a.get_origin_tag(), key_b.get_origin_tag()); for (size_t i = 0; i < lookup_data[ColumnIdx::C1].size(); ++i) { lookup[ColumnIdx::C1].emplace_back( field_t::from_witness_index(ctx, accumulator_witnesses[ColumnIdx::C1][i])); @@ -61,6 +62,9 @@ plookup::ReadData> plookup_read::get_lookup_accumulato field_t::from_witness_index(ctx, accumulator_witnesses[ColumnIdx::C2][i])); lookup[ColumnIdx::C3].emplace_back( field_t::from_witness_index(ctx, accumulator_witnesses[ColumnIdx::C3][i])); + lookup[ColumnIdx::C1].back().set_origin_tag(merged_tag); + lookup[ColumnIdx::C2].back().set_origin_tag(merged_tag); + lookup[ColumnIdx::C3].back().set_origin_tag(merged_tag); } } return lookup; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp index 607a0d868c6f..2bea47b140da 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp @@ -151,7 +151,7 @@ template struct ZKSumcheckData { } total_sum *= scaling_factor; - return { total_sum + constant_term * (static_cast(1) << libra_univariates.size()), scaling_factor }; + return { total_sum + constant_term * (1UL << libra_univariates.size()), scaling_factor }; } /** diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/RELATIONS.md b/barretenberg/cpp/src/barretenberg/translator_vm/RELATIONS.md index f3f296895525..cad508b38258 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/RELATIONS.md +++ b/barretenberg/cpp/src/barretenberg/translator_vm/RELATIONS.md @@ -439,10 +439,11 @@ The Permutation Relation is the foundation of all range constraints in the Trans If the two multisets are equal (i.e., one is a permutation of the other), then all values are valid. -The relation consists of 2 subrelations: +The relation consists of 3 subrelations: 1. Grand product identity (degree 7) 2. Finalization check (degree 3) +3. Initialization check (degree 3) #### Interaction with the Delta Range Constraints @@ -482,11 +483,9 @@ $$\boxed{\left( z_{\text{perm}} + L_{\text{first}} \right) \cdot \prod_{j=0}^{3} where: -- $L_{\text{first}}$: Lagrange polynomial for first row ($z_{\text{perm}}[0] = 0$ is enforced implicitly) +- $L_{\text{first}}$: Lagrange polynomial for first row ($z_{\text{perm}}[0] = 0$ is enforced by subrelation 3) - $L_{\text{last}}$: Lagrange polynomial for last row (we enforce $z_{\text{perm}}[\text{last}] = 0$ in subrelation 2) - $z_{\text{perm}}^{\text{shift}}$: Shifted grand product polynomial ($z_{\text{perm}}[i+1]$) - -Note that $z_{\text{perm}}[0] = 0$ follows implicitly from the fact that we are opening $z_{\text{perm}}$ and $z_{\text{perm}}^{\text{shift}}$ both at the same challenge. If the two multisets are equal: 1. At each step, the products telescope: contributions cancel out @@ -515,6 +514,24 @@ Active when: Last row only ($L_{\text{last}} = 1$) Degree: 2 (Lagrange × shifted polynomial) +--- + +### Subrelation 3: Initialization Check + +Purpose: Ensure the grand product polynomial starts at zero. + +$$\boxed{L_{\text{first}} \cdot z_{\text{perm}} = 0}$$ + +Interpretation: + +- At the first row, $L_{\text{first}} = 1$ +- $z_{\text{perm}}$ must be 0 at this row +- This is necessary for the $(z_{\text{perm}} + L_{\text{first}})$ term in subrelation 1 to evaluate to 1 + +Active when: First row only ($L_{\text{first}} = 1$) + +Degree: 2 (Lagrange × polynomial) + ## Delta Range Constraint Relation The Delta Range Constraint Relation works in tandem with the Permutation Relation to prove that the ordered (sorted) multiset is actually sorted and bounded correctly. diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/relation_failure.test.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/relation_failure.test.cpp index f0fedbe501d4..a26cf86e6c4e 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/relation_failure.test.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/relation_failure.test.cpp @@ -267,6 +267,64 @@ TEST_F(TranslatorRelationFailureTests, PermutationFailsOnZPermCorruption) EXPECT_FALSE(failures.empty()) << "Permutation should fail after z_perm corruption"; } +/** + * @brief Test that z_perm must be zero at the lagrange_first row. + * + * @details The permutation grand product relies on z_perm[0] = 0 so that (z_perm + lagrange_first) + * evaluates to 1 at the first row. Sub-relation 2 (lagrange_first * z_perm = 0) enforces this. + * + * We cross-check the lagrange_first position two ways: + * 1. Structurally: z_perm.start_index() - 1 (the zero row before the shiftable region) + * 2. By scanning the lagrange_first polynomial for its non-zero entry + */ +TEST_F(TranslatorRelationFailureTests, PermutationFailsOnZPermNonZeroAtFirstRow) +{ + auto [key, params] = build_valid_translator_state(); + auto& pp = key.proving_key->polynomials; + + // Baseline: permutation relation passes + auto baseline = + RelationChecker::check>(pp, params, "TranslatorPermutationRelation"); + EXPECT_TRUE(baseline.empty()) << "Baseline permutation should pass"; + + // Derive expected lagrange_first position from z_perm shiftable structure + ASSERT_TRUE(pp.z_perm.is_shiftable()); + size_t structural_first_row = pp.z_perm.start_index() - 1; + + // Independently scan lagrange_first for its non-zero entry + const auto& lagrange_first = pp.lagrange_first; + size_t scanned_first_row = 0; + bool found = false; + for (size_t i = lagrange_first.start_index(); i < lagrange_first.end_index(); ++i) { + if (lagrange_first[i] != FF(0)) { + scanned_first_row = i; + found = true; + break; + } + } + ASSERT_TRUE(found) << "lagrange_first has no non-zero entry"; + ASSERT_EQ(structural_first_row, scanned_first_row) + << "lagrange_first position doesn't match z_perm shiftable structure"; + + const size_t first_row = scanned_first_row; + + // Expand to full polynomials so we can write at the zero row + pp.z_perm = pp.z_perm.full(); + pp.z_perm_shift = pp.z_perm_shift.full(); + + ASSERT_EQ(pp.z_perm[first_row], FF(0)); + + // Tamper: set z_perm to non-zero where lagrange_first is active + pp.z_perm.at(first_row) = FF(1); + + auto failures = RelationChecker::check>( + pp, params, "TranslatorPermutationRelation - After setting z_perm != 0 at lagrange_first"); + EXPECT_FALSE(failures.empty()) << "Permutation should fail after z_perm init corruption"; + // Sub-relation 2 (lagrange_first * z_perm = 0) should catch this + EXPECT_TRUE(failures.contains(2)) << "Sub-relation 2 (z_perm init) should catch the corruption"; + EXPECT_EQ(failures.at(2), static_cast(first_row)) << "Failure should be at lagrange_first row"; +} + /** * @brief Corrupt ordered poly at position circuit_size - MAX_RANDOM - 2, the last row where the delta * constraint is enforced. This is right before lagrange_real_last + lagrange_ordered_masking kicks in. diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator.test.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator.test.cpp index 99a1c980722b..460167dec556 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator.test.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator.test.cpp @@ -517,6 +517,60 @@ TEST_F(TranslatorTests, EvaluationPartition) * @details Start from all-zeros, call set_minicircuit_evaluations + complete_full_circuit_evaluations * with random inputs, and check that no entity remains zero (with overwhelming probability). */ +/** + * @brief Verify that REPEATED_COMMITMENTS indices correctly pair to-be-shifted and shifted commitments. + * @details The Translator has two duplicate ranges and uses get_pcs_unshifted()/get_pcs_to_be_shifted() + * instead of the standard get_unshifted()/get_to_be_shifted(). This test commits to all PCS-level polynomials + * and verifies the commitments at original and duplicate positions match. + */ +TEST_F(TranslatorTests, RepeatedCommitmentsIndicesCorrect) +{ + using Flavor = TranslatorFlavor; + using Commitment = Flavor::Commitment; + + fq batching_challenge_v = fq::random_element(); + fq evaluation_challenge_x = fq::random_element(); + CircuitBuilder circuit_builder = generate_test_circuit(batching_challenge_v, evaluation_challenge_x); + auto pk = std::make_shared(circuit_builder); + + pk->proving_key->commitment_key = Flavor::CommitmentKey(pk->proving_key->circuit_size); + + auto pcs_unshifted = pk->proving_key->polynomials.get_pcs_unshifted(); + auto pcs_to_be_shifted = pk->proving_key->polynomials.get_pcs_to_be_shifted(); + + // Commit to all PCS polynomials + const auto& ck = pk->proving_key->commitment_key; + std::vector unshifted_comms; + for (auto& poly : pcs_unshifted) { + unshifted_comms.push_back(ck.commit(poly)); + } + std::vector shifted_comms; + for (auto& poly : pcs_to_be_shifted) { + shifted_comms.push_back(ck.commit(poly)); + } + + // Build the commitment vector exactly as Shplemini does: [Q, pcs_unshifted..., pcs_to_be_shifted...] + std::vector commitments; + commitments.push_back(Commitment::one()); // dummy Q + commitments.insert(commitments.end(), unshifted_comms.begin(), unshifted_comms.end()); + commitments.insert(commitments.end(), shifted_comms.begin(), shifted_comms.end()); + + constexpr auto repeated = Flavor::REPEATED_COMMITMENTS; + // Same offset logic as remove_repeated_commitments + constexpr size_t offset = Flavor::HasZK ? 2 : 1; + + // Verify both ranges using the same indexing as remove_repeated_commitments + auto check_range = [&](const auto& range, const std::string& label) { + for (size_t i = 0; i < range.count; i++) { + EXPECT_EQ(commitments[range.original_start + offset + i], commitments[range.duplicate_start + offset + i]) + << label << " commitment mismatch at index " << i; + } + }; + + check_range(repeated.first, "Range 1"); + check_range(repeated.second, "Range 2"); +} + TEST_F(TranslatorTests, VerifierPopulatesAllEntities) { using Flavor = TranslatorFlavor; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp index 3c9b29be4d25..e924778a594c 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/mega_honk.test.cpp @@ -336,3 +336,46 @@ TYPED_TEST(MegaHonkTests, MaskingTailCommitments) } } } + +/** + * @brief Verify that REPEATED_COMMITMENTS indices correctly pair to-be-shifted and shifted commitments. + * @details Mirrors the Shplemini vector construction: [Q, unshifted..., to_be_shifted...] with + * offset = HasZK ? 2 : 1, then checks the same index pairs that remove_repeated_commitments asserts. + */ +TYPED_TEST(MegaHonkTests, RepeatedCommitmentsIndicesCorrect) +{ + using Flavor = TypeParam; + using Builder = typename Flavor::CircuitBuilder; + using DefaultIO = stdlib::recursion::honk::DefaultIO; + using CommitmentKey = typename Flavor::CommitmentKey; + using Commitment = typename Flavor::Commitment; + + auto builder = Builder{}; + DefaultIO::add_default(builder); + auto prover_instance = std::make_shared>(builder); + CommitmentKey ck(prover_instance->dyadic_size()); + + auto unshifted = prover_instance->polynomials.get_unshifted(); + auto to_be_shifted = prover_instance->polynomials.get_to_be_shifted(); + + constexpr auto repeated = Flavor::REPEATED_COMMITMENTS; + ASSERT_EQ(to_be_shifted.size(), repeated.first.count); + + // Build the commitment vector exactly as Shplemini does: [Q, unshifted..., to_be_shifted...] + std::vector commitments; + commitments.push_back(Commitment::one()); // dummy Q + for (auto& poly : unshifted) { + commitments.push_back(ck.commit(poly)); + } + for (auto& poly : to_be_shifted) { + commitments.push_back(ck.commit(poly)); + } + + // Same offset logic as remove_repeated_commitments + constexpr size_t offset = Flavor::HasZK ? 2 : 1; + for (size_t i = 0; i < repeated.first.count; i++) { + EXPECT_EQ(commitments[repeated.first.original_start + offset + i], + commitments[repeated.first.duplicate_start + offset + i]) + << "REPEATED_COMMITMENTS commitment mismatch at index " << i; + } +} diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/permutation.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/permutation.test.cpp index 664cbe392c87..59e27d7a1b90 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/permutation.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/permutation.test.cpp @@ -255,6 +255,109 @@ TYPED_TEST(PermutationNonZKTests, ZPermZeroedOutFailure) EXPECT_FALSE(tampered_permutation_relation_failures.empty()); } +/** + * @brief Test that z_perm must be zero at the first row (where lagrange_first = 1). + * + * @details The permutation argument includes an initialization constraint: lagrange_first * z_perm = 0. + * The grand product relies on z_perm[0] = 0 so that (z_perm + lagrange_first) evaluates to 1 at row 0. + * + * This test: + * 1. Builds a valid circuit and verifies the permutation relation holds + * 2. Expands z_perm to a full polynomial to access the boundary at index 0 + * 3. Tampers with z_perm at index 0, making it non-zero + * 4. Verifies the permutation relation now fails (sub-relation 2: lagrange_first * z_perm = 0) + * + * @note This test excludes ZK flavors because we manually tamper with z_perm, which would + * conflict with the ZK masking applied to witness polynomials. + */ +TYPED_TEST(PermutationNonZKTests, ZPermNonZeroAtFirstRowFailure) +{ + using Flavor = TypeParam; + using Builder = typename Flavor::CircuitBuilder; + + using ProverInstance = ProverInstance_; + using VerificationKey = Flavor::VerificationKey; + + using Prover = TestFixture::Prover; + + Builder builder; + + auto a = fr::random_element(); + auto b = fr::random_element(); + auto c = a + b; + + uint32_t a_idx = builder.add_variable(a); + uint32_t a_copy_idx = builder.add_variable(a); + uint32_t b_idx = builder.add_variable(b); + uint32_t c_idx = builder.add_variable(c); + + builder.create_add_gate({ a_idx, b_idx, c_idx, 1, 1, -1, 0 }); + builder.create_add_gate({ a_copy_idx, b_idx, c_idx, 1, 1, -1, 0 }); + builder.assert_equal(a_copy_idx, a_idx); + + TestFixture::set_default_pairing_points_and_ipa_claim_and_proof(builder); + + auto prover_instance = std::make_shared(builder); + auto verification_key = std::make_shared(prover_instance->get_precomputed()); + + Prover prover(prover_instance, verification_key); + auto proof = prover.construct_proof(); + + // Verify the permutation relation holds before tampering. + auto permutation_relation_failures = RelationChecker::template check>( + prover_instance->polynomials, prover_instance->relation_parameters, "UltraPermutation - Before Tampering"); + EXPECT_TRUE(permutation_relation_failures.empty()); + + // Derive the expected lagrange_first position from the z_perm polynomial structure: + // z_perm is shiftable with start_index = NUM_ZERO_ROWS, so the zero row just before it + // is where lagrange_first must be active. Read this before expanding to full. + auto& z_perm = prover_instance->polynomials.z_perm; + auto& z_perm_shift = prover_instance->polynomials.z_perm_shift; + ASSERT_TRUE(z_perm.is_shiftable()); + size_t structural_first_row = z_perm.start_index() - 1; + + // z_perm is shiftable (start_index = 1), so z_perm[0] is a virtual zero not backed by memory. + // To tamper with it, we must expand to a full polynomial. We also expand z_perm_shift independently + // (it cannot be derived via shifted() from a full polynomial with start_index = 0). + prover_instance->polynomials.z_perm = z_perm.full(); + prover_instance->polynomials.z_perm_shift = z_perm_shift.full(); + + // Independently scan the lagrange_first polynomial for its non-zero entry. + const auto& lagrange_first = prover_instance->polynomials.lagrange_first; + size_t scanned_first_row = 0; + bool found = false; + for (size_t i = lagrange_first.start_index(); i < lagrange_first.end_index(); ++i) { + if (lagrange_first[i] != fr(0)) { + scanned_first_row = i; + found = true; + break; + } + } + ASSERT_TRUE(found) << "lagrange_first has no non-zero entry"; + + // Cross-check: both derivations must agree. + ASSERT_EQ(structural_first_row, scanned_first_row) + << "lagrange_first position doesn't match z_perm shiftable structure"; + + const size_t first_row = scanned_first_row; + + // Sanity check: z_perm is currently 0 at the lagrange_first row + ASSERT_EQ(prover_instance->polynomials.z_perm[first_row], fr(0)); + + // Tamper: set z_perm to non-zero where lagrange_first is active + prover_instance->polynomials.z_perm.at(first_row) = fr(1); + + // Verify the permutation relation now fails. + auto tampered_failures = RelationChecker::template check>( + prover_instance->polynomials, + prover_instance->relation_parameters, + "UltraPermutation - After setting z_perm != 0 at lagrange_first"); + EXPECT_FALSE(tampered_failures.empty()); + // Sub-relation 2 (lagrange_first * z_perm = 0) should fail at the lagrange_first row + ASSERT_TRUE(tampered_failures.contains(2)) << "Expected sub-relation 2 (z_perm init) to fail"; + ASSERT_EQ(tampered_failures.at(2), first_row) << "Expected failure at lagrange_first row"; +} + /** * @brief Test that z_perm_shift must be zero at the last row (where lagrange_last = 1). * diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_honk.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_honk.test.cpp index 9841f13f488a..9f2903f835e3 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_honk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_honk.test.cpp @@ -527,3 +527,46 @@ TYPED_TEST(UltraHonkTests, MaskingTailCommitments) } } } + +/** + * @brief Verify that REPEATED_COMMITMENTS indices correctly pair to-be-shifted and shifted commitments. + * @details Mirrors the Shplemini vector construction: [Q, unshifted..., to_be_shifted...] with + * offset = HasZK ? 2 : 1, then checks the same index pairs that remove_repeated_commitments asserts. + */ +TYPED_TEST(UltraHonkTests, RepeatedCommitmentsIndicesCorrect) +{ + using Flavor = TypeParam; + using Builder = typename Flavor::CircuitBuilder; + using IO = typename TestFixture::IO; + using CommitmentKey = typename Flavor::CommitmentKey; + using Commitment = typename Flavor::Commitment; + + auto builder = Builder{}; + IO::add_default(builder); + auto prover_instance = std::make_shared>(builder); + CommitmentKey ck(prover_instance->dyadic_size()); + + auto unshifted = prover_instance->polynomials.get_unshifted(); + auto to_be_shifted = prover_instance->polynomials.get_to_be_shifted(); + + constexpr auto repeated = Flavor::REPEATED_COMMITMENTS; + ASSERT_EQ(to_be_shifted.size(), repeated.first.count); + + // Build the commitment vector exactly as Shplemini does: [Q, unshifted..., to_be_shifted...] + std::vector commitments; + commitments.push_back(Commitment::one()); // dummy Q + for (auto& poly : unshifted) { + commitments.push_back(ck.commit(poly)); + } + for (auto& poly : to_be_shifted) { + commitments.push_back(ck.commit(poly)); + } + + // Same offset logic as remove_repeated_commitments + constexpr size_t offset = Flavor::HasZK ? 2 : 1; + for (size_t i = 0; i < repeated.first.count; i++) { + EXPECT_EQ(commitments[repeated.first.original_start + offset + i], + commitments[repeated.first.duplicate_start + offset + i]) + << "REPEATED_COMMITMENTS commitment mismatch at index " << i; + } +} diff --git a/barretenberg/sol/src/honk/HonkTypes.sol b/barretenberg/sol/src/honk/HonkTypes.sol index 15732484857a..e68c8d048017 100644 --- a/barretenberg/sol/src/honk/HonkTypes.sol +++ b/barretenberg/sol/src/honk/HonkTypes.sol @@ -6,7 +6,7 @@ import {Fr} from "./Fr.sol"; uint256 constant CONST_PROOF_SIZE_LOG_N = 25; -uint256 constant NUMBER_OF_SUBRELATIONS = 28; +uint256 constant NUMBER_OF_SUBRELATIONS = 29; uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8; uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9; uint256 constant NUMBER_OF_ENTITIES = 41; diff --git a/barretenberg/sol/src/honk/Relations.sol b/barretenberg/sol/src/honk/Relations.sol index a0abef6a7144..0f3ec0c6cb60 100644 --- a/barretenberg/sol/src/honk/Relations.sol +++ b/barretenberg/sol/src/honk/Relations.sol @@ -200,6 +200,12 @@ library RelationsLib { Fr acc = (wire(p, WIRE.LAGRANGE_LAST) * wire(p, WIRE.Z_PERM_SHIFT)) * domainSep; evals[3] = acc; } + + // Contribution 4: z_perm initialization check (lagrange_first * z_perm = 0) + { + Fr acc = (wire(p, WIRE.LAGRANGE_FIRST) * wire(p, WIRE.Z_PERM)) * domainSep; + evals[4] = acc; + } } function accumulateLogDerivativeLookupRelation( @@ -249,9 +255,9 @@ library RelationsLib { Fr read_tag_boolean_relation = read_tag * read_tag - read_tag; - evals[4] = accumulatorNone; - evals[5] = accumulatorOne; - evals[6] = read_tag_boolean_relation * domainSep; + evals[5] = accumulatorNone; + evals[6] = accumulatorOne; + evals[7] = read_tag_boolean_relation * domainSep; } function accumulateDeltaRangeRelation( @@ -277,7 +283,7 @@ library RelationsLib { acc = acc * (delta_1 + minus_three); acc = acc * wire(p, WIRE.Q_RANGE); acc = acc * domainSep; - evals[7] = acc; + evals[8] = acc; } // Contribution 7 @@ -288,7 +294,7 @@ library RelationsLib { acc = acc * (delta_2 + minus_three); acc = acc * wire(p, WIRE.Q_RANGE); acc = acc * domainSep; - evals[8] = acc; + evals[9] = acc; } // Contribution 8 @@ -299,7 +305,7 @@ library RelationsLib { acc = acc * (delta_3 + minus_three); acc = acc * wire(p, WIRE.Q_RANGE); acc = acc * domainSep; - evals[9] = acc; + evals[10] = acc; } // Contribution 9 @@ -310,7 +316,7 @@ library RelationsLib { acc = acc * (delta_4 + minus_three); acc = acc * wire(p, WIRE.Q_RANGE); acc = acc * domainSep; - evals[10] = acc; + evals[11] = acc; } } @@ -345,7 +351,7 @@ library RelationsLib { x_add_identity = x_add_identity * x_diff * x_diff; x_add_identity = x_add_identity - y2_sqr - y1_sqr + y1y2 + y1y2; - evals[11] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); + evals[12] = x_add_identity * partialEval * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); } // Contribution 11 point addition, x-coordinate check @@ -354,7 +360,7 @@ library RelationsLib { Fr y1_plus_y3 = ep.y_1 + ep.y_3; Fr y_diff = ep.y_2 * q_sign - ep.y_1; Fr y_add_identity = y1_plus_y3 * x_diff + (ep.x_3 - ep.x_1) * y_diff; - evals[12] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); + evals[13] = y_add_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * (ONE - q_is_double); } // Contribution 10 point doubling, x-coordinate check @@ -370,7 +376,7 @@ library RelationsLib { ep.x_double_identity = (ep.x_3 + ep.x_1 + ep.x_1) * y1_sqr_mul_4 - x1_pow_4_mul_9; Fr acc = ep.x_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; - evals[11] = evals[11] + acc; + evals[12] = evals[12] + acc; } // Contribution 11 point doubling, y-coordinate check @@ -378,7 +384,7 @@ library RelationsLib { { Fr x1_sqr_mul_3 = (ep.x_1 + ep.x_1 + ep.x_1) * ep.x_1; Fr y_double_identity = x1_sqr_mul_3 * (ep.x_1 - ep.x_3) - (ep.y_1 + ep.y_1) * (ep.y_1 + ep.y_3); - evals[12] = evals[12] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; + evals[13] = evals[13] + y_double_identity * domainSep * wire(p, WIRE.Q_ELLIPTIC) * q_is_double; } } @@ -465,9 +471,9 @@ library RelationsLib { ap.adjacent_values_match_if_adjacent_indices_match = (ap.index_delta * MINUS_ONE + ONE) * ap.record_delta; // deg 2 - evals[14] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) + evals[15] = ap.adjacent_values_match_if_adjacent_indices_match * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 - evals[15] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) + evals[16] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 ap.ROM_consistency_check_identity = ap.memory_record_check * (wire(p, WIRE.Q_L) * wire(p, WIRE.Q_R)); // deg 3 or 7 @@ -515,10 +521,10 @@ library RelationsLib { ap.next_gate_access_type * ap.next_gate_access_type - ap.next_gate_access_type; // Putting it all together... - evals[16] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation + evals[17] = ap.adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 5 or 8 - evals[17] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 - evals[18] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 + evals[18] = ap.index_is_monotonically_increasing * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 + evals[19] = ap.next_gate_access_type_is_boolean * (wire(p, WIRE.Q_O)) * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 6 ap.RAM_consistency_check_identity = ap.access_check * (wire(p, WIRE.Q_O)); // deg 3 or 9 @@ -549,7 +555,7 @@ library RelationsLib { // (deg 3 or 9) + (deg 4) + (deg 3) ap.memory_identity = ap.memory_identity * (wire(p, WIRE.Q_MEMORY) * domainSep); // deg 4 or 10 - evals[13] = ap.memory_identity; + evals[14] = ap.memory_identity; } function accumulateNnfRelation( @@ -625,7 +631,7 @@ library RelationsLib { ap.nnf_identity = non_native_field_identity + limb_accumulator_identity; ap.nnf_identity = ap.nnf_identity * (wire(p, WIRE.Q_NNF) * domainSep); - evals[19] = ap.nnf_identity; + evals[20] = ap.nnf_identity; } function accumulatePoseidonExternalRelation( @@ -661,13 +667,13 @@ library RelationsLib { ep.v3 = ep.t2 + ep.v4; // u_1 + 3u_2 + 5u_3 + 7u_4 ep.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_EXTERNAL) * domainSep; - evals[20] = evals[20] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT)); + evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v1 - wire(p, WIRE.W_L_SHIFT)); - evals[21] = evals[21] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT)); + evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.v2 - wire(p, WIRE.W_R_SHIFT)); - evals[22] = evals[22] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT)); + evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.v3 - wire(p, WIRE.W_O_SHIFT)); - evals[23] = evals[23] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT)); + evals[24] = evals[24] + ep.q_pos_by_scaling * (ep.v4 - wire(p, WIRE.W_4_SHIFT)); } function accumulatePoseidonInternalRelation( @@ -699,16 +705,16 @@ library RelationsLib { ip.q_pos_by_scaling = wire(p, WIRE.Q_POSEIDON2_INTERNAL) * domainSep; ip.v1 = ip.u1 * INTERNAL_MATRIX_DIAGONAL[0] + ip.u_sum; - evals[24] = evals[24] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT)); + evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v1 - wire(p, WIRE.W_L_SHIFT)); ip.v2 = ip.u2 * INTERNAL_MATRIX_DIAGONAL[1] + ip.u_sum; - evals[25] = evals[25] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT)); + evals[26] = evals[26] + ip.q_pos_by_scaling * (ip.v2 - wire(p, WIRE.W_R_SHIFT)); ip.v3 = ip.u3 * INTERNAL_MATRIX_DIAGONAL[2] + ip.u_sum; - evals[26] = evals[26] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT)); + evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v3 - wire(p, WIRE.W_O_SHIFT)); ip.v4 = ip.u4 * INTERNAL_MATRIX_DIAGONAL[3] + ip.u_sum; - evals[27] = evals[27] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT)); + evals[28] = evals[28] + ip.q_pos_by_scaling * (ip.v4 - wire(p, WIRE.W_4_SHIFT)); } // Batch subrelation evaluations using precomputed powers of alpha diff --git a/barretenberg/sol/src/honk/optimised/generate_offsets.py b/barretenberg/sol/src/honk/optimised/generate_offsets.py index 8001478d9272..7916e4d9d047 100755 --- a/barretenberg/sol/src/honk/optimised/generate_offsets.py +++ b/barretenberg/sol/src/honk/optimised/generate_offsets.py @@ -187,7 +187,7 @@ def print_proof(pointer: int): BATCHED_RELATION_PARTIAL_LENGTH = 8 PROOF_SIZE_LOG_N = 15 NUMBER_OF_ENTITIES = 41 -NUMBER_OF_SUBRELATIONS = 28 +NUMBER_OF_SUBRELATIONS = 29 NUMBER_OF_ALPHAS = NUMBER_OF_SUBRELATIONS - 1 # For the meantime we will load the entire proof into memory here # however i predict that it will be more efficient to load in the sumcheck univars diff --git a/barretenberg/sol/src/honk/optimised/honk-optimized.sol.template b/barretenberg/sol/src/honk/optimised/honk-optimized.sol.template index 282eb771de07..a0f8e200572a 100644 --- a/barretenberg/sol/src/honk/optimised/honk-optimized.sol.template +++ b/barretenberg/sol/src/honk/optimised/honk-optimized.sol.template @@ -3,7 +3,7 @@ pragma solidity ^0.8.27; import {IVerifier} from "src/interfaces/IVerifier.sol"; -uint256 constant NUMBER_OF_SUBRELATIONS = 28; +uint256 constant NUMBER_OF_SUBRELATIONS = 29; uint256 constant BATCHED_RELATION_PARTIAL_LENGTH = 8; uint256 constant ZK_BATCHED_RELATION_PARTIAL_LENGTH = 9; uint256 constant NUMBER_OF_ENTITIES = 41; @@ -420,36 +420,37 @@ contract BlakeOptHonkVerifier is IVerifier { uint256 internal constant ALPHA_CHALLENGE_24 = 0x3860; uint256 internal constant ALPHA_CHALLENGE_25 = 0x3880; uint256 internal constant ALPHA_CHALLENGE_26 = 0x38a0; - uint256 internal constant GATE_CHALLENGE_0 = 0x38c0; - uint256 internal constant GATE_CHALLENGE_1 = 0x38e0; - uint256 internal constant GATE_CHALLENGE_2 = 0x3900; - uint256 internal constant GATE_CHALLENGE_3 = 0x3920; - uint256 internal constant GATE_CHALLENGE_4 = 0x3940; - uint256 internal constant GATE_CHALLENGE_5 = 0x3960; - uint256 internal constant GATE_CHALLENGE_6 = 0x3980; - uint256 internal constant GATE_CHALLENGE_7 = 0x39a0; - uint256 internal constant GATE_CHALLENGE_8 = 0x39c0; - uint256 internal constant GATE_CHALLENGE_9 = 0x39e0; - uint256 internal constant GATE_CHALLENGE_10 = 0x3a00; - uint256 internal constant GATE_CHALLENGE_11 = 0x3a20; - uint256 internal constant GATE_CHALLENGE_12 = 0x3a40; - uint256 internal constant GATE_CHALLENGE_13 = 0x3a60; - uint256 internal constant GATE_CHALLENGE_14 = 0x3a80; - uint256 internal constant SUM_U_CHALLENGE_0 = 0x3aa0; - uint256 internal constant SUM_U_CHALLENGE_1 = 0x3ac0; - uint256 internal constant SUM_U_CHALLENGE_2 = 0x3ae0; - uint256 internal constant SUM_U_CHALLENGE_3 = 0x3b00; - uint256 internal constant SUM_U_CHALLENGE_4 = 0x3b20; - uint256 internal constant SUM_U_CHALLENGE_5 = 0x3b40; - uint256 internal constant SUM_U_CHALLENGE_6 = 0x3b60; - uint256 internal constant SUM_U_CHALLENGE_7 = 0x3b80; - uint256 internal constant SUM_U_CHALLENGE_8 = 0x3ba0; - uint256 internal constant SUM_U_CHALLENGE_9 = 0x3bc0; - uint256 internal constant SUM_U_CHALLENGE_10 = 0x3be0; - uint256 internal constant SUM_U_CHALLENGE_11 = 0x3c00; - uint256 internal constant SUM_U_CHALLENGE_12 = 0x3c20; - uint256 internal constant SUM_U_CHALLENGE_13 = 0x3c40; - uint256 internal constant SUM_U_CHALLENGE_14 = 0x3c60; + uint256 internal constant ALPHA_CHALLENGE_27 = 0x38c0; + uint256 internal constant GATE_CHALLENGE_0 = 0x38e0; + uint256 internal constant GATE_CHALLENGE_1 = 0x3900; + uint256 internal constant GATE_CHALLENGE_2 = 0x3920; + uint256 internal constant GATE_CHALLENGE_3 = 0x3940; + uint256 internal constant GATE_CHALLENGE_4 = 0x3960; + uint256 internal constant GATE_CHALLENGE_5 = 0x3980; + uint256 internal constant GATE_CHALLENGE_6 = 0x39a0; + uint256 internal constant GATE_CHALLENGE_7 = 0x39c0; + uint256 internal constant GATE_CHALLENGE_8 = 0x39e0; + uint256 internal constant GATE_CHALLENGE_9 = 0x3a00; + uint256 internal constant GATE_CHALLENGE_10 = 0x3a20; + uint256 internal constant GATE_CHALLENGE_11 = 0x3a40; + uint256 internal constant GATE_CHALLENGE_12 = 0x3a60; + uint256 internal constant GATE_CHALLENGE_13 = 0x3a80; + uint256 internal constant GATE_CHALLENGE_14 = 0x3aa0; + uint256 internal constant SUM_U_CHALLENGE_0 = 0x3ac0; + uint256 internal constant SUM_U_CHALLENGE_1 = 0x3ae0; + uint256 internal constant SUM_U_CHALLENGE_2 = 0x3b00; + uint256 internal constant SUM_U_CHALLENGE_3 = 0x3b20; + uint256 internal constant SUM_U_CHALLENGE_4 = 0x3b40; + uint256 internal constant SUM_U_CHALLENGE_5 = 0x3b60; + uint256 internal constant SUM_U_CHALLENGE_6 = 0x3b80; + uint256 internal constant SUM_U_CHALLENGE_7 = 0x3ba0; + uint256 internal constant SUM_U_CHALLENGE_8 = 0x3bc0; + uint256 internal constant SUM_U_CHALLENGE_9 = 0x3be0; + uint256 internal constant SUM_U_CHALLENGE_10 = 0x3c00; + uint256 internal constant SUM_U_CHALLENGE_11 = 0x3c20; + uint256 internal constant SUM_U_CHALLENGE_12 = 0x3c40; + uint256 internal constant SUM_U_CHALLENGE_13 = 0x3c60; + uint256 internal constant SUM_U_CHALLENGE_14 = 0x3c80; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CHALLENGES - COMPLETE */ @@ -462,134 +463,134 @@ contract BlakeOptHonkVerifier is IVerifier { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SUMCHECK - RUNTIME MEMORY - BARYCENTRIC */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_0_LOC = 0x3c80; - uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_1_LOC = 0x3ca0; - uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_2_LOC = 0x3cc0; - uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_3_LOC = 0x3ce0; - uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_4_LOC = 0x3d00; - uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_5_LOC = 0x3d20; - uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_6_LOC = 0x3d40; - uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_7_LOC = 0x3d60; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_0_LOC = 0x3d80; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_1_LOC = 0x3da0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_2_LOC = 0x3dc0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_3_LOC = 0x3de0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_4_LOC = 0x3e00; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_5_LOC = 0x3e20; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_6_LOC = 0x3e40; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_7_LOC = 0x3e60; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_0_LOC = 0x3e80; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_1_LOC = 0x3ea0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_2_LOC = 0x3ec0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_3_LOC = 0x3ee0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_4_LOC = 0x3f00; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_5_LOC = 0x3f20; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_6_LOC = 0x3f40; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_7_LOC = 0x3f60; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_0_LOC = 0x3f80; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_1_LOC = 0x3fa0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_2_LOC = 0x3fc0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_3_LOC = 0x3fe0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_4_LOC = 0x4000; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_5_LOC = 0x4020; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_6_LOC = 0x4040; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_7_LOC = 0x4060; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_0_LOC = 0x4080; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_1_LOC = 0x40a0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_2_LOC = 0x40c0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_3_LOC = 0x40e0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_4_LOC = 0x4100; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_5_LOC = 0x4120; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_6_LOC = 0x4140; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_7_LOC = 0x4160; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_0_LOC = 0x4180; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_1_LOC = 0x41a0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_2_LOC = 0x41c0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_3_LOC = 0x41e0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_4_LOC = 0x4200; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_5_LOC = 0x4220; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_6_LOC = 0x4240; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_7_LOC = 0x4260; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_0_LOC = 0x4280; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_1_LOC = 0x42a0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_2_LOC = 0x42c0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_3_LOC = 0x42e0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_4_LOC = 0x4300; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_5_LOC = 0x4320; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_6_LOC = 0x4340; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_7_LOC = 0x4360; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_0_LOC = 0x4380; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_1_LOC = 0x43a0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_2_LOC = 0x43c0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_3_LOC = 0x43e0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_4_LOC = 0x4400; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_5_LOC = 0x4420; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_6_LOC = 0x4440; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_7_LOC = 0x4460; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_0_LOC = 0x4480; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_1_LOC = 0x44a0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_2_LOC = 0x44c0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_3_LOC = 0x44e0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_4_LOC = 0x4500; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_5_LOC = 0x4520; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_6_LOC = 0x4540; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_7_LOC = 0x4560; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_0_LOC = 0x4580; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_1_LOC = 0x45a0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_2_LOC = 0x45c0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_3_LOC = 0x45e0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_4_LOC = 0x4600; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_5_LOC = 0x4620; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_6_LOC = 0x4640; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_7_LOC = 0x4660; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_0_LOC = 0x4680; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_1_LOC = 0x46a0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_2_LOC = 0x46c0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_3_LOC = 0x46e0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_4_LOC = 0x4700; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_5_LOC = 0x4720; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_6_LOC = 0x4740; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_7_LOC = 0x4760; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_0_LOC = 0x4780; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_1_LOC = 0x47a0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_2_LOC = 0x47c0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_3_LOC = 0x47e0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_4_LOC = 0x4800; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_5_LOC = 0x4820; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_6_LOC = 0x4840; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_7_LOC = 0x4860; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_0_LOC = 0x4880; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_1_LOC = 0x48a0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_2_LOC = 0x48c0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_3_LOC = 0x48e0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_4_LOC = 0x4900; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_5_LOC = 0x4920; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_6_LOC = 0x4940; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_7_LOC = 0x4960; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_0_LOC = 0x4980; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_1_LOC = 0x49a0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_2_LOC = 0x49c0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_3_LOC = 0x49e0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_4_LOC = 0x4a00; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_5_LOC = 0x4a20; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_6_LOC = 0x4a40; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_7_LOC = 0x4a60; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_0_LOC = 0x4a80; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_1_LOC = 0x4aa0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_2_LOC = 0x4ac0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_3_LOC = 0x4ae0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_4_LOC = 0x4b00; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_5_LOC = 0x4b20; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_6_LOC = 0x4b40; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_7_LOC = 0x4b60; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_0_LOC = 0x4b80; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_1_LOC = 0x4ba0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_2_LOC = 0x4bc0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_3_LOC = 0x4be0; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_4_LOC = 0x4c00; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_5_LOC = 0x4c20; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_6_LOC = 0x4c40; - uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_7_LOC = 0x4c60; + uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_0_LOC = 0x3ca0; + uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_1_LOC = 0x3cc0; + uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_2_LOC = 0x3ce0; + uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_3_LOC = 0x3d00; + uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_4_LOC = 0x3d20; + uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_5_LOC = 0x3d40; + uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_6_LOC = 0x3d60; + uint256 internal constant BARYCENTRIC_LAGRANGE_DENOMINATOR_7_LOC = 0x3d80; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_0_LOC = 0x3da0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_1_LOC = 0x3dc0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_2_LOC = 0x3de0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_3_LOC = 0x3e00; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_4_LOC = 0x3e20; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_5_LOC = 0x3e40; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_6_LOC = 0x3e60; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_0_7_LOC = 0x3e80; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_0_LOC = 0x3ea0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_1_LOC = 0x3ec0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_2_LOC = 0x3ee0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_3_LOC = 0x3f00; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_4_LOC = 0x3f20; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_5_LOC = 0x3f40; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_6_LOC = 0x3f60; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_1_7_LOC = 0x3f80; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_0_LOC = 0x3fa0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_1_LOC = 0x3fc0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_2_LOC = 0x3fe0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_3_LOC = 0x4000; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_4_LOC = 0x4020; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_5_LOC = 0x4040; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_6_LOC = 0x4060; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_2_7_LOC = 0x4080; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_0_LOC = 0x40a0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_1_LOC = 0x40c0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_2_LOC = 0x40e0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_3_LOC = 0x4100; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_4_LOC = 0x4120; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_5_LOC = 0x4140; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_6_LOC = 0x4160; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_3_7_LOC = 0x4180; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_0_LOC = 0x41a0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_1_LOC = 0x41c0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_2_LOC = 0x41e0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_3_LOC = 0x4200; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_4_LOC = 0x4220; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_5_LOC = 0x4240; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_6_LOC = 0x4260; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_4_7_LOC = 0x4280; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_0_LOC = 0x42a0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_1_LOC = 0x42c0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_2_LOC = 0x42e0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_3_LOC = 0x4300; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_4_LOC = 0x4320; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_5_LOC = 0x4340; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_6_LOC = 0x4360; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_5_7_LOC = 0x4380; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_0_LOC = 0x43a0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_1_LOC = 0x43c0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_2_LOC = 0x43e0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_3_LOC = 0x4400; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_4_LOC = 0x4420; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_5_LOC = 0x4440; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_6_LOC = 0x4460; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_6_7_LOC = 0x4480; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_0_LOC = 0x44a0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_1_LOC = 0x44c0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_2_LOC = 0x44e0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_3_LOC = 0x4500; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_4_LOC = 0x4520; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_5_LOC = 0x4540; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_6_LOC = 0x4560; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_7_7_LOC = 0x4580; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_0_LOC = 0x45a0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_1_LOC = 0x45c0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_2_LOC = 0x45e0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_3_LOC = 0x4600; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_4_LOC = 0x4620; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_5_LOC = 0x4640; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_6_LOC = 0x4660; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_8_7_LOC = 0x4680; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_0_LOC = 0x46a0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_1_LOC = 0x46c0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_2_LOC = 0x46e0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_3_LOC = 0x4700; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_4_LOC = 0x4720; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_5_LOC = 0x4740; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_6_LOC = 0x4760; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_9_7_LOC = 0x4780; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_0_LOC = 0x47a0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_1_LOC = 0x47c0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_2_LOC = 0x47e0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_3_LOC = 0x4800; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_4_LOC = 0x4820; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_5_LOC = 0x4840; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_6_LOC = 0x4860; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_10_7_LOC = 0x4880; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_0_LOC = 0x48a0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_1_LOC = 0x48c0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_2_LOC = 0x48e0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_3_LOC = 0x4900; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_4_LOC = 0x4920; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_5_LOC = 0x4940; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_6_LOC = 0x4960; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_11_7_LOC = 0x4980; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_0_LOC = 0x49a0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_1_LOC = 0x49c0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_2_LOC = 0x49e0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_3_LOC = 0x4a00; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_4_LOC = 0x4a20; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_5_LOC = 0x4a40; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_6_LOC = 0x4a60; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_12_7_LOC = 0x4a80; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_0_LOC = 0x4aa0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_1_LOC = 0x4ac0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_2_LOC = 0x4ae0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_3_LOC = 0x4b00; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_4_LOC = 0x4b20; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_5_LOC = 0x4b40; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_6_LOC = 0x4b60; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_13_7_LOC = 0x4b80; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_0_LOC = 0x4ba0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_1_LOC = 0x4bc0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_2_LOC = 0x4be0; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_3_LOC = 0x4c00; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_4_LOC = 0x4c20; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_5_LOC = 0x4c40; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_6_LOC = 0x4c60; + uint256 internal constant BARYCENTRIC_DENOMINATOR_INVERSES_14_7_LOC = 0x4c80; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SUMCHECK - RUNTIME MEMORY - BARYCENTRIC COMPLETE */ @@ -598,34 +599,35 @@ contract BlakeOptHonkVerifier is IVerifier { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SUMCHECK - RUNTIME MEMORY - SUBRELATION EVALUATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - uint256 internal constant SUBRELATION_EVAL_0_LOC = 0x4c80; - uint256 internal constant SUBRELATION_EVAL_1_LOC = 0x4ca0; - uint256 internal constant SUBRELATION_EVAL_2_LOC = 0x4cc0; - uint256 internal constant SUBRELATION_EVAL_3_LOC = 0x4ce0; - uint256 internal constant SUBRELATION_EVAL_4_LOC = 0x4d00; - uint256 internal constant SUBRELATION_EVAL_5_LOC = 0x4d20; - uint256 internal constant SUBRELATION_EVAL_6_LOC = 0x4d40; - uint256 internal constant SUBRELATION_EVAL_7_LOC = 0x4d60; - uint256 internal constant SUBRELATION_EVAL_8_LOC = 0x4d80; - uint256 internal constant SUBRELATION_EVAL_9_LOC = 0x4da0; - uint256 internal constant SUBRELATION_EVAL_10_LOC = 0x4dc0; - uint256 internal constant SUBRELATION_EVAL_11_LOC = 0x4de0; - uint256 internal constant SUBRELATION_EVAL_12_LOC = 0x4e00; - uint256 internal constant SUBRELATION_EVAL_13_LOC = 0x4e20; - uint256 internal constant SUBRELATION_EVAL_14_LOC = 0x4e40; - uint256 internal constant SUBRELATION_EVAL_15_LOC = 0x4e60; - uint256 internal constant SUBRELATION_EVAL_16_LOC = 0x4e80; - uint256 internal constant SUBRELATION_EVAL_17_LOC = 0x4ea0; - uint256 internal constant SUBRELATION_EVAL_18_LOC = 0x4ec0; - uint256 internal constant SUBRELATION_EVAL_19_LOC = 0x4ee0; - uint256 internal constant SUBRELATION_EVAL_20_LOC = 0x4f00; - uint256 internal constant SUBRELATION_EVAL_21_LOC = 0x4f20; - uint256 internal constant SUBRELATION_EVAL_22_LOC = 0x4f40; - uint256 internal constant SUBRELATION_EVAL_23_LOC = 0x4f60; - uint256 internal constant SUBRELATION_EVAL_24_LOC = 0x4f80; - uint256 internal constant SUBRELATION_EVAL_25_LOC = 0x4fa0; - uint256 internal constant SUBRELATION_EVAL_26_LOC = 0x4fc0; - uint256 internal constant SUBRELATION_EVAL_27_LOC = 0x4fe0; + uint256 internal constant SUBRELATION_EVAL_0_LOC = 0x4ca0; + uint256 internal constant SUBRELATION_EVAL_1_LOC = 0x4cc0; + uint256 internal constant SUBRELATION_EVAL_2_LOC = 0x4ce0; + uint256 internal constant SUBRELATION_EVAL_3_LOC = 0x4d00; + uint256 internal constant SUBRELATION_EVAL_4_LOC = 0x4d20; + uint256 internal constant SUBRELATION_EVAL_5_LOC = 0x4d40; + uint256 internal constant SUBRELATION_EVAL_6_LOC = 0x4d60; + uint256 internal constant SUBRELATION_EVAL_7_LOC = 0x4d80; + uint256 internal constant SUBRELATION_EVAL_8_LOC = 0x4da0; + uint256 internal constant SUBRELATION_EVAL_9_LOC = 0x4dc0; + uint256 internal constant SUBRELATION_EVAL_10_LOC = 0x4de0; + uint256 internal constant SUBRELATION_EVAL_11_LOC = 0x4e00; + uint256 internal constant SUBRELATION_EVAL_12_LOC = 0x4e20; + uint256 internal constant SUBRELATION_EVAL_13_LOC = 0x4e40; + uint256 internal constant SUBRELATION_EVAL_14_LOC = 0x4e60; + uint256 internal constant SUBRELATION_EVAL_15_LOC = 0x4e80; + uint256 internal constant SUBRELATION_EVAL_16_LOC = 0x4ea0; + uint256 internal constant SUBRELATION_EVAL_17_LOC = 0x4ec0; + uint256 internal constant SUBRELATION_EVAL_18_LOC = 0x4ee0; + uint256 internal constant SUBRELATION_EVAL_19_LOC = 0x4f00; + uint256 internal constant SUBRELATION_EVAL_20_LOC = 0x4f20; + uint256 internal constant SUBRELATION_EVAL_21_LOC = 0x4f40; + uint256 internal constant SUBRELATION_EVAL_22_LOC = 0x4f60; + uint256 internal constant SUBRELATION_EVAL_23_LOC = 0x4f80; + uint256 internal constant SUBRELATION_EVAL_24_LOC = 0x4fa0; + uint256 internal constant SUBRELATION_EVAL_25_LOC = 0x4fc0; + uint256 internal constant SUBRELATION_EVAL_26_LOC = 0x4fe0; + uint256 internal constant SUBRELATION_EVAL_27_LOC = 0x5000; + uint256 internal constant SUBRELATION_EVAL_28_LOC = 0x5020; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SUMCHECK - RUNTIME MEMORY - SUBRELATION EVALUATIONS COMPLETE */ @@ -634,13 +636,13 @@ contract BlakeOptHonkVerifier is IVerifier { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SUMCHECK - RUNTIME MEMORY - SUBRELATION INTERMEDIATES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - uint256 internal constant FINAL_ROUND_TARGET_LOC = 0x5000; - uint256 internal constant POW_PARTIAL_EVALUATION_LOC = 0x5020; - uint256 internal constant AUX_NON_NATIVE_FIELD_IDENTITY = 0x5040; - uint256 internal constant AUX_LIMB_ACCUMULATOR_IDENTITY = 0x5060; - uint256 internal constant AUX_RAM_CONSISTENCY_CHECK_IDENTITY = 0x5080; - uint256 internal constant AUX_ROM_CONSISTENCY_CHECK_IDENTITY = 0x50a0; - uint256 internal constant AUX_MEMORY_CHECK_IDENTITY = 0x50c0; + uint256 internal constant FINAL_ROUND_TARGET_LOC = 0x5040; + uint256 internal constant POW_PARTIAL_EVALUATION_LOC = 0x5060; + uint256 internal constant AUX_NON_NATIVE_FIELD_IDENTITY = 0x5080; + uint256 internal constant AUX_LIMB_ACCUMULATOR_IDENTITY = 0x50a0; + uint256 internal constant AUX_RAM_CONSISTENCY_CHECK_IDENTITY = 0x50c0; + uint256 internal constant AUX_ROM_CONSISTENCY_CHECK_IDENTITY = 0x50e0; + uint256 internal constant AUX_MEMORY_CHECK_IDENTITY = 0x5100; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SUMCHECK - RUNTIME MEMORY - COMPLETE */ @@ -654,21 +656,21 @@ contract BlakeOptHonkVerifier is IVerifier { /* SHPLEMINI - POWERS OF EVALUATION CHALLENGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// {{ UNROLL_SECTION_START POWERS_OF_EVALUATION_CHALLENGE }} - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_0_LOC = 0x50e0; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_1_LOC = 0x5100; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_2_LOC = 0x5120; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_3_LOC = 0x5140; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_4_LOC = 0x5160; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_5_LOC = 0x5180; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_6_LOC = 0x51a0; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_7_LOC = 0x51c0; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_8_LOC = 0x51e0; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_9_LOC = 0x5200; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_10_LOC = 0x5220; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_11_LOC = 0x5240; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_12_LOC = 0x5260; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_13_LOC = 0x5280; - uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_14_LOC = 0x52a0; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_0_LOC = 0x5120; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_1_LOC = 0x5140; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_2_LOC = 0x5160; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_3_LOC = 0x5180; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_4_LOC = 0x51a0; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_5_LOC = 0x51c0; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_6_LOC = 0x51e0; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_7_LOC = 0x5200; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_8_LOC = 0x5220; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_9_LOC = 0x5240; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_10_LOC = 0x5260; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_11_LOC = 0x5280; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_12_LOC = 0x52a0; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_13_LOC = 0x52c0; + uint256 internal constant POWERS_OF_EVALUATION_CHALLENGE_14_LOC = 0x52e0; /// {{ UNROLL_SECTION_END POWERS_OF_EVALUATION_CHALLENGE }} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ @@ -678,74 +680,74 @@ contract BlakeOptHonkVerifier is IVerifier { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SHPLEMINI - RUNTIME MEMORY - BATCH SCALARS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ - uint256 internal constant BATCH_SCALAR_1_LOC = 0x52c0; - uint256 internal constant BATCH_SCALAR_2_LOC = 0x52e0; - uint256 internal constant BATCH_SCALAR_3_LOC = 0x5300; - uint256 internal constant BATCH_SCALAR_4_LOC = 0x5320; - uint256 internal constant BATCH_SCALAR_5_LOC = 0x5340; - uint256 internal constant BATCH_SCALAR_6_LOC = 0x5360; - uint256 internal constant BATCH_SCALAR_7_LOC = 0x5380; - uint256 internal constant BATCH_SCALAR_8_LOC = 0x53a0; - uint256 internal constant BATCH_SCALAR_9_LOC = 0x53c0; - uint256 internal constant BATCH_SCALAR_10_LOC = 0x53e0; - uint256 internal constant BATCH_SCALAR_11_LOC = 0x5400; - uint256 internal constant BATCH_SCALAR_12_LOC = 0x5420; - uint256 internal constant BATCH_SCALAR_13_LOC = 0x5440; - uint256 internal constant BATCH_SCALAR_14_LOC = 0x5460; - uint256 internal constant BATCH_SCALAR_15_LOC = 0x5480; - uint256 internal constant BATCH_SCALAR_16_LOC = 0x54a0; - uint256 internal constant BATCH_SCALAR_17_LOC = 0x54c0; - uint256 internal constant BATCH_SCALAR_18_LOC = 0x54e0; - uint256 internal constant BATCH_SCALAR_19_LOC = 0x5500; - uint256 internal constant BATCH_SCALAR_20_LOC = 0x5520; - uint256 internal constant BATCH_SCALAR_21_LOC = 0x5540; - uint256 internal constant BATCH_SCALAR_22_LOC = 0x5560; - uint256 internal constant BATCH_SCALAR_23_LOC = 0x5580; - uint256 internal constant BATCH_SCALAR_24_LOC = 0x55a0; - uint256 internal constant BATCH_SCALAR_25_LOC = 0x55c0; - uint256 internal constant BATCH_SCALAR_26_LOC = 0x55e0; - uint256 internal constant BATCH_SCALAR_27_LOC = 0x5600; - uint256 internal constant BATCH_SCALAR_28_LOC = 0x5620; - uint256 internal constant BATCH_SCALAR_29_LOC = 0x5640; - uint256 internal constant BATCH_SCALAR_30_LOC = 0x5660; - uint256 internal constant BATCH_SCALAR_31_LOC = 0x5680; - uint256 internal constant BATCH_SCALAR_32_LOC = 0x56a0; - uint256 internal constant BATCH_SCALAR_33_LOC = 0x56c0; - uint256 internal constant BATCH_SCALAR_34_LOC = 0x56e0; - uint256 internal constant BATCH_SCALAR_35_LOC = 0x5700; - uint256 internal constant BATCH_SCALAR_36_LOC = 0x5720; - uint256 internal constant BATCH_SCALAR_37_LOC = 0x5740; - uint256 internal constant BATCH_SCALAR_38_LOC = 0x5760; - uint256 internal constant BATCH_SCALAR_39_LOC = 0x5780; - uint256 internal constant BATCH_SCALAR_40_LOC = 0x57a0; - uint256 internal constant BATCH_SCALAR_41_LOC = 0x57c0; - uint256 internal constant BATCH_SCALAR_42_LOC = 0x57e0; - uint256 internal constant BATCH_SCALAR_43_LOC = 0x5800; - uint256 internal constant BATCH_SCALAR_44_LOC = 0x5820; - uint256 internal constant BATCH_SCALAR_45_LOC = 0x5840; - uint256 internal constant BATCH_SCALAR_46_LOC = 0x5860; - uint256 internal constant BATCH_SCALAR_47_LOC = 0x5880; - uint256 internal constant BATCH_SCALAR_48_LOC = 0x58a0; - uint256 internal constant BATCH_SCALAR_49_LOC = 0x58c0; - uint256 internal constant BATCH_SCALAR_50_LOC = 0x58e0; - uint256 internal constant BATCH_SCALAR_51_LOC = 0x5900; - uint256 internal constant BATCH_SCALAR_52_LOC = 0x5920; - uint256 internal constant BATCH_SCALAR_53_LOC = 0x5940; - uint256 internal constant BATCH_SCALAR_54_LOC = 0x5960; - uint256 internal constant BATCH_SCALAR_55_LOC = 0x5980; - uint256 internal constant BATCH_SCALAR_56_LOC = 0x59a0; - uint256 internal constant BATCH_SCALAR_57_LOC = 0x59c0; - uint256 internal constant BATCH_SCALAR_58_LOC = 0x59e0; - uint256 internal constant BATCH_SCALAR_59_LOC = 0x5a00; - uint256 internal constant BATCH_SCALAR_60_LOC = 0x5a20; - uint256 internal constant BATCH_SCALAR_61_LOC = 0x5a40; - uint256 internal constant BATCH_SCALAR_62_LOC = 0x5a60; - uint256 internal constant BATCH_SCALAR_63_LOC = 0x5a80; - uint256 internal constant BATCH_SCALAR_64_LOC = 0x5aa0; - uint256 internal constant BATCH_SCALAR_65_LOC = 0x5ac0; - uint256 internal constant BATCH_SCALAR_66_LOC = 0x5ae0; - uint256 internal constant BATCH_SCALAR_67_LOC = 0x5b00; - uint256 internal constant BATCH_SCALAR_68_LOC = 0x5b20; + uint256 internal constant BATCH_SCALAR_1_LOC = 0x5300; + uint256 internal constant BATCH_SCALAR_2_LOC = 0x5320; + uint256 internal constant BATCH_SCALAR_3_LOC = 0x5340; + uint256 internal constant BATCH_SCALAR_4_LOC = 0x5360; + uint256 internal constant BATCH_SCALAR_5_LOC = 0x5380; + uint256 internal constant BATCH_SCALAR_6_LOC = 0x53a0; + uint256 internal constant BATCH_SCALAR_7_LOC = 0x53c0; + uint256 internal constant BATCH_SCALAR_8_LOC = 0x53e0; + uint256 internal constant BATCH_SCALAR_9_LOC = 0x5400; + uint256 internal constant BATCH_SCALAR_10_LOC = 0x5420; + uint256 internal constant BATCH_SCALAR_11_LOC = 0x5440; + uint256 internal constant BATCH_SCALAR_12_LOC = 0x5460; + uint256 internal constant BATCH_SCALAR_13_LOC = 0x5480; + uint256 internal constant BATCH_SCALAR_14_LOC = 0x54a0; + uint256 internal constant BATCH_SCALAR_15_LOC = 0x54c0; + uint256 internal constant BATCH_SCALAR_16_LOC = 0x54e0; + uint256 internal constant BATCH_SCALAR_17_LOC = 0x5500; + uint256 internal constant BATCH_SCALAR_18_LOC = 0x5520; + uint256 internal constant BATCH_SCALAR_19_LOC = 0x5540; + uint256 internal constant BATCH_SCALAR_20_LOC = 0x5560; + uint256 internal constant BATCH_SCALAR_21_LOC = 0x5580; + uint256 internal constant BATCH_SCALAR_22_LOC = 0x55a0; + uint256 internal constant BATCH_SCALAR_23_LOC = 0x55c0; + uint256 internal constant BATCH_SCALAR_24_LOC = 0x55e0; + uint256 internal constant BATCH_SCALAR_25_LOC = 0x5600; + uint256 internal constant BATCH_SCALAR_26_LOC = 0x5620; + uint256 internal constant BATCH_SCALAR_27_LOC = 0x5640; + uint256 internal constant BATCH_SCALAR_28_LOC = 0x5660; + uint256 internal constant BATCH_SCALAR_29_LOC = 0x5680; + uint256 internal constant BATCH_SCALAR_30_LOC = 0x56a0; + uint256 internal constant BATCH_SCALAR_31_LOC = 0x56c0; + uint256 internal constant BATCH_SCALAR_32_LOC = 0x56e0; + uint256 internal constant BATCH_SCALAR_33_LOC = 0x5700; + uint256 internal constant BATCH_SCALAR_34_LOC = 0x5720; + uint256 internal constant BATCH_SCALAR_35_LOC = 0x5740; + uint256 internal constant BATCH_SCALAR_36_LOC = 0x5760; + uint256 internal constant BATCH_SCALAR_37_LOC = 0x5780; + uint256 internal constant BATCH_SCALAR_38_LOC = 0x57a0; + uint256 internal constant BATCH_SCALAR_39_LOC = 0x57c0; + uint256 internal constant BATCH_SCALAR_40_LOC = 0x57e0; + uint256 internal constant BATCH_SCALAR_41_LOC = 0x5800; + uint256 internal constant BATCH_SCALAR_42_LOC = 0x5820; + uint256 internal constant BATCH_SCALAR_43_LOC = 0x5840; + uint256 internal constant BATCH_SCALAR_44_LOC = 0x5860; + uint256 internal constant BATCH_SCALAR_45_LOC = 0x5880; + uint256 internal constant BATCH_SCALAR_46_LOC = 0x58a0; + uint256 internal constant BATCH_SCALAR_47_LOC = 0x58c0; + uint256 internal constant BATCH_SCALAR_48_LOC = 0x58e0; + uint256 internal constant BATCH_SCALAR_49_LOC = 0x5900; + uint256 internal constant BATCH_SCALAR_50_LOC = 0x5920; + uint256 internal constant BATCH_SCALAR_51_LOC = 0x5940; + uint256 internal constant BATCH_SCALAR_52_LOC = 0x5960; + uint256 internal constant BATCH_SCALAR_53_LOC = 0x5980; + uint256 internal constant BATCH_SCALAR_54_LOC = 0x59a0; + uint256 internal constant BATCH_SCALAR_55_LOC = 0x59c0; + uint256 internal constant BATCH_SCALAR_56_LOC = 0x59e0; + uint256 internal constant BATCH_SCALAR_57_LOC = 0x5a00; + uint256 internal constant BATCH_SCALAR_58_LOC = 0x5a20; + uint256 internal constant BATCH_SCALAR_59_LOC = 0x5a40; + uint256 internal constant BATCH_SCALAR_60_LOC = 0x5a60; + uint256 internal constant BATCH_SCALAR_61_LOC = 0x5a80; + uint256 internal constant BATCH_SCALAR_62_LOC = 0x5aa0; + uint256 internal constant BATCH_SCALAR_63_LOC = 0x5ac0; + uint256 internal constant BATCH_SCALAR_64_LOC = 0x5ae0; + uint256 internal constant BATCH_SCALAR_65_LOC = 0x5b00; + uint256 internal constant BATCH_SCALAR_66_LOC = 0x5b20; + uint256 internal constant BATCH_SCALAR_67_LOC = 0x5b40; + uint256 internal constant BATCH_SCALAR_68_LOC = 0x5b60; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SHPLEMINI - RUNTIME MEMORY - BATCH SCALARS COMPLETE */ @@ -1454,7 +1456,7 @@ contract BlakeOptHonkVerifier is IVerifier { // Compute powers of alpha: alpha^2, alpha^3, ..., alpha^26 let alpha_off_set := ALPHA_CHALLENGE_1 - for {} lt(alpha_off_set, add(ALPHA_CHALLENGE_26, 0x20)) {} { + for {} lt(alpha_off_set, add(ALPHA_CHALLENGE_27, 0x20)) {} { let prev_alpha := mload(sub(alpha_off_set, 0x20)) mstore(alpha_off_set, mulmod(prev_alpha, alpha, p)) alpha_off_set := add(alpha_off_set, 0x20) @@ -2863,6 +2865,16 @@ contract BlakeOptHonkVerifier is IVerifier { ) mstore(SUBRELATION_EVAL_3_LOC, acc) } + + // Contribution 4: z_perm initialization (lagrange_first * z_perm = 0) + { + let acc := mulmod( + mulmod(mload(LAGRANGE_FIRST_EVAL_LOC), mload(Z_PERM_EVAL_LOC), p), + mload(POW_PARTIAL_EVALUATION_LOC), + p + ) + mstore(SUBRELATION_EVAL_4_LOC, acc) + } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ @@ -2926,9 +2938,9 @@ contract BlakeOptHonkVerifier is IVerifier { let read_tag_boolean_relation := mulmod(read_tag, addmod(read_tag, sub(p, 1), p), p) read_tag_boolean_relation := mulmod(read_tag_boolean_relation, mload(POW_PARTIAL_EVALUATION_LOC), p) - mstore(SUBRELATION_EVAL_4_LOC, accumulator_none) - mstore(SUBRELATION_EVAL_5_LOC, accumulator_one) - mstore(SUBRELATION_EVAL_6_LOC, read_tag_boolean_relation) + mstore(SUBRELATION_EVAL_5_LOC, accumulator_none) + mstore(SUBRELATION_EVAL_6_LOC, accumulator_one) + mstore(SUBRELATION_EVAL_7_LOC, read_tag_boolean_relation) } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ @@ -2951,7 +2963,7 @@ contract BlakeOptHonkVerifier is IVerifier { acc := mulmod(acc, addmod(delta_1, minus_three, p), p) acc := mulmod(acc, mload(QRANGE_EVAL_LOC), p) acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p) - mstore(SUBRELATION_EVAL_7_LOC, acc) + mstore(SUBRELATION_EVAL_8_LOC, acc) } { @@ -2961,7 +2973,7 @@ contract BlakeOptHonkVerifier is IVerifier { acc := mulmod(acc, addmod(delta_2, minus_three, p), p) acc := mulmod(acc, mload(QRANGE_EVAL_LOC), p) acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p) - mstore(SUBRELATION_EVAL_8_LOC, acc) + mstore(SUBRELATION_EVAL_9_LOC, acc) } { @@ -2971,7 +2983,7 @@ contract BlakeOptHonkVerifier is IVerifier { acc := mulmod(acc, addmod(delta_3, minus_three, p), p) acc := mulmod(acc, mload(QRANGE_EVAL_LOC), p) acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p) - mstore(SUBRELATION_EVAL_9_LOC, acc) + mstore(SUBRELATION_EVAL_10_LOC, acc) } { @@ -2981,7 +2993,7 @@ contract BlakeOptHonkVerifier is IVerifier { acc := mulmod(acc, addmod(delta_4, minus_three, p), p) acc := mulmod(acc, mload(QRANGE_EVAL_LOC), p) acc := mulmod(acc, mload(POW_PARTIAL_EVALUATION_LOC), p) - mstore(SUBRELATION_EVAL_10_LOC, acc) + mstore(SUBRELATION_EVAL_11_LOC, acc) } } @@ -3006,7 +3018,7 @@ contract BlakeOptHonkVerifier is IVerifier { let eval := mulmod(x_add_identity, mload(POW_PARTIAL_EVALUATION_LOC), p) eval := mulmod(eval, mload(QELLIPTIC_EVAL_LOC), p) eval := mulmod(eval, addmod(1, sub(p, mload(EC_Q_IS_DOUBLE)), p), p) - mstore(SUBRELATION_EVAL_11_LOC, eval) + mstore(SUBRELATION_EVAL_12_LOC, eval) } { @@ -3023,7 +3035,7 @@ contract BlakeOptHonkVerifier is IVerifier { let eval := mulmod(y_add_identity, mload(POW_PARTIAL_EVALUATION_LOC), p) eval := mulmod(eval, mload(QELLIPTIC_EVAL_LOC), p) eval := mulmod(eval, addmod(1, sub(p, mload(EC_Q_IS_DOUBLE)), p), p) - mstore(SUBRELATION_EVAL_12_LOC, eval) + mstore(SUBRELATION_EVAL_13_LOC, eval) } { @@ -3039,10 +3051,10 @@ contract BlakeOptHonkVerifier is IVerifier { let acc := mulmod(ep_x_double_identity, mload(POW_PARTIAL_EVALUATION_LOC), p) acc := mulmod(mulmod(acc, mload(QELLIPTIC_EVAL_LOC), p), mload(EC_Q_IS_DOUBLE), p) - acc := addmod(acc, mload(SUBRELATION_EVAL_11_LOC), p) + acc := addmod(acc, mload(SUBRELATION_EVAL_12_LOC), p) // Add to existing contribution - and double check that numbers here - mstore(SUBRELATION_EVAL_11_LOC, acc) + mstore(SUBRELATION_EVAL_12_LOC, acc) } { @@ -3065,10 +3077,10 @@ contract BlakeOptHonkVerifier is IVerifier { let acc := mulmod(y_double_identity, mload(POW_PARTIAL_EVALUATION_LOC), p) acc := mulmod(mulmod(acc, mload(QELLIPTIC_EVAL_LOC), p), mload(EC_Q_IS_DOUBLE), p) - acc := addmod(acc, mload(SUBRELATION_EVAL_12_LOC), p) + acc := addmod(acc, mload(SUBRELATION_EVAL_13_LOC), p) // Add to existing contribution - and double check that numbers here - mstore(SUBRELATION_EVAL_12_LOC, acc) + mstore(SUBRELATION_EVAL_13_LOC, acc) } } @@ -3175,7 +3187,7 @@ contract BlakeOptHonkVerifier is IVerifier { mulmod(record_delta, addmod(1, sub(p, index_delta), p), p) mstore( - SUBRELATION_EVAL_14_LOC, + SUBRELATION_EVAL_15_LOC, mulmod( adjacent_values_match_if_adjacent_indices_match, mulmod( @@ -3193,7 +3205,7 @@ contract BlakeOptHonkVerifier is IVerifier { // ROM_CONSISTENCY_CHECK_2 mstore( - SUBRELATION_EVAL_15_LOC, + SUBRELATION_EVAL_16_LOC, mulmod( index_is_monotonically_increasing, mulmod( @@ -3289,7 +3301,7 @@ contract BlakeOptHonkVerifier is IVerifier { ) mstore( - SUBRELATION_EVAL_16_LOC, + SUBRELATION_EVAL_17_LOC, mulmod( adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation, scaled_activation_selector, @@ -3298,12 +3310,12 @@ contract BlakeOptHonkVerifier is IVerifier { ) mstore( - SUBRELATION_EVAL_17_LOC, + SUBRELATION_EVAL_18_LOC, mulmod(index_is_monotonically_increasing, scaled_activation_selector, p) ) mstore( - SUBRELATION_EVAL_18_LOC, + SUBRELATION_EVAL_19_LOC, mulmod(next_gate_access_type_is_boolean, scaled_activation_selector, p) ) @@ -3360,7 +3372,7 @@ contract BlakeOptHonkVerifier is IVerifier { mulmod(mload(QMEMORY_EVAL_LOC), mload(POW_PARTIAL_EVALUATION_LOC), p), p ) - mstore(SUBRELATION_EVAL_13_LOC, memory_identity) + mstore(SUBRELATION_EVAL_14_LOC, memory_identity) } } } @@ -3507,7 +3519,7 @@ contract BlakeOptHonkVerifier is IVerifier { p ) - mstore(SUBRELATION_EVAL_19_LOC, nnf_identity) + mstore(SUBRELATION_EVAL_20_LOC, nnf_identity) } /* @@ -3560,22 +3572,22 @@ contract BlakeOptHonkVerifier is IVerifier { mulmod(mload(QPOSEIDON2_EXTERNAL_EVAL_LOC), mload(POW_PARTIAL_EVALUATION_LOC), p) mstore( - SUBRELATION_EVAL_20_LOC, + SUBRELATION_EVAL_21_LOC, mulmod(q_pos_by_scaling, addmod(v1, sub(p, mload(W1_SHIFT_EVAL_LOC)), p), p) ) mstore( - SUBRELATION_EVAL_21_LOC, + SUBRELATION_EVAL_22_LOC, mulmod(q_pos_by_scaling, addmod(v2, sub(p, mload(W2_SHIFT_EVAL_LOC)), p), p) ) mstore( - SUBRELATION_EVAL_22_LOC, + SUBRELATION_EVAL_23_LOC, mulmod(q_pos_by_scaling, addmod(v3, sub(p, mload(W3_SHIFT_EVAL_LOC)), p), p) ) mstore( - SUBRELATION_EVAL_23_LOC, + SUBRELATION_EVAL_24_LOC, mulmod(q_pos_by_scaling, addmod(v4, sub(p, mload(W4_SHIFT_EVAL_LOC)), p), p) ) } @@ -3603,25 +3615,25 @@ contract BlakeOptHonkVerifier is IVerifier { let v1 := addmod(mulmod(u1, POS_INTERNAL_MATRIX_D_0, p), u_sum, p) mstore( - SUBRELATION_EVAL_24_LOC, + SUBRELATION_EVAL_25_LOC, mulmod(q_pos_by_scaling, addmod(v1, sub(p, mload(W1_SHIFT_EVAL_LOC)), p), p) ) let v2 := addmod(mulmod(u2, POS_INTERNAL_MATRIX_D_1, p), u_sum, p) mstore( - SUBRELATION_EVAL_25_LOC, + SUBRELATION_EVAL_26_LOC, mulmod(q_pos_by_scaling, addmod(v2, sub(p, mload(W2_SHIFT_EVAL_LOC)), p), p) ) let v3 := addmod(mulmod(u3, POS_INTERNAL_MATRIX_D_2, p), u_sum, p) mstore( - SUBRELATION_EVAL_26_LOC, + SUBRELATION_EVAL_27_LOC, mulmod(q_pos_by_scaling, addmod(v3, sub(p, mload(W3_SHIFT_EVAL_LOC)), p), p) ) let v4 := addmod(mulmod(u4, POS_INTERNAL_MATRIX_D_3, p), u_sum, p) mstore( - SUBRELATION_EVAL_27_LOC, + SUBRELATION_EVAL_28_LOC, mulmod(q_pos_by_scaling, addmod(v4, sub(p, mload(W4_SHIFT_EVAL_LOC)), p), p) ) } @@ -3770,6 +3782,11 @@ contract BlakeOptHonkVerifier is IVerifier { mulmod(mload(SUBRELATION_EVAL_27_LOC), mload(ALPHA_CHALLENGE_26), p), p ) + accumulator := addmod( + accumulator, + mulmod(mload(SUBRELATION_EVAL_28_LOC), mload(ALPHA_CHALLENGE_27), p), + p + ) let sumcheck_valid := eq(accumulator, mload(FINAL_ROUND_TARGET_LOC))