use crate::Block;
use cipher::{
Array,
array::ArraySize,
consts::{U2, U4},
};
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, Shr};
pub(crate) trait Word:
Sized
+ Copy
+ Default
+ 'static
+ BitAnd<Output = Self>
+ BitAndAssign
+ BitOr<Output = Self>
+ BitOrAssign
+ BitXor<Output = Self>
+ BitXorAssign
+ Not<Output = Self>
+ Shl<u32, Output = Self>
+ Shr<u32, Output = Self>
{
type Blocks: ArraySize;
const ROW_BITS: u32 = (size_of::<Self>() * 2) as u32;
const HALF_ROW: u32 = Self::ROW_BITS / 2;
const QUARTER_ROW: u32 = Self::ROW_BITS / 4;
#[inline(always)]
fn ror_distance(rows: u32, cols: u32) -> u32 {
rows * Self::ROW_BITS + cols * Self::QUARTER_ROW
}
fn ror(self, n: u32) -> Self;
fn uniform_row(b: u8) -> Self;
fn pack_rows(r0: u8, r1: u8, r2: u8, r3: u8) -> Self;
fn byte_repeat(b: u8) -> Self;
fn bitslice(output: &mut [Self], input: &Array<Block, Self::Blocks>);
fn inv_bitslice(input: &[Self]) -> Array<Block, Self::Blocks>;
}
impl Word for u32 {
type Blocks = U2;
#[inline(always)]
fn ror(self, n: u32) -> u32 {
self.rotate_right(n)
}
#[inline(always)]
fn uniform_row(b: u8) -> u32 {
(b as u32) * 0x01010101
}
#[inline(always)]
fn pack_rows(r0: u8, r1: u8, r2: u8, r3: u8) -> u32 {
(r0 as u32) | ((r1 as u32) << 8) | ((r2 as u32) << 16) | ((r3 as u32) << 24)
}
#[inline(always)]
fn byte_repeat(b: u8) -> u32 {
(b as u32) * 0x01010101
}
fn bitslice(output: &mut [u32], input: &Array<Block, U2>) {
debug_assert_eq!(output.len(), 8);
let input0 = input[0].as_slice();
let input1 = input[1].as_slice();
let mut t = [
u32::from_le_bytes(input0[0x00..0x04].try_into().unwrap()),
u32::from_le_bytes(input1[0x00..0x04].try_into().unwrap()),
u32::from_le_bytes(input0[0x04..0x08].try_into().unwrap()),
u32::from_le_bytes(input1[0x04..0x08].try_into().unwrap()),
u32::from_le_bytes(input0[0x08..0x0c].try_into().unwrap()),
u32::from_le_bytes(input1[0x08..0x0c].try_into().unwrap()),
u32::from_le_bytes(input0[0x0c..0x10].try_into().unwrap()),
u32::from_le_bytes(input1[0x0c..0x10].try_into().unwrap()),
];
bitslice_swaps(&mut t);
output[..8].copy_from_slice(&t);
}
fn inv_bitslice(input: &[u32]) -> Array<Block, U2> {
debug_assert_eq!(input.len(), 8);
let mut t = [
input[0], input[1], input[2], input[3], input[4], input[5], input[6], input[7],
];
bitslice_swaps(&mut t);
let mut output = Array::<Block, U2>::default();
output[0][0x00..0x04].copy_from_slice(&t[0].to_le_bytes());
output[0][0x04..0x08].copy_from_slice(&t[2].to_le_bytes());
output[0][0x08..0x0c].copy_from_slice(&t[4].to_le_bytes());
output[0][0x0c..0x10].copy_from_slice(&t[6].to_le_bytes());
output[1][0x00..0x04].copy_from_slice(&t[1].to_le_bytes());
output[1][0x04..0x08].copy_from_slice(&t[3].to_le_bytes());
output[1][0x08..0x0c].copy_from_slice(&t[5].to_le_bytes());
output[1][0x0c..0x10].copy_from_slice(&t[7].to_le_bytes());
output
}
}
#[inline(always)]
const fn double_bits(b: u8) -> u16 {
let x = b as u16;
let x = (x | (x << 4)) & 0x0f0f;
let x = (x | (x << 2)) & 0x3333;
let x = (x | (x << 1)) & 0x5555;
x | (x << 1)
}
impl Word for u64 {
type Blocks = U4;
#[inline(always)]
fn ror(self, n: u32) -> u64 {
self.rotate_right(n)
}
#[inline(always)]
fn uniform_row(b: u8) -> u64 {
(double_bits(b) as u64) * 0x0001_0001_0001_0001
}
#[inline(always)]
fn pack_rows(r0: u8, r1: u8, r2: u8, r3: u8) -> u64 {
(double_bits(r0) as u64)
| ((double_bits(r1) as u64) << 16)
| ((double_bits(r2) as u64) << 32)
| ((double_bits(r3) as u64) << 48)
}
#[inline(always)]
fn byte_repeat(b: u8) -> u64 {
(b as u64) * 0x0101010101010101
}
fn bitslice(output: &mut [u64], input: &Array<Block, U4>) {
debug_assert_eq!(output.len(), 8);
#[rustfmt::skip]
fn read_reordered(input: &[u8]) -> u64 {
(u64::from(input[0x0]) ) |
(u64::from(input[0x1]) << 0x10) |
(u64::from(input[0x2]) << 0x20) |
(u64::from(input[0x3]) << 0x30) |
(u64::from(input[0x8]) << 0x08) |
(u64::from(input[0x9]) << 0x18) |
(u64::from(input[0xa]) << 0x28) |
(u64::from(input[0xb]) << 0x38)
}
let mut t = [
read_reordered(&input[0][0x00..0x0c]),
read_reordered(&input[1][0x00..0x0c]),
read_reordered(&input[2][0x00..0x0c]),
read_reordered(&input[3][0x00..0x0c]),
read_reordered(&input[0][0x04..0x10]),
read_reordered(&input[1][0x04..0x10]),
read_reordered(&input[2][0x04..0x10]),
read_reordered(&input[3][0x04..0x10]),
];
bitslice_swaps(&mut t);
output[..8].copy_from_slice(&t);
}
fn inv_bitslice(input: &[u64]) -> Array<Block, U4> {
debug_assert_eq!(input.len(), 8);
let mut t = [
input[0], input[1], input[2], input[3], input[4], input[5], input[6], input[7],
];
bitslice_swaps(&mut t);
#[rustfmt::skip]
fn write_reordered(columns: u64, output: &mut [u8]) {
output[0x0] = (columns ) as u8;
output[0x1] = (columns >> 0x10) as u8;
output[0x2] = (columns >> 0x20) as u8;
output[0x3] = (columns >> 0x30) as u8;
output[0x8] = (columns >> 0x08) as u8;
output[0x9] = (columns >> 0x18) as u8;
output[0xa] = (columns >> 0x28) as u8;
output[0xb] = (columns >> 0x38) as u8;
}
let mut output = Array::<Block, U4>::default();
write_reordered(t[0], &mut output[0][0x00..0x0c]);
write_reordered(t[4], &mut output[0][0x04..0x10]);
write_reordered(t[1], &mut output[1][0x00..0x0c]);
write_reordered(t[5], &mut output[1][0x04..0x10]);
write_reordered(t[2], &mut output[2][0x00..0x0c]);
write_reordered(t[6], &mut output[2][0x04..0x10]);
write_reordered(t[3], &mut output[3][0x00..0x0c]);
write_reordered(t[7], &mut output[3][0x04..0x10]);
output
}
}
#[inline(always)]
fn bitslice_swaps<W: Word>(t: &mut [W; 8]) {
use super::utils::delta_swap_2;
let [t0, t1, t2, t3, t4, t5, t6, t7] = t;
let m0 = W::byte_repeat(0x55);
delta_swap_2(t1, t0, 1, m0);
delta_swap_2(t3, t2, 1, m0);
delta_swap_2(t5, t4, 1, m0);
delta_swap_2(t7, t6, 1, m0);
let m1 = W::byte_repeat(0x33);
delta_swap_2(t2, t0, 2, m1);
delta_swap_2(t3, t1, 2, m1);
delta_swap_2(t6, t4, 2, m1);
delta_swap_2(t7, t5, 2, m1);
let m2 = W::byte_repeat(0x0f);
delta_swap_2(t4, t0, 4, m2);
delta_swap_2(t5, t1, 4, m2);
delta_swap_2(t6, t2, 4, m2);
delta_swap_2(t7, t3, 4, m2);
}