Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
translator_verifier.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Sergei], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
19
20namespace bb {
21
22namespace {
23// Native helper: slice uint256_t values into limbs
24template <typename Flavor>
25void put_translation_data_in_relation_parameters_impl(RelationParameters<typename Flavor::FF>& relation_parameters,
26 const uint256_t& evaluation_input_x,
27 const typename Flavor::BF& batching_challenge_v,
28 const uint256_t& accumulated_result)
29 requires(!Flavor::Curve::is_stdlib_type)
30{
31 using FF = typename Flavor::FF;
32 using BF = typename Flavor::BF;
33
34 const auto compute_four_limbs = [](const auto& in) {
35 constexpr size_t NUM_LIMB_BITS = Flavor::NUM_LIMB_BITS;
36 return std::array<FF, 4>{ in.slice(0, NUM_LIMB_BITS),
37 in.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2),
38 in.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3),
39 in.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4) };
40 };
41
42 const auto compute_five_limbs = [](const auto& in) {
43 constexpr size_t NUM_LIMB_BITS = Flavor::NUM_LIMB_BITS;
44 return std::array<FF, 5>{ in.slice(0, NUM_LIMB_BITS),
45 in.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2),
46 in.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3),
47 in.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4),
48 in };
49 };
50
51 relation_parameters.evaluation_input_x = compute_five_limbs(evaluation_input_x);
52
53 uint256_t batching_challenge_v_power{ batching_challenge_v };
54 for (size_t i = 0; i < 4; i++) {
55 relation_parameters.batching_challenge_v[i] = compute_five_limbs(batching_challenge_v_power);
56 batching_challenge_v_power = BF(batching_challenge_v_power) * batching_challenge_v;
57 }
58
59 relation_parameters.accumulated_result = compute_four_limbs(accumulated_result);
60}
61
62// Recursive helper: extract limbs from bigfield elements
63template <typename Flavor>
64void put_translation_data_in_relation_parameters_impl(RelationParameters<typename Flavor::FF>& relation_parameters,
65 const typename Flavor::BF& evaluation_input_x,
66 const typename Flavor::BF& batching_challenge_v,
67 const typename Flavor::BF& accumulated_result)
68 requires(Flavor::Curve::is_stdlib_type)
69{
70 using FF = typename Flavor::FF;
71 using BF = typename Flavor::BF;
72
73 const auto compute_four_limbs = [](const BF& in) {
74 auto result = std::array<FF, 4>{ FF(in.get_limb(0).element),
75 FF(in.get_limb(1).element),
76 FF(in.get_limb(2).element),
77 FF(in.get_limb(3).element) };
78 // Ensure extracted limbs are witnesses, not constants
79 for (const auto& limb : result) {
80 BB_ASSERT(!limb.is_constant());
81 }
82 return result;
83 };
84
85 const auto compute_five_limbs = [](const BF& in) {
86 auto result = std::array<FF, 5>{ FF(in.get_limb(0).element),
87 FF(in.get_limb(1).element),
88 FF(in.get_limb(2).element),
89 FF(in.get_limb(3).element),
90 FF(in.get_prime_basis_limb()) };
91 // Ensure extracted limbs are witnesses, not constants
92 for (const auto& limb : result) {
93 BB_ASSERT(!limb.is_constant());
94 }
95 return result;
96 };
97
98 relation_parameters.evaluation_input_x = compute_five_limbs(evaluation_input_x);
99
100 BF batching_challenge_v_power = batching_challenge_v;
101 for (size_t i = 0; i < 4; i++) {
102 relation_parameters.batching_challenge_v[i] = compute_five_limbs(batching_challenge_v_power);
103 batching_challenge_v_power = batching_challenge_v_power * batching_challenge_v;
104 }
105
106 relation_parameters.accumulated_result = compute_four_limbs(accumulated_result);
107
108 // OriginTag false positive: The accumulated_result limbs originate from ECCVM verifier (different protocol phase)
109 // and are used directly in Translator relations. The fact that these values do not interact
110 // with any other value from the Translator circuit would trigger the round provenance mechanism if we didn't clear
111 // the round provenance. This cross-protocol usage is sound because:
112 // 1. ECCVM proves correctness of translation evaluations via its own sumcheck + IPA
113 // 2. ECCVM computes accumulated_result = (op + v·Px + v²·Py + v³·z1 + v⁴·z2 - masking) / x
114 // 3. Translator re-computes the same accumulator non-natively in its circuit
115 // 4. TranslatorAccumulatorTransferRelationImpl enforces exact equality at the final row:
116 // accumulators_binary_limbs_i == accumulated_result[i] for i ∈ {0,1,2,3}
117 // This binds the two protocols - Translator output must match ECCVM claim.
118 for (auto& limb : relation_parameters.accumulated_result) {
119 limb.clear_round_provenance();
120 }
121}
122} // namespace
123
125{
126 put_translation_data_in_relation_parameters_impl<Flavor>(
127 relation_parameters, evaluation_input_x, batching_challenge_v, accumulated_result);
128}
129
142template <typename Flavor>
144{
145 transcript->load_proof(proof);
146
147 // Fiat-Shamir the vk hash
148 transcript->add_to_hash_buffer("vk_hash", vk_hash);
149 vinfo("Translator vk hash in verifier: ", vk_hash);
150
151 VerifierCommitments commitments{ key };
152 CommitmentLabels commitment_labels;
153
154 // For recursive verification, mark the accumulated result's prime basis limb as used
155 // (it can be recovered from binary basis limbs, so no need to constrain it further)
156 if constexpr (IsRecursive) {
157 mark_witness_as_used(accumulated_result.get_prime_basis_limb());
158 }
159
160 // Use accumulated_result from ECCVM verifier
161 put_translation_data_in_relation_parameters();
162
163 // Receive Gemini masking polynomial commitment (for ZK-PCS)
164 commitments.gemini_masking_poly = transcript->template receive_from_prover<Commitment>("Gemini:masking_poly_comm");
165
166 // Set op queue wire commitments (provided by merge protocol, not from translator proof)
167 commitments.op = op_queue_wire_commitments[0];
168 commitments.x_lo_y_hi = op_queue_wire_commitments[1];
169 commitments.x_hi_z_1 = op_queue_wire_commitments[2];
170 commitments.y_lo_z_2 = op_queue_wire_commitments[3];
171
172 // Receive commitments to non-op-queue wires and ordered range constraints
173 for (auto [comm, label] : zip_view(commitments.get_non_opqueue_wires_and_ordered_range_constraints(),
174 commitment_labels.get_non_opqueue_wires_and_ordered_range_constraints())) {
175 comm = transcript->template receive_from_prover<Commitment>(label);
176 }
177
178 // Get permutation challenges
179 FF beta = transcript->template get_challenge<FF>("beta");
180 FF gamma = transcript->template get_challenge<FF>("gamma");
181
182 relation_parameters.beta = beta;
183 relation_parameters.gamma = gamma;
184
185 // Get commitment to permutation and lookup grand products
186 commitments.z_perm = transcript->template receive_from_prover<Commitment>(commitment_labels.z_perm);
187
188 return commitments;
189}
190
191template <typename Flavor>
193{
194 BB_BENCH_NAME("TranslatorVerifier::reduce");
195 using PCS = typename Flavor::PCS;
197 using ClaimBatcher = ClaimBatcher_<Curve>;
198 using ClaimBatch = typename ClaimBatcher::Batch;
199 using Sumcheck = SumcheckVerifier<Flavor>;
200
201 auto commitments = receive_pre_sumcheck();
202
203 // Each linearly independent subrelation contribution is multiplied by `alpha^i`, where
204 // i = 0, ..., NUM_SUBRELATIONS- 1.
205 const FF alpha = transcript->template get_challenge<FF>("Sumcheck:alpha");
206
207 // Execute Sumcheck Verifier
208 Sumcheck sumcheck(transcript, alpha, TranslatorFlavor::CONST_TRANSLATOR_LOG_N);
209
210 std::vector<FF> gate_challenges = transcript->template get_dyadic_powers_of_challenge<FF>(
211 "Sumcheck:gate_challenge", TranslatorFlavor::CONST_TRANSLATOR_LOG_N);
212
213 // Receive commitments to Libra masking polynomials
214 std::array<Commitment, NUM_SMALL_IPA_COMMITMENTS> libra_commitments = {};
215 libra_commitments[0] = transcript->template receive_from_prover<Commitment>("Libra:concatenation_commitment");
216
217 auto sumcheck_output = sumcheck.verify(relation_parameters, gate_challenges);
218
219 libra_commitments[1] = transcript->template receive_from_prover<Commitment>("Libra:grand_sum_commitment");
220 libra_commitments[2] = transcript->template receive_from_prover<Commitment>("Libra:quotient_commitment");
221
222 // Unshifted concat evals are reconstructed inside sumcheck (via complete_full_circuit_evaluations).
223 // Here we only need the shifted concat evals for PCS, which are not stored in AllEntities.
224 auto& claimed = sumcheck_output.claimed_evaluations;
226 claimed.get_groups_to_be_concatenated_shifted(), std::span<const FF>(sumcheck_output.challenge));
227
228 // --- PCS: build opening claims and verify ---
229 auto combined_unshifted_comms = commitments.get_pcs_unshifted();
230 auto combined_unshifted_evals = claimed.get_pcs_unshifted();
231
232 // For shifted: commitments use the getter, but evals must be assembled manually since
233 // the reconstructed shifted concat evals live in a local array, not in AllEntities.
234 auto combined_shifted_comms = commitments.get_pcs_to_be_shifted();
235 RefVector<FF> combined_shifted_evals(claimed.get_pcs_shifted());
236 for (auto& eval : concat_shift_evals) {
237 combined_shifted_evals.push_back(eval);
238 }
239
240 if (combined_unshifted_comms.size() != TranslatorFlavor::NUM_PCS_UNSHIFTED ||
241 combined_unshifted_evals.size() != TranslatorFlavor::NUM_PCS_UNSHIFTED ||
242 combined_shifted_comms.size() != TranslatorFlavor::NUM_PCS_TO_BE_SHIFTED ||
243 combined_shifted_evals.size() != TranslatorFlavor::NUM_PCS_TO_BE_SHIFTED) {
244 throw_or_abort("Translator verifier: PCS commitment/evaluation size mismatch");
245 }
246
247 ClaimBatcher claim_batcher{ .unshifted = ClaimBatch{ combined_unshifted_comms, combined_unshifted_evals },
248 .shifted = ClaimBatch{ combined_shifted_comms, combined_shifted_evals } };
249
250 Commitment commitment_one;
251 if constexpr (IsRecursive) {
252 commitment_one = Commitment::one(builder);
253 } else {
254 commitment_one = Commitment::one();
255 }
256
257 auto [opening_claim, consistency_checked] =
258 Shplemini::compute_batch_opening_claim(claim_batcher,
259 sumcheck_output.challenge,
260 commitment_one,
261 transcript,
262 Flavor::REPEATED_COMMITMENTS,
263 libra_commitments,
264 sumcheck_output.claimed_libra_evaluation);
265
266 auto pairing_points = PCS::reduce_verify_batch_opening_claim(std::move(opening_claim), transcript);
267
268 vinfo("Translator Verifier: sumcheck verified: ", sumcheck_output.verified);
269 vinfo("Translator Verifier: consistency checked: ", consistency_checked);
270
271 return { pairing_points, sumcheck_output.verified && consistency_checked };
272}
273
274// Explicit instantiations
277
278} // namespace bb
#define BB_ASSERT(expression,...)
Definition assert.hpp:70
bb::field< bb::Bn254FrParams > FF
Definition field.cpp:24
#define BB_BENCH_NAME(name)
Definition bb_bench.hpp:264
typename Curve::ScalarField FF
typename Curve::BaseField BF
IPA (inner product argument) commitment scheme class.
Definition ipa.hpp:87
A template class for a reference vector. Behaves as if std::vector<T&> was possible.
std::size_t size() const
void push_back(T &element)
Implementation of the sumcheck Verifier for statements of the form for multilinear polynomials .
Definition sumcheck.hpp:802
static constexpr size_t NUM_PCS_UNSHIFTED
static constexpr size_t CONST_TRANSLATOR_LOG_N
static std::array< FFType, NUM_CONCATENATED_POLYS > reconstruct_concatenated_evaluations(const std::vector< RefVector< FFType > > &groups, std::span< const FFType > challenge)
Reconstruct concatenated polynomial evaluations from individual wire evaluations using the Lagrange b...
static constexpr size_t NUM_PCS_TO_BE_SHIFTED
Translator verifier class that verifies the proof of the Translator circuit.
ReductionResult reduce_to_pairing_check()
Reduce the translator proof to a pairing check.
void put_translation_data_in_relation_parameters()
Populate relation parameters with translation data from ECCVM verifier.
typename Flavor::VerifierCommitments VerifierCommitments
VerifierCommitments receive_pre_sumcheck()
Load translator proof and run the pre-sumcheck (Oink-like) phase on the shared transcript.
typename Flavor::CommitmentLabels CommitmentLabels
typename Flavor::Commitment Commitment
#define vinfo(...)
Definition log.hpp:94
AluTraceBuilder builder
Definition alu.test.cpp:124
std::string label
Entry point for Barretenberg command-line interface.
Definition api.hpp:5
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
This file contains part of the logic for the Origin Tag mechanism that tracks the use of in-circuit p...
Logic to support batching opening claims for unshifted and shifted polynomials in Shplemini.
Result of reducing translator proof to pairing check.
void throw_or_abort(std::string const &err)
VectorField result