#![no_std]
pub fn encipher(blocks: &mut [u32], key: &[u32], delta: u32, rounds: usize) {
let n = blocks.len();
if n < 2 {
return;
}
let mut a: u32;
let mut b: u32;
let mut s: u32;
for i in 0..(n / 2) {
a = blocks[i * 2];
b = blocks[(i * 2) + 1];
s = 0;
for _ in 0..rounds {
a = a.wrapping_add((((b << 4) ^ (b >> 5)).wrapping_add(b)) ^
s.wrapping_add(key[(s & 3) as usize]));
s = s.wrapping_add(delta);
b = b.wrapping_add((((a << 4) ^ (a >> 5)).wrapping_add(a)) ^
s.wrapping_add(key[((s >> 11) & 3) as usize]));
}
blocks[i * 2] = a;
blocks[(i * 2) + 1] = b;
}
}
pub fn encipher_pair(aa: &mut u32, bb: &mut u32, key: &[u32], delta: u32, rounds: usize) {
let mut a: u32 = *aa;
let mut b: u32 = *bb;
let mut s: u32 = 0;
for _ in 0..rounds {
a = a.wrapping_add((((b << 4) ^ (b >> 5)).wrapping_add(b)) ^
s.wrapping_add(key[(s & 3) as usize]));
s = s.wrapping_add(delta);
b = b.wrapping_add((((a << 4) ^ (a >> 5)).wrapping_add(a)) ^
s.wrapping_add(key[((s >> 11) & 3) as usize]));
}
*aa = a;
*bb = b;
}
pub fn decipher(blocks: &mut [u32], key: &[u32], delta: u32, rounds: usize) {
let n = blocks.len();
if n < 2 {
return;
}
let mut a: u32;
let mut b: u32;
let mut s: u32;
let sum: u32 = delta.wrapping_mul(rounds as u32);
for i in 0..(n / 2) {
a = blocks[i * 2];
b = blocks[(i * 2) + 1];
s = sum;
for _ in 0..rounds {
b = b.wrapping_sub((((a << 4) ^ (a >> 5)).wrapping_add(a)) ^
s.wrapping_add(key[((s >> 11) & 3) as usize]));
s = s.wrapping_sub(delta);
a = a.wrapping_sub((((b << 4) ^ (b >> 5)).wrapping_add(b)) ^
s.wrapping_add(key[(s & 3) as usize]));
}
blocks[i * 2] = a;
blocks[(i * 2) + 1] = b;
}
}
pub fn decipher_pair(aa: &mut u32, bb: &mut u32, key: &[u32], delta: u32, rounds: usize) {
let mut a: u32 = *aa;
let mut b: u32 = *bb;
let mut s: u32 = delta.wrapping_mul(rounds as u32);
for _ in 0..rounds {
b = b.wrapping_sub((((a << 4) ^ (a >> 5)).wrapping_add(a)) ^
s.wrapping_add(key[((s >> 11) & 3) as usize]));
s = s.wrapping_sub(delta);
a = a.wrapping_sub((((b << 4) ^ (b >> 5)).wrapping_add(b)) ^
s.wrapping_add(key[(s & 3) as usize]));
}
*aa = a;
*bb = b;
}
#[cfg(test)]
mod test {
#[test]
fn simple_test() {
use super::{encipher, decipher};
const DELTA: u32 = 0x9E3779B9;
const ROUNDS: usize = 32;
const KEY: [u32; 4] = [0xDEADBEEF, 0xAAAAAAAA, 0x0CD0CDAA, 0x12345678];
let data_d: [u32; 32] =
[0x90b61054, 0x4f117340, 0x2a192f72, 0xc6d20912, 0xd4a00486, 0x343b1fa9, 0xe7806b43,
0xd80e41e0, 0x81462e8a, 0x5e59805e, 0x7310266c, 0xb5c3f09d, 0xc830c818, 0xff5425ad,
0x5a4f3477, 0xb63eb737, 0x3df4acab, 0x679b76e1, 0x52befb4a, 0x54a6d777, 0xcfb5eb73,
0x83e661e2, 0xcddc1290, 0xe1d3972b, 0x9e9fe877, 0xe021d4c5, 0x69ac7f72, 0x3c3476cd,
0x7bf3ba34, 0x4183fa09, 0xbd82c98a, 0xdc181a43];
let data_e: [u32; 32] =
[0xecaf9488, 0xd768bb69, 0xa6b2a074, 0x6b43c81c, 0x2fefb898, 0xa385f8cc, 0x3a9d7e7a,
0x2461333d, 0x5faffa3e, 0x043fa28b, 0x22e91e81, 0x11b5e618, 0x10d741fe, 0x661f1de6,
0x19b91f26, 0xa3f94e5d, 0xe822918e, 0x62afd15b, 0x14aa9fb4, 0x23237adb, 0xdc64bf3a,
0x6e93102d, 0x2b1b7c24, 0x246e6058, 0x590e37a8, 0x60b51b69, 0x35970d7c, 0x2f247f1d,
0x361bded3, 0x40c6ff4b, 0xb7d1370d, 0x471ebe43];
let mut data: [u32; 32] = data_d.clone();
encipher(&mut data, &KEY, DELTA, ROUNDS);
for i in 0..32 {
assert_eq!(data_e[i], data[i]);
}
decipher(&mut data, &KEY, DELTA, ROUNDS);
for i in 0..32 {
assert_eq!(data_d[i], data[i]);
}
}
#[test]
fn simple_test_pairs() {
use super::{encipher, decipher};
const DELTA: u32 = 0x9E3779B9;
const ROUNDS: usize = 32;
const KEY: [u32; 4] = [0xDEADBEEF, 0xAAAAAAAA, 0x0CD0CDAA, 0x12345678];
let data_d: [u32; 32] =
[0x90b61054, 0x4f117340, 0x2a192f72, 0xc6d20912, 0xd4a00486, 0x343b1fa9, 0xe7806b43,
0xd80e41e0, 0x81462e8a, 0x5e59805e, 0x7310266c, 0xb5c3f09d, 0xc830c818, 0xff5425ad,
0x5a4f3477, 0xb63eb737, 0x3df4acab, 0x679b76e1, 0x52befb4a, 0x54a6d777, 0xcfb5eb73,
0x83e661e2, 0xcddc1290, 0xe1d3972b, 0x9e9fe877, 0xe021d4c5, 0x69ac7f72, 0x3c3476cd,
0x7bf3ba34, 0x4183fa09, 0xbd82c98a, 0xdc181a43];
let data_e: [u32; 32] =
[0xecaf9488, 0xd768bb69, 0xa6b2a074, 0x6b43c81c, 0x2fefb898, 0xa385f8cc, 0x3a9d7e7a,
0x2461333d, 0x5faffa3e, 0x043fa28b, 0x22e91e81, 0x11b5e618, 0x10d741fe, 0x661f1de6,
0x19b91f26, 0xa3f94e5d, 0xe822918e, 0x62afd15b, 0x14aa9fb4, 0x23237adb, 0xdc64bf3a,
0x6e93102d, 0x2b1b7c24, 0x246e6058, 0x590e37a8, 0x60b51b69, 0x35970d7c, 0x2f247f1d,
0x361bded3, 0x40c6ff4b, 0xb7d1370d, 0x471ebe43];
for j in 0..16 {
let a = j * 2;
let b = a + 1;
let mut data: [u32; 2] = [data_d[a], data_d[b]];
encipher(&mut data, &KEY, DELTA, ROUNDS);
assert_eq!(data_e[a], data[0]);
assert_eq!(data_e[b], data[1]);
decipher(&mut data, &KEY, DELTA, ROUNDS);
assert_eq!(data_d[a], data[0]);
assert_eq!(data_d[b], data[1]);
}
}
}