Skip to content

Commit

Permalink
feat: biggroup handles points at infinity (#6391)
Browse files Browse the repository at this point in the history
This PR introdues a stdlib boolean flag into biggroup to track whether
an element is the point at infinity. This is uses to handle edge cases
around the point at infinity in biggroup operations. We now correctly
handle points at infinity under addition and subtraction. The
`batch_mul` method correctly handles points at infinity (at least in
three tested cases) under the Mega arithmetization (though this is not
all that meaningful without a full Goblin proof!). The `wnaf_batch_mul`
method correctly handles points at infinity (at least in three tested
cases) under the Ultra arithmetization, which is the only
arithmetization for which it's implemented.

The PR adds constraints that increase the cost of biggroup operations.
This cases the UltraPlonk recursive verifier circuit size to grow,
crossing a power-of-two boundary. This means that we can no longer
execute two UltraPlonk recursive verifications in WASM due to an
out-of-memory error during provcing key creation. (cf the
`double_verify_proof` tests; note that `double_verify_nested_proof` was
already not available in WASM). Moreover, the PR exposed that noir.js is
not capable of executing proof construction for a circuit of size
$2^{19}$. In response to these two issues, we have disabled tests. We
did this in consulation with @TomAFrench and @vezenovm. 
Related issues:
noir-lang/noir#5106,
AztecProtocol/aztec-packages#6672.

---------

Co-authored-by: codygunton <codygunton@gmail.com>
  • Loading branch information
2 people authored and AztecBot committed May 26, 2024
1 parent 46963c8 commit f7e4253
Show file tree
Hide file tree
Showing 26 changed files with 885 additions and 173 deletions.
12 changes: 8 additions & 4 deletions Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,10 @@ barretenberg-acir-tests-bb.js:
ENV VERBOSE=1
ENV TEST_SRC /usr/src/acir_artifacts

# Run double_verify_proof through bb.js on node to check 512k support.
RUN BIN=../ts/dest/node/main.js FLOW=prove_then_verify ./run_acir_tests.sh double_verify_proof
# TODO(https://github.com/noir-lang/noir/issues/5106)
# TODO(https://github.com/AztecProtocol/aztec-packages/issues/6672)c
# Run ecdsa_secp256r1_3x through bb.js on node to check 256k support.
RUN BIN=../ts/dest/node/main.js FLOW=prove_then_verify ./run_acir_tests.sh ecdsa_secp256r1_3x
# Run a single arbitrary test not involving recursion through bb.js for UltraHonk
RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_ultra_honk ./run_acir_tests.sh 6_array
# Run a single arbitrary test not involving recursion through bb.js for MegaHonk
Expand All @@ -88,11 +90,13 @@ barretenberg-acir-tests-bb.js:
RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_goblin ./run_acir_tests.sh 6_array
# Run 1_mul through bb.js build, all_cmds flow, to test all cli args.
RUN BIN=../ts/dest/node/main.js FLOW=all_cmds ./run_acir_tests.sh 1_mul
# Run double_verify_proof through bb.js on chrome testing multi-threaded browser support.
# TODO(https://github.com/AztecProtocol/aztec-packages/issues/6672)
# Run 6_array through bb.js on chrome testing multi-threaded browser support.
# TODO: Currently headless webkit doesn't seem to have shared memory so skipping multi-threaded test.
RUN BROWSER=chrome THREAD_MODEL=mt ./run_acir_tests_browser.sh double_verify_proof
RUN BROWSER=chrome THREAD_MODEL=mt ./run_acir_tests_browser.sh 6_array
# Run 1_mul through bb.js on chrome/webkit testing single threaded browser support.
RUN BROWSER=chrome THREAD_MODEL=st ./run_acir_tests_browser.sh 1_mul
# Commenting for now as fails intermittently. Unreproducable on mainframe.
# See https://github.com/AztecProtocol/aztec-packages/issues/2104
#RUN BROWSER=webkit THREAD_MODEL=st ./run_acir_tests_browser.sh 1_mul

11 changes: 7 additions & 4 deletions acir_tests/Dockerfile.bb.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ RUN cd browser-test-app && yarn && yarn build
RUN cd headless-test && yarn && npx playwright install && npx playwright install-deps
COPY . .
ENV VERBOSE=1
# Run double_verify_proof through bb.js on node to check 512k support.
RUN BIN=../ts/dest/node/main.js FLOW=prove_then_verify ./run_acir_tests.sh double_verify_proof
# TODO(https://github.com/noir-lang/noir/issues/5106)
# TODO(https://github.com/AztecProtocol/aztec-packages/issues/6672)
# Run ecdsa_secp256r1_3x through bb.js on node to check 256k support.
RUN BIN=../ts/dest/node/main.js FLOW=prove_then_verify ./run_acir_tests.sh ecdsa_secp256r1_3x
# Run a single arbitrary test not involving recursion through bb.js for UltraHonk
RUN BIN=../ts/dest/node/main.js FLOW=prove_then_verify_ultra_honk ./run_acir_tests.sh nested_array_dynamic
# Run a single arbitrary test not involving recursion through bb.js for Plonk
Expand All @@ -27,9 +29,10 @@ RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_mega_honk ./run_acir_tests
RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_goblin ./run_acir_tests.sh 6_array
# Run 1_mul through bb.js build, all_cmds flow, to test all cli args.
RUN BIN=../ts/dest/node/main.js FLOW=all_cmds ./run_acir_tests.sh 1_mul
# Run double_verify_proof through bb.js on chrome testing multi-threaded browser support.
# TODO(https://github.com/AztecProtocol/aztec-packages/issues/6672)
# Run 6_array through bb.js on chrome testing multi-threaded browser support.
# TODO: Currently headless webkit doesn't seem to have shared memory so skipping multi-threaded test.
RUN BROWSER=chrome THREAD_MODEL=mt ./run_acir_tests_browser.sh double_verify_proof
RUN BROWSER=chrome THREAD_MODEL=mt ./run_acir_tests_browser.sh 6_array
# Run 1_mul through bb.js on chrome/webkit testing single threaded browser support.
RUN BROWSER=chrome THREAD_MODEL=st ./run_acir_tests_browser.sh 1_mul
# Commenting for now as fails intermittently. Unreproducable on mainframe.
Expand Down
42 changes: 35 additions & 7 deletions cpp/src/barretenberg/dsl/acir_format/acir_integration.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <filesystem>
#include <gtest/gtest.h>

// #define LOG_SIZES

class AcirIntegrationTest : public ::testing::Test {
public:
static std::vector<uint8_t> get_bytecode(const std::string& bytecodePath)
Expand Down Expand Up @@ -53,17 +55,37 @@ class AcirIntegrationTest : public ::testing::Test {
using VerificationKey = Flavor::VerificationKey;

Prover prover{ builder };
// builder.blocks.summarize();
// info("num gates = ", builder.get_num_gates());
// info("total circuit size = ", builder.get_total_circuit_size());
// info("circuit size = ", prover.instance->proving_key.circuit_size);
// info("log circuit size = ", prover.instance->proving_key.log_circuit_size);
#ifdef LOG_SIZES
builder.blocks.summarize();
info("num gates = ", builder.get_num_gates());
info("total circuit size = ", builder.get_total_circuit_size());
info("circuit size = ", prover.instance->proving_key.circuit_size);
info("log circuit size = ", prover.instance->proving_key.log_circuit_size);
#endif
auto proof = prover.construct_proof();

// Verify Honk proof
auto verification_key = std::make_shared<VerificationKey>(prover.instance->proving_key);
Verifier verifier{ verification_key };
return verifier.verify_proof(proof);
}

template <class Flavor> bool prove_and_verify_plonk(Flavor::CircuitBuilder& builder)
{
plonk::UltraComposer composer;

auto prover = composer.create_prover(builder);
#ifdef LOG_SIZES
// builder.blocks.summarize();
// info("num gates = ", builder.get_num_gates());
// info("total circuit size = ", builder.get_total_circuit_size());
#endif
auto proof = prover.construct_proof();
#ifdef LOG_SIZES
// info("circuit size = ", prover.circuit_size);
// info("log circuit size = ", numeric::get_msb(prover.circuit_size));
#endif
// Verify Plonk proof
auto verifier = composer.create_verifier(builder);
return verifier.verify_proof(proof);
}
};
Expand All @@ -81,6 +103,7 @@ class AcirIntegrationFoldingTest : public AcirIntegrationTest, public testing::W
TEST_P(AcirIntegrationSingleTest, ProveAndVerifyProgram)
{
using Flavor = MegaFlavor;
// using Flavor = bb::plonk::flavor::Ultra;
using Builder = Flavor::CircuitBuilder;

std::string test_name = GetParam();
Expand All @@ -91,7 +114,11 @@ TEST_P(AcirIntegrationSingleTest, ProveAndVerifyProgram)
Builder builder = acir_format::create_circuit<Builder>(acir_program.constraints, 0, acir_program.witness);

// Construct and verify Honk proof
EXPECT_TRUE(prove_and_verify_honk<Flavor>(builder));
if constexpr (IsPlonkFlavor<Flavor>) {
EXPECT_TRUE(prove_and_verify_plonk<Flavor>(builder));
} else {
EXPECT_TRUE(prove_and_verify_honk<Flavor>(builder));
}
}

// TODO(https://github.com/AztecProtocol/barretenberg/issues/994): Run all tests
Expand Down Expand Up @@ -195,6 +222,7 @@ INSTANTIATE_TEST_SUITE_P(AcirTests,
"double_verify_proof_recursive",
"ecdsa_secp256k1",
"ecdsa_secp256r1",
"ecdsa_secp256r1_3x",
"eddsa",
"embedded_curve_ops",
"field_attribute",
Expand Down
8 changes: 4 additions & 4 deletions cpp/src/barretenberg/goblin/mock_circuits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ class GoblinMockCircuits {

if (large) {
stdlib::generate_sha256_test_circuit(builder, NUM_ITERATIONS_LARGE);
stdlib::generate_ecdsa_verification_test_circuit(builder, NUM_ITERATIONS_LARGE);
stdlib::generate_ecdsa_verification_test_circuit(builder, NUM_ITERATIONS_LARGE / 2);
stdlib::generate_merkle_membership_test_circuit(builder, NUM_ITERATIONS_LARGE);
} else { // Results in circuit size 2^17 when accumulated via ClientIvc
stdlib::generate_sha256_test_circuit(builder, 5);
stdlib::generate_ecdsa_verification_test_circuit(builder, 2);
stdlib::generate_ecdsa_verification_test_circuit(builder, 1);
stdlib::generate_merkle_membership_test_circuit(builder, 10);
}

Expand Down Expand Up @@ -153,7 +153,7 @@ class GoblinMockCircuits {
{
// Add operations representing general kernel logic e.g. state updates. Note: these are structured to make the
// kernel "full" within the dyadic size 2^17 (130914 gates)
const size_t NUM_MERKLE_CHECKS = 45;
const size_t NUM_MERKLE_CHECKS = 40;
const size_t NUM_ECDSA_VERIFICATIONS = 1;
const size_t NUM_SHA_HASHES = 1;
stdlib::generate_merkle_membership_test_circuit(builder, NUM_MERKLE_CHECKS);
Expand Down Expand Up @@ -185,7 +185,7 @@ class GoblinMockCircuits {
// Add operations representing general kernel logic e.g. state updates. Note: these are structured to make
// the kernel "full" within the dyadic size 2^17
const size_t NUM_MERKLE_CHECKS = 20;
const size_t NUM_ECDSA_VERIFICATIONS = 2;
const size_t NUM_ECDSA_VERIFICATIONS = 1;
const size_t NUM_SHA_HASHES = 1;
stdlib::generate_merkle_membership_test_circuit(builder, NUM_MERKLE_CHECKS);
stdlib::generate_ecdsa_verification_test_circuit(builder, NUM_ECDSA_VERIFICATIONS);
Expand Down
6 changes: 3 additions & 3 deletions cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ using namespace bb;
* this, to the degree that matters for proof construction time, using these "pinning tests" that fix values.
*
*/
class MockCircuitsPinning : public ::testing::Test {
class MegaMockCircuitsPinning : public ::testing::Test {
protected:
using ProverInstance = ProverInstance_<MegaFlavor>;
static void SetUpTestSuite() { srs::init_crs_factory("../srs_db/ignition"); }
};

TEST_F(MockCircuitsPinning, FunctionSizes)
TEST_F(MegaMockCircuitsPinning, FunctionSizes)
{
const auto run_test = [](bool large) {
Goblin goblin;
Expand All @@ -34,7 +34,7 @@ TEST_F(MockCircuitsPinning, FunctionSizes)
run_test(false);
}

TEST_F(MockCircuitsPinning, RecursionKernelSizes)
TEST_F(MegaMockCircuitsPinning, RecursionKernelSizes)
{
const auto run_test = [](bool large) {
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ struct ecc_op_tuple {
uint32_t y_hi;
uint32_t z_1;
uint32_t z_2;
bool return_is_infinity;
};

template <typename B, typename FF> inline void read(B& buf, poly_triple_<FF>& constraint)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
#include "barretenberg/stdlib_circuit_builders/standard_circuit_builder.hpp"
#include "barretenberg/stdlib_circuit_builders/ultra_circuit_builder.hpp"

using namespace bb;
using namespace bb::plonk;

namespace {
auto& engine = numeric::get_debug_randomness();
} // namespace

using namespace bb::plonk;

/**
* @brief A test fixture that will let us generate VK data and run tests
* for all builder types
Expand Down
6 changes: 6 additions & 0 deletions cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,12 @@ template <typename Builder, typename T> class bigfield {

bigfield conditional_negate(const bool_t<Builder>& predicate) const;
bigfield conditional_select(const bigfield& other, const bool_t<Builder>& predicate) const;
static bigfield conditional_assign(const bool_t<Builder>& predicate, const bigfield& lhs, const bigfield& rhs)
{
return rhs.conditional_select(lhs, predicate);
}

bool_t<Builder> operator==(const bigfield& other) const;

void assert_is_in_field() const;
void assert_less_than(const uint256_t upper_limit) const;
Expand Down
44 changes: 44 additions & 0 deletions cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,45 @@ template <typename Builder> class stdlib_bigfield : public testing::Test {
fq_ct ret = fq_ct::div_check_denominator_nonzero({}, a_ct);
EXPECT_NE(ret.get_context(), nullptr);
}

static void test_assert_equal_not_equal()
{
auto builder = Builder();
size_t num_repetitions = 10;
for (size_t i = 0; i < num_repetitions; ++i) {
fq inputs[4]{ fq::random_element(), fq::random_element(), fq::random_element(), fq::random_element() };

fq_ct a(witness_ct(&builder, fr(uint256_t(inputs[0]).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
witness_ct(&builder,
fr(uint256_t(inputs[0]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
fq_ct b(witness_ct(&builder, fr(uint256_t(inputs[1]).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
witness_ct(&builder,
fr(uint256_t(inputs[1]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
fq_ct c(witness_ct(&builder, fr(uint256_t(inputs[2]).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
witness_ct(&builder,
fr(uint256_t(inputs[2]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));
fq_ct d(witness_ct(&builder, fr(uint256_t(inputs[3]).slice(0, fq_ct::NUM_LIMB_BITS * 2))),
witness_ct(&builder,
fr(uint256_t(inputs[3]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4))));

fq_ct two(witness_ct(&builder, fr(2)),
witness_ct(&builder, fr(0)),
witness_ct(&builder, fr(0)),
witness_ct(&builder, fr(0)));
fq_ct t0 = a + a;
fq_ct t1 = a * two;

t0.assert_equal(t1);
t0.assert_is_not_equal(c);
t0.assert_is_not_equal(d);
stdlib::bool_t<Builder> is_equal_a = t0 == t1;
stdlib::bool_t<Builder> is_equal_b = t0 == c;
EXPECT_TRUE(is_equal_a.get_value());
EXPECT_FALSE(is_equal_b.get_value());
}
bool result = CircuitChecker::check(builder);
EXPECT_EQ(result, true);
}
};

// Define types for which the above tests will be constructed.
Expand Down Expand Up @@ -929,6 +968,11 @@ TYPED_TEST(stdlib_bigfield, division_context)
TestFixture::test_division_context();
}

TYPED_TEST(stdlib_bigfield, assert_equal_not_equal)
{
TestFixture::test_assert_equal_not_equal();
}

// // This test was disabled before the refactor to use TYPED_TEST's/
// TEST(stdlib_bigfield, DISABLED_test_div_against_constants)
// {
Expand Down
Loading

0 comments on commit f7e4253

Please sign in to comment.