1use core::ops::{Index, IndexMut};
2
3use crate::{
4 poly::{kyber::KyberPoly, SizedPolynomial, UNIFORM_SEED_BYTES},
5 polyvec::*,
6};
7
8#[derive(Debug)]
9pub struct PolyMat<P, const N: usize, const K: usize, const L: usize>([PolyVec<P, N, L>; K])
10where
11 P: SizedPolynomial<N>;
12
13impl<P, const N: usize, const K: usize, const L: usize> Default for PolyMat<P, N, K, L>
14where
15 P: SizedPolynomial<N>,
16{
17 #[inline]
18 fn default() -> Self {
19 Self([PolyVec::default(); K])
20 }
21}
22
23impl<P, const N: usize, const K: usize, const L: usize> Index<usize> for PolyMat<P, N, K, L>
24where
25 P: SizedPolynomial<N>,
26{
27 type Output = PolyVec<P, N, L>;
28
29 #[inline(always)]
30 fn index(&self, i: usize) -> &Self::Output {
31 &self.0[i]
32 }
33}
34
35impl<P, const N: usize, const K: usize, const L: usize> IndexMut<usize> for PolyMat<P, N, K, L>
36where
37 P: SizedPolynomial<N>,
38{
39 #[inline(always)]
40 fn index_mut(&mut self, i: usize) -> &mut Self::Output {
41 &mut self.0[i]
42 }
43}
44
45impl<P, const N: usize, const K: usize, const L: usize> AsRef<[PolyVec<P, N, L>; K]>
46 for PolyMat<P, N, K, L>
47where
48 P: SizedPolynomial<N>,
49{
50 #[inline(always)]
51 fn as_ref(&self) -> &[PolyVec<P, N, L>; K] {
52 &self.0
53 }
54}
55
56impl<P, const N: usize, const K: usize, const L: usize> AsMut<[PolyVec<P, N, L>; K]>
57 for PolyMat<P, N, K, L>
58where
59 P: SizedPolynomial<N>,
60{
61 #[inline(always)]
62 fn as_mut(&mut self) -> &mut [PolyVec<P, N, L>; K] {
63 &mut self.0
64 }
65}
66
67impl<P, const N: usize, const K: usize, const L: usize> PolyMat<P, N, K, L>
68where
69 P: SizedPolynomial<N>,
70{
71 #[inline(always)]
87 pub fn gen_matrix<const TRANSPOSED: bool>(seed: &[u8; UNIFORM_SEED_BYTES]) -> Self {
88 let mut a = Self::default();
89 a.gen_matrix_into::<TRANSPOSED>(seed);
90 a
91 }
92
93 #[inline(always)]
94 pub fn gen_a(seed: &[u8; UNIFORM_SEED_BYTES]) -> Self {
95 Self::gen_matrix::<false>(seed)
96 }
97
98 #[inline(always)]
99 pub fn gen_at(seed: &[u8; UNIFORM_SEED_BYTES]) -> Self {
100 Self::gen_matrix::<true>(seed)
101 }
102
103 #[inline]
104 pub fn gen_matrix_into<const TRANSPOSED: bool>(&mut self, seed: &[u8; UNIFORM_SEED_BYTES]) {
105 for (i, vec) in self.as_mut().iter_mut().enumerate() {
106 vec.uniform_xof::<TRANSPOSED>(seed, i as u8);
107 }
108 }
109}
110
111pub type KyberMatrix<const K: usize> = PolyMat<KyberPoly, { KyberPoly::N }, K, K>;
112
113#[cfg(test)]
114mod tests {
115 use rand::Rng;
116
117 use crate::poly::kyber::KYBER_N;
118
119 use super::*;
120
121 #[test]
122 fn gen_matrix() {
123 gen_matrix_x::<2, true>();
124 gen_matrix_x::<3, true>();
125 gen_matrix_x::<4, true>();
126 gen_matrix_x::<2, false>();
127 gen_matrix_x::<3, false>();
128 gen_matrix_x::<4, false>();
129 }
130
131 fn gen_matrix_x<const K: usize, const TRANSPOSED: bool>() {
132 let mut seed = [0u8; 32];
133 let mut rng = rand::thread_rng();
134
135 const NUM_TESTS: usize = if cfg!(miri) { 3 } else { 111 };
136
137 let mut a_ref = [[[0i16; KYBER_N]; K]; K];
138
139 for _ in 0..NUM_TESTS {
140 rng.fill(&mut seed);
141
142 let a = KyberMatrix::<K>::gen_matrix::<TRANSPOSED>(&seed);
143
144 crystals_cref::kyber::gen_matrix(&mut a_ref, &seed, TRANSPOSED);
145
146 for i in 0..K {
147 for j in 0..K {
148 for k in 0..KYBER_N {
149 assert_eq!(
150 a[i][j][k / 2].0[k % 2],
151 a_ref[i][j][k],
152 "i={}, j={}, k={}",
153 i,
154 j,
155 k
156 );
157 }
158 }
159 }
160 }
161 }
162}