use crypto_bigint::{
CtEq,
CtLt,
U256,
U512,
};
use lib_q_sha3::{
ExtendableOutput,
Update,
XofReader,
};
use crate::error::PrfError;
pub fn shake256_to_field_u256(seed: &[u8], label: &[u8], p: &U256) -> Result<U256, PrfError> {
if bool::from(p.ct_eq(&U256::ZERO)) {
return Err(PrfError::InvalidParam);
}
let mut ctr: u32 = 0;
loop {
let mut h = lib_q_sha3::Shake256::default();
h.update(label);
h.update(&(ctr as u64).to_le_bytes());
h.update(seed);
let mut buf = [0u8; 32];
let mut r = h.finalize_xof();
XofReader::read(&mut r, &mut buf);
let candidate = U256::from_le_slice(&buf);
let in_range = candidate.ct_lt(p);
let nonzero = !candidate.ct_eq(&U256::ZERO);
if bool::from(in_range & nonzero) {
return Ok(candidate);
}
ctr = ctr.wrapping_add(1);
if ctr > 1024 {
return Err(PrfError::InvalidParam);
}
}
}
pub fn shake256_to_field_u512(seed: &[u8], label: &[u8], p: &U512) -> Result<U512, PrfError> {
if bool::from(p.ct_eq(&U512::ZERO)) {
return Err(PrfError::InvalidParam);
}
let mut ctr: u32 = 0;
loop {
let mut h = lib_q_sha3::Shake256::default();
h.update(label);
h.update(&(ctr as u64).to_le_bytes());
h.update(seed);
let mut buf = [0u8; 64];
let mut r = h.finalize_xof();
XofReader::read(&mut r, &mut buf);
let candidate = U512::from_le_slice(&buf);
let in_range = candidate.ct_lt(p);
let nonzero = !candidate.ct_eq(&U512::ZERO);
if bool::from(in_range & nonzero) {
return Ok(candidate);
}
ctr = ctr.wrapping_add(1);
if ctr > 1024 {
return Err(PrfError::InvalidParam);
}
}
}