16#include <gtest/gtest.h>
36template <
typename Builder_,
bool IsPla
intextConstant,
bool IsKeyConstant,
bool IsIVConstant>
56 if constexpr (!IsPlaintextConstant) {
59 if constexpr (!IsKeyConstant) {
62 if constexpr (!IsIVConstant) {
71 std::vector<std::string> labels = {
"None" };
72 if constexpr (!IsPlaintextConstant) {
73 labels.push_back(
"Plaintext");
75 if constexpr (!IsKeyConstant) {
76 labels.push_back(
"Key");
78 if constexpr (!IsIVConstant) {
79 labels.push_back(
"IV");
81 labels.push_back(
"Output");
101 size_t plaintext_size = num_blocks * 16;
103 std::vector<uint8_t> plaintext(plaintext_size);
104 for (
auto&
byte : plaintext) {
109 std::array<uint8_t, 16>
key{};
110 for (
auto&
byte :
key) {
115 std::array<uint8_t, 16> iv{};
116 for (
auto&
byte : iv) {
134 for (
const auto&
byte : plaintext) {
135 input_witnesses.push_back(make_witness_or_constant(
FF(
byte), IsPlaintextConstant));
140 for (
size_t i = 0; i < 16; ++i) {
141 key_witnesses[i] = make_witness_or_constant(
FF(
key[i]), IsKeyConstant);
146 for (
size_t i = 0; i < 16; ++i) {
147 iv_witnesses[i] = make_witness_or_constant(
FF(iv[i]), IsIVConstant);
151 std::vector<uint32_t> output_indices;
152 for (
const auto&
byte : ciphertext) {
154 output_indices.push_back(witness_idx);
161 .key = key_witnesses,
180 if constexpr (IsPlaintextConstant) {
181 if (!constraint.
inputs.empty()) {
185 if (!constraint.
inputs.empty()) {
186 witness_values[constraint.
inputs[0].index] +=
FF(1);
193 if constexpr (IsKeyConstant) {
196 witness_values[constraint.
key[0].index] +=
FF(1);
202 if constexpr (IsIVConstant) {
205 witness_values[constraint.
iv[0].index] +=
FF(1);
211 if (!constraint.
outputs.empty()) {
212 witness_values[constraint.
outputs[0]] +=
FF(1);
217 return { constraint, witness_values };
228 const std::array<uint8_t, 16>&
key,
229 const std::array<uint8_t, 16>& iv)
232 std::vector<uint8_t>
buffer = plaintext;
235 std::array<uint8_t, 16> iv_copy = iv;
244using BuilderTypes = testing::Types<UltraCircuitBuilder, MegaCircuitBuilder>;
249template <
typename Builder>
251 public TestClass<AES128TestingFunctions<Builder, false, false, false>> {
261 TestFixture::template test_vk_independence<Flavor>();
266 TestFixture::test_tampering();
271template <
typename Builder>
273 public TestClass<AES128TestingFunctions<Builder, true, false, false>> {
283 TestFixture::template test_vk_independence<Flavor>();
288 TestFixture::test_tampering();
294template <
typename Builder>
296 public TestClass<AES128TestingFunctions<Builder, false, true, false>> {
306 TestFixture::template test_vk_independence<Flavor>();
311 TestFixture::test_tampering();
317template <
typename Builder>
319 public TestClass<AES128TestingFunctions<Builder, false, false, true>> {
329 TestFixture::template test_vk_independence<Flavor>();
334 TestFixture::test_tampering();
340template <
typename Builder>
342 public TestClass<AES128TestingFunctions<Builder, true, true, true>> {
352 TestFixture::template test_vk_independence<Flavor>();
357 TestFixture::test_tampering();
376 static constexpr std::array<FF, 16>
valid_plaintext = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
377 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a };
379 static constexpr std::array<FF, 16>
valid_key = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
380 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
382 static constexpr std::array<FF, 16>
valid_iv = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
383 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
390 std::vector<uint8_t>
buffer(16);
391 std::array<uint8_t, 16> key_bytes{};
392 std::array<uint8_t, 16> iv_bytes{};
394 for (
size_t i = 0; i < 16; ++i) {
402 std::array<FF, 16> result{};
403 for (
size_t i = 0; i < 16; ++i) {
418 const std::array<FF, 16>& key_vals,
419 const std::array<FF, 16>& iv_vals,
420 const std::array<FF, 16>& output_vals)
428 for (
const auto& val : plaintext_vals) {
434 for (
size_t i = 0; i < 16; ++i) {
440 for (
size_t i = 0; i < 16; ++i) {
445 std::vector<uint32_t> output_indices;
446 for (
const auto& val : output_vals) {
447 output_indices.push_back(add_witness(val));
453 .key = key_witnesses,
492 std::array<FF, 16> overflowed_plaintext = {};
493 overflowed_plaintext[14] =
FF(1);
494 overflowed_plaintext[15] =
FF(0);
498 std::vector<uint8_t>
buffer(16, 0);
501 std::array<uint8_t, 16> key_bytes{};
502 std::array<uint8_t, 16> iv_bytes{};
503 for (
size_t i = 0; i < 16; ++i) {
504 key_bytes[i] =
static_cast<uint8_t
>(
uint256_t(valid_key[i]));
505 iv_bytes[i] =
static_cast<uint8_t
>(
uint256_t(valid_iv[i]));
509 std::array<FF, 16> overflowed_ciphertext{};
510 for (
size_t i = 0; i < 16; ++i) {
511 overflowed_ciphertext[i] =
FF(
buffer[i]);
518 create_constraint(overflowed_plaintext, valid_key, valid_iv, overflowed_ciphertext);
521 <<
"Sanity check: [..., 1, 0] with correct ciphertext should pass (lookups work)";
526 std::array<FF, 16> attacker_plaintext = {};
527 attacker_plaintext[15] =
FF(256);
531 auto [
builder, constraint] = create_constraint(attacker_plaintext, valid_key, valid_iv, overflowed_ciphertext);
533 EXPECT_TRUE(
builder.failed()) <<
"Circuit should fail when plaintext has byte > 255";
546 std::array<FF, 16> overflowed_key = {};
547 overflowed_key[14] =
FF(1);
548 overflowed_key[15] =
FF(0);
551 std::vector<uint8_t>
buffer(16);
552 std::array<uint8_t, 16> key_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
553 std::array<uint8_t, 16> iv_bytes{};
554 for (
size_t i = 0; i < 16; ++i) {
556 iv_bytes[i] =
static_cast<uint8_t
>(
uint256_t(valid_iv[i]));
560 std::array<FF, 16> overflowed_ciphertext{};
561 for (
size_t i = 0; i < 16; ++i) {
562 overflowed_ciphertext[i] =
FF(
buffer[i]);
568 create_constraint(valid_plaintext, overflowed_key, valid_iv, overflowed_ciphertext);
574 std::array<FF, 16> attacker_key = {};
575 attacker_key[15] =
FF(256);
577 auto [
builder, constraint] = create_constraint(valid_plaintext, attacker_key, valid_iv, overflowed_ciphertext);
579 EXPECT_TRUE(
builder.failed()) <<
"Circuit should fail when key has byte > 255";
591 std::array<FF, 16> overflowed_iv = {};
592 overflowed_iv[14] =
FF(1);
593 overflowed_iv[15] =
FF(0);
596 std::vector<uint8_t>
buffer(16);
597 std::array<uint8_t, 16> key_bytes{};
598 std::array<uint8_t, 16> iv_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
599 for (
size_t i = 0; i < 16; ++i) {
601 key_bytes[i] =
static_cast<uint8_t
>(
uint256_t(valid_key[i]));
605 std::array<FF, 16> overflowed_ciphertext{};
606 for (
size_t i = 0; i < 16; ++i) {
607 overflowed_ciphertext[i] =
FF(
buffer[i]);
613 create_constraint(valid_plaintext, valid_key, overflowed_iv, overflowed_ciphertext);
619 std::array<FF, 16> attacker_iv = {};
620 attacker_iv[15] =
FF(256);
622 auto [
builder, constraint] = create_constraint(valid_plaintext, valid_key, attacker_iv, overflowed_ciphertext);
624 EXPECT_TRUE(
builder.failed()) <<
"Circuit should fail when IV has byte > 255";
638 auto valid_ciphertext = compute_ciphertext();
642 auto [
builder, constraint] = create_constraint(valid_plaintext, valid_key, valid_iv, valid_ciphertext);
649 std::array<FF, 16> attacker_output = valid_ciphertext;
650 uint64_t second_last_byte =
static_cast<uint64_t
>(
uint256_t(valid_ciphertext[14]));
651 uint64_t last_byte =
static_cast<uint64_t
>(
uint256_t(valid_ciphertext[15]));
654 ASSERT_GE(second_last_byte, 1u) <<
"Test requires ciphertext[14] >= 1";
656 attacker_output[14] =
FF(second_last_byte - 1);
657 attacker_output[15] =
FF(last_byte + 256);
659 auto [
builder, constraint] = create_constraint(valid_plaintext, valid_key, valid_iv, attacker_output);
661 EXPECT_TRUE(
builder.failed()) <<
"Circuit should fail when output has byte > 255";
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 void SetUpTestSuite()
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 void SetUpTestSuite()
static void SetUpTestSuite()
static void SetUpTestSuite()
static void SetUpTestSuite()
static void SetUpTestSuite()
static std::vector< std::string > get_labels()
static std::vector< Target > get_all()
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
std::unique_ptr< uint8_t[]> buffer
void aes128_encrypt_buffer_cbc(uint8_t *buffer, uint8_t *iv, const uint8_t *key, const size_t length)
RNG & get_debug_randomness(bool reset, std::uint_fast64_t seed)
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
::testing::Types< UltraCircuitBuilder, MegaCircuitBuilder > BuilderTypes