Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
triple_ipa_recursive.test.cpp
Go to the documentation of this file.
9
10using namespace bb;
11
12namespace {
13
16using RecursiveCurve = stdlib::grumpkin<Builder>;
17
18class TripleIPARecursiveTest : public CommitmentTest<NativeCurve> {
19 public:
20 using Fr = typename NativeCurve::ScalarField;
24 using Commitment = typename NativeCurve::AffineElement;
25 using StdlibProof = stdlib::Proof<Builder>;
27
28 static constexpr size_t log_n = 4;
29 static constexpr size_t n = 1UL << log_n;
30 using NativePCS = TripleIPA<NativeCurve, log_n>;
31 using RecursivePCS = TripleIPA<RecursiveCurve, log_n>;
32 // The non-cyclic shift tensor as an explicit vector: b_sh[0] = 0, b_sh[i] = eq(u)_{i-1}. Production only exposes
33 // the succinct fold (ShiftedEqPolynomial), never the vector, and evaluate_mle(shift=true) asserts a zero constant
34 // term, which this suite deliberately violates — so this stays as the explicit oracle, built off the production eq.
35 static std::vector<Fr> materialize_shift(const std::vector<Fr>& point)
36 {
37 const auto eq = ProverEqPolynomial<Fr>::construct(point, log_n);
38 std::vector<Fr> result(n, Fr::zero());
39 for (size_t idx = 1; idx < n; ++idx) {
40 result[idx] = eq[idx - 1];
41 }
42 return result;
43 }
44
45 static Fr inner_product(const Polynomial& left, std::span<const Fr> right)
46 {
47 BB_ASSERT_EQ(right.size(), n);
48 Fr result = Fr::zero();
49 for (size_t idx = 0; idx < n; ++idx) {
50 result += left[idx] * right[idx];
51 }
52 return result;
53 }
54
55 static CK ck;
56 static VK vk;
57
58 static void SetUpTestSuite()
59 {
60 // Use the file CRS: replacing the global factory with a tiny mem CRS breaks suites sharing this binary
61 // (e.g. Shplemini tests that run the ECCVM prover and need the full Grumpkin SRS).
63 ck = CK(n);
65 }
66
67 typename NativePCS::TripleIpaInput create_triple_ipa_input()
68 {
69 typename NativePCS::TripleIpaInput input;
70 const auto multilinear_challenge = this->random_evaluation_point(log_n);
71 input.claim_data.unshifted.multilinear_challenge = multilinear_challenge;
72
73 const auto shift_tensor = materialize_shift(multilinear_challenge);
74
75 for (size_t idx = 0; idx < 5; ++idx) {
76 auto polynomial = this->random_polynomial(n);
77 input.claim_data.unshifted.evaluations.emplace_back(
78 polynomial.evaluate_mle(std::span<const Fr>(multilinear_challenge)));
79 input.claim_data.unshifted.commitments.emplace_back(ck.commit(polynomial));
80 input.unshifted_polynomials.emplace_back(std::move(polynomial));
81 }
82 using ClaimData = typename NativePCS::TripleIpaClaimData;
83 input.claim_data.unshifted.rho_powers =
84 ClaimData::rho_powers(this->random_element(), input.unshifted_polynomials.size());
85
86 const std::vector<size_t> shifted_sources = { 1, 3 };
87 input.claim_data.shifted.rho_powers = ClaimData::rho_powers(this->random_element(), shifted_sources.size());
88 for (const size_t source_idx : shifted_sources) {
89 input.claim_data.shifted.commitments.emplace_back(input.claim_data.unshifted.commitments[source_idx]);
90 input.claim_data.shifted.source_unshifted_evaluations.emplace_back(
91 input.claim_data.unshifted.evaluations[source_idx]);
92 input.claim_data.shifted.shifted_evaluations.emplace_back(
93 inner_product(input.unshifted_polynomials[source_idx], std::span<const Fr>(shift_tensor)));
94 input.shifted_polynomials.emplace_back(input.unshifted_polynomials[source_idx].share());
95 }
96
97 input.univariate_polynomial = this->random_polynomial(n);
98 input.claim_data.univariate.opening_pair.challenge = this->random_element();
99 input.claim_data.univariate.opening_pair.evaluation =
100 input.univariate_polynomial.evaluate(input.claim_data.univariate.opening_pair.challenge);
101 input.claim_data.univariate.commitment = ck.commit(input.univariate_polynomial);
102 return input;
103 }
104
105 typename RecursivePCS::TripleIpaInput to_recursive_input(Builder& builder,
106 const typename NativePCS::TripleIpaInput& native_input)
107 {
109 for (const auto& commitment : native_input.claim_data.unshifted.commitments) {
110 result.claim_data.unshifted.commitments.emplace_back(
111 RecursiveCurve::Group::from_witness(&builder, commitment));
112 }
113 for (const auto& evaluation : native_input.claim_data.unshifted.evaluations) {
114 result.claim_data.unshifted.evaluations.emplace_back(
115 RecursiveCurve::ScalarField::from_witness(&builder, evaluation));
116 }
117 for (const auto& rho_power : native_input.claim_data.unshifted.rho_powers) {
118 result.claim_data.unshifted.rho_powers.emplace_back(
119 RecursiveCurve::ScalarField::from_witness(&builder, rho_power));
120 }
121 for (const auto& coordinate : native_input.claim_data.unshifted.multilinear_challenge) {
122 result.claim_data.unshifted.multilinear_challenge.emplace_back(
123 RecursiveCurve::ScalarField::from_witness(&builder, coordinate));
124 }
125
126 for (const auto& commitment : native_input.claim_data.shifted.commitments) {
127 result.claim_data.shifted.commitments.emplace_back(
128 RecursiveCurve::Group::from_witness(&builder, commitment));
129 }
130 for (const auto& evaluation : native_input.claim_data.shifted.shifted_evaluations) {
131 result.claim_data.shifted.shifted_evaluations.emplace_back(
132 RecursiveCurve::ScalarField::from_witness(&builder, evaluation));
133 }
134 for (const auto& rho_power : native_input.claim_data.shifted.rho_powers) {
135 result.claim_data.shifted.rho_powers.emplace_back(
136 RecursiveCurve::ScalarField::from_witness(&builder, rho_power));
137 }
138
139 result.claim_data.univariate = {
140 { RecursiveCurve::ScalarField::from_witness(&builder,
141 native_input.claim_data.univariate.opening_pair.challenge),
142 RecursiveCurve::ScalarField::from_witness(&builder,
143 native_input.claim_data.univariate.opening_pair.evaluation) },
144 RecursiveCurve::Group::from_witness(&builder, native_input.claim_data.univariate.commitment)
145 };
146 return result;
147 }
148
149 NativeTranscript::Proof prove_triple_ipa(const typename NativePCS::TripleIpaInput& input)
150 {
151 auto prover_transcript = std::make_shared<NativeTranscript>();
152 NativePCS::compute_opening_proof(ck, input, prover_transcript);
153 return prover_transcript->export_proof();
154 }
155};
156
157TripleIPARecursiveTest::CK TripleIPARecursiveTest::ck;
158TripleIPARecursiveTest::VK TripleIPARecursiveTest::vk;
159
160} // namespace
161
162TEST_F(TripleIPARecursiveTest, RecursiveReduceVerifyEmitsAccumulator)
163{
164 auto input = create_triple_ipa_input();
165 auto proof = prove_triple_ipa(input);
166
168 auto recursive_input = to_recursive_input(builder, input);
169 auto transcript = std::make_shared<StdlibTranscript>(StdlibProof(builder, proof));
170 auto accumulator = RecursivePCS::reduce_verify(recursive_input.claim_data.batch(), transcript);
171
172 EXPECT_EQ(accumulator.u_challenges_inv.size(), log_n);
173 EXPECT_TRUE(accumulator.running_truth_value);
175 builder.finalize_circuit();
176 EXPECT_FALSE(builder.failed()) << builder.err();
177 EXPECT_TRUE(CircuitChecker::check(builder));
178}
179
180// A tampered TripleIPA proof must be rejected by the in-circuit relation, not merely by the native
181// `running_truth_value` side-channel: corrupting the first prover message (the `TripleIPA:cross_F_shift` cross-sum)
182// diverges the verifier's zeta challenges and combined claim from the prover's, so the IPA group-relation
183// `assert_equal` cannot close and the circuit becomes unsatisfiable.
184TEST_F(TripleIPARecursiveTest, RecursiveReduceVerifyRejectsTamperedProof)
185{
186 auto input = create_triple_ipa_input();
187 auto proof = prove_triple_ipa(input);
188 ASSERT_FALSE(proof.empty());
189 using ProofElement = std::decay_t<decltype(proof[0])>;
190 proof[0] += ProofElement::one();
191
193 auto recursive_input = to_recursive_input(builder, input);
194 auto transcript = std::make_shared<StdlibTranscript>(StdlibProof(builder, proof));
195 auto accumulator = RecursivePCS::reduce_verify(recursive_input.claim_data.batch(), transcript);
196 static_cast<void>(accumulator);
197
199 builder.finalize_circuit();
200 EXPECT_FALSE(CircuitChecker::check(builder));
201}
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:83
Common transcript class for both parties. Stores the data for the current round, as well as the manif...
std::vector< DataType > Proof
CommitmentKey object over a pairing group 𝔾₁.
CommitmentKey< Curve > CK
Polynomial random_polynomial(const size_t poly_size)
VerifierCommitmentKey< Curve > VK
std::vector< Fr > random_evaluation_point(const size_t num_variables)
static void SetUpTestSuite()
static Polynomial< FF > construct(std::span< const FF > challenges, size_t log_num_monomials)
Construct eq(X, r) coefficient table over Boolean hypercube {0,1}^d.
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
bb::TripleIpaClaimData< Curve > TripleIpaClaimData
static void compute_opening_proof(const CK &ck, const TripleIpaInput &input, const std::shared_ptr< Transcript > &transcript)
bb::TripleIpaInput< Curve > TripleIpaInput
Representation of the Grumpkin Verifier Commitment Key inside a bn254 circuit.
typename Group::affine_element AffineElement
Definition bn254.hpp:22
bb::fr ScalarField
Definition bn254.hpp:18
A simple wrapper around a vector of stdlib field elements representing a proof.
Definition proof.hpp:20
static void add_default(Builder &builder)
Add default public inputs when they are not present.
AluTraceBuilder builder
Definition alu.test.cpp:124
void init_grumpkin_file_crs_factory(const std::filesystem::path &path)
std::filesystem::path bb_crs_path()
std::shared_ptr< factories::CrsFactory< curve::Grumpkin > > get_grumpkin_crs_factory()
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:160
BaseTranscript< stdlib::StdlibCodec< stdlib::field_t< UltraCircuitBuilder > >, stdlib::poseidon2< UltraCircuitBuilder > > UltraStdlibTranscript
UltraCircuitBuilder_< UltraExecutionTraceBlocks > UltraCircuitBuilder
CommitmentKey< Curve > ck
VerifierCommitmentKey< Curve > vk
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static constexpr field zero()
Curve grumpkin in circuit setting.
Definition grumpkin.hpp:21
VectorField result