From 9579fe94536c606a10921884fc9edbe8053959b7 Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Mon, 17 Apr 2023 23:36:32 +0000 Subject: [PATCH 01/11] FInished aux --- .../plonk/composer/ultra_composer.cpp | 1 + .../ultra_circuit_constructor.cpp | 598 ++++++++++++++++++ .../ultra_circuit_constructor.hpp | 21 + .../stdlib/primitives/bigfield/bigfield.hpp | 2 +- 4 files changed, 621 insertions(+), 1 deletion(-) diff --git a/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp b/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp index ad6fd54f9a..a160f79bb0 100644 --- a/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp +++ b/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp @@ -1845,6 +1845,7 @@ std::array UltraComposer::decompose_non_native_field_double_width_l const uint256_t value = get_variable(limb_idx); const uint256_t low = value & LIMB_MASK; const uint256_t hi = value >> DEFAULT_NON_NATIVE_FIELD_LIMB_BITS; + // WTF(kesha): What is this supposed to do? Unless uint256_t has failed, this should always work ASSERT(low + (hi << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS) == value); const uint32_t low_idx = add_variable(low); diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp index 425efbdb58..0df4232915 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp @@ -1,4 +1,15 @@ +/** + * @file ultra_circuit_constructor.cpp + * @author Luke (ledwards2225) and Kesha (Rumata888) (you@domain.com) + * @brief This file contains the implementation of UltraCircuitConstructor class that defines the logic of ultra-style + * circuits and is intended for the use in UltraHonk and UltraPlonk systems + * + * @todo 1) Replace barretenberg::fr with templated FF or Field + * @todo 2) See the inefficiency in auxilary gate. Delete extra LIMB multiplication and see if something breaks + * + */ #include "ultra_circuit_constructor.hpp" +#include #include #include @@ -2368,4 +2379,591 @@ void UltraCircuitConstructor::process_RAM_arrays(const size_t gate_offset_from_p } } +/** + * @brief Various methods relating to circuit evaluation + * + */ + +/** + * @brief Arithmetic gate-related methods + * + * @details The whole formula without alpha scaling is: + * + * q_arith * ( ( (-1/2) * (q_arith - 3) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c ) + + * (q_arith - 1)*( α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + w_4_omega) ) = 0 + * + * This formula results in several cases depending on q_arith: + * 1. q_arith == 0: Arithmetic gate is completely disabled + * + * 2. q_arith == 1: Everything in the minigate on the right is disabled. The equation is just a standard plonk equation + * with extra wires: q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c = 0 + * + * 3. q_arith == 2: The (w_1 + w_4 - ...) term is disabled. THe equation is: + * (1/2) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + w_4_omega = 0 + * It allows defining w_4 at next index (w_4_omega) in terms of current wire values + * + * 4. q_arith == 3: The product of w_1 and w_2 is disabled, but a mini addition gate is enabled. α² allows us to split + * the equation into two: + * + * q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0 + * + * w_1 + w_4 - w_1_omega + q_m = 0 (we are reusing q_m here) + * + * 5. q_arith > 3: The product of w_1 and w_2 is scaled by (q_arith - 3), while the w_4_omega term is scaled by (q_arith + * - 1). The equation can be split into two: + * + * (q_arith - 3)* q_m * w_1 * w_ 2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + (q_arith - 1) * w_4_omega = 0 + * + * w_1 + w_4 - w_1_omega + q_m = 0 + * + * The problem that q_m is used both in both equations can be dealt with by appropriately changing selector values at + * the next gate. Then we can treat (q_arith - 1) as a simulated q_6 selector and scale q_m to handle (q_arith - 3) at + * product. + * + * Uses only the alpha challenge + * + */ + +/** + * @brief Compute the arithmetic relation/gate evaluation base on given selector and witness evaluations + * + * @details We need this function because in ultra we have committed and non-committed gates (for example RAM and ROM). + * However, we'd still like to evaluate all of them, so we can't access selectors and witness values directly. + * + * You can scroll up to look at the description of the general logic of this gate + * + * @param q_arith_value + * @param q_1_value + * @param q_2_value + * @param q_3_value + * @param q_4_value + * @param q_m_value + * @param q_c_value + * @param w_1_value + * @param w_2_value + * @param w_3_value + * @param w_4_value + * @param w_1_shifted_value + * @param w_4_shifted_value + * @param alpha_base + * @param alpha + * @return fr + */ +fr compute_arithmetic_identity(fr q_arith_value, + fr q_1_value, + fr q_2_value, + fr q_3_value, + fr q_4_value, + fr q_m_value, + fr q_c_value, + fr w_1_value, + fr w_2_value, + fr w_3_value, + fr w_4_value, + fr w_1_shifted_value, + fr w_4_shifted_value, + fr alpha_base, + fr alpha) +{ + constexpr fr neg_half = fr(-2).invert(); + // The main arithmetic identity that gets activated for q_arith_value == 1 + fr arithmetic_identity = w_2_value; + arithmetic_identity *= q_m_value; + arithmetic_identity *= (q_arith_value - 3); + arithmetic_identity *= neg_half; + arithmetic_identity += q_1_value; + arithmetic_identity += (w_2_value * q_2_value); + arithmetic_identity += (w_3_value * q_3_value); + arithmetic_identity += (w_4_value * q_4_value); + arithmetic_identity += q_c_value; + + // The additional small addition identity + fr extra_small_addition_identity = w_1_value + w_4_value - w_1_shifted_value + q_m_value; + extra_small_addition_identity *= alpha; + extra_small_addition_identity *= (q_arith_value - 2); + + // The concatenation of small addition identity + shifted w_4 value that can be enabled separately + the main + // arithemtic identity + fr final_identity = extra_small_addition_identity + w_4_shifted_value; + final_identity *= (q_arith_value - 1); + final_identity += arithmetic_identity; + final_identity *= q_arith_value; + final_identity *= alpha_base; + return final_identity; +} +/** + * @brief Evaluate the contribution of the arithmetic gate constraint + * + * @param gate_index Gate index + * @param alpha_base The base value that the whole evaluation is multiplied by + * @return fr + */ +inline fr UltraCircuitConstructor::arithmetic_gate_evaluation(const size_t gate_index, const fr alpha_base) +{ + ASSERT(gate_index < num_gates); +} + +/** + * @brief General permutation sorting identity + * + * @details This identity binds together the values of witnesses on the same row (w_1, w_2, w_3, w_4) and the w_1 + * witness on the next row (w_1_shifted) so that the difference between 2 consecutive elements is in the set {0,1,2,3} + * + */ + +/** + * @brief Compute a single general permutation sorting identity + * + * @param w_1_value + * @param w_2_value + * @param w_3_value + * @param w_4_value + * @param w_1_shifted_value + * @param alpha_base + * @param alpha + * @return fr + */ +fr compute_genperm_sort_identity( + fr w_1_value, fr w_2_value, fr w_3_value, fr w_4_value, fr w_1_shifted_value, fr alpha_base, fr alpha) +{ + constexpr fr minus_two(-2); + constexpr fr minus_three(-3); + // Power of alpha to separate individual delta relations + // TODO(kesha): This is a repeated computation which can be efficiently optimized + const fr alpha_a = alpha_base; + const fr alpha_b = alpha_a * alpha; + const fr alpha_c = alpha_b * alpha; + const fr alpha_d = alpha_c * alpha; + + // (second - first)*(second - first - 1)*(second - first - 2)*(second - first - 3) + auto neighbour_difference = [](const fr first, const fr second) { + const fr delta = second - first; + return (delta.sqr() - delta) * (delta + minus_two) * (delta + minus_three); + }; + + return alpha_a * neighbour_difference(w_1_value, w_2_value) + alpha_b * neighbour_difference(w_2_value, w_3_value) + + alpha_c * neighbour_difference(w_3_value, w_4_value) + + alpha_d * neighbour_difference(w_4_value, w_1_shifted_value); +} + +/** + * @brief Elliptic curve identity gate methods implement elliptic curve point addition. The gate is enhanced to handle + * the case where one of the points is automatically scaled by the endomorphism constant β or negated + * + * + * @details The basic equation for the elliptic curve in short weierstrass form is y^2 == x^3 + a * x + b. + * + * The addition formulas are: + * λ = (y_2 - y_1) / (x_2 - x_1) + * x_3 = λ^2 - x_2 - x_1 = (y_2 - y_1)^2 / (x_2 - x_1)^2 - x_2 - x_1 = ((y_2 - y_1)^2 - (x_2 - x_1) * (x_2^2 - + * x_1^2)) / (x_2 - x_1)^2 + * + * If we assume that the points being added are distinct and not invereses of each other (so their x coordinates + * differ), then we can rephrase this equality: + * x_3 * (x_2 - x_1)^2 = ((y_2 - y_1)^2 - (x_2 - x_1) * (x_2^2 - x_1^2)) + * Let's say we want to apply the endomorphism to the (x_2, y_2) point at the same time and maybe change the sign of + * y_2: + * + * (x_2, y_2) = (β * x_2', sign * y_2') + * x_3 * (β * x_2' - x_1)^2 = ((sign * y_2' - y_1)^2 - (β * x_2' - x_1) * ((β * x_2')^2 - x_1^2)) + * + * Let's open the brackets and group the terms by β, β^2, sign: + * + * x_2'^2 * x_3 * β^2 - 2 * β * x_1 * x_2' * x_3 - x_1^2 * x_3 = sign^2 * y_2'^2 - 2 * sign * y_1 * y_2 + y_1^2 - β^3 + * * x_2'^3 + β * x_1^2 * x_2' + β^2 * x_1 * x_2'^2 - x_1^3 + * + * β^3 = 1 + * sign^2 = 1 (at least we always expect sign to be set to 1 or -1) + * + * sign * (-2 * y_1 * y_2) + β * (2 * x_1 * x_2' * x_3 +x_1^2 * x_2') + β^2 * (x_1 * x_2'^2 - x_2'^2 * x_3) + (x_1^2 * + * x_3 + y_2'^2 + y_1^2 - x_2'^3 - x_1^3) = 0 + * This is the equation computed in x_identity and scaled by α + * + * Now let's deal with the y equation: + * y_3 = λ * (x_3 - x_1) + y_1 = (y_2 - y_1) * (x_3 - x_1) / (x_2 - x_1) + y_1 = ((y_2 - y_1) * (x_3 - x_1) + y_1 * + * (x_2 - x_1)) / (x_2 - x_1) + * + * (x_2 - x_1) * y_3 = (y_2 - y_1) * (x_3 - x_1) + y_1 * (x_2 - x_1) + * + * Let's substitute (x_2, y_2) = (β * x_2', sign * y_2'): + * + * β * x_2' * y_3 - x_1 * y_3 - sign * y_2' * x_3 + y_1 * x_3 + sign * y_2' * x_1 - y_1 * x_1 - β * y_1 * x_2' + x_1 + * * y_1 = 0 + * + * Let's group: + * + * sign * (-y_2' * x_3 + y_2' * x_1) + β * (x_2' * x_3 + y_1 * x_2') + (-x_1 * y_3 + y_1 * x_3 - x_1 * y_1 + + * x_1 * y_1) = 0 + * + */ + +/** + * @brief Compute the identity of the arithmetic gate fiven all coefficients + * + * @param q_1_value 1 or -1 (the sign). Controls whether we are subtracting or adding the second point + * @param q_3_value The endomorphism coefficient β, if we are using the endomorphism here + * @param q_4_value β² if we need it + * @param w_2_value x₁ + * @param w_3_value y₁ + * @param w_1_shifted_value x₂ + * @param w_2_shifted_value y₂ + * @param w_3_shifted_value x₃ + * @param w_4_shifted_value y₃ + * @return fr + */ +fr compute_elliptic_identity(fr q_1_value, + fr q_3_value, + fr q_4_value, + fr w_2_value, + fr w_3_value, + fr w_1_shifted_value, + fr w_2_shifted_value, + fr w_3_shifted_value, + fr w_4_shifted_value, + fr alpha_base, + fr alpha) +{ + // TODO(kesha): Can this be implemented more efficiently? + // It seems that Zac wanted to group the elements by selectors to use several linear terms initially, + // but in the end we are using one, so there is no reason why we can't optimize computation in another way + const fr x_1 = w_2_value; + const fr y_1 = w_3_value; + const fr x_2 = w_1_shifted_value; + const fr y_2 = w_4_shifted_value; + const fr x_3 = w_2_shifted_value; + const fr y_3 = w_3_shifted_value; + const fr q_beta = q_3_value; + const fr q_beta_sqr = q_4_value; + const fr q_sign = q_1_value; + + fr beta_term = -x_2 * x_1 * (x_3 + x_3 + x_1); // -x_1 * x_2 * (2 * x_3 + x_1) + fr beta_sqr_term = x_2.sqr(); // x_2^2 + fr leftovers = beta_sqr_term; // x_2^2 + beta_sqr_term *= (x_3 - x_1); // x_2^2 * (x_3 - x_1) + fr sign_term = y_2 * y_1; // y_1 * y_2 + sign_term += sign_term; // 2 * y_1 * y_2 + beta_term *= q_beta; // -β * x_1 * x_2 * (2 * x_3 + x_1) + beta_sqr_term *= q_beta_sqr; // β^2 * x_2^2 * (x_3 - x_1) + sign_term *= q_sign; // 2 * y_1 * y_2 * sign + leftovers *= x_2; // x_2^3 + leftovers += x_1.sqr() * (x_3 + x_1); // x_2^3 + x_1 * (x_3 + x_1) + leftovers -= (y_2.sqr() + y_1.sqr()); // x_2^3 + x_1 * (x_3 + x_1) - y_2^2 - y_1^2 + + // Can be found in class description + fr x_identity = beta_term + beta_sqr_term + sign_term + leftovers; + x_identity *= alpha_base; + + beta_term = x_2 * (y_3 + y_1) * q_beta; // β * x_2 * (y_3 + y_1) + sign_term = -y_2 * (x_1 - x_3) * q_sign; // - signt * y_2 * (x_1 - x_3) + // TODO: remove extra additions if we decide to stay with this implementation + leftovers = -x_1 * (y_3 + y_1) + y_1 * (x_1 - x_3); // -x_1 * y_3 - x_1 * y_1 + y_1 * x_1 - y_1 * x_3 + + fr y_identity = beta_term + sign_term + leftovers; + y_identity *= alpha_base * alpha; + + return x_identity + y_identity; +} + +/** + * @brief Plookup Auxiliary Gate Identity + * + * @details Evaluates polynomial identities associated with the following Ultra custom gates: + * * RAM/ROM read-write consistency check + * * RAM timestamp difference consistency check + * * RAM/ROM index difference consistency check + * * Bigfield product evaluation (3 in total) + * * Bigfield limb accumulation (2 in total) + * + * Multiple selectors are used to 'switch' aux gates on/off according to the following pattern: + * + * | gate type | q_aux | q_1 | q_2 | q_3 | q_4 | q_m | q_c | q_arith | + * | ---------------------------- | ----- | --- | --- | --- | --- | --- | --- | ------ | + * | Bigfield Limb Accumulation 1 | 1 | 0 | 0 | 1 | 1 | 0 | --- | 0 | + * | Bigfield Limb Accumulation 2 | 1 | 0 | 0 | 1 | 0 | 1 | --- | 0 | + * | Bigfield Product 1 | 1 | 0 | 1 | 1 | 0 | 0 | --- | 0 | + * | Bigfield Product 2 | 1 | 0 | 1 | 0 | 1 | 0 | --- | 0 | + * | Bigfield Product 3 | 1 | 0 | 1 | 0 | 0 | 1 | --- | 0 | + * | RAM/ROM access gate | 1 | 1 | 0 | 0 | 0 | 1 | --- | 0 | + * | RAM timestamp check | 1 | 1 | 0 | 0 | 1 | 0 | --- | 0 | + * | ROM consistency check | 1 | 1 | 1 | 0 | 0 | 0 | --- | 0 | + * | RAM consistency check | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | + * + * N.B. The RAM consistency check identity is degree 3. To keep the overall quotient degree at <=5, only 2 selectors can + * be used to select it. + * + * N.B.2 The q_c selector is used to store circuit-specific values in the RAM/ROM access gate + * + */ + +fr compute_auxilary_identity(fr q_aux_value, + fr q_m_value, + fr q_1_value, + fr q_2_value, + fr q_3_value, + fr q_4_value, + fr q_c_value, + fr q_arith_value, + fr w_1_value, + fr w_2_value, + fr w_3_value, + fr w_4_value, + fr w_1_shifted_value, + fr w_2_shifted_value, + fr w_3_shifted_value, + fr w_4_shifted_value, + fr alpha_base, + fr alpha, + fr eta) +{ + constexpr barretenberg::fr LIMB_SIZE(uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS); + // TODO(kesha): Replace with a constant defined in header + constexpr barretenberg::fr SUBLIMB_SHIFT(uint256_t(1) << 14); + + // Non-native field arithmetic gate relations + // a{a_0, ..., a_3}⋅b{b_0,...,b_3} + q{q_0,..., q_3}⋅neg_p{neg_p_0,...,neg_p_3} - r{r_0,...,r_3} = 0 mod 2²⁷² + // neg_p and limb shifts are constants, so we can use big addition gates for them. + // Activated with q_2 & (q_3 | q_4 | q_m) - first, second, third appropriately + // For native gate_1: limb_subproduct = a_1 ⋅ b_0 + a_0 ⋅ b_1 + // For native gate_2: limb_subproduct = a_0 ⋅ b_2 + a_2 ⋅ b_0 + // For native gate_3: limb_subproduct = a_2 ⋅ b_1 + a_1 ⋅ b_2 + fr limb_subproduct = w_1_value * w_2_shifted_value + w_1_shifted_value * w_2_value; + + // ( a_0 ⋅ b_3 + a_3 ⋅ b_0 - r_3 ) + fr non_native_field_gate_2 = (w_1_value * w_4_value + w_2_value * w_3_value - w_3_shifted_value); + // ( a_0 ⋅ b_3 + a_3 ⋅ b_0 - r_3 ) << 68 + non_native_field_gate_2 *= LIMB_SIZE; + // ( a_0 ⋅ b_3 + a_3 ⋅ b_0 - r_3 ) << 68 - hi_0 + non_native_field_gate_2 -= w_4_shifted_value; + // ( a_0 ⋅ b_3 + a_3 ⋅ b_0 - r_3 ) << 68 - hi_0 + a_0 ⋅ b_2 + a_2 ⋅ b_0 + non_native_field_gate_2 += limb_subproduct; + non_native_field_gate_2 *= q_4_value; + + limb_subproduct *= LIMB_SIZE; + + // ( a_1 ⋅ b_0 + a_0 ⋅ b_1 ) << 68 + ( a_0 ⋅ b_0 ) + limb_subproduct += (w_1_shifted_value * w_2_shifted_value); + fr non_native_field_gate_1 = limb_subproduct; + // ( a_1 ⋅ b_0 + a_0 ⋅ b_1 ) << 68 + ( a_0 ⋅ b_0 ) + non_native_field_gate_1 -= (w_3_value + w_4_value); + non_native_field_gate_1 *= q_3_value; + + // ( a_2 ⋅ b_1 + a_1 ⋅ b_2 ) << 68 + ( a_1 ⋅ b_1 ) + fr non_native_field_gate_3 = limb_subproduct; + // ( a_2 ⋅ b_1 + a_1 ⋅ b_2 ) << 68 + ( a_1 ⋅ b_1 ) + hi_0 + non_native_field_gate_3 += w_4_value; + // ( a_2 ⋅ b_1 + a_1 ⋅ b_2 ) << 68 + ( a_1 ⋅ b_1 ) + hi_0 - r_2 - hi_1 + non_native_field_gate_3 -= (w_3_shifted_value + w_4_shifted_value); + non_native_field_gate_3 *= q_m_value; + + // Accumulate the 3 gates and multiply by q_2 + fr non_native_field_identity = non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3; + non_native_field_identity *= q_2_value; + + // Accummulator limbs. These are activated with (q_3)&( q_4 | q_m). + // The limbs are configured in such a way as to take 3 gates to process a decomposition of 2 at maximum 70-bit + // elements into 5 14-bit limbs each. Then through set permutation we can range constrain each + // + // w_4 == (w_2_shifted << 56) | (w_1_shifted << 42) | (w_3 << 28) | (w_2 << 14) | + // w_1 + fr limb_accumulator_1 = w_2_shifted_value; + limb_accumulator_1 *= SUBLIMB_SHIFT; + limb_accumulator_1 += w_1_shifted_value; + limb_accumulator_1 *= SUBLIMB_SHIFT; + limb_accumulator_1 += w_3_value; + limb_accumulator_1 *= SUBLIMB_SHIFT; + limb_accumulator_1 += w_2_value; + limb_accumulator_1 *= SUBLIMB_SHIFT; + limb_accumulator_1 += w_1_value; + limb_accumulator_1 -= w_4_value; + limb_accumulator_1 *= q_4_value; + + // w_4_shifted == (w_3_shifted << 56) | (w_2_shifted << 42) | (w_1_shifted << 28) | (w_4 << 14) | w_3 + fr limb_accumulator_2 = w_3_shifted_value; + limb_accumulator_2 *= SUBLIMB_SHIFT; + limb_accumulator_2 += w_2_shifted_value; + limb_accumulator_2 *= SUBLIMB_SHIFT; + limb_accumulator_2 += w_1_shifted_value; + limb_accumulator_2 *= SUBLIMB_SHIFT; + limb_accumulator_2 += w_4_value; + limb_accumulator_2 *= SUBLIMB_SHIFT; + limb_accumulator_2 += w_3_value; + limb_accumulator_2 -= w_4_shifted_value; + limb_accumulator_2 *= q_m_value; + + fr limb_accumulator_identity = limb_accumulator_1 + limb_accumulator_2; + limb_accumulator_identity *= q_3_value; + + /** + * MEMORY + * + * A RAM memory record contains a tuple of the following fields: + * * i: `index` of memory cell being accessed + * * t: `timestamp` of memory cell being accessed (used for RAM, set to 0 for ROM) + * * v: `value` of memory cell being accessed + * * a: `access` type of record. read: 0 = read, 1 = write + * * r: `record` of memory cell. record = access + index * eta + timestamp * eta^2 + value * eta^3 + * + * A ROM memory record contains a tuple of the following fields: + * * i: `index` of memory cell being accessed + * * v: `value1` of memory cell being accessed (ROM tables can store up to 2 values per index) + * * v2:`value2` of memory cell being accessed (ROM tables can store up to 2 values per index) + * * r: `record` of memory cell. record = index * eta + value2 * eta^2 + value1 * eta^3 + * + * When performing a read/write access, the values of i, t, v, v2, a, r are stored in the following wires + + * selectors, depending on whether the gate is a RAM read/write or a ROM read + * + * | gate type | i | v2/t | v | a | r | + * | --------- | -- | ----- | -- | -- | -- | + * | ROM | w1 | w2 | w3 | -- | w4 | + * | RAM | w1 | w2 | w3 | qc | w4 | + * + * (for accesses where `index` is a circuit constant, it is assumed the circuit will apply a copy constraint on + * `w2` to fix its value) + * + **/ + + /** + * Memory Record Check + * + * Memory record check is needed to generate a 4 ~ 1 correspondence between the record of the memory cell and all + * the other values. It allows us to use set equivalence for whole cells, since we only need to take care of + * 1 witness per cell + * + * A ROM/ROM access gate can be evaluated with the identity: + * + * qc + w1 \eta + w2 \eta^2 + w3 \eta^3 - w4 = 0 + * + * For ROM gates, qc = 0 + */ + + fr memory_record_check = w_3_value; + memory_record_check *= eta; + memory_record_check += w_2_value; + memory_record_check *= eta; + memory_record_check += w_1_value; + memory_record_check *= eta; + memory_record_check += q_c_value; + fr partial_record_check = memory_record_check; // used in RAM consistency check + memory_record_check = memory_record_check - w_4_value; + + /** + * ROM Consistency Check + * + * For every ROM read, a set equivalence check is applied between the record witnesses, and a second set of + * records that are sorted. + * + * We apply the following checks for the sorted records: + * + * 1. w1, w2, w3 correctly map to 'index', 'v1, 'v2' for a given record value at w4 + * 2. index values for adjacent records are monotonically increasing + * 3. if, at gate i, index_i == index_{i + 1}, then value1_i == value1_{i + 1} and value2_i == value2_{i + 1} + * + */ + + fr index_delta = w_1_shifted_value - w_1_value; + fr record_delta = w_4_shifted_value - w_4_value; + + // (index_delta - 1) ⋅ (index_delta) + fr index_is_monotonically_increasing = index_delta.sqr() - index_delta; + // (1 - index_delta) ⋅ (record_delta) + fr adjacent_values_match_if_adjacent_indices_match = (fr(1) - index_delta) * record_delta; + + fr ROM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match; + ROM_consistency_check_identity *= alpha; + ROM_consistency_check_identity += index_is_monotonically_increasing; + ROM_consistency_check_identity *= alpha; + // α²⋅(1 - index_delta) ⋅ record_delta + α ⋅ (index_delta - 1) ⋅ index_delta + (q_c + η ⋅ w_1 + η ⋅ w_2 + η ⋅ w_3 - + // w_4) + ROM_consistency_check_identity += memory_record_check; + + /** + * RAM Consistency Check + * + * The 'access' type of the record is extracted with the expression `w_4 - partial_record_check` + * (i.e. for an honest Prover `w1 * eta + w2 * eta^2 + w3 * eta^3 - w4 = access`. + * This is validated by requiring `access` to be boolean + * + * For two adjacent entries in the sorted list if _both_ + * A) index values match + * B) adjacent access value is 0 (i.e. next gate is a READ) + * then + * C) both values must match. + * The gate boolean check is + * (A && B) => C === !(A && B) || C === !A || !B || C + * + * N.B. it is the responsibility of the circuit writer to ensure that every RAM cell is initialized + * with a WRITE operation. + */ + fr access_type = (w_4_value - partial_record_check); // will be 0 or 1 for honest Prover + fr access_check = access_type.sqr() - access_type; // check value is 0 or 1 + + // TODO: oof nasty compute here. If we sorted in reverse order we could re-use `partial_record_check` + fr next_gate_access_type = w_3_shifted_value; + next_gate_access_type *= eta; + next_gate_access_type += w_2_shifted_value; + next_gate_access_type *= eta; + next_gate_access_type += w_1_shifted_value; + next_gate_access_type *= eta; + next_gate_access_type = w_4_shifted_value - next_gate_access_type; + + fr value_delta = w_3_shifted_value - w_3_value; + fr adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = + (fr(1) - index_delta) * value_delta * (fr(1) - next_gate_access_type); + + // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the + // next gate would make the identity fail). + // We need to validate that its 'access type' bool is correct. Can't do + // with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access type is + // correct, to cover this edge case + fr next_gate_access_type_is_boolean = next_gate_access_type.sqr() - next_gate_access_type; + + // Putting it all together... + fr RAM_consistency_check_identity = + adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; + RAM_consistency_check_identity *= alpha; + RAM_consistency_check_identity += index_is_monotonically_increasing; + RAM_consistency_check_identity *= alpha; + RAM_consistency_check_identity += next_gate_access_type_is_boolean; + RAM_consistency_check_identity *= alpha; + RAM_consistency_check_identity += access_check; + + /** + * RAM Timestamp Consistency Check + * + * | w1 | w2 | w3 | w4 | + * | index | timestamp | timestamp_check | -- | + * + * Let delta_index = index_{i + 1} - index_{i} + * + * Iff delta_index == 0, timestamp_check = timestamp_{i + 1} - timestamp_i + * Else timestamp_check = 0 + */ + fr timestamp_delta = w_2_shifted_value - w_2_value; + fr RAM_timestamp_check_identity = (fr(1) - index_delta) * timestamp_delta - w_3_value; + + /** + * The complete RAM/ROM memory identity + * + */ + fr memory_identity = ROM_consistency_check_identity * q_2_value; + memory_identity += RAM_timestamp_check_identity * q_4_value; + memory_identity += memory_record_check * q_m_value; + memory_identity *= q_1_value; + memory_identity += (RAM_consistency_check_identity * q_arith_value); + + fr auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity; + auxiliary_identity *= q_aux_value; + auxiliary_identity *= alpha_base; + + return auxiliary_identity; +} + +/** + * @brief + * + * @return true + * @return false + */ +bool UltraCircuitConstructor::check_circuit() {} + } // namespace proof_system \ No newline at end of file diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp index 2e4803fa44..ff2cfa2139 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp @@ -609,5 +609,26 @@ class UltraCircuitConstructor : public CircuitConstructorBase class bigfield { // code assumes modulus is at most 256 bits so good to define it via a uint256_t static constexpr uint256_t modulus = (uint256_t(T::modulus_0, T::modulus_1, T::modulus_2, T::modulus_3)); static constexpr uint512_t modulus_u512 = uint512_t(modulus); - static constexpr uint64_t NUM_LIMB_BITS = 68; + static constexpr uint64_t NUM_LIMB_BITS = NUM_LIMB_BITS_IN_FIELD_SIMULATION; static constexpr uint64_t NUM_LAST_LIMB_BITS = modulus_u512.get_msb() + 1 - (NUM_LIMB_BITS * 3); static constexpr uint1024_t DEFAULT_MAXIMUM_REMAINDER = (uint1024_t(1) << (NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS)) - uint1024_t(1); From 993ef5ba3faa755a6ad1e8b798d44f504c6e772c Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Wed, 19 Apr 2023 12:56:52 +0000 Subject: [PATCH 02/11] In-the-head stuff is added --- .../ultra_circuit_constructor.cpp | 703 ++++++++++-------- .../ultra_circuit_constructor.hpp | 226 +++++- 2 files changed, 613 insertions(+), 316 deletions(-) diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp index 0df4232915..a73bc3c840 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp @@ -43,12 +43,14 @@ void UltraCircuitConstructor::finalize_circuit() * Therefore, we introduce a boolean flag `circuit_finalised` here. Once we add the rom and range gates, * our circuit is finalised, and we must not to execute these functions again. */ - if (!circuit_finalised) { + bool switched_circuit_finalised = + (in_the_head && circuit_in_the_head.circuit_finalized) | (!in_the_head && circuit_finalised); + if (!switched_circuit_finalised) { process_non_native_field_multiplications(); process_ROM_arrays(public_inputs.size()); process_RAM_arrays(public_inputs.size()); process_range_lists(); - circuit_finalised = true; + switched_circuit_finalised = true; } } @@ -92,24 +94,24 @@ void UltraCircuitConstructor::create_add_gate(const add_triple& in) */ void UltraCircuitConstructor::create_big_add_gate(const add_quad& in, const bool include_next_gate_w_4) { + ENABLE_ALL_IN_THE_HEAD_SWITCHES assert_valid_variables({ in.a, in.b, in.c, in.d }); - - w_l.emplace_back(in.a); - w_r.emplace_back(in.b); - w_o.emplace_back(in.c); - w_4.emplace_back(in.d); - q_m.emplace_back(0); - q_1.emplace_back(in.a_scaling); - q_2.emplace_back(in.b_scaling); - q_3.emplace_back(in.c_scaling); - q_c.emplace_back(in.const_scaling); - q_arith.emplace_back(include_next_gate_w_4 ? 2 : 1); - q_4.emplace_back(in.d_scaling); - q_sort.emplace_back(0); - q_lookup_type.emplace_back(0); - q_elliptic.emplace_back(0); - q_aux.emplace_back(0); - ++num_gates; + switched_w_l.emplace_back(in.a); + switched_w_r.emplace_back(in.b); + switched_w_o.emplace_back(in.c); + switched_w_4.emplace_back(in.d); + switched_q_m.emplace_back(0); + switched_q_1.emplace_back(in.a_scaling); + switched_q_2.emplace_back(in.b_scaling); + switched_q_3.emplace_back(in.c_scaling); + switched_q_c.emplace_back(in.const_scaling); + switched_q_arith.emplace_back(include_next_gate_w_4 ? 2 : 1); + switched_q_4.emplace_back(in.d_scaling); + switched_q_sort.emplace_back(0); + switched_q_lookup_type.emplace_back(0); + switched_q_elliptic.emplace_back(0); + switched_q_aux.emplace_back(0); + ++switched_num_gates; } /** @@ -404,34 +406,37 @@ void UltraCircuitConstructor::create_ecc_add_gate(const ecc_add_gate& in) */ void UltraCircuitConstructor::fix_witness(const uint32_t witness_index, const barretenberg::fr& witness_value) { + ENABLE_ALL_IN_THE_HEAD_SWITCHES assert_valid_variables({ witness_index }); - w_l.emplace_back(witness_index); - w_r.emplace_back(zero_idx); - w_o.emplace_back(zero_idx); - w_4.emplace_back(zero_idx); - q_m.emplace_back(0); - q_1.emplace_back(1); - q_2.emplace_back(0); - q_3.emplace_back(0); - q_c.emplace_back(-witness_value); - q_arith.emplace_back(1); - q_4.emplace_back(0); - q_sort.emplace_back(0); - q_lookup_type.emplace_back(0); - q_elliptic.emplace_back(0); - q_aux.emplace_back(0); - ++num_gates; + switched_w_l.emplace_back(witness_index); + switched_w_r.emplace_back(zero_idx); + switched_w_o.emplace_back(zero_idx); + switched_w_4.emplace_back(zero_idx); + switched_q_m.emplace_back(0); + switched_q_1.emplace_back(1); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(0); + switched_q_c.emplace_back(-witness_value); + switched_q_arith.emplace_back(1); + switched_q_4.emplace_back(0); + switched_q_sort.emplace_back(0); + switched_q_lookup_type.emplace_back(0); + switched_q_elliptic.emplace_back(0); + switched_q_aux.emplace_back(0); + ++switched_num_gates; } uint32_t UltraCircuitConstructor::put_constant_variable(const barretenberg::fr& variable) { - if (constant_variable_indices.contains(variable)) { + auto& switched_constant_variable_indices = + choose_virtual_or_real(circuit_in_the_head.constant_variable_indices, constant_variable_indices, in_the_head); + if (switched_constant_variable_indices.contains(variable)) { return constant_variable_indices.at(variable); } else { uint32_t variable_index = add_variable(variable); fix_witness(variable_index, variable); - constant_variable_indices.insert({ variable, variable_index }); + switched_constant_variable_indices.insert({ variable, variable_index }); return variable_index; } } @@ -649,16 +654,17 @@ void UltraCircuitConstructor::create_new_range_constraint(const uint32_t variabl const uint64_t target_range, std::string const msg) { + ENABLE_ALL_IN_THE_HEAD_SWITCHES if (uint256_t(get_variable(variable_index)).data[0] > target_range) { if (!failed()) { failure(msg); } } - if (range_lists.count(target_range) == 0) { - range_lists.insert({ target_range, create_range_list(target_range) }); + if (switched_range_lists.count(target_range) == 0) { + switched_range_lists.insert({ target_range, create_range_list(target_range) }); } - auto& list = range_lists[target_range]; + auto& list = switched_range_lists[target_range]; assign_tag(variable_index, list.range_tag); list.variable_indices.emplace_back(variable_index); } @@ -769,6 +775,7 @@ void UltraCircuitConstructor::create_sort_constraint(const std::vector // multiples of three void UltraCircuitConstructor::create_dummy_constraints(const std::vector& variable_index) { + ENABLE_ALL_IN_THE_HEAD_SWITCHES std::vector padded_list = variable_index; constexpr size_t gate_width = plonk::ultra_settings::program_width; const uint64_t padding = (gate_width - (padded_list.size() % gate_width)) % gate_width; @@ -779,22 +786,22 @@ void UltraCircuitConstructor::create_dummy_constraints(const std::vector gate_width); assert_valid_variables(variable_index); // enforce range checks of first row and starting at start - w_l.emplace_back(variable_index[0]); - w_r.emplace_back(variable_index[1]); - w_o.emplace_back(variable_index[2]); - w_4.emplace_back(variable_index[3]); - ++num_gates; - q_m.emplace_back(0); - q_1.emplace_back(1); - q_2.emplace_back(0); - q_3.emplace_back(0); - q_c.emplace_back(-start); - q_arith.emplace_back(1); - q_4.emplace_back(0); - q_sort.emplace_back(1); - q_elliptic.emplace_back(0); - q_lookup_type.emplace_back(0); - q_aux.emplace_back(0); + switched_w_l.emplace_back(variable_index[0]); + switched_w_r.emplace_back(variable_index[1]); + switched_w_o.emplace_back(variable_index[2]); + switched_w_4.emplace_back(variable_index[3]); + ++switched_num_gates; + switched_q_m.emplace_back(0); + switched_q_1.emplace_back(1); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(0); + switched_q_c.emplace_back(-start); + switched_q_arith.emplace_back(1); + switched_q_4.emplace_back(0); + switched_q_sort.emplace_back(1); + switched_q_elliptic.emplace_back(0); + switched_q_lookup_type.emplace_back(0); + switched_q_aux.emplace_back(0); // enforce range check for middle rows for (size_t i = gate_width; i < variable_index.size() - gate_width; i += gate_width) { - w_l.emplace_back(variable_index[i]); - w_r.emplace_back(variable_index[i + 1]); - w_o.emplace_back(variable_index[i + 2]); - w_4.emplace_back(variable_index[i + 3]); - ++num_gates; - q_m.emplace_back(0); - q_1.emplace_back(0); - q_2.emplace_back(0); - q_3.emplace_back(0); - q_c.emplace_back(0); - q_arith.emplace_back(0); - q_4.emplace_back(0); - q_sort.emplace_back(1); - q_elliptic.emplace_back(0); - q_lookup_type.emplace_back(0); - q_aux.emplace_back(0); + switched_w_l.emplace_back(variable_index[i]); + switched_w_r.emplace_back(variable_index[i + 1]); + switched_w_o.emplace_back(variable_index[i + 2]); + switched_w_4.emplace_back(variable_index[i + 3]); + ++switched_num_gates; + switched_q_m.emplace_back(0); + switched_q_1.emplace_back(0); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(0); + switched_q_c.emplace_back(0); + switched_q_arith.emplace_back(0); + switched_q_4.emplace_back(0); + switched_q_sort.emplace_back(1); + switched_q_elliptic.emplace_back(0); + switched_q_lookup_type.emplace_back(0); + switched_q_aux.emplace_back(0); } // enforce range checks of last row and ending at end if (variable_index.size() > gate_width) { - w_l.emplace_back(variable_index[variable_index.size() - 4]); - w_r.emplace_back(variable_index[variable_index.size() - 3]); - w_o.emplace_back(variable_index[variable_index.size() - 2]); - w_4.emplace_back(variable_index[variable_index.size() - 1]); - ++num_gates; - q_m.emplace_back(0); - q_1.emplace_back(0); - q_2.emplace_back(0); - q_3.emplace_back(0); - q_c.emplace_back(0); - q_arith.emplace_back(0); - q_4.emplace_back(0); - q_sort.emplace_back(1); - q_elliptic.emplace_back(0); - q_lookup_type.emplace_back(0); - q_aux.emplace_back(0); + switched_w_l.emplace_back(variable_index[variable_index.size() - 4]); + switched_w_r.emplace_back(variable_index[variable_index.size() - 3]); + switched_w_o.emplace_back(variable_index[variable_index.size() - 2]); + switched_w_4.emplace_back(variable_index[variable_index.size() - 1]); + ++switched_num_gates; + switched_q_m.emplace_back(0); + switched_q_1.emplace_back(0); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(0); + switched_q_c.emplace_back(0); + switched_q_arith.emplace_back(0); + switched_q_4.emplace_back(0); + switched_q_sort.emplace_back(1); + switched_q_elliptic.emplace_back(0); + switched_q_lookup_type.emplace_back(0); + switched_q_aux.emplace_back(0); } // dummy gate needed because of sort widget's check of next row // use this gate to check end condition - w_l.emplace_back(variable_index[variable_index.size() - 1]); - w_r.emplace_back(zero_idx); - w_o.emplace_back(zero_idx); - w_4.emplace_back(zero_idx); - ++num_gates; - q_m.emplace_back(0); - q_1.emplace_back(1); - q_2.emplace_back(0); - q_3.emplace_back(0); - q_c.emplace_back(-end); - q_arith.emplace_back(1); - q_4.emplace_back(0); - q_sort.emplace_back(0); - q_elliptic.emplace_back(0); - q_lookup_type.emplace_back(0); - q_aux.emplace_back(0); + switched_w_l.emplace_back(variable_index[variable_index.size() - 1]); + switched_w_r.emplace_back(zero_idx); + switched_w_o.emplace_back(zero_idx); + switched_w_4.emplace_back(zero_idx); + ++switched_num_gates; + switched_q_m.emplace_back(0); + switched_q_1.emplace_back(1); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(0); + switched_q_c.emplace_back(-end); + switched_q_arith.emplace_back(1); + switched_q_4.emplace_back(0); + switched_q_sort.emplace_back(0); + switched_q_elliptic.emplace_back(0); + switched_q_lookup_type.emplace_back(0); + switched_q_aux.emplace_back(0); } // range constraint a value by decomposing it into limbs whose size should be the default range constraint size @@ -983,59 +991,60 @@ std::vector UltraCircuitConstructor::decompose_into_default_range_bett */ void UltraCircuitConstructor::apply_aux_selectors(const AUX_SELECTORS type) { - q_aux.emplace_back(type == AUX_SELECTORS::NONE ? 0 : 1); - q_sort.emplace_back(0); - q_lookup_type.emplace_back(0); - q_elliptic.emplace_back(0); + ENABLE_ALL_IN_THE_HEAD_SWITCHES + switched_q_aux.emplace_back(type == AUX_SELECTORS::NONE ? 0 : 1); + switched_q_sort.emplace_back(0); + switched_q_lookup_type.emplace_back(0); + switched_q_elliptic.emplace_back(0); switch (type) { case AUX_SELECTORS::LIMB_ACCUMULATE_1: { - q_1.emplace_back(0); - q_2.emplace_back(0); - q_3.emplace_back(1); - q_4.emplace_back(1); - q_m.emplace_back(0); - q_c.emplace_back(0); - q_arith.emplace_back(0); + switched_q_1.emplace_back(0); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(1); + switched_q_4.emplace_back(1); + switched_q_m.emplace_back(0); + switched_q_c.emplace_back(0); + switched_q_arith.emplace_back(0); break; } case AUX_SELECTORS::LIMB_ACCUMULATE_2: { - q_1.emplace_back(0); - q_2.emplace_back(0); - q_3.emplace_back(1); - q_4.emplace_back(0); - q_m.emplace_back(1); - q_c.emplace_back(0); - q_arith.emplace_back(0); + switched_q_1.emplace_back(0); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(1); + switched_q_4.emplace_back(0); + switched_q_m.emplace_back(1); + switched_q_c.emplace_back(0); + switched_q_arith.emplace_back(0); break; } case AUX_SELECTORS::NON_NATIVE_FIELD_1: { - q_1.emplace_back(0); - q_2.emplace_back(1); - q_3.emplace_back(1); - q_4.emplace_back(0); - q_m.emplace_back(0); - q_c.emplace_back(0); - q_arith.emplace_back(0); + switched_q_1.emplace_back(0); + switched_q_2.emplace_back(1); + switched_q_3.emplace_back(1); + switched_q_4.emplace_back(0); + switched_q_m.emplace_back(0); + switched_q_c.emplace_back(0); + switched_q_arith.emplace_back(0); break; } case AUX_SELECTORS::NON_NATIVE_FIELD_2: { - q_1.emplace_back(0); - q_2.emplace_back(1); - q_3.emplace_back(0); - q_4.emplace_back(1); - q_m.emplace_back(0); - q_c.emplace_back(0); - q_arith.emplace_back(0); + switched_q_1.emplace_back(0); + switched_q_2.emplace_back(1); + switched_q_3.emplace_back(0); + switched_q_4.emplace_back(1); + switched_q_m.emplace_back(0); + switched_q_c.emplace_back(0); + switched_q_arith.emplace_back(0); break; } case AUX_SELECTORS::NON_NATIVE_FIELD_3: { - q_1.emplace_back(0); - q_2.emplace_back(1); - q_3.emplace_back(0); - q_4.emplace_back(0); - q_m.emplace_back(1); - q_c.emplace_back(0); - q_arith.emplace_back(0); + switched_q_1.emplace_back(0); + switched_q_2.emplace_back(1); + switched_q_3.emplace_back(0); + switched_q_4.emplace_back(0); + switched_q_m.emplace_back(1); + switched_q_c.emplace_back(0); + switched_q_arith.emplace_back(0); break; } case AUX_SELECTORS::ROM_CONSISTENCY_CHECK: { @@ -1043,13 +1052,13 @@ void UltraCircuitConstructor::apply_aux_selectors(const AUX_SELECTORS type) // Apply sorted memory read checks with the following additional check: // 1. Assert that if index field across two gates does not change, the value field does not change. // Used for ROM reads and RAM reads across write/read boundaries - q_1.emplace_back(1); - q_2.emplace_back(1); - q_3.emplace_back(0); - q_4.emplace_back(0); - q_m.emplace_back(0); - q_c.emplace_back(0); - q_arith.emplace_back(0); + switched_q_1.emplace_back(1); + switched_q_2.emplace_back(1); + switched_q_3.emplace_back(0); + switched_q_4.emplace_back(0); + switched_q_m.emplace_back(0); + switched_q_c.emplace_back(0); + switched_q_arith.emplace_back(0); break; } case AUX_SELECTORS::RAM_CONSISTENCY_CHECK: { @@ -1058,74 +1067,74 @@ void UltraCircuitConstructor::apply_aux_selectors(const AUX_SELECTORS type) // 2. Validate record computation (r = read_write_flag + index * \eta + \timestamp * \eta^2 + value * \eta^3) // 3. If adjacent index values across 2 gates does not change, and the next gate's read_write_flag is set to // 'read', validate adjacent values do not change Used for ROM reads and RAM reads across read/write boundaries - q_1.emplace_back(0); - q_2.emplace_back(0); - q_3.emplace_back(0); - q_4.emplace_back(0); - q_m.emplace_back(0); - q_c.emplace_back(0); - q_arith.emplace_back(1); + switched_q_1.emplace_back(0); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(0); + switched_q_4.emplace_back(0); + switched_q_m.emplace_back(0); + switched_q_c.emplace_back(0); + switched_q_arith.emplace_back(1); break; } case AUX_SELECTORS::RAM_TIMESTAMP_CHECK: { // For two adjacent RAM entries that share the same index, validate the timestamp value is monotonically // increasing - q_1.emplace_back(1); - q_2.emplace_back(0); - q_3.emplace_back(0); - q_4.emplace_back(1); - q_m.emplace_back(0); - q_c.emplace_back(0); - q_arith.emplace_back(0); + switched_q_1.emplace_back(1); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(0); + switched_q_4.emplace_back(1); + switched_q_m.emplace_back(0); + switched_q_c.emplace_back(0); + switched_q_arith.emplace_back(0); break; } case AUX_SELECTORS::ROM_READ: { // Memory read gate for reading memory cells. // Validates record witness computation (r = read_write_flag + index * \eta + timestamp * \eta^2 + value * // \eta^3) - q_1.emplace_back(1); - q_2.emplace_back(0); - q_3.emplace_back(0); - q_4.emplace_back(0); - q_m.emplace_back(1); // validate record witness is correctly computed - q_c.emplace_back(0); // read/write flag stored in q_c - q_arith.emplace_back(0); + switched_q_1.emplace_back(1); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(0); + switched_q_4.emplace_back(0); + switched_q_m.emplace_back(1); // validate record witness is correctly computed + switched_q_c.emplace_back(0); // read/write flag stored in switched_q_c + switched_q_arith.emplace_back(0); break; } case AUX_SELECTORS::RAM_READ: { // Memory read gate for reading memory cells. // Validates record witness computation (r = read_write_flag + index * \eta + timestamp * \eta^2 + value * // \eta^3) - q_1.emplace_back(1); - q_2.emplace_back(0); - q_3.emplace_back(0); - q_4.emplace_back(0); - q_m.emplace_back(1); // validate record witness is correctly computed - q_c.emplace_back(0); // read/write flag stored in q_c - q_arith.emplace_back(0); + switched_q_1.emplace_back(1); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(0); + switched_q_4.emplace_back(0); + switched_q_m.emplace_back(1); // validate record witness is correctly computed + switched_q_c.emplace_back(0); // read/write flag stored in switched_q_c + switched_q_arith.emplace_back(0); break; } case AUX_SELECTORS::RAM_WRITE: { // Memory read gate for writing memory cells. // Validates record witness computation (r = read_write_flag + index * \eta + timestamp * \eta^2 + value * // \eta^3) - q_1.emplace_back(1); - q_2.emplace_back(0); - q_3.emplace_back(0); - q_4.emplace_back(0); - q_m.emplace_back(1); // validate record witness is correctly computed - q_c.emplace_back(1); // read/write flag stored in q_c - q_arith.emplace_back(0); + switched_q_1.emplace_back(1); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(0); + switched_q_4.emplace_back(0); + switched_q_m.emplace_back(1); // validate record witness is correctly computed + switched_q_c.emplace_back(1); // read/write flag stored in switched_q_c + switched_q_arith.emplace_back(0); break; } default: { - q_1.emplace_back(0); - q_2.emplace_back(0); - q_3.emplace_back(0); - q_4.emplace_back(0); - q_m.emplace_back(0); - q_c.emplace_back(0); - q_arith.emplace_back(0); + switched_q_1.emplace_back(0); + switched_q_2.emplace_back(0); + switched_q_3.emplace_back(0); + switched_q_4.emplace_back(0); + switched_q_m.emplace_back(0); + switched_q_c.emplace_back(0); + switched_q_arith.emplace_back(0); break; } } @@ -1792,12 +1801,13 @@ void UltraCircuitConstructor::create_ROM_gate(RomRecord& record) // Record wire value can't yet be computed record.record_witness = add_variable(0); apply_aux_selectors(AUX_SELECTORS::ROM_READ); - w_l.emplace_back(record.index_witness); - w_r.emplace_back(record.value_column1_witness); - w_o.emplace_back(record.value_column2_witness); - w_4.emplace_back(record.record_witness); - record.gate_index = num_gates; - ++num_gates; + ENABLE_ALL_IN_THE_HEAD_SWITCHES + switched_w_l.emplace_back(record.index_witness); + switched_w_r.emplace_back(record.value_column1_witness); + switched_w_o.emplace_back(record.value_column2_witness); + switched_w_4.emplace_back(record.record_witness); + record.gate_index = switched_num_gates; + ++switched_num_gates; } /** @@ -1811,13 +1821,13 @@ void UltraCircuitConstructor::create_sorted_ROM_gate(RomRecord& record) { record.record_witness = add_variable(0); apply_aux_selectors(AUX_SELECTORS::ROM_CONSISTENCY_CHECK); - w_l.emplace_back(record.index_witness); - w_r.emplace_back(record.value_column1_witness); - w_o.emplace_back(record.value_column2_witness); - w_4.emplace_back(record.record_witness); - - record.gate_index = num_gates; - ++num_gates; + ENABLE_ALL_IN_THE_HEAD_SWITCHES + switched_w_l.emplace_back(record.index_witness); + switched_w_r.emplace_back(record.value_column1_witness); + switched_w_o.emplace_back(record.value_column2_witness); + switched_w_4.emplace_back(record.record_witness); + record.gate_index = switched_num_gates; + ++switched_num_gates; } /** @@ -1856,12 +1866,13 @@ void UltraCircuitConstructor::create_RAM_gate(RamRecord& record) record.record_witness = add_variable(0); apply_aux_selectors(record.access_type == RamRecord::AccessType::READ ? AUX_SELECTORS::RAM_READ : AUX_SELECTORS::RAM_WRITE); - w_l.emplace_back(record.index_witness); - w_r.emplace_back(record.timestamp_witness); - w_o.emplace_back(record.value_witness); - w_4.emplace_back(record.record_witness); - record.gate_index = num_gates; - ++num_gates; + ENABLE_ALL_IN_THE_HEAD_SWITCHES + switched_w_l.emplace_back(record.index_witness); + switched_w_r.emplace_back(record.timestamp_witness); + switched_w_o.emplace_back(record.value_witness); + switched_w_4.emplace_back(record.record_witness); + record.gate_index = switched_num_gates; + ++switched_num_gates; } /** @@ -1873,14 +1884,15 @@ void UltraCircuitConstructor::create_RAM_gate(RamRecord& record) */ void UltraCircuitConstructor::create_sorted_RAM_gate(RamRecord& record) { + ENABLE_ALL_IN_THE_HEAD_SWITCHES record.record_witness = add_variable(0); apply_aux_selectors(AUX_SELECTORS::RAM_CONSISTENCY_CHECK); - w_l.emplace_back(record.index_witness); - w_r.emplace_back(record.timestamp_witness); - w_o.emplace_back(record.value_witness); - w_4.emplace_back(record.record_witness); - record.gate_index = num_gates; - ++num_gates; + switched_w_l.emplace_back(record.index_witness); + switched_w_r.emplace_back(record.timestamp_witness); + switched_w_o.emplace_back(record.value_witness); + switched_w_4.emplace_back(record.record_witness); + record.gate_index = switched_num_gates; + ++switched_num_gates; } /** @@ -1938,13 +1950,14 @@ void UltraCircuitConstructor::init_RAM_element(const size_t ram_id, const size_t index_value, const uint32_t value_witness) { - ASSERT(ram_arrays.size() > ram_id); - RamTranscript& ram_array = ram_arrays[ram_id]; + ENABLE_ALL_IN_THE_HEAD_SWITCHES + ASSERT(switched_ram_arrays.size() > ram_id); + RamTranscript& ram_array = switched_ram_arrays[ram_id]; const uint32_t index_witness = (index_value == 0) ? zero_idx : put_constant_variable((uint64_t)index_value); ASSERT(ram_array.state.size() > index_value); ASSERT(ram_array.state[index_value] == UNINITIALIZED_MEMORY_RECORD); RamRecord new_record{ .index_witness = index_witness, - .timestamp_witness = put_constant_variable((uint64_t)ram_array.access_count), + .timestamp_witness = put_constant_variable((uint64_t)ram_array.access_count, in_the_head), .value_witness = value_witness, .index = static_cast(index_value), // TODO: size_t? .timestamp = static_cast(ram_array.access_count), @@ -2066,7 +2079,8 @@ void UltraCircuitConstructor::set_ROM_element_pair(const size_t rom_id, const size_t index_value, const std::array& value_witnesses) { - ASSERT(rom_arrays.size() > rom_id); + auto& switched_rom_arrays = choose_virtual_or_real(circuit_in_the_head.rom_arrays, rom_arrays, in_the_head); + ASSERT(switched_rom_arrays.size() > rom_id); RomTranscript& rom_array = rom_arrays[rom_id]; const uint32_t index_witness = (index_value == 0) ? zero_idx : put_constant_variable((uint64_t)index_value); ASSERT(rom_array.state.size() > index_value); @@ -2147,7 +2161,11 @@ uint32_t UltraCircuitConstructor::read_ROM_array(const size_t rom_id, const uint */ void UltraCircuitConstructor::process_ROM_array(const size_t rom_id, const size_t gate_offset_from_public_inputs) { - auto& rom_array = rom_arrays[rom_id]; + + auto& switched_rom_arrays = choose_virtual_or_real(circuit_in_the_head.rom_arrays, rom_arrays, in_the_head); + auto& switched_memory_read_records = + choose_virtual_or_real(circuit_in_the_head.memory_read_records, memory_read_records, in_the_head); + auto& rom_array = switched_rom_arrays[rom_id]; const auto read_tag = get_new_tag(); // current_tag + 1; const auto sorted_list_tag = get_new_tag(); // current_tag + 2; create_tag(read_tag, sorted_list_tag); @@ -2197,8 +2215,10 @@ void UltraCircuitConstructor::process_ROM_array(const size_t rom_id, const size_ // record (w4) = w3 * eta^3 + w2 * eta^2 + w1 * eta + read_write_flag (0 for reads, 1 for writes) // Separate containers used to store gate indices of reads and writes. Need to differentiate because of // `read_write_flag` (N.B. all ROM accesses are considered reads. Writes are for RAM operations) - memory_read_records.push_back(static_cast(sorted_record.gate_index + gate_offset_from_public_inputs)); - memory_read_records.push_back(static_cast(record.gate_index + gate_offset_from_public_inputs)); + switched_memory_read_records.push_back( + static_cast(sorted_record.gate_index + gate_offset_from_public_inputs)); + switched_memory_read_records.push_back( + static_cast(record.gate_index + gate_offset_from_public_inputs)); } // One of the checks we run on the sorted list, is to validate the difference between // the index field across two gates is either 0 or 1. @@ -2207,17 +2227,19 @@ void UltraCircuitConstructor::process_ROM_array(const size_t rom_id, const size_ // we have validated that all ROM reads are correctly constrained fr max_index_value((uint64_t)rom_array.state.size()); uint32_t max_index = add_variable(max_index_value); - create_big_add_gate({ - max_index, - zero_idx, - zero_idx, - zero_idx, - 1, - 0, - 0, - 0, - -max_index_value, - }); + create_big_add_gate( + { + max_index, + zero_idx, + zero_idx, + zero_idx, + 1, + 0, + 0, + 0, + -max_index_value, + }, + false); // N.B. If the above check holds, we know the sorted list begins with an index value of 0, // because the first cell is explicitly initialized using zero_idx as the index field. } @@ -2230,7 +2252,8 @@ void UltraCircuitConstructor::process_ROM_array(const size_t rom_id, const size_ */ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_t gate_offset_from_public_inputs) { - RamTranscript& ram_array = ram_arrays[ram_id]; + ENABLE_ALL_IN_THE_HEAD_SWITCHES + RamTranscript& ram_array = switched_ram_arrays[ram_id]; const auto access_tag = get_new_tag(); // current_tag + 1; const auto sorted_list_tag = get_new_tag(); // current_tag + 2; create_tag(access_tag, sorted_list_tag); @@ -2297,15 +2320,17 @@ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_ switch (record.access_type) { case RamRecord::AccessType::READ: { - memory_read_records.push_back( + switched_memory_read_records.push_back( static_cast(sorted_record.gate_index + gate_offset_from_public_inputs)); - memory_read_records.push_back(static_cast(record.gate_index + gate_offset_from_public_inputs)); + switched_memory_read_records.push_back( + static_cast(record.gate_index + gate_offset_from_public_inputs)); break; } case RamRecord::AccessType::WRITE: { - memory_write_records.push_back( + switched_memory_write_records.push_back( static_cast(sorted_record.gate_index + gate_offset_from_public_inputs)); - memory_write_records.push_back(static_cast(record.gate_index + gate_offset_from_public_inputs)); + switched_memory_write_records.push_back( + static_cast(record.gate_index + gate_offset_from_public_inputs)); break; } default: { @@ -2333,11 +2358,11 @@ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_ uint32_t timestamp_delta_witness = add_variable(timestamp_delta); apply_aux_selectors(AUX_SELECTORS::RAM_TIMESTAMP_CHECK); - w_l.emplace_back(current.index_witness); - w_r.emplace_back(current.timestamp_witness); - w_o.emplace_back(timestamp_delta_witness); - w_4.emplace_back(zero_idx); - ++num_gates; + switched_w_l.emplace_back(current.index_witness); + switched_w_r.emplace_back(current.timestamp_witness); + switched_w_o.emplace_back(timestamp_delta_witness); + switched_w_4.emplace_back(zero_idx); + ++switched_num_gates; // store timestamp offsets for later. Need to apply range checks to them, but calling // `create_new_range_constraint` can add gates. Would ruin the structure of our sorted timestamp list. @@ -2449,21 +2474,21 @@ void UltraCircuitConstructor::process_RAM_arrays(const size_t gate_offset_from_p * @param alpha * @return fr */ -fr compute_arithmetic_identity(fr q_arith_value, - fr q_1_value, - fr q_2_value, - fr q_3_value, - fr q_4_value, - fr q_m_value, - fr q_c_value, - fr w_1_value, - fr w_2_value, - fr w_3_value, - fr w_4_value, - fr w_1_shifted_value, - fr w_4_shifted_value, - fr alpha_base, - fr alpha) +inline fr compute_arithmetic_identity(fr q_arith_value, + fr q_1_value, + fr q_2_value, + fr q_3_value, + fr q_4_value, + fr q_m_value, + fr q_c_value, + fr w_1_value, + fr w_2_value, + fr w_3_value, + fr w_4_value, + fr w_1_shifted_value, + fr w_4_shifted_value, + fr alpha_base, + fr alpha) { constexpr fr neg_half = fr(-2).invert(); // The main arithmetic identity that gets activated for q_arith_value == 1 @@ -2523,8 +2548,14 @@ inline fr UltraCircuitConstructor::arithmetic_gate_evaluation(const size_t gate_ * @param alpha * @return fr */ -fr compute_genperm_sort_identity( - fr w_1_value, fr w_2_value, fr w_3_value, fr w_4_value, fr w_1_shifted_value, fr alpha_base, fr alpha) +inline fr compute_genperm_sort_identity(fr q_sort_value, + fr w_1_value, + fr w_2_value, + fr w_3_value, + fr w_4_value, + fr w_1_shifted_value, + fr alpha_base, + fr alpha) { constexpr fr minus_two(-2); constexpr fr minus_three(-3); @@ -2541,9 +2572,10 @@ fr compute_genperm_sort_identity( return (delta.sqr() - delta) * (delta + minus_two) * (delta + minus_three); }; - return alpha_a * neighbour_difference(w_1_value, w_2_value) + alpha_b * neighbour_difference(w_2_value, w_3_value) + - alpha_c * neighbour_difference(w_3_value, w_4_value) + - alpha_d * neighbour_difference(w_4_value, w_1_shifted_value); + return q_sort_value * (alpha_a * neighbour_difference(w_1_value, w_2_value) + + alpha_b * neighbour_difference(w_2_value, w_3_value) + + alpha_c * neighbour_difference(w_3_value, w_4_value) + + alpha_d * neighbour_difference(w_4_value, w_1_shifted_value)); } /** @@ -2611,17 +2643,18 @@ fr compute_genperm_sort_identity( * @param w_4_shifted_value y₃ * @return fr */ -fr compute_elliptic_identity(fr q_1_value, - fr q_3_value, - fr q_4_value, - fr w_2_value, - fr w_3_value, - fr w_1_shifted_value, - fr w_2_shifted_value, - fr w_3_shifted_value, - fr w_4_shifted_value, - fr alpha_base, - fr alpha) +inline fr compute_elliptic_identity(fr q_elliptic_value, + fr q_1_value, + fr q_3_value, + fr q_4_value, + fr w_2_value, + fr w_3_value, + fr w_1_shifted_value, + fr w_2_shifted_value, + fr w_3_shifted_value, + fr w_4_shifted_value, + fr alpha_base, + fr alpha) { // TODO(kesha): Can this be implemented more efficiently? // It seems that Zac wanted to group the elements by selectors to use several linear terms initially, @@ -2661,7 +2694,7 @@ fr compute_elliptic_identity(fr q_1_value, fr y_identity = beta_term + sign_term + leftovers; y_identity *= alpha_base * alpha; - return x_identity + y_identity; + return q_elliptic_value * (x_identity + y_identity); } /** @@ -2695,25 +2728,25 @@ fr compute_elliptic_identity(fr q_1_value, * */ -fr compute_auxilary_identity(fr q_aux_value, - fr q_m_value, - fr q_1_value, - fr q_2_value, - fr q_3_value, - fr q_4_value, - fr q_c_value, - fr q_arith_value, - fr w_1_value, - fr w_2_value, - fr w_3_value, - fr w_4_value, - fr w_1_shifted_value, - fr w_2_shifted_value, - fr w_3_shifted_value, - fr w_4_shifted_value, - fr alpha_base, - fr alpha, - fr eta) +inline fr compute_auxilary_identity(fr q_aux_value, + fr q_m_value, + fr q_1_value, + fr q_2_value, + fr q_3_value, + fr q_4_value, + fr q_c_value, + fr q_arith_value, + fr w_1_value, + fr w_2_value, + fr w_3_value, + fr w_4_value, + fr w_1_shifted_value, + fr w_2_shifted_value, + fr w_3_shifted_value, + fr w_4_shifted_value, + fr alpha_base, + fr alpha, + fr eta) { constexpr barretenberg::fr LIMB_SIZE(uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS); // TODO(kesha): Replace with a constant defined in header @@ -2966,4 +2999,50 @@ fr compute_auxilary_identity(fr q_aux_value, */ bool UltraCircuitConstructor::check_circuit() {} +/** + * @brief Reset the circuit-in-the-head construction that we use for checking the correctness of the circuit + * + */ +void UltraCircuitConstructor::reset_circuit_in_the_head() +{ + // Unfortunately we have to copy all variable structures + circuit_in_the_head.public_inputs = public_inputs; + circuit_in_the_head.variables = variables; + circuit_in_the_head.next_var_index = next_var_index; + circuit_in_the_head.prev_var_index = prev_var_index; + circuit_in_the_head.real_variable_index = real_variable_index; + circuit_in_the_head.real_variable_tags = real_variable_tags; + circuit_in_the_head.constant_variable_indices = constant_variable_indices; + // Reset witness and selector vectors + circuit_in_the_head.w_l.clear(); + circuit_in_the_head.w_r.clear(); + circuit_in_the_head.w_o.clear(); + circuit_in_the_head.w_4.clear(); + circuit_in_the_head.q_m.clear(); + circuit_in_the_head.q_c.clear(); + circuit_in_the_head.q_1.clear(); + circuit_in_the_head.q_2.clear(); + circuit_in_the_head.q_3.clear(); + circuit_in_the_head.q_4.clear(); + circuit_in_the_head.q_arith.clear(); + circuit_in_the_head.q_elliptic.clear(); + circuit_in_the_head.q_aux.clear(); + circuit_in_the_head.q_lookup_type.clear(); + // Update current tag in the head to be the same as current real tag + circuit_in_the_head.current_tag = current_tag; + // Reset tau + circuit_in_the_head.tau.clear(); + // Copy rom and ram arrays + circuit_in_the_head.rom_arrays = rom_arrays; + circuit_in_the_head.ram_arrays = ram_arrays; + + circuit_in_the_head.memory_read_records.clear(); + circuit_in_the_head.memory_write_records.clear(); + circuit_in_the_head.ram_arrays = ram_arrays; + circuit_in_the_head.rom_arrays = rom_arrays; + circuit_in_the_head.range_lists = range_lists; + + circuit_in_the_head.num_gates = num_gates; + circuit_finalised = false; +} } // namespace proof_system \ No newline at end of file diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp index ff2cfa2139..b9ae561e98 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp @@ -206,8 +206,49 @@ inline std::vector ultra_selector_names() return result; } +struct CircuitInTheHead { + std::vector public_inputs; + std::vector variables; + // index of next variable in equivalence class (=REAL_VARIABLE if you're last) + std::vector next_var_index; + // index of previous variable in equivalence class (=FIRST if you're in a cycle alone) + std::vector prev_var_index; + // indices of corresponding real variables + std::vector real_variable_index; + std::vector real_variable_tags; + std::map constant_variable_indices; + std::vector w_l; + std::vector w_r; + std::vector w_o; + std::vector w_4; + std::vector q_m; + std::vector q_c; + std::vector q_1; + std::vector q_2; + std::vector q_3; + std::vector q_4; + std::vector q_arith; + std::vector q_sort; + std::vector q_elliptic; + std::vector q_aux; + std::vector q_lookup_type; + uint32_t current_tag = DUMMY_TAG; + std::map tau; + + std::vector ram_arrays; + std::vector rom_arrays; + + std::vector memory_read_records; + std::vector memory_write_records; + std::map range_lists; + size_t num_gates; + bool circuit_finalized = false; +}; class UltraCircuitConstructor : public CircuitConstructorBase { public: + CircuitInTheHead circuit_in_the_head; + // Switch, forcing gates to interact with circuit_in_the_head instead of the regular members + bool in_the_head = false; std::vector& w_l = std::get<0>(wires); std::vector& w_r = std::get<1>(wires); std::vector& w_o = std::get<2>(wires); @@ -283,6 +324,54 @@ class UltraCircuitConstructor : public CircuitConstructorBase::add_variable(in); + } + + circuit_in_the_head.variables.emplace_back(in); + + // By default, we assume each new variable belongs in its own copy-cycle. These defaults can be modified later + // by `assert_equal`. + const uint32_t index = static_cast(circuit_in_the_head.variables.size()) - 1U; + circuit_in_the_head.real_variable_index.emplace_back(index); + circuit_in_the_head.next_var_index.emplace_back(REAL_VARIABLE); + circuit_in_the_head.prev_var_index.emplace_back(FIRST_VARIABLE_IN_CLASS); + circuit_in_the_head.real_variable_tags.emplace_back(DUMMY_TAG); + return index; + } + inline barretenberg::fr get_variable(const uint32_t index) const + { + if (!in_the_head) { + return CircuitConstructorBase::get_variable(index); + } + ASSERT(circuit_in_the_head.variables.size() > index); + return circuit_in_the_head.variables[circuit_in_the_head.real_variable_index[index]]; + } + void assert_valid_variables(const std::vector& variable_indices) + { + for (const auto& variable_index : variable_indices) { + ASSERT(is_valid_variable(variable_index)); + } + } + bool is_valid_variable(uint32_t variable_index) + { + if (in_the_head) { + return variable_index < circuit_in_the_head.variables.size(); + } else { + return variable_index < variables.size(); + } + }; + void finalize_circuit(); void create_add_gate(const add_triple& in) override; @@ -528,13 +617,28 @@ class UltraCircuitConstructor : public CircuitConstructorBase= current_tag); + circuit_in_the_head.tau.insert({ tag_index, tau_index }); + circuit_in_the_head.current_tag++; + return circuit_in_the_head.current_tag; + } tau.insert({ tag_index, tau_index }); current_tag++; // Why exactly? return current_tag; @@ -542,6 +646,12 @@ class UltraCircuitConstructor : public CircuitConstructorBase= current_tag); + circuit_in_the_head.current_tag++; + return circuit_in_the_head.current_tag; + } current_tag++; return current_tag; } @@ -610,6 +720,74 @@ class UltraCircuitConstructor : public CircuitConstructorBase inline T& choose_virtual_or_real(T& virtual_member, T& real_member, bool in_the_head) + { + if (in_the_head) { + return virtual_member; + } else { + return real_member; + } + } + +#define PARENS () +// Rescan macro tokens 256 times +#define EXPAND(arg) EXPAND1(EXPAND1(EXPAND1(EXPAND1(arg)))) +#define EXPAND1(arg) EXPAND2(EXPAND2(EXPAND2(EXPAND2(arg)))) +#define EXPAND2(arg) EXPAND3(EXPAND3(EXPAND3(EXPAND3(arg)))) +#define EXPAND3(arg) EXPAND4(EXPAND4(EXPAND4(EXPAND4(arg)))) +#define EXPAND4(arg) arg + +#define FOR_EACH(macro, ...) __VA_OPT__(EXPAND(FOR_EACH_HELPER(macro, __VA_ARGS__))) +#define FOR_EACH_HELPER(macro, a1, a2, a3, ...) \ + macro(a1, a2, a3) __VA_OPT__(FOR_EACH_AGAIN PARENS(macro, a1, a2, __VA_ARGS__)) +#define FOR_EACH_AGAIN() FOR_EACH_HELPER + +#define HEAD(x, ...) x +#define TAIL(x, ...) __VA_ARGS__ + +#define ASSIGN_VARIABLE_TO_VIRTUAL_OR_REAL(variable_prefix, switch_name, member) \ + auto& variable_prefix##member = choose_virtual_or_real(circuit_in_the_head.##member, member, switch_name); \ + (void)variable_prefix##member; +#define CHOOSE_VIRTUAL_OR_REAL_MULTIPLE(variable_prefix, switch_name, member_name, ...) \ + FOR_EACH(ASSIGN_VARIABLE_TO_VIRTUAL_OR_REAL, variable_prefix, switch_name, member_name, __VA_ARGS__) +#define ENABLE_ALL_IN_THE_HEAD_SWITCHES \ + CHOOSE_VIRTUAL_OR_REAL_MULTIPLE(switched_, \ + in_the_head, \ + w_l, \ + w_r, \ + w_o, \ + w_4, \ + q_m, \ + q_1, \ + q_2, \ + q_3, \ + q_c, \ + q_arith, \ + q_4, \ + q_sort, \ + q_lookup_type, \ + q_elliptic, \ + q_aux, \ + num_gates, \ + ram_arrays, \ + rom_arrays, \ + memory_read_records, \ + memory_write_records, \ + range_lists) // Circuit evaluation methods fr compute_arithmetic_identity(fr q_arith_value, @@ -628,7 +806,47 @@ class UltraCircuitConstructor : public CircuitConstructorBase Date: Thu, 20 Apr 2023 23:13:47 +0000 Subject: [PATCH 03/11] Check circuit is woests and comments left --- cpp/CMakeLists.txt | 1 + .../barretenberg/proof_system/CMakeLists.txt | 2 +- .../ultra_circuit_constructor.cpp | 388 ++++++++++++++---- .../ultra_circuit_constructor.hpp | 19 +- .../ultra_circuit_constructor.test.cpp | 128 ++++++ 5 files changed, 458 insertions(+), 80 deletions(-) create mode 100644 cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 4f719a0335..606dbd6f65 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -38,6 +38,7 @@ endif() if(ENABLE_ASAN) add_compile_options(-fsanitize=address) add_link_options(-fsanitize=address) + set(DISABLE_ASM ON) endif() if(SERIALIZE_CANARY) diff --git a/cpp/src/barretenberg/proof_system/CMakeLists.txt b/cpp/src/barretenberg/proof_system/CMakeLists.txt index 3a8ed4dd8b..ec894c6748 100644 --- a/cpp/src/barretenberg/proof_system/CMakeLists.txt +++ b/cpp/src/barretenberg/proof_system/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(proof_system polynomials crypto_generators) \ No newline at end of file +barretenberg_module(proof_system polynomials crypto_generators plonk) \ No newline at end of file diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp index a73bc3c840..a906b835f8 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp @@ -1957,7 +1957,7 @@ void UltraCircuitConstructor::init_RAM_element(const size_t ram_id, ASSERT(ram_array.state.size() > index_value); ASSERT(ram_array.state[index_value] == UNINITIALIZED_MEMORY_RECORD); RamRecord new_record{ .index_witness = index_witness, - .timestamp_witness = put_constant_variable((uint64_t)ram_array.access_count, in_the_head), + .timestamp_witness = put_constant_variable((uint64_t)ram_array.access_count), .value_witness = value_witness, .index = static_cast(index_value), // TODO: size_t? .timestamp = static_cast(ram_array.access_count), @@ -2474,21 +2474,21 @@ void UltraCircuitConstructor::process_RAM_arrays(const size_t gate_offset_from_p * @param alpha * @return fr */ -inline fr compute_arithmetic_identity(fr q_arith_value, - fr q_1_value, - fr q_2_value, - fr q_3_value, - fr q_4_value, - fr q_m_value, - fr q_c_value, - fr w_1_value, - fr w_2_value, - fr w_3_value, - fr w_4_value, - fr w_1_shifted_value, - fr w_4_shifted_value, - fr alpha_base, - fr alpha) +inline fr UltraCircuitConstructor::compute_arithmetic_identity(fr q_arith_value, + fr q_1_value, + fr q_2_value, + fr q_3_value, + fr q_4_value, + fr q_m_value, + fr q_c_value, + fr w_1_value, + fr w_2_value, + fr w_3_value, + fr w_4_value, + fr w_1_shifted_value, + fr w_4_shifted_value, + fr alpha_base, + fr alpha) const { constexpr fr neg_half = fr(-2).invert(); // The main arithmetic identity that gets activated for q_arith_value == 1 @@ -2497,6 +2497,7 @@ inline fr compute_arithmetic_identity(fr q_arith_value, arithmetic_identity *= (q_arith_value - 3); arithmetic_identity *= neg_half; arithmetic_identity += q_1_value; + arithmetic_identity *= w_1_value; arithmetic_identity += (w_2_value * q_2_value); arithmetic_identity += (w_3_value * q_3_value); arithmetic_identity += (w_4_value * q_4_value); @@ -2516,17 +2517,6 @@ inline fr compute_arithmetic_identity(fr q_arith_value, final_identity *= alpha_base; return final_identity; } -/** - * @brief Evaluate the contribution of the arithmetic gate constraint - * - * @param gate_index Gate index - * @param alpha_base The base value that the whole evaluation is multiplied by - * @return fr - */ -inline fr UltraCircuitConstructor::arithmetic_gate_evaluation(const size_t gate_index, const fr alpha_base) -{ - ASSERT(gate_index < num_gates); -} /** * @brief General permutation sorting identity @@ -2548,17 +2538,15 @@ inline fr UltraCircuitConstructor::arithmetic_gate_evaluation(const size_t gate_ * @param alpha * @return fr */ -inline fr compute_genperm_sort_identity(fr q_sort_value, - fr w_1_value, - fr w_2_value, - fr w_3_value, - fr w_4_value, - fr w_1_shifted_value, - fr alpha_base, - fr alpha) +inline fr UltraCircuitConstructor::compute_genperm_sort_identity(fr q_sort_value, + fr w_1_value, + fr w_2_value, + fr w_3_value, + fr w_4_value, + fr w_1_shifted_value, + fr alpha_base, + fr alpha) const { - constexpr fr minus_two(-2); - constexpr fr minus_three(-3); // Power of alpha to separate individual delta relations // TODO(kesha): This is a repeated computation which can be efficiently optimized const fr alpha_a = alpha_base; @@ -2568,6 +2556,8 @@ inline fr compute_genperm_sort_identity(fr q_sort_value, // (second - first)*(second - first - 1)*(second - first - 2)*(second - first - 3) auto neighbour_difference = [](const fr first, const fr second) { + constexpr fr minus_two(-2); + constexpr fr minus_three(-3); const fr delta = second - first; return (delta.sqr() - delta) * (delta + minus_two) * (delta + minus_three); }; @@ -2643,18 +2633,18 @@ inline fr compute_genperm_sort_identity(fr q_sort_value, * @param w_4_shifted_value y₃ * @return fr */ -inline fr compute_elliptic_identity(fr q_elliptic_value, - fr q_1_value, - fr q_3_value, - fr q_4_value, - fr w_2_value, - fr w_3_value, - fr w_1_shifted_value, - fr w_2_shifted_value, - fr w_3_shifted_value, - fr w_4_shifted_value, - fr alpha_base, - fr alpha) +inline fr UltraCircuitConstructor::compute_elliptic_identity(fr q_elliptic_value, + fr q_1_value, + fr q_3_value, + fr q_4_value, + fr w_2_value, + fr w_3_value, + fr w_1_shifted_value, + fr w_2_shifted_value, + fr w_3_shifted_value, + fr w_4_shifted_value, + fr alpha_base, + fr alpha) const { // TODO(kesha): Can this be implemented more efficiently? // It seems that Zac wanted to group the elements by selectors to use several linear terms initially, @@ -2728,25 +2718,25 @@ inline fr compute_elliptic_identity(fr q_elliptic_value, * */ -inline fr compute_auxilary_identity(fr q_aux_value, - fr q_m_value, - fr q_1_value, - fr q_2_value, - fr q_3_value, - fr q_4_value, - fr q_c_value, - fr q_arith_value, - fr w_1_value, - fr w_2_value, - fr w_3_value, - fr w_4_value, - fr w_1_shifted_value, - fr w_2_shifted_value, - fr w_3_shifted_value, - fr w_4_shifted_value, - fr alpha_base, - fr alpha, - fr eta) +inline fr UltraCircuitConstructor::compute_auxilary_identity(fr q_aux_value, + fr q_arith_value, + fr q_1_value, + fr q_2_value, + fr q_3_value, + fr q_4_value, + fr q_m_value, + fr q_c_value, + fr w_1_value, + fr w_2_value, + fr w_3_value, + fr w_4_value, + fr w_1_shifted_value, + fr w_2_shifted_value, + fr w_3_shifted_value, + fr w_4_shifted_value, + fr alpha_base, + fr alpha, + fr eta) const { constexpr barretenberg::fr LIMB_SIZE(uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS); // TODO(kesha): Replace with a constant defined in header @@ -2997,7 +2987,267 @@ inline fr compute_auxilary_identity(fr q_aux_value, * @return true * @return false */ -bool UltraCircuitConstructor::check_circuit() {} +bool UltraCircuitConstructor::check_circuit() +{ + bool result = true; + reset_circuit_in_the_head(); + in_the_head = true; + finalize_circuit(); + const fr arithmetic_base = fr::random_element(); + const fr elliptic_base = fr::random_element(); + const fr genperm_sort_base = fr::random_element(); + const fr auxillary_base = fr::random_element(); + const fr alpha = fr::random_element(); + const fr eta = fr::random_element(); + const fr eta_sqr = eta.sqr(); + // We need to update memory records + std::unordered_set memory_record_gates; + for (const auto& gate_idx : circuit_in_the_head.memory_read_records) { + memory_record_gates.insert(gate_idx); + circuit_in_the_head.variables[circuit_in_the_head.real_variable_index[w_4[gate_idx]]] = + circuit_in_the_head.variables[real_variable_index[w_l[gate_idx]]] + + circuit_in_the_head.variables[circuit_in_the_head.real_variable_index[w_r[gate_idx]]] * eta + + circuit_in_the_head.variables[circuit_in_the_head.real_variable_index[w_o[gate_idx]]] * eta_sqr; + } + for (const auto& gate_idx : circuit_in_the_head.memory_write_records) { + memory_record_gates.insert(gate_idx); + variables[real_variable_index[w_4[gate_idx]]] = variables[real_variable_index[w_l[gate_idx]]] + + variables[real_variable_index[w_r[gate_idx]]] * eta + + variables[real_variable_index[w_o[gate_idx]]] * eta_sqr; + } + + struct HashFrTuple { + const barretenberg::fr mult_const = barretenberg::fr(uint256_t(0x1337, 0x1336, 0x1335, 0x1334)); + const barretenberg::fr mc_sqr = mult_const.sqr(); + const barretenberg::fr mc_cube = mult_const * mc_sqr; + + public: + size_t operator()( + const std::tuple& entry) const + { + return (size_t)((std::get<0>(entry) + mult_const * std::get<1>(entry) + mc_sqr * std::get<2>(entry) + + mc_cube * std::get<3>(entry)) + .reduce_once() + .data[0]); + } + }; + + struct EqualFrTuple { + const barretenberg::fr mult_const = barretenberg::fr(uint256_t(0xdead, 0xbeef, 0xc0ff, 0xffee)); + const barretenberg::fr mc_sqr = mult_const.sqr(); + const barretenberg::fr mc_cube = mult_const * mc_sqr; + + public: + bool operator()( + const std::tuple& entry1, + const std::tuple& entry2) const + { + return entry1 == entry2; + } + }; + std::unordered_set, + HashFrTuple, + EqualFrTuple> + table_hash; + for (auto& table : lookup_tables) { + const fr table_index(table.table_index); + for (size_t i = 0; i < table.size; ++i) { + const auto components = + std::make_tuple(table.column_1[i], table.column_2[i], table.column_3[i], table_index); + table_hash.insert(components); + } + } + fr left_tag_product = fr::one(); + fr right_tag_product = fr::one(); + const fr tag_gamma = fr::random_element(); + std::unordered_set encountered_variables; + + auto update_tag_check_information = [&](size_t variable_index, fr value) { + size_t real_index = circuit_in_the_head.real_variable_index[variable_index]; + if (encountered_variables.contains(real_index)) { + return; + } + size_t tag_in = circuit_in_the_head.real_variable_tags[real_index]; + if (tag_in != DUMMY_TAG) { + size_t tag_out = circuit_in_the_head.tau.at((uint32_t)tag_in); + left_tag_product *= value + tag_gamma * fr(tag_in); + right_tag_product *= value + tag_gamma * fr(tag_out); + encountered_variables.insert(real_index); + } + }; + for (size_t i = 0; i < circuit_in_the_head.num_gates; i++) { + fr q_arith_value; + fr q_aux_value; + fr q_elliptic_value; + fr q_sort_value; + fr q_lookup_type_value; + fr q_1_value; + fr q_2_value; + fr q_3_value; + fr q_4_value; + fr q_m_value; + fr q_c_value; + + fr w_1_value; + fr w_2_value; + fr w_3_value; + fr w_4_value; + fr w_1_real_index; + fr w_2_real_index; + fr w_3_real_index; + fr w_4_real_index; + if (i < num_gates) { + q_arith_value = q_arith[i]; + q_aux_value = q_aux[i]; + q_elliptic_value = q_elliptic[i]; + q_sort_value = q_sort[i]; + q_lookup_type_value = q_lookup_type[i]; + q_1_value = q_1[i]; + q_2_value = q_2[i]; + q_3_value = q_3[i]; + q_4_value = q_4[i]; + q_m_value = q_m[i]; + q_c_value = q_c[i]; + w_1_value = get_variable(w_l[i]); + update_tag_check_information(w_l[i], w_1_value); + w_2_value = get_variable(w_r[i]); + update_tag_check_information(w_r[i], w_2_value); + w_3_value = get_variable(w_o[i]); + update_tag_check_information(w_o[i], w_3_value); + w_4_value = get_variable(w_4[i]); + update_tag_check_information(w_4[i], w_4_value); + + } else { + size_t offset = i - num_gates; + q_arith_value = circuit_in_the_head.q_arith[offset]; + q_aux_value = circuit_in_the_head.q_aux[offset]; + q_elliptic_value = circuit_in_the_head.q_elliptic[offset]; + q_sort_value = circuit_in_the_head.q_sort[offset]; + + q_lookup_type_value = circuit_in_the_head.q_lookup_type[i]; + q_1_value = circuit_in_the_head.q_1[offset]; + q_2_value = circuit_in_the_head.q_2[offset]; + q_3_value = circuit_in_the_head.q_3[offset]; + q_4_value = circuit_in_the_head.q_4[offset]; + q_m_value = circuit_in_the_head.q_m[offset]; + q_c_value = circuit_in_the_head.q_c[offset]; + w_1_value = get_variable(circuit_in_the_head.w_l[offset]); + update_tag_check_information(circuit_in_the_head.w_l[offset], w_1_value); + w_2_value = get_variable(circuit_in_the_head.w_r[offset]); + update_tag_check_information(circuit_in_the_head.w_r[offset], w_2_value); + w_3_value = get_variable(circuit_in_the_head.w_o[offset]); + update_tag_check_information(circuit_in_the_head.w_o[offset], w_3_value); + w_4_value = get_variable(circuit_in_the_head.w_4[offset]); + update_tag_check_information(circuit_in_the_head.w_4[offset], w_4_value); + } + if (memory_record_gates.contains(i)) { + w_4_value = w_1_value + eta * w_2_value + eta_sqr * w_3_value; + } + fr w_1_shifted_value; + fr w_2_shifted_value; + fr w_3_shifted_value; + fr w_4_shifted_value; + if (i < (num_gates - 1)) { + + w_1_shifted_value = get_variable(w_l[i + 1]); + w_2_shifted_value = get_variable(w_r[i + 1]); + w_3_shifted_value = get_variable(w_o[i + 1]); + w_4_shifted_value = get_variable(w_4[i + 1]); + } else if (i < (circuit_in_the_head.num_gates - 1)) { + + w_1_shifted_value = get_variable(circuit_in_the_head.w_l[i + 1]); + w_2_shifted_value = get_variable(circuit_in_the_head.w_r[i + 1]); + w_3_shifted_value = get_variable(circuit_in_the_head.w_o[i + 1]); + w_4_shifted_value = get_variable(circuit_in_the_head.w_4[i + 1]); + } else { + w_1_shifted_value = fr::zero(); + w_2_shifted_value = fr::zero(); + w_3_shifted_value = fr::zero(); + w_4_shifted_value = fr::zero(); + } + if (memory_record_gates.contains(i + 1)) { + w_4_shifted_value = w_1_shifted_value + eta * w_2_shifted_value + eta_sqr * w_3_shifted_value; + } + if (!compute_arithmetic_identity(q_arith_value, + q_1_value, + q_2_value, + q_3_value, + q_4_value, + q_m_value, + q_c_value, + w_1_value, + w_2_value, + w_3_value, + w_4_value, + w_1_shifted_value, + w_4_shifted_value, + arithmetic_base, + alpha) + .is_zero()) { + result = false; + break; + } + if (!compute_auxilary_identity(q_aux_value, + q_arith_value, + q_1_value, + q_2_value, + q_3_value, + q_4_value, + q_m_value, + q_c_value, + w_1_value, + w_2_value, + w_3_value, + w_4_value, + w_1_shifted_value, + w_2_shifted_value, + w_3_shifted_value, + w_4_shifted_value, + auxillary_base, + alpha, + eta) + .is_zero()) { + result = false; + break; + } + if (!compute_elliptic_identity(q_elliptic_value, + q_1_value, + q_3_value, + q_4_value, + w_2_value, + w_3_value, + w_1_shifted_value, + w_2_shifted_value, + w_3_shifted_value, + w_4_shifted_value, + elliptic_base, + alpha) + .is_zero()) { + result = false; + break; + } + if (!compute_genperm_sort_identity( + q_sort_value, w_1_value, w_2_value, w_3_value, w_4_value, w_1_shifted_value, genperm_sort_base, alpha) + .is_zero()) { + result = false; + break; + } + if (!q_lookup_type_value.is_zero()) { + if (!table_hash.contains(std::make_tuple(w_1_value + q_2_value * w_1_shifted_value, + w_2_value + q_m_value * w_2_shifted_value, + w_3_value + q_c_value * w_3_shifted_value, + q_3_value))) { + result = false; + break; + } + } + } + if (left_tag_product != right_tag_product) { + result = false; + } + in_the_head = false; + return result; +} // namespace proof_system /** * @brief Reset the circuit-in-the-head construction that we use for checking the correctness of the circuit diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp index b9ae561e98..e4502daed0 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp @@ -332,7 +332,7 @@ class UltraCircuitConstructor : public CircuitConstructorBase::add_variable(in); @@ -758,9 +758,9 @@ class UltraCircuitConstructor : public CircuitConstructorBase + +using namespace barretenberg; + +namespace { +auto& engine = numeric::random::get_debug_engine(); +} +namespace proof_system { +using plookup::ColumnIdx; +using plookup::MultiTableId; + +TEST(ultra_circuit_constructor, create_gates_from_plookup_accumulators) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + + barretenberg::fr input_value = fr::random_element(); + const fr input_hi = uint256_t(input_value).slice(126, 256); + const fr input_lo = uint256_t(input_value).slice(0, 126); + const auto input_hi_index = circuit_constructor.add_variable(input_hi); + const auto input_lo_index = circuit_constructor.add_variable(input_lo); + + const auto sequence_data_hi = plookup::get_lookup_accumulators(MultiTableId::PEDERSEN_LEFT_HI, input_hi); + const auto sequence_data_lo = plookup::get_lookup_accumulators(MultiTableId::PEDERSEN_LEFT_LO, input_lo); + + const auto lookup_witnesses_hi = circuit_constructor.create_gates_from_plookup_accumulators( + MultiTableId::PEDERSEN_LEFT_HI, sequence_data_hi, input_hi_index); + const auto lookup_witnesses_lo = circuit_constructor.create_gates_from_plookup_accumulators( + MultiTableId::PEDERSEN_LEFT_LO, sequence_data_lo, input_lo_index); + + std::vector expected_x; + std::vector expected_y; + + const size_t num_lookups_hi = + (128 + crypto::pedersen_hash::lookup::BITS_PER_TABLE) / crypto::pedersen_hash::lookup::BITS_PER_TABLE; + const size_t num_lookups_lo = 126 / crypto::pedersen_hash::lookup::BITS_PER_TABLE; + const size_t num_lookups = num_lookups_hi + num_lookups_lo; + + EXPECT_EQ(num_lookups_hi, lookup_witnesses_hi[ColumnIdx::C1].size()); + EXPECT_EQ(num_lookups_lo, lookup_witnesses_lo[ColumnIdx::C1].size()); + + std::vector expected_scalars; + expected_x.resize(num_lookups); + expected_y.resize(num_lookups); + expected_scalars.resize(num_lookups); + + { + const size_t num_rounds = (num_lookups + 1) / 2; + uint256_t bits(input_value); + + const auto mask = crypto::pedersen_hash::lookup::PEDERSEN_TABLE_SIZE - 1; + + for (size_t i = 0; i < num_rounds; ++i) { + const auto& table = crypto::pedersen_hash::lookup::get_table(i); + const size_t index = i * 2; + + uint64_t slice_a = ((bits >> (index * 9)) & mask).data[0]; + expected_x[index] = (table[(size_t)slice_a].x); + expected_y[index] = (table[(size_t)slice_a].y); + expected_scalars[index] = slice_a; + + if (i < 14) { + uint64_t slice_b = ((bits >> ((index + 1) * 9)) & mask).data[0]; + expected_x[index + 1] = (table[(size_t)slice_b].x); + expected_y[index + 1] = (table[(size_t)slice_b].y); + expected_scalars[index + 1] = slice_b; + } + } + } + + for (size_t i = num_lookups - 2; i < num_lookups; --i) { + expected_scalars[i] += (expected_scalars[i + 1] * crypto::pedersen_hash::lookup::PEDERSEN_TABLE_SIZE); + } + + size_t hi_shift = 126; + const fr hi_cumulative = circuit_constructor.get_variable(lookup_witnesses_hi[ColumnIdx::C1][0]); + for (size_t i = 0; i < num_lookups_lo; ++i) { + const fr hi_mult = fr(uint256_t(1) << hi_shift); + EXPECT_EQ(circuit_constructor.get_variable(lookup_witnesses_lo[ColumnIdx::C1][i]) + (hi_cumulative * hi_mult), + expected_scalars[i]); + EXPECT_EQ(circuit_constructor.get_variable(lookup_witnesses_lo[ColumnIdx::C2][i]), expected_x[i]); + EXPECT_EQ(circuit_constructor.get_variable(lookup_witnesses_lo[ColumnIdx::C3][i]), expected_y[i]); + hi_shift -= crypto::pedersen_hash::lookup::BITS_PER_TABLE; + } + + for (size_t i = 0; i < num_lookups_hi; ++i) { + EXPECT_EQ(circuit_constructor.get_variable(lookup_witnesses_hi[ColumnIdx::C1][i]), + expected_scalars[i + num_lookups_lo]); + EXPECT_EQ(circuit_constructor.get_variable(lookup_witnesses_hi[ColumnIdx::C2][i]), + expected_x[i + num_lookups_lo]); + EXPECT_EQ(circuit_constructor.get_variable(lookup_witnesses_hi[ColumnIdx::C3][i]), + expected_y[i + num_lookups_lo]); + } + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); +} +TEST(ultra_circuit_constructor, base_case) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + fr a = fr::one(); + circuit_constructor.add_public_variable(a); + bool result = circuit_constructor.check_circuit(); + EXPECT_EQ(result, true); +} +TEST(ultra_circuit_constructor, test_no_lookup_proof) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + + for (size_t i = 0; i < 16; ++i) { + for (size_t j = 0; j < 16; ++j) { + uint64_t left = static_cast(j); + uint64_t right = static_cast(i); + uint32_t left_idx = circuit_constructor.add_variable(fr(left)); + uint32_t right_idx = circuit_constructor.add_variable(fr(right)); + uint32_t result_idx = circuit_constructor.add_variable(fr(left ^ right)); + + uint32_t add_idx = + circuit_constructor.add_variable(fr(left) + fr(right) + circuit_constructor.get_variable(result_idx)); + circuit_constructor.create_big_add_gate( + { left_idx, right_idx, result_idx, add_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) }); + } + } + + bool result = circuit_constructor.check_circuit(); + EXPECT_EQ(result, true); +} +} // namespace proof_system \ No newline at end of file From aec6ac607c3a0e3f9f85d92c4b64c946322b56f5 Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Fri, 21 Apr 2023 14:38:59 +0000 Subject: [PATCH 04/11] Added comments and state checks --- .../ultra_circuit_constructor.cpp | 64 ++--- .../ultra_circuit_constructor.hpp | 218 +++++++++++++++++- .../ultra_circuit_constructor.test.cpp | 2 + 3 files changed, 255 insertions(+), 29 deletions(-) diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp index a906b835f8..26308acd4d 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp @@ -44,7 +44,7 @@ void UltraCircuitConstructor::finalize_circuit() * our circuit is finalised, and we must not to execute these functions again. */ bool switched_circuit_finalised = - (in_the_head && circuit_in_the_head.circuit_finalized) | (!in_the_head && circuit_finalised); + (in_the_head && circuit_in_the_head.circuit_finalised) | (!in_the_head && circuit_finalised); if (!switched_circuit_finalised) { process_non_native_field_multiplications(); process_ROM_arrays(public_inputs.size()); @@ -1903,8 +1903,9 @@ void UltraCircuitConstructor::create_sorted_RAM_gate(RamRecord& record) */ void UltraCircuitConstructor::create_final_sorted_RAM_gate(RamRecord& record, const size_t ram_array_size) { + ENABLE_ALL_IN_THE_HEAD_SWITCHES record.record_witness = add_variable(0); - record.gate_index = num_gates; + record.gate_index = switched_num_gates; create_big_add_gate({ record.index_witness, @@ -2982,7 +2983,10 @@ inline fr UltraCircuitConstructor::compute_auxilary_identity(fr q_aux_value, } /** - * @brief + * @brief Check that the circuit is correct in its current state + * + * @details The method switches the circuit to the "in-the-head" version, finalizes it, checks gates, lookups and + * permutations and then switches it back from the in-the-head version, discarding the updates * * @return true * @return false @@ -2990,9 +2994,12 @@ inline fr UltraCircuitConstructor::compute_auxilary_identity(fr q_aux_value, bool UltraCircuitConstructor::check_circuit() { bool result = true; - reset_circuit_in_the_head(); + // Put the circuit in the head + update_circuit_in_the_head(); in_the_head = true; + // Finalize circuit-in-the-head finalize_circuit(); + // Sample randomness const fr arithmetic_base = fr::random_element(); const fr elliptic_base = fr::random_element(); const fr genperm_sort_base = fr::random_element(); @@ -3000,28 +3007,22 @@ bool UltraCircuitConstructor::check_circuit() const fr alpha = fr::random_element(); const fr eta = fr::random_element(); const fr eta_sqr = eta.sqr(); - // We need to update memory records + + // We need to get all memory std::unordered_set memory_record_gates; for (const auto& gate_idx : circuit_in_the_head.memory_read_records) { memory_record_gates.insert(gate_idx); - circuit_in_the_head.variables[circuit_in_the_head.real_variable_index[w_4[gate_idx]]] = - circuit_in_the_head.variables[real_variable_index[w_l[gate_idx]]] + - circuit_in_the_head.variables[circuit_in_the_head.real_variable_index[w_r[gate_idx]]] * eta + - circuit_in_the_head.variables[circuit_in_the_head.real_variable_index[w_o[gate_idx]]] * eta_sqr; } for (const auto& gate_idx : circuit_in_the_head.memory_write_records) { memory_record_gates.insert(gate_idx); - variables[real_variable_index[w_4[gate_idx]]] = variables[real_variable_index[w_l[gate_idx]]] + - variables[real_variable_index[w_r[gate_idx]]] * eta + - variables[real_variable_index[w_o[gate_idx]]] * eta_sqr; } + // A hashing implementation for quick simulation lookups struct HashFrTuple { const barretenberg::fr mult_const = barretenberg::fr(uint256_t(0x1337, 0x1336, 0x1335, 0x1334)); const barretenberg::fr mc_sqr = mult_const.sqr(); const barretenberg::fr mc_cube = mult_const * mc_sqr; - public: size_t operator()( const std::tuple& entry) const { @@ -3032,12 +3033,9 @@ bool UltraCircuitConstructor::check_circuit() } }; + // Equality checks for lookup tuples struct EqualFrTuple { - const barretenberg::fr mult_const = barretenberg::fr(uint256_t(0xdead, 0xbeef, 0xc0ff, 0xffee)); - const barretenberg::fr mc_sqr = mult_const.sqr(); - const barretenberg::fr mc_cube = mult_const * mc_sqr; - public: bool operator()( const std::tuple& entry1, const std::tuple& entry2) const @@ -3045,10 +3043,12 @@ bool UltraCircuitConstructor::check_circuit() return entry1 == entry2; } }; + // The set of all lookup tuples that are in the tables std::unordered_set, HashFrTuple, EqualFrTuple> table_hash; + // Prepare the lookup set for use in the circuit for (auto& table : lookup_tables) { const fr table_index(table.table_index); for (size_t i = 0; i < table.size; ++i) { @@ -3057,13 +3057,21 @@ bool UltraCircuitConstructor::check_circuit() table_hash.insert(components); } } + + // We use a running tag product mechanism to ensure tag correctness + // This is the product of (value + γ ⋅ tag) fr left_tag_product = fr::one(); + // This is the product of (value + γ ⋅ tau[tag]) fr right_tag_product = fr::one(); + // Randomness for the tag check const fr tag_gamma = fr::random_element(); + // We need to include each variable only once std::unordered_set encountered_variables; + // Function to quickly update tag products and encountered variable set by index and value auto update_tag_check_information = [&](size_t variable_index, fr value) { size_t real_index = circuit_in_the_head.real_variable_index[variable_index]; + // Check to ensure that we are not including a variable twice if (encountered_variables.contains(real_index)) { return; } @@ -3075,6 +3083,7 @@ bool UltraCircuitConstructor::check_circuit() encountered_variables.insert(real_index); } }; + // For each gate for (size_t i = 0; i < circuit_in_the_head.num_gates; i++) { fr q_arith_value; fr q_aux_value; @@ -3087,7 +3096,6 @@ bool UltraCircuitConstructor::check_circuit() fr q_4_value; fr q_m_value; fr q_c_value; - fr w_1_value; fr w_2_value; fr w_3_value; @@ -3096,6 +3104,7 @@ bool UltraCircuitConstructor::check_circuit() fr w_2_real_index; fr w_3_real_index; fr w_4_real_index; + // Get the values of selectors and wires and update tag products along the way if (i < num_gates) { q_arith_value = q_arith[i]; q_aux_value = q_aux[i]; @@ -3118,12 +3127,13 @@ bool UltraCircuitConstructor::check_circuit() update_tag_check_information(w_4[i], w_4_value); } else { + // The in-the-head selector and wire variable indices are not copies of the circuit values, but rather the + // continuation of them, so we need to access them at an offset size_t offset = i - num_gates; q_arith_value = circuit_in_the_head.q_arith[offset]; q_aux_value = circuit_in_the_head.q_aux[offset]; q_elliptic_value = circuit_in_the_head.q_elliptic[offset]; q_sort_value = circuit_in_the_head.q_sort[offset]; - q_lookup_type_value = circuit_in_the_head.q_lookup_type[i]; q_1_value = circuit_in_the_head.q_1[offset]; q_2_value = circuit_in_the_head.q_2[offset]; @@ -3140,6 +3150,7 @@ bool UltraCircuitConstructor::check_circuit() w_4_value = get_variable(circuit_in_the_head.w_4[offset]); update_tag_check_information(circuit_in_the_head.w_4[offset], w_4_value); } + // If we are touching a gate with memory access, we need to update the value of the 4th witness if (memory_record_gates.contains(i)) { w_4_value = w_1_value + eta * w_2_value + eta_sqr * w_3_value; } @@ -3247,13 +3258,14 @@ bool UltraCircuitConstructor::check_circuit() } in_the_head = false; return result; -} // namespace proof_system +} /** - * @brief Reset the circuit-in-the-head construction that we use for checking the correctness of the circuit + * @brief Reset the circuit-in-the-head construction that we use for checking the correctness of the circuit to the + * values in the circuit * */ -void UltraCircuitConstructor::reset_circuit_in_the_head() +void UltraCircuitConstructor::update_circuit_in_the_head() { // Unfortunately we have to copy all variable structures circuit_in_the_head.public_inputs = public_inputs; @@ -3281,18 +3293,18 @@ void UltraCircuitConstructor::reset_circuit_in_the_head() // Update current tag in the head to be the same as current real tag circuit_in_the_head.current_tag = current_tag; // Reset tau - circuit_in_the_head.tau.clear(); + circuit_in_the_head.tau = tau; // Copy rom and ram arrays circuit_in_the_head.rom_arrays = rom_arrays; circuit_in_the_head.ram_arrays = ram_arrays; - circuit_in_the_head.memory_read_records.clear(); - circuit_in_the_head.memory_write_records.clear(); + circuit_in_the_head.memory_read_records = memory_read_records; + circuit_in_the_head.memory_write_records = memory_write_records; circuit_in_the_head.ram_arrays = ram_arrays; circuit_in_the_head.rom_arrays = rom_arrays; circuit_in_the_head.range_lists = range_lists; circuit_in_the_head.num_gates = num_gates; - circuit_finalised = false; + circuit_in_the_head.circuit_finalised = circuit_finalised; } } // namespace proof_system \ No newline at end of file diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp index e4502daed0..1e4366e57e 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp @@ -12,7 +12,6 @@ #include namespace proof_system { - static constexpr ComposerType type = ComposerType::PLOOKUP; static constexpr merkle::HashType merkle_hash_type = merkle::HashType::LOOKUP_PEDERSEN; static constexpr size_t NUM_RESERVED_GATES = 4; // This must be >= num_roots_cut_out_of_vanishing_polynomial @@ -120,6 +119,11 @@ struct RangeList { uint32_t range_tag; uint32_t tau_tag; std::vector variable_indices; + bool operator==(const RangeList& other) const noexcept + { + return target_range == other.target_range && range_tag == other.range_tag && tau_tag == other.tau_tag && + variable_indices == other.variable_indices; + } }; /** @@ -135,6 +139,12 @@ struct RomRecord { uint32_t record_witness = 0; size_t gate_index = 0; bool operator<(const RomRecord& other) const { return index < other.index; } + bool operator==(const RomRecord& other) const noexcept + { + return index_witness == other.index_witness && value_column1_witness == other.value_column1_witness && + value_column2_witness == other.value_column2_witness && index == other.index && + record_witness == other.record_witness && gate_index == other.gate_index; + } }; /** @@ -160,6 +170,13 @@ struct RamRecord { bool index_test = (index) < (other.index); return index_test || (index == other.index && timestamp < other.timestamp); } + bool operator==(const RamRecord& other) const noexcept + { + return index_witness == other.index_witness && timestamp_witness == other.timestamp_witness && + value_witness == other.value_witness && index == other.index && timestamp == other.timestamp && + access_type == other.access_type && record_witness == other.record_witness && + gate_index == other.gate_index; + } }; /** @@ -180,6 +197,11 @@ struct RamTranscript { // used for RAM records, to compute the timestamp when performing a read/write size_t access_count = 0; + // Used to check that the state hasn't changed in tests + bool operator==(const RamTranscript& other) const noexcept + { + return (state == other.state && records == other.records && access_count == other.access_count); + } }; /** @@ -197,6 +219,12 @@ struct RomTranscript { // + The value in the memory slot // + The actual index value std::vector records; + + // Used to check that the state hasn't changed in tests + bool operator==(const RomTranscript& other) const noexcept + { + return (state == other.state && records == other.records); + } }; inline std::vector ultra_selector_names() @@ -206,6 +234,14 @@ inline std::vector ultra_selector_names() return result; } +/** + * @brief Circuit-in-the-head is a structure we use to store all the information about the circuit which should be used + * during check_circuit method call, but needs to be discarded later + * + * @details In check_circuit method in UltraCircuitConstructor we want to check that the whole circuit works, but ultra + * circuits need to have ram, rom and range gates added in the end for the check to be complete as well as the set + * permutation check. + */ struct CircuitInTheHead { std::vector public_inputs; std::vector variables; @@ -242,10 +278,167 @@ struct CircuitInTheHead { std::vector memory_write_records; std::map range_lists; size_t num_gates; - bool circuit_finalized = false; + bool circuit_finalised = false; + /** + * @brief Stores the state of everything logic-related in the constructor. + * + * @details We need this function for tests. Specifically, to ensure that we are not changing anything in + * check_circuit + * + * @param circuit_constructor + * @return CircuitInTheHead + */ + template + static CircuitInTheHead store_state(const CircuitConstructor& circuit_constructor) + { + CircuitInTheHead stored_state; + stored_state.public_inputs = circuit_constructor.public_inputs; + stored_state.variables = circuit_constructor.variables; + + stored_state.next_var_index = circuit_constructor.next_var_index; + + stored_state.prev_var_index = circuit_constructor.prev_var_index; + + stored_state.real_variable_index = circuit_constructor.real_variable_index; + stored_state.real_variable_tags = circuit_constructor.real_variable_tags; + stored_state.constant_variable_indices = circuit_constructor.constant_variable_indices; + stored_state.w_l = circuit_constructor.w_l; + stored_state.w_r = circuit_constructor.w_r; + stored_state.w_o = circuit_constructor.w_o; + stored_state.w_4 = circuit_constructor.w_4; + stored_state.q_m = circuit_constructor.q_m; + stored_state.q_c = circuit_constructor.q_c; + stored_state.q_1 = circuit_constructor.q_1; + stored_state.q_2 = circuit_constructor.q_2; + stored_state.q_3 = circuit_constructor.q_3; + stored_state.q_4 = circuit_constructor.q_4; + stored_state.q_arith = circuit_constructor.q_arith; + stored_state.q_sort = circuit_constructor.q_sort; + stored_state.q_elliptic = circuit_constructor.q_elliptic; + stored_state.q_aux = circuit_constructor.q_aux; + stored_state.q_lookup_type = circuit_constructor.q_lookup_type; + stored_state.current_tag = circuit_constructor.current_tag; + stored_state.tau = circuit_constructor.tau; + + stored_state.ram_arrays = circuit_constructor.ram_arrays; + stored_state.rom_arrays = circuit_constructor.rom_arrays; + + stored_state.memory_read_records = circuit_constructor.memory_read_records; + stored_state.memory_write_records = circuit_constructor.memory_write_records; + stored_state.range_lists = circuit_constructor.range_lists; + stored_state.circuit_finalised = circuit_constructor.circuit_finalised; + stored_state.num_gates = circuit_constructor.num_gates; + return stored_state; + } + /** + * @brief CHecks that the circuit states is the same as the stored circuit's one + * + * @param circuit_constructor + * @return true + * @return false + */ + template bool is_same_state(const CircuitConstructor& circuit_constructor) + { + if (!(public_inputs == circuit_constructor.public_inputs)) { + return false; + } + if (!(variables == circuit_constructor.variables)) { + return false; + } + if (!(next_var_index == circuit_constructor.next_var_index)) { + return false; + } + if (!(prev_var_index == circuit_constructor.prev_var_index)) { + return false; + } + if (!(real_variable_index == circuit_constructor.real_variable_index)) { + return false; + } + if (!(real_variable_tags == circuit_constructor.real_variable_tags)) { + return false; + } + if (!(constant_variable_indices == circuit_constructor.constant_variable_indices)) { + return false; + } + if (!(w_l == circuit_constructor.w_l)) { + return false; + } + if (!(w_r == circuit_constructor.w_r)) { + return false; + } + if (!(w_o == circuit_constructor.w_o)) { + return false; + } + if (!(w_4 == circuit_constructor.w_4)) { + return false; + } + if (!(q_m == circuit_constructor.q_m)) { + return false; + } + if (!(q_c == circuit_constructor.q_c)) { + return false; + } + if (!(q_1 == circuit_constructor.q_1)) { + return false; + } + if (!(q_2 == circuit_constructor.q_2)) { + return false; + } + if (!(q_3 == circuit_constructor.q_3)) { + return false; + } + if (!(q_4 == circuit_constructor.q_4)) { + return false; + } + if (!(q_arith == circuit_constructor.q_arith)) { + return false; + } + if (!(q_sort == circuit_constructor.q_sort)) { + return false; + } + if (!(q_elliptic == circuit_constructor.q_elliptic)) { + return false; + } + if (!(q_aux == circuit_constructor.q_aux)) { + return false; + } + if (!(q_lookup_type == circuit_constructor.q_lookup_type)) { + return false; + } + if (!(current_tag == circuit_constructor.current_tag)) { + return false; + } + if (!(tau == circuit_constructor.tau)) { + return false; + } + if (!(ram_arrays == circuit_constructor.ram_arrays)) { + return false; + } + if (!(rom_arrays == circuit_constructor.rom_arrays)) { + return false; + } + if (!(memory_read_records == circuit_constructor.memory_read_records)) { + return false; + } + if (!(memory_write_records == circuit_constructor.memory_write_records)) { + return false; + } + if (!(range_lists == circuit_constructor.range_lists)) { + return false; + } + if (!(num_gates == circuit_constructor.num_gates)) { + return false; + } + if (!(circuit_finalised == circuit_constructor.circuit_finalised)) { + return false; + } + return true; + } }; class UltraCircuitConstructor : public CircuitConstructorBase { public: + // We use the concept of "Circuit-in-the-head" for the check_circuit method. We have to finalize the circuit to + // check it, so we put all the updates in this structure, instead of messing with the circuit itself CircuitInTheHead circuit_in_the_head; // Switch, forcing gates to interact with circuit_in_the_head instead of the regular members bool in_the_head = false; @@ -349,6 +542,12 @@ class UltraCircuitConstructor : public CircuitConstructorBase index); return circuit_in_the_head.variables[circuit_in_the_head.real_variable_index[index]]; } + + /** + * @brief Check that variable indices are valid + * + * @param variable_indices + */ void assert_valid_variables(const std::vector& variable_indices) { for (const auto& variable_index : variable_indices) { ASSERT(is_valid_variable(variable_index)); } } + /** + * @brief Checks that the variable index is valid (in the circuit or in the in-the-head circuit) + * + * @param variable_index + * @return true + * @return false + */ bool is_valid_variable(uint32_t variable_index) { if (in_the_head) { @@ -845,7 +1057,7 @@ class UltraCircuitConstructor : public CircuitConstructorBase Date: Fri, 21 Apr 2023 16:52:08 +0000 Subject: [PATCH 05/11] Move plookup tables into proof_system --- .../barretenberg/honk/composer/ultra_honk_composer.hpp | 2 +- .../plonk/composer/splitting_tmp/ultra_plonk_composer.hpp | 2 +- cpp/src/barretenberg/plonk/composer/ultra_composer.cpp | 8 ++++---- cpp/src/barretenberg/plonk/composer/ultra_composer.hpp | 2 +- .../barretenberg/plonk/composer/ultra_composer.test.cpp | 2 +- cpp/src/barretenberg/proof_system/CMakeLists.txt | 2 +- .../circuit_constructors/ultra_circuit_constructor.hpp | 4 ++-- .../composer => proof_system}/plookup_tables/aes128.hpp | 0 .../composer => proof_system}/plookup_tables/blake2s.hpp | 0 .../plookup_tables/keccak/keccak_chi.hpp | 0 .../plookup_tables/keccak/keccak_input.hpp | 0 .../plookup_tables/keccak/keccak_output.hpp | 0 .../plookup_tables/keccak/keccak_rho.hpp | 0 .../plookup_tables/keccak/keccak_theta.hpp | 0 .../plookup_tables/non_native_group_generator.cpp | 0 .../plookup_tables/non_native_group_generator.hpp | 0 .../composer => proof_system}/plookup_tables/pedersen.hpp | 0 .../plookup_tables/plookup_tables.cpp | 0 .../plookup_tables/plookup_tables.hpp | 0 .../composer => proof_system}/plookup_tables/sha256.hpp | 0 .../composer => proof_system}/plookup_tables/sparse.hpp | 0 .../composer => proof_system}/plookup_tables/types.hpp | 0 .../composer => proof_system}/plookup_tables/uint.hpp | 0 .../stdlib/commitment/pedersen/pedersen_plookup.cpp | 2 +- .../barretenberg/stdlib/hash/blake2s/blake2s_plookup.cpp | 4 ++-- .../barretenberg/stdlib/hash/blake2s/blake2s_plookup.hpp | 2 +- cpp/src/barretenberg/stdlib/hash/blake2s/blake_util.hpp | 2 +- .../barretenberg/stdlib/hash/blake3s/blake3s_plookup.cpp | 2 +- .../barretenberg/stdlib/hash/blake3s/blake3s_plookup.hpp | 2 +- .../stdlib/hash/pedersen/pedersen_plookup.cpp | 2 +- cpp/src/barretenberg/stdlib/hash/sha256/sha256.test.cpp | 2 +- .../barretenberg/stdlib/hash/sha256/sha256_plookup.cpp | 4 ++-- .../barretenberg/stdlib/hash/sha256/sha256_plookup.hpp | 2 +- .../barretenberg/stdlib/primitives/plookup/plookup.cpp | 4 ++-- .../barretenberg/stdlib/primitives/plookup/plookup.hpp | 4 ++-- 35 files changed, 27 insertions(+), 27 deletions(-) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/aes128.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/blake2s.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/keccak/keccak_chi.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/keccak/keccak_input.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/keccak/keccak_output.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/keccak/keccak_rho.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/keccak/keccak_theta.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/non_native_group_generator.cpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/non_native_group_generator.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/pedersen.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/plookup_tables.cpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/plookup_tables.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/sha256.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/sparse.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/types.hpp (100%) rename cpp/src/barretenberg/{plonk/composer => proof_system}/plookup_tables/uint.hpp (100%) diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp index f2eb030039..4e5169c558 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp @@ -1,5 +1,5 @@ #pragma once -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include "barretenberg/honk/proof_system/ultra_prover.hpp" #include "barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp" #include "barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.hpp" diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp index dd51d0aa3d..3f5843fdf5 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp @@ -1,6 +1,6 @@ #pragma once #include "barretenberg/plonk/composer/composer_base.hpp" -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include "barretenberg/plonk/proof_system/prover/prover.hpp" #include "barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp" #include "barretenberg/proof_system/types/merkle_hash_type.hpp" diff --git a/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp b/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp index a160f79bb0..1f3e9fb3ed 100644 --- a/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp +++ b/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp @@ -14,10 +14,10 @@ #include "barretenberg/plonk/proof_system/commitment_scheme/kate_commitment_scheme.hpp" #include "barretenberg/srs/reference_string/file_reference_string.hpp" -#include "plookup_tables/types.hpp" -#include "plookup_tables/plookup_tables.hpp" -#include "plookup_tables/aes128.hpp" -#include "plookup_tables/sha256.hpp" +#include "barretenberg/proof_system/plookup_tables/types.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/aes128.hpp" +#include "barretenberg/proof_system/plookup_tables/sha256.hpp" #ifndef NO_TBB #include diff --git a/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp b/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp index d8988e3fca..6f22b40bb0 100644 --- a/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp +++ b/cpp/src/barretenberg/plonk/composer/ultra_composer.hpp @@ -2,7 +2,7 @@ #include "composer_base.hpp" #include "barretenberg/proof_system/types/merkle_hash_type.hpp" #include "barretenberg/proof_system/types/pedersen_commitment_type.hpp" -#include "plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include namespace proof_system::plonk { diff --git a/cpp/src/barretenberg/plonk/composer/ultra_composer.test.cpp b/cpp/src/barretenberg/plonk/composer/ultra_composer.test.cpp index 9745d397e2..0ec324aa47 100644 --- a/cpp/src/barretenberg/plonk/composer/ultra_composer.test.cpp +++ b/cpp/src/barretenberg/plonk/composer/ultra_composer.test.cpp @@ -5,7 +5,7 @@ #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/numeric/uintx/uintx.hpp" #include "../proof_system/widgets/random_widgets/plookup_widget.hpp" -#include "./plookup_tables/sha256.hpp" +#include "barretenberg/proof_system/plookup_tables/sha256.hpp" using namespace barretenberg; using namespace proof_system; diff --git a/cpp/src/barretenberg/proof_system/CMakeLists.txt b/cpp/src/barretenberg/proof_system/CMakeLists.txt index ec894c6748..c4e00489ca 100644 --- a/cpp/src/barretenberg/proof_system/CMakeLists.txt +++ b/cpp/src/barretenberg/proof_system/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(proof_system polynomials crypto_generators plonk) \ No newline at end of file +barretenberg_module(proof_system polynomials crypto_generators crypto_pedersen_hash) \ No newline at end of file diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp index 1e4366e57e..94c4ab6e9c 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp @@ -6,8 +6,8 @@ #include "barretenberg/proof_system/flavor/flavor.hpp" #include "barretenberg/proof_system/types/merkle_hash_type.hpp" #include "barretenberg/polynomials/polynomial.hpp" -#include "barretenberg/plonk/composer/plookup_tables/types.hpp" -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/types.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include "barretenberg/plonk/proof_system/types/prover_settings.hpp" #include diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/aes128.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/aes128.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/aes128.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/aes128.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/blake2s.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/blake2s.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/blake2s.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/blake2s.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/keccak/keccak_chi.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/keccak/keccak_chi.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/keccak/keccak_chi.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/keccak/keccak_chi.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/keccak/keccak_input.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/keccak/keccak_input.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/keccak/keccak_input.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/keccak/keccak_input.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/keccak/keccak_output.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/keccak/keccak_output.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/keccak/keccak_output.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/keccak/keccak_output.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/keccak/keccak_rho.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/keccak/keccak_rho.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/keccak/keccak_rho.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/keccak/keccak_rho.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/keccak/keccak_theta.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/keccak/keccak_theta.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/keccak/keccak_theta.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/keccak/keccak_theta.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/non_native_group_generator.cpp b/cpp/src/barretenberg/proof_system/plookup_tables/non_native_group_generator.cpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/non_native_group_generator.cpp rename to cpp/src/barretenberg/proof_system/plookup_tables/non_native_group_generator.cpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/non_native_group_generator.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/non_native_group_generator.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/non_native_group_generator.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/non_native_group_generator.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/pedersen.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/pedersen.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/pedersen.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/pedersen.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/plookup_tables.cpp b/cpp/src/barretenberg/proof_system/plookup_tables/plookup_tables.cpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/plookup_tables.cpp rename to cpp/src/barretenberg/proof_system/plookup_tables/plookup_tables.cpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/plookup_tables.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/plookup_tables.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/sha256.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/sha256.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/sha256.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/sha256.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/sparse.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/sparse.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/sparse.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/sparse.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/types.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/types.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/types.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/types.hpp diff --git a/cpp/src/barretenberg/plonk/composer/plookup_tables/uint.hpp b/cpp/src/barretenberg/proof_system/plookup_tables/uint.hpp similarity index 100% rename from cpp/src/barretenberg/plonk/composer/plookup_tables/uint.hpp rename to cpp/src/barretenberg/proof_system/plookup_tables/uint.hpp diff --git a/cpp/src/barretenberg/stdlib/commitment/pedersen/pedersen_plookup.cpp b/cpp/src/barretenberg/stdlib/commitment/pedersen/pedersen_plookup.cpp index 7d3bdc0950..70b84e515e 100644 --- a/cpp/src/barretenberg/stdlib/commitment/pedersen/pedersen_plookup.cpp +++ b/cpp/src/barretenberg/stdlib/commitment/pedersen/pedersen_plookup.cpp @@ -3,7 +3,7 @@ #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include "../../hash/pedersen/pedersen_plookup.hpp" -#include "barretenberg/plonk/composer/plookup_tables/types.hpp" +#include "barretenberg/proof_system/plookup_tables/types.hpp" #include "../../primitives/composers/composers.hpp" #include "../../primitives/plookup/plookup.hpp" diff --git a/cpp/src/barretenberg/stdlib/hash/blake2s/blake2s_plookup.cpp b/cpp/src/barretenberg/stdlib/hash/blake2s/blake2s_plookup.cpp index 3fad189ef2..d7f4176f7d 100644 --- a/cpp/src/barretenberg/stdlib/hash/blake2s/blake2s_plookup.cpp +++ b/cpp/src/barretenberg/stdlib/hash/blake2s/blake2s_plookup.cpp @@ -1,8 +1,8 @@ #include "blake2s_plookup.hpp" #include "blake_util.hpp" -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" -#include "barretenberg/plonk/composer/plookup_tables/sha256.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/sha256.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" #include "barretenberg/stdlib/primitives/bit_array/bit_array.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" diff --git a/cpp/src/barretenberg/stdlib/hash/blake2s/blake2s_plookup.hpp b/cpp/src/barretenberg/stdlib/hash/blake2s/blake2s_plookup.hpp index a729018f9f..008b98cd86 100644 --- a/cpp/src/barretenberg/stdlib/hash/blake2s/blake2s_plookup.hpp +++ b/cpp/src/barretenberg/stdlib/hash/blake2s/blake2s_plookup.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include "barretenberg/stdlib/primitives/uint/uint.hpp" #include "barretenberg/numeric/bitop/sparse_form.hpp" diff --git a/cpp/src/barretenberg/stdlib/hash/blake2s/blake_util.hpp b/cpp/src/barretenberg/stdlib/hash/blake2s/blake_util.hpp index fe7650bbb5..884387bedf 100644 --- a/cpp/src/barretenberg/stdlib/hash/blake2s/blake_util.hpp +++ b/cpp/src/barretenberg/stdlib/hash/blake2s/blake_util.hpp @@ -3,7 +3,7 @@ #include "barretenberg/plonk/composer/ultra_composer.hpp" #include "barretenberg/stdlib/primitives/uint/uint.hpp" #include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp" -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include "barretenberg/stdlib/primitives/plookup/plookup.hpp" namespace proof_system::plonk { diff --git a/cpp/src/barretenberg/stdlib/hash/blake3s/blake3s_plookup.cpp b/cpp/src/barretenberg/stdlib/hash/blake3s/blake3s_plookup.cpp index 3253483722..ffa904e3ce 100644 --- a/cpp/src/barretenberg/stdlib/hash/blake3s/blake3s_plookup.cpp +++ b/cpp/src/barretenberg/stdlib/hash/blake3s/blake3s_plookup.cpp @@ -1,7 +1,7 @@ #include "blake3s_plookup.hpp" #include "../blake2s/blake_util.hpp" -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" #include "barretenberg/stdlib/primitives/bit_array/bit_array.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" diff --git a/cpp/src/barretenberg/stdlib/hash/blake3s/blake3s_plookup.hpp b/cpp/src/barretenberg/stdlib/hash/blake3s/blake3s_plookup.hpp index 789c0b96bf..e82a9cad9d 100644 --- a/cpp/src/barretenberg/stdlib/hash/blake3s/blake3s_plookup.hpp +++ b/cpp/src/barretenberg/stdlib/hash/blake3s/blake3s_plookup.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include "barretenberg/stdlib/primitives/uint/uint.hpp" #include "barretenberg/numeric/bitop/sparse_form.hpp" diff --git a/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen_plookup.cpp b/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen_plookup.cpp index d55161447a..f451a2b573 100644 --- a/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen_plookup.cpp +++ b/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen_plookup.cpp @@ -2,7 +2,7 @@ #include "barretenberg/crypto/pedersen_hash/pedersen.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" -#include "barretenberg/plonk/composer/plookup_tables/types.hpp" +#include "barretenberg/proof_system/plookup_tables/types.hpp" #include "../../primitives/composers/composers.hpp" #include "../../primitives/plookup/plookup.hpp" diff --git a/cpp/src/barretenberg/stdlib/hash/sha256/sha256.test.cpp b/cpp/src/barretenberg/stdlib/hash/sha256/sha256.test.cpp index 8f9952da34..8589866b6d 100644 --- a/cpp/src/barretenberg/stdlib/hash/sha256/sha256.test.cpp +++ b/cpp/src/barretenberg/stdlib/hash/sha256/sha256.test.cpp @@ -4,7 +4,7 @@ #include "barretenberg/plonk/composer/standard_composer.hpp" #include "barretenberg/plonk/composer/turbo_composer.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/numeric/bitop/rotate.hpp" diff --git a/cpp/src/barretenberg/stdlib/hash/sha256/sha256_plookup.cpp b/cpp/src/barretenberg/stdlib/hash/sha256/sha256_plookup.cpp index 04a5632eab..7b611e8ee6 100644 --- a/cpp/src/barretenberg/stdlib/hash/sha256/sha256_plookup.cpp +++ b/cpp/src/barretenberg/stdlib/hash/sha256/sha256_plookup.cpp @@ -1,7 +1,7 @@ #include "sha256_plookup.hpp" -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" -#include "barretenberg/plonk/composer/plookup_tables/sha256.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/sha256.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" #include "barretenberg/stdlib/primitives/bit_array/bit_array.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" diff --git a/cpp/src/barretenberg/stdlib/hash/sha256/sha256_plookup.hpp b/cpp/src/barretenberg/stdlib/hash/sha256/sha256_plookup.hpp index b1801ad2b7..aa16ff32fd 100644 --- a/cpp/src/barretenberg/stdlib/hash/sha256/sha256_plookup.hpp +++ b/cpp/src/barretenberg/stdlib/hash/sha256/sha256_plookup.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include "barretenberg/stdlib/primitives/uint/uint.hpp" #include "barretenberg/plonk/composer/composer_base.hpp" diff --git a/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.cpp b/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.cpp index ac251c7081..9c60d61752 100644 --- a/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.cpp +++ b/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.cpp @@ -1,7 +1,7 @@ #include "./plookup.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" -#include "barretenberg/plonk/composer/plookup_tables/types.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/types.hpp" namespace proof_system::plonk { class UltraComposer; diff --git a/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.hpp b/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.hpp index b178032b10..8e14806b4c 100644 --- a/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.hpp +++ b/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.hpp @@ -1,9 +1,9 @@ #pragma once #include #include -#include "barretenberg/plonk/composer/plookup_tables/plookup_tables.hpp" +#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" -#include "barretenberg/plonk/composer/plookup_tables/types.hpp" +#include "barretenberg/proof_system/plookup_tables/types.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" namespace proof_system::plonk { From 8fe3463ee784f101333c04a7f4d2eac041a4612d Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Fri, 21 Apr 2023 22:05:23 +0000 Subject: [PATCH 06/11] All the standard tests are working with check_circuit --- .../ultra_circuit_constructor.cpp | 123 +++- .../ultra_circuit_constructor.hpp | 13 +- .../ultra_circuit_constructor.test.cpp | 669 ++++++++++++++++++ 3 files changed, 779 insertions(+), 26 deletions(-) diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp index 26308acd4d..947d2529ac 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp @@ -1,11 +1,10 @@ /** * @file ultra_circuit_constructor.cpp - * @author Luke (ledwards2225) and Kesha (Rumata888) (you@domain.com) + * @author Luke (ledwards2225) and Kesha (Rumata888) * @brief This file contains the implementation of UltraCircuitConstructor class that defines the logic of ultra-style * circuits and is intended for the use in UltraHonk and UltraPlonk systems * * @todo 1) Replace barretenberg::fr with templated FF or Field - * @todo 2) See the inefficiency in auxilary gate. Delete extra LIMB multiplication and see if something breaks * */ #include "ultra_circuit_constructor.hpp" @@ -655,6 +654,7 @@ void UltraCircuitConstructor::create_new_range_constraint(const uint32_t variabl std::string const msg) { ENABLE_ALL_IN_THE_HEAD_SWITCHES + if (uint256_t(get_variable(variable_index)).data[0] > target_range) { if (!failed()) { failure(msg); @@ -664,9 +664,44 @@ void UltraCircuitConstructor::create_new_range_constraint(const uint32_t variabl switched_range_lists.insert({ target_range, create_range_list(target_range) }); } + const auto existing_tag = switched_real_variable_tags[switched_real_variable_index[variable_index]]; auto& list = switched_range_lists[target_range]; - assign_tag(variable_index, list.range_tag); - list.variable_indices.emplace_back(variable_index); + + // If the variable's tag matches the target range list's tag, do nothing. + if (existing_tag != list.range_tag) { + // If the variable is 'untagged' (i.e., it has the dummy tag), assign it the appropriate tag. + // Otherwise, find the range for which the variable has already been tagged. + if (existing_tag != DUMMY_TAG) { + bool found_tag = false; + for (const auto& r : range_lists) { + if (r.second.range_tag == existing_tag) { + found_tag = true; + if (r.first < target_range) { + // The variable already has a more restrictive range check, so do nothing. + return; + } else { + // The range constraint we are trying to impose is more restrictive than the existing range + // constraint. It would be difficult to remove an existing range check. Instead deep-copy the + // variable and apply a range check to new variable + const uint32_t copied_witness = add_variable(get_variable(variable_index)); + create_add_gate({ .a = variable_index, + .b = copied_witness, + .c = zero_idx, + .a_scaling = 1, + .b_scaling = -1, + .c_scaling = 0, + .const_scaling = 0 }); + // Recurse with new witness that has no tag attached. + create_new_range_constraint(copied_witness, target_range, msg); + return; + } + } + } + ASSERT(found_tag == true); + } + assign_tag(variable_index, list.range_tag); + list.variable_indices.emplace_back(variable_index); + } } void UltraCircuitConstructor::process_range_list(const RangeList& list) @@ -710,7 +745,8 @@ void UltraCircuitConstructor::process_range_list(const RangeList& list) void UltraCircuitConstructor::process_range_lists() { - for (const auto& i : range_lists) + ENABLE_ALL_IN_THE_HEAD_SWITCHES + for (const auto& i : switched_range_lists) process_range_list(i.second); } @@ -2343,6 +2379,7 @@ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_ // Step 2: Create gates that validate correctness of RAM timestamps std::vector timestamp_deltas; + for (size_t i = 0; i < ram_array.records.size() - 1; ++i) { // create_RAM_timestamp_gate(sorted_records[i], sorted_records[i + 1]) const auto& current = ram_array.records[i]; @@ -2384,7 +2421,6 @@ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_ 0, 0, }); - // Step 3: validate difference in timestamps is monotonically increasing. i.e. is <= maximum timestamp const size_t max_timestamp = ram_array.access_count - 1; for (auto& w : timestamp_deltas) { @@ -2969,6 +3005,7 @@ inline fr UltraCircuitConstructor::compute_auxilary_identity(fr q_aux_value, * The complete RAM/ROM memory identity * */ + fr memory_identity = ROM_consistency_check_identity * q_2_value; memory_identity += RAM_timestamp_check_identity * q_4_value; memory_identity += memory_record_check * q_m_value; @@ -2998,7 +3035,9 @@ bool UltraCircuitConstructor::check_circuit() update_circuit_in_the_head(); in_the_head = true; // Finalize circuit-in-the-head + finalize_circuit(); + // Sample randomness const fr arithmetic_base = fr::random_element(); const fr elliptic_base = fr::random_element(); @@ -3006,15 +3045,15 @@ bool UltraCircuitConstructor::check_circuit() const fr auxillary_base = fr::random_element(); const fr alpha = fr::random_element(); const fr eta = fr::random_element(); - const fr eta_sqr = eta.sqr(); // We need to get all memory - std::unordered_set memory_record_gates; + std::unordered_set memory_read_record_gates; + std::unordered_set memory_write_record_gates; for (const auto& gate_idx : circuit_in_the_head.memory_read_records) { - memory_record_gates.insert(gate_idx); + memory_read_record_gates.insert(gate_idx); } for (const auto& gate_idx : circuit_in_the_head.memory_write_records) { - memory_record_gates.insert(gate_idx); + memory_write_record_gates.insert(gate_idx); } // A hashing implementation for quick simulation lookups @@ -3100,10 +3139,7 @@ bool UltraCircuitConstructor::check_circuit() fr w_2_value; fr w_3_value; fr w_4_value; - fr w_1_real_index; - fr w_2_real_index; - fr w_3_real_index; - fr w_4_real_index; + fr w_4_index; // Get the values of selectors and wires and update tag products along the way if (i < num_gates) { q_arith_value = q_arith[i]; @@ -3124,7 +3160,8 @@ bool UltraCircuitConstructor::check_circuit() w_3_value = get_variable(w_o[i]); update_tag_check_information(w_o[i], w_3_value); w_4_value = get_variable(w_4[i]); - update_tag_check_information(w_4[i], w_4_value); + // We need to wait before updating tag product for w_4 + w_4_index = w_4[i]; } else { // The in-the-head selector and wire variable indices are not copies of the circuit values, but rather the @@ -3134,7 +3171,7 @@ bool UltraCircuitConstructor::check_circuit() q_aux_value = circuit_in_the_head.q_aux[offset]; q_elliptic_value = circuit_in_the_head.q_elliptic[offset]; q_sort_value = circuit_in_the_head.q_sort[offset]; - q_lookup_type_value = circuit_in_the_head.q_lookup_type[i]; + q_lookup_type_value = circuit_in_the_head.q_lookup_type[offset]; q_1_value = circuit_in_the_head.q_1[offset]; q_2_value = circuit_in_the_head.q_2[offset]; q_3_value = circuit_in_the_head.q_3[offset]; @@ -3148,12 +3185,18 @@ bool UltraCircuitConstructor::check_circuit() w_3_value = get_variable(circuit_in_the_head.w_o[offset]); update_tag_check_information(circuit_in_the_head.w_o[offset], w_3_value); w_4_value = get_variable(circuit_in_the_head.w_4[offset]); - update_tag_check_information(circuit_in_the_head.w_4[offset], w_4_value); + // We need to wait before updating tag product for w_4 + w_4_index = circuit_in_the_head.w_4[offset]; } // If we are touching a gate with memory access, we need to update the value of the 4th witness - if (memory_record_gates.contains(i)) { - w_4_value = w_1_value + eta * w_2_value + eta_sqr * w_3_value; + if (memory_read_record_gates.contains(i)) { + w_4_value = ((w_3_value * eta + w_2_value) * eta + w_1_value) * eta; + } + if (memory_write_record_gates.contains(i)) { + w_4_value = ((w_3_value * eta + w_2_value) * eta + w_1_value) * eta + fr::one(); } + // Now we can update the tag product for w_4 + update_tag_check_information((uint32_t)w_4_index, w_4_value); fr w_1_shifted_value; fr w_2_shifted_value; fr w_3_shifted_value; @@ -3166,18 +3209,23 @@ bool UltraCircuitConstructor::check_circuit() w_4_shifted_value = get_variable(w_4[i + 1]); } else if (i < (circuit_in_the_head.num_gates - 1)) { - w_1_shifted_value = get_variable(circuit_in_the_head.w_l[i + 1]); - w_2_shifted_value = get_variable(circuit_in_the_head.w_r[i + 1]); - w_3_shifted_value = get_variable(circuit_in_the_head.w_o[i + 1]); - w_4_shifted_value = get_variable(circuit_in_the_head.w_4[i + 1]); + size_t offset = i - num_gates; + w_1_shifted_value = get_variable(circuit_in_the_head.w_l[offset + 1]); + w_2_shifted_value = get_variable(circuit_in_the_head.w_r[offset + 1]); + w_3_shifted_value = get_variable(circuit_in_the_head.w_o[offset + 1]); + w_4_shifted_value = get_variable(circuit_in_the_head.w_4[offset + 1]); } else { w_1_shifted_value = fr::zero(); w_2_shifted_value = fr::zero(); w_3_shifted_value = fr::zero(); w_4_shifted_value = fr::zero(); } - if (memory_record_gates.contains(i + 1)) { - w_4_shifted_value = w_1_shifted_value + eta * w_2_shifted_value + eta_sqr * w_3_shifted_value; + if (memory_read_record_gates.contains(i + 1)) { + w_4_shifted_value = ((w_3_shifted_value * eta + w_2_shifted_value) * eta + w_1_shifted_value) * eta; + } + if (memory_write_record_gates.contains(i + 1)) { + w_4_shifted_value = + ((w_3_shifted_value * eta + w_2_shifted_value) * eta + w_1_shifted_value) * eta + fr::one(); } if (!compute_arithmetic_identity(q_arith_value, q_1_value, @@ -3195,6 +3243,9 @@ bool UltraCircuitConstructor::check_circuit() arithmetic_base, alpha) .is_zero()) { +#ifndef FUZZING + info("Arithemtic identity fails at gate ", i); +#endif result = false; break; } @@ -3218,6 +3269,10 @@ bool UltraCircuitConstructor::check_circuit() alpha, eta) .is_zero()) { +#ifndef FUZZING + info("Auxilary identity fails at gate ", i); +#endif + result = false; break; } @@ -3234,12 +3289,19 @@ bool UltraCircuitConstructor::check_circuit() elliptic_base, alpha) .is_zero()) { +#ifndef FUZZING + info("Elliptic identity fails at gate ", i); +#endif result = false; break; } if (!compute_genperm_sort_identity( q_sort_value, w_1_value, w_2_value, w_3_value, w_4_value, w_1_shifted_value, genperm_sort_base, alpha) .is_zero()) { +#ifndef FUZZING + info("Genperm sort identity fails at gate ", i); +#endif + result = false; break; } @@ -3248,12 +3310,22 @@ bool UltraCircuitConstructor::check_circuit() w_2_value + q_m_value * w_2_shifted_value, w_3_value + q_c_value * w_3_shifted_value, q_3_value))) { +#ifndef FUZZING + info("Lookup fails at gate ", i); +#endif + result = false; break; } } } if (left_tag_product != right_tag_product) { +#ifndef FUZZING + if (result) { + info("Tag permutation failed"); + } +#endif + result = false; } in_the_head = false; @@ -3289,6 +3361,7 @@ void UltraCircuitConstructor::update_circuit_in_the_head() circuit_in_the_head.q_arith.clear(); circuit_in_the_head.q_elliptic.clear(); circuit_in_the_head.q_aux.clear(); + circuit_in_the_head.q_sort.clear(); circuit_in_the_head.q_lookup_type.clear(); // Update current tag in the head to be the same as current real tag circuit_in_the_head.current_tag = current_tag; diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp index 94c4ab6e9c..2833c39ac3 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp @@ -831,12 +831,21 @@ class UltraCircuitConstructor : public CircuitConstructorBase using namespace barretenberg; @@ -127,4 +128,672 @@ TEST(ultra_circuit_constructor, test_no_lookup_proof) bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); } + +TEST(ultra_circuit_constructor, test_elliptic_gate) +{ + typedef grumpkin::g1::affine_element affine_element; + typedef grumpkin::g1::element element; + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + + affine_element p1 = crypto::generators::get_generator_data({ 0, 0 }).generator; + + affine_element p2 = crypto::generators::get_generator_data({ 0, 1 }).generator; + affine_element p3(element(p1) + element(p2)); + + uint32_t x1 = circuit_constructor.add_variable(p1.x); + uint32_t y1 = circuit_constructor.add_variable(p1.y); + uint32_t x2 = circuit_constructor.add_variable(p2.x); + uint32_t y2 = circuit_constructor.add_variable(p2.y); + uint32_t x3 = circuit_constructor.add_variable(p3.x); + uint32_t y3 = circuit_constructor.add_variable(p3.y); + + ecc_add_gate gate{ x1, y1, x2, y2, x3, y3, 1, 1 }; + circuit_constructor.create_ecc_add_gate(gate); + + grumpkin::fq beta = grumpkin::fq::cube_root_of_unity(); + affine_element p2_endo = p2; + p2_endo.x *= beta; + p3 = affine_element(element(p1) + element(p2_endo)); + x3 = circuit_constructor.add_variable(p3.x); + y3 = circuit_constructor.add_variable(p3.y); + gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta, 1 }; + circuit_constructor.create_ecc_add_gate(gate); + + p2_endo.x *= beta; + p3 = affine_element(element(p1) - element(p2_endo)); + x3 = circuit_constructor.add_variable(p3.x); + y3 = circuit_constructor.add_variable(p3.y); + gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta.sqr(), -1 }; + circuit_constructor.create_ecc_add_gate(gate); + + auto saved_state = CircuitInTheHead::store_state(circuit_constructor); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); + EXPECT_TRUE(saved_state.is_same_state(circuit_constructor)); + + gate = ecc_add_gate{ x1 + 1, y1, x2, y2, x3, y3, beta.sqr(), -1 }; + circuit_constructor.create_ecc_add_gate(gate); + + EXPECT_EQ(circuit_constructor.check_circuit(), false); +} + +TEST(ultra_circuit_constructor, non_trivial_tag_permutation) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + fr a = fr::random_element(); + fr b = -a; + + auto a_idx = circuit_constructor.add_variable(a); + auto b_idx = circuit_constructor.add_variable(b); + auto c_idx = circuit_constructor.add_variable(b); + auto d_idx = circuit_constructor.add_variable(a); + + circuit_constructor.create_add_gate( + { a_idx, b_idx, circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), fr::zero() }); + circuit_constructor.create_add_gate( + { c_idx, d_idx, circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), fr::zero() }); + + circuit_constructor.create_tag(1, 2); + circuit_constructor.create_tag(2, 1); + + circuit_constructor.assign_tag(a_idx, 1); + circuit_constructor.assign_tag(b_idx, 1); + circuit_constructor.assign_tag(c_idx, 2); + circuit_constructor.assign_tag(d_idx, 2); + + auto saved_state = CircuitInTheHead::store_state(circuit_constructor); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); + EXPECT_TRUE(saved_state.is_same_state(circuit_constructor)); + + // Break the tag + circuit_constructor.real_variable_tags[circuit_constructor.real_variable_index[a_idx]] = 2; + EXPECT_EQ(circuit_constructor.check_circuit(), false); +} + +TEST(ultra_circuit_constructor, non_trivial_tag_permutation_and_cycles) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + fr a = fr::random_element(); + fr c = -a; + + auto a_idx = circuit_constructor.add_variable(a); + auto b_idx = circuit_constructor.add_variable(a); + circuit_constructor.assert_equal(a_idx, b_idx); + auto c_idx = circuit_constructor.add_variable(c); + auto d_idx = circuit_constructor.add_variable(c); + circuit_constructor.assert_equal(c_idx, d_idx); + auto e_idx = circuit_constructor.add_variable(a); + auto f_idx = circuit_constructor.add_variable(a); + circuit_constructor.assert_equal(e_idx, f_idx); + auto g_idx = circuit_constructor.add_variable(c); + auto h_idx = circuit_constructor.add_variable(c); + circuit_constructor.assert_equal(g_idx, h_idx); + + circuit_constructor.create_tag(1, 2); + circuit_constructor.create_tag(2, 1); + + circuit_constructor.assign_tag(a_idx, 1); + circuit_constructor.assign_tag(c_idx, 1); + circuit_constructor.assign_tag(e_idx, 2); + circuit_constructor.assign_tag(g_idx, 2); + + circuit_constructor.create_add_gate( + { b_idx, a_idx, circuit_constructor.zero_idx, fr::one(), fr::neg_one(), fr::zero(), fr::zero() }); + circuit_constructor.create_add_gate( + { c_idx, g_idx, circuit_constructor.zero_idx, fr::one(), -fr::one(), fr::zero(), fr::zero() }); + circuit_constructor.create_add_gate( + { e_idx, f_idx, circuit_constructor.zero_idx, fr::one(), -fr::one(), fr::zero(), fr::zero() }); + + auto saved_state = CircuitInTheHead::store_state(circuit_constructor); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); + EXPECT_TRUE(saved_state.is_same_state(circuit_constructor)); + + // Break the tag + circuit_constructor.real_variable_tags[circuit_constructor.real_variable_index[a_idx]] = 2; + EXPECT_EQ(circuit_constructor.check_circuit(), false); +} +TEST(ultra_circuit_constructor, bad_tag_permutation) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + fr a = fr::random_element(); + fr b = -a; + + auto a_idx = circuit_constructor.add_variable(a); + auto b_idx = circuit_constructor.add_variable(b); + auto c_idx = circuit_constructor.add_variable(b); + auto d_idx = circuit_constructor.add_variable(a + 1); + + circuit_constructor.create_add_gate({ a_idx, b_idx, circuit_constructor.zero_idx, 1, 1, 0, 0 }); + circuit_constructor.create_add_gate({ c_idx, d_idx, circuit_constructor.zero_idx, 1, 1, 0, -1 }); + + auto saved_state = CircuitInTheHead::store_state(circuit_constructor); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); + EXPECT_TRUE(saved_state.is_same_state(circuit_constructor)); + + circuit_constructor.create_tag(1, 2); + circuit_constructor.create_tag(2, 1); + + circuit_constructor.assign_tag(a_idx, 1); + circuit_constructor.assign_tag(b_idx, 1); + circuit_constructor.assign_tag(c_idx, 2); + circuit_constructor.assign_tag(d_idx, 2); + + result = circuit_constructor.check_circuit(); + EXPECT_EQ(result, false); +} + +TEST(ultra_circuit_constructor, sort_widget) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + fr a = fr::one(); + fr b = fr(2); + fr c = fr(3); + fr d = fr(4); + + auto a_idx = circuit_constructor.add_variable(a); + auto b_idx = circuit_constructor.add_variable(b); + auto c_idx = circuit_constructor.add_variable(c); + auto d_idx = circuit_constructor.add_variable(d); + circuit_constructor.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); +} + +std::vector add_variables(UltraCircuitConstructor& circuit_constructor, std::vector variables) +{ + std::vector res; + for (size_t i = 0; i < variables.size(); i++) { + res.emplace_back(circuit_constructor.add_variable(variables[i])); + } + return res; +} +TEST(ultra_circuit_constructor, sort_with_edges_gate) +{ + + fr a = fr::one(); + fr b = fr(2); + fr c = fr(3); + fr d = fr(4); + fr e = fr(5); + fr f = fr(6); + fr g = fr(7); + fr h = fr(8); + + { + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto a_idx = circuit_constructor.add_variable(a); + auto b_idx = circuit_constructor.add_variable(b); + auto c_idx = circuit_constructor.add_variable(c); + auto d_idx = circuit_constructor.add_variable(d); + auto e_idx = circuit_constructor.add_variable(e); + auto f_idx = circuit_constructor.add_variable(f); + auto g_idx = circuit_constructor.add_variable(g); + auto h_idx = circuit_constructor.add_variable(h); + circuit_constructor.create_sort_constraint_with_edges( + { a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, h); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); + } + + { + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto a_idx = circuit_constructor.add_variable(a); + auto b_idx = circuit_constructor.add_variable(b); + auto c_idx = circuit_constructor.add_variable(c); + auto d_idx = circuit_constructor.add_variable(d); + auto e_idx = circuit_constructor.add_variable(e); + auto f_idx = circuit_constructor.add_variable(f); + auto g_idx = circuit_constructor.add_variable(g); + auto h_idx = circuit_constructor.add_variable(h); + circuit_constructor.create_sort_constraint_with_edges( + { a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, g); + + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, false); + } + { + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto a_idx = circuit_constructor.add_variable(a); + auto b_idx = circuit_constructor.add_variable(b); + auto c_idx = circuit_constructor.add_variable(c); + auto d_idx = circuit_constructor.add_variable(d); + auto e_idx = circuit_constructor.add_variable(e); + auto f_idx = circuit_constructor.add_variable(f); + auto g_idx = circuit_constructor.add_variable(g); + auto h_idx = circuit_constructor.add_variable(h); + circuit_constructor.create_sort_constraint_with_edges( + { a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, h); + + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, false); + } + { + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto a_idx = circuit_constructor.add_variable(a); + auto c_idx = circuit_constructor.add_variable(c); + auto d_idx = circuit_constructor.add_variable(d); + auto e_idx = circuit_constructor.add_variable(e); + auto f_idx = circuit_constructor.add_variable(f); + auto g_idx = circuit_constructor.add_variable(g); + auto h_idx = circuit_constructor.add_variable(h); + auto b2_idx = circuit_constructor.add_variable(fr(15)); + circuit_constructor.create_sort_constraint_with_edges( + { a_idx, b2_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, h); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, false); + } + { + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto idx = add_variables(circuit_constructor, { 1, 2, 5, 6, 7, 10, 11, 13, 16, 17, 20, 22, 22, 25, + 26, 29, 29, 32, 32, 33, 35, 38, 39, 39, 42, 42, 43, 45 }); + circuit_constructor.create_sort_constraint_with_edges(idx, 1, 45); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); + } + { + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto idx = add_variables(circuit_constructor, { 1, 2, 5, 6, 7, 10, 11, 13, 16, 17, 20, 22, 22, 25, + 26, 29, 29, 32, 32, 33, 35, 38, 39, 39, 42, 42, 43, 45 }); + + circuit_constructor.create_sort_constraint_with_edges(idx, 1, 29); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, false); + } +} + +TEST(ultra_circuit_constructor, range_constraint) +{ + { + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto indices = add_variables(circuit_constructor, { 1, 2, 3, 4, 5, 6, 7, 8 }); + for (size_t i = 0; i < indices.size(); i++) { + circuit_constructor.create_new_range_constraint(indices[i], 8); + } + // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; + circuit_constructor.create_sort_constraint(indices); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); + } + { + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto indices = add_variables(circuit_constructor, { 3 }); + for (size_t i = 0; i < indices.size(); i++) { + circuit_constructor.create_new_range_constraint(indices[i], 3); + } + // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; + circuit_constructor.create_dummy_constraints(indices); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); + } + { + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto indices = add_variables(circuit_constructor, { 1, 2, 3, 4, 5, 6, 8, 25 }); + for (size_t i = 0; i < indices.size(); i++) { + circuit_constructor.create_new_range_constraint(indices[i], 8); + } + circuit_constructor.create_sort_constraint(indices); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, false); + } + { + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto indices = add_variables(circuit_constructor, + { 1, 2, 3, 4, 5, 6, 10, 8, 15, 11, 32, 21, 42, 79, 16, 10, 3, 26, 19, 51 }); + for (size_t i = 0; i < indices.size(); i++) { + circuit_constructor.create_new_range_constraint(indices[i], 128); + } + circuit_constructor.create_dummy_constraints(indices); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); + } + { + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto indices = add_variables(circuit_constructor, + { 1, 2, 3, 80, 5, 6, 29, 8, 15, 11, 32, 21, 42, 79, 16, 10, 3, 26, 13, 14 }); + for (size_t i = 0; i < indices.size(); i++) { + circuit_constructor.create_new_range_constraint(indices[i], 79); + } + circuit_constructor.create_dummy_constraints(indices); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, false); + } + { + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto indices = add_variables(circuit_constructor, + { 1, 0, 3, 80, 5, 6, 29, 8, 15, 11, 32, 21, 42, 79, 16, 10, 3, 26, 13, 14 }); + for (size_t i = 0; i < indices.size(); i++) { + circuit_constructor.create_new_range_constraint(indices[i], 79); + } + circuit_constructor.create_dummy_constraints(indices); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, false); + } +} + +TEST(ultra_circuit_constructor, range_with_gates) +{ + + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto idx = add_variables(circuit_constructor, { 1, 2, 3, 4, 5, 6, 7, 8 }); + for (size_t i = 0; i < idx.size(); i++) { + circuit_constructor.create_new_range_constraint(idx[i], 8); + } + + circuit_constructor.create_add_gate( + { idx[0], idx[1], circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), -3 }); + circuit_constructor.create_add_gate( + { idx[2], idx[3], circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), -7 }); + circuit_constructor.create_add_gate( + { idx[4], idx[5], circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), -11 }); + circuit_constructor.create_add_gate( + { idx[6], idx[7], circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), -15 }); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); +} + +TEST(ultra_circuit_constructor, range_with_gates_where_range_is_not_a_power_of_two) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto idx = add_variables(circuit_constructor, { 1, 2, 3, 4, 5, 6, 7, 8 }); + for (size_t i = 0; i < idx.size(); i++) { + circuit_constructor.create_new_range_constraint(idx[i], 12); + } + + circuit_constructor.create_add_gate( + { idx[0], idx[1], circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), -3 }); + circuit_constructor.create_add_gate( + { idx[2], idx[3], circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), -7 }); + circuit_constructor.create_add_gate( + { idx[4], idx[5], circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), -11 }); + circuit_constructor.create_add_gate( + { idx[6], idx[7], circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), -15 }); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); +} + +TEST(ultra_circuit_constructor, sort_widget_complex) +{ + { + + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + std::vector a = { 1, 3, 4, 7, 7, 8, 11, 14, 15, 15, 18, 19, 21, 21, 24, 25, 26, 27, 30, 32 }; + std::vector ind; + for (size_t i = 0; i < a.size(); i++) + ind.emplace_back(circuit_constructor.add_variable(a[i])); + circuit_constructor.create_sort_constraint(ind); + + bool result = circuit_constructor.check_circuit(); + EXPECT_EQ(result, true); + } + { + + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + std::vector a = { 1, 3, 4, 7, 7, 8, 16, 14, 15, 15, 18, 19, 21, 21, 24, 25, 26, 27, 30, 32 }; + std::vector ind; + for (size_t i = 0; i < a.size(); i++) + ind.emplace_back(circuit_constructor.add_variable(a[i])); + circuit_constructor.create_sort_constraint(ind); + + bool result = circuit_constructor.check_circuit(); + EXPECT_EQ(result, false); + } +} +TEST(ultra_circuit_constructor, sort_widget_neg) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + fr a = fr::one(); + fr b = fr(2); + fr c = fr(3); + fr d = fr(8); + + auto a_idx = circuit_constructor.add_variable(a); + auto b_idx = circuit_constructor.add_variable(b); + auto c_idx = circuit_constructor.add_variable(c); + auto d_idx = circuit_constructor.add_variable(d); + circuit_constructor.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); + + bool result = circuit_constructor.check_circuit(); + EXPECT_EQ(result, false); +} + +TEST(ultra_circuit_constructor, composed_range_constraint) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + auto c = fr::random_element(); + auto d = uint256_t(c).slice(0, 133); + auto e = fr(d); + auto a_idx = circuit_constructor.add_variable(fr(e)); + circuit_constructor.create_add_gate( + { a_idx, circuit_constructor.zero_idx, circuit_constructor.zero_idx, 1, 0, 0, -fr(e) }); + circuit_constructor.decompose_into_default_range(a_idx, 134); + + bool result = circuit_constructor.check_circuit(); + EXPECT_EQ(result, true); +} + +TEST(ultra_circuit_constructor, non_native_field_multiplication) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + + fq a = fq::random_element(); + fq b = fq::random_element(); + uint256_t modulus = fq::modulus; + + uint1024_t a_big = uint512_t(uint256_t(a)); + uint1024_t b_big = uint512_t(uint256_t(b)); + uint1024_t p_big = uint512_t(uint256_t(modulus)); + + uint1024_t q_big = (a_big * b_big) / p_big; + uint1024_t r_big = (a_big * b_big) % p_big; + + uint256_t q(q_big.lo.lo); + uint256_t r(r_big.lo.lo); + + const auto split_into_limbs = [&](const uint512_t& input) { + constexpr size_t NUM_BITS = 68; + std::array limbs; + limbs[0] = input.slice(0, NUM_BITS).lo; + limbs[1] = input.slice(NUM_BITS * 1, NUM_BITS * 2).lo; + limbs[2] = input.slice(NUM_BITS * 2, NUM_BITS * 3).lo; + limbs[3] = input.slice(NUM_BITS * 3, NUM_BITS * 4).lo; + limbs[4] = fr(input.lo); + return limbs; + }; + + const auto get_limb_witness_indices = [&](const std::array& limbs) { + std::array limb_indices; + limb_indices[0] = circuit_constructor.add_variable(limbs[0]); + limb_indices[1] = circuit_constructor.add_variable(limbs[1]); + limb_indices[2] = circuit_constructor.add_variable(limbs[2]); + limb_indices[3] = circuit_constructor.add_variable(limbs[3]); + limb_indices[4] = circuit_constructor.add_variable(limbs[4]); + return limb_indices; + }; + const uint512_t BINARY_BASIS_MODULUS = uint512_t(1) << (68 * 4); + auto modulus_limbs = split_into_limbs(BINARY_BASIS_MODULUS - uint512_t(modulus)); + + const auto a_indices = get_limb_witness_indices(split_into_limbs(uint256_t(a))); + const auto b_indices = get_limb_witness_indices(split_into_limbs(uint256_t(b))); + const auto q_indices = get_limb_witness_indices(split_into_limbs(uint256_t(q))); + const auto r_indices = get_limb_witness_indices(split_into_limbs(uint256_t(r))); + + proof_system::non_native_field_witnesses inputs{ + a_indices, b_indices, q_indices, r_indices, modulus_limbs, fr(uint256_t(modulus)), + }; + const auto [lo_1_idx, hi_1_idx] = circuit_constructor.evaluate_non_native_field_multiplication(inputs); + circuit_constructor.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70); + + bool result = circuit_constructor.check_circuit(); + EXPECT_EQ(result, true); +} + +TEST(ultra_circuit_constructor, rom) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + + uint32_t rom_values[8]{ + circuit_constructor.add_variable(fr::random_element()), circuit_constructor.add_variable(fr::random_element()), + circuit_constructor.add_variable(fr::random_element()), circuit_constructor.add_variable(fr::random_element()), + circuit_constructor.add_variable(fr::random_element()), circuit_constructor.add_variable(fr::random_element()), + circuit_constructor.add_variable(fr::random_element()), circuit_constructor.add_variable(fr::random_element()), + }; + + size_t rom_id = circuit_constructor.create_ROM_array(8); + + for (size_t i = 0; i < 8; ++i) { + circuit_constructor.set_ROM_element(rom_id, i, rom_values[i]); + } + + uint32_t a_idx = circuit_constructor.read_ROM_array(rom_id, circuit_constructor.add_variable(5)); + EXPECT_EQ(a_idx != rom_values[5], true); + uint32_t b_idx = circuit_constructor.read_ROM_array(rom_id, circuit_constructor.add_variable(4)); + uint32_t c_idx = circuit_constructor.read_ROM_array(rom_id, circuit_constructor.add_variable(1)); + + const auto d_value = circuit_constructor.get_variable(a_idx) + circuit_constructor.get_variable(b_idx) + + circuit_constructor.get_variable(c_idx); + uint32_t d_idx = circuit_constructor.add_variable(d_value); + + circuit_constructor.create_big_add_gate({ + a_idx, + b_idx, + c_idx, + d_idx, + 1, + 1, + 1, + -1, + 0, + }); + + bool result = circuit_constructor.check_circuit(); + EXPECT_EQ(result, true); +} + +TEST(ultra_circuit_constructor, ram) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + + uint32_t ram_values[8]{ + circuit_constructor.add_variable(fr::random_element()), circuit_constructor.add_variable(fr::random_element()), + circuit_constructor.add_variable(fr::random_element()), circuit_constructor.add_variable(fr::random_element()), + circuit_constructor.add_variable(fr::random_element()), circuit_constructor.add_variable(fr::random_element()), + circuit_constructor.add_variable(fr::random_element()), circuit_constructor.add_variable(fr::random_element()), + }; + + size_t ram_id = circuit_constructor.create_RAM_array(8); + + for (size_t i = 0; i < 8; ++i) { + circuit_constructor.init_RAM_element(ram_id, i, ram_values[i]); + } + + uint32_t a_idx = circuit_constructor.read_RAM_array(ram_id, circuit_constructor.add_variable(5)); + EXPECT_EQ(a_idx != ram_values[5], true); + + uint32_t b_idx = circuit_constructor.read_RAM_array(ram_id, circuit_constructor.add_variable(4)); + uint32_t c_idx = circuit_constructor.read_RAM_array(ram_id, circuit_constructor.add_variable(1)); + + circuit_constructor.write_RAM_array( + ram_id, circuit_constructor.add_variable(4), circuit_constructor.add_variable(500)); + uint32_t d_idx = circuit_constructor.read_RAM_array(ram_id, circuit_constructor.add_variable(4)); + + EXPECT_EQ(circuit_constructor.get_variable(d_idx), 500); + + // ensure these vars get used in another arithmetic gate + const auto e_value = circuit_constructor.get_variable(a_idx) + circuit_constructor.get_variable(b_idx) + + circuit_constructor.get_variable(c_idx) + circuit_constructor.get_variable(d_idx); + uint32_t e_idx = circuit_constructor.add_variable(e_value); + + circuit_constructor.create_big_add_gate( + { + a_idx, + b_idx, + c_idx, + d_idx, + -1, + -1, + -1, + -1, + 0, + }, + true); + circuit_constructor.create_big_add_gate( + { + circuit_constructor.zero_idx, + circuit_constructor.zero_idx, + circuit_constructor.zero_idx, + e_idx, + 0, + 0, + 0, + 0, + 0, + }, + false); + + auto saved_state = CircuitInTheHead::store_state(circuit_constructor); + bool result = circuit_constructor.check_circuit(); + + EXPECT_EQ(result, true); + + EXPECT_TRUE(saved_state.is_same_state(circuit_constructor)); +} + +TEST(ultra_circuit_constructor, range_checks_on_duplicates) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + + uint32_t a = circuit_constructor.add_variable(100); + uint32_t b = circuit_constructor.add_variable(100); + uint32_t c = circuit_constructor.add_variable(100); + uint32_t d = circuit_constructor.add_variable(100); + + circuit_constructor.assert_equal(a, b); + circuit_constructor.assert_equal(a, c); + circuit_constructor.assert_equal(a, d); + + circuit_constructor.create_new_range_constraint(a, 1000); + circuit_constructor.create_new_range_constraint(b, 1001); + circuit_constructor.create_new_range_constraint(c, 999); + circuit_constructor.create_new_range_constraint(d, 1000); + + circuit_constructor.create_big_add_gate( + { + a, + b, + c, + d, + 0, + 0, + 0, + 0, + 0, + }, + false); + bool result = circuit_constructor.check_circuit(); + EXPECT_EQ(result, true); +} + } // namespace proof_system \ No newline at end of file From 77a6e6f7de3178453297fba6228a05384e8149a7 Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Fri, 21 Apr 2023 22:37:22 +0000 Subject: [PATCH 07/11] Added a showcase for check_circuit --- .../ultra_circuit_constructor.test.cpp | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp index c280558c1c..09dfbe4eff 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp @@ -796,4 +796,40 @@ TEST(ultra_circuit_constructor, range_checks_on_duplicates) EXPECT_EQ(result, true); } +TEST(ultra_circuit_constructor, check_circuit_showcase) +{ + UltraCircuitConstructor circuit_constructor = UltraCircuitConstructor(); + // check_circuit allows us to check correctness on the go + + uint32_t a = circuit_constructor.add_variable(0xdead); + uint32_t b = circuit_constructor.add_variable(0xbeef); + // Let's create 2 gates that will bind these 2 variables to be one these two values + circuit_constructor.create_poly_gate( + { a, a, circuit_constructor.zero_idx, fr(1), -fr(0xdead) - fr(0xbeef), 0, 0, fr(0xdead) * fr(0xbeef) }); + circuit_constructor.create_poly_gate( + { b, b, circuit_constructor.zero_idx, fr(1), -fr(0xdead) - fr(0xbeef), 0, 0, fr(0xdead) * fr(0xbeef) }); + + // We can check if this works + EXPECT_EQ(circuit_constructor.check_circuit(), true); + + // Now let's create a range constraint for b + circuit_constructor.create_new_range_constraint(b, 0xbeef); + + // We can check if this works + EXPECT_EQ(circuit_constructor.check_circuit(), true); + + // But what if we now assert b to be equal to a? + circuit_constructor.assert_equal(a, b, "Oh no"); + + // It fails, because a is 0xdead and it can't fit in the range constraint + EXPECT_EQ(circuit_constructor.check_circuit(), false); + + // But if we force them both back to be 0xbeef... + uint32_t c = circuit_constructor.add_variable(0xbeef); + circuit_constructor.assert_equal(c, b); + + // The circuit will magically pass again + EXPECT_EQ(circuit_constructor.check_circuit(), true); +} + } // namespace proof_system \ No newline at end of file From 4f5ac8665425c286f220844854714843ee877c29 Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Tue, 25 Apr 2023 13:47:46 +0000 Subject: [PATCH 08/11] Moved members from proof_system into the UltraCircuitConstructor --- .../ultra_honk_composer_helper.cpp | 2 +- .../honk/composer/ultra_honk_composer.hpp | 14 +- .../composer/ultra_honk_composer.test.cpp | 2 +- .../ultra_plonk_composer_helper.cpp | 6 +- .../ultra_plonk_composer_helper.hpp | 2 +- .../splitting_tmp/ultra_plonk_composer.hpp | 14 +- .../ultra_plonk_composer.test.cpp | 2 +- .../ultra_circuit_constructor.cpp | 2 +- .../ultra_circuit_constructor.hpp | 759 ++++++++---------- .../ultra_circuit_constructor.test.cpp | 14 +- 10 files changed, 378 insertions(+), 439 deletions(-) diff --git a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp index b1c5850b04..dce07006c4 100644 --- a/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp +++ b/cpp/src/barretenberg/honk/composer/composer_helper/ultra_honk_composer_helper.cpp @@ -37,7 +37,7 @@ void UltraHonkComposerHelper::compute_witness(CircuitConstru const size_t filled_gates = circuit_constructor.num_gates + circuit_constructor.public_inputs.size(); const size_t total_num_gates = std::max(filled_gates, tables_size + lookups_size); - const size_t subgroup_size = circuit_constructor.get_circuit_subgroup_size(total_num_gates + NUM_RESERVED_GATES); + const size_t subgroup_size = circuit_constructor.get_circuit_subgroup_size(total_num_gates + NUM_RANDOMIZED_GATES); // Pad the wires (pointers to `witness_indices` of the `variables` vector). // Note: the remaining NUM_RESERVED_GATES indices are padded with zeros within `compute_witness_base` (called diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp index 4e5169c558..dfdf5ff8da 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.hpp @@ -289,7 +289,7 @@ class UltraHonkComposer { std::vector decompose_into_default_range( const uint32_t variable_index, const uint64_t num_bits, - const uint64_t target_range_bitnum = DEFAULT_PLOOKUP_RANGE_BITNUM, + const uint64_t target_range_bitnum = UltraCircuitConstructor::DEFAULT_PLOOKUP_RANGE_BITNUM, std::string const& msg = "decompose_into_default_range") { return circuit_constructor.decompose_into_default_range(variable_index, num_bits, target_range_bitnum, msg); @@ -348,17 +348,19 @@ class UltraHonkComposer { // /** // * Non Native Field Arithmetic // **/ - void range_constrain_two_limbs(const uint32_t lo_idx, - const uint32_t hi_idx, - const size_t lo_limb_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS, - const size_t hi_limb_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS) + void range_constrain_two_limbs( + const uint32_t lo_idx, + const uint32_t hi_idx, + const size_t lo_limb_bits = UltraCircuitConstructor::DEFAULT_NON_NATIVE_FIELD_LIMB_BITS, + const size_t hi_limb_bits = UltraCircuitConstructor::DEFAULT_NON_NATIVE_FIELD_LIMB_BITS) { circuit_constructor.range_constrain_two_limbs(lo_idx, hi_idx, lo_limb_bits, hi_limb_bits); }; // std::array decompose_non_native_field_double_width_limb( // const uint32_t limb_idx, const size_t num_limb_bits = (2 * DEFAULT_NON_NATIVE_FIELD_LIMB_BITS)); std::array queue_non_native_field_multiplication( - const non_native_field_witnesses& input, const bool range_constrain_quotient_and_remainder = true) + const UltraCircuitConstructor::non_native_field_witnesses& input, + const bool range_constrain_quotient_and_remainder = true) { return circuit_constructor.queue_non_native_field_multiplication(input, range_constrain_quotient_and_remainder); }; diff --git a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp index 7e857dd490..a36d563a79 100644 --- a/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp +++ b/cpp/src/barretenberg/honk/composer/ultra_honk_composer.test.cpp @@ -748,7 +748,7 @@ TEST(UltraHonkComposer, non_native_field_multiplication) const auto q_indices = get_limb_witness_indices(split_into_limbs(uint256_t(q))); const auto r_indices = get_limb_witness_indices(split_into_limbs(uint256_t(r))); - proof_system::non_native_field_witnesses inputs{ + proof_system::UltraCircuitConstructor::non_native_field_witnesses inputs{ a_indices, b_indices, q_indices, r_indices, modulus_limbs, fr(uint256_t(modulus)), }; const auto [lo_1_idx, hi_1_idx] = honk_composer.queue_non_native_field_multiplication(inputs); diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/ultra_plonk_composer_helper.cpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/ultra_plonk_composer_helper.cpp index 26e7049443..48f2bc64cb 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/ultra_plonk_composer_helper.cpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/ultra_plonk_composer_helper.cpp @@ -50,7 +50,7 @@ void UltraPlonkComposerHelper::compute_witness(CircuitConstr // TODO(luke): subgroup size was already computed above but compute_witness_base computes it again. If we pass in // NUM_RANDOMIZED_GATES (as in the other split composers) the resulting sizes can differ. Reconcile this. - auto wire_polynomial_evaluations = compute_witness_base(circuit_constructor, total_num_gates, NUM_RANDOMIZED_GATES); + auto wire_polynomial_evaluations = compute_witness_base(circuit_constructor, total_num_gates, NUM_RESERVED_GATES); for (size_t j = 0; j < program_width; ++j) { std::string index = std::to_string(j + 1); @@ -225,7 +225,7 @@ std::shared_ptr UltraPlonkComposerHelper::compu } const size_t minimum_circuit_size = tables_size + lookups_size; - const size_t num_randomized_gates = NUM_RANDOMIZED_GATES; + const size_t num_randomized_gates = NUM_RESERVED_GATES; // Initialize circuit_proving_key // TODO(#229)(Kesha): replace composer types. circuit_proving_key = initialize_proving_key( @@ -359,7 +359,7 @@ std::shared_ptr UltraPlonkComposerHelperget_verifier_crs()); - circuit_verification_key->composer_type = type; // Invariably plookup for this class. + circuit_verification_key->composer_type = ComposerType::PLOOKUP; // Invariably plookup for this class. // See `add_recusrive_proof()` for how this recursive data is assigned. circuit_verification_key->recursive_proof_public_input_indices = diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/ultra_plonk_composer_helper.hpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/ultra_plonk_composer_helper.hpp index c66ce7eea0..0c0f155b15 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/ultra_plonk_composer_helper.hpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/composer_helper/ultra_plonk_composer_helper.hpp @@ -20,7 +20,7 @@ template class UltraPlonkComposerHelper { // NUM_RESERVED_GATES). Therefore for consistency within this composer itself, and consistency with the original // Ultra Composer, this value must match that of NUM_RESERVED_GATES. This issue needs to be reconciled // simultaneously here and in the other split composers. - static constexpr size_t NUM_RANDOMIZED_GATES = 4; // equal to the number of multilinear evaluations leaked + static constexpr size_t NUM_RESERVED_GATES = 4; // equal to the number of multilinear evaluations leaked static constexpr size_t program_width = CircuitConstructor::program_width; std::shared_ptr circuit_proving_key; std::shared_ptr circuit_verification_key; diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp index 3f5843fdf5..73a5f6ed94 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.hpp @@ -311,7 +311,7 @@ class UltraPlonkComposer { std::vector decompose_into_default_range( const uint32_t variable_index, const uint64_t num_bits, - const uint64_t target_range_bitnum = DEFAULT_PLOOKUP_RANGE_BITNUM, + const uint64_t target_range_bitnum = UltraCircuitConstructor::DEFAULT_PLOOKUP_RANGE_BITNUM, std::string const& msg = "decompose_into_default_range") { return circuit_constructor.decompose_into_default_range(variable_index, num_bits, target_range_bitnum, msg); @@ -370,17 +370,19 @@ class UltraPlonkComposer { // /** // * Non Native Field Arithmetic // **/ - void range_constrain_two_limbs(const uint32_t lo_idx, - const uint32_t hi_idx, - const size_t lo_limb_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS, - const size_t hi_limb_bits = DEFAULT_NON_NATIVE_FIELD_LIMB_BITS) + void range_constrain_two_limbs( + const uint32_t lo_idx, + const uint32_t hi_idx, + const size_t lo_limb_bits = UltraCircuitConstructor::DEFAULT_NON_NATIVE_FIELD_LIMB_BITS, + const size_t hi_limb_bits = UltraCircuitConstructor::DEFAULT_NON_NATIVE_FIELD_LIMB_BITS) { circuit_constructor.range_constrain_two_limbs(lo_idx, hi_idx, lo_limb_bits, hi_limb_bits); }; // std::array decompose_non_native_field_double_width_limb( // const uint32_t limb_idx, const size_t num_limb_bits = (2 * DEFAULT_NON_NATIVE_FIELD_LIMB_BITS)); std::array queue_non_native_field_multiplication( - const non_native_field_witnesses& input, const bool range_constrain_quotient_and_remainder = true) + const UltraCircuitConstructor::non_native_field_witnesses& input, + const bool range_constrain_quotient_and_remainder = true) { return circuit_constructor.queue_non_native_field_multiplication(input, range_constrain_quotient_and_remainder); }; diff --git a/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.test.cpp b/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.test.cpp index cac3e754ae..1e697f07d4 100644 --- a/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.test.cpp +++ b/cpp/src/barretenberg/plonk/composer/splitting_tmp/ultra_plonk_composer.test.cpp @@ -780,7 +780,7 @@ TEST(ultra_plonk_composer_splitting_tmp, non_native_field_multiplication) const auto q_indices = get_limb_witness_indices(split_into_limbs(uint256_t(q))); const auto r_indices = get_limb_witness_indices(split_into_limbs(uint256_t(r))); - non_native_field_witnesses inputs{ + UltraCircuitConstructor::non_native_field_witnesses inputs{ a_indices, b_indices, q_indices, r_indices, modulus_limbs, fr(uint256_t(modulus)), }; const auto [lo_1_idx, hi_1_idx] = composer.queue_non_native_field_multiplication(inputs); diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp index 947d2529ac..b11f8530b5 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp @@ -504,7 +504,7 @@ plookup::ReadData UltraCircuitConstructor::create_gates_from_plookup_a * Generalized Permutation Methods **/ -RangeList UltraCircuitConstructor::create_range_list(const uint64_t target_range) +UltraCircuitConstructor::RangeList UltraCircuitConstructor::create_range_list(const uint64_t target_range) { RangeList result; const auto range_tag = get_new_tag(); // current_tag + 1; diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp index 2833c39ac3..699b8d8c17 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp @@ -12,431 +12,371 @@ #include namespace proof_system { -static constexpr ComposerType type = ComposerType::PLOOKUP; -static constexpr merkle::HashType merkle_hash_type = merkle::HashType::LOOKUP_PEDERSEN; -static constexpr size_t NUM_RESERVED_GATES = 4; // This must be >= num_roots_cut_out_of_vanishing_polynomial - // See the comment in plonk/proof_system/prover/prover.cpp - // ProverBase::compute_quotient_commitments() for why 4 exactly. -static constexpr size_t UINT_LOG2_BASE = 6; // DOCTODO: explain what this is, or rename. -// The plookup range proof requires work linear in range size, thus cannot be used directly for -// large ranges such as 2^64. For such ranges the element will be decomposed into smaller -// chuncks according to the parameter below -static constexpr size_t DEFAULT_PLOOKUP_RANGE_BITNUM = 14; -static constexpr size_t DEFAULT_PLOOKUP_RANGE_STEP_SIZE = 3; -static constexpr size_t DEFAULT_PLOOKUP_RANGE_SIZE = (1 << DEFAULT_PLOOKUP_RANGE_BITNUM) - 1; -static constexpr size_t DEFAULT_NON_NATIVE_FIELD_LIMB_BITS = 68; -static constexpr uint32_t UNINITIALIZED_MEMORY_RECORD = UINT32_MAX; -static constexpr size_t NUMBER_OF_GATES_PER_RAM_ACCESS = 2; -static constexpr size_t NUMBER_OF_ARITHMETIC_GATES_PER_RAM_ARRAY = 1; -// number of gates created per non-native field operation in process_non_native_field_multiplications -static constexpr size_t GATES_PER_NON_NATIVE_FIELD_MULTIPLICATION_ARITHMETIC = 7; - -struct non_native_field_witnesses { - // first 4 array elements = limbs - // 5th element = prime basis limb - std::array a; - std::array b; - std::array q; - std::array r; - std::array neg_modulus; - barretenberg::fr modulus; -}; - -struct non_native_field_multiplication_cross_terms { - uint32_t lo_0_idx; - uint32_t lo_1_idx; - uint32_t hi_0_idx; - uint32_t hi_1_idx; - uint32_t hi_2_idx; - uint32_t hi_3_idx; -}; - -/** - * @brief Used to store instructions to create non_native_field_multiplication gates. - * We want to cache these (and remove duplicates) as the stdlib code can end up multiplying the same inputs - * repeatedly. - */ -struct cached_non_native_field_multiplication { - std::array a; - std::array b; - std::array q; - std::array r; - non_native_field_multiplication_cross_terms cross_terms; - std::array neg_modulus; - - bool operator==(const cached_non_native_field_multiplication& other) const - { - bool valid = true; - for (size_t i = 0; i < 5; ++i) { - valid = valid && (a[i] == other.a[i]); - valid = valid && (b[i] == other.b[i]); - valid = valid && (q[i] == other.q[i]); - valid = valid && (r[i] == other.r[i]); - } - return valid; - } - bool operator<(const cached_non_native_field_multiplication& other) const - { - if (a < other.a) { - return true; - } - if (a == other.a) { - if (b < other.b) { - return true; - } - if (b == other.b) { - if (q < other.q) { - return true; - } - if (q == other.q) { - if (r < other.r) { - return true; - } - } - } - } - return false; - } -}; - -enum AUX_SELECTORS { - NONE, - LIMB_ACCUMULATE_1, - LIMB_ACCUMULATE_2, - NON_NATIVE_FIELD_1, - NON_NATIVE_FIELD_2, - NON_NATIVE_FIELD_3, - RAM_CONSISTENCY_CHECK, - ROM_CONSISTENCY_CHECK, - RAM_TIMESTAMP_CHECK, - ROM_READ, - RAM_READ, - RAM_WRITE, -}; - -struct RangeList { - uint64_t target_range; - uint32_t range_tag; - uint32_t tau_tag; - std::vector variable_indices; - bool operator==(const RangeList& other) const noexcept - { - return target_range == other.target_range && range_tag == other.range_tag && tau_tag == other.tau_tag && - variable_indices == other.variable_indices; - } -}; -/** - * @brief A ROM memory record that can be ordered - * - * - */ -struct RomRecord { - uint32_t index_witness = 0; - uint32_t value_column1_witness = 0; - uint32_t value_column2_witness = 0; - uint32_t index = 0; - uint32_t record_witness = 0; - size_t gate_index = 0; - bool operator<(const RomRecord& other) const { return index < other.index; } - bool operator==(const RomRecord& other) const noexcept - { - return index_witness == other.index_witness && value_column1_witness == other.value_column1_witness && - value_column2_witness == other.value_column2_witness && index == other.index && - record_witness == other.record_witness && gate_index == other.gate_index; - } -}; +class UltraCircuitConstructor : public CircuitConstructorBase { + public: + static constexpr ComposerType type = ComposerType::PLOOKUP; + static constexpr merkle::HashType merkle_hash_type = merkle::HashType::LOOKUP_PEDERSEN; + static constexpr size_t UINT_LOG2_BASE = 6; // DOCTODO: explain what this is, or rename. + // The plookup range proof requires work linear in range size, thus cannot be used directly for + // large ranges such as 2^64. For such ranges the element will be decomposed into smaller + // chuncks according to the parameter below + static constexpr size_t DEFAULT_PLOOKUP_RANGE_BITNUM = 14; + static constexpr size_t DEFAULT_PLOOKUP_RANGE_STEP_SIZE = 3; + static constexpr size_t DEFAULT_PLOOKUP_RANGE_SIZE = (1 << DEFAULT_PLOOKUP_RANGE_BITNUM) - 1; + static constexpr size_t DEFAULT_NON_NATIVE_FIELD_LIMB_BITS = 68; + static constexpr uint32_t UNINITIALIZED_MEMORY_RECORD = UINT32_MAX; + static constexpr size_t NUMBER_OF_GATES_PER_RAM_ACCESS = 2; + static constexpr size_t NUMBER_OF_ARITHMETIC_GATES_PER_RAM_ARRAY = 1; + + struct non_native_field_witnesses { + // first 4 array elements = limbs + // 5th element = prime basis limb + std::array a; + std::array b; + std::array q; + std::array r; + std::array neg_modulus; + barretenberg::fr modulus; + }; -/** - * @brief A RAM memory record that can be ordered - * - * - */ -struct RamRecord { - enum AccessType { - READ, - WRITE, + enum AUX_SELECTORS { + NONE, + LIMB_ACCUMULATE_1, + LIMB_ACCUMULATE_2, + NON_NATIVE_FIELD_1, + NON_NATIVE_FIELD_2, + NON_NATIVE_FIELD_3, + RAM_CONSISTENCY_CHECK, + ROM_CONSISTENCY_CHECK, + RAM_TIMESTAMP_CHECK, + ROM_READ, + RAM_READ, + RAM_WRITE, }; - uint32_t index_witness = 0; - uint32_t timestamp_witness = 0; - uint32_t value_witness = 0; - uint32_t index = 0; - uint32_t timestamp = 0; - AccessType access_type = AccessType::READ; // read or write? - uint32_t record_witness = 0; - size_t gate_index = 0; - bool operator<(const RamRecord& other) const - { - bool index_test = (index) < (other.index); - return index_test || (index == other.index && timestamp < other.timestamp); - } - bool operator==(const RamRecord& other) const noexcept - { - return index_witness == other.index_witness && timestamp_witness == other.timestamp_witness && - value_witness == other.value_witness && index == other.index && timestamp == other.timestamp && - access_type == other.access_type && record_witness == other.record_witness && - gate_index == other.gate_index; - } -}; -/** - * @brief Each ram array is an instance of memory transcript. It saves values and indexes for a particular memory - * array - * - * - */ -struct RamTranscript { - // Contains the value of each index of the array - std::vector state; - - // A vector of records, each of which contains: - // + The constant witness with the index - // + The value in the memory slot - // + The actual index value - std::vector records; - - // used for RAM records, to compute the timestamp when performing a read/write - size_t access_count = 0; - // Used to check that the state hasn't changed in tests - bool operator==(const RamTranscript& other) const noexcept - { - return (state == other.state && records == other.records && access_count == other.access_count); - } -}; + struct RangeList { + uint64_t target_range; + uint32_t range_tag; + uint32_t tau_tag; + std::vector variable_indices; + bool operator==(const RangeList& other) const noexcept + { + return target_range == other.target_range && range_tag == other.range_tag && tau_tag == other.tau_tag && + variable_indices == other.variable_indices; + } + }; -/** - * @brief Each rom array is an instance of memory transcript. It saves values and indexes for a particular memory - * array - * - * - */ -struct RomTranscript { - // Contains the value of each index of the array - std::vector> state; - - // A vector of records, each of which contains: - // + The constant witness with the index - // + The value in the memory slot - // + The actual index value - std::vector records; - - // Used to check that the state hasn't changed in tests - bool operator==(const RomTranscript& other) const noexcept - { - return (state == other.state && records == other.records); - } -}; + /** + * @brief A ROM memory record that can be ordered + * + * + */ + struct RomRecord { + uint32_t index_witness = 0; + uint32_t value_column1_witness = 0; + uint32_t value_column2_witness = 0; + uint32_t index = 0; + uint32_t record_witness = 0; + size_t gate_index = 0; + bool operator<(const RomRecord& other) const { return index < other.index; } + bool operator==(const RomRecord& other) const noexcept + { + return index_witness == other.index_witness && value_column1_witness == other.value_column1_witness && + value_column2_witness == other.value_column2_witness && index == other.index && + record_witness == other.record_witness && gate_index == other.gate_index; + } + }; -inline std::vector ultra_selector_names() -{ - std::vector result{ "q_m", "q_c", "q_1", "q_2", "q_3", "q_4", - "q_arith", "q_sort", "q_elliptic", "q_aux", "table_type" }; - return result; -} - -/** - * @brief Circuit-in-the-head is a structure we use to store all the information about the circuit which should be used - * during check_circuit method call, but needs to be discarded later - * - * @details In check_circuit method in UltraCircuitConstructor we want to check that the whole circuit works, but ultra - * circuits need to have ram, rom and range gates added in the end for the check to be complete as well as the set - * permutation check. - */ -struct CircuitInTheHead { - std::vector public_inputs; - std::vector variables; - // index of next variable in equivalence class (=REAL_VARIABLE if you're last) - std::vector next_var_index; - // index of previous variable in equivalence class (=FIRST if you're in a cycle alone) - std::vector prev_var_index; - // indices of corresponding real variables - std::vector real_variable_index; - std::vector real_variable_tags; - std::map constant_variable_indices; - std::vector w_l; - std::vector w_r; - std::vector w_o; - std::vector w_4; - std::vector q_m; - std::vector q_c; - std::vector q_1; - std::vector q_2; - std::vector q_3; - std::vector q_4; - std::vector q_arith; - std::vector q_sort; - std::vector q_elliptic; - std::vector q_aux; - std::vector q_lookup_type; - uint32_t current_tag = DUMMY_TAG; - std::map tau; + /** + * @brief A RAM memory record that can be ordered + * + * + */ + struct RamRecord { + enum AccessType { + READ, + WRITE, + }; + uint32_t index_witness = 0; + uint32_t timestamp_witness = 0; + uint32_t value_witness = 0; + uint32_t index = 0; + uint32_t timestamp = 0; + AccessType access_type = AccessType::READ; // read or write? + uint32_t record_witness = 0; + size_t gate_index = 0; + bool operator<(const RamRecord& other) const + { + bool index_test = (index) < (other.index); + return index_test || (index == other.index && timestamp < other.timestamp); + } + bool operator==(const RamRecord& other) const noexcept + { + return index_witness == other.index_witness && timestamp_witness == other.timestamp_witness && + value_witness == other.value_witness && index == other.index && timestamp == other.timestamp && + access_type == other.access_type && record_witness == other.record_witness && + gate_index == other.gate_index; + } + }; - std::vector ram_arrays; - std::vector rom_arrays; + /** + * @brief Each ram array is an instance of memory transcript. It saves values and indexes for a particular memory + * array + * + * + */ + struct RamTranscript { + // Contains the value of each index of the array + std::vector state; + + // A vector of records, each of which contains: + // + The constant witness with the index + // + The value in the memory slot + // + The actual index value + std::vector records; + + // used for RAM records, to compute the timestamp when performing a read/write + size_t access_count = 0; + // Used to check that the state hasn't changed in tests + bool operator==(const RamTranscript& other) const noexcept + { + return (state == other.state && records == other.records && access_count == other.access_count); + } + }; - std::vector memory_read_records; - std::vector memory_write_records; - std::map range_lists; - size_t num_gates; - bool circuit_finalised = false; /** - * @brief Stores the state of everything logic-related in the constructor. + * @brief Each rom array is an instance of memory transcript. It saves values and indexes for a particular memory + * array * - * @details We need this function for tests. Specifically, to ensure that we are not changing anything in - * check_circuit * - * @param circuit_constructor - * @return CircuitInTheHead */ - template - static CircuitInTheHead store_state(const CircuitConstructor& circuit_constructor) + struct RomTranscript { + // Contains the value of each index of the array + std::vector> state; + + // A vector of records, each of which contains: + // + The constant witness with the index + // + The value in the memory slot + // + The actual index value + std::vector records; + + // Used to check that the state hasn't changed in tests + bool operator==(const RomTranscript& other) const noexcept + { + return (state == other.state && records == other.records); + } + }; + + inline std::vector ultra_selector_names() { - CircuitInTheHead stored_state; - stored_state.public_inputs = circuit_constructor.public_inputs; - stored_state.variables = circuit_constructor.variables; - - stored_state.next_var_index = circuit_constructor.next_var_index; - - stored_state.prev_var_index = circuit_constructor.prev_var_index; - - stored_state.real_variable_index = circuit_constructor.real_variable_index; - stored_state.real_variable_tags = circuit_constructor.real_variable_tags; - stored_state.constant_variable_indices = circuit_constructor.constant_variable_indices; - stored_state.w_l = circuit_constructor.w_l; - stored_state.w_r = circuit_constructor.w_r; - stored_state.w_o = circuit_constructor.w_o; - stored_state.w_4 = circuit_constructor.w_4; - stored_state.q_m = circuit_constructor.q_m; - stored_state.q_c = circuit_constructor.q_c; - stored_state.q_1 = circuit_constructor.q_1; - stored_state.q_2 = circuit_constructor.q_2; - stored_state.q_3 = circuit_constructor.q_3; - stored_state.q_4 = circuit_constructor.q_4; - stored_state.q_arith = circuit_constructor.q_arith; - stored_state.q_sort = circuit_constructor.q_sort; - stored_state.q_elliptic = circuit_constructor.q_elliptic; - stored_state.q_aux = circuit_constructor.q_aux; - stored_state.q_lookup_type = circuit_constructor.q_lookup_type; - stored_state.current_tag = circuit_constructor.current_tag; - stored_state.tau = circuit_constructor.tau; - - stored_state.ram_arrays = circuit_constructor.ram_arrays; - stored_state.rom_arrays = circuit_constructor.rom_arrays; - - stored_state.memory_read_records = circuit_constructor.memory_read_records; - stored_state.memory_write_records = circuit_constructor.memory_write_records; - stored_state.range_lists = circuit_constructor.range_lists; - stored_state.circuit_finalised = circuit_constructor.circuit_finalised; - stored_state.num_gates = circuit_constructor.num_gates; - return stored_state; + std::vector result{ "q_m", "q_c", "q_1", "q_2", "q_3", "q_4", + "q_arith", "q_sort", "q_elliptic", "q_aux", "table_type" }; + return result; } + /** - * @brief CHecks that the circuit states is the same as the stored circuit's one + * @brief Circuit-in-the-head is a structure we use to store all the information about the circuit which should be + * used during check_circuit method call, but needs to be discarded later * - * @param circuit_constructor - * @return true - * @return false + * @details In check_circuit method in UltraCircuitConstructor we want to check that the whole circuit works, but + * ultra circuits need to have ram, rom and range gates added in the end for the check to be complete as well as the + * set permutation check. */ - template bool is_same_state(const CircuitConstructor& circuit_constructor) - { - if (!(public_inputs == circuit_constructor.public_inputs)) { - return false; - } - if (!(variables == circuit_constructor.variables)) { - return false; - } - if (!(next_var_index == circuit_constructor.next_var_index)) { - return false; - } - if (!(prev_var_index == circuit_constructor.prev_var_index)) { - return false; - } - if (!(real_variable_index == circuit_constructor.real_variable_index)) { - return false; - } - if (!(real_variable_tags == circuit_constructor.real_variable_tags)) { - return false; - } - if (!(constant_variable_indices == circuit_constructor.constant_variable_indices)) { - return false; - } - if (!(w_l == circuit_constructor.w_l)) { - return false; - } - if (!(w_r == circuit_constructor.w_r)) { - return false; - } - if (!(w_o == circuit_constructor.w_o)) { - return false; - } - if (!(w_4 == circuit_constructor.w_4)) { - return false; - } - if (!(q_m == circuit_constructor.q_m)) { - return false; - } - if (!(q_c == circuit_constructor.q_c)) { - return false; - } - if (!(q_1 == circuit_constructor.q_1)) { - return false; - } - if (!(q_2 == circuit_constructor.q_2)) { - return false; - } - if (!(q_3 == circuit_constructor.q_3)) { - return false; - } - if (!(q_4 == circuit_constructor.q_4)) { - return false; - } - if (!(q_arith == circuit_constructor.q_arith)) { - return false; - } - if (!(q_sort == circuit_constructor.q_sort)) { - return false; - } - if (!(q_elliptic == circuit_constructor.q_elliptic)) { - return false; - } - if (!(q_aux == circuit_constructor.q_aux)) { - return false; - } - if (!(q_lookup_type == circuit_constructor.q_lookup_type)) { - return false; - } - if (!(current_tag == circuit_constructor.current_tag)) { - return false; - } - if (!(tau == circuit_constructor.tau)) { - return false; - } - if (!(ram_arrays == circuit_constructor.ram_arrays)) { - return false; - } - if (!(rom_arrays == circuit_constructor.rom_arrays)) { - return false; - } - if (!(memory_read_records == circuit_constructor.memory_read_records)) { - return false; - } - if (!(memory_write_records == circuit_constructor.memory_write_records)) { - return false; - } - if (!(range_lists == circuit_constructor.range_lists)) { - return false; - } - if (!(num_gates == circuit_constructor.num_gates)) { - return false; - } - if (!(circuit_finalised == circuit_constructor.circuit_finalised)) { - return false; + struct CircuitInTheHead { + std::vector public_inputs; + std::vector variables; + // index of next variable in equivalence class (=REAL_VARIABLE if you're last) + std::vector next_var_index; + // index of previous variable in equivalence class (=FIRST if you're in a cycle alone) + std::vector prev_var_index; + // indices of corresponding real variables + std::vector real_variable_index; + std::vector real_variable_tags; + std::map constant_variable_indices; + std::vector w_l; + std::vector w_r; + std::vector w_o; + std::vector w_4; + std::vector q_m; + std::vector q_c; + std::vector q_1; + std::vector q_2; + std::vector q_3; + std::vector q_4; + std::vector q_arith; + std::vector q_sort; + std::vector q_elliptic; + std::vector q_aux; + std::vector q_lookup_type; + uint32_t current_tag = DUMMY_TAG; + std::map tau; + + std::vector ram_arrays; + std::vector rom_arrays; + + std::vector memory_read_records; + std::vector memory_write_records; + std::map range_lists; + size_t num_gates; + bool circuit_finalised = false; + /** + * @brief Stores the state of everything logic-related in the constructor. + * + * @details We need this function for tests. Specifically, to ensure that we are not changing anything in + * check_circuit + * + * @param circuit_constructor + * @return CircuitInTheHead + */ + template + static CircuitInTheHead store_state(const CircuitConstructor& circuit_constructor) + { + CircuitInTheHead stored_state; + stored_state.public_inputs = circuit_constructor.public_inputs; + stored_state.variables = circuit_constructor.variables; + + stored_state.next_var_index = circuit_constructor.next_var_index; + + stored_state.prev_var_index = circuit_constructor.prev_var_index; + + stored_state.real_variable_index = circuit_constructor.real_variable_index; + stored_state.real_variable_tags = circuit_constructor.real_variable_tags; + stored_state.constant_variable_indices = circuit_constructor.constant_variable_indices; + stored_state.w_l = circuit_constructor.w_l; + stored_state.w_r = circuit_constructor.w_r; + stored_state.w_o = circuit_constructor.w_o; + stored_state.w_4 = circuit_constructor.w_4; + stored_state.q_m = circuit_constructor.q_m; + stored_state.q_c = circuit_constructor.q_c; + stored_state.q_1 = circuit_constructor.q_1; + stored_state.q_2 = circuit_constructor.q_2; + stored_state.q_3 = circuit_constructor.q_3; + stored_state.q_4 = circuit_constructor.q_4; + stored_state.q_arith = circuit_constructor.q_arith; + stored_state.q_sort = circuit_constructor.q_sort; + stored_state.q_elliptic = circuit_constructor.q_elliptic; + stored_state.q_aux = circuit_constructor.q_aux; + stored_state.q_lookup_type = circuit_constructor.q_lookup_type; + stored_state.current_tag = circuit_constructor.current_tag; + stored_state.tau = circuit_constructor.tau; + + stored_state.ram_arrays = circuit_constructor.ram_arrays; + stored_state.rom_arrays = circuit_constructor.rom_arrays; + + stored_state.memory_read_records = circuit_constructor.memory_read_records; + stored_state.memory_write_records = circuit_constructor.memory_write_records; + stored_state.range_lists = circuit_constructor.range_lists; + stored_state.circuit_finalised = circuit_constructor.circuit_finalised; + stored_state.num_gates = circuit_constructor.num_gates; + return stored_state; + } + /** + * @brief CHecks that the circuit states is the same as the stored circuit's one + * + * @param circuit_constructor + * @return true + * @return false + */ + template bool is_same_state(const CircuitConstructor& circuit_constructor) + { + if (!(public_inputs == circuit_constructor.public_inputs)) { + return false; + } + if (!(variables == circuit_constructor.variables)) { + return false; + } + if (!(next_var_index == circuit_constructor.next_var_index)) { + return false; + } + if (!(prev_var_index == circuit_constructor.prev_var_index)) { + return false; + } + if (!(real_variable_index == circuit_constructor.real_variable_index)) { + return false; + } + if (!(real_variable_tags == circuit_constructor.real_variable_tags)) { + return false; + } + if (!(constant_variable_indices == circuit_constructor.constant_variable_indices)) { + return false; + } + if (!(w_l == circuit_constructor.w_l)) { + return false; + } + if (!(w_r == circuit_constructor.w_r)) { + return false; + } + if (!(w_o == circuit_constructor.w_o)) { + return false; + } + if (!(w_4 == circuit_constructor.w_4)) { + return false; + } + if (!(q_m == circuit_constructor.q_m)) { + return false; + } + if (!(q_c == circuit_constructor.q_c)) { + return false; + } + if (!(q_1 == circuit_constructor.q_1)) { + return false; + } + if (!(q_2 == circuit_constructor.q_2)) { + return false; + } + if (!(q_3 == circuit_constructor.q_3)) { + return false; + } + if (!(q_4 == circuit_constructor.q_4)) { + return false; + } + if (!(q_arith == circuit_constructor.q_arith)) { + return false; + } + if (!(q_sort == circuit_constructor.q_sort)) { + return false; + } + if (!(q_elliptic == circuit_constructor.q_elliptic)) { + return false; + } + if (!(q_aux == circuit_constructor.q_aux)) { + return false; + } + if (!(q_lookup_type == circuit_constructor.q_lookup_type)) { + return false; + } + if (!(current_tag == circuit_constructor.current_tag)) { + return false; + } + if (!(tau == circuit_constructor.tau)) { + return false; + } + if (!(ram_arrays == circuit_constructor.ram_arrays)) { + return false; + } + if (!(rom_arrays == circuit_constructor.rom_arrays)) { + return false; + } + if (!(memory_read_records == circuit_constructor.memory_read_records)) { + return false; + } + if (!(memory_write_records == circuit_constructor.memory_write_records)) { + return false; + } + if (!(range_lists == circuit_constructor.range_lists)) { + return false; + } + if (!(num_gates == circuit_constructor.num_gates)) { + return false; + } + if (!(circuit_finalised == circuit_constructor.circuit_finalised)) { + return false; + } + return true; } - return true; - } -}; -class UltraCircuitConstructor : public CircuitConstructorBase { - public: + }; + // We use the concept of "Circuit-in-the-head" for the check_circuit method. We have to finalize the circuit to // check it, so we put all the updates in this structure, instead of messing with the circuit itself CircuitInTheHead circuit_in_the_head; @@ -459,11 +399,6 @@ class UltraCircuitConstructor : public CircuitConstructorBase& q_aux = std::get<9>(selectors); std::vector& q_lookup_type = std::get<10>(selectors); - // TODO(#216)(Kesha): replace this with Honk enums after we have a verifier and no longer depend on plonk - // prover/verifier - static constexpr ComposerType type = ComposerType::STANDARD_HONK; - static constexpr size_t UINT_LOG2_BASE = 2; - // These are variables that we have used a gate on, to enforce that they are // equal to a defined value. // TODO(#216)(Adrian): Why is this not in CircuitConstructorBase diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp index 09dfbe4eff..13182bc97c 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp @@ -92,7 +92,7 @@ TEST(ultra_circuit_constructor, create_gates_from_plookup_accumulators) EXPECT_EQ(circuit_constructor.get_variable(lookup_witnesses_hi[ColumnIdx::C3][i]), expected_y[i + num_lookups_lo]); } - auto saved_state = CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); @@ -166,7 +166,7 @@ TEST(ultra_circuit_constructor, test_elliptic_gate) gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta.sqr(), -1 }; circuit_constructor.create_ecc_add_gate(gate); - auto saved_state = CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); @@ -202,7 +202,7 @@ TEST(ultra_circuit_constructor, non_trivial_tag_permutation) circuit_constructor.assign_tag(c_idx, 2); circuit_constructor.assign_tag(d_idx, 2); - auto saved_state = CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); @@ -247,7 +247,7 @@ TEST(ultra_circuit_constructor, non_trivial_tag_permutation_and_cycles) circuit_constructor.create_add_gate( { e_idx, f_idx, circuit_constructor.zero_idx, fr::one(), -fr::one(), fr::zero(), fr::zero() }); - auto saved_state = CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); @@ -271,7 +271,7 @@ TEST(ultra_circuit_constructor, bad_tag_permutation) circuit_constructor.create_add_gate({ a_idx, b_idx, circuit_constructor.zero_idx, 1, 1, 0, 0 }); circuit_constructor.create_add_gate({ c_idx, d_idx, circuit_constructor.zero_idx, 1, 1, 0, -1 }); - auto saved_state = CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); @@ -640,7 +640,7 @@ TEST(ultra_circuit_constructor, non_native_field_multiplication) const auto q_indices = get_limb_witness_indices(split_into_limbs(uint256_t(q))); const auto r_indices = get_limb_witness_indices(split_into_limbs(uint256_t(r))); - proof_system::non_native_field_witnesses inputs{ + proof_system::UltraCircuitConstructor::non_native_field_witnesses inputs{ a_indices, b_indices, q_indices, r_indices, modulus_limbs, fr(uint256_t(modulus)), }; const auto [lo_1_idx, hi_1_idx] = circuit_constructor.evaluate_non_native_field_multiplication(inputs); @@ -753,7 +753,7 @@ TEST(ultra_circuit_constructor, ram) }, false); - auto saved_state = CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); From 26abe0e0ca589107afd2480cc9f5bd74b61e7570 Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Tue, 25 Apr 2023 14:43:44 +0000 Subject: [PATCH 09/11] Fixed non-native caching --- .../ultra_circuit_constructor.cpp | 50 +++++++------- .../ultra_circuit_constructor.hpp | 65 +++++++++++++++++++ .../ultra_circuit_constructor.test.cpp | 5 +- 3 files changed, 95 insertions(+), 25 deletions(-) diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp index b11f8530b5..b421e0bbaa 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp @@ -1409,12 +1409,14 @@ std::array UltraCircuitConstructor::queue_non_native_field_multipli */ void UltraCircuitConstructor::process_non_native_field_multiplications() { - std::sort(cached_non_native_field_multiplications.begin(), cached_non_native_field_multiplications.end()); + ENABLE_ALL_IN_THE_HEAD_SWITCHES + std::sort(switched_cached_non_native_field_multiplications.begin(), + switched_cached_non_native_field_multiplications.end()); - auto last = - std::unique(cached_non_native_field_multiplications.begin(), cached_non_native_field_multiplications.end()); + auto last = std::unique(switched_cached_non_native_field_multiplications.begin(), + switched_cached_non_native_field_multiplications.end()); - auto it = cached_non_native_field_multiplications.begin(); + auto it = switched_cached_non_native_field_multiplications.begin(); constexpr barretenberg::fr LIMB_SHIFT = uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS; constexpr barretenberg::fr LIMB_RSHIFT = @@ -1445,30 +1447,30 @@ void UltraCircuitConstructor::process_non_native_field_multiplications() 0 }, true); - w_l.emplace_back(input.a[1]); - w_r.emplace_back(input.b[1]); - w_o.emplace_back(input.r[0]); - w_4.emplace_back(lo_0_idx); + switched_w_l.emplace_back(input.a[1]); + switched_w_r.emplace_back(input.b[1]); + switched_w_o.emplace_back(input.r[0]); + switched_w_4.emplace_back(lo_0_idx); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_1); - ++num_gates; - w_l.emplace_back(input.a[0]); - w_r.emplace_back(input.b[0]); - w_o.emplace_back(input.a[3]); - w_4.emplace_back(input.b[3]); + ++switched_num_gates; + switched_w_l.emplace_back(input.a[0]); + switched_w_r.emplace_back(input.b[0]); + switched_w_o.emplace_back(input.a[3]); + switched_w_4.emplace_back(input.b[3]); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_2); - ++num_gates; - w_l.emplace_back(input.a[2]); - w_r.emplace_back(input.b[2]); - w_o.emplace_back(input.r[3]); - w_4.emplace_back(hi_0_idx); + ++switched_num_gates; + switched_w_l.emplace_back(input.a[2]); + switched_w_r.emplace_back(input.b[2]); + switched_w_o.emplace_back(input.r[3]); + switched_w_4.emplace_back(hi_0_idx); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_3); - ++num_gates; - w_l.emplace_back(input.a[1]); - w_r.emplace_back(input.b[1]); - w_o.emplace_back(input.r[2]); - w_4.emplace_back(hi_1_idx); + ++switched_num_gates; + switched_w_l.emplace_back(input.a[1]); + switched_w_r.emplace_back(input.b[1]); + switched_w_o.emplace_back(input.r[2]); + switched_w_4.emplace_back(hi_1_idx); apply_aux_selectors(AUX_SELECTORS::NONE); - ++num_gates; + ++switched_num_gates; /** * product gate 6 diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp index 699b8d8c17..483964856a 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp @@ -174,7 +174,61 @@ class UltraCircuitConstructor : public CircuitConstructorBase a; + std::array b; + std::array q; + std::array r; + non_native_field_multiplication_cross_terms cross_terms; + std::array neg_modulus; + bool operator==(const cached_non_native_field_multiplication& other) const + { + bool valid = true; + for (size_t i = 0; i < 5; ++i) { + valid = valid && (a[i] == other.a[i]); + valid = valid && (b[i] == other.b[i]); + valid = valid && (q[i] == other.q[i]); + valid = valid && (r[i] == other.r[i]); + } + return valid; + } + bool operator<(const cached_non_native_field_multiplication& other) const + { + if (a < other.a) { + return true; + } + if (a == other.a) { + if (b < other.b) { + return true; + } + if (b == other.b) { + if (q < other.q) { + return true; + } + if (q == other.q) { + if (r < other.r) { + return true; + } + } + } + } + return false; + } + }; /** * @brief Circuit-in-the-head is a structure we use to store all the information about the circuit which should be * used during check_circuit method call, but needs to be discarded later @@ -218,6 +272,10 @@ class UltraCircuitConstructor : public CircuitConstructorBase memory_read_records; std::vector memory_write_records; std::map range_lists; + + std::vector + cached_non_native_field_multiplications; + size_t num_gates; bool circuit_finalised = false; /** @@ -269,6 +327,8 @@ class UltraCircuitConstructor : public CircuitConstructorBase Date: Wed, 26 Apr 2023 22:56:13 +0000 Subject: [PATCH 10/11] Changed check_circuit according to Cody's suggestion --- .../ultra_circuit_constructor.cpp | 715 ++++++++---------- .../ultra_circuit_constructor.hpp | 281 +++---- .../ultra_circuit_constructor.test.cpp | 14 +- 3 files changed, 411 insertions(+), 599 deletions(-) diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp index b421e0bbaa..a12364f702 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp @@ -42,14 +42,12 @@ void UltraCircuitConstructor::finalize_circuit() * Therefore, we introduce a boolean flag `circuit_finalised` here. Once we add the rom and range gates, * our circuit is finalised, and we must not to execute these functions again. */ - bool switched_circuit_finalised = - (in_the_head && circuit_in_the_head.circuit_finalised) | (!in_the_head && circuit_finalised); - if (!switched_circuit_finalised) { + if (!circuit_finalised) { process_non_native_field_multiplications(); process_ROM_arrays(public_inputs.size()); process_RAM_arrays(public_inputs.size()); process_range_lists(); - switched_circuit_finalised = true; + circuit_finalised = true; } } @@ -93,24 +91,23 @@ void UltraCircuitConstructor::create_add_gate(const add_triple& in) */ void UltraCircuitConstructor::create_big_add_gate(const add_quad& in, const bool include_next_gate_w_4) { - ENABLE_ALL_IN_THE_HEAD_SWITCHES assert_valid_variables({ in.a, in.b, in.c, in.d }); - switched_w_l.emplace_back(in.a); - switched_w_r.emplace_back(in.b); - switched_w_o.emplace_back(in.c); - switched_w_4.emplace_back(in.d); - switched_q_m.emplace_back(0); - switched_q_1.emplace_back(in.a_scaling); - switched_q_2.emplace_back(in.b_scaling); - switched_q_3.emplace_back(in.c_scaling); - switched_q_c.emplace_back(in.const_scaling); - switched_q_arith.emplace_back(include_next_gate_w_4 ? 2 : 1); - switched_q_4.emplace_back(in.d_scaling); - switched_q_sort.emplace_back(0); - switched_q_lookup_type.emplace_back(0); - switched_q_elliptic.emplace_back(0); - switched_q_aux.emplace_back(0); - ++switched_num_gates; + w_l.emplace_back(in.a); + w_r.emplace_back(in.b); + w_o.emplace_back(in.c); + w_4.emplace_back(in.d); + q_m.emplace_back(0); + q_1.emplace_back(in.a_scaling); + q_2.emplace_back(in.b_scaling); + q_3.emplace_back(in.c_scaling); + q_c.emplace_back(in.const_scaling); + q_arith.emplace_back(include_next_gate_w_4 ? 2 : 1); + q_4.emplace_back(in.d_scaling); + q_sort.emplace_back(0); + q_lookup_type.emplace_back(0); + q_elliptic.emplace_back(0); + q_aux.emplace_back(0); + ++num_gates; } /** @@ -405,37 +402,34 @@ void UltraCircuitConstructor::create_ecc_add_gate(const ecc_add_gate& in) */ void UltraCircuitConstructor::fix_witness(const uint32_t witness_index, const barretenberg::fr& witness_value) { - ENABLE_ALL_IN_THE_HEAD_SWITCHES assert_valid_variables({ witness_index }); - switched_w_l.emplace_back(witness_index); - switched_w_r.emplace_back(zero_idx); - switched_w_o.emplace_back(zero_idx); - switched_w_4.emplace_back(zero_idx); - switched_q_m.emplace_back(0); - switched_q_1.emplace_back(1); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(0); - switched_q_c.emplace_back(-witness_value); - switched_q_arith.emplace_back(1); - switched_q_4.emplace_back(0); - switched_q_sort.emplace_back(0); - switched_q_lookup_type.emplace_back(0); - switched_q_elliptic.emplace_back(0); - switched_q_aux.emplace_back(0); - ++switched_num_gates; + w_l.emplace_back(witness_index); + w_r.emplace_back(zero_idx); + w_o.emplace_back(zero_idx); + w_4.emplace_back(zero_idx); + q_m.emplace_back(0); + q_1.emplace_back(1); + q_2.emplace_back(0); + q_3.emplace_back(0); + q_c.emplace_back(-witness_value); + q_arith.emplace_back(1); + q_4.emplace_back(0); + q_sort.emplace_back(0); + q_lookup_type.emplace_back(0); + q_elliptic.emplace_back(0); + q_aux.emplace_back(0); + ++num_gates; } uint32_t UltraCircuitConstructor::put_constant_variable(const barretenberg::fr& variable) { - auto& switched_constant_variable_indices = - choose_virtual_or_real(circuit_in_the_head.constant_variable_indices, constant_variable_indices, in_the_head); - if (switched_constant_variable_indices.contains(variable)) { + if (constant_variable_indices.contains(variable)) { return constant_variable_indices.at(variable); } else { uint32_t variable_index = add_variable(variable); fix_witness(variable_index, variable); - switched_constant_variable_indices.insert({ variable, variable_index }); + constant_variable_indices.insert({ variable, variable_index }); return variable_index; } } @@ -653,19 +647,18 @@ void UltraCircuitConstructor::create_new_range_constraint(const uint32_t variabl const uint64_t target_range, std::string const msg) { - ENABLE_ALL_IN_THE_HEAD_SWITCHES if (uint256_t(get_variable(variable_index)).data[0] > target_range) { if (!failed()) { failure(msg); } } - if (switched_range_lists.count(target_range) == 0) { - switched_range_lists.insert({ target_range, create_range_list(target_range) }); + if (range_lists.count(target_range) == 0) { + range_lists.insert({ target_range, create_range_list(target_range) }); } - const auto existing_tag = switched_real_variable_tags[switched_real_variable_index[variable_index]]; - auto& list = switched_range_lists[target_range]; + const auto existing_tag = real_variable_tags[real_variable_index[variable_index]]; + auto& list = range_lists[target_range]; // If the variable's tag matches the target range list's tag, do nothing. if (existing_tag != list.range_tag) { @@ -745,8 +738,7 @@ void UltraCircuitConstructor::process_range_list(const RangeList& list) void UltraCircuitConstructor::process_range_lists() { - ENABLE_ALL_IN_THE_HEAD_SWITCHES - for (const auto& i : switched_range_lists) + for (const auto& i : range_lists) process_range_list(i.second); } @@ -811,7 +803,6 @@ void UltraCircuitConstructor::create_sort_constraint(const std::vector // multiples of three void UltraCircuitConstructor::create_dummy_constraints(const std::vector& variable_index) { - ENABLE_ALL_IN_THE_HEAD_SWITCHES std::vector padded_list = variable_index; constexpr size_t gate_width = plonk::ultra_settings::program_width; const uint64_t padding = (gate_width - (padded_list.size() % gate_width)) % gate_width; @@ -822,22 +813,22 @@ void UltraCircuitConstructor::create_dummy_constraints(const std::vector gate_width); assert_valid_variables(variable_index); // enforce range checks of first row and starting at start - switched_w_l.emplace_back(variable_index[0]); - switched_w_r.emplace_back(variable_index[1]); - switched_w_o.emplace_back(variable_index[2]); - switched_w_4.emplace_back(variable_index[3]); - ++switched_num_gates; - switched_q_m.emplace_back(0); - switched_q_1.emplace_back(1); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(0); - switched_q_c.emplace_back(-start); - switched_q_arith.emplace_back(1); - switched_q_4.emplace_back(0); - switched_q_sort.emplace_back(1); - switched_q_elliptic.emplace_back(0); - switched_q_lookup_type.emplace_back(0); - switched_q_aux.emplace_back(0); + w_l.emplace_back(variable_index[0]); + w_r.emplace_back(variable_index[1]); + w_o.emplace_back(variable_index[2]); + w_4.emplace_back(variable_index[3]); + ++num_gates; + q_m.emplace_back(0); + q_1.emplace_back(1); + q_2.emplace_back(0); + q_3.emplace_back(0); + q_c.emplace_back(-start); + q_arith.emplace_back(1); + q_4.emplace_back(0); + q_sort.emplace_back(1); + q_elliptic.emplace_back(0); + q_lookup_type.emplace_back(0); + q_aux.emplace_back(0); // enforce range check for middle rows for (size_t i = gate_width; i < variable_index.size() - gate_width; i += gate_width) { - switched_w_l.emplace_back(variable_index[i]); - switched_w_r.emplace_back(variable_index[i + 1]); - switched_w_o.emplace_back(variable_index[i + 2]); - switched_w_4.emplace_back(variable_index[i + 3]); - ++switched_num_gates; - switched_q_m.emplace_back(0); - switched_q_1.emplace_back(0); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(0); - switched_q_c.emplace_back(0); - switched_q_arith.emplace_back(0); - switched_q_4.emplace_back(0); - switched_q_sort.emplace_back(1); - switched_q_elliptic.emplace_back(0); - switched_q_lookup_type.emplace_back(0); - switched_q_aux.emplace_back(0); + w_l.emplace_back(variable_index[i]); + w_r.emplace_back(variable_index[i + 1]); + w_o.emplace_back(variable_index[i + 2]); + w_4.emplace_back(variable_index[i + 3]); + ++num_gates; + q_m.emplace_back(0); + q_1.emplace_back(0); + q_2.emplace_back(0); + q_3.emplace_back(0); + q_c.emplace_back(0); + q_arith.emplace_back(0); + q_4.emplace_back(0); + q_sort.emplace_back(1); + q_elliptic.emplace_back(0); + q_lookup_type.emplace_back(0); + q_aux.emplace_back(0); } // enforce range checks of last row and ending at end if (variable_index.size() > gate_width) { - switched_w_l.emplace_back(variable_index[variable_index.size() - 4]); - switched_w_r.emplace_back(variable_index[variable_index.size() - 3]); - switched_w_o.emplace_back(variable_index[variable_index.size() - 2]); - switched_w_4.emplace_back(variable_index[variable_index.size() - 1]); - ++switched_num_gates; - switched_q_m.emplace_back(0); - switched_q_1.emplace_back(0); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(0); - switched_q_c.emplace_back(0); - switched_q_arith.emplace_back(0); - switched_q_4.emplace_back(0); - switched_q_sort.emplace_back(1); - switched_q_elliptic.emplace_back(0); - switched_q_lookup_type.emplace_back(0); - switched_q_aux.emplace_back(0); + w_l.emplace_back(variable_index[variable_index.size() - 4]); + w_r.emplace_back(variable_index[variable_index.size() - 3]); + w_o.emplace_back(variable_index[variable_index.size() - 2]); + w_4.emplace_back(variable_index[variable_index.size() - 1]); + ++num_gates; + q_m.emplace_back(0); + q_1.emplace_back(0); + q_2.emplace_back(0); + q_3.emplace_back(0); + q_c.emplace_back(0); + q_arith.emplace_back(0); + q_4.emplace_back(0); + q_sort.emplace_back(1); + q_elliptic.emplace_back(0); + q_lookup_type.emplace_back(0); + q_aux.emplace_back(0); } // dummy gate needed because of sort widget's check of next row // use this gate to check end condition - switched_w_l.emplace_back(variable_index[variable_index.size() - 1]); - switched_w_r.emplace_back(zero_idx); - switched_w_o.emplace_back(zero_idx); - switched_w_4.emplace_back(zero_idx); - ++switched_num_gates; - switched_q_m.emplace_back(0); - switched_q_1.emplace_back(1); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(0); - switched_q_c.emplace_back(-end); - switched_q_arith.emplace_back(1); - switched_q_4.emplace_back(0); - switched_q_sort.emplace_back(0); - switched_q_elliptic.emplace_back(0); - switched_q_lookup_type.emplace_back(0); - switched_q_aux.emplace_back(0); + w_l.emplace_back(variable_index[variable_index.size() - 1]); + w_r.emplace_back(zero_idx); + w_o.emplace_back(zero_idx); + w_4.emplace_back(zero_idx); + ++num_gates; + q_m.emplace_back(0); + q_1.emplace_back(1); + q_2.emplace_back(0); + q_3.emplace_back(0); + q_c.emplace_back(-end); + q_arith.emplace_back(1); + q_4.emplace_back(0); + q_sort.emplace_back(0); + q_elliptic.emplace_back(0); + q_lookup_type.emplace_back(0); + q_aux.emplace_back(0); } // range constraint a value by decomposing it into limbs whose size should be the default range constraint size @@ -1027,60 +1017,59 @@ std::vector UltraCircuitConstructor::decompose_into_default_range_bett */ void UltraCircuitConstructor::apply_aux_selectors(const AUX_SELECTORS type) { - ENABLE_ALL_IN_THE_HEAD_SWITCHES - switched_q_aux.emplace_back(type == AUX_SELECTORS::NONE ? 0 : 1); - switched_q_sort.emplace_back(0); - switched_q_lookup_type.emplace_back(0); - switched_q_elliptic.emplace_back(0); + q_aux.emplace_back(type == AUX_SELECTORS::NONE ? 0 : 1); + q_sort.emplace_back(0); + q_lookup_type.emplace_back(0); + q_elliptic.emplace_back(0); switch (type) { case AUX_SELECTORS::LIMB_ACCUMULATE_1: { - switched_q_1.emplace_back(0); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(1); - switched_q_4.emplace_back(1); - switched_q_m.emplace_back(0); - switched_q_c.emplace_back(0); - switched_q_arith.emplace_back(0); + q_1.emplace_back(0); + q_2.emplace_back(0); + q_3.emplace_back(1); + q_4.emplace_back(1); + q_m.emplace_back(0); + q_c.emplace_back(0); + q_arith.emplace_back(0); break; } case AUX_SELECTORS::LIMB_ACCUMULATE_2: { - switched_q_1.emplace_back(0); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(1); - switched_q_4.emplace_back(0); - switched_q_m.emplace_back(1); - switched_q_c.emplace_back(0); - switched_q_arith.emplace_back(0); + q_1.emplace_back(0); + q_2.emplace_back(0); + q_3.emplace_back(1); + q_4.emplace_back(0); + q_m.emplace_back(1); + q_c.emplace_back(0); + q_arith.emplace_back(0); break; } case AUX_SELECTORS::NON_NATIVE_FIELD_1: { - switched_q_1.emplace_back(0); - switched_q_2.emplace_back(1); - switched_q_3.emplace_back(1); - switched_q_4.emplace_back(0); - switched_q_m.emplace_back(0); - switched_q_c.emplace_back(0); - switched_q_arith.emplace_back(0); + q_1.emplace_back(0); + q_2.emplace_back(1); + q_3.emplace_back(1); + q_4.emplace_back(0); + q_m.emplace_back(0); + q_c.emplace_back(0); + q_arith.emplace_back(0); break; } case AUX_SELECTORS::NON_NATIVE_FIELD_2: { - switched_q_1.emplace_back(0); - switched_q_2.emplace_back(1); - switched_q_3.emplace_back(0); - switched_q_4.emplace_back(1); - switched_q_m.emplace_back(0); - switched_q_c.emplace_back(0); - switched_q_arith.emplace_back(0); + q_1.emplace_back(0); + q_2.emplace_back(1); + q_3.emplace_back(0); + q_4.emplace_back(1); + q_m.emplace_back(0); + q_c.emplace_back(0); + q_arith.emplace_back(0); break; } case AUX_SELECTORS::NON_NATIVE_FIELD_3: { - switched_q_1.emplace_back(0); - switched_q_2.emplace_back(1); - switched_q_3.emplace_back(0); - switched_q_4.emplace_back(0); - switched_q_m.emplace_back(1); - switched_q_c.emplace_back(0); - switched_q_arith.emplace_back(0); + q_1.emplace_back(0); + q_2.emplace_back(1); + q_3.emplace_back(0); + q_4.emplace_back(0); + q_m.emplace_back(1); + q_c.emplace_back(0); + q_arith.emplace_back(0); break; } case AUX_SELECTORS::ROM_CONSISTENCY_CHECK: { @@ -1088,13 +1077,13 @@ void UltraCircuitConstructor::apply_aux_selectors(const AUX_SELECTORS type) // Apply sorted memory read checks with the following additional check: // 1. Assert that if index field across two gates does not change, the value field does not change. // Used for ROM reads and RAM reads across write/read boundaries - switched_q_1.emplace_back(1); - switched_q_2.emplace_back(1); - switched_q_3.emplace_back(0); - switched_q_4.emplace_back(0); - switched_q_m.emplace_back(0); - switched_q_c.emplace_back(0); - switched_q_arith.emplace_back(0); + q_1.emplace_back(1); + q_2.emplace_back(1); + q_3.emplace_back(0); + q_4.emplace_back(0); + q_m.emplace_back(0); + q_c.emplace_back(0); + q_arith.emplace_back(0); break; } case AUX_SELECTORS::RAM_CONSISTENCY_CHECK: { @@ -1103,74 +1092,74 @@ void UltraCircuitConstructor::apply_aux_selectors(const AUX_SELECTORS type) // 2. Validate record computation (r = read_write_flag + index * \eta + \timestamp * \eta^2 + value * \eta^3) // 3. If adjacent index values across 2 gates does not change, and the next gate's read_write_flag is set to // 'read', validate adjacent values do not change Used for ROM reads and RAM reads across read/write boundaries - switched_q_1.emplace_back(0); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(0); - switched_q_4.emplace_back(0); - switched_q_m.emplace_back(0); - switched_q_c.emplace_back(0); - switched_q_arith.emplace_back(1); + q_1.emplace_back(0); + q_2.emplace_back(0); + q_3.emplace_back(0); + q_4.emplace_back(0); + q_m.emplace_back(0); + q_c.emplace_back(0); + q_arith.emplace_back(1); break; } case AUX_SELECTORS::RAM_TIMESTAMP_CHECK: { // For two adjacent RAM entries that share the same index, validate the timestamp value is monotonically // increasing - switched_q_1.emplace_back(1); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(0); - switched_q_4.emplace_back(1); - switched_q_m.emplace_back(0); - switched_q_c.emplace_back(0); - switched_q_arith.emplace_back(0); + q_1.emplace_back(1); + q_2.emplace_back(0); + q_3.emplace_back(0); + q_4.emplace_back(1); + q_m.emplace_back(0); + q_c.emplace_back(0); + q_arith.emplace_back(0); break; } case AUX_SELECTORS::ROM_READ: { // Memory read gate for reading memory cells. // Validates record witness computation (r = read_write_flag + index * \eta + timestamp * \eta^2 + value * // \eta^3) - switched_q_1.emplace_back(1); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(0); - switched_q_4.emplace_back(0); - switched_q_m.emplace_back(1); // validate record witness is correctly computed - switched_q_c.emplace_back(0); // read/write flag stored in switched_q_c - switched_q_arith.emplace_back(0); + q_1.emplace_back(1); + q_2.emplace_back(0); + q_3.emplace_back(0); + q_4.emplace_back(0); + q_m.emplace_back(1); // validate record witness is correctly computed + q_c.emplace_back(0); // read/write flag stored in q_c + q_arith.emplace_back(0); break; } case AUX_SELECTORS::RAM_READ: { // Memory read gate for reading memory cells. // Validates record witness computation (r = read_write_flag + index * \eta + timestamp * \eta^2 + value * // \eta^3) - switched_q_1.emplace_back(1); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(0); - switched_q_4.emplace_back(0); - switched_q_m.emplace_back(1); // validate record witness is correctly computed - switched_q_c.emplace_back(0); // read/write flag stored in switched_q_c - switched_q_arith.emplace_back(0); + q_1.emplace_back(1); + q_2.emplace_back(0); + q_3.emplace_back(0); + q_4.emplace_back(0); + q_m.emplace_back(1); // validate record witness is correctly computed + q_c.emplace_back(0); // read/write flag stored in q_c + q_arith.emplace_back(0); break; } case AUX_SELECTORS::RAM_WRITE: { // Memory read gate for writing memory cells. // Validates record witness computation (r = read_write_flag + index * \eta + timestamp * \eta^2 + value * // \eta^3) - switched_q_1.emplace_back(1); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(0); - switched_q_4.emplace_back(0); - switched_q_m.emplace_back(1); // validate record witness is correctly computed - switched_q_c.emplace_back(1); // read/write flag stored in switched_q_c - switched_q_arith.emplace_back(0); + q_1.emplace_back(1); + q_2.emplace_back(0); + q_3.emplace_back(0); + q_4.emplace_back(0); + q_m.emplace_back(1); // validate record witness is correctly computed + q_c.emplace_back(1); // read/write flag stored in q_c + q_arith.emplace_back(0); break; } default: { - switched_q_1.emplace_back(0); - switched_q_2.emplace_back(0); - switched_q_3.emplace_back(0); - switched_q_4.emplace_back(0); - switched_q_m.emplace_back(0); - switched_q_c.emplace_back(0); - switched_q_arith.emplace_back(0); + q_1.emplace_back(0); + q_2.emplace_back(0); + q_3.emplace_back(0); + q_4.emplace_back(0); + q_m.emplace_back(0); + q_c.emplace_back(0); + q_arith.emplace_back(0); break; } } @@ -1409,14 +1398,12 @@ std::array UltraCircuitConstructor::queue_non_native_field_multipli */ void UltraCircuitConstructor::process_non_native_field_multiplications() { - ENABLE_ALL_IN_THE_HEAD_SWITCHES - std::sort(switched_cached_non_native_field_multiplications.begin(), - switched_cached_non_native_field_multiplications.end()); + std::sort(cached_non_native_field_multiplications.begin(), cached_non_native_field_multiplications.end()); - auto last = std::unique(switched_cached_non_native_field_multiplications.begin(), - switched_cached_non_native_field_multiplications.end()); + auto last = + std::unique(cached_non_native_field_multiplications.begin(), cached_non_native_field_multiplications.end()); - auto it = switched_cached_non_native_field_multiplications.begin(); + auto it = cached_non_native_field_multiplications.begin(); constexpr barretenberg::fr LIMB_SHIFT = uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS; constexpr barretenberg::fr LIMB_RSHIFT = @@ -1447,30 +1434,30 @@ void UltraCircuitConstructor::process_non_native_field_multiplications() 0 }, true); - switched_w_l.emplace_back(input.a[1]); - switched_w_r.emplace_back(input.b[1]); - switched_w_o.emplace_back(input.r[0]); - switched_w_4.emplace_back(lo_0_idx); + w_l.emplace_back(input.a[1]); + w_r.emplace_back(input.b[1]); + w_o.emplace_back(input.r[0]); + w_4.emplace_back(lo_0_idx); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_1); - ++switched_num_gates; - switched_w_l.emplace_back(input.a[0]); - switched_w_r.emplace_back(input.b[0]); - switched_w_o.emplace_back(input.a[3]); - switched_w_4.emplace_back(input.b[3]); + ++num_gates; + w_l.emplace_back(input.a[0]); + w_r.emplace_back(input.b[0]); + w_o.emplace_back(input.a[3]); + w_4.emplace_back(input.b[3]); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_2); - ++switched_num_gates; - switched_w_l.emplace_back(input.a[2]); - switched_w_r.emplace_back(input.b[2]); - switched_w_o.emplace_back(input.r[3]); - switched_w_4.emplace_back(hi_0_idx); + ++num_gates; + w_l.emplace_back(input.a[2]); + w_r.emplace_back(input.b[2]); + w_o.emplace_back(input.r[3]); + w_4.emplace_back(hi_0_idx); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_3); - ++switched_num_gates; - switched_w_l.emplace_back(input.a[1]); - switched_w_r.emplace_back(input.b[1]); - switched_w_o.emplace_back(input.r[2]); - switched_w_4.emplace_back(hi_1_idx); + ++num_gates; + w_l.emplace_back(input.a[1]); + w_r.emplace_back(input.b[1]); + w_o.emplace_back(input.r[2]); + w_4.emplace_back(hi_1_idx); apply_aux_selectors(AUX_SELECTORS::NONE); - ++switched_num_gates; + ++num_gates; /** * product gate 6 @@ -1839,13 +1826,12 @@ void UltraCircuitConstructor::create_ROM_gate(RomRecord& record) // Record wire value can't yet be computed record.record_witness = add_variable(0); apply_aux_selectors(AUX_SELECTORS::ROM_READ); - ENABLE_ALL_IN_THE_HEAD_SWITCHES - switched_w_l.emplace_back(record.index_witness); - switched_w_r.emplace_back(record.value_column1_witness); - switched_w_o.emplace_back(record.value_column2_witness); - switched_w_4.emplace_back(record.record_witness); - record.gate_index = switched_num_gates; - ++switched_num_gates; + w_l.emplace_back(record.index_witness); + w_r.emplace_back(record.value_column1_witness); + w_o.emplace_back(record.value_column2_witness); + w_4.emplace_back(record.record_witness); + record.gate_index = num_gates; + ++num_gates; } /** @@ -1859,13 +1845,12 @@ void UltraCircuitConstructor::create_sorted_ROM_gate(RomRecord& record) { record.record_witness = add_variable(0); apply_aux_selectors(AUX_SELECTORS::ROM_CONSISTENCY_CHECK); - ENABLE_ALL_IN_THE_HEAD_SWITCHES - switched_w_l.emplace_back(record.index_witness); - switched_w_r.emplace_back(record.value_column1_witness); - switched_w_o.emplace_back(record.value_column2_witness); - switched_w_4.emplace_back(record.record_witness); - record.gate_index = switched_num_gates; - ++switched_num_gates; + w_l.emplace_back(record.index_witness); + w_r.emplace_back(record.value_column1_witness); + w_o.emplace_back(record.value_column2_witness); + w_4.emplace_back(record.record_witness); + record.gate_index = num_gates; + ++num_gates; } /** @@ -1904,13 +1889,12 @@ void UltraCircuitConstructor::create_RAM_gate(RamRecord& record) record.record_witness = add_variable(0); apply_aux_selectors(record.access_type == RamRecord::AccessType::READ ? AUX_SELECTORS::RAM_READ : AUX_SELECTORS::RAM_WRITE); - ENABLE_ALL_IN_THE_HEAD_SWITCHES - switched_w_l.emplace_back(record.index_witness); - switched_w_r.emplace_back(record.timestamp_witness); - switched_w_o.emplace_back(record.value_witness); - switched_w_4.emplace_back(record.record_witness); - record.gate_index = switched_num_gates; - ++switched_num_gates; + w_l.emplace_back(record.index_witness); + w_r.emplace_back(record.timestamp_witness); + w_o.emplace_back(record.value_witness); + w_4.emplace_back(record.record_witness); + record.gate_index = num_gates; + ++num_gates; } /** @@ -1922,15 +1906,14 @@ void UltraCircuitConstructor::create_RAM_gate(RamRecord& record) */ void UltraCircuitConstructor::create_sorted_RAM_gate(RamRecord& record) { - ENABLE_ALL_IN_THE_HEAD_SWITCHES record.record_witness = add_variable(0); apply_aux_selectors(AUX_SELECTORS::RAM_CONSISTENCY_CHECK); - switched_w_l.emplace_back(record.index_witness); - switched_w_r.emplace_back(record.timestamp_witness); - switched_w_o.emplace_back(record.value_witness); - switched_w_4.emplace_back(record.record_witness); - record.gate_index = switched_num_gates; - ++switched_num_gates; + w_l.emplace_back(record.index_witness); + w_r.emplace_back(record.timestamp_witness); + w_o.emplace_back(record.value_witness); + w_4.emplace_back(record.record_witness); + record.gate_index = num_gates; + ++num_gates; } /** @@ -1941,9 +1924,8 @@ void UltraCircuitConstructor::create_sorted_RAM_gate(RamRecord& record) */ void UltraCircuitConstructor::create_final_sorted_RAM_gate(RamRecord& record, const size_t ram_array_size) { - ENABLE_ALL_IN_THE_HEAD_SWITCHES record.record_witness = add_variable(0); - record.gate_index = switched_num_gates; + record.gate_index = num_gates; create_big_add_gate({ record.index_witness, @@ -1989,9 +1971,8 @@ void UltraCircuitConstructor::init_RAM_element(const size_t ram_id, const size_t index_value, const uint32_t value_witness) { - ENABLE_ALL_IN_THE_HEAD_SWITCHES - ASSERT(switched_ram_arrays.size() > ram_id); - RamTranscript& ram_array = switched_ram_arrays[ram_id]; + ASSERT(ram_arrays.size() > ram_id); + RamTranscript& ram_array = ram_arrays[ram_id]; const uint32_t index_witness = (index_value == 0) ? zero_idx : put_constant_variable((uint64_t)index_value); ASSERT(ram_array.state.size() > index_value); ASSERT(ram_array.state[index_value] == UNINITIALIZED_MEMORY_RECORD); @@ -2118,8 +2099,7 @@ void UltraCircuitConstructor::set_ROM_element_pair(const size_t rom_id, const size_t index_value, const std::array& value_witnesses) { - auto& switched_rom_arrays = choose_virtual_or_real(circuit_in_the_head.rom_arrays, rom_arrays, in_the_head); - ASSERT(switched_rom_arrays.size() > rom_id); + ASSERT(rom_arrays.size() > rom_id); RomTranscript& rom_array = rom_arrays[rom_id]; const uint32_t index_witness = (index_value == 0) ? zero_idx : put_constant_variable((uint64_t)index_value); ASSERT(rom_array.state.size() > index_value); @@ -2201,10 +2181,7 @@ uint32_t UltraCircuitConstructor::read_ROM_array(const size_t rom_id, const uint void UltraCircuitConstructor::process_ROM_array(const size_t rom_id, const size_t gate_offset_from_public_inputs) { - auto& switched_rom_arrays = choose_virtual_or_real(circuit_in_the_head.rom_arrays, rom_arrays, in_the_head); - auto& switched_memory_read_records = - choose_virtual_or_real(circuit_in_the_head.memory_read_records, memory_read_records, in_the_head); - auto& rom_array = switched_rom_arrays[rom_id]; + auto& rom_array = rom_arrays[rom_id]; const auto read_tag = get_new_tag(); // current_tag + 1; const auto sorted_list_tag = get_new_tag(); // current_tag + 2; create_tag(read_tag, sorted_list_tag); @@ -2254,10 +2231,8 @@ void UltraCircuitConstructor::process_ROM_array(const size_t rom_id, const size_ // record (w4) = w3 * eta^3 + w2 * eta^2 + w1 * eta + read_write_flag (0 for reads, 1 for writes) // Separate containers used to store gate indices of reads and writes. Need to differentiate because of // `read_write_flag` (N.B. all ROM accesses are considered reads. Writes are for RAM operations) - switched_memory_read_records.push_back( - static_cast(sorted_record.gate_index + gate_offset_from_public_inputs)); - switched_memory_read_records.push_back( - static_cast(record.gate_index + gate_offset_from_public_inputs)); + memory_read_records.push_back(static_cast(sorted_record.gate_index + gate_offset_from_public_inputs)); + memory_read_records.push_back(static_cast(record.gate_index + gate_offset_from_public_inputs)); } // One of the checks we run on the sorted list, is to validate the difference between // the index field across two gates is either 0 or 1. @@ -2291,8 +2266,7 @@ void UltraCircuitConstructor::process_ROM_array(const size_t rom_id, const size_ */ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_t gate_offset_from_public_inputs) { - ENABLE_ALL_IN_THE_HEAD_SWITCHES - RamTranscript& ram_array = switched_ram_arrays[ram_id]; + RamTranscript& ram_array = ram_arrays[ram_id]; const auto access_tag = get_new_tag(); // current_tag + 1; const auto sorted_list_tag = get_new_tag(); // current_tag + 2; create_tag(access_tag, sorted_list_tag); @@ -2359,17 +2333,15 @@ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_ switch (record.access_type) { case RamRecord::AccessType::READ: { - switched_memory_read_records.push_back( + memory_read_records.push_back( static_cast(sorted_record.gate_index + gate_offset_from_public_inputs)); - switched_memory_read_records.push_back( - static_cast(record.gate_index + gate_offset_from_public_inputs)); + memory_read_records.push_back(static_cast(record.gate_index + gate_offset_from_public_inputs)); break; } case RamRecord::AccessType::WRITE: { - switched_memory_write_records.push_back( + memory_write_records.push_back( static_cast(sorted_record.gate_index + gate_offset_from_public_inputs)); - switched_memory_write_records.push_back( - static_cast(record.gate_index + gate_offset_from_public_inputs)); + memory_write_records.push_back(static_cast(record.gate_index + gate_offset_from_public_inputs)); break; } default: { @@ -2398,11 +2370,11 @@ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_ uint32_t timestamp_delta_witness = add_variable(timestamp_delta); apply_aux_selectors(AUX_SELECTORS::RAM_TIMESTAMP_CHECK); - switched_w_l.emplace_back(current.index_witness); - switched_w_r.emplace_back(current.timestamp_witness); - switched_w_o.emplace_back(timestamp_delta_witness); - switched_w_4.emplace_back(zero_idx); - ++switched_num_gates; + w_l.emplace_back(current.index_witness); + w_r.emplace_back(current.timestamp_witness); + w_o.emplace_back(timestamp_delta_witness); + w_4.emplace_back(zero_idx); + ++num_gates; // store timestamp offsets for later. Need to apply range checks to them, but calling // `create_new_range_constraint` can add gates. Would ruin the structure of our sorted timestamp list. @@ -3033,9 +3005,7 @@ inline fr UltraCircuitConstructor::compute_auxilary_identity(fr q_aux_value, bool UltraCircuitConstructor::check_circuit() { bool result = true; - // Put the circuit in the head - update_circuit_in_the_head(); - in_the_head = true; + CircuitDataBackup circuit_backup = CircuitDataBackup::store_prefinilized_state(this); // Finalize circuit-in-the-head finalize_circuit(); @@ -3051,10 +3021,10 @@ bool UltraCircuitConstructor::check_circuit() // We need to get all memory std::unordered_set memory_read_record_gates; std::unordered_set memory_write_record_gates; - for (const auto& gate_idx : circuit_in_the_head.memory_read_records) { + for (const auto& gate_idx : memory_read_records) { memory_read_record_gates.insert(gate_idx); } - for (const auto& gate_idx : circuit_in_the_head.memory_write_records) { + for (const auto& gate_idx : memory_write_records) { memory_write_record_gates.insert(gate_idx); } @@ -3111,21 +3081,21 @@ bool UltraCircuitConstructor::check_circuit() // Function to quickly update tag products and encountered variable set by index and value auto update_tag_check_information = [&](size_t variable_index, fr value) { - size_t real_index = circuit_in_the_head.real_variable_index[variable_index]; + size_t real_index = real_variable_index[variable_index]; // Check to ensure that we are not including a variable twice if (encountered_variables.contains(real_index)) { return; } - size_t tag_in = circuit_in_the_head.real_variable_tags[real_index]; + size_t tag_in = real_variable_tags[real_index]; if (tag_in != DUMMY_TAG) { - size_t tag_out = circuit_in_the_head.tau.at((uint32_t)tag_in); + size_t tag_out = tau.at((uint32_t)tag_in); left_tag_product *= value + tag_gamma * fr(tag_in); right_tag_product *= value + tag_gamma * fr(tag_out); encountered_variables.insert(real_index); } }; // For each gate - for (size_t i = 0; i < circuit_in_the_head.num_gates; i++) { + for (size_t i = 0; i < num_gates; i++) { fr q_arith_value; fr q_aux_value; fr q_elliptic_value; @@ -3143,53 +3113,27 @@ bool UltraCircuitConstructor::check_circuit() fr w_4_value; fr w_4_index; // Get the values of selectors and wires and update tag products along the way - if (i < num_gates) { - q_arith_value = q_arith[i]; - q_aux_value = q_aux[i]; - q_elliptic_value = q_elliptic[i]; - q_sort_value = q_sort[i]; - q_lookup_type_value = q_lookup_type[i]; - q_1_value = q_1[i]; - q_2_value = q_2[i]; - q_3_value = q_3[i]; - q_4_value = q_4[i]; - q_m_value = q_m[i]; - q_c_value = q_c[i]; - w_1_value = get_variable(w_l[i]); - update_tag_check_information(w_l[i], w_1_value); - w_2_value = get_variable(w_r[i]); - update_tag_check_information(w_r[i], w_2_value); - w_3_value = get_variable(w_o[i]); - update_tag_check_information(w_o[i], w_3_value); - w_4_value = get_variable(w_4[i]); - // We need to wait before updating tag product for w_4 - w_4_index = w_4[i]; + q_arith_value = q_arith[i]; + q_aux_value = q_aux[i]; + q_elliptic_value = q_elliptic[i]; + q_sort_value = q_sort[i]; + q_lookup_type_value = q_lookup_type[i]; + q_1_value = q_1[i]; + q_2_value = q_2[i]; + q_3_value = q_3[i]; + q_4_value = q_4[i]; + q_m_value = q_m[i]; + q_c_value = q_c[i]; + w_1_value = get_variable(w_l[i]); + update_tag_check_information(w_l[i], w_1_value); + w_2_value = get_variable(w_r[i]); + update_tag_check_information(w_r[i], w_2_value); + w_3_value = get_variable(w_o[i]); + update_tag_check_information(w_o[i], w_3_value); + w_4_value = get_variable(w_4[i]); + // We need to wait before updating tag product for w_4 + w_4_index = w_4[i]; - } else { - // The in-the-head selector and wire variable indices are not copies of the circuit values, but rather the - // continuation of them, so we need to access them at an offset - size_t offset = i - num_gates; - q_arith_value = circuit_in_the_head.q_arith[offset]; - q_aux_value = circuit_in_the_head.q_aux[offset]; - q_elliptic_value = circuit_in_the_head.q_elliptic[offset]; - q_sort_value = circuit_in_the_head.q_sort[offset]; - q_lookup_type_value = circuit_in_the_head.q_lookup_type[offset]; - q_1_value = circuit_in_the_head.q_1[offset]; - q_2_value = circuit_in_the_head.q_2[offset]; - q_3_value = circuit_in_the_head.q_3[offset]; - q_4_value = circuit_in_the_head.q_4[offset]; - q_m_value = circuit_in_the_head.q_m[offset]; - q_c_value = circuit_in_the_head.q_c[offset]; - w_1_value = get_variable(circuit_in_the_head.w_l[offset]); - update_tag_check_information(circuit_in_the_head.w_l[offset], w_1_value); - w_2_value = get_variable(circuit_in_the_head.w_r[offset]); - update_tag_check_information(circuit_in_the_head.w_r[offset], w_2_value); - w_3_value = get_variable(circuit_in_the_head.w_o[offset]); - update_tag_check_information(circuit_in_the_head.w_o[offset], w_3_value); - w_4_value = get_variable(circuit_in_the_head.w_4[offset]); - // We need to wait before updating tag product for w_4 - w_4_index = circuit_in_the_head.w_4[offset]; - } // If we are touching a gate with memory access, we need to update the value of the 4th witness if (memory_read_record_gates.contains(i)) { w_4_value = ((w_3_value * eta + w_2_value) * eta + w_1_value) * eta; @@ -3209,13 +3153,6 @@ bool UltraCircuitConstructor::check_circuit() w_2_shifted_value = get_variable(w_r[i + 1]); w_3_shifted_value = get_variable(w_o[i + 1]); w_4_shifted_value = get_variable(w_4[i + 1]); - } else if (i < (circuit_in_the_head.num_gates - 1)) { - - size_t offset = i - num_gates; - w_1_shifted_value = get_variable(circuit_in_the_head.w_l[offset + 1]); - w_2_shifted_value = get_variable(circuit_in_the_head.w_r[offset + 1]); - w_3_shifted_value = get_variable(circuit_in_the_head.w_o[offset + 1]); - w_4_shifted_value = get_variable(circuit_in_the_head.w_4[offset + 1]); } else { w_1_shifted_value = fr::zero(); w_2_shifted_value = fr::zero(); @@ -3330,56 +3267,8 @@ bool UltraCircuitConstructor::check_circuit() result = false; } - in_the_head = false; + circuit_backup.restore_prefinilized_state(this); return result; } -/** - * @brief Reset the circuit-in-the-head construction that we use for checking the correctness of the circuit to the - * values in the circuit - * - */ -void UltraCircuitConstructor::update_circuit_in_the_head() -{ - // Unfortunately we have to copy all variable structures - circuit_in_the_head.public_inputs = public_inputs; - circuit_in_the_head.variables = variables; - circuit_in_the_head.next_var_index = next_var_index; - circuit_in_the_head.prev_var_index = prev_var_index; - circuit_in_the_head.real_variable_index = real_variable_index; - circuit_in_the_head.real_variable_tags = real_variable_tags; - circuit_in_the_head.constant_variable_indices = constant_variable_indices; - // Reset witness and selector vectors - circuit_in_the_head.w_l.clear(); - circuit_in_the_head.w_r.clear(); - circuit_in_the_head.w_o.clear(); - circuit_in_the_head.w_4.clear(); - circuit_in_the_head.q_m.clear(); - circuit_in_the_head.q_c.clear(); - circuit_in_the_head.q_1.clear(); - circuit_in_the_head.q_2.clear(); - circuit_in_the_head.q_3.clear(); - circuit_in_the_head.q_4.clear(); - circuit_in_the_head.q_arith.clear(); - circuit_in_the_head.q_elliptic.clear(); - circuit_in_the_head.q_aux.clear(); - circuit_in_the_head.q_sort.clear(); - circuit_in_the_head.q_lookup_type.clear(); - // Update current tag in the head to be the same as current real tag - circuit_in_the_head.current_tag = current_tag; - // Reset tau - circuit_in_the_head.tau = tau; - // Copy rom and ram arrays - circuit_in_the_head.rom_arrays = rom_arrays; - circuit_in_the_head.ram_arrays = ram_arrays; - - circuit_in_the_head.memory_read_records = memory_read_records; - circuit_in_the_head.memory_write_records = memory_write_records; - circuit_in_the_head.ram_arrays = ram_arrays; - circuit_in_the_head.rom_arrays = rom_arrays; - circuit_in_the_head.range_lists = range_lists; - - circuit_in_the_head.num_gates = num_gates; - circuit_in_the_head.circuit_finalised = circuit_finalised; -} } // namespace proof_system \ No newline at end of file diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp index 483964856a..4f1df17604 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp @@ -237,7 +237,7 @@ class UltraCircuitConstructor : public CircuitConstructorBase public_inputs; std::vector variables; // index of next variable in equivalence class (=REAL_VARIABLE if you're last) @@ -285,12 +285,12 @@ class UltraCircuitConstructor : public CircuitConstructorBase - static CircuitInTheHead store_state(const CircuitConstructor& circuit_constructor) + static CircuitDataBackup store_full_state(const CircuitConstructor& circuit_constructor) { - CircuitInTheHead stored_state; + CircuitDataBackup stored_state; stored_state.public_inputs = circuit_constructor.public_inputs; stored_state.variables = circuit_constructor.variables; @@ -331,6 +331,98 @@ class UltraCircuitConstructor : public CircuitConstructorBase + static CircuitDataBackup store_prefinilized_state(const CircuitConstructor* circuit_constructor) + { + CircuitDataBackup stored_state; + stored_state.public_inputs = circuit_constructor->public_inputs; + stored_state.variables = circuit_constructor->variables; + + stored_state.next_var_index = circuit_constructor->next_var_index; + + stored_state.prev_var_index = circuit_constructor->prev_var_index; + + stored_state.real_variable_index = circuit_constructor->real_variable_index; + stored_state.real_variable_tags = circuit_constructor->real_variable_tags; + stored_state.constant_variable_indices = circuit_constructor->constant_variable_indices; + stored_state.current_tag = circuit_constructor->current_tag; + stored_state.tau = circuit_constructor->tau; + + stored_state.ram_arrays = circuit_constructor->ram_arrays; + stored_state.rom_arrays = circuit_constructor->rom_arrays; + + stored_state.memory_read_records = circuit_constructor->memory_read_records; + stored_state.memory_write_records = circuit_constructor->memory_write_records; + stored_state.range_lists = circuit_constructor->range_lists; + stored_state.circuit_finalised = circuit_constructor->circuit_finalised; + stored_state.num_gates = circuit_constructor->num_gates; + stored_state.cached_non_native_field_multiplications = + circuit_constructor->cached_non_native_field_multiplications; + + return stored_state; + } + + /** + * @brief Stores the state of all members of the circuit constructor that are needed to restore the state after + * finalizing the circuit. + * + * @details We need this function for tests. Specifically, to ensure that we are not changing anything in + * check_circuit + * + * @param circuit_constructor + * @return CircuitDataBackup + */ + template void restore_prefinilized_state(CircuitConstructor* circuit_constructor) + { + circuit_constructor->public_inputs = public_inputs; + circuit_constructor->variables = variables; + + circuit_constructor->next_var_index = next_var_index; + + circuit_constructor->prev_var_index = prev_var_index; + + circuit_constructor->real_variable_index = real_variable_index; + circuit_constructor->real_variable_tags = real_variable_tags; + circuit_constructor->constant_variable_indices = constant_variable_indices; + circuit_constructor->current_tag = current_tag; + circuit_constructor->tau = tau; + + circuit_constructor->ram_arrays = ram_arrays; + circuit_constructor->rom_arrays = rom_arrays; + + circuit_constructor->memory_read_records = memory_read_records; + circuit_constructor->memory_write_records = memory_write_records; + circuit_constructor->range_lists = range_lists; + circuit_constructor->circuit_finalised = circuit_finalised; + circuit_constructor->num_gates = num_gates; + circuit_constructor->cached_non_native_field_multiplications = cached_non_native_field_multiplications; + circuit_constructor->w_l.resize(num_gates); + circuit_constructor->w_r.resize(num_gates); + circuit_constructor->w_o.resize(num_gates); + circuit_constructor->w_4.resize(num_gates); + circuit_constructor->q_m.resize(num_gates); + circuit_constructor->q_c.resize(num_gates); + circuit_constructor->q_1.resize(num_gates); + circuit_constructor->q_2.resize(num_gates); + circuit_constructor->q_3.resize(num_gates); + circuit_constructor->q_4.resize(num_gates); + circuit_constructor->q_arith.resize(num_gates); + circuit_constructor->q_sort.resize(num_gates); + circuit_constructor->q_elliptic.resize(num_gates); + circuit_constructor->q_aux.resize(num_gates); + circuit_constructor->q_lookup_type.resize(num_gates); + } /** * @brief CHecks that the circuit states is the same as the stored circuit's one * @@ -441,11 +533,6 @@ class UltraCircuitConstructor : public CircuitConstructorBase& w_l = std::get<0>(wires); std::vector& w_r = std::get<1>(wires); std::vector& w_o = std::get<2>(wires); @@ -516,73 +603,6 @@ class UltraCircuitConstructor : public CircuitConstructorBase::add_variable(in); - } - - circuit_in_the_head.variables.emplace_back(in); - - // By default, we assume each new variable belongs in its own copy-cycle. These defaults can be modified later - // by `assert_equal`. - const uint32_t index = static_cast(circuit_in_the_head.variables.size()) - 1U; - circuit_in_the_head.real_variable_index.emplace_back(index); - circuit_in_the_head.next_var_index.emplace_back(REAL_VARIABLE); - circuit_in_the_head.prev_var_index.emplace_back(FIRST_VARIABLE_IN_CLASS); - circuit_in_the_head.real_variable_tags.emplace_back(DUMMY_TAG); - return index; - } - /** - * @brief Get the variable value from the actual of in-the-head circuit - * - * @param index - * @return barretenberg::fr - */ - inline barretenberg::fr get_variable(const uint32_t index) const - { - if (!in_the_head) { - return CircuitConstructorBase::get_variable(index); - } - ASSERT(circuit_in_the_head.variables.size() > index); - return circuit_in_the_head.variables[circuit_in_the_head.real_variable_index[index]]; - } - - /** - * @brief Check that variable indices are valid - * - * @param variable_indices - */ - void assert_valid_variables(const std::vector& variable_indices) - { - for (const auto& variable_index : variable_indices) { - ASSERT(is_valid_variable(variable_index)); - } - } - /** - * @brief Checks that the variable index is valid (in the circuit or in the in-the-head circuit) - * - * @param variable_index - * @return true - * @return false - */ - bool is_valid_variable(uint32_t variable_index) - { - if (in_the_head) { - return variable_index < circuit_in_the_head.variables.size(); - } else { - return variable_index < variables.size(); - } - }; - void finalize_circuit(); void create_add_gate(const add_triple& in) override; @@ -828,37 +848,17 @@ class UltraCircuitConstructor : public CircuitConstructorBase= current_tag); - circuit_in_the_head.tau.insert({ tag_index, tau_index }); - circuit_in_the_head.current_tag++; - return circuit_in_the_head.current_tag; - } tau.insert({ tag_index, tau_index }); current_tag++; // Why exactly? return current_tag; @@ -866,12 +866,6 @@ class UltraCircuitConstructor : public CircuitConstructorBase= current_tag); - circuit_in_the_head.current_tag++; - return circuit_in_the_head.current_tag; - } current_tag++; return current_tag; } @@ -940,77 +934,6 @@ class UltraCircuitConstructor : public CircuitConstructorBase inline T& choose_virtual_or_real(T& virtual_member, T& real_member, bool in_the_head) - { - if (in_the_head) { - return virtual_member; - } else { - return real_member; - } - } - -#define PARENS () -// Rescan macro tokens 256 times -#define EXPAND(arg) EXPAND1(EXPAND1(EXPAND1(EXPAND1(arg)))) -#define EXPAND1(arg) EXPAND2(EXPAND2(EXPAND2(EXPAND2(arg)))) -#define EXPAND2(arg) EXPAND3(EXPAND3(EXPAND3(EXPAND3(arg)))) -#define EXPAND3(arg) EXPAND4(EXPAND4(EXPAND4(EXPAND4(arg)))) -#define EXPAND4(arg) arg - -#define FOR_EACH(macro, ...) __VA_OPT__(EXPAND(FOR_EACH_HELPER(macro, __VA_ARGS__))) -#define FOR_EACH_HELPER(macro, a1, a2, a3, ...) \ - macro(a1, a2, a3) __VA_OPT__(FOR_EACH_AGAIN PARENS(macro, a1, a2, __VA_ARGS__)) -#define FOR_EACH_AGAIN() FOR_EACH_HELPER - -#define HEAD(x, ...) x -#define TAIL(x, ...) __VA_ARGS__ -#define IN_THE_HEAD_MEMBER_NAME(member) circuit_in_the_head.member -#define ASSIGN_VARIABLE_TO_VIRTUAL_OR_REAL(variable_prefix, switch_name, member) \ - auto& variable_prefix##member = choose_virtual_or_real(IN_THE_HEAD_MEMBER_NAME(member), member, switch_name); \ - (void)variable_prefix##member; -#define CHOOSE_VIRTUAL_OR_REAL_MULTIPLE(variable_prefix, switch_name, member_name, ...) \ - FOR_EACH(ASSIGN_VARIABLE_TO_VIRTUAL_OR_REAL, variable_prefix, switch_name, member_name, __VA_ARGS__) -#define ENABLE_ALL_IN_THE_HEAD_SWITCHES \ - CHOOSE_VIRTUAL_OR_REAL_MULTIPLE(switched_, \ - in_the_head, \ - w_l, \ - w_r, \ - w_o, \ - w_4, \ - q_m, \ - q_1, \ - q_2, \ - q_3, \ - q_c, \ - q_arith, \ - q_4, \ - q_sort, \ - q_lookup_type, \ - q_elliptic, \ - q_aux, \ - num_gates, \ - ram_arrays, \ - rom_arrays, \ - memory_read_records, \ - memory_write_records, \ - range_lists, \ - cached_non_native_field_multiplications, \ - real_variable_tags, \ - real_variable_index) // Circuit evaluation methods fr compute_arithmetic_identity(fr q_arith_value, diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp index 2393d811c9..aea6e78bde 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.test.cpp @@ -92,7 +92,7 @@ TEST(ultra_circuit_constructor, create_gates_from_plookup_accumulators) EXPECT_EQ(circuit_constructor.get_variable(lookup_witnesses_hi[ColumnIdx::C3][i]), expected_y[i + num_lookups_lo]); } - auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitDataBackup::store_full_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); @@ -166,7 +166,7 @@ TEST(ultra_circuit_constructor, test_elliptic_gate) gate = ecc_add_gate{ x1, y1, x2, y2, x3, y3, beta.sqr(), -1 }; circuit_constructor.create_ecc_add_gate(gate); - auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitDataBackup::store_full_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); @@ -202,7 +202,7 @@ TEST(ultra_circuit_constructor, non_trivial_tag_permutation) circuit_constructor.assign_tag(c_idx, 2); circuit_constructor.assign_tag(d_idx, 2); - auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitDataBackup::store_full_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); @@ -247,7 +247,7 @@ TEST(ultra_circuit_constructor, non_trivial_tag_permutation_and_cycles) circuit_constructor.create_add_gate( { e_idx, f_idx, circuit_constructor.zero_idx, fr::one(), -fr::one(), fr::zero(), fr::zero() }); - auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitDataBackup::store_full_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); @@ -271,7 +271,7 @@ TEST(ultra_circuit_constructor, bad_tag_permutation) circuit_constructor.create_add_gate({ a_idx, b_idx, circuit_constructor.zero_idx, 1, 1, 0, 0 }); circuit_constructor.create_add_gate({ c_idx, d_idx, circuit_constructor.zero_idx, 1, 1, 0, -1 }); - auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitDataBackup::store_full_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); @@ -646,7 +646,7 @@ TEST(ultra_circuit_constructor, non_native_field_multiplication) const auto [lo_1_idx, hi_1_idx] = circuit_constructor.queue_non_native_field_multiplication(inputs); circuit_constructor.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70); - auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitDataBackup::store_full_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); @@ -756,7 +756,7 @@ TEST(ultra_circuit_constructor, ram) }, false); - auto saved_state = UltraCircuitConstructor::CircuitInTheHead::store_state(circuit_constructor); + auto saved_state = UltraCircuitConstructor::CircuitDataBackup::store_full_state(circuit_constructor); bool result = circuit_constructor.check_circuit(); EXPECT_EQ(result, true); From 3ffca901bf3577136fdcbe880ff78296484426ef Mon Sep 17 00:00:00 2001 From: Rumata888 Date: Wed, 26 Apr 2023 23:06:55 +0000 Subject: [PATCH 11/11] Some cosmetic changes --- .../ultra_circuit_constructor.cpp | 6 +----- .../ultra_circuit_constructor.hpp | 19 ++++++------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp index a12364f702..8cbea71bc5 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.cpp @@ -2353,7 +2353,6 @@ void UltraCircuitConstructor::process_RAM_array(const size_t ram_id, const size_ // Step 2: Create gates that validate correctness of RAM timestamps std::vector timestamp_deltas; - for (size_t i = 0; i < ram_array.records.size() - 1; ++i) { // create_RAM_timestamp_gate(sorted_records[i], sorted_records[i + 1]) const auto& current = ram_array.records[i]; @@ -2415,10 +2414,7 @@ void UltraCircuitConstructor::process_RAM_arrays(const size_t gate_offset_from_p } } -/** - * @brief Various methods relating to circuit evaluation - * - */ +// Various methods relating to circuit evaluation /** * @brief Arithmetic gate-related methods diff --git a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp index 4f1df17604..c939163c31 100644 --- a/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp +++ b/cpp/src/barretenberg/proof_system/circuit_constructors/ultra_circuit_constructor.hpp @@ -230,12 +230,12 @@ class UltraCircuitConstructor : public CircuitConstructorBase public_inputs; @@ -336,9 +336,6 @@ class UltraCircuitConstructor : public CircuitConstructorBaseq_lookup_type.resize(num_gates); } /** - * @brief CHecks that the circuit states is the same as the stored circuit's one + * @brief Checks that the circuit state is the same as the stored circuit's one * * @param circuit_constructor * @return true