bouncycastle_mldsa/
matrix.rs1use crate::aux_functions::multiply_ntt;
5use crate::mldsa::H;
6use crate::polynomial::Polynomial;
7use bouncycastle_core::traits::XOF;
8use bouncycastle_utils::secret::ZeroizablePrimitive;
9use core::ops::{Index, IndexMut};
10
11#[derive(Clone)]
13pub struct Matrix<const k: usize, const l: usize>([[Polynomial; l]; k]);
14
15impl<const k: usize, const l: usize> Index<usize> for Matrix<k, l> {
17 type Output = [Polynomial; l];
18
19 fn index(&self, index: usize) -> &Self::Output {
20 &self.0[index]
21 }
22}
23impl<const k: usize, const l: usize> IndexMut<usize> for Matrix<k, l> {
25 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
26 &mut self.0[index]
27 }
28}
29
30impl<const k: usize, const l: usize> Matrix<k, l> {
31 pub(crate) fn new() -> Self {
32 Self { 0: [[(); l]; k].map(|_| [(); l].map(|_| Polynomial::new())) }
33 }
34
35 pub fn matrix_vector_ntt(&self, v: &Vector<l>) -> Vector<k> {
43 let mut w = Vector::<k>::new();
44 for i in 0..k {
45 w[i].coeffs.copy_from_slice(&multiply_ntt(&self[i][0], &v[0]).coeffs);
47
48 let mut w1: Polynomial;
49 for j in 1..l {
50 w1 = multiply_ntt(&self[i][j], &v[j]);
54 w[i].add_ntt(&w1);
55 }
56 }
57
58 w
59 }
60}
61
62#[derive(Clone, Copy)]
63pub(crate) struct Vector<const LEN: usize> {
64 pub(crate) vec: [Polynomial; LEN],
65}
66
67impl<const LEN: usize> Index<usize> for Vector<LEN> {
69 type Output = Polynomial;
70
71 fn index(&self, index: usize) -> &Self::Output {
72 &self.vec[index]
73 }
74}
75impl<const LEN: usize> IndexMut<usize> for Vector<LEN> {
77 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
78 &mut self.vec[index]
79 }
80}
81
82impl<const LEN: usize> ZeroizablePrimitive for Vector<LEN> {
83 const ZEROED: Self = Self::new();
84}
85
86impl<const LEN: usize> Vector<LEN> {
87 pub(crate) const fn new() -> Self {
88 Self { vec: [Polynomial::new(); LEN] }
89 }
90
91 pub(crate) fn add_vector_ntt(&mut self, s: &Self) {
97 for i in 0..LEN {
98 self[i].add_ntt(&s[i]);
100 }
101 }
102
103 pub(crate) fn sub_vector(&self, s: &Self) -> Self {
104 let mut out = self.clone();
105 for i in 0..LEN {
106 out[i].sub(&s[i]);
107 }
108 out
109 }
110
111 pub(crate) fn scalar_vector_ntt(&self, w: &Polynomial) -> Self {
116 let mut s_hat = Self::new();
117 for i in 0..LEN {
118 s_hat[i] = multiply_ntt(&self[i], &w);
119 }
120
121 s_hat
122 }
123
124 pub(crate) fn conditional_add_q(&mut self) {
125 for i in 0..LEN {
126 self[i].conditional_add_q();
127 }
128 }
129
130 pub(crate) fn reduce(&mut self) {
131 for i in 0..LEN {
132 self[i].reduce();
133 }
134 }
135
136 pub(crate) fn ntt(&mut self) {
137 for i in 0..LEN {
138 self[i].ntt();
139 }
140 }
141
142 pub(crate) fn inv_ntt(&mut self) {
143 for i in 0..LEN {
144 self[i].inv_ntt();
145 }
146 }
147
148 pub(crate) fn high_bits<const GAMMA2: i32>(&self) -> Self {
149 let mut s = Self::new();
150
151 for i in 0..LEN {
152 s[i] = self[i].high_bits::<GAMMA2>();
153 }
154
155 s
156 }
157
158 pub(crate) fn low_bits<const GAMMA2: i32>(&self) -> Self {
159 let mut s = Self::new();
160
161 for i in 0..LEN {
162 s[i] = self[i].low_bits::<GAMMA2>();
163 }
164
165 s
166 }
167
168 pub(crate) fn shift_left<const d: i32>(&self) -> Self {
169 let mut out = self.clone();
170 for i in 0..LEN {
171 out[i].shift_left::<d>();
172 }
173
174 out
175 }
176
177 pub(crate) fn check_norm<const BOUND: i32>(&self) -> bool {
178 for x in self.vec.iter() {
180 if x.check_norm::<BOUND>() {
181 return true;
182 }
183 }
184 false
185 }
186
187 pub(crate) fn w1_encode_and_hash<const POLY_W1_PACKED_LEN: usize>(&self, h: &mut H) {
193 for w in self.vec.iter() {
200 h.absorb(&w.w1_encode::<POLY_W1_PACKED_LEN>())
201 .expect("absorb before squeeze is infallible");
202 }
203 }
204}