Skip to content

Commit

Permalink
feat: Goblinize the final ecc ops in ZM (AztecProtocol#3741)
Browse files Browse the repository at this point in the history
In the initial implementation of ZM I forgot to goblinize a couple of
the final group operations in Zeromorph which was causing the gate count
of the recursive verifier to blow up. We fix this. We implement the
addition, subtraction, and single scalar multiplication operation
inefficiently using the batch_mul methods. We disable some member
functions that do not use Goblin when they could, and leave references
to AztecProtocol/barretenberg#707 as a future
optimization task.

---------

Co-authored-by: codygunton <codygunton@gmail.com>
  • Loading branch information
ledwards2225 and codygunton authored Jan 3, 2024
1 parent f924037 commit 3048d08
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,16 @@ template <typename Curve> 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<FF> scalars = { FF(builder, 1), z_challenge };
std::vector<Commitment> 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<Commitment>("ZM:PI");
Expand All @@ -702,7 +711,17 @@ template <typename Curve> 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<FF> scalars = { FF(builder, 1), x_challenge };
std::vector<Commitment> 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 };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename Builder, typename NativeGroup>
concept IsNotGoblinInefficiencyTrap = !(IsGoblinBuilder<Builder> && std::same_as<NativeGroup, barretenberg::g1>);

