40template <
typename Builder>
44 auto block_data_copy = block_data;
51 for (
size_t i = 0; i < 16; ++i) {
52 sparse_bytes[15 - i] = lookup[ColumnIdx::C2][i];
61 uint64_t sparse_byte =
uint256_t(sparse_bytes[i].get_value()).
data[0];
62 uint256_t byte = numeric::map_from_sparse_form<AES128_BASE>(sparse_byte);
64 accumulator += (byte);
72 sparse_bytes[
BLOCK_SIZE - 1 - i].assert_equal(lookup[ColumnIdx::C2][i]);
108template <
typename Builder>
115 0x20, 0x40, 0x80, 0x1b, 0x36 };
116 const auto sparse_round_constants = [&]() {
118 for (
size_t i = 0; i < 11; ++i) {
119 result[i] =
field_t<Builder>(ctx,
fr(numeric::map_into_sparse_form<AES128_BASE>(round_constants[i])));
136 for (
size_t i = 0; i < 16; ++i) {
137 round_key[i] = sparse_key[i];
141 for (
size_t i = 4; i < 44; ++i) {
142 size_t k = (i - 1) * 4;
144 temp_add_counts[0] = add_counts[k + 0];
145 temp_add_counts[1] = add_counts[k + 1];
146 temp_add_counts[2] = add_counts[k + 2];
147 temp_add_counts[3] = add_counts[k + 3];
149 temp[0] = round_key[k];
150 temp[1] = round_key[k + 1];
151 temp[2] = round_key[k + 2];
152 temp[3] = round_key[k + 3];
155 if ((i & 0x03) == 0) {
157 const auto t = temp[0];
171 temp[0] = temp[0] + sparse_round_constants[i >> 2];
172 ++temp_add_counts[0];
179 round_key[j] = round_key[k] + temp[0];
180 round_key[j + 1] = round_key[k + 1] + temp[1];
181 round_key[j + 2] = round_key[k + 2] + temp[2];
182 round_key[j + 3] = round_key[k + 3] + temp[3];
184 add_counts[j] = add_counts[k] + temp_add_counts[0];
185 add_counts[j + 1] = add_counts[k + 1] + temp_add_counts[1];
186 add_counts[j + 2] = add_counts[k + 2] + temp_add_counts[2];
187 add_counts[j + 3] = add_counts[k + 3] + temp_add_counts[3];
190 constexpr uint64_t target = 3;
191 for (
size_t k = 0; k < 4; ++k) {
194 size_t byte_index = j + k;
195 if (add_counts[byte_index] > target || (add_counts[byte_index] > 1 && (byte_index & 12) == 12)) {
198 add_counts[byte_index] = 1;
218 state[9] = state[13];
222 state[2] = state[10];
225 state[6] = state[14];
229 state[3] = state[15];
230 state[15] = state[11];
231 state[11] = state[7];
265template <
typename Builder>
273 auto t0 = column_pairs[0].first.add_two(column_pairs[3].first, column_pairs[1].second);
275 auto t1 = column_pairs[1].first.add_two(column_pairs[2].first, column_pairs[3].second);
278 auto r0 = t0.add_two(column_pairs[2].first, column_pairs[0].second);
280 auto r1 = t0.add_two(column_pairs[1].first, column_pairs[2].second);
282 auto r2 = t1.add_two(column_pairs[0].first, column_pairs[2].second);
284 auto r3 = t1.add_two(column_pairs[0].second, column_pairs[3].first);
290 column_pairs[0].first = r0 + round_key[key_offset];
291 column_pairs[1].first = r1 + round_key[key_offset + 1];
292 column_pairs[2].first = r2 + round_key[key_offset + 2];
293 column_pairs[3].first = r3 + round_key[key_offset + 3];
296template <
typename Builder>
299 mix_column_and_add_round_key<Builder>(state_pairs.template subspan<0, COLUMN_SIZE>(), round_key, round, 0);
300 mix_column_and_add_round_key<Builder>(state_pairs.template subspan<4, COLUMN_SIZE>(), round_key, round, 1);
301 mix_column_and_add_round_key<Builder>(state_pairs.template subspan<8, COLUMN_SIZE>(), round_key, round, 2);
302 mix_column_and_add_round_key<Builder>(state_pairs.template subspan<12, COLUMN_SIZE>(), round_key, round, 3);
312template <
typename Builder>
318 sparse_state[i + j].first += sparse_round_key[key_offset + i + j];
326 state[i].first += iv[i];
330template <
typename Builder>
333 add_round_key<Builder>(state, sparse_round_key, 0);
338 for (
size_t round = 1; round <
NUM_ROUNDS; ++round) {
340 shift_rows<Builder>(state);
341 mix_columns_and_add_round_key<Builder>(state, sparse_round_key, round);
348 shift_rows<Builder>(state);
349 add_round_key<Builder>(state, sparse_round_key,
NUM_ROUNDS);
352template <
typename Builder>
359 for (
const auto& input_block : input) {
360 if (!input_block.is_constant()) {
361 all_constants =
false;
369 std::vector<uint8_t> key_bytes(16);
370 std::vector<uint8_t> iv_bytes(16);
371 std::vector<uint8_t> input_bytes(input.size() * 16);
375 for (
size_t i = 0; i < 16; ++i) {
376 key_bytes[15 - i] =
static_cast<uint8_t
>((key_value >> (i * 8)) & 0xFF);
381 for (
size_t i = 0; i < 16; ++i) {
382 iv_bytes[15 - i] =
static_cast<uint8_t
>((iv_value >> (i * 8)) & 0xFF);
386 for (
size_t block_idx = 0; block_idx < input.size(); ++block_idx) {
387 uint256_t block_value = input[block_idx].get_value();
388 for (
size_t i = 0; i < 16; ++i) {
389 input_bytes[block_idx * 16 + 15 - i] =
static_cast<uint8_t
>((block_value >> (i * 8)) & 0xFF);
397 for (
size_t block_idx = 0; block_idx < input.size(); ++block_idx) {
399 for (
size_t i = 0; i < 16; ++i) {
401 result_value += input_bytes[block_idx * 16 + i];
411 if (!
key.is_constant()) {
412 ctx =
key.get_context();
416 for (
const auto& input_block : input) {
417 if (!input_block.is_constant()) {
418 ctx = input_block.get_context();
429 const size_t num_blocks = input.size();
432 for (
size_t i = 0; i < num_blocks; ++i) {
434 for (
const auto&
byte : bytes) {
435 sparse_state.push_back({ byte,
field_t(ctx,
fr(0)) });
442 for (
size_t i = 0; i < num_blocks; ++i) {
444 xor_with_iv<Builder>(round_state, sparse_iv_span);
448 sparse_iv[j] = round_state[j].first;
453 for (
auto&
element : sparse_state) {
458 for (
size_t i = 0; i < num_blocks; ++i) {
465#define INSTANTIATE_AES128_TEMPLATES(Builder) \
466 template std::vector<field_t<Builder>> encrypt_buffer_cbc<Builder>( \
467 const std::vector<field_t<Builder>>&, const field_t<Builder>&, const field_t<Builder>&); \
468 template std::array<field_t<Builder>, BLOCK_SIZE> convert_into_sparse_bytes<Builder>(Builder*, \
469 const field_t<Builder>&); \
470 template field_t<Builder> convert_from_sparse_bytes<Builder>(Builder*, std::span<field_t<Builder>, BLOCK_SIZE>)
#define BB_ASSERT(expression,...)
Builder * get_context() const
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
void convert_constant_to_fixed_witness(Builder *ctx)
static plookup::ReadData< field_pt > get_lookup_accumulators(const plookup::MultiTableId id, const field_pt &key_a, const field_pt &key_b=0, const bool is_2_to_1_lookup=false)
static field_pt read_from_1_to_2_table(const plookup::MultiTableId id, const field_pt &key_a)
static std::pair< field_pt, field_pt > read_pair_from_table(const plookup::MultiTableId id, const field_pt &key)
void aes128_encrypt_buffer_cbc(uint8_t *buffer, uint8_t *iv, const uint8_t *key, const size_t length)
byte_pair< Builder > apply_aes_sbox_map(Builder *, field_t< Builder > &input)
std::span< byte_pair< Builder >, COLUMN_SIZE > column_span
constexpr size_t NUM_ROUNDS
field_t< Builder > normalize_sparse_form(Builder *, field_t< Builder > &byte)
void sub_bytes(Builder *ctx, state_span< Builder > state_pairs)
constexpr size_t BLOCK_SIZE
std::array< field_t< Builder >, 16 > convert_into_sparse_bytes(Builder *ctx, const field_t< Builder > &block_data)
Converts a 128-bit block into 16 sparse-form bytes via AES_INPUT plookup table.
field_t< Builder > convert_from_sparse_bytes(Builder *ctx, block_span< Builder > sparse_bytes)
std::pair< field_t< Builder >, field_t< Builder > > byte_pair
constexpr size_t COLUMN_SIZE
std::span< field_t< Builder >, EXTENDED_KEY_LENGTH > key_span
std::array< field_t< Builder >, EXTENDED_KEY_LENGTH > expand_key(Builder *ctx, const field_t< Builder > &key)
Expands a 128-bit AES key into the full key schedule (EXTENDED_KEY_LENGTH bytes / 11 round keys).
void mix_column_and_add_round_key(column_span< Builder > column_pairs, key_span< Builder > round_key, size_t round, size_t column)
Performs MixColumns on a single column and adds the round key (FIPS 197, Sections 5....
constexpr size_t EXTENDED_KEY_LENGTH
void shift_rows(state_span< Builder > state)
The SHIFTROW() operation as in FIPS 197, Section 5.1.2.
std::span< field_t< Builder >, BLOCK_SIZE > block_span
void add_round_key(state_span< Builder > sparse_state, key_span< Builder > sparse_round_key, size_t round)
void xor_with_iv(state_span< Builder > state, block_span< Builder > iv)
std::vector< field_t< Builder > > encrypt_buffer_cbc(const std::vector< field_t< Builder > > &input, const field_t< Builder > &iv, const field_t< Builder > &key)
Main public interface: AES-128 CBC encryption.
void aes128_cipher(Builder *ctx, state_span< Builder > state, key_span< Builder > sparse_round_key)
void mix_columns_and_add_round_key(state_span< Builder > state_pairs, key_span< Builder > round_key, size_t round)
std::span< byte_pair< Builder >, BLOCK_SIZE > state_span
std::conditional_t< IsGoblinBigGroup< C, Fq, Fr, G >, element_goblin::goblin_element< C, goblin_field< C >, Fr, G >, element_default::element< C, Fq, Fr, G > > element
element wraps either element_default::element or element_goblin::goblin_element depending on parametr...
field< Bn254FrParams > fr
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
#define INSTANTIATE_AES128_TEMPLATES(Builder)