A single AES block.
pub const Block = struct
pub const Block = struct {
const Repr = @Vector(2, u64);
pub const block_length: usize = 16;
/// Internal representation of a block.
repr: Repr,
/// Convert a byte sequence into an internal representation.
pub fn fromBytes(bytes: *const [16]u8) Block {
const repr = mem.bytesToValue(Repr, bytes);
return Block{ .repr = repr };
}
/// Convert the internal representation of a block into a byte sequence.
pub fn toBytes(block: Block) [16]u8 {
return mem.toBytes(block.repr);
}
/// XOR the block with a byte sequence.
pub fn xorBytes(block: Block, bytes: *const [16]u8) [16]u8 {
const x = block.repr ^ fromBytes(bytes).repr;
return mem.toBytes(x);
}
const zero = @Vector(2, u64){ 0, 0 };
/// Encrypt a block with a round key.
pub fn encrypt(block: Block, round_key: Block) Block {
return Block{
.repr = (asm (
\\ mov %[out].16b, %[in].16b
\\ aese %[out].16b, %[zero].16b
\\ aesmc %[out].16b, %[out].16b
: [out] "=&x" (-> Repr),
: [in] "x" (block.repr),
[zero] "x" (zero),
)) ^ round_key.repr,
};
}
/// Encrypt a block with the last round key.
pub fn encryptLast(block: Block, round_key: Block) Block {
return Block{
.repr = (asm (
\\ mov %[out].16b, %[in].16b
\\ aese %[out].16b, %[zero].16b
: [out] "=&x" (-> Repr),
: [in] "x" (block.repr),
[zero] "x" (zero),
)) ^ round_key.repr,
};
}
/// Decrypt a block with a round key.
pub fn decrypt(block: Block, inv_round_key: Block) Block {
return Block{
.repr = (asm (
\\ mov %[out].16b, %[in].16b
\\ aesd %[out].16b, %[zero].16b
\\ aesimc %[out].16b, %[out].16b
: [out] "=&x" (-> Repr),
: [in] "x" (block.repr),
[zero] "x" (zero),
)) ^ inv_round_key.repr,
};
}
/// Decrypt a block with the last round key.
pub fn decryptLast(block: Block, inv_round_key: Block) Block {
return Block{
.repr = (asm (
\\ mov %[out].16b, %[in].16b
\\ aesd %[out].16b, %[zero].16b
: [out] "=&x" (-> Repr),
: [in] "x" (block.repr),
[zero] "x" (zero),
)) ^ inv_round_key.repr,
};
}
/// Apply the bitwise XOR operation to the content of two blocks.
pub fn xorBlocks(block1: Block, block2: Block) Block {
return Block{ .repr = block1.repr ^ block2.repr };
}
/// Apply the bitwise AND operation to the content of two blocks.
pub fn andBlocks(block1: Block, block2: Block) Block {
return Block{ .repr = block1.repr & block2.repr };
}
/// Apply the bitwise OR operation to the content of two blocks.
pub fn orBlocks(block1: Block, block2: Block) Block {
return Block{ .repr = block1.repr | block2.repr };
}
/// Apply the inverse MixColumns operation to a block.
pub fn invMixColumns(block: Block) Block {
return Block{
.repr = asm (
\\ aesimc %[out].16b, %[in].16b
: [out] "=x" (-> Repr),
: [in] "x" (block.repr),
),
};
}
/// Perform operations on multiple blocks in parallel.
pub const parallel = struct {
/// The recommended number of AES encryption/decryption to perform in parallel for the chosen implementation.
pub const optimal_parallel_blocks = 6;
/// Encrypt multiple blocks in parallel, each their own round key.
pub fn encryptParallel(comptime count: usize, blocks: [count]Block, round_keys: [count]Block) [count]Block {
comptime var i = 0;
var out: [count]Block = undefined;
inline while (i < count) : (i += 1) {
out[i] = blocks[i].encrypt(round_keys[i]);
}
return out;
}
/// Decrypt multiple blocks in parallel, each their own round key.
pub fn decryptParallel(comptime count: usize, blocks: [count]Block, round_keys: [count]Block) [count]Block {
comptime var i = 0;
var out: [count]Block = undefined;
inline while (i < count) : (i += 1) {
out[i] = blocks[i].decrypt(round_keys[i]);
}
return out;
}
/// Encrypt multiple blocks in parallel with the same round key.
pub fn encryptWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
comptime var i = 0;
var out: [count]Block = undefined;
inline while (i < count) : (i += 1) {
out[i] = blocks[i].encrypt(round_key);
}
return out;
}
/// Decrypt multiple blocks in parallel with the same round key.
pub fn decryptWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
comptime var i = 0;
var out: [count]Block = undefined;
inline while (i < count) : (i += 1) {
out[i] = blocks[i].decrypt(round_key);
}
return out;
}
/// Encrypt multiple blocks in parallel with the same last round key.
pub fn encryptLastWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
comptime var i = 0;
var out: [count]Block = undefined;
inline while (i < count) : (i += 1) {
out[i] = blocks[i].encryptLast(round_key);
}
return out;
}
/// Decrypt multiple blocks in parallel with the same last round key.
pub fn decryptLastWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
comptime var i = 0;
var out: [count]Block = undefined;
inline while (i < count) : (i += 1) {
out[i] = blocks[i].decryptLast(round_key);
}
return out;
}
};
}