1use crate::ntt::{ntt_forward, ntt_inverse, ntt_pointwise_mul, reduce_coeff};
8use crate::params::{Params, N, SEED_SIZE};
9use crate::poly::{expand_a, poly_zero, sample_cbd_vec, Poly, PolyVec};
10use rand::{CryptoRng, RngCore};
11use zeroize::{Zeroize, ZeroizeOnDrop};
12
13#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct PublicKey {
16 pub rho: [u8; SEED_SIZE],
18
19 pub t: PolyVec,
21}
22
23#[derive(Zeroize, ZeroizeOnDrop)]
28pub struct SecretKey {
29 seed: [u8; SEED_SIZE],
30 rho: [u8; SEED_SIZE],
31 s: PolyVec,
32 e: PolyVec,
33 t: PolyVec,
34 #[zeroize(skip)]
35 public_key: PublicKey,
36}
37
38#[cfg(feature = "serde")]
39impl serde::Serialize for PublicKey {
40 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
41 where
42 S: serde::Serializer,
43 {
44 use serde::ser::SerializeStruct;
45
46 let mut state = serializer.serialize_struct("PublicKey", 2)?;
47 state.serialize_field("rho", &self.rho.as_slice())?;
48 state.serialize_field("t", &crate::poly::polyvec_to_nested_vec(&self.t))?;
49 state.end()
50 }
51}
52
53#[cfg(feature = "serde")]
54impl<'de> serde::Deserialize<'de> for PublicKey {
55 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
56 where
57 D: serde::Deserializer<'de>,
58 {
59 #[derive(serde::Deserialize)]
60 struct PublicKeyRepr {
61 rho: Vec<u8>,
62 t: Vec<Vec<i64>>,
63 }
64
65 let repr = PublicKeyRepr::deserialize(deserializer)?;
66 if repr.rho.len() != SEED_SIZE {
67 return Err(serde::de::Error::invalid_length(
68 repr.rho.len(),
69 &"32-byte public matrix seed",
70 ));
71 }
72 let mut rho = [0_u8; SEED_SIZE];
73 rho.copy_from_slice(&repr.rho);
74 let t = crate::poly::nested_vec_to_polyvec(repr.t).map_err(serde::de::Error::custom)?;
75 Ok(Self { rho, t })
76 }
77}
78
79#[cfg(feature = "serde")]
80impl serde::Serialize for SecretKey {
81 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
82 where
83 S: serde::Serializer,
84 {
85 use serde::ser::SerializeStruct;
86
87 let mut state = serializer.serialize_struct("SecretKey", 5)?;
88 state.serialize_field("seed", &self.seed.as_slice())?;
89 state.serialize_field("rho", &self.rho.as_slice())?;
90 state.serialize_field("s", &crate::poly::polyvec_to_nested_vec(&self.s))?;
91 state.serialize_field("e", &crate::poly::polyvec_to_nested_vec(&self.e))?;
92 state.serialize_field("t", &crate::poly::polyvec_to_nested_vec(&self.t))?;
93 state.end()
94 }
95}
96
97impl SecretKey {
98 #[cfg(feature = "serde")]
104 pub fn from_parts(
105 rho: [u8; SEED_SIZE],
106 s: PolyVec,
107 e: PolyVec,
108 t: PolyVec,
109 seed: [u8; SEED_SIZE],
110 ) -> Self {
111 let public_key = PublicKey { rho, t: t.clone() };
112 Self {
113 seed,
114 rho,
115 s,
116 e,
117 t,
118 public_key,
119 }
120 }
121
122 pub fn rho(&self) -> &[u8; SEED_SIZE] {
124 &self.rho
125 }
126
127 pub fn public_key(&self) -> &PublicKey {
131 &self.public_key
132 }
133
134 pub(crate) fn s(&self) -> &PolyVec {
135 &self.s
136 }
137
138 pub(crate) fn e(&self) -> &PolyVec {
139 &self.e
140 }
141
142 pub(crate) fn t(&self) -> &PolyVec {
143 &self.t
144 }
145
146 pub(crate) fn seed(&self) -> &[u8; SEED_SIZE] {
147 &self.seed
148 }
149}
150
151impl std::fmt::Debug for SecretKey {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 f.debug_struct("SecretKey")
155 .field("rho", &self.rho)
156 .field("seed", &"[REDACTED]")
157 .field("s", &"[REDACTED]")
158 .field("e", &"[REDACTED]")
159 .field("t", &"[REDACTED]")
160 .finish_non_exhaustive()
161 }
162}
163
164pub fn eyvara_keygen<R>(params: &Params, rng: &mut R) -> (PublicKey, SecretKey)
168where
169 R: CryptoRng + RngCore,
170{
171 let mut seed = [0u8; SEED_SIZE];
172 rng.fill_bytes(&mut seed);
173
174 let mut rho = [0u8; SEED_SIZE];
175 rng.fill_bytes(&mut rho);
176
177 let a_ntt = expand_a(&rho, params.k());
178 let s = sample_cbd_vec(rng, params.k(), params.eta());
179 let e = sample_cbd_vec(rng, params.k(), params.eta());
180
181 let s_ntt: Vec<Poly> = s
182 .iter()
183 .map(|p| {
184 let mut pn = *p;
185 ntt_forward(&mut pn);
186 pn
187 })
188 .collect();
189
190 let mut t = vec![poly_zero(); params.k()];
191 for i in 0..params.k() {
192 let mut acc = poly_zero();
193 for j in 0..params.k() {
194 let product = ntt_pointwise_mul(&a_ntt[i][j], &s_ntt[j]);
195 for idx in 0..N {
196 acc[idx] += product[idx];
197 }
198 }
199 ntt_inverse(&mut acc);
200 for idx in 0..N {
201 acc[idx] = reduce_coeff(acc[idx] + e[i][idx]);
202 }
203 t[i] = acc;
204 }
205
206 let pk = PublicKey { rho, t: t.clone() };
207 let sk = SecretKey {
208 seed,
209 rho,
210 s,
211 e,
212 t,
213 public_key: pk.clone(),
214 };
215
216 (pk, sk)
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222 use crate::params::EYVARA_128;
223 use crate::poly::infinity_norm_vec;
224 use rand::SeedableRng;
225 use rand_chacha::ChaCha20Rng;
226
227 #[test]
228 fn test_keygen_produces_valid_keys() {
229 let mut rng = ChaCha20Rng::seed_from_u64(42);
231 let (pk, sk) = eyvara_keygen(&EYVARA_128, &mut rng);
232
233 assert_eq!(pk.t.len(), EYVARA_128.k());
234 assert!(infinity_norm_vec(sk.s()) <= EYVARA_128.eta());
235 assert!(infinity_norm_vec(sk.e()) <= EYVARA_128.eta());
236 assert_eq!(pk.t, *sk.t());
237 assert_eq!(pk.rho, *sk.rho());
238 assert_eq!(&pk, sk.public_key());
239 }
240
241 #[test]
242 fn test_keygen_different_seeds_different_keys() {
243 let mut rng1 = ChaCha20Rng::seed_from_u64(1);
245 let mut rng2 = ChaCha20Rng::seed_from_u64(2);
247 let (pk1, _) = eyvara_keygen(&EYVARA_128, &mut rng1);
248 let (pk2, _) = eyvara_keygen(&EYVARA_128, &mut rng2);
249
250 assert_ne!(pk1.rho, pk2.rho);
251 }
252
253 #[test]
254 fn test_secret_key_debug_redacts_secret_fields() {
255 let mut rng = ChaCha20Rng::seed_from_u64(42);
257 let (_, sk) = eyvara_keygen(&EYVARA_128, &mut rng);
258 let debug = format!("{sk:?}");
259
260 assert!(debug.contains("[REDACTED]"));
261 assert!(!debug.contains("s: [["));
262 }
263}