use crate::params::params::PUBLICKEYS_BYTES;
use super::kem_error::KemErrors;
use crate::{
encode::rq,
poly::{r3::R3, rq::Rq},
};
use super::priv_key::PrivKey;
pub type PubKey = Rq;
impl PubKey {
pub fn compute(f: &Rq, g: &R3) -> Result<Self, KemErrors> {
let finv = f.recip::<3>().map_err(KemErrors::PolyErrors)?;
Ok(finv.mult_r3(g))
}
pub fn from_sk(priv_key: &PrivKey) -> Result<Self, KemErrors> {
let f = priv_key.0.rq_from_r3();
let ginv = &priv_key.1;
let g = ginv.recip().map_err(KemErrors::PolyErrors)?;
let finv = f.recip::<3>().map_err(KemErrors::PolyErrors)?;
let h = finv.mult_r3(&g);
Ok(h)
}
pub fn import(bytes: &[u8; PUBLICKEYS_BYTES]) -> Self {
rq::decode(bytes).into()
}
}
impl TryFrom<PrivKey> for PubKey {
type Error = KemErrors;
fn try_from(value: PrivKey) -> Result<Self, Self::Error> {
Self::from_sk(&value)
}
}
#[cfg(test)]
mod test_pub_key {
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
use super::*;
use crate::rng::{random_small, short_random};
#[test]
fn test_import_export() {
let mut rng = ChaCha20Rng::from_rng(&mut rand::rng());
for _ in 0..1 {
let f: Rq = Rq::from(short_random(&mut rng).unwrap());
let g: R3 = R3::from(random_small(&mut rng));
let pub_key = PubKey::compute(&f, &g).unwrap();
let bytes = pub_key.to_bytes();
let new_pub_key = PubKey::import(&bytes);
assert_eq!(new_pub_key.coeffs, pub_key.coeffs);
}
}
#[test]
fn test_from_sk() {
let mut rng = ChaCha20Rng::from_rng(&mut rand::rng());
let f: Rq = Rq::from(short_random(&mut rng).unwrap());
let mut g: R3;
let sk = loop {
g = R3::from(random_small(&mut rng));
match PrivKey::compute(&f, &g) {
Ok(s) => break s,
Err(_) => continue,
};
};
let pub_key_from_entropy = PubKey::compute(&f, &g).unwrap();
let pub_key_from_sk = PubKey::from_sk(&sk).unwrap();
assert_eq!(pub_key_from_sk.coeffs, pub_key_from_entropy.coeffs);
}
}