use crypto_bigint::{
NonZero,
U256,
U512,
};
use zeroize::{
Zeroize,
ZeroizeOnDrop,
};
use crate::error::PrfError;
use crate::field::{
fp_add,
legendre_symbol_monty,
to_monty,
uint_ct_eq_zero,
};
use crate::keys::{
validate_key_u256,
validate_key_u512,
};
use crate::params::{
LegendrePrfParams256,
LegendrePrfParams512,
};
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct LegendreKey256 {
k: U256,
}
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct LegendreKey512 {
k: U512,
}
impl LegendreKey256 {
pub fn from_uint(k: U256, params: &LegendrePrfParams256) -> Result<Self, PrfError> {
validate_key_u256(&k, ¶ms.p.get())?;
Ok(Self { k })
}
pub fn derive_from_seed(seed: &[u8], params: &LegendrePrfParams256) -> Result<Self, PrfError> {
let k =
crate::shake::shake256_to_field_u256(seed, b"lib-q-prf/leg-k256/v1", ¶ms.p.get())?;
Self::from_uint(k, params)
}
#[inline]
#[must_use]
pub fn as_uint(&self) -> &U256 {
&self.k
}
}
impl LegendreKey512 {
pub fn from_uint(k: U512, params: &LegendrePrfParams512) -> Result<Self, PrfError> {
validate_key_u512(&k, ¶ms.p)?;
Ok(Self { k })
}
pub fn derive_from_seed(seed: &[u8], params: &LegendrePrfParams512) -> Result<Self, PrfError> {
let k = crate::shake::shake256_to_field_u512(seed, b"lib-q-prf/leg-k512/v1", ¶ms.p)?;
Self::from_uint(k, params)
}
#[inline]
#[must_use]
pub fn as_uint(&self) -> &U512 {
&self.k
}
}
pub fn legendre_prf_u256(
key: &LegendreKey256,
x: &U256,
params: &LegendrePrfParams256,
) -> Result<i8, PrfError> {
let xm = to_monty(&x.rem_vartime(¶ms.p), ¶ms.monty);
let km = to_monty(&key.k, ¶ms.monty);
let sum = fp_add(xm, &km);
let zero_sum = uint_ct_eq_zero(&sum.retrieve());
if bool::from(zero_sum) {
return Err(PrfError::ZeroInput);
}
legendre_symbol_monty(&sum)
}
pub fn legendre_prf_u512(
key: &LegendreKey512,
x: &U512,
params: &LegendrePrfParams512,
) -> Result<i8, PrfError> {
let nz = NonZero::new(params.p)
.into_option()
.ok_or(PrfError::InvalidParam)?;
let xm = to_monty(&x.rem_vartime(&nz), ¶ms.monty);
let km = to_monty(&key.k, ¶ms.monty);
let sum = fp_add(xm, &km);
let zero_sum = uint_ct_eq_zero(&sum.retrieve());
if bool::from(zero_sum) {
return Err(PrfError::ZeroInput);
}
legendre_symbol_monty(&sum)
}
#[cfg(test)]
pub fn legendre_symbol_euler_u256(x_plus_k: &U256, params: &LegendrePrfParams256) -> i8 {
let p = params.p.get();
let e = p.wrapping_sub(&U256::ONE).shr(1);
let reduced = x_plus_k.rem_vartime(¶ms.p);
let m = to_monty(&reduced, ¶ms.monty);
let y = m.pow(&e).retrieve();
crate::field::legendre_symbol_residue(&y, &p).expect("prime field")
}