Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
transcript_test_fixture.hpp
Go to the documentation of this file.
1// Unified transcript test infrastructure
2// Templates on Codec and HashFn to match BaseTranscript structure
3
4#pragma once
13#include <gtest/gtest.h>
14
15namespace bb::test {
16
17// ============================================================================
18// Unified Test Fixture - Templates on Codec and HashFn like BaseTranscript
19// ============================================================================
20
21template <typename Codec, typename HashFunction> class TranscriptTest : public ::testing::Test {
22 public:
24 using FF = typename Codec::fr;
25 using BF = typename Codec::fq;
26 using bn254_commitment = typename Codec::bn254_commitment;
27 using grumpkin_commitment = typename Codec::grumpkin_commitment;
28
29 static constexpr bool IsStdlib = Transcript::in_circuit;
30
31 // Helper to get Builder type or int for native
32 template <typename C, typename = void> struct GetBuilder {
33 using type = int; // Dummy type for native
34 };
35 template <typename C> struct GetBuilder<C, std::void_t<typename C::Builder>> {
36 using type = typename C::Builder;
37 };
38
39 // For stdlib transcripts, we need a builder
41
42 void SetUp() override
43 {
44 if constexpr (IsStdlib) {
46 }
47 }
48
49 // ========================================================================
50 // Helper Methods
51 // ========================================================================
52
53 void skip_if_native(const char* reason)
54 {
55 if constexpr (!IsStdlib) {
56 GTEST_SKIP() << reason;
57 }
58 }
59
60 void skip_if_stdlib(const char* reason)
61 {
62 if constexpr (IsStdlib) {
63 GTEST_SKIP() << reason;
64 }
65 }
66
68 {
69 if constexpr (IsStdlib) {
70 // Only check circuit for stdlib transcripts with valid builder
71 EXPECT_TRUE(CircuitChecker::check(builder));
72 }
73 }
74
76 {
77 if constexpr (IsStdlib) {
79 } else {
80 return prover.export_proof();
81 }
82 }
83
84 template <typename T> auto to_native(const T& val) const
85 {
86 if constexpr (IsStdlib) {
87 return val.get_value();
88 } else {
89 return val;
90 }
91 }
92
94 {
95 NativeTranscript prover;
96 bb::fr scalar_value = bb::fr::random_element();
97 prover.send_to_verifier("scalar", scalar_value);
98
99 Transcript verifier;
100 verifier.load_proof(export_proof(prover));
101 auto received = verifier.template receive_from_prover<FF>("scalar");
102
103 BB_ASSERT_EQ(scalar_value, to_native(received));
105 }
106
108 {
109 NativeTranscript prover;
110 bb::fq basefield_value = bb::fq::random_element();
111 prover.send_to_verifier("basefield", basefield_value);
112
113 Transcript verifier;
114 verifier.load_proof(export_proof(prover));
115 auto received = verifier.template receive_from_prover<BF>("basefield");
116
117 BB_ASSERT_EQ(basefield_value, bb::fq(to_native(received)));
119 }
120
122 {
123 NativeTranscript prover;
124 auto commitment = curve::BN254::AffineElement::random_element();
125 prover.send_to_verifier("commitment", commitment);
126
127 Transcript verifier;
128 verifier.load_proof(export_proof(prover));
129 auto received = verifier.template receive_from_prover<bn254_commitment>("commitment");
130
131 BB_ASSERT_EQ(commitment, to_native(received));
133 }
134
136 {
137 NativeTranscript prover;
138 auto commitment = curve::Grumpkin::AffineElement::random_element();
139 prover.send_to_verifier("commitment", commitment);
140
141 Transcript verifier;
142 verifier.load_proof(export_proof(prover));
143 auto received = verifier.template receive_from_prover<grumpkin_commitment>("commitment");
144
145 BB_ASSERT_EQ(commitment, to_native(received));
147 }
148
149 template <size_t SIZE> void test_array_send_receive()
150 {
151 NativeTranscript prover;
152 std::array<bb::fr, SIZE> array_value;
153 for (auto& val : array_value) {
155 }
156 prover.send_to_verifier("array", array_value);
157
158 Transcript verifier;
159 verifier.load_proof(export_proof(prover));
160 auto received = verifier.template receive_from_prover<std::array<FF, SIZE>>("array");
161
162 for (size_t i = 0; i < SIZE; ++i) {
163 BB_ASSERT_EQ(array_value[i], to_native(received[i]));
164 }
166 }
167
168 template <size_t SIZE> void test_grumpkin_field_array_send_receive()
169 {
170 NativeTranscript prover;
172 for (auto& val : array_value) {
174 }
175 prover.send_to_verifier("grumpkin_array", array_value);
176
177 Transcript verifier;
178 verifier.load_proof(export_proof(prover));
179
180 // For stdlib, grumpkin::fr is serialized as bigfield
181 auto received = verifier.template receive_from_prover<std::array<BF, SIZE>>("grumpkin_array");
182 for (size_t i = 0; i < SIZE; ++i) {
183 // Convert bigfield back to grumpkin::fr via uint256_t
184 grumpkin::fr received_value(to_native(received[i]));
185 BB_ASSERT_EQ(array_value[i], received_value);
186 }
188 }
189
190 template <size_t LENGTH> void test_univariate_send_receive()
191 {
192 NativeTranscript prover;
194 for (auto& eval : evals) {
195 eval = bb::fr::random_element();
196 }
197 bb::Univariate<bb::fr, LENGTH> univariate(evals);
198 prover.send_to_verifier("univariate", univariate);
199
200 Transcript verifier;
201 verifier.load_proof(export_proof(prover));
202 auto received = verifier.template receive_from_prover<bb::Univariate<FF, LENGTH>>("univariate");
203
204 for (size_t i = 0; i < LENGTH; ++i) {
205 BB_ASSERT_EQ(evals[i], to_native(received.evaluations[i]));
206 }
208 }
209
210 template <size_t LENGTH> void test_grumpkin_univariate_send_receive()
211 {
212 NativeTranscript prover;
214 for (auto& eval : evals) {
216 }
217 bb::Univariate<grumpkin::fr, LENGTH> univariate(evals);
218 prover.send_to_verifier("grumpkin_univariate", univariate);
219
220 Transcript verifier;
221 verifier.load_proof(export_proof(prover));
222
223 if constexpr (IsStdlib) {
224 auto received = verifier.template receive_from_prover<bb::Univariate<BF, LENGTH>>("grumpkin_univariate");
225 for (size_t i = 0; i < LENGTH; ++i) {
226 grumpkin::fr received_value(received.evaluations[i].get_value());
227 BB_ASSERT_EQ(evals[i], received_value);
228 }
229 } else {
230 auto received =
231 verifier.template receive_from_prover<bb::Univariate<grumpkin::fr, LENGTH>>("grumpkin_univariate");
232 for (size_t i = 0; i < LENGTH; ++i) {
233 BB_ASSERT_EQ(evals[i], received.evaluations[i]);
234 }
235 }
237 }
238
240 {
241 NativeTranscript prover;
242 auto infinity = curve::BN254::AffineElement::infinity();
243 prover.send_to_verifier("infinity", infinity);
244
245 Transcript verifier;
246 verifier.load_proof(export_proof(prover));
247 auto received = verifier.template receive_from_prover<bn254_commitment>("infinity");
248
249 if constexpr (IsStdlib) {
250 EXPECT_TRUE(received.is_point_at_infinity().get_value());
251 } else {
252 EXPECT_TRUE(received.is_point_at_infinity());
253 }
254 BB_ASSERT_EQ(infinity, to_native(received));
256 }
257
259 {
260 NativeTranscript prover;
261 auto infinity = curve::Grumpkin::AffineElement::infinity();
262 prover.send_to_verifier("infinity", infinity);
263
264 Transcript verifier;
265 verifier.load_proof(export_proof(prover));
266 auto received = verifier.template receive_from_prover<grumpkin_commitment>("infinity");
267
268 if constexpr (IsStdlib) {
269 EXPECT_TRUE(received.is_point_at_infinity().get_value());
270 } else {
271 EXPECT_TRUE(received.is_point_at_infinity());
272 }
273 BB_ASSERT_EQ(infinity, to_native(received));
275 }
276
278 {
279 NativeTranscript prover;
280
281 // Round 0
282 uint32_t data = 25;
283 prover.send_to_verifier("data", data);
284 auto prover_alpha = prover.template get_challenge<bb::fr>("alpha");
285
286 // Round 1
288 auto commitment = curve::BN254::AffineElement::random_element();
289 prover.send_to_verifier("scalar", scalar);
290 prover.send_to_verifier("commitment", commitment);
291 std::array<std::string, 2> challenge_labels = { "beta", "gamma" };
292 auto [prover_beta, prover_gamma] = prover.template get_challenges<bb::fr>(challenge_labels);
293
294 // Verifier side
295 Transcript verifier;
296 verifier.load_proof(export_proof(prover));
297
298 // Round 0
299 [[maybe_unused]] auto data_recv = verifier.template receive_from_prover<FF>("data");
300 auto verifier_alpha = verifier.template get_challenge<FF>("alpha");
301
302 // Round 1
303 auto recv_scalar = verifier.template receive_from_prover<FF>("scalar");
304 auto recv_commitment = verifier.template receive_from_prover<bn254_commitment>("commitment");
305 auto [verifier_beta, verifier_gamma] = verifier.template get_challenges<FF>(challenge_labels);
306
307 // Verify values match
308 BB_ASSERT_EQ(scalar, to_native(recv_scalar));
309 BB_ASSERT_EQ(commitment, to_native(recv_commitment));
310 BB_ASSERT_EQ(prover_alpha, to_native(verifier_alpha));
311 BB_ASSERT_EQ(prover_beta, to_native(verifier_beta));
312 BB_ASSERT_EQ(prover_gamma, to_native(verifier_gamma));
313
315 }
316
318 {
319 NativeTranscript prover;
320
321 // Simulate a simple protocol
322 prover.send_to_verifier("scalar", bb::fr::random_element());
323 prover.template get_challenge<bb::fr>("alpha");
324 prover.send_to_verifier("commitment", curve::BN254::AffineElement::random_element());
325 std::array<std::string, 2> challenge_labels = { "beta", "gamma" };
326 prover.template get_challenges<bb::fr>(challenge_labels);
327
328 Transcript verifier;
329 verifier.load_proof(export_proof(prover));
330 verifier.template receive_from_prover<FF>("scalar");
331 verifier.template get_challenge<FF>("alpha");
332 verifier.template receive_from_prover<bn254_commitment>("commitment");
333 verifier.template get_challenges<FF>(challenge_labels);
334
335 EXPECT_EQ(prover.get_manifest(), verifier.get_manifest());
336
338 }
339
341 {
342 NativeTranscript prover;
344
345 auto challenge1 = prover.template get_challenge<bb::fr>("alpha");
346 auto challenge2 = prover.template get_challenge<bb::fr>("beta");
347 auto challenge3 = prover.template get_challenge<bb::fr>("gamma");
348
349 BB_ASSERT_NEQ(challenge1, bb::fr::zero());
350 BB_ASSERT_NEQ(challenge2, bb::fr::zero());
351 BB_ASSERT_NEQ(challenge3, bb::fr::zero());
352 }
353
355 {
356 NativeTranscript prover;
357 Transcript verifier;
358 prover.add_to_hash_buffer("a", bb::fr(1));
359
360 FF one(1);
361 if constexpr (IsStdlib) {
362 one.convert_constant_to_fixed_witness(&builder);
363 }
364 verifier.add_to_hash_buffer("a", one);
365 auto prover_chal = prover.template get_challenge<bb::fr>("alpha");
366 auto verifier_chal = verifier.template get_challenge<FF>("alpha");
367 BB_ASSERT_EQ(prover_chal, to_native(verifier_chal));
368 }
369
371 {
372 skip_if_stdlib("Native-only - tests transcript conversion");
373
374 auto prover_transcript = std::make_shared<NativeTranscript>();
375
376 bb::fr elt_a = 100;
377 prover_transcript->send_to_verifier("a", elt_a);
378 [[maybe_unused]] auto proof1 = prover_transcript->export_proof();
379
380 bb::fr elt_b = 200;
381 prover_transcript->send_to_verifier("b", elt_b);
382 [[maybe_unused]] auto proof2 = prover_transcript->export_proof();
383
384 auto verifier_transcript =
386
387 BB_ASSERT_EQ(verifier_transcript->test_get_proof_start(), 0);
388 BB_ASSERT_EQ(prover_transcript->template get_challenge<bb::fr>("test_challenge"),
389 verifier_transcript->template get_challenge<bb::fr>("test_challenge"));
390 }
391
393 {
394 class TamperableTranscript : public NativeTranscript {
395 public:
396 void tamper_proof_data() { proof_data[0] += 1; }
397 };
398
399 TamperableTranscript prover;
400 Transcript verifier;
401
402 prover.enable_manifest();
403 verifier.enable_manifest();
404
405 prover.add_to_hash_buffer("vk_field", bb::fr(1));
406
407 prover.send_to_verifier("random_field", bb::fr::random_element());
408 prover.send_to_verifier("random_grumpkin", curve::Grumpkin::AffineElement::random_element());
409 prover.send_to_verifier("random_bn254", curve::BN254::AffineElement::random_element());
410
411 auto prover_challenge = prover.template get_challenge<bb::fr>("alpha");
412
413 prover.tamper_proof_data();
414
415 FF one(1);
416 if constexpr (IsStdlib) {
417 one.convert_constant_to_fixed_witness(&builder);
418 }
419 verifier.load_proof(export_proof(prover));
420 verifier.add_to_hash_buffer("vk_field", one);
421 verifier.template receive_from_prover<FF>("random_field");
422 verifier.template receive_from_prover<grumpkin_commitment>("random_grumpkin");
423 verifier.template receive_from_prover<bn254_commitment>("random_bn254");
424 auto verifier_challenge = verifier.template get_challenge<FF>("alpha");
425
426 EXPECT_EQ(prover.get_manifest(), verifier.get_manifest());
427 BB_ASSERT_NEQ(prover_challenge, to_native(verifier_challenge));
428 }
429
431};
432
433// ============================================================================
434// Test Type Lists
435// ============================================================================
436
439
442
445
446// NOTE: Keccak transcripts use U256Codec and are tested separately via flavor-specific tests
447// (e.g., UltraKeccakFlavor tests) because they require different data representation (uint256_t vs fr)
448using TranscriptTypes = ::testing::
449 Types<std::pair<NativeCodec, NativeHash>, std::pair<UltraCodec, UltraHash>, std::pair<MegaCodec, MegaHash>>;
450
451} // namespace bb::test
#define BB_ASSERT_NEQ(actual, expected,...)
Definition assert.hpp:92
#define BB_ASSERT_EQ(actual, expected,...)
Definition assert.hpp:77
std::vector< DataType > export_proof()
Return the proof data starting at proof_start.
void add_to_hash_buffer(const std::string &label, const T &element)
Adds an element to the transcript.
void send_to_verifier(const std::string &label, const T &element)
Adds a prover message to the transcript, only intended to be used by the prover.
void load_proof(const std::vector< DataType > &proof)
Verifier-specific method. The verifier needs to load a proof or its segment before the verification.
TranscriptManifest get_manifest() const
static std::shared_ptr< BaseTranscript > convert_prover_transcript_to_verifier_transcript(const std::shared_ptr< BaseTranscript > &prover_transcript)
Convert a prover transcript to a verifier transcript.
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
A univariate polynomial represented by its values on {0, 1,..., domain_end - 1}.
A simple wrapper around a vector of stdlib field elements representing a proof.
Definition proof.hpp:19
stdlib class that evaluates in-circuit poseidon2 hashes, consistent with behavior in crypto::poseidon...
Definition poseidon2.hpp:20
auto export_proof(NativeTranscript &prover)
void skip_if_stdlib(const char *reason)
typename GetBuilder< Codec >::type BuilderType
auto to_native(const T &val) const
typename Codec::grumpkin_commitment grumpkin_commitment
typename Codec::bn254_commitment bn254_commitment
void skip_if_native(const char *reason)
const std::vector< MemoryValue > data
::testing::Types< std::pair< NativeCodec, NativeHash >, std::pair< UltraCodec, UltraHash >, std::pair< MegaCodec, MegaHash > > TranscriptTypes
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
static field random_element(numeric::RNG *engine=nullptr) noexcept
static constexpr field zero()