binius_ntt/
additive_ntt.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use binius_field::{BinaryField, ExtensionField, PackedExtension, PackedField};
4use binius_math::BinarySubspace;
5
6use super::error::Error;
7
8/// The binary field additive NTT.
9///
10/// A number-theoretic transform (NTT) is a linear transformation on a finite field analogous to
11/// the discrete fourier transform. The version of the additive NTT we use is originally described
12/// in [LCH14]. In [DP24] Section 3.1, the authors present the LCH additive NTT algorithm in a way
13/// that makes apparent its compatibility with the FRI proximity test. Throughout the
14/// documentation, we will refer to the notation used in [DP24].
15///
16/// The additive NTT is parameterized by a binary field $K$ and $\mathbb{F}_2$-linear subspace. We
17/// write $\beta_0, \ldots, \beta_{\ell-1}$ for the ordered basis elements of the subspace and
18/// require $\beta_0 = 1$. The basis determines a novel polynomial basis and an evaluation domain.
19/// In the forward direction, the additive NTT transforms a vector of polynomial coefficients, with
20/// respect to the novel polynomial basis, into a vector of their evaluations over the evaluation
21/// domain. The inverse transformation interpolates polynomial values over the domain into novel
22/// polynomial basis coefficients.
23///
24/// [LCH14]: <https://arxiv.org/abs/1404.3458>
25/// [DP24]: <https://eprint.iacr.org/2024/504>
26pub trait AdditiveNTT<F: BinaryField> {
27	/// Base-2 logarithm of the maximum size of the NTT domain, $\ell$.
28	fn log_domain_size(&self) -> usize;
29
30	/// Returns the binary subspace $S^(i)$.
31	///
32	/// The domain will have dimension $\ell - i$.
33	///
34	/// ## Preconditions
35	///
36	/// * `i` must be less than `self.log_domain_size()`
37	fn subspace(&self, i: usize) -> BinarySubspace<F>;
38
39	/// Get the normalized subspace polynomial evaluation $\hat{W}_i(\beta_j)$.
40	///
41	/// ## Preconditions
42	///
43	/// * `i` must be less than `self.log_domain_size()`
44	/// * `j` must be less than `self.log_domain_size() - i`
45	fn get_subspace_eval(&self, i: usize, j: usize) -> F;
46
47	/// Forward transformation defined in [LCH14] on a batch of inputs.
48	///
49	/// Input is the vector of polynomial coefficients in novel basis, output is in Lagrange basis.
50	/// The batched inputs are interleaved, which improves the cache-efficiency of the computation.
51	///
52	/// [LCH14]: <https://arxiv.org/abs/1404.3458>
53	fn forward_transform<P: PackedField<Scalar = F>>(
54		&self,
55		data: &mut [P],
56		coset: u32,
57		log_batch_size: usize,
58		log_n: usize,
59	) -> Result<(), Error>;
60
61	/// Inverse transformation defined in [LCH14] on a batch of inputs.
62	///
63	/// Input is the vector of polynomial coefficients in Lagrange basis, output is in novel basis.
64	/// The batched inputs are interleaved, which improves the cache-efficiency of the computation.
65	///
66	/// [LCH14]: https://arxiv.org/abs/1404.3458
67	fn inverse_transform<P: PackedField<Scalar = F>>(
68		&self,
69		data: &mut [P],
70		coset: u32,
71		log_batch_size: usize,
72		log_n: usize,
73	) -> Result<(), Error>;
74
75	fn forward_transform_ext<PE: PackedExtension<F>>(
76		&self,
77		data: &mut [PE],
78		coset: u32,
79		log_n: usize,
80	) -> Result<(), Error> {
81		self.forward_transform(PE::cast_bases_mut(data), coset, PE::Scalar::LOG_DEGREE, log_n)
82	}
83
84	fn inverse_transform_ext<PE: PackedExtension<F>>(
85		&self,
86		data: &mut [PE],
87		coset: u32,
88		log_n: usize,
89	) -> Result<(), Error> {
90		self.inverse_transform(PE::cast_bases_mut(data), coset, PE::Scalar::LOG_DEGREE, log_n)
91	}
92}