use crate::{digest::sha2::{qrc_hmac512_blockfinalize, qrc_hmac512_initialize, QrcHmac512State, QRC_HMAC_512_RATE}, provider::rcrng::qrc_rcrng_generate, tools::intutils::{qrc_intutils_be8increment, qrc_intutils_clear8, qrc_intutils_copy8, qrc_intutils_min}};
use core::default::Default;
#[cfg(feature = "no_std")]
use alloc::vec;
pub const QRC_DEFAULT_INFO: [u8; 17] = [ 0x51, 0x53, 0x43, 0x2D, 0x48, 0x43, 0x47, 0x2D, 0x53, 0x48, 0x41, 0x32, 0x35, 0x31, 0x32, 0x00, 0x01 ];
pub const QRC_HCG_CACHE_SIZE: usize = 64;
pub const QRC_HCG_MAX_INFO_SIZE: usize = 56;
pub const QRC_HCG_NONCE_SIZE: usize = 8;
pub const QRC_HCG_RESEED_THRESHHOLD: usize = 1024000;
pub const QRC_HCG_SEED_SIZE: usize = 64;
pub struct QrcHcgState {
pub hstate: QrcHmac512State,
pub cache: [u8; QRC_HCG_CACHE_SIZE],
pub info: [u8; QRC_HCG_MAX_INFO_SIZE],
pub nonce: [u8; QRC_HCG_NONCE_SIZE],
pub bctr: usize,
pub cpos: usize,
pub crmd: usize,
pub pres: bool,
}
impl Default for QrcHcgState {
fn default() -> Self {
Self {
hstate: QrcHmac512State::default(),
cache: [Default::default(); QRC_HCG_CACHE_SIZE],
info: [Default::default(); QRC_HCG_MAX_INFO_SIZE],
nonce: [Default::default(); QRC_HCG_NONCE_SIZE],
bctr: Default::default(),
cpos: Default::default(),
crmd: Default::default(),
pres: Default::default(),
}
}
}
pub fn qrc_hcg_dispose(ctx: &mut QrcHcgState) {
qrc_intutils_clear8(&mut ctx.cache, QRC_HCG_CACHE_SIZE);
ctx.bctr = 0;
ctx.cpos = 0;
ctx.crmd = 0;
ctx.pres = false;
}
pub fn qrc_hcg_initialize(ctx: &mut QrcHcgState, seed: &[u8], seedlen: usize, info: &[u8], infolen: usize, predictive_resistance: bool) {
qrc_intutils_clear8(&mut ctx.cache, QRC_HCG_CACHE_SIZE);
qrc_intutils_clear8(&mut ctx.nonce, QRC_HCG_NONCE_SIZE);
ctx.bctr = 0;
ctx.cpos = 0;
ctx.pres = predictive_resistance;
qrc_hmac512_initialize(&mut ctx.hstate, seed, seedlen);
if infolen != 0 {
let rmdlen = qrc_intutils_min(QRC_HCG_MAX_INFO_SIZE, infolen);
qrc_intutils_copy8(&mut ctx.info, info, rmdlen);
} else {
qrc_intutils_copy8(&mut ctx.info, &QRC_DEFAULT_INFO, 17);
}
let mut prand = vec![0u8; 0];
let mut prand_len = 0;
if ctx.pres {
prand = vec![0u8; QRC_HMAC_512_RATE];
prand_len = QRC_HMAC_512_RATE;
qrc_rcrng_generate(&mut prand, prand_len);
}
qrc_hmac512_blockfinalize(&mut ctx.hstate, &mut ctx.cache, &prand, prand_len);
hcg_fill_buffer(ctx);
}
pub fn qrc_hcg_generate(ctx: &mut QrcHcgState, output: &mut [u8], mut outlen: usize) {
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;
}
while outlen != 0 {
hcg_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;
}
csg_auto_reseed(ctx);
}
pub fn qrc_hcg_update(ctx: &mut QrcHcgState, seed: &[u8], seedlen: usize) {
let hblk = &mut [0u8; QRC_HMAC_512_RATE];
qrc_intutils_copy8(hblk, &ctx.cache, QRC_HCG_CACHE_SIZE);
qrc_intutils_copy8(&mut hblk[QRC_HCG_CACHE_SIZE..], seed, seedlen);
qrc_hmac512_initialize(&mut ctx.hstate, hblk, QRC_HMAC_512_RATE);
}
fn hcg_fill_buffer(ctx: &mut QrcHcgState) {
let hblk = &mut [0u8; QRC_HMAC_512_RATE];
qrc_intutils_copy8(hblk, &ctx.cache, QRC_HCG_CACHE_SIZE);
qrc_intutils_be8increment(&mut ctx.nonce, QRC_HCG_NONCE_SIZE);
qrc_intutils_copy8(&mut hblk[QRC_HCG_CACHE_SIZE..], &ctx.nonce, QRC_HCG_NONCE_SIZE);
qrc_intutils_copy8(&mut hblk[QRC_HCG_CACHE_SIZE + QRC_HCG_NONCE_SIZE..], &ctx.info, QRC_HCG_MAX_INFO_SIZE);
qrc_hmac512_blockfinalize(&mut ctx.hstate, &mut ctx.cache, hblk, QRC_HMAC_512_RATE);
ctx.crmd = QRC_HCG_CACHE_SIZE;
ctx.cpos = 0;
}
fn csg_auto_reseed(ctx: &mut QrcHcgState) {
if ctx.pres && ctx.bctr >= QRC_HCG_RESEED_THRESHHOLD {
let prand = &mut [0u8; QRC_HMAC_512_RATE];
qrc_rcrng_generate(prand, QRC_HMAC_512_RATE);
qrc_hcg_update(ctx, prand, QRC_HMAC_512_RATE);
hcg_fill_buffer(ctx);
ctx.bctr = 0;
}
}