mod key;
pub use self::key::Key;
#[inline]
pub fn chacha20_block(key: &Key, nonce: &[u32], block_count: u32) -> Vec<u32> {
assert_eq!(nonce.len(), 3);
let mut state = setup_state(key, nonce, block_count);
let working_state = rot20(&state);
for (i, working) in working_state.iter().enumerate() {
state[i] = state[i].wrapping_add(*working);
}
state
}
#[inline]
pub fn setup_state(key: &Key, nonce: &[u32], block_count: u32) -> Vec<u32> {
let mut state: Vec<u32> = Vec::with_capacity(16);
state.push(0x61707865_u32);
state.push(0x3320646e_u32);
state.push(0x79622d32_u32);
state.push(0x6b206574_u32);
state.extend_from_slice(key.key());
state.push(block_count);
state.extend_from_slice(nonce);
state
}
#[inline]
pub fn rot20(state: &Vec<u32>) -> Vec<u32> {
let mut working_state = state.clone();
for _ in 0..10 {
qround(&mut working_state, 0, 4, 8, 12);
qround(&mut working_state, 1, 5, 9, 13);
qround(&mut working_state, 2, 6, 10, 14);
qround(&mut working_state, 3, 7, 11, 15);
qround(&mut working_state, 0, 5, 10, 15);
qround(&mut working_state, 1, 6, 11, 12);
qround(&mut working_state, 2, 7, 8, 13);
qround(&mut working_state, 3, 4, 9, 14);
}
working_state
}
pub fn qround(state: &mut Vec<u32>, a: u16, b: u16, c: u16, d: u16) {
let a = a as usize;
let b = b as usize;
let c = c as usize;
let d = d as usize;
let (a_res, b_res, c_res, d_res) =
quarter_round(state[a], state[b], state[c], state[d]);
state[a] = a_res;
state[b] = b_res;
state[c] = c_res;
state[d] = d_res;
}
#[inline]
pub fn quarter_round(
mut a: u32,
mut b: u32,
mut c: u32,
mut d: u32,
) -> (u32, u32, u32, u32) {
a = a.wrapping_add(b);
d ^= a;
d = d.rotate_left(16);
c = c.wrapping_add(d);
b ^= c;
b = b.rotate_left(12);
a = a.wrapping_add(b);
d ^= a;
d = d.rotate_left(8);
c = c.wrapping_add(d);
b ^= c;
b = b.rotate_left(7);
(a, b, c, d)
}