#[inline(always)]
const fn next_round(mut x: u32) -> u32 {
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
x
}
#[inline(always)]
pub const fn keystream<const LEN: usize>(key: u32) -> [u16; LEN] {
let mut keys = [0u16; LEN];
let mut round_key = key;
let mut i = 0;
while i < LEN & !1 {
round_key = next_round(round_key);
let kb = round_key.to_ne_bytes();
keys[i + 0] = u16::from_ne_bytes([kb[0], kb[1]]);
keys[i + 1] = u16::from_ne_bytes([kb[2], kb[3]]);
i += 2;
}
if LEN % 2 != 0 {
round_key = next_round(round_key);
keys[i] = round_key as u16;
}
keys
}
pub const fn obfuscate<const LEN: usize>(s: &[u16], k: &[u16; LEN]) -> [u16; LEN] {
if s.len() != LEN {
loop { }
}
let mut data = [0u16; LEN];
let mut i = 0usize;
while i < LEN {
data[i] = s[i] ^ k[i];
i += 1;
}
data
}
#[inline(always)]
pub fn deobfuscate<const LEN: usize>(s: &[u16; LEN], k: &[u16; LEN]) -> [u16; LEN] {
let mut buffer = [0u16; LEN];
let mut i = 0;
unsafe {
use ::core::ptr::{read_volatile, write};
let src = s.as_ptr();
let dest = buffer.as_mut_ptr();
#[cfg(target_pointer_width = "64")]
while i < LEN & !3 {
let ct = read_volatile(src.offset(i as isize) as *const [u16; 4]);
let tmp = [
ct[0] ^ k[i + 0],
ct[1] ^ k[i + 1],
ct[2] ^ k[i + 2],
ct[3] ^ k[i + 3],
];
write(dest.offset(i as isize) as *mut [u16; 4], tmp);
i += 4;
}
while i < LEN & !1 {
let ct = read_volatile(src.offset(i as isize) as *const [u16; 2]);
let tmp = [
ct[0] ^ k[i + 0],
ct[1] ^ k[i + 1],
];
write(dest.offset(i as isize) as *mut [u16; 2], tmp);
i += 2;
}
if LEN % 2 != 0 {
let ct = read_volatile(src.offset(i as isize));
write(dest.offset(i as isize), ct ^ k[i]);
}
}
buffer
}
#[test]
fn test_remaining_bytes() {
const STRING: &[u16] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
fn test<const LEN: usize>(key: u32) {
let keys = keystream::<LEN>(key);
let data = obfuscate::<LEN>(&STRING[..LEN], &keys);
let buffer = deobfuscate::<LEN>(&data, &keys);
assert_ne!(&data[..], &STRING[..LEN]);
assert_eq!(&buffer[..], &STRING[..LEN]);
}
test::<8>(0x1111);
test::<9>(0x2222);
test::<10>(0x3333);
test::<11>(0x4444);
test::<12>(0x5555);
test::<13>(0x6666);
test::<14>(0x7777);
test::<15>(0x8888);
test::<16>(0x9999);
}