use crate::tools::intutils::{qrc_intutils_clear32, qrc_intutils_copy8, qrc_intutils_le32to8, qrc_intutils_le8to32, qrc_intutils_rotl32, qrc_intutils_xor};
use core::default::Default;
#[cfg(feature = "no_std")]
use alloc::vec::Vec;
pub const QRC_CHACHA_BLOCK_SIZE: usize = 64;
pub const QRC_CHACHA_KEY128_SIZE: usize = 16;
pub const QRC_CHACHA_KEY256_SIZE: usize = 32;
pub const QRC_CHACHA_NONCE_SIZE: usize = 8;
pub const QRC_CHACHA_ROUND_COUNT: usize = 20;
#[derive(Clone)]
pub struct QrcChachaState {
pub state: [u32; 16],
}
impl Default for QrcChachaState{
fn default() -> Self {
Self {
state: [Default::default(); 16],
}
}
}
#[derive(Clone)]
pub struct QrcChachaKeyparams {
pub key: Vec<u8>,
pub keylen: usize,
pub nonce: Vec<u8>,
}
impl Default for QrcChachaKeyparams{
fn default() -> Self {
Self {
key: Default::default(),
keylen: Default::default(),
nonce: Default::default(),
}
}
}
pub fn qrc_chacha_dispose(ctx: &mut QrcChachaState) {
qrc_intutils_clear32(&mut ctx.state, 16);
}
pub fn qrc_chacha_initialize(ctx: &mut QrcChachaState, keyparams: QrcChachaKeyparams) {
if keyparams.keylen == 32 {
ctx.state[0] = 0x61707865;
ctx.state[1] = 0x3320646E;
ctx.state[2] = 0x79622D32;
ctx.state[3] = 0x6B206574;
ctx.state[4] = qrc_intutils_le8to32(&keyparams.key);
ctx.state[5] = qrc_intutils_le8to32(&keyparams.key[4..]);
ctx.state[6] = qrc_intutils_le8to32(&keyparams.key[8..]);
ctx.state[7] = qrc_intutils_le8to32(&keyparams.key[12..]);
ctx.state[8] = qrc_intutils_le8to32(&keyparams.key[16..]);
ctx.state[9] = qrc_intutils_le8to32(&keyparams.key[20..]);
ctx.state[10] = qrc_intutils_le8to32(&keyparams.key[24..]);
ctx.state[11] = qrc_intutils_le8to32(&keyparams.key[28..]);
ctx.state[12] = 0;
ctx.state[13] = 0;
ctx.state[14] = qrc_intutils_le8to32(&keyparams.nonce);
ctx.state[15] = qrc_intutils_le8to32(&keyparams.nonce[4..]);
} else {
ctx.state[0] = 0x61707865;
ctx.state[1] = 0x3120646E;
ctx.state[2] = 0x79622D36;
ctx.state[3] = 0x6B206574;
ctx.state[4] = qrc_intutils_le8to32(&keyparams.key[0..]);
ctx.state[5] = qrc_intutils_le8to32(&keyparams.key[4..]);
ctx.state[6] = qrc_intutils_le8to32(&keyparams.key[8..]);
ctx.state[7] = qrc_intutils_le8to32(&keyparams.key[12..]);
ctx.state[8] = qrc_intutils_le8to32(&keyparams.key[0..]);
ctx.state[9] = qrc_intutils_le8to32(&keyparams.key[4..]);
ctx.state[10] = qrc_intutils_le8to32(&keyparams.key[8..]);
ctx.state[11] = qrc_intutils_le8to32(&keyparams.key[12..]);
ctx.state[12] = 0;
ctx.state[13] = 0;
ctx.state[14] = qrc_intutils_le8to32(&keyparams.nonce);
ctx.state[15] = qrc_intutils_le8to32(&keyparams.nonce[4..]);
}
}
pub fn qrc_chacha_transform(ctx: &mut QrcChachaState, output: &mut [u8], input: &[u8], mut length: usize) {
let mut oft = 0;
if length != 0 {
while length >= QRC_CHACHA_BLOCK_SIZE {
chacha_permute_p512c(ctx.clone(), &mut output[oft..]);
chacha_increment(ctx);
qrc_intutils_xor(&mut output[oft..], &input[oft..], QRC_CHACHA_BLOCK_SIZE);
oft += QRC_CHACHA_BLOCK_SIZE;
length -= QRC_CHACHA_BLOCK_SIZE;
}
if length != 0 {
let tmp = &mut [0u8; QRC_CHACHA_BLOCK_SIZE];
chacha_permute_p512c(ctx.clone(), tmp);
chacha_increment(ctx);
qrc_intutils_copy8(&mut output[oft..], tmp, length);
for i in oft..oft + length {
output[i] ^= input[i];
}
}
}
}
fn chacha_increment(ctx: &mut QrcChachaState) {
ctx.state[12] = ctx.state[12].wrapping_add(1);
if ctx.state[12] == 0 {
ctx.state[13] = ctx.state[13].wrapping_add(1);
}
}
fn chacha_permute_p512c(ctx: QrcChachaState, output: &mut [u8]) {
let mut x0 = ctx.state[0];
let mut x1 = ctx.state[1];
let mut x2 = ctx.state[2];
let mut x3 = ctx.state[3];
let mut x4 = ctx.state[4];
let mut x5 = ctx.state[5];
let mut x6 = ctx.state[6];
let mut x7 = ctx.state[7];
let mut x8 = ctx.state[8];
let mut x9 = ctx.state[9];
let mut x10 = ctx.state[10];
let mut x11 = ctx.state[11];
let mut x12 = ctx.state[12];
let mut x13 = ctx.state[13];
let mut x14 = ctx.state[14];
let mut x15 = ctx.state[15];
let mut ctr = QRC_CHACHA_ROUND_COUNT;
while ctr != 0 {
x0 = x0.wrapping_add(x4);
x12 = qrc_intutils_rotl32(x12 ^ x0, 16);
x8 = x8.wrapping_add(x12);
x4 = qrc_intutils_rotl32(x4 ^ x8, 12);
x0 = x0.wrapping_add(x4);
x12 = qrc_intutils_rotl32(x12 ^ x0, 8);
x8 = x8.wrapping_add(x12);
x4 = qrc_intutils_rotl32(x4 ^ x8, 7);
x1 = x1.wrapping_add(x5);
x13 = qrc_intutils_rotl32(x13 ^ x1, 16);
x9 = x9.wrapping_add(x13);
x5 = qrc_intutils_rotl32(x5 ^ x9, 12);
x1 = x1.wrapping_add(x5);
x13 = qrc_intutils_rotl32(x13 ^ x1, 8);
x9 = x9.wrapping_add(x13);
x5 = qrc_intutils_rotl32(x5 ^ x9, 7);
x2 = x2.wrapping_add(x6);
x14 = qrc_intutils_rotl32(x14 ^ x2, 16);
x10 = x10.wrapping_add(x14);
x6 = qrc_intutils_rotl32(x6 ^ x10, 12);
x2 = x2.wrapping_add(x6);
x14 = qrc_intutils_rotl32(x14 ^ x2, 8);
x10 = x10.wrapping_add(x14);
x6 = qrc_intutils_rotl32(x6 ^ x10, 7);
x3 = x3.wrapping_add(x7);
x15 = qrc_intutils_rotl32(x15 ^ x3, 16);
x11 = x11.wrapping_add(x15);
x7 = qrc_intutils_rotl32(x7 ^ x11, 12);
x3 = x3.wrapping_add(x7);
x15 = qrc_intutils_rotl32(x15 ^ x3, 8);
x11 = x11.wrapping_add(x15);
x7 = qrc_intutils_rotl32(x7 ^ x11, 7);
x0 = x0.wrapping_add(x5);
x15 = qrc_intutils_rotl32(x15 ^ x0, 16);
x10 = x10.wrapping_add(x15);
x5 = qrc_intutils_rotl32(x5 ^ x10, 12);
x0 = x0.wrapping_add(x5);
x15 = qrc_intutils_rotl32(x15 ^ x0, 8);
x10 = x10.wrapping_add(x15);
x5 = qrc_intutils_rotl32(x5 ^ x10, 7);
x1 = x1.wrapping_add(x6);
x12 = qrc_intutils_rotl32(x12 ^ x1, 16);
x11 = x11.wrapping_add(x12);
x6 = qrc_intutils_rotl32(x6 ^ x11, 12);
x1 = x1.wrapping_add(x6);
x12 = qrc_intutils_rotl32(x12 ^ x1, 8);
x11 = x11.wrapping_add(x12);
x6 = qrc_intutils_rotl32(x6 ^ x11, 7);
x2 = x2.wrapping_add(x7);
x13 = qrc_intutils_rotl32(x13 ^ x2, 16);
x8 = x8.wrapping_add(x13);
x7 = qrc_intutils_rotl32(x7 ^ x8, 12);
x2 = x2.wrapping_add(x7);
x13 = qrc_intutils_rotl32(x13 ^ x2, 8);
x8 = x8.wrapping_add(x13);
x7 = qrc_intutils_rotl32(x7 ^ x8, 7);
x3 = x3.wrapping_add(x4);
x14 = qrc_intutils_rotl32(x14 ^ x3, 16);
x9 = x9.wrapping_add(x14);
x4 = qrc_intutils_rotl32(x4 ^ x9, 12);
x3 = x3.wrapping_add(x4);
x14 = qrc_intutils_rotl32(x14 ^ x3, 8);
x9 = x9.wrapping_add(x14);
x4 = qrc_intutils_rotl32(x4 ^ x9, 7);
ctr -= 2;
}
qrc_intutils_le32to8(output, x0.wrapping_add(ctx.state[0]));
qrc_intutils_le32to8(&mut output[4..], x1.wrapping_add(ctx.state[1]));
qrc_intutils_le32to8(&mut output[8..], x2.wrapping_add(ctx.state[2]));
qrc_intutils_le32to8(&mut output[12..], x3.wrapping_add(ctx.state[3]));
qrc_intutils_le32to8(&mut output[16..], x4.wrapping_add(ctx.state[4]));
qrc_intutils_le32to8(&mut output[20..], x5.wrapping_add(ctx.state[5]));
qrc_intutils_le32to8(&mut output[24..], x6.wrapping_add(ctx.state[6]));
qrc_intutils_le32to8(&mut output[28..], x7.wrapping_add(ctx.state[7]));
qrc_intutils_le32to8(&mut output[32..], x8.wrapping_add(ctx.state[8]));
qrc_intutils_le32to8(&mut output[36..], x9.wrapping_add(ctx.state[9]));
qrc_intutils_le32to8(&mut output[40..], x10.wrapping_add(ctx.state[10]));
qrc_intutils_le32to8(&mut output[44..], x11.wrapping_add(ctx.state[11]));
qrc_intutils_le32to8(&mut output[48..], x12.wrapping_add(ctx.state[12]));
qrc_intutils_le32to8(&mut output[52..], x13.wrapping_add(ctx.state[13]));
qrc_intutils_le32to8(&mut output[56..], x14.wrapping_add(ctx.state[14]));
qrc_intutils_le32to8(&mut output[60..], x15.wrapping_add(ctx.state[15]));
}