use super::simon_speck_util::{load_le, rotl, rotr, store_le};
#[derive(Clone, Copy)]
struct SpeckParams {
alpha: u32,
beta: u32,
word_bits: u32,
key_words: usize,
rounds: usize,
mask: u64,
}
fn speck_expand(key: &[u8], params: SpeckParams, rk: &mut [u64]) {
let wb = (params.word_bits / 8) as usize;
let mut l = [0u64; 40];
rk[0] = load_le(&key[0..wb]);
for j in 0..params.key_words - 1 {
l[j] = load_le(&key[(j + 1) * wb..(j + 2) * wb]);
}
for i in 0..params.rounds - 1 {
l[i + params.key_words - 1] =
(rk[i].wrapping_add(rotr(l[i], params.alpha, params.word_bits, params.mask))
^ u64::try_from(i).expect("round index fits in u64"))
& params.mask;
rk[i + 1] = (rotl(rk[i], params.beta, params.word_bits, params.mask)
^ l[i + params.key_words - 1])
& params.mask;
}
}
fn speck_enc(block: &mut [u8], rk: &[u64], alpha: u32, beta: u32, n: u32, mask: u64) {
let wb = (n / 8) as usize;
let mut x = load_le(&block[0..wb]);
let mut y = load_le(&block[wb..2 * wb]);
for &k in rk {
x = (rotr(x, alpha, n, mask).wrapping_add(y) ^ k) & mask;
y = (rotl(y, beta, n, mask) ^ x) & mask;
}
store_le(x, &mut block[0..wb]);
store_le(y, &mut block[wb..2 * wb]);
}
fn speck_dec(block: &mut [u8], rk: &[u64], alpha: u32, beta: u32, n: u32, mask: u64) {
let wb = (n / 8) as usize;
let mut x = load_le(&block[0..wb]);
let mut y = load_le(&block[wb..2 * wb]);
for &k in rk.iter().rev() {
y = rotr(y ^ x, beta, n, mask);
x = rotl((x ^ k).wrapping_sub(y) & mask, alpha, n, mask);
}
store_le(x, &mut block[0..wb]);
store_le(y, &mut block[wb..2 * wb]);
}
macro_rules! speck_variant {
($Name:ident, $n:expr, $m:expr, $T:literal, $alpha:expr, $beta:expr, $mask:expr,
$key_len:literal, $blk_len:literal) => {
pub struct $Name {
round_keys: [u64; $T],
}
impl $Name {
pub fn new(key: &[u8; $key_len]) -> Self {
let mut rk = [0u64; $T];
speck_expand(
key,
SpeckParams {
alpha: $alpha,
beta: $beta,
word_bits: $n,
key_words: $m,
rounds: $T,
mask: $mask,
},
&mut rk,
);
Self { round_keys: rk }
}
pub fn new_wiping(key: &mut [u8; $key_len]) -> Self {
let out = Self::new(key);
crate::ct::zeroize_slice(key.as_mut_slice());
out
}
pub fn encrypt_block(&self, block: &[u8; $blk_len]) -> [u8; $blk_len] {
let mut out = *block;
speck_enc(&mut out, &self.round_keys, $alpha, $beta, $n, $mask);
out
}
pub fn decrypt_block(&self, block: &[u8; $blk_len]) -> [u8; $blk_len] {
let mut out = *block;
speck_dec(&mut out, &self.round_keys, $alpha, $beta, $n, $mask);
out
}
}
impl crate::BlockCipher for $Name {
const BLOCK_LEN: usize = $blk_len;
fn encrypt(&self, block: &mut [u8]) {
let arr: &[u8; $blk_len] = (&*block).try_into().expect("wrong block length");
block.copy_from_slice(&self.encrypt_block(arr));
}
fn decrypt(&self, block: &mut [u8]) {
let arr: &[u8; $blk_len] = (&*block).try_into().expect("wrong block length");
block.copy_from_slice(&self.decrypt_block(arr));
}
}
impl Drop for $Name {
fn drop(&mut self) {
crate::ct::zeroize_slice(self.round_keys.as_mut_slice());
}
}
};
}
speck_variant!(Speck32_64, 16, 4, 22, 7, 2, 0xffff_u64, 8, 4);
speck_variant!(Speck48_72, 24, 3, 22, 8, 3, 0xff_ffff_u64, 9, 6);
speck_variant!(Speck48_96, 24, 4, 23, 8, 3, 0xff_ffff_u64, 12, 6);
speck_variant!(Speck64_96, 32, 3, 26, 8, 3, 0xffff_ffff_u64, 12, 8);
speck_variant!(Speck64_128, 32, 4, 27, 8, 3, 0xffff_ffff_u64, 16, 8);
speck_variant!(Speck96_96, 48, 2, 28, 8, 3, 0xffff_ffff_ffff_u64, 12, 12);
speck_variant!(Speck96_144, 48, 3, 29, 8, 3, 0xffff_ffff_ffff_u64, 18, 12);
speck_variant!(Speck128_128, 64, 2, 32, 8, 3, u64::MAX, 16, 16);
speck_variant!(Speck128_192, 64, 3, 33, 8, 3, u64::MAX, 24, 16);
speck_variant!(Speck128_256, 64, 4, 34, 8, 3, u64::MAX, 32, 16);
#[cfg(test)]
mod tests {
use super::*;
fn parse<const N: usize>(s: &str) -> [u8; N] {
let v: Vec<u8> = (0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
.collect();
v.try_into().unwrap()
}
#[test]
fn speck32_64_kat() {
let key: [u8; 8] = parse("0001080910111819");
let pt: [u8; 4] = parse("74654c69");
let ct: [u8; 4] = parse("68a8f242");
let c = Speck32_64::new(&key);
assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
}
#[test]
fn speck48_72_kat() {
let key: [u8; 9] = parse("00010208090a101112");
let pt: [u8; 6] = parse("6c792072616c");
let ct: [u8; 6] = parse("a549c0dc5a38");
let c = Speck48_72::new(&key);
assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
}
#[test]
fn speck48_96_kat() {
let key: [u8; 12] = parse("00010208090a10111218191a");
let pt: [u8; 6] = parse("73206d746869");
let ct: [u8; 6] = parse("105e735d44b6");
let c = Speck48_96::new(&key);
assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
}
#[test]
fn speck64_96_kat() {
let key: [u8; 12] = parse("0001020308090a0b10111213");
let pt: [u8; 8] = parse("2046617465616e73");
let ct: [u8; 8] = parse("ec52799f6c947541");
let c = Speck64_96::new(&key);
assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
}
#[test]
fn speck64_128_kat() {
let key: [u8; 16] = parse("0001020308090a0b1011121318191a1b");
let pt: [u8; 8] = parse("7465723b2d437574");
let ct: [u8; 8] = parse("48a56f8c8b024e45");
let c = Speck64_128::new(&key);
assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
}
#[test]
fn speck96_96_kat() {
let key: [u8; 12] = parse("00010203040508090a0b0c0d");
let pt: [u8; 12] = parse("2c20686f7765207573616765");
let ct: [u8; 12] = parse("7871ab094d9eaa798fdebd62");
let c = Speck96_96::new(&key);
assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
}
#[test]
fn speck96_144_kat() {
let key: [u8; 18] = parse("00010203040508090a0b0c0d101112131415");
let pt: [u8; 12] = parse("6e2074696d657665722c2069");
let ct: [u8; 12] = parse("8a227210f32be62e2540e47a");
let c = Speck96_144::new(&key);
assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
}
#[test]
fn speck128_128_kat() {
let key: [u8; 16] = parse("000102030405060708090a0b0c0d0e0f");
let pt: [u8; 16] = parse("206571756976616c206d616465206974");
let ct: [u8; 16] = parse("6532787951985da6180d575cdffe6078");
let c = Speck128_128::new(&key);
assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
}
#[test]
fn speck128_192_kat() {
let key: [u8; 24] = parse("000102030405060708090a0b0c0d0e0f1011121314151617");
let pt: [u8; 16] = parse("6869656620486172656e7420746f2043");
let ct: [u8; 16] = parse("665513133acfe41b86183ce05d18bcf9");
let c = Speck128_192::new(&key);
assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
}
#[test]
fn speck128_256_kat() {
let key: [u8; 32] =
parse("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
let pt: [u8; 16] = parse("496e2074686f7365706f6f6e65722e20");
let ct: [u8; 16] = parse("3ef5c00504010941438f189c8db4ee4e");
let c = Speck128_256::new(&key);
assert_eq!(c.encrypt_block(&pt), ct, "encrypt");
assert_eq!(c.decrypt_block(&ct), pt, "decrypt");
}
}