1use core::ops::{AddAssign, Index, IndexMut};
2
3use rand::{CryptoRng, RngCore};
4
5use crate::{
6 keccak::fips202::{CrystalsPrf, CrystalsXof, SpongeOps},
7 poly::{
8 dilithium::DilithiumPoly,
9 kyber::{KyberPoly, Prf, Xof, KYBER_N, NOISE_SEED_BYTES, POLYBYTES, XOF_BLOCK_BYTES},
10 Polynomial, UNIFORM_SEED_BYTES,
11 },
12};
13
14use super::poly::SizedPolynomial;
15
16pub trait PolynomialVector: Default + Sized + Index<usize> + IndexMut<usize> {
17 type Poly: Polynomial;
18 const K: usize;
19
20 fn ntt(&mut self);
21 fn ntt_and_reduce(&mut self);
22 fn inv_ntt_tomont(&mut self);
23
24 fn reduce(&mut self);
25 fn uniform_xof<const TRANSPOSED: bool>(&mut self, seed: &[u8; UNIFORM_SEED_BYTES], i: u8);
26
27 fn basemul_acc(&self, other: &Self, result: &mut <Self as PolynomialVector>::Poly);
28}
29
30#[derive(Debug, Clone, Copy)]
31pub struct PolyVec<P, const N: usize, const K: usize>([P; K])
32where
33 P: Polynomial;
34
35impl<P, const N: usize, const K: usize> Default for PolyVec<P, N, K>
36where
37 P: Polynomial,
38{
39 fn default() -> Self {
40 PolyVec([P::default(); K])
41 }
42}
43
44impl<P, const N: usize, const K: usize> Index<usize> for PolyVec<P, N, K>
45where
46 P: Polynomial,
47{
48 type Output = P;
49 fn index(&self, i: usize) -> &Self::Output {
50 &self.0[i]
51 }
52}
53
54impl<P, const N: usize, const K: usize> IndexMut<usize> for PolyVec<P, N, K>
55where
56 P: Polynomial,
57{
58 fn index_mut(&mut self, i: usize) -> &mut Self::Output {
59 &mut self.0[i]
60 }
61}
62
63impl<P, const N: usize, const K: usize> AsRef<[P; K]> for PolyVec<P, N, K>
64where
65 P: Polynomial,
66{
67 #[inline(always)]
68 fn as_ref(&self) -> &[P; K] {
69 &self.0
70 }
71}
72
73impl<P, const N: usize, const K: usize> AsMut<[P; K]> for PolyVec<P, N, K>
74where
75 P: Polynomial,
76{
77 #[inline(always)]
78 fn as_mut(&mut self) -> &mut [P; K] {
79 &mut self.0
80 }
81}
82
83impl<P, const N: usize, const K: usize> PolynomialVector for PolyVec<P, N, K>
84where
85 P: SizedPolynomial<N>,
86{
87 const K: usize = K;
88 type Poly = P;
89
90 #[inline]
91 fn ntt(&mut self) {
92 for poly in self {
93 poly.ntt();
94 }
95 }
96
97 #[inline]
98 fn ntt_and_reduce(&mut self) {
99 for poly in self {
100 poly.ntt();
101 poly.reduce();
102 }
103 }
104
105 #[inline]
106 fn inv_ntt_tomont(&mut self) {
107 for poly in self {
108 poly.inv_ntt();
109 }
110 }
111
112 #[inline]
113 fn reduce(&mut self) {
114 for poly in self {
115 poly.reduce();
116 }
117 }
118
119 #[inline]
120 fn uniform_xof<const TRANSPOSED: bool>(&mut self, seed: &[u8; UNIFORM_SEED_BYTES], i: u8) {
121 let mut shake128 = Xof::default();
122 let mut xof_out = [0u8; XOF_BLOCK_BYTES];
123
124 for (j, poly) in self.as_mut().iter_mut().enumerate() {
125 let (i, j) = if TRANSPOSED {
126 (i, j as u8)
127 } else {
128 (j as u8, i)
129 };
130
131 shake128.absorb_xof_with_nonces(seed, i, j);
132
133 let mut ctr = 0;
134 while ctr < Self::Poly::NUM_SCALARS {
135 shake128.squeeze(&mut xof_out);
136 ctr = poly.rej_uniform(ctr, &xof_out);
137 }
138
139 debug_assert_eq!(ctr, Self::Poly::NUM_SCALARS);
140 }
141 }
142
143 fn basemul_acc(&self, other: &Self, result: &mut <Self as PolynomialVector>::Poly) {
144 for (left, right) in self.into_iter().zip(other) {
146 left.pointwise_acc(right, result);
147 }
148 result.reduce();
149 }
150}
151
152impl<'a, const N: usize, P, const K: usize> IntoIterator for &'a mut PolyVec<P, N, K>
153where
154 P: Polynomial,
155{
156 type Item = &'a mut P;
157
158 type IntoIter = core::slice::IterMut<'a, P>;
159
160 fn into_iter(self) -> Self::IntoIter {
161 (*self).as_mut().iter_mut()
162 }
163}
164
165impl<'a, P, const N: usize, const K: usize> IntoIterator for &'a PolyVec<P, N, K>
166where
167 P: Polynomial,
168{
169 type Item = &'a P;
170
171 type IntoIter = core::slice::Iter<'a, P>;
172
173 fn into_iter(self) -> Self::IntoIter {
174 (*self).as_ref().iter()
175 }
176}
177
178impl<P, const N: usize, const K: usize> AddAssign<&Self> for PolyVec<P, N, K>
179where
180 P: Polynomial,
181{
182 fn add_assign(&mut self, rhs: &Self) {
183 for i in 0..K {
184 self[i] += &rhs[i];
185 }
186 }
187}
188
189impl<const N: usize, const K: usize> PolyVec<KyberPoly, N, K> {
190 #[inline(always)]
191 pub fn new_deserialize(bytes: &[[u8; POLYBYTES]; K]) -> Self {
192 let mut pv = Self::default();
193 pv.deserialize(bytes);
194 pv
195 }
196
197 #[inline(always)]
198 pub fn deserialize(&mut self, bytes: &[[u8; POLYBYTES]; K]) {
199 for (poly, b) in self.into_iter().zip(bytes) {
200 poly.deserialize(b);
201 }
202 }
203
204 #[inline(always)]
205 pub fn serialize(&self, r: &mut [[u8; POLYBYTES]; K]) {
206 for (poly, bytes) in self.into_iter().zip(r) {
207 poly.serialize(bytes);
208 }
209 }
210}
211pub type KyberPolyVec<const K: usize> = PolyVec<KyberPoly, { KyberPoly::N }, K>;
212
213impl<const K: usize> KyberPolyVec<K> {
214 #[doc(hidden)]
215 pub fn new_random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
216 let mut pv = Self::default();
217 for i in 0..K {
218 pv[i] = KyberPoly::new_random(rng);
219 }
220 pv
221 }
222
223 #[inline]
224 pub fn getnoise_eta1(&mut self, prf: &mut Prf, seed: &[u8; NOISE_SEED_BYTES], nonce: u8) {
225 if K == 2 {
226 const ETA1: usize = 3;
227 let mut buf = [0u8; ETA1 * KYBER_N / 4];
228 for (i, poly) in self.as_mut().iter_mut().enumerate() {
229 prf.absorb_prf(seed, i as u8 + nonce);
230 prf.squeeze(&mut buf);
231 poly.cbd3(&buf);
232 }
233 } else {
234 self.getnoise_eta2(prf, seed, nonce);
235 }
236 }
237
238 #[inline]
239 pub fn getnoise_eta2(&mut self, prf: &mut Prf, seed: &[u8; NOISE_SEED_BYTES], nonce: u8) {
240 const ETA2: usize = 2;
241 prf.absorb_prf(seed, nonce);
242 let mut buf = [0u8; ETA2 * KYBER_N / 4];
243 for (i, poly) in self.as_mut().iter_mut().enumerate() {
244 prf.absorb_prf(seed, i as u8 + nonce);
245 prf.squeeze(&mut buf);
246 poly.cbd2(&buf);
247 }
248 }
249
250 #[inline] pub fn compress<const D: usize>(&self, ct: &mut [[[u8; D]; 32]; K]) {
252 for (poly, a) in self.into_iter().zip(ct.iter_mut()) {
253 poly.compress(a);
254 }
255 }
256
257 #[inline]
258 pub fn decompress<const D: usize>(&mut self, ct: &[[[u8; D]; 32]; K]) {
259 for (poly, a) in self.into_iter().zip(ct.iter()) {
260 poly.decompress(a);
261 }
262 }
263}
264
265pub type DilithiumPolyVec<const K: usize> = PolyVec<DilithiumPoly, { DilithiumPoly::N }, K>;
266
267impl<const K: usize> DilithiumPolyVec<K> {
268 pub fn new_random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
269 let mut pv = DilithiumPolyVec::<K>::default();
270 for i in 0..K {
271 pv[i] = DilithiumPoly::new_random(rng);
272 }
273 pv
274 }
275}