namespace proof_system::plonk::stdlib {

// ( ͡° ͜ʖ ͡°)
template <class Builder, class Fq, class Fr, class NativeGroup> class element {
Expand Down Expand Up @@ -154,14 +157,22 @@ template <class Builder, class Fq, class Fr, class NativeGroup> 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<chain_add_accumulator>& to_add) const;
element quadruple_and_add(const std::vector<element>& to_add) const;
static chain_add_accumulator chain_add_start(const element& p1, const element& p2)
requires(IsNotGoblinInefficiencyTrap<Builder, NativeGroup>);
static chain_add_accumulator chain_add(const element& p1, const chain_add_accumulator& accumulator)
requires(IsNotGoblinInefficiencyTrap<Builder, NativeGroup>);
static element chain_add_end(const chain_add_accumulator& accumulator)
requires(IsNotGoblinInefficiencyTrap<Builder, NativeGroup>);

element montgomery_ladder(const element& other) const
requires(IsNotGoblinInefficiencyTrap<Builder, NativeGroup>);
element montgomery_ladder(const chain_add_accumulator& accumulator)
requires(IsNotGoblinInefficiencyTrap<Builder, NativeGroup>);
element multiple_montgomery_ladder(const std::vector<chain_add_accumulator>& to_add) const
requires(IsNotGoblinInefficiencyTrap<Builder, NativeGroup>);

element quadruple_and_add(const std::vector<element>& to_add) const
requires(IsNotGoblinInefficiencyTrap<Builder, NativeGroup>);

typename NativeGroup::affine_element get_value() const
{
Expand All @@ -179,6 +190,9 @@ template <class Builder, class Fq, class Fr, class NativeGroup> class element {
static element batch_mul(const std::vector<element>& points,
const std::vector<Fr>& 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<element>& points,
const std::vector<Fr>& scalars,
const size_t max_num_bits = 0);
Expand All @@ -196,13 +210,15 @@ template <class Builder, class Fq, class Fr, class NativeGroup> class element {
// i.e. for the bn254 curve, the template param is `typename = void`
// for any other curve, there is no template param
template <typename X = NativeGroup, typename = typename std::enable_if_t<std::is_same<X, barretenberg::g1>::value>>
requires(IsNotGoblinBuilder<Builder>) // TODO(https://github.com/AztecProtocol/barretenberg/issues/707)
static element bn254_endo_batch_mul(const std::vector<element>& big_points,
const std::vector<Fr>& big_scalars,
const std::vector<element>& small_points,
const std::vector<Fr>& small_scalars,
const size_t max_num_small_bits);

template <typename X = NativeGroup, typename = typename std::enable_if_t<std::is_same<X, barretenberg::g1>::value>>
requires(IsNotGoblinBuilder<Builder>) // TODO(https://github.com/AztecProtocol/barretenberg/issues/707)
static element bn254_endo_batch_mul_with_generator(const std::vector<element>& big_points,
const std::vector<Fr>& big_scalars,
const std::vector<element>& small_points,
Expand Down Expand Up @@ -889,8 +905,7 @@ inline std::ostream& operator<<(std::ostream& os, element<C, Fq, Fr, G> 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"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
#include "barretenberg/common/test.hpp"
#include <type_traits>

#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 <memory>

namespace test_stdlib_biggroup {
namespace {
auto& engine = numeric::random::get_debug_engine();
Expand Down Expand Up @@ -825,12 +820,17 @@ template <typename TestType> class stdlib_biggroup : public testing::Test {

enum UseBigfield { No, Yes };
using TestTypes = testing::Types<TestType<stdlib::bn254<proof_system::StandardCircuitBuilder>, UseBigfield::No>,
TestType<stdlib::bn254<proof_system::UltraCircuitBuilder>, UseBigfield::Yes>>;
TestType<stdlib::bn254<proof_system::UltraCircuitBuilder>, UseBigfield::Yes>,
TestType<stdlib::bn254<proof_system::GoblinUltraCircuitBuilder>, UseBigfield::No>>;

TYPED_TEST_SUITE(stdlib_biggroup, TestTypes);

template <typename T>
concept HasGoblinBuilder = IsGoblinBuilder<typename T::Curve::Builder>;

TYPED_TEST(stdlib_biggroup, add)
{

TestFixture::test_add();
}
TYPED_TEST(stdlib_biggroup, sub)
Expand All @@ -843,23 +843,39 @@ TYPED_TEST(stdlib_biggroup, dbl)
}
TYPED_TEST(stdlib_biggroup, montgomery_ladder)
{
TestFixture::test_montgomery_ladder();
if constexpr (HasGoblinBuilder<TypeParam>) {
GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707";
} else {
TestFixture::test_montgomery_ladder();
};
}
HEAVY_TYPED_TEST(stdlib_biggroup, mul)
{
TestFixture::test_mul();
}
HEAVY_TYPED_TEST(stdlib_biggroup, twin_mul)
{
TestFixture::test_twin_mul();
if constexpr (HasGoblinBuilder<TypeParam>) {
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<TypeParam>) {
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<TypeParam>) {
GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707";
} else {
TestFixture::test_quad_mul();
};
}
HEAVY_TYPED_TEST(stdlib_biggroup, one)
{
Expand All @@ -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<TypeParam>) {
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<TypeParam>) {
GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707";
} else {
TestFixture::test_multiple_montgomery_ladder();
};
}

HEAVY_TYPED_TEST(stdlib_biggroup, compute_naf)
Expand All @@ -897,7 +921,11 @@ HEAVY_TYPED_TEST(stdlib_biggroup, compute_naf)
HEAVY_TYPED_TEST(stdlib_biggroup, wnaf_batch_mul)
{
if constexpr (HasPlookup<typename TypeParam::Curve::Builder>) {
TestFixture::test_compute_wnaf();
if constexpr (HasGoblinBuilder<TypeParam>) {
GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707";
} else {
TestFixture::test_compute_wnaf();
};
} else {
GTEST_SKIP();
}
Expand All @@ -921,15 +949,23 @@ 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<TypeParam>) {
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)
{
if constexpr (TypeParam::use_bigfield) {
GTEST_SKIP();
} else {
TestFixture::test_wnaf_batch_mul_128_bit();
if constexpr (HasGoblinBuilder<TypeParam>) {
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)
Expand All @@ -945,15 +981,23 @@ 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<TypeParam>) {
GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707";
} else {
TestFixture::test_bn254_endo_batch_mul();
};
} else {
GTEST_SKIP();
}
}
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<TypeParam>) {
GTEST_SKIP() << "https://github.com/AztecProtocol/barretenberg/issues/707";
} else {
TestFixture::test_mixed_mul_bn254_endo();
};
} else {
GTEST_SKIP();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ namespace stdlib {
**/
template <class C, class Fq, class Fr, class G>
template <typename, typename>
requires(IsNotGoblinBuilder<C>)
element<C, Fq, Fr, G> element<C, Fq, Fr, G>::bn254_endo_batch_mul_with_generator(
const std::vector<element>& big_points,
const std::vector<Fr>& big_scalars,
Expand Down Expand Up @@ -216,6 +217,7 @@ element<C, Fq, Fr, G> element<C, Fq, Fr, G>::bn254_endo_batch_mul_with_generator
**/
template <typename C, class Fq, class Fr, class G>
template <typename, typename>
requires(IsNotGoblinBuilder<C>)
element<C, Fq, Fr, G> element<C, Fq, Fr, G>::bn254_endo_batch_mul(const std::vector<element>& big_points,
const std::vector<Fr>& big_scalars,
const std::vector<element>& small_points,
Expand Down
Loading

0 comments on commit 3048d08

Please sign in to comment.