use crate::{digest::sha3::{qrc_cshake_initialize, qrc_cshake_squeezeblocks, qrc_cshake_update, qrc_keccak_dispose, QrcKeccakRate, QrcKeccakState, QRC_KECCAK_256_RATE, QRC_KECCAK_512_RATE, QRC_KECCAK_STATE_SIZE}, provider::rcrng::qrc_rcrng_generate, tools::intutils::{qrc_intutils_clear64, qrc_intutils_clear8, qrc_intutils_copy8, qrc_intutils_min}};
use core::{mem::size_of, default::Default};
pub const QRC_CSG_256_SEED_SIZE: usize = 32;
pub const QRC_CSG_512_SEED_SIZE: usize = 64;
pub const QRC_CSG_RESEED_THRESHHOLD: usize = 1024000;
#[derive(PartialEq)]
pub struct QrcCsgState {
pub kstate: QrcKeccakState,
pub cache: [u8; QRC_KECCAK_256_RATE],
pub bctr: usize,
pub cpos: usize,
pub crmd: usize,
pub rate: usize,
pub pres: bool
}
impl Default for QrcCsgState {
fn default() -> Self {
Self {
kstate: QrcKeccakState::default(),
cache: [Default::default(); QRC_KECCAK_256_RATE],
bctr: Default::default(),
cpos: Default::default(),
crmd: Default::default(),
rate: Default::default(),
pres: Default::default(),
}
}
}
pub fn qrc_csg_dispose(ctx: &mut QrcCsgState) {
qrc_keccak_dispose(&mut ctx.kstate);
qrc_intutils_clear8(&mut ctx.cache, QRC_KECCAK_256_RATE);
ctx.bctr = 0;
ctx.cpos = 0;
ctx.crmd = 0;
ctx.rate = 0;
ctx.pres = false;
}
pub fn qrc_csg_initialize(ctx: &mut QrcCsgState, seed: &[u8], seedlen: usize, info: &[u8], infolen: usize, predres: bool) {
if seedlen == QRC_CSG_512_SEED_SIZE {
ctx.rate = QRC_KECCAK_512_RATE;
} else {
ctx.rate = QRC_KECCAK_256_RATE;
}
qrc_intutils_clear8(&mut ctx.cache, QRC_KECCAK_256_RATE);
ctx.bctr = 0;
ctx.cpos = 0;
ctx.pres = predres;
qrc_intutils_clear64(&mut ctx.kstate.state, QRC_KECCAK_STATE_SIZE / size_of::<u64>());
if ctx.rate == QRC_KECCAK_512_RATE {
let rate = QrcKeccakRate::QrcKeccakRate512 as usize;
if ctx.pres {
let prand = &mut [0u8; QRC_CSG_512_SEED_SIZE];
qrc_rcrng_generate(prand, QRC_CSG_512_SEED_SIZE);
qrc_cshake_initialize(&mut ctx.kstate, rate, seed, seedlen, info, infolen, prand, QRC_CSG_512_SEED_SIZE);
} else {
qrc_cshake_initialize(&mut ctx.kstate, rate, seed, seedlen, info, infolen, &[], 0);
}
} else {
let rate = QrcKeccakRate::QrcKeccakRate256 as usize;
if ctx.pres {
let prand = &mut [0u8; QRC_CSG_256_SEED_SIZE];
qrc_rcrng_generate(prand, QRC_CSG_256_SEED_SIZE);
qrc_cshake_initialize(&mut ctx.kstate, rate, seed, seedlen, info, infolen, prand, QRC_CSG_256_SEED_SIZE);
} else {
qrc_cshake_initialize(&mut ctx.kstate, rate, seed, seedlen, info, infolen, &[], 0);
}
}
csg_fill_buffer(ctx);
}
pub fn qrc_csg_generate(ctx: &mut QrcCsgState, output: &mut [u8], mut outlen: usize) {
ctx.bctr += outlen;
if ctx.crmd < outlen {
let mut outpos = 0;
if ctx.crmd != 0 {
qrc_intutils_copy8(output, &ctx.cache[ctx.cpos..], ctx.crmd);
outpos += ctx.crmd;
outlen -= ctx.crmd;
}
loop {
if outlen == 0 {
break
}
csg_fill_buffer(ctx);
let rmdlen = qrc_intutils_min(ctx.crmd, outlen);
qrc_intutils_copy8(&mut output[outpos..], &ctx.cache, rmdlen);
outlen -= rmdlen;
outpos += rmdlen;
ctx.crmd -= rmdlen;
ctx.cpos += rmdlen;
}
} else {
let rmdlen = qrc_intutils_min(ctx.crmd, outlen);
qrc_intutils_copy8(output, &ctx.cache[ctx.cpos..], rmdlen);
ctx.crmd -= rmdlen;
ctx.cpos += rmdlen;
}
if ctx.crmd != 0 {
qrc_intutils_clear8(&mut ctx.cache, QRC_KECCAK_256_RATE);
}
csg_auto_reseed(ctx);
}
pub fn qrc_csg_update(ctx: &mut QrcCsgState, seed: &mut [u8], seedlen: usize) {
if ctx.rate == QRC_KECCAK_512_RATE {
qrc_cshake_update(&mut ctx.kstate, QrcKeccakRate::QrcKeccakRate512 as usize, seed, seedlen);
} else {
qrc_cshake_update(&mut ctx.kstate, QrcKeccakRate::QrcKeccakRate256 as usize, seed, seedlen);
}
csg_fill_buffer(ctx);
}
fn csg_fill_buffer(ctx: &mut QrcCsgState) {
if ctx.rate == QRC_KECCAK_512_RATE {
qrc_cshake_squeezeblocks(&mut ctx.kstate, QrcKeccakRate::QrcKeccakRate512 as usize, &mut ctx.cache, 1);
} else {
qrc_cshake_squeezeblocks(&mut ctx.kstate, QrcKeccakRate::QrcKeccakRate256 as usize, &mut ctx.cache, 1);
}
ctx.crmd = ctx.rate;
ctx.cpos = 0;
}
fn csg_auto_reseed(ctx: &mut QrcCsgState) {
if ctx.pres && ctx.bctr >= QRC_CSG_RESEED_THRESHHOLD {
if ctx.rate == QRC_KECCAK_512_RATE {
let prand = &mut [0u8; QRC_CSG_512_SEED_SIZE];
qrc_rcrng_generate(prand, QRC_CSG_512_SEED_SIZE);
qrc_cshake_update(&mut ctx.kstate, QrcKeccakRate::QrcKeccakRate512 as usize, prand, QRC_CSG_512_SEED_SIZE);
} else {
let prand = &mut [0u8; QRC_CSG_256_SEED_SIZE];
qrc_rcrng_generate(prand, QRC_CSG_256_SEED_SIZE);
qrc_cshake_update(&mut ctx.kstate, QrcKeccakRate::QrcKeccakRate256 as usize, prand, QRC_CSG_256_SEED_SIZE);
}
csg_fill_buffer(ctx);
ctx.bctr = 0;
}
}