Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
aes128_constraint.test.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], commit: }
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
8#include "acir_format.hpp"
15
16#include <cstdint>
17#include <gtest/gtest.h>
18#include <vector>
19
20using namespace acir_format;
21
22namespace {
24} // namespace
25
37template <typename Builder_, bool IsPlaintextConstant, bool IsKeyConstant, bool IsIVConstant>
39 public:
40 using Builder = Builder_;
42 using FF = typename Builder::FF;
43
45 public:
46 enum class Target : uint8_t {
47 None, // No invalidation - circuit should succeed
48 Plaintext, // Tamper with plaintext (only valid when plaintext is witness)
49 Key, // Tamper with encryption key (only valid when key is witness)
50 IV, // Tamper with initialization vector (only valid when IV is witness)
51 Output, // Tamper with expected output
52 };
53
55 {
57 if constexpr (!IsPlaintextConstant) {
58 targets.push_back(Target::Plaintext);
59 }
60 if constexpr (!IsKeyConstant) {
61 targets.push_back(Target::Key);
62 }
63 if constexpr (!IsIVConstant) {
64 targets.push_back(Target::IV);
65 }
66 targets.push_back(Target::Output);
67 return targets;
68 }
69
70 static std::vector<std::string> get_labels()
71 {
72 std::vector<std::string> labels = { "None" };
73 if constexpr (!IsPlaintextConstant) {
74 labels.push_back("Plaintext");
75 }
76 if constexpr (!IsKeyConstant) {
77 labels.push_back("Key");
78 }
79 if constexpr (!IsIVConstant) {
80 labels.push_back("IV");
81 }
82 labels.push_back("Output");
83 return labels;
84 }
85 };
86
88
98 static void generate_constraints(AcirConstraint& constraint, WitnessVector& witness_values)
99 {
100 // Generate random plaintext with 1-3 full blocks (16, 32, or 48 bytes)
101 size_t num_blocks = 1 + (engine.get_random_uint32() % 3);
102 size_t plaintext_size = num_blocks * 16;
103
104 std::vector<uint8_t> plaintext(plaintext_size);
105 for (auto& byte : plaintext) {
106 byte = static_cast<uint8_t>(engine.get_random_uint32() & 0xFF);
107 }
108
109 // Generate random key (16 bytes)
110 std::array<uint8_t, 16> key{};
111 for (auto& byte : key) {
112 byte = static_cast<uint8_t>(engine.get_random_uint32() & 0xFF);
113 }
114
115 // Generate random IV (16 bytes)
116 std::array<uint8_t, 16> iv{};
117 for (auto& byte : iv) {
118 byte = static_cast<uint8_t>(engine.get_random_uint32() & 0xFF);
119 }
120
121 // Compute the expected ciphertext using native AES-128-CBC (no padding for full blocks)
122 std::vector<uint8_t> ciphertext = native_aes128_cbc_encrypt(plaintext, key, iv);
123
124 // Lambda to create WitnessOrConstant based on template param
125 auto make_witness_or_constant = [&witness_values](FF value, bool is_constant) -> WitnessOrConstant<FF> {
126 if (is_constant) {
128 }
129 uint32_t witness_idx = add_to_witness_and_track_indices(witness_values, value);
130 return WitnessOrConstant<FF>::from_index(witness_idx);
131 };
132
133 // Add plaintext bytes to constraint
134 std::vector<WitnessOrConstant<FF>> input_witnesses;
135 for (const auto& byte : plaintext) {
136 input_witnesses.push_back(make_witness_or_constant(FF(byte), IsPlaintextConstant));
137 }
138
139 // Add key bytes to constraint
140 std::array<WitnessOrConstant<FF>, 16> key_witnesses{};
141 for (size_t i = 0; i < 16; ++i) {
142 key_witnesses[i] = make_witness_or_constant(FF(key[i]), IsKeyConstant);
143 }
144
145 // Add IV bytes to constraint
146 std::array<WitnessOrConstant<FF>, 16> iv_witnesses{};
147 for (size_t i = 0; i < 16; ++i) {
148 iv_witnesses[i] = make_witness_or_constant(FF(iv[i]), IsIVConstant);
149 }
150
151 // Add output (ciphertext) bytes to witness (always witness)
152 std::vector<uint32_t> output_indices;
153 for (const auto& byte : ciphertext) {
154 uint32_t witness_idx = add_to_witness_and_track_indices(witness_values, FF(byte));
155 output_indices.push_back(witness_idx);
156 }
157
158 // Build the constraint
159 constraint = AES128Constraint{
160 .inputs = std::move(input_witnesses),
161 .iv = iv_witnesses,
162 .key = key_witnesses,
163 .outputs = std::move(output_indices),
164 };
165 }
166
171 WitnessVector witness_values,
172 const typename InvalidWitness::Target& target)
173 {
174 switch (target) {
176 // No tampering
177 break;
178
180 // Tamper with the first plaintext byte
181 if constexpr (IsPlaintextConstant) {
182 if (!constraint.inputs.empty()) {
183 constraint.inputs[0] = WitnessOrConstant<FF>::from_constant(constraint.inputs[0].value + FF(1));
184 }
185 } else {
186 if (!constraint.inputs.empty()) {
187 witness_values[constraint.inputs[0].index] += FF(1);
188 }
189 }
190 break;
191
193 // Tamper with the first key byte
194 if constexpr (IsKeyConstant) {
195 constraint.key[0] = WitnessOrConstant<FF>::from_constant(constraint.key[0].value + FF(1));
196 } else {
197 witness_values[constraint.key[0].index] += FF(1);
198 }
199 break;
200
202 // Tamper with the first IV byte
203 if constexpr (IsIVConstant) {
204 constraint.iv[0] = WitnessOrConstant<FF>::from_constant(constraint.iv[0].value + FF(1));
205 } else {
206 witness_values[constraint.iv[0].index] += FF(1);
207 }
208 break;
209
211 // Tamper with the first output byte
212 if (!constraint.outputs.empty()) {
213 witness_values[constraint.outputs[0]] += FF(1);
214 }
215 break;
216 }
217
218 return { constraint, witness_values };
219 }
220
221 private:
228 static std::vector<uint8_t> native_aes128_cbc_encrypt(const std::vector<uint8_t>& plaintext,
229 const std::array<uint8_t, 16>& key,
230 const std::array<uint8_t, 16>& iv)
231 {
232 // Copy plaintext to output buffer (no padding for full blocks)
233 std::vector<uint8_t> buffer = plaintext;
234
235 // Create mutable copy of IV (the native function modifies it)
236 std::array<uint8_t, 16> iv_copy = iv;
237
238 // Encrypt in-place using the native crypto implementation
239 crypto::aes128_encrypt_buffer_cbc(buffer.data(), iv_copy.data(), key.data(), buffer.size());
240
241 return buffer;
242 }
243};
244
245using BuilderTypes = testing::Types<UltraCircuitBuilder, MegaCircuitBuilder>;
246
247// =============================================================================
248// Test Configuration 1: All witnesses (plaintext, key, and IV are witnesses)
249// =============================================================================
250template <typename Builder>
251class AES128TestAllWitness : public ::testing::Test,
252 public TestClass<AES128TestingFunctions<Builder, false, false, false>> {
253 protected:
255};
256
258
259TYPED_TEST(AES128TestAllWitness, GenerateVKFromConstraints)
260{
262 TestFixture::template test_vk_independence<Flavor>();
263}
264
266{
267 TestFixture::test_tampering();
268}
269// =============================================================================
270// Test Configuration 2: Constant plaintext (key and IV are witnesses)
271// =============================================================================
272template <typename Builder>
273class AES128TestConstantPlaintext : public ::testing::Test,
274 public TestClass<AES128TestingFunctions<Builder, true, false, false>> {
275 protected:
277};
278
280
281TYPED_TEST(AES128TestConstantPlaintext, GenerateVKFromConstraints)
282{
284 TestFixture::template test_vk_independence<Flavor>();
285}
286
288{
289 TestFixture::test_tampering();
290}
291
292// =============================================================================
293// Test Configuration 3: Constant key (plaintext and IV are witnesses)
294// =============================================================================
295template <typename Builder>
296class AES128TestConstantKey : public ::testing::Test,
297 public TestClass<AES128TestingFunctions<Builder, false, true, false>> {
298 protected:
300};
301
303
304TYPED_TEST(AES128TestConstantKey, GenerateVKFromConstraints)
305{
307 TestFixture::template test_vk_independence<Flavor>();
308}
309
311{
312 TestFixture::test_tampering();
313}
314
315// =============================================================================
316// Test Configuration 4: Constant IV (plaintext and key are witnesses)
317// =============================================================================
318template <typename Builder>
319class AES128TestConstantIV : public ::testing::Test,
320 public TestClass<AES128TestingFunctions<Builder, false, false, true>> {
321 protected:
323};
324
326
327TYPED_TEST(AES128TestConstantIV, GenerateVKFromConstraints)
328{
330 TestFixture::template test_vk_independence<Flavor>();
331}
332
334{
335 TestFixture::test_tampering();
336}
337
338// =============================================================================
339// Test Configuration 5: All constants (plaintext, key, and IV are constants)
340// =============================================================================
341template <typename Builder>
342class AES128TestAllConstant : public ::testing::Test,
343 public TestClass<AES128TestingFunctions<Builder, true, true, true>> {
344 protected:
346};
347
349
350TYPED_TEST(AES128TestAllConstant, GenerateVKFromConstraints)
351{
353 TestFixture::template test_vk_independence<Flavor>();
354}
355
357{
358 TestFixture::test_tampering();
359}
360
361// =============================================================================
362// Range Constraint Regression Tests
363// =============================================================================
364// These tests verify that the AES128 constraint properly enforces that all byte
365// values (input, key, IV, output) are in the range [0, 255]. Values outside this
366// range should cause circuit verification to fail.
367// =============================================================================
368
369class AES128RangeConstraintTest : public ::testing::Test {
370 protected:
372
375
376 // Valid test vectors for AES-128-CBC (16 bytes = 1 block)
377 static constexpr std::array<FF, 16> valid_plaintext = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
378 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a };
379
380 static constexpr std::array<FF, 16> valid_key = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
381 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
382
383 static constexpr std::array<FF, 16> valid_iv = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
384 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
385
389 static std::array<FF, 16> compute_ciphertext()
390 {
391 std::vector<uint8_t> buffer(16);
392 std::array<uint8_t, 16> key_bytes{};
393 std::array<uint8_t, 16> iv_bytes{};
394
395 for (size_t i = 0; i < 16; ++i) {
396 buffer[i] = static_cast<uint8_t>(uint256_t(valid_plaintext[i]));
397 key_bytes[i] = static_cast<uint8_t>(uint256_t(valid_key[i]));
398 iv_bytes[i] = static_cast<uint8_t>(uint256_t(valid_iv[i]));
399 }
400
401 crypto::aes128_encrypt_buffer_cbc(buffer.data(), iv_bytes.data(), key_bytes.data(), buffer.size());
402
403 std::array<FF, 16> result{};
404 for (size_t i = 0; i < 16; ++i) {
405 result[i] = FF(buffer[i]);
406 }
407 return result;
408 }
409
418 static std::pair<Builder, AES128Constraint> create_constraint(const std::array<FF, 16>& plaintext_vals,
419 const std::array<FF, 16>& key_vals,
420 const std::array<FF, 16>& iv_vals,
421 const std::array<FF, 16>& output_vals)
422 {
424
425 auto add_witness = [&builder](FF value) -> uint32_t { return builder.add_variable(value); };
426
427 // Add plaintext witnesses
428 std::vector<WitnessOrConstant<FF>> input_witnesses;
429 for (const auto& val : plaintext_vals) {
430 input_witnesses.push_back(WitnessOrConstant<FF>::from_index(add_witness(val)));
431 }
432
433 // Add key witnesses
434 std::array<WitnessOrConstant<FF>, 16> key_witnesses{};
435 for (size_t i = 0; i < 16; ++i) {
436 key_witnesses[i] = WitnessOrConstant<FF>::from_index(add_witness(key_vals[i]));
437 }
438
439 // Add IV witnesses
440 std::array<WitnessOrConstant<FF>, 16> iv_witnesses{};
441 for (size_t i = 0; i < 16; ++i) {
442 iv_witnesses[i] = WitnessOrConstant<FF>::from_index(add_witness(iv_vals[i]));
443 }
444
445 // Add output witnesses
446 std::vector<uint32_t> output_indices;
447 for (const auto& val : output_vals) {
448 output_indices.push_back(add_witness(val));
449 }
450
451 AES128Constraint constraint{
452 .inputs = std::move(input_witnesses),
453 .iv = iv_witnesses,
454 .key = key_witnesses,
455 .outputs = std::move(output_indices),
456 };
457
458 return { std::move(builder), std::move(constraint) };
459 }
460
468 {
469 // Don't catch exceptions - we want to verify CIRCUIT constraints catch the issue,
470 // not native checks that could be bypassed by a malicious prover
473 }
474};
475
489TEST_F(AES128RangeConstraintTest, PlaintextOutOfRangeFails)
490{
491 // The "overflowed" plaintext that AES would actually see after slicing
492 // attacker [..., 0, 256] becomes [..., 1, 0] when packed (256) and sliced
493 std::array<FF, 16> overflowed_plaintext = {};
494 overflowed_plaintext[14] = FF(1); // Carry from position 15
495 overflowed_plaintext[15] = FF(0); // 256 % 256 = 0
496 // rest are 0
497
498 // Compute the ciphertext for the OVERFLOWED plaintext
499 std::vector<uint8_t> buffer(16, 0);
500 buffer[14] = 1;
501 buffer[15] = 0;
502 std::array<uint8_t, 16> key_bytes{};
503 std::array<uint8_t, 16> iv_bytes{};
504 for (size_t i = 0; i < 16; ++i) {
505 key_bytes[i] = static_cast<uint8_t>(uint256_t(valid_key[i]));
506 iv_bytes[i] = static_cast<uint8_t>(uint256_t(valid_iv[i]));
507 }
508 crypto::aes128_encrypt_buffer_cbc(buffer.data(), iv_bytes.data(), key_bytes.data(), buffer.size());
509
510 std::array<FF, 16> overflowed_ciphertext{};
511 for (size_t i = 0; i < 16; ++i) {
512 overflowed_ciphertext[i] = FF(buffer[i]);
513 }
514
515 // PART 1: Verify that [..., 1, 0] with matching ciphertext PASSES
516 // This proves the lookups work fine - there's no issue with the data itself
517 {
518 auto [builder, constraint] =
519 create_constraint(overflowed_plaintext, valid_key, valid_iv, overflowed_ciphertext);
521 EXPECT_TRUE(CircuitChecker::check(builder))
522 << "Sanity check: [..., 1, 0] with correct ciphertext should pass (lookups work)";
523 }
524
525 // PART 2: Verify that [..., 0, 256] FAILS due to range constraint
526 // The attacker's plaintext has 256 in LSB position, overflows to [..., 1, 0]
527 std::array<FF, 16> attacker_plaintext = {};
528 attacker_plaintext[15] = FF(256); // Out of range in LSB position!
529 // rest are 0
530
531 // Attacker provides the ciphertext that matches the overflowed interpretation
532 auto [builder, constraint] = create_constraint(attacker_plaintext, valid_key, valid_iv, overflowed_ciphertext);
534 EXPECT_TRUE(builder.failed()) << "Circuit should fail when plaintext has byte > 255";
535 EXPECT_FALSE(CircuitChecker::check(builder));
536}
537
545{
546 // The "overflowed" key that AES would see: [..., 1, 0]
547 std::array<FF, 16> overflowed_key = {};
548 overflowed_key[14] = FF(1); // Carry from position 15
549 overflowed_key[15] = FF(0); // 256 % 256 = 0
550
551 // Compute ciphertext with the overflowed key
552 std::vector<uint8_t> buffer(16);
553 std::array<uint8_t, 16> key_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
554 std::array<uint8_t, 16> iv_bytes{};
555 for (size_t i = 0; i < 16; ++i) {
556 buffer[i] = static_cast<uint8_t>(uint256_t(valid_plaintext[i]));
557 iv_bytes[i] = static_cast<uint8_t>(uint256_t(valid_iv[i]));
558 }
559 crypto::aes128_encrypt_buffer_cbc(buffer.data(), iv_bytes.data(), key_bytes.data(), buffer.size());
560
561 std::array<FF, 16> overflowed_ciphertext{};
562 for (size_t i = 0; i < 16; ++i) {
563 overflowed_ciphertext[i] = FF(buffer[i]);
564 }
565
566 // PART 1: Verify lookups work with valid key [..., 1, 0]
567 {
568 auto [builder, constraint] =
569 create_constraint(valid_plaintext, overflowed_key, valid_iv, overflowed_ciphertext);
571 EXPECT_TRUE(CircuitChecker::check(builder)) << "Sanity check: key [..., 1, 0] should pass (lookups work)";
572 }
573
574 // PART 2: Verify [..., 0, 256] key FAILS due to range constraint
575 std::array<FF, 16> attacker_key = {};
576 attacker_key[15] = FF(256); // Out of range in LSB position!
577
578 auto [builder, constraint] = create_constraint(valid_plaintext, attacker_key, valid_iv, overflowed_ciphertext);
580 EXPECT_TRUE(builder.failed()) << "Circuit should fail when key has byte > 255";
581 EXPECT_FALSE(CircuitChecker::check(builder));
582}
583
590{
591 // The "overflowed" IV that AES would see: [..., 1, 0]
592 std::array<FF, 16> overflowed_iv = {};
593 overflowed_iv[14] = FF(1); // Carry from position 15
594 overflowed_iv[15] = FF(0); // 256 % 256 = 0
595
596 // Compute ciphertext with the overflowed IV
597 std::vector<uint8_t> buffer(16);
598 std::array<uint8_t, 16> key_bytes{};
599 std::array<uint8_t, 16> iv_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
600 for (size_t i = 0; i < 16; ++i) {
601 buffer[i] = static_cast<uint8_t>(uint256_t(valid_plaintext[i]));
602 key_bytes[i] = static_cast<uint8_t>(uint256_t(valid_key[i]));
603 }
604 crypto::aes128_encrypt_buffer_cbc(buffer.data(), iv_bytes.data(), key_bytes.data(), buffer.size());
605
606 std::array<FF, 16> overflowed_ciphertext{};
607 for (size_t i = 0; i < 16; ++i) {
608 overflowed_ciphertext[i] = FF(buffer[i]);
609 }
610
611 // PART 1: Verify lookups work with valid IV [..., 1, 0]
612 {
613 auto [builder, constraint] =
614 create_constraint(valid_plaintext, valid_key, overflowed_iv, overflowed_ciphertext);
616 EXPECT_TRUE(CircuitChecker::check(builder)) << "Sanity check: IV [..., 1, 0] should pass (lookups work)";
617 }
618
619 // PART 2: Verify [..., 0, 256] IV FAILS due to range constraint
620 std::array<FF, 16> attacker_iv = {};
621 attacker_iv[15] = FF(256); // Out of range in LSB position!
622
623 auto [builder, constraint] = create_constraint(valid_plaintext, valid_key, attacker_iv, overflowed_ciphertext);
625 EXPECT_TRUE(builder.failed()) << "Circuit should fail when IV has byte > 255";
626 EXPECT_FALSE(CircuitChecker::check(builder));
627}
628
636TEST_F(AES128RangeConstraintTest, OutputOutOfRangeFails)
637{
638 // Compute the valid ciphertext
639 auto valid_ciphertext = compute_ciphertext();
640
641 // PART 1: Verify circuit passes with valid output
642 {
643 auto [builder, constraint] = create_constraint(valid_plaintext, valid_key, valid_iv, valid_ciphertext);
645 EXPECT_TRUE(CircuitChecker::check(builder)) << "Sanity check: valid ciphertext should pass";
646 }
647
648 // PART 2: Create attacker output that packs to the same value using LSB positions
649 // [..., X-1, Y+256] packs same as [..., X, Y] due to overflow
650 std::array<FF, 16> attacker_output = valid_ciphertext;
651 uint64_t second_last_byte = static_cast<uint64_t>(uint256_t(valid_ciphertext[14])); // X
652 uint64_t last_byte = static_cast<uint64_t>(uint256_t(valid_ciphertext[15])); // Y
653
654 // Need second_last_byte >= 1 to subtract 1 from it
655 ASSERT_GE(second_last_byte, 1u) << "Test requires ciphertext[14] >= 1";
656
657 attacker_output[14] = FF(second_last_byte - 1); // X - 1
658 attacker_output[15] = FF(last_byte + 256); // Y + 256 (out of range!)
659
660 auto [builder, constraint] = create_constraint(valid_plaintext, valid_key, valid_iv, attacker_output);
662 EXPECT_TRUE(builder.failed()) << "Circuit should fail when output has byte > 255";
663 EXPECT_FALSE(CircuitChecker::check(builder));
664}
665
666// =============================================================================
667// Shape Validation Regression Tests
668// =============================================================================
669// Guards in create_aes128_constraints enforce:
670// - inputs.size() % 16 == 0
671// - outputs.size() == inputs.size()
672// Malformed ACIR violating either invariant would otherwise produce circuits
673// with undefined behaviour (span OOB) or under-constrained output witnesses.
674// =============================================================================
675
676class AES128ShapeValidationTest : public ::testing::Test {
677 protected:
680
681 // Build a well-formed AES128Constraint with `num_input_bytes` input and
682 // `num_output_bytes` output witnesses. Values are zero; we only exercise
683 // the shape guards, which run before any AES math.
684 static std::pair<Builder, AES128Constraint> make_constraint(size_t num_input_bytes, size_t num_output_bytes)
685 {
687 auto add_witness = [&builder](FF value) { return builder.add_variable(value); };
688
689 std::vector<WitnessOrConstant<FF>> input_witnesses;
690 for (size_t i = 0; i < num_input_bytes; ++i) {
691 input_witnesses.push_back(WitnessOrConstant<FF>::from_index(add_witness(FF(0))));
692 }
693
694 std::array<WitnessOrConstant<FF>, 16> key_witnesses{};
695 std::array<WitnessOrConstant<FF>, 16> iv_witnesses{};
696 for (size_t i = 0; i < 16; ++i) {
697 key_witnesses[i] = WitnessOrConstant<FF>::from_index(add_witness(FF(0)));
698 iv_witnesses[i] = WitnessOrConstant<FF>::from_index(add_witness(FF(0)));
699 }
700
701 std::vector<uint32_t> output_indices;
702 for (size_t i = 0; i < num_output_bytes; ++i) {
703 output_indices.push_back(add_witness(FF(0)));
704 }
705
706 AES128Constraint constraint{
707 .inputs = std::move(input_witnesses),
708 .iv = iv_witnesses,
709 .key = key_witnesses,
710 .outputs = std::move(output_indices),
711 };
712 return { std::move(builder), std::move(constraint) };
713 }
714};
715
716TEST_F(AES128ShapeValidationTest, InputsNotBlockAlignedRejected)
717{
718 auto [builder, constraint] = make_constraint(/*num_input_bytes=*/17, /*num_output_bytes=*/17);
719 EXPECT_THROW_OR_ABORT(create_aes128_constraints(builder, constraint), ".*multiple of 16.*");
720}
721
722TEST_F(AES128ShapeValidationTest, OutputsSizeMismatchRejected)
723{
724 auto [builder, constraint] = make_constraint(/*num_input_bytes=*/16, /*num_output_bytes=*/32);
725 EXPECT_THROW_OR_ABORT(create_aes128_constraints(builder, constraint), ".*same length as inputs.*");
726}
#define EXPECT_THROW_OR_ABORT(statement, matcher)
Definition assert.hpp:192
static constexpr std::array< FF, 16 > valid_iv
static std::pair< Builder, AES128Constraint > create_constraint(const std::array< FF, 16 > &plaintext_vals, const std::array< FF, 16 > &key_vals, const std::array< FF, 16 > &iv_vals, const std::array< FF, 16 > &output_vals)
Build an AES128 constraint with specified values.
static constexpr std::array< FF, 16 > valid_plaintext
static std::array< FF, 16 > compute_ciphertext()
Compute valid ciphertext for the test vectors.
static bool circuit_rejects_bad_input(Builder &builder, AES128Constraint &constraint)
Helper to test that out-of-range bytes are rejected BY THE CIRCUIT, not by native checks.
static constexpr std::array< FF, 16 > valid_key
static std::pair< Builder, AES128Constraint > make_constraint(size_t num_input_bytes, size_t num_output_bytes)
static std::vector< std::string > get_labels()
Testing functions to generate the AES128Test test suite.
static ProgramMetadata generate_metadata()
static std::vector< uint8_t > native_aes128_cbc_encrypt(const std::vector< uint8_t > &plaintext, const std::array< uint8_t, 16 > &key, const std::array< uint8_t, 16 > &iv)
Native AES-128-CBC encryption for generating expected outputs.
static void generate_constraints(AcirConstraint &constraint, WitnessVector &witness_values)
Generate valid AES128 encryption constraints with random inputs.
static std::pair< AcirConstraint, WitnessVector > invalidate_witness(AcirConstraint constraint, WitnessVector witness_values, const typename InvalidWitness::Target &target)
Invalidate witness values to test circuit failure detection.
static bool check(const Builder &circuit)
Check the witness satisifies the circuit.
typename ExecutionTrace::FF FF
virtual uint32_t get_random_uint32()=0
AluTraceBuilder builder
Definition alu.test.cpp:124
numeric::RNG & engine
std::unique_ptr< uint8_t[]> buffer
Definition engine.cpp:60
std::vector< bb::fr > WitnessVector
std::vector< uint32_t > add_to_witness_and_track_indices(std::vector< bb::fr > &witness, const T &input)
Append values to a witness vector and track their indices.
Definition utils.hpp:90
void create_aes128_constraints(Builder &builder, const AES128Constraint &constraint)
AvmFlavorSettings::FF FF
Definition field.hpp:10
void aes128_encrypt_buffer_cbc(uint8_t *buffer, uint8_t *iv, const uint8_t *key, const size_t length)
Definition aes128.cpp:234
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
Definition engine.cpp:245
std::filesystem::path bb_crs_path()
void init_file_crs_factory(const std::filesystem::path &path)
TEST_F(BoomerangGoblinRecursiveVerifierTests, graph_description_basic)
Construct and check a goblin recursive verification circuit.
TYPED_TEST_SUITE(CommitmentKeyTest, Curves)
TYPED_TEST(CommitmentKeyTest, CommitToZeroPoly)
UltraCircuitBuilder_< UltraExecutionTraceBlocks > UltraCircuitBuilder
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
::testing::Types< UltraCircuitBuilder, MegaCircuitBuilder > BuilderTypes
std::array< WitnessOrConstant< bb::fr >, 16 > iv
std::vector< uint32_t > outputs
std::vector< WitnessOrConstant< bb::fr > > inputs
std::array< WitnessOrConstant< bb::fr >, 16 > key
Metadata required to create a circuit.
static WitnessOrConstant from_index(uint32_t index)
static WitnessOrConstant from_constant(FF value)