diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp index 034bf007d20..0339e7fff1d 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp @@ -692,7 +692,16 @@ template class ZeroMorphVerifier_ { concatenation_group_commitments); // Compute commitment C_{\zeta,Z} - auto C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; + Commitment C_zeta_Z; + if constexpr (Curve::is_stdlib_type) { + // Express operation as a batch_mul in order to use Goblinization if available + auto builder = rho.get_context(); + std::vector scalars = { FF(builder, 1), z_challenge }; + std::vector points = { C_zeta_x, C_Z_x }; + C_zeta_Z = Commitment::batch_mul(points, scalars); + } else { + C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; + } // Receive proof commitment \pi auto C_pi = transcript->template receive_from_prover("ZM:PI"); @@ -702,7 +711,17 @@ template class ZeroMorphVerifier_ { // e(C_{\zeta,Z}, [1]_2) = e(pi, [X - x]_2). This can be rearranged (e.g. see the plonk paper) as // e(C_{\zeta,Z} - x*pi, [1]_2) * e(-pi, [X]_2) = 1, or // e(P_0, [1]_2) * e(P_1, [X]_2) = 1 - auto P0 = C_zeta_Z + C_pi * x_challenge; + Commitment P0; + if constexpr (Curve::is_stdlib_type) { + // Express operation as a batch_mul in order to use Goblinization if available + auto builder = rho.get_context(); + std::vector scalars = { FF(builder, 1), x_challenge }; + std::vector points = { C_zeta_Z, C_pi }; + P0 = Commitment::batch_mul(points, scalars); + } else { + P0 = C_zeta_Z + C_pi * x_challenge; + } + auto P1 = -C_pi; return { P0, P1 }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp index ee2a04f956a..f413ce25523 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.hpp @@ -2,18 +2,21 @@ #include "../bigfield/bigfield.hpp" #include "../byte_array/byte_array.hpp" -#include "../field/field.hpp" -#include "barretenberg/ecc/curves/bn254/g1.hpp" - #include "../circuit_builders/circuit_builders_fwd.hpp" +#include "../field/field.hpp" #include "../memory/rom_table.hpp" #include "../memory/twin_rom_table.hpp" #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/ecc/curves/secp256k1/secp256k1.hpp" #include "barretenberg/ecc/curves/secp256r1/secp256r1.hpp" -namespace proof_system::plonk { -namespace stdlib { +// TODO(https://github.com/AztecProtocol/barretenberg/issues/707) If using a a circuit builder with Goblin, which is +// designed to have efficient barretenberg::g1 operations, a developer might accidentally write inefficient circuits +// using biggroup functions that do not use the OpQueue. We use this concept to prevent compilation of such functions. +template +concept IsNotGoblinInefficiencyTrap = !(IsGoblinBuilder && std::same_as); + +namespace proof_system::plonk::stdlib { // ( ͡° ͜ʖ ͡°) template class element { @@ -154,14 +157,22 @@ template class element { * We can chain repeated point additions together, where we only require 2 non-native field multiplications per * point addition, instead of 3 **/ - static chain_add_accumulator chain_add_start(const element& p1, const element& p2); - static chain_add_accumulator chain_add(const element& p1, const chain_add_accumulator& accumulator); - static element chain_add_end(const chain_add_accumulator& accumulator); - - element montgomery_ladder(const element& other) const; - element montgomery_ladder(const chain_add_accumulator& accumulator); - element multiple_montgomery_ladder(const std::vector& to_add) const; - element quadruple_and_add(const std::vector& to_add) const; + static chain_add_accumulator chain_add_start(const element& p1, const element& p2) + requires(IsNotGoblinInefficiencyTrap); + static chain_add_accumulator chain_add(const element& p1, const chain_add_accumulator& accumulator) + requires(IsNotGoblinInefficiencyTrap); + static element chain_add_end(const chain_add_accumulator& accumulator) + requires(IsNotGoblinInefficiencyTrap); + + element montgomery_ladder(const element& other) const + requires(IsNotGoblinInefficiencyTrap); + element montgomery_ladder(const chain_add_accumulator& accumulator) + requires(IsNotGoblinInefficiencyTrap); + element multiple_montgomery_ladder(const std::vector& to_add) const + requires(IsNotGoblinInefficiencyTrap); + + element quadruple_and_add(const std::vector& to_add) const + requires(IsNotGoblinInefficiencyTrap); typename NativeGroup::affine_element get_value() const { @@ -179,6 +190,9 @@ template class element { static element batch_mul(const std::vector& points, const std::vector& scalars, const size_t max_num_bits = 0); + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/707) max_num_bits is unused; could implement and use + // this to optimize other operations. static element goblin_batch_mul(const std::vector& points, const std::vector& scalars, const size_t max_num_bits = 0); @@ -196,6 +210,7 @@ template class element { // i.e. for the bn254 curve, the template param is `typename = void` // for any other curve, there is no template param template ::value>> + requires(IsNotGoblinBuilder) // TODO(https://github.com/AztecProtocol/barretenberg/issues/707) static element bn254_endo_batch_mul(const std::vector& big_points, const std::vector& big_scalars, const std::vector& small_points, @@ -203,6 +218,7 @@ template class element { const size_t max_num_small_bits); template ::value>> + requires(IsNotGoblinBuilder) // TODO(https://github.com/AztecProtocol/barretenberg/issues/707) static element bn254_endo_batch_mul_with_generator(const std::vector& big_points, const std::vector& big_scalars, const std::vector& small_points, @@ -889,8 +905,7 @@ inline std::ostream& operator<<(std::ostream& os, element const& v { return os << "{ " << v.x << " , " << v.y << " }"; } -} // namespace stdlib -} // namespace proof_system::plonk +} // namespace proof_system::plonk::stdlib #include "biggroup_batch_mul.hpp" #include "biggroup_bn254.hpp" diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp index 3e02c3cb6b0..e80440aaa4f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp @@ -1,19 +1,14 @@ -#include "barretenberg/common/test.hpp" -#include - -#include "../bigfield/bigfield.hpp" #include "../biggroup/biggroup.hpp" +#include "../bigfield/bigfield.hpp" #include "../bool/bool.hpp" #include "../field/field.hpp" +#include "barretenberg/common/test.hpp" +#include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" - #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/primitives/curves/secp256k1.hpp" #include "barretenberg/stdlib/primitives/curves/secp256r1.hpp" -#include "barretenberg/numeric/random/engine.hpp" -#include - namespace test_stdlib_biggroup { namespace { auto& engine = numeric::random::get_debug_engine(); @@ -825,12 +820,17 @@ template class stdlib_biggroup : public testing::Test { enum UseBigfield { No, Yes }; using TestTypes = testing::Types, UseBigfield::No>, - TestType, UseBigfield::Yes>>; + TestType, UseBigfield::Yes>, + TestType, UseBigfield::No>>; TYPED_TEST_SUITE(stdlib_biggroup, TestTypes); +template +concept HasGoblinBuilder = IsGoblinBuilder; + TYPED_TEST(stdlib_biggroup, add) { + TestFixture::test_add(); } TYPED_TEST(stdlib_biggroup, sub) @@ -843,7 +843,11 @@ TYPED_TEST(stdlib_biggroup, dbl) } TYPED_TEST(stdlib_biggroup, montgomery_ladder) { - TestFixture::test_montgomery_ladder(); + if constexpr (HasGoblinBuilder) { + GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707"; + } else { + TestFixture::test_montgomery_ladder(); + }; } HEAVY_TYPED_TEST(stdlib_biggroup, mul) { @@ -851,15 +855,27 @@ HEAVY_TYPED_TEST(stdlib_biggroup, mul) } HEAVY_TYPED_TEST(stdlib_biggroup, twin_mul) { - TestFixture::test_twin_mul(); + if constexpr (HasGoblinBuilder) { + GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707"; + } else { + TestFixture::test_twin_mul(); + }; } HEAVY_TYPED_TEST(stdlib_biggroup, triple_mul) { - TestFixture::test_triple_mul(); + if constexpr (HasGoblinBuilder) { + GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707"; + } else { + TestFixture::test_triple_mul(); + }; } HEAVY_TYPED_TEST(stdlib_biggroup, quad_mul) { - TestFixture::test_quad_mul(); + if constexpr (HasGoblinBuilder) { + GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707"; + } else { + TestFixture::test_quad_mul(); + }; } HEAVY_TYPED_TEST(stdlib_biggroup, one) { @@ -872,12 +888,20 @@ HEAVY_TYPED_TEST(stdlib_biggroup, batch_mul) HEAVY_TYPED_TEST(stdlib_biggroup, chain_add) { - TestFixture::test_chain_add(); + if constexpr (HasGoblinBuilder) { + GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707"; + } else { + TestFixture::test_chain_add(); + }; } HEAVY_TYPED_TEST(stdlib_biggroup, multiple_montgomery_ladder) { - TestFixture::test_multiple_montgomery_ladder(); + if constexpr (HasGoblinBuilder) { + GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707"; + } else { + TestFixture::test_multiple_montgomery_ladder(); + }; } HEAVY_TYPED_TEST(stdlib_biggroup, compute_naf) @@ -897,7 +921,11 @@ HEAVY_TYPED_TEST(stdlib_biggroup, compute_naf) HEAVY_TYPED_TEST(stdlib_biggroup, wnaf_batch_mul) { if constexpr (HasPlookup) { - TestFixture::test_compute_wnaf(); + if constexpr (HasGoblinBuilder) { + GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707"; + } else { + TestFixture::test_compute_wnaf(); + }; } else { GTEST_SKIP(); } @@ -921,7 +949,11 @@ HEAVY_TYPED_TEST(stdlib_biggroup, batch_mul_short_scalars) if constexpr (TypeParam::use_bigfield) { GTEST_SKIP(); } else { - TestFixture::test_batch_mul_short_scalars(); + if constexpr (HasGoblinBuilder) { + GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707"; + } else { + TestFixture::test_batch_mul_short_scalars(); + }; } } HEAVY_TYPED_TEST(stdlib_biggroup, wnaf_batch_mul_128_bit) @@ -929,7 +961,11 @@ HEAVY_TYPED_TEST(stdlib_biggroup, wnaf_batch_mul_128_bit) if constexpr (TypeParam::use_bigfield) { GTEST_SKIP(); } else { - TestFixture::test_wnaf_batch_mul_128_bit(); + if constexpr (HasGoblinBuilder) { + GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707"; + } else { + TestFixture::test_wnaf_batch_mul_128_bit(); + }; } } HEAVY_TYPED_TEST(stdlib_biggroup, wnaf_batch_4) @@ -945,7 +981,11 @@ HEAVY_TYPED_TEST(stdlib_biggroup, wnaf_batch_4) HEAVY_TYPED_TEST(stdlib_biggroup, bn254_endo_batch_mul) { if constexpr (TypeParam::Curve::type == proof_system::CurveType::BN254 && !TypeParam::use_bigfield) { - TestFixture::test_bn254_endo_batch_mul(); + if constexpr (HasGoblinBuilder) { + GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707"; + } else { + TestFixture::test_bn254_endo_batch_mul(); + }; } else { GTEST_SKIP(); } @@ -953,7 +993,11 @@ HEAVY_TYPED_TEST(stdlib_biggroup, bn254_endo_batch_mul) HEAVY_TYPED_TEST(stdlib_biggroup, mixed_mul_bn254_endo) { if constexpr (TypeParam::Curve::type == proof_system::CurveType::BN254 && !TypeParam::use_bigfield) { - TestFixture::test_mixed_mul_bn254_endo(); + if constexpr (HasGoblinBuilder) { + GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707"; + } else { + TestFixture::test_mixed_mul_bn254_endo(); + }; } else { GTEST_SKIP(); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_bn254.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_bn254.hpp index 1384bc2813c..4f4c655e079 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_bn254.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_bn254.hpp @@ -22,6 +22,7 @@ namespace stdlib { **/ template template + requires(IsNotGoblinBuilder) element element::bn254_endo_batch_mul_with_generator( const std::vector& big_points, const std::vector& big_scalars, @@ -216,6 +217,7 @@ element element::bn254_endo_batch_mul_with_generator **/ template template + requires(IsNotGoblinBuilder) element element::bn254_endo_batch_mul(const std::vector& big_points, const std::vector& big_scalars, const std::vector& small_points, diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_impl.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_impl.hpp index a6503bf1285..95302189a68 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_impl.hpp @@ -1,18 +1,11 @@ #pragma once -#include "barretenberg/numeric/uint256/uint256.hpp" -#include "barretenberg/numeric/uintx/uintx.hpp" -#include - -#include "../circuit_builders/circuit_builders.hpp" - #include "../bit_array/bit_array.hpp" -// #include "../field/field.hpp" +#include "../circuit_builders/circuit_builders.hpp" using namespace barretenberg; -namespace proof_system::plonk { -namespace stdlib { +namespace proof_system::plonk::stdlib { template element::element() @@ -63,6 +56,14 @@ element& element::operator=(element&& other) template element element::operator+(const element& other) const { + if constexpr (IsGoblinBuilder && std::same_as) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/707) Optimize + // Current gate count: 6398 + std::vector points{ *this, other }; + std::vector scalars{ 1, 1 }; + return goblin_batch_mul(points, scalars); + } + other.x.assert_is_not_equal(x); const Fq lambda = Fq::div_without_denominator_check({ other.y, -y }, (other.x - x)); const Fq x3 = lambda.sqradd({ -other.x, -x }); @@ -73,6 +74,13 @@ element element::operator+(const element& other) con template element element::operator-(const element& other) const { + if constexpr (IsGoblinBuilder && std::same_as) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/707) Optimize + std::vector points{ *this, other }; + std::vector scalars{ 1, -Fr(1) }; + return goblin_batch_mul(points, scalars); + } + other.x.assert_is_not_equal(x); const Fq lambda = Fq::div_without_denominator_check({ other.y, y }, (other.x - x)); const Fq x_3 = lambda.sqradd({ -other.x, -x }); @@ -95,9 +103,14 @@ element element::operator-(const element& other) con * @param other * @return std::array, 2> */ +// TODO(https://github.com/AztecProtocol/barretenberg/issues/657): This function is untested template std::array, 2> element::add_sub(const element& other) const { + if constexpr (IsGoblinBuilder && std::same_as) { + return { *this + other, *this - other }; + } + other.x.assert_is_not_equal(x); const Fq denominator = other.x - x; @@ -115,6 +128,7 @@ std::array, 2> element::add_sub(const elemen template element element::dbl() const { + Fq two_x = x + x; if constexpr (G::has_a) { Fq a(get_context(), uint256_t(G::curve_a)); @@ -150,6 +164,7 @@ template element element template typename element::chain_add_accumulator element::chain_add_start(const element& p1, const element& p2) + requires(IsNotGoblinInefficiencyTrap) { chain_add_accumulator output; output.x1_prev = p1.x; @@ -167,6 +182,7 @@ typename element::chain_add_accumulator element::cha template typename element::chain_add_accumulator element::chain_add(const element& p1, const chain_add_accumulator& acc) + requires(IsNotGoblinInefficiencyTrap) { // use `chain_add_start` to start an addition chain (i.e. if acc has a y-coordinate) if (acc.is_element) { @@ -210,6 +226,7 @@ typename element::chain_add_accumulator element::cha **/ template element element::chain_add_end(const chain_add_accumulator& acc) + requires(IsNotGoblinInefficiencyTrap) { if (acc.is_element) { return element(acc.x3_prev, acc.y3_prev); @@ -263,6 +280,7 @@ element element::chain_add_end(const chain_add_accum **/ template element element::montgomery_ladder(const element& other) const + requires(IsNotGoblinInefficiencyTrap) { other.x.assert_is_not_equal(x); const Fq lambda_1 = Fq::div_without_denominator_check({ other.y - y }, (other.x - x)); @@ -299,6 +317,7 @@ element element::montgomery_ladder(const element& ot **/ template element element::montgomery_ladder(const chain_add_accumulator& to_add) + requires(IsNotGoblinInefficiencyTrap) { if (to_add.is_element) { throw_or_abort("An accumulator expected"); @@ -342,6 +361,7 @@ element element::montgomery_ladder(const chain_add_a */ template element element::quadruple_and_add(const std::vector& to_add) const + requires(IsNotGoblinInefficiencyTrap) { const Fq two_x = x + x; Fq x_1; @@ -437,6 +457,7 @@ element element::quadruple_and_add(const std::vector template element element::multiple_montgomery_ladder( const std::vector& add) const + requires(IsNotGoblinInefficiencyTrap) { struct composite_y { std::vector mul_left; @@ -603,48 +624,50 @@ element element::batch_mul(const std::vector && std::same_as) { return goblin_batch_mul(points, scalars); - } + } else { - const size_t num_points = points.size(); - ASSERT(scalars.size() == num_points); - batch_lookup_table point_table(points); - const size_t num_rounds = (max_num_bits == 0) ? Fr::modulus.get_msb() + 1 : max_num_bits; + const size_t num_points = points.size(); + ASSERT(scalars.size() == num_points); + batch_lookup_table point_table(points); + const size_t num_rounds = (max_num_bits == 0) ? Fr::modulus.get_msb() + 1 : max_num_bits; - std::vector>> naf_entries; - for (size_t i = 0; i < num_points; ++i) { - naf_entries.emplace_back(compute_naf(scalars[i], max_num_bits)); - } - const auto offset_generators = compute_offset_generators(num_rounds); - element accumulator = - element::chain_add_end(element::chain_add(offset_generators.first, point_table.get_chain_initial_entry())); - - constexpr size_t num_rounds_per_iteration = 4; - size_t num_iterations = num_rounds / num_rounds_per_iteration; - num_iterations += ((num_iterations * num_rounds_per_iteration) == num_rounds) ? 0 : 1; - const size_t num_rounds_per_final_iteration = (num_rounds - 1) - ((num_iterations - 1) * num_rounds_per_iteration); - for (size_t i = 0; i < num_iterations; ++i) { - - std::vector> nafs(num_points); - std::vector to_add; - const size_t inner_num_rounds = - (i != num_iterations - 1) ? num_rounds_per_iteration : num_rounds_per_final_iteration; - for (size_t j = 0; j < inner_num_rounds; ++j) { - for (size_t k = 0; k < num_points; ++k) { - nafs[k] = (naf_entries[k][i * num_rounds_per_iteration + j + 1]); + std::vector>> naf_entries; + for (size_t i = 0; i < num_points; ++i) { + naf_entries.emplace_back(compute_naf(scalars[i], max_num_bits)); + } + const auto offset_generators = compute_offset_generators(num_rounds); + element accumulator = + element::chain_add_end(element::chain_add(offset_generators.first, point_table.get_chain_initial_entry())); + + constexpr size_t num_rounds_per_iteration = 4; + size_t num_iterations = num_rounds / num_rounds_per_iteration; + num_iterations += ((num_iterations * num_rounds_per_iteration) == num_rounds) ? 0 : 1; + const size_t num_rounds_per_final_iteration = + (num_rounds - 1) - ((num_iterations - 1) * num_rounds_per_iteration); + for (size_t i = 0; i < num_iterations; ++i) { + + std::vector> nafs(num_points); + std::vector to_add; + const size_t inner_num_rounds = + (i != num_iterations - 1) ? num_rounds_per_iteration : num_rounds_per_final_iteration; + for (size_t j = 0; j < inner_num_rounds; ++j) { + for (size_t k = 0; k < num_points; ++k) { + nafs[k] = (naf_entries[k][i * num_rounds_per_iteration + j + 1]); + } + to_add.emplace_back(point_table.get_chain_add_accumulator(nafs)); } - to_add.emplace_back(point_table.get_chain_add_accumulator(nafs)); + accumulator = accumulator.multiple_montgomery_ladder(to_add); } - accumulator = accumulator.multiple_montgomery_ladder(to_add); - } - for (size_t i = 0; i < num_points; ++i) { - element skew = accumulator - points[i]; - Fq out_x = accumulator.x.conditional_select(skew.x, naf_entries[i][num_rounds]); - Fq out_y = accumulator.y.conditional_select(skew.y, naf_entries[i][num_rounds]); - accumulator = element(out_x, out_y); - } - accumulator = accumulator - offset_generators.second; + for (size_t i = 0; i < num_points; ++i) { + element skew = accumulator - points[i]; + Fq out_x = accumulator.x.conditional_select(skew.x, naf_entries[i][num_rounds]); + Fq out_y = accumulator.y.conditional_select(skew.y, naf_entries[i][num_rounds]); + accumulator = element(out_x, out_y); + } + accumulator = accumulator - offset_generators.second; - return accumulator; + return accumulator; + } } /** @@ -678,27 +701,33 @@ element element::operator*(const Fr& scalar) const * specifics. * **/ - constexpr uint64_t num_rounds = Fr::modulus.get_msb() + 1; - std::vector> naf_entries = compute_naf(scalar); + if constexpr (IsGoblinBuilder && std::same_as) { + std::vector points{ *this }; + std::vector scalars{ scalar }; + return goblin_batch_mul(points, scalars); + } else { + constexpr uint64_t num_rounds = Fr::modulus.get_msb() + 1; - const auto offset_generators = compute_offset_generators(num_rounds); + std::vector> naf_entries = compute_naf(scalar); - element accumulator = *this + offset_generators.first; + const auto offset_generators = compute_offset_generators(num_rounds); - for (size_t i = 1; i < num_rounds; ++i) { - bool_t predicate = naf_entries[i]; - bigfield y_test = y.conditional_negate(predicate); - element to_add(x, y_test); - accumulator = accumulator.montgomery_ladder(to_add); - } + element accumulator = *this + offset_generators.first; - element skew_output = accumulator - (*this); + for (size_t i = 1; i < num_rounds; ++i) { + bool_t predicate = naf_entries[i]; + bigfield y_test = y.conditional_negate(predicate); + element to_add(x, y_test); + accumulator = accumulator.montgomery_ladder(to_add); + } + + element skew_output = accumulator - (*this); - Fq out_x = accumulator.x.conditional_select(skew_output.x, naf_entries[num_rounds]); - Fq out_y = accumulator.y.conditional_select(skew_output.y, naf_entries[num_rounds]); + Fq out_x = accumulator.x.conditional_select(skew_output.x, naf_entries[num_rounds]); + Fq out_y = accumulator.y.conditional_select(skew_output.y, naf_entries[num_rounds]); - return element(out_x, out_y) - element(offset_generators.second); + return element(out_x, out_y) - element(offset_generators.second); + } } -} // namespace stdlib -} // namespace proof_system::plonk +} // namespace proof_system::plonk::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp index d748baa72a8..045e1445d57 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp @@ -13,6 +13,9 @@ concept HasPlookup = template concept IsGoblinBuilder = proof_system::IsAnyOf; +template +concept IsNotGoblinBuilder = ! +IsGoblinBuilder; #define INSTANTIATE_STDLIB_METHOD(stdlib_method) \ template stdlib_method(proof_system::StandardCircuitBuilder); \ diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp index 8130ff26e85..22e82dc4824 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp @@ -187,6 +187,7 @@ template class GoblinRecursiveVerifierTest : public testi OuterBuilder outer_circuit; RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; auto pairing_points = verifier.verify_proof(inner_proof); + info("Recursive Verifier: num gates = ", outer_circuit.num_gates); // Check for a failure flag in the recursive verifier circuit EXPECT_EQ(outer_circuit.failed(), false) << outer_circuit.err();