A fixed-size vector of AES blocks. All operations are performed in parallel, using SIMD instructions when available.
pub fn BlockVec(comptime blocks_count: comptime_int) type
pub fn BlockVec(comptime blocks_count: comptime_int) type {
return struct {
const Self = @This();
/// The number of AES blocks the target architecture can process with a single instruction.
pub const native_vector_size = 1;
/// The size of the AES block vector that the target architecture can process with a single instruction, in bytes.
pub const native_word_size = native_vector_size * 16;
const native_words = blocks_count;
/// Internal representation of a block vector.
repr: [native_words]Block,
/// Length of the block vector in bytes.
pub const block_length: usize = blocks_count * 16;
/// Convert a byte sequence into an internal representation.
pub fn fromBytes(bytes: *const [blocks_count * 16]u8) Self {
var out: Self = undefined;
for (0..native_words) |i| {
out.repr[i] = Block.fromBytes(bytes[i * native_word_size ..][0..native_word_size]);
}
return out;
}
/// Convert the internal representation of a block vector into a byte sequence.
pub fn toBytes(block_vec: Self) [blocks_count * 16]u8 {
var out: [blocks_count * 16]u8 = undefined;
for (0..native_words) |i| {
out[i * native_word_size ..][0..native_word_size].* = block_vec.repr[i].toBytes();
}
return out;
}
/// XOR the block vector with a byte sequence.
pub fn xorBytes(block_vec: Self, bytes: *const [blocks_count * 16]u8) [blocks_count * 16]u8 {
var out: [blocks_count * 16]u8 = undefined;
for (0..native_words) |i| {
out[i * native_word_size ..][0..native_word_size].* = block_vec.repr[i].xorBytes(bytes[i * native_word_size ..][0..native_word_size]);
}
return out;
}
/// Apply the forward AES operation to the block vector with a vector of round keys.
pub fn encrypt(block_vec: Self, round_key_vec: Self) Self {
var out: Self = undefined;
for (0..native_words) |i| {
out.repr[i] = block_vec.repr[i].encrypt(round_key_vec.repr[i]);
}
return out;
}
/// Apply the forward AES operation to the block vector with a vector of last round keys.
pub fn encryptLast(block_vec: Self, round_key_vec: Self) Self {
var out: Self = undefined;
for (0..native_words) |i| {
out.repr[i] = block_vec.repr[i].encryptLast(round_key_vec.repr[i]);
}
return out;
}
/// Apply the inverse AES operation to the block vector with a vector of round keys.
pub fn decrypt(block_vec: Self, inv_round_key_vec: Self) Self {
var out: Self = undefined;
for (0..native_words) |i| {
out.repr[i] = block_vec.repr[i].decrypt(inv_round_key_vec.repr[i]);
}
return out;
}
/// Apply the inverse AES operation to the block vector with a vector of last round keys.
pub fn decryptLast(block_vec: Self, inv_round_key_vec: Self) Self {
var out: Self = undefined;
for (0..native_words) |i| {
out.repr[i] = block_vec.repr[i].decryptLast(inv_round_key_vec.repr[i]);
}
return out;
}
/// Apply the bitwise XOR operation to the content of two block vectors.
pub fn xorBlocks(block_vec1: Self, block_vec2: Self) Self {
var out: Self = undefined;
for (0..native_words) |i| {
out.repr[i] = block_vec1.repr[i].xorBlocks(block_vec2.repr[i]);
}
return out;
}
/// Apply the bitwise AND operation to the content of two block vectors.
pub fn andBlocks(block_vec1: Self, block_vec2: Self) Self {
var out: Self = undefined;
for (0..native_words) |i| {
out.repr[i] = block_vec1.repr[i].andBlocks(block_vec2.repr[i]);
}
return out;
}
/// Apply the bitwise OR operation to the content of two block vectors.
pub fn orBlocks(block_vec1: Self, block_vec2: Self) Self {
var out: Self = undefined;
for (0..native_words) |i| {
out.repr[i] = block_vec1.repr[i].orBlocks(block_vec2.repr[i]);
}
return out;
}
/// Apply the inverse MixColumns operation to each block in the vector.
pub fn invMixColumns(block_vec: Self) Self {
var out: Self = undefined;
for (0..native_words) |i| {
out.repr[i] = block_vec.repr[i].invMixColumns();
}
return out;
}
};
}