17#include <gtest/gtest.h>
37template <
typename Builder_,
bool IsPla
intextConstant,
bool IsKeyConstant,
bool IsIVConstant>
57 if constexpr (!IsPlaintextConstant) {
60 if constexpr (!IsKeyConstant) {
63 if constexpr (!IsIVConstant) {
72 std::vector<std::string> labels = {
"None" };
73 if constexpr (!IsPlaintextConstant) {
74 labels.push_back(
"Plaintext");
76 if constexpr (!IsKeyConstant) {
77 labels.push_back(
"Key");
79 if constexpr (!IsIVConstant) {
80 labels.push_back(
"IV");
82 labels.push_back(
"Output");
102 size_t plaintext_size = num_blocks * 16;
104 std::vector<uint8_t> plaintext(plaintext_size);
105 for (
auto&
byte : plaintext) {
110 std::array<uint8_t, 16>
key{};
111 for (
auto&
byte :
key) {
116 std::array<uint8_t, 16> iv{};
117 for (
auto&
byte : iv) {
135 for (
const auto&
byte : plaintext) {
136 input_witnesses.push_back(make_witness_or_constant(
FF(
byte), IsPlaintextConstant));
141 for (
size_t i = 0; i < 16; ++i) {
142 key_witnesses[i] = make_witness_or_constant(
FF(
key[i]), IsKeyConstant);
147 for (
size_t i = 0; i < 16; ++i) {
148 iv_witnesses[i] = make_witness_or_constant(
FF(iv[i]), IsIVConstant);
152 std::vector<uint32_t> output_indices;
153 for (
const auto&
byte : ciphertext) {
155 output_indices.push_back(witness_idx);
162 .key = key_witnesses,
181 if constexpr (IsPlaintextConstant) {
182 if (!constraint.
inputs.empty()) {
186 if (!constraint.
inputs.empty()) {
187 witness_values[constraint.
inputs[0].index] +=
FF(1);
194 if constexpr (IsKeyConstant) {
197 witness_values[constraint.
key[0].index] +=
FF(1);
203 if constexpr (IsIVConstant) {
206 witness_values[constraint.
iv[0].index] +=
FF(1);
212 if (!constraint.
outputs.empty()) {
213 witness_values[constraint.
outputs[0]] +=
FF(1);
218 return { constraint, witness_values };
229 const std::array<uint8_t, 16>&
key,
230 const std::array<uint8_t, 16>& iv)
233 std::vector<uint8_t>
buffer = plaintext;
236 std::array<uint8_t, 16> iv_copy = iv;
245using BuilderTypes = testing::Types<UltraCircuitBuilder, MegaCircuitBuilder>;
250template <
typename Builder>
252 public TestClass<AES128TestingFunctions<Builder, false, false, false>> {
262 TestFixture::template test_vk_independence<Flavor>();
267 TestFixture::test_tampering();
272template <
typename Builder>
274 public TestClass<AES128TestingFunctions<Builder, true, false, false>> {
284 TestFixture::template test_vk_independence<Flavor>();
289 TestFixture::test_tampering();
295template <
typename Builder>
297 public TestClass<AES128TestingFunctions<Builder, false, true, false>> {
307 TestFixture::template test_vk_independence<Flavor>();
312 TestFixture::test_tampering();
318template <
typename Builder>
320 public TestClass<AES128TestingFunctions<Builder, false, false, true>> {
330 TestFixture::template test_vk_independence<Flavor>();
335 TestFixture::test_tampering();
341template <
typename Builder>
343 public TestClass<AES128TestingFunctions<Builder, true, true, true>> {
353 TestFixture::template test_vk_independence<Flavor>();
358 TestFixture::test_tampering();
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 };
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 };
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 };
391 std::vector<uint8_t>
buffer(16);
392 std::array<uint8_t, 16> key_bytes{};
393 std::array<uint8_t, 16> iv_bytes{};
395 for (
size_t i = 0; i < 16; ++i) {
403 std::array<FF, 16> result{};
404 for (
size_t i = 0; i < 16; ++i) {
419 const std::array<FF, 16>& key_vals,
420 const std::array<FF, 16>& iv_vals,
421 const std::array<FF, 16>& output_vals)
429 for (
const auto& val : plaintext_vals) {
435 for (
size_t i = 0; i < 16; ++i) {
441 for (
size_t i = 0; i < 16; ++i) {
446 std::vector<uint32_t> output_indices;
447 for (
const auto& val : output_vals) {
448 output_indices.push_back(add_witness(val));
454 .key = key_witnesses,
493 std::array<FF, 16> overflowed_plaintext = {};
494 overflowed_plaintext[14] =
FF(1);
495 overflowed_plaintext[15] =
FF(0);
499 std::vector<uint8_t>
buffer(16, 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]));
510 std::array<FF, 16> overflowed_ciphertext{};
511 for (
size_t i = 0; i < 16; ++i) {
512 overflowed_ciphertext[i] =
FF(
buffer[i]);
519 create_constraint(overflowed_plaintext, valid_key, valid_iv, overflowed_ciphertext);
522 <<
"Sanity check: [..., 1, 0] with correct ciphertext should pass (lookups work)";
527 std::array<FF, 16> attacker_plaintext = {};
528 attacker_plaintext[15] =
FF(256);
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";
547 std::array<FF, 16> overflowed_key = {};
548 overflowed_key[14] =
FF(1);
549 overflowed_key[15] =
FF(0);
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) {
557 iv_bytes[i] =
static_cast<uint8_t
>(
uint256_t(valid_iv[i]));
561 std::array<FF, 16> overflowed_ciphertext{};
562 for (
size_t i = 0; i < 16; ++i) {
563 overflowed_ciphertext[i] =
FF(
buffer[i]);
569 create_constraint(valid_plaintext, overflowed_key, valid_iv, overflowed_ciphertext);
575 std::array<FF, 16> attacker_key = {};
576 attacker_key[15] =
FF(256);
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";
592 std::array<FF, 16> overflowed_iv = {};
593 overflowed_iv[14] =
FF(1);
594 overflowed_iv[15] =
FF(0);
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) {
602 key_bytes[i] =
static_cast<uint8_t
>(
uint256_t(valid_key[i]));
606 std::array<FF, 16> overflowed_ciphertext{};
607 for (
size_t i = 0; i < 16; ++i) {
608 overflowed_ciphertext[i] =
FF(
buffer[i]);
614 create_constraint(valid_plaintext, valid_key, overflowed_iv, overflowed_ciphertext);
620 std::array<FF, 16> attacker_iv = {};
621 attacker_iv[15] =
FF(256);
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";
639 auto valid_ciphertext = compute_ciphertext();
643 auto [
builder, constraint] = create_constraint(valid_plaintext, valid_key, valid_iv, valid_ciphertext);
650 std::array<FF, 16> attacker_output = valid_ciphertext;
651 uint64_t second_last_byte =
static_cast<uint64_t
>(
uint256_t(valid_ciphertext[14]));
652 uint64_t last_byte =
static_cast<uint64_t
>(
uint256_t(valid_ciphertext[15]));
655 ASSERT_GE(second_last_byte, 1u) <<
"Test requires ciphertext[14] >= 1";
657 attacker_output[14] =
FF(second_last_byte - 1);
658 attacker_output[15] =
FF(last_byte + 256);
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";
690 for (
size_t i = 0; i < num_input_bytes; ++i) {
696 for (
size_t i = 0; i < 16; ++i) {
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)));
709 .key = key_witnesses,
718 auto [
builder, constraint] = make_constraint(17, 17);
724 auto [
builder, constraint] = make_constraint(16, 32);
#define EXPECT_THROW_OR_ABORT(statement, matcher)
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 std::pair< Builder, AES128Constraint > make_constraint(size_t num_input_bytes, size_t num_output_bytes)
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