Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
grand_product_library.test.cpp
Go to the documentation of this file.
4
5#include <gtest/gtest.h>
6using namespace bb;
7
8template <class FF> class GrandProductTests : public testing::Test {
9
11
12 public:
14
15 static void populate_span(auto& polynomial_view, const auto& polynomial)
16 {
17 ASSERT_LE(polynomial_view.size(), polynomial.size());
18 for (size_t idx = 0; idx < polynomial.size(); idx++) {
19 polynomial_view[idx] = polynomial[idx];
20 }
21 };
22
31 template <typename Flavor> static void test_permutation_grand_product_construction()
32 {
34
35 // Set a mock circuit size
36 static const size_t circuit_size = 8;
37
38 // Construct a ProverPolynomials object with completely random polynomials
39 ProverPolynomials prover_polynomials;
40 for (auto& poly : prover_polynomials.get_to_be_shifted()) {
41 poly = Polynomial::random(circuit_size, /*shiftable*/ 1);
42 }
43 for (auto& poly : prover_polynomials.get_all()) {
44 if (poly.is_empty()) {
45 poly = Polynomial::random(circuit_size);
46 }
47 }
48
49 // Get random challenges
50 auto beta = FF::random_element();
51 auto gamma = FF::random_element();
52
54 .eta = 0,
55 .beta = beta,
56 .gamma = gamma,
57 .public_input_delta = 1,
58 };
59
60 compute_grand_product<Flavor, typename bb::UltraPermutationRelation<FF>>(prover_polynomials, params);
61
62 // Method 2: Compute z_perm locally using the simplest non-optimized syntax possible. The comment below,
63 // which describes the computation in 4 steps, is adapted from a similar comment in
64 // compute_grand_product_polynomial.
65 /*
66 * Assume Flavor::NUM_WIRES 3. Z_perm may be defined in terms of its values
67 * on X_i = 0,1,...,n-1 as Z_perm[0] = 0 and for i = 1:n-1
68 *
69 * (w_1(j) + β⋅id_1(j) + γ) ⋅ (w_2(j) + β⋅id_2(j) + γ) ⋅ (w_3(j) + β⋅id_3(j) + γ)
70 * Z_perm[i] = ∏ --------------------------------------------------------------------------------
71 * (w_1(j) + β⋅σ_1(j) + γ) ⋅ (w_2(j) + β⋅σ_2(j) + γ) ⋅ (w_3(j) + β⋅σ_3(j) + γ)
72 *
73 * where ∏ := ∏_{j=0:i-1} and id_i(X) = id(X) + n*(i-1). These evaluations are constructed over the
74 * course of three steps. For expositional simplicity, write Z_perm[i] as
75 *
76 * A_1(j) ⋅ A_2(j) ⋅ A_3(j)
77 * Z_perm[i] = ∏ --------------------------
78 * B_1(j) ⋅ B_2(j) ⋅ B_3(j)
79 *
80 * Step 1) Compute the 2*Flavor::NUM_WIRES length-n polynomials A_i and B_i
81 * Step 2) Compute the 2*Flavor::NUM_WIRES length-n polynomials ∏ A_i(j) and ∏ B_i(j)
82 * Step 3) Compute the two length-n polynomials defined by
83 * numer[i] = ∏ A_1(j)⋅A_2(j)⋅A_3(j), and denom[i] = ∏ B_1(j)⋅B_2(j)⋅B_3(j)
84 * Step 4) Compute Z_perm[i+1] = numer[i]/denom[i] (recall: Z_perm[0] = 1)
85 */
86
87 // Make scratch space for the numerator and denominator accumulators.
90
91 auto wires = prover_polynomials.get_wires();
92 auto sigmas = prover_polynomials.get_sigmas();
93 auto ids = prover_polynomials.get_ids();
94 // Step (1)
95 for (size_t i = 0; i < circuit_size; ++i) {
96 for (size_t k = 0; k < Flavor::NUM_WIRES; ++k) {
97 numerator_accum[k][i] = wires[k][i] + (ids[k][i] * beta) + gamma; // w_k(i) + β.id_k(i) + γ
98 denominator_accum[k][i] = wires[k][i] + (sigmas[k][i] * beta) + gamma; // w_k(i) + β.σ_k(i) + γ
99 }
100 }
101
102 // Step (2)
103 for (size_t k = 0; k < Flavor::NUM_WIRES; ++k) {
104 for (size_t i = 0; i < circuit_size - 1; ++i) {
105 numerator_accum[k][i + 1] *= numerator_accum[k][i];
106 denominator_accum[k][i + 1] *= denominator_accum[k][i];
107 }
108 }
109
110 // Step (3)
111 for (size_t i = 0; i < circuit_size; ++i) {
112 for (size_t k = 1; k < Flavor::NUM_WIRES; ++k) {
113 numerator_accum[0][i] *= numerator_accum[k][i];
114 denominator_accum[0][i] *= denominator_accum[k][i];
115 }
116 }
117
118 // Step (4)
119 Polynomial z_permutation_expected(circuit_size);
120 z_permutation_expected.at(0) = FF::zero(); // Z_0 = 1
121 // Note: in practice, we replace this expensive element-wise division with Montgomery batch inversion
122 for (size_t i = 0; i < circuit_size - 1; ++i) {
123 z_permutation_expected.at(i + 1) = numerator_accum[0][i] / denominator_accum[0][i];
124 }
125
126 // Check consistency between locally computed z_perm and the one computed by the prover library
127 EXPECT_EQ(prover_polynomials.z_perm, z_permutation_expected);
128 };
129};
130
131using FieldTypes = testing::Types<bb::fr>;
133
134TYPED_TEST(GrandProductTests, GrandProductPermutation)
135{
136 TestFixture::template test_permutation_grand_product_construction<UltraFlavor>();
137}
static void test_permutation_grand_product_construction()
Check consistency of the computation of the permutation grand product polynomial z_permutation.
static void populate_span(auto &polynomial_view, const auto &polynomial)
A container for the prover polynomials handles.
static constexpr size_t NUM_WIRES
static Polynomial random(size_t size, size_t start_index=0)
Fr & at(size_t index)
Our mutable accessor, unlike operator[]. We abuse precedent a bit to differentiate at() and operator[...
typename ECCVMFlavor::ProverPolynomials ProverPolynomials
testing::Types< bb::fr > FieldTypes
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
Entry point for Barretenberg command-line interface.
TYPED_TEST_SUITE(ShpleminiTest, TestSettings)
TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
Container for parameters used by the grand product (permutation, lookup) Honk relations.