1use super::truncate::Truncate;
2
3use array::{Array, ArraySize, typenum::U256};
4use core::fmt::Debug;
5use core::ops::{Add, Mul, Neg, Sub};
6use num_traits::PrimInt;
7
8#[cfg(feature = "ctutils")]
9use ctutils::{Choice, CtEq, CtEqSlice};
10#[cfg(feature = "zeroize")]
11use zeroize::Zeroize;
12
13pub trait Field: Copy + Default + Debug + PartialEq {
15 type Int: PrimInt + Default + Debug + From<u8> + Into<u128> + Into<Self::Long> + Truncate<u128>;
17 type Long: PrimInt + From<Self::Int>;
19 type LongLong: PrimInt;
21
22 const Q: Self::Int;
24 const QL: Self::Long;
26 const QLL: Self::LongLong;
28
29 const BARRETT_SHIFT: usize;
31 const BARRETT_MULTIPLIER: Self::LongLong;
33
34 fn small_reduce(x: Self::Int) -> Self::Int;
36 fn barrett_reduce(x: Self::Long) -> Self::Int;
38}
39
40#[macro_export]
51macro_rules! define_field {
52 ($field:ident, $int:ty, $long:ty, $longlong:ty, $q:literal) => {
53 $crate::define_field!($field, $int, $long, $longlong, $q, "Finite field");
54 };
55 ($field:ident, $int:ty, $long:ty, $longlong:ty, $q:literal, $doc:expr) => {
56 #[doc = $doc]
57 #[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
58 pub struct $field;
59
60 impl $crate::Field for $field {
61 type Int = $int;
62 type Long = $long;
63 type LongLong = $longlong;
64
65 const Q: Self::Int = $q;
66 const QL: Self::Long = $q;
67 const QLL: Self::LongLong = $q;
68
69 #[allow(clippy::as_conversions)]
70 const BARRETT_SHIFT: usize = 2 * (Self::Q.ilog2() + 1) as usize;
71 #[allow(clippy::integer_division_remainder_used)]
72 const BARRETT_MULTIPLIER: Self::LongLong = (1 << Self::BARRETT_SHIFT) / Self::QLL;
73
74 fn small_reduce(x: Self::Int) -> Self::Int {
75 use $crate::ctutils::{CtLt, CtSelect};
76 x - Self::Q.ct_select(&0, x.ct_lt(&Self::Q))
77 }
78
79 fn barrett_reduce(x: Self::Long) -> Self::Int {
80 let x: Self::LongLong = x.into();
81 let product = x * Self::BARRETT_MULTIPLIER;
82 let quotient = product >> Self::BARRETT_SHIFT;
83 let remainder = x - quotient * Self::QLL;
84 Self::small_reduce($crate::Truncate::truncate(remainder))
85 }
86 }
87 };
88}
89
90#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
99pub struct Elem<F: Field>(pub F::Int);
100
101impl<F: Field> Elem<F> {
102 pub const fn new(x: F::Int) -> Self {
104 Self(x)
105 }
106}
107
108#[cfg(feature = "ctutils")]
109impl<F: Field> CtEq for Elem<F>
110where
111 F::Int: CtEq,
112{
113 fn ct_eq(&self, other: &Self) -> Choice {
114 self.0.ct_eq(&other.0)
115 }
116}
117
118#[cfg(feature = "ctutils")]
119impl<F: Field<Int: CtEq>> CtEqSlice for Elem<F> {}
120
121#[cfg(feature = "zeroize")]
122impl<F: Field> Zeroize for Elem<F>
123where
124 F::Int: Zeroize,
125{
126 fn zeroize(&mut self) {
127 self.0.zeroize();
128 }
129}
130
131impl<F: Field> Neg for Elem<F> {
132 type Output = Elem<F>;
133
134 fn neg(self) -> Elem<F> {
135 Elem(F::small_reduce(F::Q - self.0))
136 }
137}
138
139impl<F: Field> Add<Elem<F>> for Elem<F> {
140 type Output = Elem<F>;
141
142 fn add(self, rhs: Elem<F>) -> Elem<F> {
143 Elem(F::small_reduce(self.0 + rhs.0))
144 }
145}
146
147impl<F: Field> Sub<Elem<F>> for Elem<F> {
148 type Output = Elem<F>;
149
150 fn sub(self, rhs: Elem<F>) -> Elem<F> {
151 Elem(F::small_reduce(self.0 + F::Q - rhs.0))
152 }
153}
154
155impl<F: Field> Mul<Elem<F>> for Elem<F> {
156 type Output = Elem<F>;
157
158 fn mul(self, rhs: Elem<F>) -> Elem<F> {
159 let lhs: F::Long = self.0.into();
160 let rhs: F::Long = rhs.0.into();
161 let prod = lhs * rhs;
162 Elem(F::barrett_reduce(prod))
163 }
164}
165
166#[derive(Clone, Copy, Default, Debug, PartialEq)]
171pub struct Polynomial<F: Field>(pub Array<Elem<F>, U256>);
172
173impl<F: Field> Polynomial<F> {
174 pub const fn new(x: Array<Elem<F>, U256>) -> Self {
176 Self(x)
177 }
178}
179
180#[cfg(feature = "zeroize")]
181impl<F: Field> Zeroize for Polynomial<F>
182where
183 F::Int: Zeroize,
184{
185 fn zeroize(&mut self) {
186 self.0.zeroize();
187 }
188}
189
190impl<F: Field> Add<&Polynomial<F>> for &Polynomial<F> {
191 type Output = Polynomial<F>;
192
193 fn add(self, rhs: &Polynomial<F>) -> Polynomial<F> {
194 Polynomial(
195 self.0
196 .iter()
197 .zip(rhs.0.iter())
198 .map(|(&x, &y)| x + y)
199 .collect(),
200 )
201 }
202}
203
204impl<F: Field> Sub<&Polynomial<F>> for &Polynomial<F> {
205 type Output = Polynomial<F>;
206
207 fn sub(self, rhs: &Polynomial<F>) -> Polynomial<F> {
208 Polynomial(
209 self.0
210 .iter()
211 .zip(rhs.0.iter())
212 .map(|(&x, &y)| x - y)
213 .collect(),
214 )
215 }
216}
217
218impl<F: Field> Mul<&Polynomial<F>> for Elem<F> {
219 type Output = Polynomial<F>;
220
221 fn mul(self, rhs: &Polynomial<F>) -> Polynomial<F> {
222 Polynomial(rhs.0.iter().map(|&x| self * x).collect())
223 }
224}
225
226impl<F: Field> Neg for &Polynomial<F> {
227 type Output = Polynomial<F>;
228
229 fn neg(self) -> Polynomial<F> {
230 Polynomial(self.0.iter().map(|&x| -x).collect())
231 }
232}
233
234#[cfg(feature = "ctutils")]
235impl<F: Field> CtEq for Polynomial<F>
236where
237 F::Int: CtEq,
238{
239 fn ct_eq(&self, other: &Self) -> Choice {
240 self.0.ct_eq(&other.0)
241 }
242}
243
244#[cfg(feature = "ctutils")]
245impl<F: Field<Int: CtEq>> CtEqSlice for Polynomial<F> {}
246
247#[derive(Clone, Default, Debug, PartialEq)]
251pub struct Vector<F: Field, K: ArraySize>(pub Array<Polynomial<F>, K>);
252
253impl<F: Field, K: ArraySize> Vector<F, K> {
254 pub const fn new(x: Array<Polynomial<F>, K>) -> Self {
256 Self(x)
257 }
258}
259
260#[cfg(feature = "zeroize")]
261impl<F: Field, K: ArraySize> Zeroize for Vector<F, K>
262where
263 F::Int: Zeroize,
264{
265 fn zeroize(&mut self) {
266 self.0.zeroize();
267 }
268}
269
270impl<F: Field, K: ArraySize> Add<Vector<F, K>> for Vector<F, K> {
271 type Output = Vector<F, K>;
272 fn add(self, rhs: Vector<F, K>) -> Vector<F, K> {
273 Add::add(&self, &rhs)
274 }
275}
276impl<F: Field, K: ArraySize> Add<&Vector<F, K>> for &Vector<F, K> {
277 type Output = Vector<F, K>;
278
279 fn add(self, rhs: &Vector<F, K>) -> Vector<F, K> {
280 Vector(
281 self.0
282 .iter()
283 .zip(rhs.0.iter())
284 .map(|(x, y)| x + y)
285 .collect(),
286 )
287 }
288}
289
290impl<F: Field, K: ArraySize> Sub<&Vector<F, K>> for &Vector<F, K> {
291 type Output = Vector<F, K>;
292
293 fn sub(self, rhs: &Vector<F, K>) -> Vector<F, K> {
294 Vector(
295 self.0
296 .iter()
297 .zip(rhs.0.iter())
298 .map(|(x, y)| x - y)
299 .collect(),
300 )
301 }
302}
303
304impl<F: Field, K: ArraySize> Mul<&Vector<F, K>> for Elem<F> {
305 type Output = Vector<F, K>;
306
307 fn mul(self, rhs: &Vector<F, K>) -> Vector<F, K> {
308 Vector(rhs.0.iter().map(|x| self * x).collect())
309 }
310}
311
312impl<F: Field, K: ArraySize> Neg for &Vector<F, K> {
313 type Output = Vector<F, K>;
314
315 fn neg(self) -> Vector<F, K> {
316 Vector(self.0.iter().map(|x| -x).collect())
317 }
318}
319
320#[cfg(feature = "ctutils")]
321impl<F: Field, K: ArraySize> CtEq for Vector<F, K>
322where
323 F::Int: CtEq,
324{
325 fn ct_eq(&self, other: &Self) -> Choice {
326 self.0.ct_eq(&other.0)
327 }
328}
329
330#[cfg(feature = "ctutils")]
331impl<F: Field<Int: CtEq>, K: ArraySize> CtEqSlice for Vector<F, K> {}
332
333#[derive(Clone, Default, Debug, Eq, PartialEq)]
343pub struct NttPolynomial<F: Field>(pub Array<Elem<F>, U256>);
344
345impl<F: Field> NttPolynomial<F> {
346 pub const fn new(x: Array<Elem<F>, U256>) -> Self {
348 Self(x)
349 }
350}
351
352impl<F: Field> Add<&NttPolynomial<F>> for &NttPolynomial<F> {
353 type Output = NttPolynomial<F>;
354
355 fn add(self, rhs: &NttPolynomial<F>) -> NttPolynomial<F> {
356 NttPolynomial(
357 self.0
358 .iter()
359 .zip(rhs.0.iter())
360 .map(|(&x, &y)| x + y)
361 .collect(),
362 )
363 }
364}
365
366impl<F: Field> Sub<&NttPolynomial<F>> for &NttPolynomial<F> {
367 type Output = NttPolynomial<F>;
368
369 fn sub(self, rhs: &NttPolynomial<F>) -> NttPolynomial<F> {
370 NttPolynomial(
371 self.0
372 .iter()
373 .zip(rhs.0.iter())
374 .map(|(&x, &y)| x - y)
375 .collect(),
376 )
377 }
378}
379
380impl<F: Field> Mul<&NttPolynomial<F>> for Elem<F> {
381 type Output = NttPolynomial<F>;
382
383 fn mul(self, rhs: &NttPolynomial<F>) -> NttPolynomial<F> {
384 NttPolynomial(rhs.0.iter().map(|&x| self * x).collect())
385 }
386}
387
388impl<F> Mul<&NttPolynomial<F>> for &NttPolynomial<F>
389where
390 F: Field + MultiplyNtt,
391{
392 type Output = NttPolynomial<F>;
393
394 fn mul(self, rhs: &NttPolynomial<F>) -> NttPolynomial<F> {
395 F::multiply_ntt(self, rhs)
396 }
397}
398
399pub trait MultiplyNtt: Field {
401 fn multiply_ntt(lhs: &NttPolynomial<Self>, rhs: &NttPolynomial<Self>) -> NttPolynomial<Self>;
403}
404
405impl<F: Field> Neg for &NttPolynomial<F> {
406 type Output = NttPolynomial<F>;
407
408 fn neg(self) -> NttPolynomial<F> {
409 NttPolynomial(self.0.iter().map(|&x| -x).collect())
410 }
411}
412
413impl<F: Field> From<Array<Elem<F>, U256>> for NttPolynomial<F> {
414 fn from(f: Array<Elem<F>, U256>) -> NttPolynomial<F> {
415 NttPolynomial(f)
416 }
417}
418
419impl<F: Field> From<NttPolynomial<F>> for Array<Elem<F>, U256> {
420 fn from(f_hat: NttPolynomial<F>) -> Array<Elem<F>, U256> {
421 f_hat.0
422 }
423}
424
425#[cfg(feature = "ctutils")]
426impl<F: Field> CtEq for NttPolynomial<F>
427where
428 F::Int: CtEq,
429{
430 fn ct_eq(&self, other: &Self) -> Choice {
431 self.0.ct_eq(&other.0)
432 }
433}
434
435#[cfg(feature = "ctutils")]
436impl<F: Field<Int: CtEq>> CtEqSlice for NttPolynomial<F> {}
437
438#[cfg(feature = "zeroize")]
439impl<F: Field> Zeroize for NttPolynomial<F>
440where
441 F::Int: Zeroize,
442{
443 fn zeroize(&mut self) {
444 self.0.zeroize();
445 }
446}
447
448#[derive(Clone, Default, Debug, Eq, PartialEq)]
454pub struct NttVector<F: Field, K: ArraySize>(pub Array<NttPolynomial<F>, K>);
455
456impl<F: Field, K: ArraySize> NttVector<F, K> {
457 pub const fn new(x: Array<NttPolynomial<F>, K>) -> Self {
459 Self(x)
460 }
461}
462
463#[cfg(feature = "ctutils")]
464impl<F: Field, K: ArraySize> CtEq for NttVector<F, K>
465where
466 F::Int: CtEq,
467{
468 fn ct_eq(&self, other: &Self) -> Choice {
469 self.0.ct_eq(&other.0)
470 }
471}
472
473#[cfg(feature = "ctutils")]
474impl<F: Field<Int: CtEq>, K: ArraySize> CtEqSlice for NttVector<F, K> {}
475
476#[cfg(feature = "zeroize")]
477impl<F: Field, K: ArraySize> Zeroize for NttVector<F, K>
478where
479 F::Int: Zeroize,
480{
481 fn zeroize(&mut self) {
482 self.0.zeroize();
483 }
484}
485
486impl<F: Field, K: ArraySize> Add<&NttVector<F, K>> for &NttVector<F, K> {
487 type Output = NttVector<F, K>;
488
489 fn add(self, rhs: &NttVector<F, K>) -> NttVector<F, K> {
490 NttVector(
491 self.0
492 .iter()
493 .zip(rhs.0.iter())
494 .map(|(x, y)| x + y)
495 .collect(),
496 )
497 }
498}
499
500impl<F: Field, K: ArraySize> Sub<&NttVector<F, K>> for &NttVector<F, K> {
501 type Output = NttVector<F, K>;
502
503 fn sub(self, rhs: &NttVector<F, K>) -> NttVector<F, K> {
504 NttVector(
505 self.0
506 .iter()
507 .zip(rhs.0.iter())
508 .map(|(x, y)| x - y)
509 .collect(),
510 )
511 }
512}
513
514impl<F: Field, K: ArraySize> Mul<&NttVector<F, K>> for &NttPolynomial<F>
515where
516 for<'a> &'a NttPolynomial<F>: Mul<&'a NttPolynomial<F>, Output = NttPolynomial<F>>,
517{
518 type Output = NttVector<F, K>;
519
520 fn mul(self, rhs: &NttVector<F, K>) -> NttVector<F, K> {
521 NttVector(rhs.0.iter().map(|x| self * x).collect())
522 }
523}
524
525impl<F: Field, K: ArraySize> Mul<&NttVector<F, K>> for &NttVector<F, K>
526where
527 for<'a> &'a NttPolynomial<F>: Mul<&'a NttPolynomial<F>, Output = NttPolynomial<F>>,
528{
529 type Output = NttPolynomial<F>;
530
531 fn mul(self, rhs: &NttVector<F, K>) -> NttPolynomial<F> {
532 self.0
533 .iter()
534 .zip(rhs.0.iter())
535 .map(|(x, y)| x * y)
536 .fold(NttPolynomial::default(), |x, y| &x + &y)
537 }
538}
539
540#[derive(Clone, Default, Debug, PartialEq)]
548pub struct NttMatrix<F: Field, K: ArraySize, L: ArraySize>(pub Array<NttVector<F, L>, K>);
549
550impl<F: Field, K: ArraySize, L: ArraySize> NttMatrix<F, K, L> {
551 pub const fn new(x: Array<NttVector<F, L>, K>) -> Self {
553 Self(x)
554 }
555}
556
557impl<F: Field, K: ArraySize, L: ArraySize> Mul<&NttVector<F, L>> for &NttMatrix<F, K, L>
558where
559 for<'a> &'a NttPolynomial<F>: Mul<&'a NttPolynomial<F>, Output = NttPolynomial<F>>,
560{
561 type Output = NttVector<F, K>;
562
563 fn mul(self, rhs: &NttVector<F, L>) -> NttVector<F, K> {
564 NttVector(self.0.iter().map(|x| x * rhs).collect())
565 }
566}
567
568#[cfg(feature = "ctutils")]
569impl<F: Field, K: ArraySize, L: ArraySize> CtEq for NttMatrix<F, K, L>
570where
571 F::Int: CtEq,
572{
573 fn ct_eq(&self, other: &Self) -> Choice {
574 self.0.ct_eq(&other.0)
575 }
576}
577
578#[cfg(feature = "ctutils")]
579impl<F: Field<Int: CtEq>, K: ArraySize, L: ArraySize> CtEqSlice for NttMatrix<F, K, L> {}