1use rand_core::{CryptoRng, RngCore};
4use zeroize::ZeroizeOnDrop;
5
6use crate::error::RuneError;
7use crate::math::{
8 poly_add, poly_is_well_formed, poly_mul_schoolbook, sample_cbd, sample_uniform_poly, Poly,
9 ZeroizingPoly,
10};
11use crate::params::Params;
12
13#[derive(Clone, Debug, PartialEq, Eq)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub struct PublicKey {
17 pub a: Poly,
19 pub t: Poly,
21}
22
23#[derive(ZeroizeOnDrop)]
25pub struct SecretKey {
26 s: Poly,
27 e: Poly,
28 t: Poly,
29}
30
31impl SecretKey {
32 fn new(s: Poly, e: Poly, t: Poly) -> Self {
33 Self { s, e, t }
34 }
35
36 pub(crate) fn s(&self) -> &Poly {
37 &self.s
38 }
39
40 pub(crate) fn e(&self) -> &Poly {
41 &self.e
42 }
43
44 pub(crate) fn t(&self) -> &Poly {
45 &self.t
46 }
47}
48
49impl std::fmt::Debug for SecretKey {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 f.debug_struct("SecretKey")
53 .field("s", &"[REDACTED]")
54 .field("e", &"[REDACTED]")
55 .field("t", &"<public>")
56 .finish()
57 }
58}
59
60pub fn generate_shared_a(params: &Params, rng: &mut (impl CryptoRng + RngCore)) -> Poly {
62 sample_uniform_poly(params, rng)
63}
64
65pub fn keygen(
72 a: &Poly,
73 params: &Params,
74 rng: &mut (impl CryptoRng + RngCore),
75) -> Result<(PublicKey, SecretKey), RuneError> {
76 if !poly_is_well_formed(a, params) {
77 return Err(RuneError::MalformedPublicKey);
78 }
79
80 let s = ZeroizingPoly(sample_cbd(params, rng));
81 let e = ZeroizingPoly(sample_cbd(params, rng));
82 let t = poly_add(&poly_mul_schoolbook(a, &s.0, params), &e.0, params);
83
84 let pk = PublicKey {
85 a: a.clone(),
86 t: t.clone(),
87 };
88 let sk = SecretKey::new(s.0.clone(), e.0.clone(), t);
89
90 Ok((pk, sk))
91}