A context to perform decryption using the standard AES key schedule.
pub fn AesDecryptCtx(comptime Aes: type) type
pub fn AesDecryptCtx(comptime Aes: type) type {
std.debug.assert(Aes.key_bits == 128 or Aes.key_bits == 256);
const rounds = Aes.rounds;
return struct {
const Self = @This();
pub const block = Aes.block;
pub const block_length = block.block_length;
key_schedule: KeySchedule(Aes),
/// Create a decryption context from an existing encryption context.
pub fn initFromEnc(ctx: AesEncryptCtx(Aes)) Self {
return Self{
.key_schedule = ctx.key_schedule.invert(),
};
}
/// Create a new decryption context with the given key.
pub fn init(key: [Aes.key_bits / 8]u8) Self {
const enc_ctx = AesEncryptCtx(Aes).init(key);
return initFromEnc(enc_ctx);
}
/// Decrypt a single block.
pub fn decrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void {
const inv_round_keys = ctx.key_schedule.round_keys;
var t = Block.fromBytes(src).xorBlocks(inv_round_keys[0]);
comptime var i = 1;
inline while (i < rounds) : (i += 1) {
t = t.decrypt(inv_round_keys[i]);
}
t = t.decryptLast(inv_round_keys[rounds]);
dst.* = t.toBytes();
}
/// Decrypt multiple blocks, possibly leveraging parallelization.
pub fn decryptWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8) void {
const inv_round_keys = ctx.key_schedule.round_keys;
var ts: [count]Block = undefined;
comptime var j = 0;
inline while (j < count) : (j += 1) {
ts[j] = Block.fromBytes(src[j * 16 .. j * 16 + 16][0..16]).xorBlocks(inv_round_keys[0]);
}
comptime var i = 1;
inline while (i < rounds) : (i += 1) {
ts = Block.parallel.decryptWide(count, ts, inv_round_keys[i]);
}
ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]);
j = 0;
inline while (j < count) : (j += 1) {
dst[16 * j .. 16 * j + 16].* = ts[j].toBytes();
}
}
};
}