Skip to main content

starkom_poly/
poly.rs

1use crate::utils;
2use anyhow::{Context, Result, anyhow};
3use starkom_ff::{Field, PrimeField, ThreeAdicField};
4use std::any::{Any, TypeId};
5use std::collections::BTreeMap;
6use std::iter::{Product, Sum};
7use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
8use std::sync::{Mutex, OnceLock};
9
10/// Builds the Lagrange basis polynomials returned by [`Polynomial::lagrange0_2`] and
11/// [`Polynomial::lagrange0_3`].
12///
13/// Running time: O(N).
14fn make_lagrange0<F: PrimeField>(n: usize) -> Polynomial<F> {
15    let mut coefficients = vec![F::ZERO; n + 1];
16    coefficients[0] = -F::ONE;
17    coefficients[n] = F::ONE;
18    let zero = Polynomial { coefficients };
19    let (quotient, remainder) = zero.horner(F::ONE);
20    assert_eq!(remainder, F::ZERO);
21    quotient * F::try_from(n).unwrap().invert_unwrap()
22}
23
24/// A polynomial expressed as an array of scalar coefficients in ascending degree order (i.e. the
25/// first coefficient is the constant term).
26#[derive(Debug, Default, Clone, PartialEq, Eq)]
27pub struct Polynomial<F: Field> {
28    coefficients: Vec<F>,
29}
30
31impl<F: Field> Polynomial<F> {
32    /// Constructs a polynomial with the provided coefficients, which must be in ascending degree
33    /// order.
34    pub fn with_coefficients(coefficients: Vec<F>) -> Self {
35        Self { coefficients }
36    }
37
38    /// Returns a zero-degree polynomial that evaluates to `y` everywhere.
39    pub fn constant(y: F) -> Self {
40        Self {
41            coefficients: vec![y],
42        }
43    }
44
45    /// Constructs a polynomial that interpolates the given points using Lagrange interpolation.
46    ///
47    /// The points are specified as (x, y) pairs.
48    ///
49    /// Running time: O(N^2).
50    pub fn interpolate(points: &[(F, F)]) -> Result<Self> {
51        let k = points.len();
52        let x = points.iter().map(|(x, _)| *x).collect::<Vec<F>>();
53        let l = Self::from_roots(x.as_slice(), F::ONE).context("duplicate X-coordinates")?;
54        let w = {
55            let one = F::ONE;
56            let mut weights = vec![one; k];
57            for i in 0..k {
58                for j in 0..k {
59                    if i != j {
60                        weights[i] *= x[i] - x[j];
61                    }
62                }
63                weights[i] = weights[i]
64                    .invert()
65                    .into_option()
66                    .context("duplicate X-coordinates")?;
67            }
68            weights
69        };
70        let mut result = Self {
71            coefficients: Vec::with_capacity(points.len()),
72        };
73        for i in 0..k {
74            let (basis, remainder) = l.horner(x[i]);
75            assert_eq!(remainder, F::ZERO);
76            let (_, y) = points[i];
77            result += basis * w[i] * y;
78        }
79        Ok(result)
80    }
81
82    /// Interpolates a polynomial that has the given roots.
83    ///
84    /// This algorithm is roughly twice faster than simply calling [`Self::interpolate`] with 0 as
85    /// the y coordinate of all points.
86    ///
87    /// NOTE: if the caller's protocol doesn't require a blinding factor it can be set to 1. Do NOT
88    /// set it to 0, as that would nullify the whole polynomial.
89    ///
90    /// Running time: O(N^2).
91    pub fn from_roots(roots: &[F], blinding_factor: F) -> Result<Self> {
92        let mut roots = roots.to_vec();
93        roots.sort();
94        for i in 1..roots.len() {
95            if roots[i] == roots[i - 1] {
96                return Err(anyhow!("duplicate roots"));
97            }
98        }
99        let n = roots.len() + 1;
100        let mut coefficients = vec![F::ZERO; n];
101        coefficients[0] = blinding_factor;
102        for i in 1..n {
103            for j in (0..i).rev() {
104                let c = coefficients[j];
105                coefficients[j + 1] -= c * roots[i - 1];
106            }
107        }
108        coefficients.reverse();
109        Ok(Self { coefficients })
110    }
111
112    /// Returns the number of coefficients, which is equal to the maximum degree plus 1.
113    pub fn len(&self) -> usize {
114        self.coefficients.len()
115    }
116
117    /// Returns the coefficients of the polynomial in ascending degree order.
118    pub fn coefficients(&self) -> &[F] {
119        self.coefficients.as_slice()
120    }
121
122    fn degree_bound_of(coefficients: &[F]) -> usize {
123        for (i, &coefficient) in coefficients.iter().enumerate().rev() {
124            if coefficient != F::ZERO {
125                return i + 1;
126            }
127        }
128        0
129    }
130
131    /// Returns the degree bound of the polynomial, ie. the smallest number `d` such that the degree
132    /// is strcitly less than `d`.
133    ///
134    /// Equivalently: this function returns the degree plus one.
135    ///
136    /// Running time: O(N) due to the possibility that some of the trailing coefficients are zero.
137    pub fn degree_bound(&self) -> usize {
138        Self::degree_bound_of(self.coefficients.as_slice())
139    }
140
141    /// Removes any trailing null coefficients.
142    ///
143    /// After this call, [`Self::len()`] is guaranteed to reflect the actual degree bound of the
144    /// polynomial:
145    ///
146    /// ```ignore
147    /// assert_eq!(poly.trim().len(), poly.degree_bound());
148    /// ```
149    pub fn trim(mut self) -> Self {
150        if let Some(i) = self
151            .coefficients
152            .iter()
153            .rposition(|value| *value != F::ZERO)
154        {
155            self.coefficients.truncate(i + 1);
156        } else {
157            self.coefficients.clear();
158        }
159        self
160    }
161
162    /// Pads the polynomial with null coefficients until the degree bound is at least
163    /// `degree_bound`.
164    pub fn pad(mut self, min_degree_bound: usize) -> Self {
165        if min_degree_bound > self.coefficients.len() {
166            self.coefficients.resize(min_degree_bound, F::ZERO);
167        }
168        self
169    }
170
171    /// Extracts the array of coefficients from this polynomial.
172    ///
173    /// NOTE: the coefficients are in ascending degree order, i.e. the first returned element is the
174    /// constant term.
175    pub fn take(self) -> Vec<F> {
176        return self.coefficients;
177    }
178
179    /// Divides this polynomial by (x - z) using Horner's method. Returns the quotient polynomial
180    /// and the remainder scalar.
181    ///
182    /// Running time: O(N).
183    pub fn horner(&self, z: F) -> (Self, F) {
184        if self.coefficients.is_empty() {
185            return (Polynomial::default(), F::ZERO);
186        }
187        let n = self.len() - 1;
188        let mut coefficients = vec![F::ZERO; n];
189        if n < 1 {
190            return (Polynomial { coefficients }, self.coefficients[0]);
191        }
192        coefficients[n - 1] = self.coefficients[n];
193        for i in (1..n).rev() {
194            coefficients[i - 1] = self.coefficients[i] + z * coefficients[i];
195        }
196        let remainder = self.coefficients[0] + z * coefficients[0];
197        (Polynomial { coefficients }, remainder)
198    }
199
200    /// Divides this polynomial by (x^n - 1), succeeding only if the remainder is 0. The polynomial
201    /// wrapped in a successful result is the quotient Q such that Q(x) * (x^n - 1) equals this
202    /// polynomial.
203    ///
204    /// Note that (x^n - 1) is a polynomial that evaluates to zero across an evaluation domain of
205    /// size `n`, because the roots of it are the n-th roots of unity. We call this the "zero
206    /// polynomial", hence the "divide by zero" terminology.
207    ///
208    /// REQUIRES: `n` must be strictly greater than 0.
209    ///
210    /// NOTE: this algorithm doesn't check that `n` is a power of 2 or 3 and will work with
211    /// arbitrary values of `n`, but it's generally most useful when `n` is a power of 2 (for the
212    /// two-adic evaluation domain) or 3 (for the three-adic one).
213    ///
214    /// Running time: O(N).
215    pub fn divide_by_zero(self, n: usize) -> Result<Self> {
216        assert!(n > 0);
217
218        let mut data = self.take();
219        if data.len() < n {
220            data.resize(n, F::ZERO);
221        }
222
223        let degree = data.len() - n;
224        let mut quotient = vec![F::ZERO; degree];
225
226        for i in 0..degree {
227            let c = -data[i];
228            quotient[i] = c;
229            data[i + n] -= c;
230        }
231
232        let remainder = &data[degree..];
233        if remainder.iter().any(|c| *c != F::ZERO) {
234            return Err(anyhow!("non-zero remainder in division by (x^n - 1)"));
235        }
236
237        if let Some(i) = quotient.iter().rposition(|c| *c != F::ZERO) {
238            quotient.truncate(i + 1);
239        }
240        Ok(Polynomial {
241            coefficients: quotient,
242        })
243    }
244
245    /// Evaluates the polynomial at the specified X coordinate.
246    ///
247    /// Running time: O(N).
248    ///
249    /// NOTE: the returned value is the same as the remainder value returned by the [`Self::horner`]
250    /// algorithm above. Even though the two algorithms have the same asymptotic running time, this
251    /// one is faster because it doesn't allocate memory for the quotient polynomial.
252    pub fn evaluate(&self, x: F) -> F {
253        let mut y = F::ZERO;
254        for coefficient in self.coefficients.iter().rev() {
255            y = y * x + *coefficient;
256        }
257        y
258    }
259
260    /// Converts this polynomial `P(X)` to `P(shift * X)`, effectively shifting the evaluation
261    /// domain.
262    ///
263    /// Running time: O(N).
264    pub fn shift_domain_by(self, shift: F) -> Self {
265        let mut coefficients = self.coefficients;
266        let mut shift_pow = F::ONE;
267        for c in coefficients.iter_mut() {
268            *c *= shift_pow;
269            shift_pow *= shift;
270        }
271        Self { coefficients }
272    }
273
274    /// Folding algorithm used in FRI and similar algorithms.
275    ///
276    /// `alpha` is a verifier challenge, typically derived via Fiat-Shamir.
277    pub fn fold2(self, alpha: F) -> Self {
278        let coefficients = self.coefficients();
279        let m = (coefficients.len() + 1) / 2;
280        let new_coefficients = (0..m)
281            .map(|i| {
282                coefficients[2 * i]
283                    + alpha * coefficients.get(2 * i + 1).copied().unwrap_or(F::ZERO)
284            })
285            .collect();
286        Self::with_coefficients(new_coefficients)
287    }
288}
289
290impl<F: PrimeField> Polynomial<F> {
291    /// 2-adic Fast Fourier Transform.
292    ///
293    /// REQUIRES: the length of `data` must be a power of two less than or equal to N and `omega`
294    /// must be an N-th root of unity, where N = 2^(F::S).
295    ///
296    /// Running time: O(N*logN).
297    fn fft2(data: &mut [F], omega: F) {
298        let n = data.len();
299        assert!(n.is_power_of_two());
300
301        let log_n = n.trailing_zeros();
302        assert!(log_n as usize <= F::S);
303
304        for i in 0..n {
305            let (j, _) = i.reverse_bits().overflowing_shr(usize::BITS - log_n);
306            if i < j {
307                data.swap(i, j);
308            }
309        }
310
311        let mut m = 1;
312        for _ in 0..log_n {
313            let step = m * 2;
314            let wm = omega.pow_small(n / step);
315            let mut w = F::ONE;
316            for k in 0..m {
317                for j in (k..n).step_by(step) {
318                    let t = w * data[j + m];
319                    let u = data[j];
320                    data[j] = u + t;
321                    data[j + m] = u - t;
322                }
323                w *= wm;
324            }
325            m = step;
326        }
327    }
328
329    /// Inverse 2-adic Fast Fourier Transform.
330    ///
331    /// REQUIRES: `n` must be a power of two less than or equal to 2^S, with `S` being the 2-adicity
332    /// of the field `F` (supplied as `F::S`).
333    ///
334    /// Running time: O(N*logN).
335    fn ifft2(data: &mut [F], omega: F) {
336        Self::fft2(data, omega.invert_unwrap());
337        let n_inv = F::try_from(data.len()).unwrap().invert_unwrap();
338        for v in data.iter_mut() {
339            *v *= n_inv;
340        }
341    }
342
343    /// Computes an N-th root of unity where N is a power of 2 less than or equal to 2^(F::S).
344    fn two_adic_root_of_unity(n: usize) -> F {
345        assert!(n.is_power_of_two());
346        let k = n.trailing_zeros() as usize;
347        assert!(k <= F::S);
348        let exponent = 1u64 << (F::S - k);
349        F::ROOT_OF_UNITY.pow_u64(exponent)
350    }
351
352    /// Interpolates a polynomial that encodes an ordered list of values.
353    ///
354    /// The returned polynomial evaluates to the provided values at certain powers of
355    /// `F::ROOT_OF_UNITY`. The exact coordinates can be retrieved by calling
356    /// [`Self::domain_element2`] with the index of the value to query and the size of the domain
357    /// (i.e. `values.len()`).
358    ///
359    /// NOTE: this function is called `encode2` because it uses the two-adic evaluation domain. For
360    /// the three-adic version see [`Self::encode3`] below.
361    ///
362    /// Under the hood we use the two-adic Inverse Fourier Transform algorithm ([`Self::ifft2`]),
363    /// which requires the size of the list to be a power of two. If that's not the case, this
364    /// function will automatically pad the provided list with zeros.
365    ///
366    /// Additionally, the provided list must not exceed the FFT capacity so it's required to have no
367    /// more than 2^(F::S) elements.
368    ///
369    /// Running time: O(N*logN).
370    pub fn encode2(mut values: Vec<F>) -> Self {
371        assert!(!values.is_empty());
372        let n = values.len().next_power_of_two();
373        assert!(n.trailing_zeros() as usize <= F::S);
374        if n != values.len() {
375            values.resize(n, F::ZERO);
376        }
377        let omega = Self::two_adic_root_of_unity(values.len());
378        Self::ifft2(values.as_mut_slice(), omega);
379        Polynomial {
380            coefficients: values,
381        }
382        .trim()
383    }
384
385    /// Recovers the ordered list of values encoded by [`Self::encode2`].
386    ///
387    /// This is the inverse of [`Self::encode2`]: given a polynomial produced by `encode2(values)`,
388    /// calling `decode2` returns a list equal to `values` (possibly padded with trailing zeros to
389    /// the next power of two).
390    ///
391    /// Under the hood we use the two-adic Fast Fourier Transform algorithm ([`Self::fft2`]). The
392    /// polynomial's coefficient list is zero-padded to the next power of two before the transform
393    /// is applied.
394    ///
395    /// Running time: O(N*logN).
396    pub fn decode2(self) -> Vec<F> {
397        let mut data = self.coefficients;
398        let n = data.len().next_power_of_two();
399        if n != data.len() {
400            data.resize(n, F::ZERO);
401        }
402        let omega = Self::two_adic_root_of_unity(n);
403        Self::fft2(&mut data, omega);
404        data
405    }
406
407    /// Multiplies two polynomials. Panics if the FFT capacity is exceeded -- that is, if the degree
408    /// of the product is greater than or equal to 2^(F::S).
409    pub fn multiply(mut self, mut other: Self) -> Self {
410        self = self.trim();
411        other = other.trim();
412
413        let mut lhs = self.coefficients;
414        let mut rhs = other.coefficients;
415
416        if lhs.is_empty() || rhs.is_empty() {
417            return Polynomial {
418                coefficients: vec![],
419            };
420        }
421        if lhs.len() == 1 {
422            return Polynomial { coefficients: rhs } * lhs[0];
423        }
424        if rhs.len() == 1 {
425            return Polynomial { coefficients: lhs } * rhs[0];
426        }
427
428        let n = (lhs.len() + rhs.len() - 1).next_power_of_two();
429
430        lhs.resize(n, F::ZERO);
431        rhs.resize(n, F::ZERO);
432
433        let omega = Self::two_adic_root_of_unity(n);
434        Self::fft2(lhs.as_mut_slice(), omega);
435        Self::fft2(rhs.as_mut_slice(), omega);
436
437        for i in 0..n {
438            lhs[i] *= rhs[i];
439        }
440
441        Self::ifft2(lhs.as_mut_slice(), omega);
442
443        Polynomial { coefficients: lhs }.trim()
444    }
445
446    /// Multiplies an arbitrary number of polynomials together, returning an error if the FFT
447    /// capacity is exceeded -- that is, if the degree bound of the product is greater than or equal
448    /// to `2^(F::S)`.
449    pub fn multiply_batch<'a, I: IntoIterator<Item = &'a Self>>(polynomials: I) -> Self
450    where
451        I::IntoIter: Clone,
452    {
453        let iter = polynomials.into_iter();
454        let n = {
455            let (count, total) =
456                iter.clone()
457                    .fold((0usize, 0usize), |(count, total), polynomial| {
458                        (count + 1, total + std::cmp::max(polynomial.len(), 1))
459                    });
460            (total - count + 1).next_power_of_two()
461        };
462        let mut data = vec![F::ONE; n];
463        let omega = Self::two_adic_root_of_unity(n);
464        for polynomial in iter {
465            let m = polynomial.len();
466            assert!(n >= m);
467            let mut values = vec![F::ZERO; n];
468            values[0..m].copy_from_slice(&polynomial.coefficients);
469            Self::fft2(values.as_mut_slice(), omega);
470            for i in 0..n {
471                data[i] *= values[i];
472            }
473        }
474        Self::ifft2(data.as_mut_slice(), omega);
475        Polynomial { coefficients: data }.trim()
476    }
477
478    /// Multiplies two polynomials defined on the value domain, assuming the provided evaluations
479    /// are defined on the same two-adic evaluation domain.
480    ///
481    /// REQUIRES: the LHS and RHS must have the same length `n` and it must be a power of two. The
482    /// implied evaluation domain is the set of powers of an `n`-th root of unity.
483    ///
484    /// The returned polynomial is also on the value domain and can be switched to the coefficient
485    /// domain by constructing a [`Polynomial`] object with [`Self::encode2`].
486    pub fn multiply_values2(mut lhs: Vec<F>, mut rhs: Vec<F>) -> Vec<F> {
487        let n = lhs.len();
488        assert!(n.is_power_of_two());
489        assert!(n.trailing_zeros() as usize + 1 <= F::S);
490        assert_eq!(rhs.len(), n);
491        let omega = Self::two_adic_root_of_unity(n);
492        Self::ifft2(&mut lhs, omega);
493        Self::ifft2(&mut rhs, omega);
494        let lhs_len = Self::degree_bound_of(lhs.as_slice());
495        let rhs_len = Self::degree_bound_of(rhs.as_slice());
496        let m = (lhs_len + rhs_len - 1).next_power_of_two();
497        lhs.resize(m, F::ZERO);
498        rhs.resize(m, F::ZERO);
499        let omega = Self::two_adic_root_of_unity(m);
500        Self::fft2(&mut lhs, omega);
501        Self::fft2(&mut rhs, omega);
502        for i in 0..m {
503            lhs[i] *= rhs[i];
504        }
505        lhs
506    }
507
508    /// Converts this polynomial `P(X)` to `P(g * X)`, where `g` is [`F::MULTIPLICATIVE_GENERATOR`].
509    ///
510    /// The choice of the multiplicative generator prevents collisions between the old and new
511    /// locations, so this shift can be used in FRI and similar algorithms to preserve secrecy of
512    /// the values at the original locations while querying the polynomial on the shifted domain.
513    ///
514    /// Running time: O(N).
515    pub fn shift_domain(self) -> Self {
516        self.shift_domain_by(F::MULTIPLICATIVE_GENERATOR)
517    }
518
519    /// Returns the X coordinate of the i-th element of a list encoded with [`Self::encode2`].
520    ///
521    /// The returned value is suitable for use with [`Self::evaluate`] to query the original value
522    /// from the encoded list.
523    ///
524    /// `domain_size` is the length of the original list. It will be rounded up to the next power of
525    /// two automatically.
526    ///
527    /// Running time: O(1).
528    pub fn domain_element2(index: usize, domain_size: usize) -> F {
529        let omega = Self::two_adic_root_of_unity(domain_size.next_power_of_two());
530        omega.pow_small(index)
531    }
532
533    /// Returns the X coordinate of the i-th point in the coset domain used by
534    /// [`Self::shift_domain`].
535    ///
536    /// Equivalent to `F::MULTIPLICATIVE_GENERATOR * domain_element2(index, domain_size)`.
537    ///
538    /// Running time: O(1).
539    pub fn coset_element2(index: usize, domain_size: usize) -> F {
540        F::MULTIPLICATIVE_GENERATOR * Self::domain_element2(index, domain_size)
541    }
542
543    /// Same as `evaluate(domain_element2(index, domain_size))`.
544    ///
545    /// Running time: O(N).
546    pub fn evaluate_on_two_adic_domain(&self, index: usize, domain_size: usize) -> F {
547        self.evaluate(Self::domain_element2(index, domain_size))
548    }
549
550    /// Same as `evaluate(coset_element2(index, domain_size))`.
551    ///
552    /// Running time: O(N).
553    pub fn evaluate_on_two_adic_coset(&self, index: usize, domain_size: usize) -> F {
554        self.evaluate(Self::coset_element2(index, domain_size))
555    }
556
557    /// Computes a low-degree extension of the polynomial by evaluating it at `m` points, where `m`
558    /// is a power of two strictly larger than the current degree bound.
559    ///
560    /// The returned vector is an array of `m` evaluations suitable for FRI and similar algorithms.
561    ///
562    /// REQUIRES: `m` must be a power of two strictly larger than `self.len()`, and no larger than
563    /// `2^(F::S)`.
564    ///
565    /// Running time: O(M*log(M)).
566    pub fn lde2(self, m: usize) -> Vec<F> {
567        assert!(m.is_power_of_two());
568        assert!(m.trailing_zeros() as usize <= F::S);
569        assert!(self.coefficients.len() < m);
570        let mut data = self.coefficients;
571        data.resize(m, F::ZERO);
572        let omega = Self::two_adic_root_of_unity(m);
573        Self::fft2(&mut data, omega);
574        data
575    }
576
577    /// Returns the Lagrange basis polynomial L0 that activates on the first point of the two-adic
578    /// evaluation domain of size `n` and evaluates to 0 over the rest.
579    ///
580    /// In other words:
581    ///
582    ///   L0(1) = 1
583    ///   L0(w^i) = 0 for all i such that 0 < i < n
584    ///
585    /// where `w` is an n-th root of unity.
586    ///
587    /// REQUIRES: `n` must be a power of 2 less than or equal to `2^(F::S)`.
588    ///
589    /// These polynomials are used in the PLONK proving scheme running over BlueSky. They're
590    /// computed on first use and cached for the lifetime of the program.
591    pub fn lagrange0_2(n: usize) -> &'static Self {
592        assert!(n.is_power_of_two());
593        let k = n.trailing_zeros() as usize;
594        assert!(k <= F::S);
595
596        static CACHE: OnceLock<Mutex<BTreeMap<(TypeId, usize), &'static (dyn Any + Send + Sync)>>> =
597            OnceLock::new();
598        let cache = CACHE.get_or_init(|| Mutex::new(BTreeMap::new()));
599
600        let polynomial = {
601            let mut map = cache.lock().unwrap();
602            *map.entry((TypeId::of::<F>(), k)).or_insert_with(|| {
603                Box::leak(Box::new(make_lagrange0::<F>(1 << k))) as &'static (dyn Any + Send + Sync)
604            })
605        };
606
607        polynomial.downcast_ref::<Polynomial<F>>().unwrap()
608    }
609}
610
611impl<F: ThreeAdicField> Polynomial<F> {
612    /// 3-adic Fast Fourier Transform.
613    ///
614    /// REQUIRES: the length of `data` must be a power of three less than or equal to N and `omega`
615    /// must be an N-th root of unity, where N = 3^(F::T).
616    ///
617    /// Running time: O(N*logN).
618    fn fft3(data: &mut [F], omega: F) {
619        let n = data.len();
620        assert!(utils::is_power_of_three(n));
621
622        let log_n = utils::ilog3(n);
623
624        for i in 0..n {
625            let mut j = 0;
626            let mut tmp = i;
627            for _ in 0..log_n {
628                j = j * 3 + tmp % 3;
629                tmp /= 3;
630            }
631            if i < j {
632                data.swap(i, j);
633            }
634        }
635
636        let omega3 = omega.pow_small(n / 3);
637        let omega3_square = omega3.square();
638
639        let mut m = 1;
640        for _ in 0..log_n {
641            let step = m * 3;
642            let wm = omega.pow_small(n / step);
643            let mut w = F::ONE;
644            let mut w2 = F::ONE;
645            for k in 0..m {
646                for j in (k..n).step_by(step) {
647                    let t0 = data[j];
648                    let t1 = w * data[j + m];
649                    let t2 = w2 * data[j + 2 * m];
650                    data[j] = t0 + t1 + t2;
651                    data[j + m] = t0 + omega3 * t1 + omega3_square * t2;
652                    data[j + 2 * m] = t0 + omega3_square * t1 + omega3 * t2;
653                }
654                w *= wm;
655                w2 = w * w;
656            }
657            m = step;
658        }
659    }
660
661    /// Inverse 3-adic Fast Fourier Transform.
662    ///
663    /// REQUIRES: the length of `data` must be a power of three less than or equal to 3^(F::T), with
664    /// `T` being the 3-adicity of the field `F` (supplied as `F::T`).
665    ///
666    /// Running time: O(N*logN).
667    fn ifft3(data: &mut [F], omega: F) {
668        Self::fft3(data, omega.invert_unwrap());
669        let n_inv = F::try_from(data.len()).unwrap().invert_unwrap();
670        for v in data.iter_mut() {
671            *v *= n_inv;
672        }
673    }
674
675    /// Computes an N-th root of unity where N is a power of 3 less than or equal to 3^(F::T).
676    fn three_adic_root_of_unity(n: usize) -> F {
677        assert!(utils::is_power_of_three(n));
678        let k = utils::ilog3(n);
679        assert!(k <= F::T);
680        let exponent = 3u64.pow((F::T - k) as u32);
681        F::THREE_ADIC_ROOT_OF_UNITY.pow_u64(exponent)
682    }
683
684    /// Interpolates a polynomial that encodes an ordered list of values.
685    ///
686    /// The returned polynomial evaluates to the provided values at certain powers of the
687    /// `F::THREE_ADIC_ROOT_OF_UNITY`. The exact coordinates can be retrieved by calling
688    /// [`Self::domain_element3`] with the index of the value to query and the size of the domain
689    /// (i.e. `values.len()`).
690    ///
691    /// NOTE: this function is called `encode3` because it uses the three-adic evaluation domain.
692    /// For the two-adic version see [`Self::encode2`] above.
693    ///
694    /// Under the hood we use the three-adic Inverse Fourier Transform algorithm ([`Self::ifft3`]),
695    /// which requires the size of the list to be a power of three. If that's not the case, this
696    /// function will automatically pad the provided list with zeros.
697    ///
698    /// Additionally, the provided list must not exceed the FFT capacity so it's required to have no
699    /// more than 3^(F::T) elements.
700    ///
701    /// Running time: O(N*logN).
702    pub fn encode3(mut values: Vec<F>) -> Self {
703        assert!(!values.is_empty());
704        let n = utils::next_power_of_three(values.len());
705        assert!(utils::ilog3(n) <= F::T as usize);
706        if n != values.len() {
707            values.resize(n, F::ZERO);
708        }
709        let omega = Self::three_adic_root_of_unity(values.len());
710        Self::ifft3(values.as_mut_slice(), omega);
711        Polynomial {
712            coefficients: values,
713        }
714        .trim()
715    }
716
717    /// Recovers the ordered list of values encoded by [`Self::encode3`].
718    ///
719    /// This is the inverse of [`Self::encode3`]: given a polynomial produced by `encode3(values)`,
720    /// calling `decode3` returns a list equal to `values` (possibly padded with trailing zeros to
721    /// the next power of three).
722    ///
723    /// Under the hood we use the three-adic Fast Fourier Transform algorithm ([`Self::fft3`]). The
724    /// polynomial's coefficient list is zero-padded to the next power of three before the transform
725    /// is applied.
726    ///
727    /// Running time: O(N*logN).
728    pub fn decode3(self) -> Vec<F> {
729        let mut data = self.coefficients;
730        let n = utils::next_power_of_three(data.len());
731        if n != data.len() {
732            data.resize(n, F::ZERO);
733        }
734        let omega = Self::three_adic_root_of_unity(n);
735        Self::fft3(&mut data, omega);
736        data
737    }
738
739    /// Returns the X coordinate of the i-th element of a list encoded with [`Self::encode3`].
740    ///
741    /// The returned value is suitable for use with [`Self::evaluate`] to query the original value
742    /// from the encoded list.
743    ///
744    /// `domain_size` is the length of the original list. It will be rounded up to the next power of
745    /// three automatically.
746    ///
747    /// Running time: O(1).
748    pub fn domain_element3(index: usize, domain_size: usize) -> F {
749        let omega = Self::three_adic_root_of_unity(utils::next_power_of_three(domain_size));
750        omega.pow_small(index)
751    }
752
753    /// Returns the X coordinate of the i-th point in the coset domain used by
754    /// [`Self::shift_domain`].
755    ///
756    /// Equivalent to `F::MULTIPLICATIVE_GENERATOR * domain_element3(index, domain_size)`.
757    ///
758    /// Running time: O(1).
759    pub fn coset_element3(index: usize, domain_size: usize) -> F {
760        F::MULTIPLICATIVE_GENERATOR * Self::domain_element3(index, domain_size)
761    }
762
763    /// Same as `evaluate(domain_element3(index, domain_size))`.
764    ///
765    /// Running time: O(N).
766    pub fn evaluate_on_three_adic_domain(&self, index: usize, domain_size: usize) -> F {
767        self.evaluate(Self::domain_element3(index, domain_size))
768    }
769
770    /// Same as `evaluate(coset_element3(index, domain_size))`.
771    ///
772    /// Running time: O(N).
773    pub fn evaluate_on_three_adic_coset(&self, index: usize, domain_size: usize) -> F {
774        self.evaluate(Self::coset_element3(index, domain_size))
775    }
776
777    /// Computes a low-degree extension of the polynomial by evaluating it at `m` points, where `m`
778    /// is a power of three strictly larger than the current degree bound.
779    ///
780    /// The returned vector is an array of `m` evaluations suitable for (ternary) FRI and similar
781    /// algorithms.
782    ///
783    /// REQUIRES: `m` must be a power of three strictly larger than `self.len()`, and no larger than
784    /// `3^(F::T)`.
785    ///
786    /// Running time: O(M*log(M)).
787    pub fn lde3(self, m: usize) -> Vec<F> {
788        assert!(utils::is_power_of_three(m));
789        assert!(utils::ilog3(m) <= F::T);
790        assert!(self.coefficients.len() < m);
791        let mut data = self.coefficients;
792        data.resize(m, F::ZERO);
793        let omega = Self::three_adic_root_of_unity(m);
794        Self::fft3(&mut data, omega);
795        data
796    }
797
798    /// Folding algorithm used in three-adic FRI and similar algorithms.
799    ///
800    /// `alpha` is a verifier challenge, typically derived via Fiat-Shamir.
801    pub fn fold3(self, alpha: F) -> Self {
802        let coefficients = self.coefficients();
803        let m = (coefficients.len() + 2) / 3;
804        let alpha_square = alpha * alpha;
805        let new_coefficients = (0..m)
806            .map(|i| {
807                coefficients[3 * i]
808                    + alpha * coefficients.get(3 * i + 1).copied().unwrap_or(F::ZERO)
809                    + alpha_square * coefficients.get(3 * i + 2).copied().unwrap_or(F::ZERO)
810            })
811            .collect();
812        Self::with_coefficients(new_coefficients)
813    }
814
815    /// Multiplies two polynomials defined on the value domain, assuming the provided evaluations
816    /// are defined on the same three-adic evaluation domain for both.
817    ///
818    /// REQUIRES: the LHS and RHS must have the same length `n` and it must be a power of three.
819    /// The implied evaluation domain is the set of powers of an `n`-th root of unity.
820    ///
821    /// The returned polynomial is also on the value domain and can be switched to the coefficient
822    /// domain by constructing a [`Polynomial`] object on it (see [`Self::encode3`]).
823    pub fn multiply_values3(mut lhs: Vec<F>, mut rhs: Vec<F>) -> Vec<F> {
824        let n = lhs.len();
825        assert!(utils::is_power_of_three(n));
826        assert!(utils::ilog3(n) + 1 <= F::T);
827        assert_eq!(rhs.len(), n);
828        let omega = Self::three_adic_root_of_unity(n);
829        Self::ifft3(&mut lhs, omega);
830        Self::ifft3(&mut rhs, omega);
831        let lhs_len = Self::degree_bound_of(lhs.as_slice());
832        let rhs_len = Self::degree_bound_of(rhs.as_slice());
833        let m = utils::next_power_of_three(lhs_len + rhs_len - 1);
834        lhs.resize(m, F::ZERO);
835        rhs.resize(m, F::ZERO);
836        let omega = Self::three_adic_root_of_unity(m);
837        Self::fft3(&mut lhs, omega);
838        Self::fft3(&mut rhs, omega);
839        for i in 0..m {
840            lhs[i] *= rhs[i];
841        }
842        lhs
843    }
844
845    /// Returns the Lagrange basis polynomial L0 that activates on the first point of the three-adic
846    /// evaluation domain of size `n` and evaluates to 0 over the rest.
847    ///
848    /// In other words:
849    ///
850    ///   L0(1) = 1
851    ///   L0(w^i) = 0 for all i such that 0 < i < n
852    ///
853    /// where `w` is an n-th root of unity.
854    ///
855    /// REQUIRES: `n` must be a power of 3 less than or equal to `3^(F::T)`.
856    ///
857    /// These polynomials are used in the PLONK proving scheme running over BlueSky. They're
858    /// computed on first use and cached for the lifetime of the program.
859    pub fn lagrange0_3(n: usize) -> &'static Self {
860        assert!(utils::is_power_of_three(n));
861        let k = utils::ilog3(n);
862        assert!(k <= (F::T as usize));
863
864        static CACHE: OnceLock<Mutex<BTreeMap<(TypeId, usize), &'static (dyn Any + Send + Sync)>>> =
865            OnceLock::new();
866        let cache = CACHE.get_or_init(|| Mutex::new(BTreeMap::new()));
867
868        let polynomial = {
869            let mut map = cache.lock().unwrap();
870            *map.entry((TypeId::of::<F>(), k)).or_insert_with(|| {
871                Box::leak(Box::new(make_lagrange0::<F>(3usize.pow(k as u32))))
872                    as &'static (dyn Any + Send + Sync)
873            })
874        };
875
876        polynomial.downcast_ref::<Polynomial<F>>().unwrap()
877    }
878}
879
880impl<F: Field> Neg for Polynomial<F> {
881    type Output = Self;
882
883    fn neg(mut self) -> Self::Output {
884        for coefficient in &mut self.coefficients {
885            *coefficient = -*coefficient;
886        }
887        self
888    }
889}
890
891impl<F: Field> Add<Polynomial<F>> for Polynomial<F> {
892    type Output = Self;
893
894    fn add(mut self, rhs: Self) -> Self::Output {
895        let len = rhs.len();
896        if len > self.len() {
897            return rhs + self;
898        }
899        for i in 0..len {
900            self.coefficients[i] += rhs.coefficients[i];
901        }
902        self
903    }
904}
905
906impl<F: Field> Add<&Polynomial<F>> for Polynomial<F> {
907    type Output = Self;
908
909    fn add(mut self, rhs: &Self) -> Self::Output {
910        let len = rhs.len();
911        if len > self.len() {
912            self.coefficients.resize(len, F::ZERO);
913        }
914        for i in 0..len {
915            self.coefficients[i] += rhs.coefficients[i];
916        }
917        self
918    }
919}
920
921impl<F: Field> AddAssign<Polynomial<F>> for Polynomial<F> {
922    fn add_assign(&mut self, mut rhs: Self) {
923        if rhs.len() > self.len() {
924            for i in 0..self.len() {
925                rhs.coefficients[i] += self.coefficients[i];
926            }
927            self.coefficients = rhs.coefficients;
928        } else {
929            for i in 0..rhs.len() {
930                self.coefficients[i] += rhs.coefficients[i];
931            }
932        }
933    }
934}
935
936impl<F: Field> AddAssign<&Polynomial<F>> for Polynomial<F> {
937    fn add_assign(&mut self, rhs: &Self) {
938        let len = rhs.len();
939        if len > self.len() {
940            self.coefficients.resize(len, F::ZERO);
941        }
942        for i in 0..len {
943            self.coefficients[i] += rhs.coefficients[i];
944        }
945    }
946}
947
948impl<F: Field> Add<F> for Polynomial<F> {
949    type Output = Self;
950
951    fn add(mut self, rhs: F) -> Self::Output {
952        if self.coefficients.is_empty() {
953            self.coefficients.push(rhs);
954        } else {
955            self.coefficients[0] += rhs;
956        }
957        self
958    }
959}
960
961impl<F: Field> AddAssign<F> for Polynomial<F> {
962    fn add_assign(&mut self, rhs: F) {
963        if self.coefficients.is_empty() {
964            self.coefficients.push(rhs);
965        } else {
966            self.coefficients[0] += rhs;
967        }
968    }
969}
970
971impl<F: Field> Sub<Polynomial<F>> for Polynomial<F> {
972    type Output = Self;
973
974    fn sub(mut self, rhs: Self) -> Self::Output {
975        if rhs.len() > self.len() {
976            return -(rhs - self);
977        }
978        for i in 0..rhs.len() {
979            self.coefficients[i] -= rhs.coefficients[i];
980        }
981        self
982    }
983}
984
985impl<F: Field> Sub<&Polynomial<F>> for Polynomial<F> {
986    type Output = Self;
987
988    fn sub(mut self, rhs: &Self) -> Self::Output {
989        let len = rhs.len();
990        if len > self.len() {
991            self.coefficients.resize(len, F::ZERO);
992        }
993        for i in 0..len {
994            self.coefficients[i] -= rhs.coefficients[i];
995        }
996        self
997    }
998}
999
1000impl<F: Field> SubAssign<Polynomial<F>> for Polynomial<F> {
1001    fn sub_assign(&mut self, mut rhs: Self) {
1002        if rhs.len() > self.len() {
1003            for i in 0..self.len() {
1004                rhs.coefficients[i] -= self.coefficients[i];
1005            }
1006            self.coefficients = rhs.coefficients;
1007            for i in 0..self.len() {
1008                self.coefficients[i] = -self.coefficients[i];
1009            }
1010        } else {
1011            for i in 0..rhs.len() {
1012                self.coefficients[i] -= rhs.coefficients[i];
1013            }
1014        }
1015    }
1016}
1017
1018impl<F: Field> SubAssign<&Polynomial<F>> for Polynomial<F> {
1019    fn sub_assign(&mut self, rhs: &Self) {
1020        let len = rhs.len();
1021        if len > self.len() {
1022            self.coefficients.resize(len, F::ZERO);
1023        }
1024        for i in 0..len {
1025            self.coefficients[i] -= rhs.coefficients[i];
1026        }
1027    }
1028}
1029
1030impl<F: Field> Sub<F> for Polynomial<F> {
1031    type Output = Self;
1032
1033    fn sub(mut self, rhs: F) -> Self::Output {
1034        if self.coefficients.is_empty() {
1035            self.coefficients.push(-rhs);
1036        } else {
1037            self.coefficients[0] -= rhs;
1038        }
1039        self
1040    }
1041}
1042
1043impl<F: Field> SubAssign<F> for Polynomial<F> {
1044    fn sub_assign(&mut self, rhs: F) {
1045        if self.coefficients.is_empty() {
1046            self.coefficients.push(-rhs);
1047        } else {
1048            self.coefficients[0] -= rhs;
1049        }
1050    }
1051}
1052
1053impl<F: Field> Mul<F> for Polynomial<F> {
1054    type Output = Self;
1055
1056    fn mul(mut self, rhs: F) -> Self::Output {
1057        for i in 0..self.len() {
1058            self.coefficients[i] *= rhs;
1059        }
1060        self
1061    }
1062}
1063
1064impl<F: Field> MulAssign<F> for Polynomial<F> {
1065    fn mul_assign(&mut self, rhs: F) {
1066        for i in 0..self.len() {
1067            self.coefficients[i] *= rhs;
1068        }
1069    }
1070}
1071
1072impl<F: PrimeField> Mul<Polynomial<F>> for Polynomial<F> {
1073    type Output = Self;
1074
1075    fn mul(self, rhs: Self) -> Self::Output {
1076        self.multiply(rhs)
1077    }
1078}
1079
1080impl<F: PrimeField> Mul<&Polynomial<F>> for Polynomial<F> {
1081    type Output = Self;
1082
1083    fn mul(self, rhs: &Self) -> Self::Output {
1084        self.multiply(rhs.clone())
1085    }
1086}
1087
1088impl<F: PrimeField> MulAssign<Polynomial<F>> for Polynomial<F> {
1089    fn mul_assign(&mut self, rhs: Self) {
1090        *self = std::mem::take(self).multiply(rhs);
1091    }
1092}
1093
1094impl<F: PrimeField> MulAssign<&Polynomial<F>> for Polynomial<F> {
1095    fn mul_assign(&mut self, rhs: &Self) {
1096        *self = std::mem::take(self).multiply(rhs.clone());
1097    }
1098}
1099
1100impl<F: Field> Sum<Polynomial<F>> for Polynomial<F> {
1101    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
1102        iter.fold(Polynomial::default(), |a, b| a + b)
1103    }
1104}
1105
1106impl<'a, F: Field> Sum<&'a Polynomial<F>> for Polynomial<F> {
1107    fn sum<I: Iterator<Item = &'a Polynomial<F>>>(iter: I) -> Self {
1108        iter.fold(Polynomial::default(), |a, b| a + b)
1109    }
1110}
1111
1112impl<F: PrimeField> Product<Polynomial<F>> for Polynomial<F> {
1113    fn product<I: Iterator<Item = Polynomial<F>>>(iter: I) -> Self {
1114        let polynomials = iter.collect::<Vec<_>>();
1115        Polynomial::multiply_batch(polynomials.iter())
1116    }
1117}
1118
1119impl<'a, F: PrimeField> Product<&'a Polynomial<F>> for Polynomial<F> {
1120    fn product<I: Iterator<Item = &'a Polynomial<F>>>(iter: I) -> Self {
1121        let polynomials = iter.collect::<Vec<_>>();
1122        Polynomial::multiply_batch(polynomials)
1123    }
1124}
1125
1126#[cfg(test)]
1127mod tests {
1128    use starkom_bluesky::{Scalar, from_const};
1129    use starkom_ff::{Field, PrimeField};
1130
1131    type Polynomial = super::Polynomial<Scalar>;
1132
1133    #[inline(always)]
1134    fn get_random_scalar() -> Scalar {
1135        Scalar::random_default()
1136    }
1137
1138    fn from_roots(roots: &[Scalar]) -> Polynomial {
1139        Polynomial::from_roots(roots, get_random_scalar()).unwrap()
1140    }
1141
1142    #[test]
1143    fn test_constant() {
1144        let p = Polynomial::constant(from_const(42));
1145        assert_eq!(p.evaluate(from_const(12)), from_const(42));
1146        assert_eq!(p.evaluate(from_const(34)), from_const(42));
1147        assert_eq!(p.evaluate(from_const(42)), from_const(42));
1148    }
1149
1150    #[test]
1151    fn test_zero() {
1152        let p = Polynomial::with_coefficients(vec![]);
1153        assert_eq!(p, Polynomial::default());
1154        assert_eq!(p.len(), 0);
1155        assert_eq!(p.degree_bound(), 0);
1156        assert_eq!(p.evaluate(from_const(42)), from_const(0));
1157    }
1158
1159    #[test]
1160    fn test_with_coefficients() {
1161        let p = Polynomial::with_coefficients(vec![from_const(12), from_const(34), from_const(56)]);
1162        assert_eq!(p.len(), 3);
1163        assert_eq!(p.degree_bound(), 3);
1164        assert_eq!(
1165            p.take(),
1166            vec![from_const(12), from_const(34), from_const(56)]
1167        );
1168    }
1169
1170    #[test]
1171    fn test_low_degree() {
1172        let p = Polynomial::with_coefficients(vec![
1173            from_const(12),
1174            from_const(34),
1175            from_const(56),
1176            from_const(0),
1177            from_const(0),
1178        ]);
1179        assert_eq!(p.len(), 5);
1180        assert_eq!(p.degree_bound(), 3);
1181    }
1182
1183    #[test]
1184    fn test_skip_degree() {
1185        let p = Polynomial::with_coefficients(vec![
1186            from_const(0),
1187            from_const(0),
1188            from_const(12),
1189            from_const(34),
1190            from_const(56),
1191        ]);
1192        assert_eq!(p.len(), 5);
1193        assert_eq!(p.degree_bound(), 5);
1194    }
1195
1196    #[test]
1197    fn test_trim_degree() {
1198        let mut p = Polynomial::with_coefficients(vec![
1199            from_const(12),
1200            from_const(34),
1201            from_const(56),
1202            from_const(0),
1203            from_const(0),
1204        ]);
1205        p = p.trim();
1206        assert_eq!(p.len(), 3);
1207        assert_eq!(p.degree_bound(), 3);
1208    }
1209
1210    #[test]
1211    fn test_no_trim() {
1212        let mut p = Polynomial::with_coefficients(vec![
1213            from_const(0),
1214            from_const(0),
1215            from_const(12),
1216            from_const(34),
1217            from_const(56),
1218        ]);
1219        p = p.trim();
1220        assert_eq!(p.len(), 5);
1221        assert_eq!(p.degree_bound(), 5);
1222    }
1223
1224    #[test]
1225    fn test_trim_all_zero() {
1226        let mut p =
1227            Polynomial::with_coefficients(vec![from_const(0), from_const(0), from_const(0)]);
1228        p = p.trim();
1229        assert_eq!(p.len(), p.degree_bound());
1230        assert_eq!(p, Polynomial::default());
1231    }
1232
1233    #[test]
1234    fn test_pad_extends() {
1235        let mut p = Polynomial::with_coefficients(vec![from_const(12), from_const(34)]);
1236        p = p.pad(5);
1237        assert_eq!(p.len(), 5);
1238        assert_eq!(
1239            p.take(),
1240            vec![
1241                from_const(12),
1242                from_const(34),
1243                from_const(0),
1244                from_const(0),
1245                from_const(0)
1246            ]
1247        );
1248    }
1249
1250    #[test]
1251    fn test_pad_exact() {
1252        let mut p =
1253            Polynomial::with_coefficients(vec![from_const(12), from_const(34), from_const(56)]);
1254        p = p.pad(3);
1255        assert_eq!(p.len(), 3);
1256        assert_eq!(
1257            p.take(),
1258            vec![from_const(12), from_const(34), from_const(56)]
1259        );
1260    }
1261
1262    #[test]
1263    fn test_pad_no_shrink() {
1264        let mut p = Polynomial::with_coefficients(vec![
1265            from_const(12),
1266            from_const(34),
1267            from_const(56),
1268            from_const(78),
1269        ]);
1270        p = p.pad(2);
1271        assert_eq!(p.len(), 4);
1272        assert_eq!(
1273            p.take(),
1274            vec![
1275                from_const(12),
1276                from_const(34),
1277                from_const(56),
1278                from_const(78)
1279            ]
1280        );
1281    }
1282
1283    #[test]
1284    fn test_pad_empty() {
1285        let mut p = Polynomial::default();
1286        p = p.pad(3);
1287        assert_eq!(p.len(), 3);
1288        assert_eq!(p.take(), vec![from_const(0), from_const(0), from_const(0)]);
1289    }
1290
1291    #[test]
1292    fn test_pad_zero_bound() {
1293        let mut p = Polynomial::with_coefficients(vec![from_const(12), from_const(34)]);
1294        p = p.pad(0);
1295        assert_eq!(p.len(), 2);
1296        assert_eq!(p.take(), vec![from_const(12), from_const(34)]);
1297    }
1298
1299    #[test]
1300    fn test_pad_preserves_evaluation() {
1301        let mut p =
1302            Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
1303        let before = p.evaluate(from_const(7));
1304        p = p.pad(6);
1305        assert_eq!(p.evaluate(from_const(7)), before);
1306    }
1307
1308    #[test]
1309    fn test_no_roots() {
1310        let p = from_roots(&[]);
1311        assert_eq!(p.len(), 1);
1312        assert_eq!(p.degree_bound(), 1);
1313        assert_ne!(p.evaluate(from_const(12)), from_const(0));
1314        assert_ne!(p.evaluate(from_const(34)), from_const(0));
1315        assert_ne!(p.evaluate(from_const(56)), from_const(0));
1316        assert_ne!(p.evaluate(from_const(78)), from_const(0));
1317        assert_ne!(p.evaluate(from_const(90)), from_const(0));
1318        assert_ne!(p.evaluate(from_const(13)), from_const(0));
1319        assert_ne!(p.evaluate(from_const(57)), from_const(0));
1320        assert_ne!(p.evaluate(from_const(92)), from_const(0));
1321        assert_ne!(p.evaluate(from_const(46)), from_const(0));
1322        assert_ne!(p.evaluate(from_const(80)), from_const(0));
1323    }
1324
1325    #[test]
1326    fn test_one_root() {
1327        let p = from_roots(&[from_const(12)]);
1328        assert_eq!(p.len(), 2);
1329        assert_eq!(p.degree_bound(), 2);
1330        assert_eq!(p.evaluate(from_const(12)), from_const(0));
1331        assert_ne!(p.evaluate(from_const(34)), from_const(0));
1332        assert_ne!(p.evaluate(from_const(56)), from_const(0));
1333        assert_ne!(p.evaluate(from_const(78)), from_const(0));
1334        assert_ne!(p.evaluate(from_const(90)), from_const(0));
1335        assert_ne!(p.evaluate(from_const(13)), from_const(0));
1336        assert_ne!(p.evaluate(from_const(57)), from_const(0));
1337        assert_ne!(p.evaluate(from_const(92)), from_const(0));
1338        assert_ne!(p.evaluate(from_const(46)), from_const(0));
1339        assert_ne!(p.evaluate(from_const(80)), from_const(0));
1340        let (q, v) = p.horner(from_const(12));
1341        assert_eq!(q.len(), 1);
1342        assert_eq!(q.degree_bound(), 1);
1343        assert_eq!(v, from_const(0));
1344        let (q, v) = p.horner(from_const(34));
1345        assert_eq!(q.len(), 1);
1346        assert_eq!(q.degree_bound(), 1);
1347        assert_ne!(v, from_const(0));
1348    }
1349
1350    #[test]
1351    fn test_three_roots() {
1352        let p = from_roots(&[from_const(12), from_const(34), from_const(56)]);
1353        assert_eq!(p.len(), 4);
1354        assert_eq!(p.degree_bound(), 4);
1355        assert_eq!(p.evaluate(from_const(12)), from_const(0));
1356        assert_eq!(p.evaluate(from_const(34)), from_const(0));
1357        assert_eq!(p.evaluate(from_const(56)), from_const(0));
1358        assert_ne!(p.evaluate(from_const(78)), from_const(0));
1359        assert_ne!(p.evaluate(from_const(90)), from_const(0));
1360        assert_ne!(p.evaluate(from_const(13)), from_const(0));
1361        assert_ne!(p.evaluate(from_const(57)), from_const(0));
1362        assert_ne!(p.evaluate(from_const(92)), from_const(0));
1363        assert_ne!(p.evaluate(from_const(46)), from_const(0));
1364        assert_ne!(p.evaluate(from_const(80)), from_const(0));
1365        let (q, v) = p.horner(from_const(12));
1366        assert_eq!(q.len(), 3);
1367        assert_eq!(q.degree_bound(), 3);
1368        assert_eq!(v, from_const(0));
1369        let (q, v) = q.horner(from_const(34));
1370        assert_eq!(q.len(), 2);
1371        assert_eq!(q.degree_bound(), 2);
1372        assert_eq!(v, from_const(0));
1373        let (q, v) = q.horner(from_const(56));
1374        assert_eq!(q.len(), 1);
1375        assert_eq!(q.degree_bound(), 1);
1376        assert_eq!(v, from_const(0));
1377        let (q, v) = p.horner(from_const(78));
1378        assert_eq!(q.len(), 3);
1379        assert_eq!(q.degree_bound(), 3);
1380        assert_ne!(v, from_const(0));
1381        let (q, v) = p.horner(from_const(90));
1382        assert_eq!(q.len(), 3);
1383        assert_eq!(q.degree_bound(), 3);
1384        assert_ne!(v, from_const(0));
1385    }
1386
1387    #[test]
1388    fn test_three_roots_reverse_order() {
1389        let p = from_roots(&[from_const(56), from_const(34), from_const(12)]);
1390        assert_eq!(p.len(), 4);
1391        assert_eq!(p.degree_bound(), 4);
1392        assert_eq!(p.evaluate(from_const(12)), from_const(0));
1393        assert_eq!(p.evaluate(from_const(34)), from_const(0));
1394        assert_eq!(p.evaluate(from_const(56)), from_const(0));
1395        assert_ne!(p.evaluate(from_const(78)), from_const(0));
1396        assert_ne!(p.evaluate(from_const(90)), from_const(0));
1397        assert_ne!(p.evaluate(from_const(13)), from_const(0));
1398        assert_ne!(p.evaluate(from_const(57)), from_const(0));
1399        assert_ne!(p.evaluate(from_const(92)), from_const(0));
1400        assert_ne!(p.evaluate(from_const(46)), from_const(0));
1401        assert_ne!(p.evaluate(from_const(80)), from_const(0));
1402        let (q, v) = p.horner(from_const(12));
1403        assert_eq!(q.len(), 3);
1404        assert_eq!(q.degree_bound(), 3);
1405        assert_eq!(v, from_const(0));
1406        let (q, v) = q.horner(from_const(34));
1407        assert_eq!(q.len(), 2);
1408        assert_eq!(q.degree_bound(), 2);
1409        assert_eq!(v, from_const(0));
1410        let (q, v) = q.horner(from_const(56));
1411        assert_eq!(q.len(), 1);
1412        assert_eq!(q.degree_bound(), 1);
1413        assert_eq!(v, from_const(0));
1414        let (q, v) = p.horner(from_const(78));
1415        assert_eq!(q.len(), 3);
1416        assert_eq!(q.degree_bound(), 3);
1417        assert_ne!(v, from_const(0));
1418        let (q, v) = p.horner(from_const(90));
1419        assert_eq!(q.len(), 3);
1420        assert_eq!(q.degree_bound(), 3);
1421        assert_ne!(v, from_const(0));
1422    }
1423
1424    #[test]
1425    fn test_seven_roots() {
1426        let p = from_roots(&[
1427            from_const(12),
1428            from_const(34),
1429            from_const(56),
1430            from_const(78),
1431            from_const(90),
1432            from_const(13),
1433            from_const(57),
1434        ]);
1435        assert_eq!(p.len(), 8);
1436        assert_eq!(p.degree_bound(), 8);
1437        assert_eq!(p.evaluate(from_const(12)), from_const(0));
1438        assert_eq!(p.evaluate(from_const(34)), from_const(0));
1439        assert_eq!(p.evaluate(from_const(56)), from_const(0));
1440        assert_eq!(p.evaluate(from_const(78)), from_const(0));
1441        assert_eq!(p.evaluate(from_const(90)), from_const(0));
1442        assert_eq!(p.evaluate(from_const(13)), from_const(0));
1443        assert_eq!(p.evaluate(from_const(57)), from_const(0));
1444        assert_ne!(p.evaluate(from_const(92)), from_const(0));
1445        assert_ne!(p.evaluate(from_const(46)), from_const(0));
1446        assert_ne!(p.evaluate(from_const(80)), from_const(0));
1447    }
1448
1449    #[test]
1450    fn test_seven_roots_reverse_order() {
1451        let p = from_roots(&[
1452            from_const(57),
1453            from_const(13),
1454            from_const(90),
1455            from_const(78),
1456            from_const(56),
1457            from_const(34),
1458            from_const(12),
1459        ]);
1460        assert_eq!(p.len(), 8);
1461        assert_eq!(p.degree_bound(), 8);
1462        assert_eq!(p.evaluate(from_const(12)), from_const(0));
1463        assert_eq!(p.evaluate(from_const(34)), from_const(0));
1464        assert_eq!(p.evaluate(from_const(56)), from_const(0));
1465        assert_eq!(p.evaluate(from_const(78)), from_const(0));
1466        assert_eq!(p.evaluate(from_const(90)), from_const(0));
1467        assert_eq!(p.evaluate(from_const(13)), from_const(0));
1468        assert_eq!(p.evaluate(from_const(57)), from_const(0));
1469        assert_ne!(p.evaluate(from_const(92)), from_const(0));
1470        assert_ne!(p.evaluate(from_const(46)), from_const(0));
1471        assert_ne!(p.evaluate(from_const(80)), from_const(0));
1472    }
1473
1474    #[test]
1475    fn test_duplicate_roots() {
1476        assert!(
1477            Polynomial::from_roots(
1478                &[
1479                    from_const(12),
1480                    from_const(34),
1481                    from_const(56),
1482                    from_const(12),
1483                    from_const(90),
1484                    from_const(12),
1485                    from_const(57),
1486                ],
1487                get_random_scalar()
1488            )
1489            .is_err()
1490        );
1491    }
1492
1493    #[test]
1494    fn test_interpolate_zero_points() {
1495        let p = Polynomial::interpolate(&[]).unwrap();
1496        assert_eq!(p, Polynomial::default());
1497    }
1498
1499    #[test]
1500    fn test_interpolate_one_point1() {
1501        let p = Polynomial::interpolate(&[(from_const(12), from_const(34))]).unwrap();
1502        assert_eq!(p.len(), 1);
1503        assert_eq!(p.degree_bound(), 1);
1504        assert_eq!(p.evaluate(from_const(12)), from_const(34));
1505    }
1506
1507    #[test]
1508    fn test_interpolate_one_point2() {
1509        let p = Polynomial::interpolate(&[(from_const(34), from_const(56))]).unwrap();
1510        assert_eq!(p.len(), 1);
1511        assert_eq!(p.degree_bound(), 1);
1512        assert_eq!(p.evaluate(from_const(34)), from_const(56));
1513    }
1514
1515    #[test]
1516    fn test_interpolate_two_points1() {
1517        let p = Polynomial::interpolate(&[
1518            (from_const(12), from_const(34)),
1519            (from_const(56), from_const(78)),
1520        ])
1521        .unwrap();
1522        assert_eq!(p.len(), 2);
1523        assert_eq!(p.degree_bound(), 2);
1524        assert_eq!(p.evaluate(from_const(12)), from_const(34));
1525        assert_eq!(p.evaluate(from_const(56)), from_const(78));
1526    }
1527
1528    #[test]
1529    fn test_interpolate_two_points2() {
1530        let p = Polynomial::interpolate(&[
1531            (from_const(34), from_const(12)),
1532            (from_const(78), from_const(56)),
1533        ])
1534        .unwrap();
1535        assert_eq!(p.len(), 2);
1536        assert_eq!(p.degree_bound(), 2);
1537        assert_eq!(p.evaluate(from_const(34)), from_const(12));
1538        assert_eq!(p.evaluate(from_const(78)), from_const(56));
1539    }
1540
1541    #[test]
1542    fn test_interpolate_three_points1() {
1543        let p = Polynomial::interpolate(&[
1544            (from_const(12), from_const(34)),
1545            (from_const(56), from_const(78)),
1546            (from_const(90), from_const(12)),
1547        ])
1548        .unwrap();
1549        assert_eq!(p.len(), 3);
1550        assert_eq!(p.degree_bound(), 3);
1551        assert_eq!(p.evaluate(from_const(12)), from_const(34));
1552        assert_eq!(p.evaluate(from_const(56)), from_const(78));
1553        assert_eq!(p.evaluate(from_const(90)), from_const(12));
1554    }
1555
1556    #[test]
1557    fn test_interpolate_three_points2() {
1558        let p = Polynomial::interpolate(&[
1559            (from_const(34), from_const(12)),
1560            (from_const(78), from_const(56)),
1561            (from_const(12), from_const(90)),
1562        ])
1563        .unwrap();
1564        assert_eq!(p.len(), 3);
1565        assert_eq!(p.degree_bound(), 3);
1566        assert_eq!(p.evaluate(from_const(34)), from_const(12));
1567        assert_eq!(p.evaluate(from_const(78)), from_const(56));
1568        assert_eq!(p.evaluate(from_const(12)), from_const(90));
1569    }
1570
1571    #[test]
1572    fn test_duplicate_coordinates() {
1573        assert!(
1574            Polynomial::interpolate(&[
1575                (from_const(12), from_const(34)),
1576                (from_const(56), from_const(78)),
1577                (from_const(12), from_const(90)),
1578            ])
1579            .is_err()
1580        );
1581    }
1582
1583    #[test]
1584    fn test_encode2_one_value_1() {
1585        let p1 = Polynomial::encode2(vec![from_const(42)]);
1586        let p2 = Polynomial::encode2(vec![from_const(42)]);
1587        assert_eq!(p1, p2);
1588        assert_eq!(p1.len(), 1);
1589        assert_eq!(p1.degree_bound(), 1);
1590        assert_eq!(p2.len(), 1);
1591        assert_eq!(p2.degree_bound(), 1);
1592        assert_eq!(
1593            p1.evaluate(Polynomial::domain_element2(0, 1)),
1594            from_const(42)
1595        );
1596        assert_eq!(p1.evaluate_on_two_adic_domain(0, 1), from_const(42));
1597        assert_eq!(
1598            p2.evaluate(Polynomial::domain_element2(0, 1)),
1599            from_const(42)
1600        );
1601        assert_eq!(p2.evaluate_on_two_adic_domain(0, 1), from_const(42));
1602    }
1603
1604    #[test]
1605    fn test_encode2_one_value_2() {
1606        let p1 = Polynomial::encode2(vec![from_const(42)]);
1607        let p2 = Polynomial::encode2(vec![from_const(123)]);
1608        assert_eq!(p2.len(), 1);
1609        assert_eq!(p2.degree_bound(), 1);
1610        assert_ne!(p1, p2);
1611        assert_eq!(
1612            p2.evaluate(Polynomial::domain_element2(0, 1)),
1613            from_const(123)
1614        );
1615        assert_eq!(p2.evaluate_on_two_adic_domain(0, 1), from_const(123));
1616    }
1617
1618    #[test]
1619    fn test_encode2_two_values_1() {
1620        let p1 = Polynomial::encode2(vec![from_const(12), from_const(34)]);
1621        let p2 = Polynomial::encode2(vec![from_const(12), from_const(34)]);
1622        assert_eq!(p1, p2);
1623        assert_eq!(p1.len(), 2);
1624        assert_eq!(p1.degree_bound(), 2);
1625        assert_eq!(p2.len(), 2);
1626        assert_eq!(p2.degree_bound(), 2);
1627        assert_eq!(
1628            p1.evaluate(Polynomial::domain_element2(0, 2)),
1629            from_const(12)
1630        );
1631        assert_eq!(p1.evaluate_on_two_adic_domain(0, 2), from_const(12));
1632        assert_eq!(
1633            p1.evaluate(Polynomial::domain_element2(1, 2)),
1634            from_const(34)
1635        );
1636        assert_eq!(p1.evaluate_on_two_adic_domain(1, 2), from_const(34));
1637        assert_eq!(
1638            p2.evaluate(Polynomial::domain_element2(0, 2)),
1639            from_const(12)
1640        );
1641        assert_eq!(p2.evaluate_on_two_adic_domain(0, 2), from_const(12));
1642        assert_eq!(
1643            p2.evaluate(Polynomial::domain_element2(1, 2)),
1644            from_const(34)
1645        );
1646        assert_eq!(p2.evaluate_on_two_adic_domain(1, 2), from_const(34));
1647    }
1648
1649    #[test]
1650    fn test_encode2_two_values_2() {
1651        let p1 = Polynomial::encode2(vec![from_const(12), from_const(34)]);
1652        let p2 = Polynomial::encode2(vec![from_const(78), from_const(56)]);
1653        assert_eq!(p1.len(), 2);
1654        assert_eq!(p1.degree_bound(), 2);
1655        assert_eq!(p2.len(), 2);
1656        assert_eq!(p2.degree_bound(), 2);
1657        assert_ne!(p1, p2);
1658        assert_eq!(
1659            p2.evaluate(Polynomial::domain_element2(0, 2)),
1660            from_const(78)
1661        );
1662        assert_eq!(p2.evaluate_on_two_adic_domain(0, 2), from_const(78));
1663        assert_eq!(
1664            p2.evaluate(Polynomial::domain_element2(1, 2)),
1665            from_const(56)
1666        );
1667        assert_eq!(p2.evaluate_on_two_adic_domain(1, 2), from_const(56));
1668    }
1669
1670    #[test]
1671    fn test_encode2_three_values_1() {
1672        let p1 = Polynomial::encode2(vec![from_const(12), from_const(34), from_const(56)]);
1673        let p2 = Polynomial::encode2(vec![from_const(12), from_const(34), from_const(56)]);
1674        assert_eq!(p1, p2);
1675        assert_eq!(p1.len(), 4);
1676        assert_eq!(p1.degree_bound(), 4);
1677        assert_eq!(p2.len(), 4);
1678        assert_eq!(p2.degree_bound(), 4);
1679        assert_eq!(
1680            p1.evaluate(Polynomial::domain_element2(0, 3)),
1681            from_const(12)
1682        );
1683        assert_eq!(p1.evaluate_on_two_adic_domain(0, 3), from_const(12));
1684        assert_eq!(
1685            p1.evaluate(Polynomial::domain_element2(0, 4)),
1686            from_const(12)
1687        );
1688        assert_eq!(p1.evaluate_on_two_adic_domain(0, 4), from_const(12));
1689        assert_eq!(
1690            p1.evaluate(Polynomial::domain_element2(1, 3)),
1691            from_const(34)
1692        );
1693        assert_eq!(p1.evaluate_on_two_adic_domain(1, 3), from_const(34));
1694        assert_eq!(
1695            p1.evaluate(Polynomial::domain_element2(1, 4)),
1696            from_const(34)
1697        );
1698        assert_eq!(p1.evaluate_on_two_adic_domain(1, 4), from_const(34));
1699        assert_eq!(
1700            p1.evaluate(Polynomial::domain_element2(2, 3)),
1701            from_const(56)
1702        );
1703        assert_eq!(p1.evaluate_on_two_adic_domain(2, 3), from_const(56));
1704        assert_eq!(
1705            p1.evaluate(Polynomial::domain_element2(2, 4)),
1706            from_const(56)
1707        );
1708        assert_eq!(p1.evaluate_on_two_adic_domain(2, 4), from_const(56));
1709        assert_eq!(
1710            p1.evaluate(Polynomial::domain_element2(3, 4)),
1711            from_const(0)
1712        );
1713        assert_eq!(p1.evaluate_on_two_adic_domain(3, 4), from_const(0));
1714        assert_eq!(
1715            p2.evaluate(Polynomial::domain_element2(0, 3)),
1716            from_const(12)
1717        );
1718        assert_eq!(p2.evaluate_on_two_adic_domain(0, 3), from_const(12));
1719        assert_eq!(
1720            p2.evaluate(Polynomial::domain_element2(0, 4)),
1721            from_const(12)
1722        );
1723        assert_eq!(p2.evaluate_on_two_adic_domain(0, 4), from_const(12));
1724        assert_eq!(
1725            p2.evaluate(Polynomial::domain_element2(1, 3)),
1726            from_const(34)
1727        );
1728        assert_eq!(p2.evaluate_on_two_adic_domain(1, 3), from_const(34));
1729        assert_eq!(
1730            p2.evaluate(Polynomial::domain_element2(1, 4)),
1731            from_const(34)
1732        );
1733        assert_eq!(p2.evaluate_on_two_adic_domain(1, 4), from_const(34));
1734        assert_eq!(
1735            p2.evaluate(Polynomial::domain_element2(2, 3)),
1736            from_const(56)
1737        );
1738        assert_eq!(p2.evaluate_on_two_adic_domain(2, 3), from_const(56));
1739        assert_eq!(
1740            p2.evaluate(Polynomial::domain_element2(2, 4)),
1741            from_const(56)
1742        );
1743        assert_eq!(p2.evaluate_on_two_adic_domain(2, 4), from_const(56));
1744        assert_eq!(
1745            p2.evaluate(Polynomial::domain_element2(3, 4)),
1746            from_const(0)
1747        );
1748        assert_eq!(p2.evaluate_on_two_adic_domain(3, 4), from_const(0));
1749    }
1750
1751    #[test]
1752    fn test_encode2_three_values_2() {
1753        let p1 = Polynomial::encode2(vec![from_const(12), from_const(34), from_const(56)]);
1754        let p2 = Polynomial::encode2(vec![from_const(90), from_const(78), from_const(34)]);
1755        assert_eq!(p1.len(), 4);
1756        assert_eq!(p1.degree_bound(), 4);
1757        assert_eq!(p2.len(), 4);
1758        assert_eq!(p2.degree_bound(), 4);
1759        assert_ne!(p1, p2);
1760        assert_eq!(
1761            p2.evaluate(Polynomial::domain_element2(0, 3)),
1762            from_const(90)
1763        );
1764        assert_eq!(p2.evaluate_on_two_adic_domain(0, 3), from_const(90));
1765        assert_eq!(
1766            p2.evaluate(Polynomial::domain_element2(0, 4)),
1767            from_const(90)
1768        );
1769        assert_eq!(p2.evaluate_on_two_adic_domain(0, 4), from_const(90));
1770        assert_eq!(
1771            p2.evaluate(Polynomial::domain_element2(1, 3)),
1772            from_const(78)
1773        );
1774        assert_eq!(p2.evaluate_on_two_adic_domain(1, 3), from_const(78));
1775        assert_eq!(
1776            p2.evaluate(Polynomial::domain_element2(1, 4)),
1777            from_const(78)
1778        );
1779        assert_eq!(p2.evaluate_on_two_adic_domain(1, 4), from_const(78));
1780        assert_eq!(
1781            p2.evaluate(Polynomial::domain_element2(2, 3)),
1782            from_const(34)
1783        );
1784        assert_eq!(p2.evaluate_on_two_adic_domain(2, 3), from_const(34));
1785        assert_eq!(
1786            p2.evaluate(Polynomial::domain_element2(2, 4)),
1787            from_const(34)
1788        );
1789        assert_eq!(p2.evaluate_on_two_adic_domain(2, 4), from_const(34));
1790        assert_eq!(
1791            p2.evaluate(Polynomial::domain_element2(3, 4)),
1792            from_const(0)
1793        );
1794        assert_eq!(p2.evaluate_on_two_adic_domain(3, 4), from_const(0));
1795    }
1796
1797    #[test]
1798    fn test_encode2_four_values() {
1799        let p = Polynomial::encode2(vec![
1800            from_const(12),
1801            from_const(34),
1802            from_const(56),
1803            from_const(78),
1804        ]);
1805        assert_eq!(p.len(), 4);
1806        assert_eq!(p.degree_bound(), 4);
1807        assert_eq!(
1808            p.evaluate(Polynomial::domain_element2(0, 4)),
1809            from_const(12)
1810        );
1811        assert_eq!(p.evaluate_on_two_adic_domain(0, 4), from_const(12));
1812        assert_eq!(
1813            p.evaluate(Polynomial::domain_element2(1, 4)),
1814            from_const(34)
1815        );
1816        assert_eq!(p.evaluate_on_two_adic_domain(1, 4), from_const(34));
1817        assert_eq!(
1818            p.evaluate(Polynomial::domain_element2(2, 4)),
1819            from_const(56)
1820        );
1821        assert_eq!(p.evaluate_on_two_adic_domain(2, 4), from_const(56));
1822        assert_eq!(
1823            p.evaluate(Polynomial::domain_element2(3, 4)),
1824            from_const(78)
1825        );
1826        assert_eq!(p.evaluate_on_two_adic_domain(3, 4), from_const(78));
1827    }
1828
1829    #[test]
1830    fn test_decode2_one_value() {
1831        let values = vec![from_const(42)];
1832        let polynomial = Polynomial::encode2(values.clone());
1833        assert_eq!(polynomial.decode2(), values);
1834    }
1835
1836    #[test]
1837    fn test_decode2_two_values() {
1838        let values = vec![from_const(12), from_const(34)];
1839        let polynomial = Polynomial::encode2(values.clone());
1840        assert_eq!(polynomial.decode2(), values);
1841    }
1842
1843    #[test]
1844    fn test_decode2_three_values() {
1845        let polynomial = Polynomial::encode2(vec![from_const(12), from_const(34), from_const(56)]);
1846        assert_eq!(
1847            polynomial.decode2(),
1848            vec![
1849                from_const(12),
1850                from_const(34),
1851                from_const(56),
1852                from_const(0)
1853            ]
1854        );
1855    }
1856
1857    #[test]
1858    fn test_decode2_four_values() {
1859        let values = vec![
1860            from_const(12),
1861            from_const(34),
1862            from_const(56),
1863            from_const(78),
1864        ];
1865        let polynomial = Polynomial::encode2(values.clone());
1866        assert_eq!(polynomial.decode2(), values);
1867    }
1868
1869    #[test]
1870    fn test_encode3_one_value_1() {
1871        let p1 = Polynomial::encode3(vec![from_const(42)]);
1872        let p2 = Polynomial::encode3(vec![from_const(42)]);
1873        assert_eq!(p1, p2);
1874        assert_eq!(p1.len(), 1);
1875        assert_eq!(p1.degree_bound(), 1);
1876        assert_eq!(p2.len(), 1);
1877        assert_eq!(p2.degree_bound(), 1);
1878        assert_eq!(
1879            p1.evaluate(Polynomial::domain_element3(0, 1)),
1880            from_const(42)
1881        );
1882        assert_eq!(p1.evaluate_on_three_adic_domain(0, 1), from_const(42));
1883        assert_eq!(
1884            p2.evaluate(Polynomial::domain_element3(0, 1)),
1885            from_const(42)
1886        );
1887        assert_eq!(p2.evaluate_on_three_adic_domain(0, 1), from_const(42));
1888    }
1889
1890    #[test]
1891    fn test_encode3_one_value_2() {
1892        let p1 = Polynomial::encode3(vec![from_const(42)]);
1893        let p2 = Polynomial::encode3(vec![from_const(123)]);
1894        assert_eq!(p2.len(), 1);
1895        assert_eq!(p2.degree_bound(), 1);
1896        assert_ne!(p1, p2);
1897        assert_eq!(
1898            p2.evaluate(Polynomial::domain_element3(0, 1)),
1899            from_const(123)
1900        );
1901        assert_eq!(p2.evaluate_on_three_adic_domain(0, 1), from_const(123));
1902    }
1903
1904    #[test]
1905    fn test_encode3_two_values_1() {
1906        let p1 = Polynomial::encode3(vec![from_const(12), from_const(34)]);
1907        let p2 = Polynomial::encode3(vec![from_const(12), from_const(34)]);
1908        assert_eq!(p1, p2);
1909        assert_eq!(p1.len(), 3);
1910        assert_eq!(p1.degree_bound(), 3);
1911        assert_eq!(p2.len(), 3);
1912        assert_eq!(p2.degree_bound(), 3);
1913        assert_eq!(
1914            p1.evaluate(Polynomial::domain_element3(0, 2)),
1915            from_const(12)
1916        );
1917        assert_eq!(p1.evaluate_on_three_adic_domain(0, 2), from_const(12));
1918        assert_eq!(
1919            p1.evaluate(Polynomial::domain_element3(0, 3)),
1920            from_const(12)
1921        );
1922        assert_eq!(p1.evaluate_on_three_adic_domain(0, 3), from_const(12));
1923        assert_eq!(
1924            p1.evaluate(Polynomial::domain_element3(1, 2)),
1925            from_const(34)
1926        );
1927        assert_eq!(p1.evaluate_on_three_adic_domain(1, 2), from_const(34));
1928        assert_eq!(
1929            p1.evaluate(Polynomial::domain_element3(1, 3)),
1930            from_const(34)
1931        );
1932        assert_eq!(p1.evaluate_on_three_adic_domain(1, 3), from_const(34));
1933        assert_eq!(
1934            p1.evaluate(Polynomial::domain_element3(2, 3)),
1935            from_const(0)
1936        );
1937        assert_eq!(p1.evaluate_on_three_adic_domain(2, 3), from_const(0));
1938        assert_eq!(
1939            p2.evaluate(Polynomial::domain_element3(0, 2)),
1940            from_const(12)
1941        );
1942        assert_eq!(p2.evaluate_on_three_adic_domain(0, 2), from_const(12));
1943        assert_eq!(
1944            p2.evaluate(Polynomial::domain_element3(0, 3)),
1945            from_const(12)
1946        );
1947        assert_eq!(p2.evaluate_on_three_adic_domain(0, 3), from_const(12));
1948        assert_eq!(
1949            p2.evaluate(Polynomial::domain_element3(1, 2)),
1950            from_const(34)
1951        );
1952        assert_eq!(p2.evaluate_on_three_adic_domain(1, 2), from_const(34));
1953        assert_eq!(
1954            p2.evaluate(Polynomial::domain_element3(1, 3)),
1955            from_const(34)
1956        );
1957        assert_eq!(p2.evaluate_on_three_adic_domain(1, 3), from_const(34));
1958        assert_eq!(
1959            p2.evaluate(Polynomial::domain_element3(2, 3)),
1960            from_const(0)
1961        );
1962        assert_eq!(p2.evaluate_on_three_adic_domain(2, 3), from_const(0));
1963    }
1964
1965    #[test]
1966    fn test_encode3_two_values_2() {
1967        let p1 = Polynomial::encode3(vec![from_const(12), from_const(34)]);
1968        let p2 = Polynomial::encode3(vec![from_const(78), from_const(56)]);
1969        assert_eq!(p1.len(), 3);
1970        assert_eq!(p1.degree_bound(), 3);
1971        assert_eq!(p2.len(), 3);
1972        assert_eq!(p2.degree_bound(), 3);
1973        assert_ne!(p1, p2);
1974        assert_eq!(
1975            p2.evaluate(Polynomial::domain_element3(0, 2)),
1976            from_const(78)
1977        );
1978        assert_eq!(p2.evaluate_on_three_adic_domain(0, 2), from_const(78));
1979        assert_eq!(
1980            p2.evaluate(Polynomial::domain_element3(1, 2)),
1981            from_const(56)
1982        );
1983        assert_eq!(p2.evaluate_on_three_adic_domain(1, 2), from_const(56));
1984        assert_eq!(
1985            p2.evaluate(Polynomial::domain_element3(2, 3)),
1986            from_const(0)
1987        );
1988        assert_eq!(p2.evaluate_on_three_adic_domain(2, 3), from_const(0));
1989    }
1990
1991    #[test]
1992    fn test_encode3_three_values_1() {
1993        let p1 = Polynomial::encode3(vec![from_const(12), from_const(34), from_const(56)]);
1994        let p2 = Polynomial::encode3(vec![from_const(12), from_const(34), from_const(56)]);
1995        assert_eq!(p1, p2);
1996        assert_eq!(p1.len(), 3);
1997        assert_eq!(p1.degree_bound(), 3);
1998        assert_eq!(p2.len(), 3);
1999        assert_eq!(p2.degree_bound(), 3);
2000        assert_eq!(
2001            p1.evaluate(Polynomial::domain_element3(0, 3)),
2002            from_const(12)
2003        );
2004        assert_eq!(p1.evaluate_on_three_adic_domain(0, 3), from_const(12));
2005        assert_eq!(
2006            p1.evaluate(Polynomial::domain_element3(1, 3)),
2007            from_const(34)
2008        );
2009        assert_eq!(p1.evaluate_on_three_adic_domain(1, 3), from_const(34));
2010        assert_eq!(
2011            p1.evaluate(Polynomial::domain_element3(2, 3)),
2012            from_const(56)
2013        );
2014        assert_eq!(p1.evaluate_on_three_adic_domain(2, 3), from_const(56));
2015        assert_eq!(
2016            p2.evaluate(Polynomial::domain_element3(0, 3)),
2017            from_const(12)
2018        );
2019        assert_eq!(p2.evaluate_on_three_adic_domain(0, 3), from_const(12));
2020        assert_eq!(
2021            p2.evaluate(Polynomial::domain_element3(1, 3)),
2022            from_const(34)
2023        );
2024        assert_eq!(p2.evaluate_on_three_adic_domain(1, 3), from_const(34));
2025        assert_eq!(
2026            p2.evaluate(Polynomial::domain_element3(2, 3)),
2027            from_const(56)
2028        );
2029        assert_eq!(p2.evaluate_on_three_adic_domain(2, 3), from_const(56));
2030    }
2031
2032    #[test]
2033    fn test_encode3_three_values_2() {
2034        let p1 = Polynomial::encode3(vec![from_const(12), from_const(34), from_const(56)]);
2035        let p2 = Polynomial::encode3(vec![from_const(90), from_const(78), from_const(34)]);
2036        assert_eq!(p1.len(), 3);
2037        assert_eq!(p1.degree_bound(), 3);
2038        assert_eq!(p2.len(), 3);
2039        assert_eq!(p2.degree_bound(), 3);
2040        assert_ne!(p1, p2);
2041        assert_eq!(
2042            p2.evaluate(Polynomial::domain_element3(0, 3)),
2043            from_const(90)
2044        );
2045        assert_eq!(p2.evaluate_on_three_adic_domain(0, 3), from_const(90));
2046        assert_eq!(
2047            p2.evaluate(Polynomial::domain_element3(1, 3)),
2048            from_const(78)
2049        );
2050        assert_eq!(p2.evaluate_on_three_adic_domain(1, 3), from_const(78));
2051        assert_eq!(
2052            p2.evaluate(Polynomial::domain_element3(2, 3)),
2053            from_const(34)
2054        );
2055        assert_eq!(p2.evaluate_on_three_adic_domain(2, 3), from_const(34));
2056    }
2057
2058    #[test]
2059    fn test_encode3_nine_values3() {
2060        let p = Polynomial::encode3(vec![
2061            from_const(12),
2062            from_const(34),
2063            from_const(56),
2064            from_const(78),
2065            from_const(90),
2066            from_const(11),
2067            from_const(22),
2068            from_const(33),
2069            from_const(44),
2070        ]);
2071        assert_eq!(p.len(), 9);
2072        assert_eq!(p.degree_bound(), 9);
2073        assert_eq!(
2074            p.evaluate(Polynomial::domain_element3(0, 9)),
2075            from_const(12)
2076        );
2077        assert_eq!(p.evaluate_on_three_adic_domain(0, 9), from_const(12));
2078        assert_eq!(
2079            p.evaluate(Polynomial::domain_element3(1, 9)),
2080            from_const(34)
2081        );
2082        assert_eq!(p.evaluate_on_three_adic_domain(1, 9), from_const(34));
2083        assert_eq!(
2084            p.evaluate(Polynomial::domain_element3(2, 9)),
2085            from_const(56)
2086        );
2087        assert_eq!(p.evaluate_on_three_adic_domain(2, 9), from_const(56));
2088        assert_eq!(
2089            p.evaluate(Polynomial::domain_element3(3, 9)),
2090            from_const(78)
2091        );
2092        assert_eq!(p.evaluate_on_three_adic_domain(3, 9), from_const(78));
2093        assert_eq!(
2094            p.evaluate(Polynomial::domain_element3(4, 9)),
2095            from_const(90)
2096        );
2097        assert_eq!(p.evaluate_on_three_adic_domain(4, 9), from_const(90));
2098        assert_eq!(
2099            p.evaluate(Polynomial::domain_element3(5, 9)),
2100            from_const(11)
2101        );
2102        assert_eq!(p.evaluate_on_three_adic_domain(5, 9), from_const(11));
2103        assert_eq!(
2104            p.evaluate(Polynomial::domain_element3(6, 9)),
2105            from_const(22)
2106        );
2107        assert_eq!(p.evaluate_on_three_adic_domain(6, 9), from_const(22));
2108        assert_eq!(
2109            p.evaluate(Polynomial::domain_element3(7, 9)),
2110            from_const(33)
2111        );
2112        assert_eq!(p.evaluate_on_three_adic_domain(7, 9), from_const(33));
2113        assert_eq!(
2114            p.evaluate(Polynomial::domain_element3(8, 9)),
2115            from_const(44)
2116        );
2117        assert_eq!(p.evaluate_on_three_adic_domain(8, 9), from_const(44));
2118    }
2119
2120    #[test]
2121    fn test_decode3_one_value() {
2122        let values = vec![from_const(42)];
2123        let polynomial = Polynomial::encode3(values.clone());
2124        assert_eq!(polynomial.decode3(), values);
2125    }
2126
2127    #[test]
2128    fn test_decode3_two_values() {
2129        let values = vec![from_const(12), from_const(34)];
2130        let polynomial = Polynomial::encode3(values.clone());
2131        assert_eq!(
2132            polynomial.decode3(),
2133            vec![from_const(12), from_const(34), from_const(0)]
2134        );
2135    }
2136
2137    #[test]
2138    fn test_decode3_three_values() {
2139        let values = vec![from_const(12), from_const(34), from_const(56)];
2140        let polynomial = Polynomial::encode3(values.clone());
2141        assert_eq!(polynomial.decode3(), values);
2142    }
2143
2144    #[test]
2145    fn test_decode3_nine_values() {
2146        let values = vec![
2147            from_const(12),
2148            from_const(34),
2149            from_const(56),
2150            from_const(78),
2151            from_const(90),
2152            from_const(11),
2153            from_const(22),
2154            from_const(33),
2155            from_const(44),
2156        ];
2157        let polynomial = Polynomial::encode3(values.clone());
2158        assert_eq!(polynomial.decode3(), values);
2159    }
2160
2161    #[test]
2162    fn test_add_same_length() {
2163        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2164        let p2 =
2165            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2166        assert_eq!(
2167            p1 + p2,
2168            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(33)])
2169        );
2170    }
2171
2172    #[test]
2173    fn test_add_lhs_longer() {
2174        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2175        let p2 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2176        assert_eq!(
2177            p1 + p2,
2178            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(3)])
2179        );
2180    }
2181
2182    #[test]
2183    fn test_add_rhs_longer() {
2184        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2185        let p2 =
2186            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2187        assert_eq!(
2188            p1 + p2,
2189            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(30)])
2190        );
2191    }
2192
2193    #[test]
2194    fn test_add_commutative() {
2195        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2196        let p2 =
2197            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2198        assert_eq!(p1.clone() + p2.clone(), p2 + p1);
2199    }
2200
2201    #[test]
2202    fn test_add_ref_same_length() {
2203        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2204        let p2 =
2205            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2206        assert_eq!(
2207            p1 + &p2,
2208            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(33)])
2209        );
2210    }
2211
2212    #[test]
2213    fn test_add_ref_lhs_longer() {
2214        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2215        let p2 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2216        assert_eq!(
2217            p1 + &p2,
2218            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(3)])
2219        );
2220    }
2221
2222    #[test]
2223    fn test_add_ref_rhs_longer() {
2224        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2225        let p2 =
2226            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2227        assert_eq!(
2228            p1 + &p2,
2229            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(30)])
2230        );
2231    }
2232
2233    #[test]
2234    fn test_add_ref_consistent_with_add() {
2235        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2236        let p2 =
2237            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2238        assert_eq!(p1.clone() + &p2, p1 + p2);
2239    }
2240
2241    #[test]
2242    fn test_add_assign_same_length() {
2243        let mut p1 =
2244            Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2245        let p2 =
2246            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2247        p1 += p2;
2248        assert_eq!(
2249            p1,
2250            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(33)])
2251        );
2252    }
2253
2254    #[test]
2255    fn test_add_assign_lhs_longer() {
2256        let mut p1 =
2257            Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2258        let p2 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2259        p1 += p2;
2260        assert_eq!(
2261            p1,
2262            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(3)])
2263        );
2264    }
2265
2266    #[test]
2267    fn test_add_assign_rhs_longer() {
2268        let mut p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2269        let p2 =
2270            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2271        p1 += p2;
2272        assert_eq!(
2273            p1,
2274            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(30)])
2275        );
2276    }
2277
2278    #[test]
2279    fn test_add_assign_consistent_with_add() {
2280        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2281        let p2 =
2282            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2283        let mut p1_assign = p1.clone();
2284        p1_assign += p2.clone();
2285        assert_eq!(p1_assign, p1 + p2);
2286    }
2287
2288    #[test]
2289    fn test_add_assign_ref_same_length() {
2290        let mut p1 =
2291            Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2292        let p2 =
2293            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2294        p1 += &p2;
2295        assert_eq!(
2296            p1,
2297            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(33)])
2298        );
2299    }
2300
2301    #[test]
2302    fn test_add_assign_ref_lhs_longer() {
2303        let mut p1 =
2304            Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2305        let p2 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2306        p1 += &p2;
2307        assert_eq!(
2308            p1,
2309            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(3)])
2310        );
2311    }
2312
2313    #[test]
2314    fn test_add_assign_ref_rhs_longer() {
2315        let mut p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2316        let p2 =
2317            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2318        p1 += &p2;
2319        assert_eq!(
2320            p1,
2321            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(30)])
2322        );
2323    }
2324
2325    #[test]
2326    fn test_add_assign_ref_consistent_with_add_assign() {
2327        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2328        let p2 =
2329            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2330        let mut p1_assign_ref = p1.clone();
2331        p1_assign_ref += &p2;
2332        let mut p1_assign = p1;
2333        p1_assign += p2;
2334        assert_eq!(p1_assign_ref, p1_assign);
2335    }
2336
2337    #[test]
2338    fn test_sum_empty() {
2339        let polynomials: Vec<Polynomial> = vec![];
2340        assert_eq!(
2341            polynomials.into_iter().sum::<Polynomial>(),
2342            Polynomial::default()
2343        );
2344    }
2345
2346    #[test]
2347    fn test_sum_one_polynomial() {
2348        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2349        assert_eq!(vec![p.clone()].into_iter().sum::<Polynomial>(), p);
2350    }
2351
2352    #[test]
2353    fn test_sum_several_polynomials() {
2354        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2355        let p2 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2356        let p3 = Polynomial::with_coefficients(vec![from_const(100)]);
2357        assert_eq!(
2358            vec![p1.clone(), p2.clone(), p3.clone()]
2359                .into_iter()
2360                .sum::<Polynomial>(),
2361            p1 + p2 + p3
2362        );
2363    }
2364
2365    #[test]
2366    fn test_sum_ref_empty() {
2367        let polynomials: Vec<Polynomial> = vec![];
2368        assert_eq!(
2369            polynomials.iter().sum::<Polynomial>(),
2370            Polynomial::default()
2371        );
2372    }
2373
2374    #[test]
2375    fn test_sum_ref_one_polynomial() {
2376        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2377        assert_eq!([p.clone()].iter().sum::<Polynomial>(), p);
2378    }
2379
2380    #[test]
2381    fn test_sum_ref_several_polynomials() {
2382        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2383        let p2 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2384        let p3 = Polynomial::with_coefficients(vec![from_const(100)]);
2385        let polynomials = [p1.clone(), p2.clone(), p3.clone()];
2386        assert_eq!(polynomials.iter().sum::<Polynomial>(), p1 + p2 + p3);
2387    }
2388
2389    #[test]
2390    fn test_sum_ref_consistent_with_sum() {
2391        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2392        let p2 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2393        let polynomials = vec![p1, p2];
2394        assert_eq!(
2395            polynomials.iter().sum::<Polynomial>(),
2396            polynomials.into_iter().sum::<Polynomial>()
2397        );
2398    }
2399
2400    #[test]
2401    fn test_sub_same_length() {
2402        let p1 =
2403            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2404        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2405        assert_eq!(
2406            p1 - p2,
2407            Polynomial::with_coefficients(vec![from_const(9), from_const(18), from_const(27)])
2408        );
2409    }
2410
2411    #[test]
2412    fn test_sub_lhs_longer() {
2413        let p1 =
2414            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2415        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2416        assert_eq!(
2417            p1 - p2,
2418            Polynomial::with_coefficients(vec![from_const(9), from_const(18), from_const(30)])
2419        );
2420    }
2421
2422    #[test]
2423    fn test_sub_rhs_longer() {
2424        let p1 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2425        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2426        assert_eq!(
2427            p1 - p2,
2428            Polynomial::with_coefficients(vec![from_const(9), from_const(18), -from_const(3)])
2429        );
2430    }
2431
2432    #[test]
2433    fn test_sub_anticommutative() {
2434        let p1 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2435        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2436        assert_eq!(p1.clone() - p2.clone(), -(p2 - p1));
2437    }
2438
2439    #[test]
2440    fn test_sub_ref_same_length() {
2441        let p1 =
2442            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2443        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2444        assert_eq!(
2445            p1 - &p2,
2446            Polynomial::with_coefficients(vec![from_const(9), from_const(18), from_const(27)])
2447        );
2448    }
2449
2450    #[test]
2451    fn test_sub_ref_lhs_longer() {
2452        let p1 =
2453            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2454        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2455        assert_eq!(
2456            p1 - &p2,
2457            Polynomial::with_coefficients(vec![from_const(9), from_const(18), from_const(30)])
2458        );
2459    }
2460
2461    #[test]
2462    fn test_sub_ref_rhs_longer() {
2463        let p1 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2464        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2465        assert_eq!(
2466            p1 - &p2,
2467            Polynomial::with_coefficients(vec![from_const(9), from_const(18), -from_const(3)])
2468        );
2469    }
2470
2471    #[test]
2472    fn test_sub_ref_consistent_with_sub() {
2473        let p1 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2474        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2475        assert_eq!(p1.clone() - &p2, p1 - p2);
2476    }
2477
2478    #[test]
2479    fn test_sub_assign_same_length() {
2480        let mut p1 =
2481            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2482        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2483        p1 -= p2;
2484        assert_eq!(
2485            p1,
2486            Polynomial::with_coefficients(vec![from_const(9), from_const(18), from_const(27)])
2487        );
2488    }
2489
2490    #[test]
2491    fn test_sub_assign_lhs_longer() {
2492        let mut p1 =
2493            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2494        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2495        p1 -= p2;
2496        assert_eq!(
2497            p1,
2498            Polynomial::with_coefficients(vec![from_const(9), from_const(18), from_const(30)])
2499        );
2500    }
2501
2502    #[test]
2503    fn test_sub_assign_rhs_longer() {
2504        let mut p1 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2505        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2506        p1 -= p2;
2507        assert_eq!(
2508            p1,
2509            Polynomial::with_coefficients(vec![from_const(9), from_const(18), -from_const(3)])
2510        );
2511    }
2512
2513    #[test]
2514    fn test_sub_assign_consistent_with_sub() {
2515        let p1 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2516        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2517        let mut p1_assign = p1.clone();
2518        p1_assign -= p2.clone();
2519        assert_eq!(p1_assign, p1 - p2);
2520    }
2521
2522    #[test]
2523    fn test_sub_assign_ref_same_length() {
2524        let mut p1 =
2525            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2526        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2527        p1 -= &p2;
2528        assert_eq!(
2529            p1,
2530            Polynomial::with_coefficients(vec![from_const(9), from_const(18), from_const(27)])
2531        );
2532    }
2533
2534    #[test]
2535    fn test_sub_assign_ref_lhs_longer() {
2536        let mut p1 =
2537            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2538        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2539        p1 -= &p2;
2540        assert_eq!(
2541            p1,
2542            Polynomial::with_coefficients(vec![from_const(9), from_const(18), from_const(30)])
2543        );
2544    }
2545
2546    #[test]
2547    fn test_sub_assign_ref_rhs_longer() {
2548        let mut p1 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2549        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2550        p1 -= &p2;
2551        assert_eq!(
2552            p1,
2553            Polynomial::with_coefficients(vec![from_const(9), from_const(18), -from_const(3)])
2554        );
2555    }
2556
2557    #[test]
2558    fn test_sub_assign_ref_consistent_with_sub_assign() {
2559        let p1 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2560        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2561        let mut p1_assign_ref = p1.clone();
2562        p1_assign_ref -= &p2;
2563        let mut p1_assign = p1;
2564        p1_assign -= p2;
2565        assert_eq!(p1_assign_ref, p1_assign);
2566    }
2567
2568    #[test]
2569    fn test_multiply_empty() {
2570        let p1 = Polynomial::default();
2571        let p2 = Polynomial::default();
2572        assert_eq!(p1.multiply(p2), Polynomial::default());
2573    }
2574
2575    #[test]
2576    fn test_multiply_empty_by_non_empty() {
2577        let p1 = Polynomial::default();
2578        let p2 = Polynomial {
2579            coefficients: vec![from_const(12), from_const(34)],
2580        };
2581        assert_eq!(p1.multiply(p2), Polynomial::default());
2582    }
2583
2584    #[test]
2585    fn test_multiply_non_empty_by_empty() {
2586        let p1 = Polynomial {
2587            coefficients: vec![from_const(56), from_const(78)],
2588        };
2589        let p2 = Polynomial::default();
2590        assert_eq!(p1.multiply(p2), Polynomial::default());
2591    }
2592
2593    #[test]
2594    fn test_multiply_constant() {
2595        let p1 = Polynomial {
2596            coefficients: vec![from_const(3)],
2597        };
2598        let p2 = Polynomial {
2599            coefficients: vec![from_const(12), from_const(34), from_const(56)],
2600        };
2601        assert_eq!(
2602            p1.multiply(p2),
2603            Polynomial {
2604                coefficients: vec![from_const(36), from_const(102), from_const(168)]
2605            }
2606        );
2607    }
2608
2609    #[test]
2610    fn test_multiply_by_constant() {
2611        let p1 = Polynomial {
2612            coefficients: vec![from_const(12), from_const(34), from_const(56)],
2613        };
2614        let p2 = Polynomial {
2615            coefficients: vec![from_const(3)],
2616        };
2617        assert_eq!(
2618            p1.multiply(p2),
2619            Polynomial {
2620                coefficients: vec![from_const(36), from_const(102), from_const(168)]
2621            }
2622        );
2623    }
2624
2625    #[test]
2626    fn test_multiply_constant_by_constant() {
2627        let p1 = Polynomial {
2628            coefficients: vec![from_const(12)],
2629        };
2630        let p2 = Polynomial {
2631            coefficients: vec![from_const(34)],
2632        };
2633        assert_eq!(
2634            p1.multiply(p2),
2635            Polynomial {
2636                coefficients: vec![from_const(408)]
2637            }
2638        );
2639    }
2640
2641    #[test]
2642    fn test_multiply_polynomials1() {
2643        let p1 = Polynomial {
2644            coefficients: vec![from_const(1), from_const(2)],
2645        };
2646        let p2 = Polynomial {
2647            coefficients: vec![from_const(3), from_const(4)],
2648        };
2649        let result = Polynomial {
2650            coefficients: vec![from_const(3), from_const(10), from_const(8)],
2651        };
2652        assert_eq!(p1.clone().multiply(p2.clone()), result);
2653        assert_eq!(p2.multiply(p1), result);
2654    }
2655
2656    #[test]
2657    fn test_multiply_polynomials2() {
2658        let p1 = Polynomial {
2659            coefficients: vec![from_const(1), from_const(2)],
2660        };
2661        let p2 = Polynomial {
2662            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2663        };
2664        let result = Polynomial {
2665            coefficients: vec![
2666                from_const(3),
2667                from_const(10),
2668                from_const(13),
2669                from_const(10),
2670            ],
2671        };
2672        assert_eq!(p1.clone().multiply(p2.clone()), result);
2673        assert_eq!(p2.multiply(p1), result);
2674    }
2675
2676    #[test]
2677    fn test_polynomial_mul_op() {
2678        let p1 = Polynomial {
2679            coefficients: vec![from_const(1), from_const(2)],
2680        };
2681        let p2 = Polynomial {
2682            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2683        };
2684        let result = Polynomial {
2685            coefficients: vec![
2686                from_const(3),
2687                from_const(10),
2688                from_const(13),
2689                from_const(10),
2690            ],
2691        };
2692        assert_eq!(p1.clone() * p2.clone(), result);
2693        assert_eq!(p2 * p1, result);
2694    }
2695
2696    #[test]
2697    fn test_polynomial_mul_ref_op() {
2698        let p1 = Polynomial {
2699            coefficients: vec![from_const(1), from_const(2)],
2700        };
2701        let p2 = Polynomial {
2702            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2703        };
2704        let result = Polynomial {
2705            coefficients: vec![
2706                from_const(3),
2707                from_const(10),
2708                from_const(13),
2709                from_const(10),
2710            ],
2711        };
2712        assert_eq!(p1.clone() * &p2, result);
2713        assert_eq!(p2 * &p1, result);
2714    }
2715
2716    #[test]
2717    fn test_polynomial_mul_assign() {
2718        let mut p1 = Polynomial {
2719            coefficients: vec![from_const(1), from_const(2)],
2720        };
2721        let p2 = Polynomial {
2722            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2723        };
2724        p1 *= p2;
2725        assert_eq!(
2726            p1,
2727            Polynomial {
2728                coefficients: vec![
2729                    from_const(3),
2730                    from_const(10),
2731                    from_const(13),
2732                    from_const(10)
2733                ],
2734            }
2735        );
2736    }
2737
2738    #[test]
2739    fn test_polynomial_mul_assign_ref() {
2740        let mut p1 = Polynomial {
2741            coefficients: vec![from_const(1), from_const(2)],
2742        };
2743        let p2 = Polynomial {
2744            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2745        };
2746        p1 *= &p2;
2747        assert_eq!(
2748            p1,
2749            Polynomial {
2750                coefficients: vec![
2751                    from_const(3),
2752                    from_const(10),
2753                    from_const(13),
2754                    from_const(10)
2755                ],
2756            }
2757        );
2758    }
2759
2760    #[test]
2761    fn test_multiply_no_polynomials() {
2762        assert_eq!(
2763            Polynomial::multiply_batch(&[]),
2764            Polynomial::default() + Scalar::ONE
2765        );
2766    }
2767
2768    #[test]
2769    fn test_multiply_one_polynomial() {
2770        let p = Polynomial {
2771            coefficients: vec![from_const(12), from_const(34)],
2772        };
2773        assert_eq!(Polynomial::multiply_batch(&[p.clone()]), p);
2774    }
2775
2776    #[test]
2777    fn test_multiply_two_polynomials() {
2778        let p1 = Polynomial {
2779            coefficients: vec![from_const(1), from_const(2)],
2780        };
2781        let p2 = Polynomial {
2782            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2783        };
2784        let result = Polynomial {
2785            coefficients: vec![
2786                from_const(3),
2787                from_const(10),
2788                from_const(13),
2789                from_const(10),
2790            ],
2791        };
2792        assert_eq!(
2793            Polynomial::multiply_batch(&[p1.clone(), p2.clone()]),
2794            result
2795        );
2796        assert_eq!(Polynomial::multiply_batch(&[p2, p1]), result);
2797    }
2798
2799    #[test]
2800    fn test_multiply_three_polynomials() {
2801        let p1 = Polynomial {
2802            coefficients: vec![from_const(1), from_const(2)],
2803        };
2804        let p2 = Polynomial {
2805            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2806        };
2807        let p3 = Polynomial {
2808            coefficients: vec![from_const(6), from_const(7), from_const(8), from_const(9)],
2809        };
2810        let result = Polynomial {
2811            coefficients: vec![
2812                from_const(18),
2813                from_const(81),
2814                from_const(172),
2815                from_const(258),
2816                from_const(264),
2817                from_const(197),
2818                from_const(90),
2819            ],
2820        };
2821        assert_eq!(
2822            Polynomial::multiply_batch(&[p1.clone(), p2.clone(), p3.clone()]),
2823            result
2824        );
2825        assert_eq!(
2826            Polynomial::multiply_batch(&[p1.clone(), p3.clone(), p2.clone()]),
2827            result
2828        );
2829        assert_eq!(
2830            Polynomial::multiply_batch(&[p2.clone(), p1.clone(), p3.clone()]),
2831            result
2832        );
2833        assert_eq!(
2834            Polynomial::multiply_batch(&[p2.clone(), p3.clone(), p1.clone()]),
2835            result
2836        );
2837        assert_eq!(
2838            Polynomial::multiply_batch(&[p3.clone(), p1.clone(), p2.clone()]),
2839            result
2840        );
2841        assert_eq!(
2842            Polynomial::multiply_batch(&[p3.clone(), p2.clone(), p1.clone()]),
2843            result
2844        );
2845    }
2846
2847    #[test]
2848    fn test_multiply_four_polynomials() {
2849        let p1 = Polynomial {
2850            coefficients: vec![from_const(1), from_const(2)],
2851        };
2852        let p2 = Polynomial {
2853            coefficients: vec![from_const(3), from_const(4)],
2854        };
2855        let p3 = Polynomial {
2856            coefficients: vec![from_const(5), from_const(6)],
2857        };
2858        let p4 = Polynomial {
2859            coefficients: vec![from_const(7), from_const(8)],
2860        };
2861        let result = Polynomial {
2862            coefficients: vec![
2863                from_const(105),
2864                from_const(596),
2865                from_const(1244),
2866                from_const(1136),
2867                from_const(384),
2868            ],
2869        };
2870        assert_eq!(
2871            Polynomial::multiply_batch(&[p1.clone(), p2.clone(), p3.clone(), p4.clone()]),
2872            result
2873        );
2874        assert_eq!(
2875            Polynomial::multiply_batch(&[p1.clone(), p2.clone(), p4.clone(), p3.clone()]),
2876            result
2877        );
2878        assert_eq!(
2879            Polynomial::multiply_batch(&[p1.clone(), p3.clone(), p2.clone(), p4.clone()]),
2880            result
2881        );
2882        assert_eq!(
2883            Polynomial::multiply_batch(&[p1.clone(), p3.clone(), p4.clone(), p2.clone()]),
2884            result
2885        );
2886        // okay, not gonna try all permutations -- too much typing for too little gain.
2887    }
2888
2889    #[test]
2890    fn test_product_empty() {
2891        let polynomials: Vec<Polynomial> = vec![];
2892        assert_eq!(
2893            polynomials.into_iter().product::<Polynomial>(),
2894            Polynomial::multiply_batch(&[])
2895        );
2896    }
2897
2898    #[test]
2899    fn test_product_one_polynomial() {
2900        let p = Polynomial {
2901            coefficients: vec![from_const(12), from_const(34)],
2902        };
2903        assert_eq!(vec![p.clone()].into_iter().product::<Polynomial>(), p);
2904    }
2905
2906    #[test]
2907    fn test_product_several_polynomials() {
2908        let p1 = Polynomial {
2909            coefficients: vec![from_const(1), from_const(2)],
2910        };
2911        let p2 = Polynomial {
2912            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2913        };
2914        let p3 = Polynomial {
2915            coefficients: vec![from_const(6), from_const(7), from_const(8), from_const(9)],
2916        };
2917        assert_eq!(
2918            vec![p1.clone(), p2.clone(), p3.clone()]
2919                .into_iter()
2920                .product::<Polynomial>(),
2921            Polynomial::multiply_batch(&[p1, p2, p3])
2922        );
2923    }
2924
2925    #[test]
2926    fn test_product_ref_empty() {
2927        let polynomials: Vec<Polynomial> = vec![];
2928        assert_eq!(
2929            polynomials.iter().product::<Polynomial>(),
2930            Polynomial::multiply_batch(&[])
2931        );
2932    }
2933
2934    #[test]
2935    fn test_product_ref_one_polynomial() {
2936        let p = Polynomial {
2937            coefficients: vec![from_const(12), from_const(34)],
2938        };
2939        assert_eq!([p.clone()].iter().product::<Polynomial>(), p);
2940    }
2941
2942    #[test]
2943    fn test_product_ref_several_polynomials() {
2944        let p1 = Polynomial {
2945            coefficients: vec![from_const(1), from_const(2)],
2946        };
2947        let p2 = Polynomial {
2948            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2949        };
2950        let p3 = Polynomial {
2951            coefficients: vec![from_const(6), from_const(7), from_const(8), from_const(9)],
2952        };
2953        let polynomials = [p1.clone(), p2.clone(), p3.clone()];
2954        assert_eq!(
2955            polynomials.iter().product::<Polynomial>(),
2956            Polynomial::multiply_batch(&[p1, p2, p3])
2957        );
2958    }
2959
2960    #[test]
2961    fn test_product_ref_consistent_with_product() {
2962        let p1 = Polynomial {
2963            coefficients: vec![from_const(1), from_const(2)],
2964        };
2965        let p2 = Polynomial {
2966            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2967        };
2968        let polynomials = vec![p1, p2];
2969        assert_eq!(
2970            polynomials.iter().product::<Polynomial>(),
2971            polynomials.into_iter().product::<Polynomial>()
2972        );
2973    }
2974
2975    #[test]
2976    fn test_divide_zero_by_zero() {
2977        let z = Polynomial {
2978            coefficients: vec![
2979                -from_const(1),
2980                from_const(0),
2981                from_const(0),
2982                from_const(0),
2983                from_const(1),
2984            ],
2985        };
2986        assert_eq!(
2987            z.divide_by_zero(4).unwrap(),
2988            Polynomial {
2989                coefficients: vec![from_const(1)]
2990            }
2991        );
2992    }
2993
2994    #[test]
2995    fn test_non_trivial_quotient1() {
2996        let ql = Polynomial::encode2(vec![
2997            from_const(0),
2998            from_const(0),
2999            from_const(1),
3000            from_const(1),
3001        ]);
3002        let qr = Polynomial::encode2(vec![
3003            from_const(0),
3004            from_const(0),
3005            from_const(1),
3006            from_const(1),
3007        ]);
3008        let qo = Polynomial::encode2(vec![-from_const(1); 4]);
3009        let qm = Polynomial::encode2(vec![
3010            from_const(1),
3011            from_const(1),
3012            from_const(0),
3013            from_const(0),
3014        ]);
3015        let qc = Polynomial::encode2(vec![from_const(0); 4]);
3016        let l = Polynomial::encode2(vec![
3017            from_const(3),
3018            from_const(9),
3019            from_const(3),
3020            from_const(30),
3021        ]);
3022        let r = Polynomial::encode2(vec![
3023            from_const(3),
3024            from_const(3),
3025            from_const(27),
3026            from_const(5),
3027        ]);
3028        let o = Polynomial::encode2(vec![
3029            from_const(9),
3030            from_const(27),
3031            from_const(30),
3032            from_const(35),
3033        ]);
3034        let lr = l.clone().multiply(r.clone());
3035        let p = ql.multiply(l) + qr.multiply(r) + qo.multiply(o) + qm.multiply(lr) + qc;
3036        let q = p.divide_by_zero(4).unwrap();
3037        assert_eq!(q.len(), 6);
3038        assert_eq!(q.degree_bound(), 6);
3039    }
3040
3041    #[test]
3042    fn test_non_trivial_quotient2() {
3043        let ql = Polynomial::encode2(vec![
3044            from_const(0),
3045            from_const(0),
3046            from_const(1),
3047            from_const(1),
3048        ]);
3049        let qr = Polynomial::encode2(vec![
3050            from_const(0),
3051            from_const(0),
3052            from_const(1),
3053            from_const(5),
3054        ]);
3055        let qo = Polynomial::encode2(vec![-from_const(1); 4]);
3056        let qm = Polynomial::encode2(vec![
3057            from_const(1),
3058            from_const(1),
3059            from_const(0),
3060            from_const(0),
3061        ]);
3062        let qc = Polynomial::encode2(vec![from_const(0); 4]);
3063        let l = Polynomial::encode2(vec![
3064            from_const(3),
3065            from_const(9),
3066            from_const(3),
3067            from_const(30),
3068        ]);
3069        let r = Polynomial::encode2(vec![
3070            from_const(3),
3071            from_const(3),
3072            from_const(27),
3073            from_const(1),
3074        ]);
3075        let o = Polynomial::encode2(vec![
3076            from_const(9),
3077            from_const(27),
3078            from_const(30),
3079            from_const(35),
3080        ]);
3081        let lr = l.clone().multiply(r.clone());
3082        let p = ql.multiply(l) + qr.multiply(r) + qo.multiply(o) + qm.multiply(lr) + qc;
3083        let q = p.divide_by_zero(4).unwrap();
3084        assert_eq!(q.len(), 6);
3085        assert_eq!(q.degree_bound(), 6);
3086    }
3087
3088    #[test]
3089    fn test_shift_domain2_1() {
3090        let values = vec![
3091            from_const(12),
3092            from_const(34),
3093            from_const(56),
3094            from_const(78),
3095        ];
3096        let p = Polynomial::encode2(values);
3097        let shifted = p.clone().shift_domain_by(Scalar::MULTIPLICATIVE_GENERATOR);
3098        assert_eq!(
3099            shifted.evaluate_on_two_adic_domain(0, 4),
3100            p.evaluate_on_two_adic_coset(0, 4)
3101        );
3102        assert_eq!(
3103            shifted.evaluate_on_two_adic_domain(1, 4),
3104            p.evaluate_on_two_adic_coset(1, 4)
3105        );
3106        assert_eq!(
3107            shifted.evaluate_on_two_adic_domain(2, 4),
3108            p.evaluate_on_two_adic_coset(2, 4)
3109        );
3110        assert_eq!(
3111            shifted.evaluate_on_two_adic_domain(3, 4),
3112            p.evaluate_on_two_adic_coset(3, 4)
3113        );
3114    }
3115
3116    #[test]
3117    fn test_shift_domain2_2() {
3118        let values = vec![
3119            from_const(12),
3120            from_const(34),
3121            from_const(56),
3122            from_const(78),
3123        ];
3124        let p = Polynomial::encode2(values);
3125        let shifted = p.clone().shift_domain();
3126        assert_eq!(
3127            shifted.evaluate_on_two_adic_domain(0, 4),
3128            p.evaluate_on_two_adic_coset(0, 4)
3129        );
3130        assert_eq!(
3131            shifted.evaluate_on_two_adic_domain(1, 4),
3132            p.evaluate_on_two_adic_coset(1, 4)
3133        );
3134        assert_eq!(
3135            shifted.evaluate_on_two_adic_domain(2, 4),
3136            p.evaluate_on_two_adic_coset(2, 4)
3137        );
3138        assert_eq!(
3139            shifted.evaluate_on_two_adic_domain(3, 4),
3140            p.evaluate_on_two_adic_coset(3, 4)
3141        );
3142    }
3143
3144    #[test]
3145    fn test_shift_domain3() {
3146        let values = vec![from_const(12), from_const(34), from_const(56)];
3147        let p = Polynomial::encode3(values);
3148        let shifted = p.clone().shift_domain_by(Scalar::MULTIPLICATIVE_GENERATOR);
3149        assert_eq!(
3150            shifted.evaluate_on_three_adic_domain(0, 3),
3151            p.evaluate_on_three_adic_coset(0, 3)
3152        );
3153        assert_eq!(
3154            shifted.evaluate_on_three_adic_domain(1, 3),
3155            p.evaluate_on_three_adic_coset(1, 3)
3156        );
3157        assert_eq!(
3158            shifted.evaluate_on_three_adic_domain(2, 3),
3159            p.evaluate_on_three_adic_coset(2, 3)
3160        );
3161    }
3162
3163    #[test]
3164    fn test_lde2_blowup2() {
3165        let values = vec![
3166            from_const(12),
3167            from_const(34),
3168            from_const(56),
3169            from_const(78),
3170        ];
3171        let p = Polynomial::encode2(values);
3172        let lde = p.clone().lde2(8);
3173        assert_eq!(
3174            lde,
3175            vec![
3176                p.evaluate_on_two_adic_domain(0, 8),
3177                p.evaluate_on_two_adic_domain(1, 8),
3178                p.evaluate_on_two_adic_domain(2, 8),
3179                p.evaluate_on_two_adic_domain(3, 8),
3180                p.evaluate_on_two_adic_domain(4, 8),
3181                p.evaluate_on_two_adic_domain(5, 8),
3182                p.evaluate_on_two_adic_domain(6, 8),
3183                p.evaluate_on_two_adic_domain(7, 8),
3184            ]
3185        );
3186    }
3187
3188    #[test]
3189    fn test_lde2_blowup4() {
3190        let values = vec![from_const(1), from_const(2), from_const(3), from_const(4)];
3191        let p = Polynomial::encode2(values);
3192        let lde = p.clone().lde2(16);
3193        assert_eq!(
3194            lde,
3195            vec![
3196                p.evaluate_on_two_adic_domain(0, 16),
3197                p.evaluate_on_two_adic_domain(1, 16),
3198                p.evaluate_on_two_adic_domain(2, 16),
3199                p.evaluate_on_two_adic_domain(3, 16),
3200                p.evaluate_on_two_adic_domain(4, 16),
3201                p.evaluate_on_two_adic_domain(5, 16),
3202                p.evaluate_on_two_adic_domain(6, 16),
3203                p.evaluate_on_two_adic_domain(7, 16),
3204                p.evaluate_on_two_adic_domain(8, 16),
3205                p.evaluate_on_two_adic_domain(9, 16),
3206                p.evaluate_on_two_adic_domain(10, 16),
3207                p.evaluate_on_two_adic_domain(11, 16),
3208                p.evaluate_on_two_adic_domain(12, 16),
3209                p.evaluate_on_two_adic_domain(13, 16),
3210                p.evaluate_on_two_adic_domain(14, 16),
3211                p.evaluate_on_two_adic_domain(15, 16),
3212            ]
3213        );
3214    }
3215
3216    #[test]
3217    fn test_lde2_shorter_polynomial() {
3218        let values = vec![from_const(42), from_const(42)];
3219        let p = Polynomial::encode2(values);
3220        assert_eq!(p.len(), 1);
3221        assert_eq!(p.degree_bound(), 1);
3222        let lde = p.clone().lde2(4);
3223        assert_eq!(
3224            lde,
3225            vec![
3226                p.evaluate_on_two_adic_domain(0, 4),
3227                p.evaluate_on_two_adic_domain(1, 4),
3228                p.evaluate_on_two_adic_domain(2, 4),
3229                p.evaluate_on_two_adic_domain(3, 4),
3230            ]
3231        );
3232    }
3233
3234    #[test]
3235    fn test_lde3_blowup3() {
3236        let values = vec![from_const(12), from_const(34), from_const(56)];
3237        let p = Polynomial::encode3(values);
3238        let lde = p.clone().lde3(9);
3239        assert_eq!(
3240            lde,
3241            vec![
3242                p.evaluate_on_three_adic_domain(0, 9),
3243                p.evaluate_on_three_adic_domain(1, 9),
3244                p.evaluate_on_three_adic_domain(2, 9),
3245                p.evaluate_on_three_adic_domain(3, 9),
3246                p.evaluate_on_three_adic_domain(4, 9),
3247                p.evaluate_on_three_adic_domain(5, 9),
3248                p.evaluate_on_three_adic_domain(6, 9),
3249                p.evaluate_on_three_adic_domain(7, 9),
3250                p.evaluate_on_three_adic_domain(8, 9),
3251            ]
3252        );
3253    }
3254
3255    #[test]
3256    fn test_lde3_blowup9() {
3257        let values = vec![from_const(1), from_const(2), from_const(3)];
3258        let p = Polynomial::encode3(values);
3259        let lde = p.clone().lde3(27);
3260        assert_eq!(
3261            lde,
3262            vec![
3263                p.evaluate_on_three_adic_domain(0, 27),
3264                p.evaluate_on_three_adic_domain(1, 27),
3265                p.evaluate_on_three_adic_domain(2, 27),
3266                p.evaluate_on_three_adic_domain(3, 27),
3267                p.evaluate_on_three_adic_domain(4, 27),
3268                p.evaluate_on_three_adic_domain(5, 27),
3269                p.evaluate_on_three_adic_domain(6, 27),
3270                p.evaluate_on_three_adic_domain(7, 27),
3271                p.evaluate_on_three_adic_domain(8, 27),
3272                p.evaluate_on_three_adic_domain(9, 27),
3273                p.evaluate_on_three_adic_domain(10, 27),
3274                p.evaluate_on_three_adic_domain(11, 27),
3275                p.evaluate_on_three_adic_domain(12, 27),
3276                p.evaluate_on_three_adic_domain(13, 27),
3277                p.evaluate_on_three_adic_domain(14, 27),
3278                p.evaluate_on_three_adic_domain(15, 27),
3279                p.evaluate_on_three_adic_domain(16, 27),
3280                p.evaluate_on_three_adic_domain(17, 27),
3281                p.evaluate_on_three_adic_domain(18, 27),
3282                p.evaluate_on_three_adic_domain(19, 27),
3283                p.evaluate_on_three_adic_domain(20, 27),
3284                p.evaluate_on_three_adic_domain(21, 27),
3285                p.evaluate_on_three_adic_domain(22, 27),
3286                p.evaluate_on_three_adic_domain(23, 27),
3287                p.evaluate_on_three_adic_domain(24, 27),
3288                p.evaluate_on_three_adic_domain(25, 27),
3289                p.evaluate_on_three_adic_domain(26, 27),
3290            ]
3291        );
3292    }
3293
3294    #[test]
3295    fn test_lde3_nine_values_blowup3() {
3296        let values = (1u64..=9).map(Scalar::from).collect();
3297        let p = Polynomial::encode3(values);
3298        let lde = p.clone().lde3(27);
3299        assert_eq!(
3300            lde,
3301            vec![
3302                p.evaluate_on_three_adic_domain(0, 27),
3303                p.evaluate_on_three_adic_domain(1, 27),
3304                p.evaluate_on_three_adic_domain(2, 27),
3305                p.evaluate_on_three_adic_domain(3, 27),
3306                p.evaluate_on_three_adic_domain(4, 27),
3307                p.evaluate_on_three_adic_domain(5, 27),
3308                p.evaluate_on_three_adic_domain(6, 27),
3309                p.evaluate_on_three_adic_domain(7, 27),
3310                p.evaluate_on_three_adic_domain(8, 27),
3311                p.evaluate_on_three_adic_domain(9, 27),
3312                p.evaluate_on_three_adic_domain(10, 27),
3313                p.evaluate_on_three_adic_domain(11, 27),
3314                p.evaluate_on_three_adic_domain(12, 27),
3315                p.evaluate_on_three_adic_domain(13, 27),
3316                p.evaluate_on_three_adic_domain(14, 27),
3317                p.evaluate_on_three_adic_domain(15, 27),
3318                p.evaluate_on_three_adic_domain(16, 27),
3319                p.evaluate_on_three_adic_domain(17, 27),
3320                p.evaluate_on_three_adic_domain(18, 27),
3321                p.evaluate_on_three_adic_domain(19, 27),
3322                p.evaluate_on_three_adic_domain(20, 27),
3323                p.evaluate_on_three_adic_domain(21, 27),
3324                p.evaluate_on_three_adic_domain(22, 27),
3325                p.evaluate_on_three_adic_domain(23, 27),
3326                p.evaluate_on_three_adic_domain(24, 27),
3327                p.evaluate_on_three_adic_domain(25, 27),
3328                p.evaluate_on_three_adic_domain(26, 27),
3329            ]
3330        );
3331    }
3332
3333    #[test]
3334    fn test_lde3_shorter_poly() {
3335        let values = vec![from_const(7), from_const(7), from_const(7)];
3336        let p = Polynomial::encode3(values);
3337        assert_eq!(p.len(), 1);
3338        assert_eq!(p.degree_bound(), 1);
3339        let lde = p.clone().lde3(9);
3340        assert_eq!(
3341            lde,
3342            vec![
3343                p.evaluate_on_three_adic_domain(0, 9),
3344                p.evaluate_on_three_adic_domain(1, 9),
3345                p.evaluate_on_three_adic_domain(2, 9),
3346                p.evaluate_on_three_adic_domain(3, 9),
3347                p.evaluate_on_three_adic_domain(4, 9),
3348                p.evaluate_on_three_adic_domain(5, 9),
3349                p.evaluate_on_three_adic_domain(6, 9),
3350                p.evaluate_on_three_adic_domain(7, 9),
3351                p.evaluate_on_three_adic_domain(8, 9),
3352            ]
3353        );
3354    }
3355
3356    #[test]
3357    fn test_fold2_degree_zero() {
3358        let p = Polynomial::with_coefficients(vec![from_const(5)]);
3359        assert_eq!(p.clone().fold2(from_const(2)).take(), vec![from_const(5)]);
3360        assert_eq!(p.fold2(from_const(3)).take(), vec![from_const(5)]);
3361    }
3362
3363    #[test]
3364    fn test_fold2_degree_one() {
3365        let p = Polynomial::with_coefficients(vec![from_const(2), from_const(3)]);
3366        assert_eq!(p.clone().fold2(from_const(2)).take(), vec![from_const(8)]);
3367        assert_eq!(p.fold2(from_const(3)).take(), vec![from_const(11)]);
3368    }
3369
3370    #[test]
3371    fn test_fold2_degree_two() {
3372        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
3373        assert_eq!(
3374            p.clone().fold2(from_const(2)).take(),
3375            vec![from_const(5), from_const(3)],
3376        );
3377        assert_eq!(
3378            p.fold2(from_const(3)).take(),
3379            vec![from_const(7), from_const(3)],
3380        );
3381    }
3382
3383    #[test]
3384    fn test_fold2_degree_three() {
3385        let p = Polynomial::with_coefficients(vec![
3386            from_const(1),
3387            from_const(2),
3388            from_const(3),
3389            from_const(4),
3390        ]);
3391        assert_eq!(
3392            p.clone().fold2(from_const(2)).take(),
3393            vec![from_const(5), from_const(11)],
3394        );
3395        assert_eq!(
3396            p.fold2(from_const(3)).take(),
3397            vec![from_const(7), from_const(15)],
3398        );
3399    }
3400
3401    #[test]
3402    fn test_fold3_degree_zero() {
3403        let p = Polynomial::with_coefficients(vec![from_const(5)]);
3404        assert_eq!(p.clone().fold3(from_const(2)).take(), vec![from_const(5)]);
3405        assert_eq!(p.fold3(from_const(3)).take(), vec![from_const(5)]);
3406    }
3407
3408    #[test]
3409    fn test_fold3_degree_two() {
3410        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
3411        assert_eq!(p.clone().fold3(from_const(2)).take(), vec![from_const(17)]);
3412        assert_eq!(p.fold3(from_const(3)).take(), vec![from_const(34)]);
3413    }
3414
3415    #[test]
3416    fn test_fold3_degree_three() {
3417        let p = Polynomial::with_coefficients(vec![
3418            from_const(1),
3419            from_const(2),
3420            from_const(3),
3421            from_const(4),
3422        ]);
3423        assert_eq!(
3424            p.clone().fold3(from_const(2)).take(),
3425            vec![from_const(17), from_const(4)],
3426        );
3427        assert_eq!(
3428            p.fold3(from_const(3)).take(),
3429            vec![from_const(34), from_const(4)],
3430        );
3431    }
3432
3433    #[test]
3434    fn test_fold3_degree_five() {
3435        let p = Polynomial::with_coefficients(vec![
3436            from_const(1),
3437            from_const(2),
3438            from_const(3),
3439            from_const(4),
3440            from_const(5),
3441            from_const(6),
3442        ]);
3443        assert_eq!(
3444            p.clone().fold3(from_const(2)).take(),
3445            vec![from_const(17), from_const(38)],
3446        );
3447        assert_eq!(
3448            p.fold3(from_const(3)).take(),
3449            vec![from_const(34), from_const(73)],
3450        );
3451    }
3452
3453    #[test]
3454    fn test_multiply_values2_same_constant() {
3455        let lhs = vec![from_const(42), from_const(42)];
3456        let rhs = vec![from_const(42), from_const(42)];
3457        let result = Polynomial::multiply_values2(lhs, rhs);
3458        assert_eq!(result, vec![from_const(1764)]);
3459    }
3460
3461    #[test]
3462    fn test_multiply_values2_different_constants() {
3463        let lhs = vec![from_const(3), from_const(3)];
3464        let rhs = vec![from_const(7), from_const(7)];
3465        let result = Polynomial::multiply_values2(lhs, rhs);
3466        assert_eq!(result, vec![from_const(21)]);
3467    }
3468
3469    #[test]
3470    fn test_multiply_values2_two_linear_polynomials() {
3471        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
3472        let q = Polynomial::with_coefficients(vec![from_const(3), from_const(4)]);
3473        let lhs = vec![
3474            p.evaluate_on_two_adic_domain(0, 2),
3475            p.evaluate_on_two_adic_domain(1, 2),
3476        ];
3477        let rhs = vec![
3478            q.evaluate_on_two_adic_domain(0, 2),
3479            q.evaluate_on_two_adic_domain(1, 2),
3480        ];
3481        let product = p.multiply(q);
3482        let result = Polynomial::multiply_values2(lhs, rhs);
3483        assert_eq!(
3484            result,
3485            vec![
3486                product.evaluate_on_two_adic_domain(0, 4),
3487                product.evaluate_on_two_adic_domain(1, 4),
3488                product.evaluate_on_two_adic_domain(2, 4),
3489                product.evaluate_on_two_adic_domain(3, 4),
3490            ]
3491        );
3492    }
3493
3494    #[test]
3495    fn test_multiply_values2_four_values() {
3496        let p = Polynomial::with_coefficients(vec![
3497            from_const(1),
3498            from_const(2),
3499            from_const(3),
3500            from_const(4),
3501        ]);
3502        let q = Polynomial::with_coefficients(vec![
3503            from_const(5),
3504            from_const(6),
3505            from_const(7),
3506            from_const(8),
3507        ]);
3508        let lhs = vec![
3509            p.evaluate_on_two_adic_domain(0, 4),
3510            p.evaluate_on_two_adic_domain(1, 4),
3511            p.evaluate_on_two_adic_domain(2, 4),
3512            p.evaluate_on_two_adic_domain(3, 4),
3513        ];
3514        let rhs = vec![
3515            q.evaluate_on_two_adic_domain(0, 4),
3516            q.evaluate_on_two_adic_domain(1, 4),
3517            q.evaluate_on_two_adic_domain(2, 4),
3518            q.evaluate_on_two_adic_domain(3, 4),
3519        ];
3520        let product = p.multiply(q);
3521        let result = Polynomial::multiply_values2(lhs, rhs);
3522        assert_eq!(
3523            result,
3524            vec![
3525                product.evaluate_on_two_adic_domain(0, 8),
3526                product.evaluate_on_two_adic_domain(1, 8),
3527                product.evaluate_on_two_adic_domain(2, 8),
3528                product.evaluate_on_two_adic_domain(3, 8),
3529                product.evaluate_on_two_adic_domain(4, 8),
3530                product.evaluate_on_two_adic_domain(5, 8),
3531                product.evaluate_on_two_adic_domain(6, 8),
3532                product.evaluate_on_two_adic_domain(7, 8),
3533            ]
3534        );
3535    }
3536
3537    #[test]
3538    fn test_multiply_values2_commutative() {
3539        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
3540        let q = Polynomial::with_coefficients(vec![from_const(3), from_const(4)]);
3541        let values_p = vec![
3542            p.evaluate_on_two_adic_domain(0, 2),
3543            p.evaluate_on_two_adic_domain(1, 2),
3544        ];
3545        let values_q = vec![
3546            q.evaluate_on_two_adic_domain(0, 2),
3547            q.evaluate_on_two_adic_domain(1, 2),
3548        ];
3549        let result_pq = Polynomial::multiply_values2(values_p.clone(), values_q.clone());
3550        let result_qp = Polynomial::multiply_values2(values_q, values_p);
3551        assert_eq!(result_pq, result_qp);
3552    }
3553
3554    #[test]
3555    fn test_multiply_values2_round_trip() {
3556        let p = Polynomial::with_coefficients(vec![
3557            from_const(1),
3558            from_const(2),
3559            from_const(3),
3560            from_const(4),
3561        ]);
3562        let q = Polynomial::with_coefficients(vec![
3563            from_const(5),
3564            from_const(6),
3565            from_const(7),
3566            from_const(8),
3567        ]);
3568        let lhs = vec![
3569            p.evaluate_on_two_adic_domain(0, 4),
3570            p.evaluate_on_two_adic_domain(1, 4),
3571            p.evaluate_on_two_adic_domain(2, 4),
3572            p.evaluate_on_two_adic_domain(3, 4),
3573        ];
3574        let rhs = vec![
3575            q.evaluate_on_two_adic_domain(0, 4),
3576            q.evaluate_on_two_adic_domain(1, 4),
3577            q.evaluate_on_two_adic_domain(2, 4),
3578            q.evaluate_on_two_adic_domain(3, 4),
3579        ];
3580        let product = p.clone().multiply(q.clone());
3581        let result = Polynomial::encode2(Polynomial::multiply_values2(lhs, rhs));
3582        assert_eq!(result, product);
3583    }
3584
3585    #[test]
3586    fn test_multiply_values3_same_constant() {
3587        let lhs = vec![from_const(42), from_const(42), from_const(42)];
3588        let rhs = vec![from_const(42), from_const(42), from_const(42)];
3589        let result = Polynomial::multiply_values3(lhs, rhs);
3590        assert_eq!(result, vec![from_const(1764)]);
3591    }
3592
3593    #[test]
3594    fn test_multiply_values3_different_constants() {
3595        let lhs = vec![from_const(3), from_const(3), from_const(3)];
3596        let rhs = vec![from_const(7), from_const(7), from_const(7)];
3597        let result = Polynomial::multiply_values3(lhs, rhs);
3598        assert_eq!(result, vec![from_const(21)]);
3599    }
3600
3601    #[test]
3602    fn test_multiply_values3_two_linear_polynomials() {
3603        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
3604        let q = Polynomial::with_coefficients(vec![from_const(3), from_const(4)]);
3605        let lhs = vec![
3606            p.evaluate_on_three_adic_domain(0, 3),
3607            p.evaluate_on_three_adic_domain(1, 3),
3608            p.evaluate_on_three_adic_domain(2, 3),
3609        ];
3610        let rhs = vec![
3611            q.evaluate_on_three_adic_domain(0, 3),
3612            q.evaluate_on_three_adic_domain(1, 3),
3613            q.evaluate_on_three_adic_domain(2, 3),
3614        ];
3615        let product = p.multiply(q);
3616        let result = Polynomial::multiply_values3(lhs, rhs);
3617        assert_eq!(
3618            result,
3619            vec![
3620                product.evaluate_on_three_adic_domain(0, 3),
3621                product.evaluate_on_three_adic_domain(1, 3),
3622                product.evaluate_on_three_adic_domain(2, 3),
3623            ]
3624        );
3625    }
3626
3627    #[test]
3628    fn test_multiply_values3_nine_values() {
3629        let p = Polynomial::with_coefficients(vec![
3630            from_const(1),
3631            from_const(2),
3632            from_const(3),
3633            from_const(4),
3634            from_const(5),
3635            from_const(6),
3636            from_const(7),
3637            from_const(8),
3638            from_const(9),
3639        ]);
3640        let q = Polynomial::with_coefficients(vec![
3641            from_const(10),
3642            from_const(11),
3643            from_const(12),
3644            from_const(13),
3645            from_const(14),
3646            from_const(15),
3647            from_const(16),
3648            from_const(17),
3649            from_const(18),
3650        ]);
3651        let lhs = vec![
3652            p.evaluate_on_three_adic_domain(0, 9),
3653            p.evaluate_on_three_adic_domain(1, 9),
3654            p.evaluate_on_three_adic_domain(2, 9),
3655            p.evaluate_on_three_adic_domain(3, 9),
3656            p.evaluate_on_three_adic_domain(4, 9),
3657            p.evaluate_on_three_adic_domain(5, 9),
3658            p.evaluate_on_three_adic_domain(6, 9),
3659            p.evaluate_on_three_adic_domain(7, 9),
3660            p.evaluate_on_three_adic_domain(8, 9),
3661        ];
3662        let rhs = vec![
3663            q.evaluate_on_three_adic_domain(0, 9),
3664            q.evaluate_on_three_adic_domain(1, 9),
3665            q.evaluate_on_three_adic_domain(2, 9),
3666            q.evaluate_on_three_adic_domain(3, 9),
3667            q.evaluate_on_three_adic_domain(4, 9),
3668            q.evaluate_on_three_adic_domain(5, 9),
3669            q.evaluate_on_three_adic_domain(6, 9),
3670            q.evaluate_on_three_adic_domain(7, 9),
3671            q.evaluate_on_three_adic_domain(8, 9),
3672        ];
3673        let product = p.multiply(q);
3674        let result = Polynomial::multiply_values3(lhs, rhs);
3675        assert_eq!(
3676            result,
3677            vec![
3678                product.evaluate_on_three_adic_domain(0, 27),
3679                product.evaluate_on_three_adic_domain(1, 27),
3680                product.evaluate_on_three_adic_domain(2, 27),
3681                product.evaluate_on_three_adic_domain(3, 27),
3682                product.evaluate_on_three_adic_domain(4, 27),
3683                product.evaluate_on_three_adic_domain(5, 27),
3684                product.evaluate_on_three_adic_domain(6, 27),
3685                product.evaluate_on_three_adic_domain(7, 27),
3686                product.evaluate_on_three_adic_domain(8, 27),
3687                product.evaluate_on_three_adic_domain(9, 27),
3688                product.evaluate_on_three_adic_domain(10, 27),
3689                product.evaluate_on_three_adic_domain(11, 27),
3690                product.evaluate_on_three_adic_domain(12, 27),
3691                product.evaluate_on_three_adic_domain(13, 27),
3692                product.evaluate_on_three_adic_domain(14, 27),
3693                product.evaluate_on_three_adic_domain(15, 27),
3694                product.evaluate_on_three_adic_domain(16, 27),
3695                product.evaluate_on_three_adic_domain(17, 27),
3696                product.evaluate_on_three_adic_domain(18, 27),
3697                product.evaluate_on_three_adic_domain(19, 27),
3698                product.evaluate_on_three_adic_domain(20, 27),
3699                product.evaluate_on_three_adic_domain(21, 27),
3700                product.evaluate_on_three_adic_domain(22, 27),
3701                product.evaluate_on_three_adic_domain(23, 27),
3702                product.evaluate_on_three_adic_domain(24, 27),
3703                product.evaluate_on_three_adic_domain(25, 27),
3704                product.evaluate_on_three_adic_domain(26, 27),
3705            ]
3706        );
3707    }
3708
3709    #[test]
3710    fn test_multiply_values3_commutative() {
3711        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
3712        let q = Polynomial::with_coefficients(vec![from_const(3), from_const(4)]);
3713        let values_p = vec![
3714            p.evaluate_on_three_adic_domain(0, 3),
3715            p.evaluate_on_three_adic_domain(1, 3),
3716            p.evaluate_on_three_adic_domain(2, 3),
3717        ];
3718        let values_q = vec![
3719            q.evaluate_on_three_adic_domain(0, 3),
3720            q.evaluate_on_three_adic_domain(1, 3),
3721            q.evaluate_on_three_adic_domain(2, 3),
3722        ];
3723        let result_pq = Polynomial::multiply_values3(values_p.clone(), values_q.clone());
3724        let result_qp = Polynomial::multiply_values3(values_q, values_p);
3725        assert_eq!(result_pq, result_qp);
3726    }
3727
3728    #[test]
3729    fn test_multiply_values3_round_trip() {
3730        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
3731        let q = Polynomial::with_coefficients(vec![from_const(4), from_const(5), from_const(6)]);
3732        let lhs = vec![
3733            p.evaluate_on_three_adic_domain(0, 3),
3734            p.evaluate_on_three_adic_domain(1, 3),
3735            p.evaluate_on_three_adic_domain(2, 3),
3736        ];
3737        let rhs = vec![
3738            q.evaluate_on_three_adic_domain(0, 3),
3739            q.evaluate_on_three_adic_domain(1, 3),
3740            q.evaluate_on_three_adic_domain(2, 3),
3741        ];
3742        let product = p.clone().multiply(q.clone());
3743        let result = Polynomial::encode3(Polynomial::multiply_values3(lhs, rhs));
3744        assert_eq!(result, product);
3745    }
3746
3747    #[test]
3748    fn test_lagrange0_two_adic_1() {
3749        let n = 1;
3750        let l0 = Polynomial::lagrange0_2(n);
3751        assert_eq!(l0.evaluate(from_const(1)), from_const(1));
3752    }
3753
3754    #[test]
3755    fn test_lagrange0_two_adic_2() {
3756        let n = 2;
3757        let omega = Polynomial::domain_element2(1, n);
3758        let l0 = Polynomial::lagrange0_2(n);
3759        assert_eq!(l0.evaluate(from_const(1)), from_const(1));
3760        assert_eq!(l0.evaluate(omega), from_const(0));
3761    }
3762
3763    #[test]
3764    fn test_lagrange0_two_adic_4() {
3765        let n = 4;
3766        let omega = Polynomial::domain_element2(1, n);
3767        let l0 = Polynomial::lagrange0_2(n);
3768        assert_eq!(l0.evaluate(from_const(1)), from_const(1));
3769        assert_eq!(l0.evaluate(omega), from_const(0));
3770        assert_eq!(l0.evaluate(omega.square()), from_const(0));
3771        assert_eq!(l0.evaluate(omega.cube()), from_const(0));
3772    }
3773
3774    #[test]
3775    fn test_lagrange0_two_adic_8() {
3776        let n = 8;
3777        let omega = Polynomial::domain_element2(1, n);
3778        let l0 = Polynomial::lagrange0_2(n);
3779        assert_eq!(l0.evaluate(from_const(1)), from_const(1));
3780        assert_eq!(l0.evaluate(omega), from_const(0));
3781        assert_eq!(l0.evaluate(omega.pow_small(2)), from_const(0));
3782        assert_eq!(l0.evaluate(omega.pow_small(3)), from_const(0));
3783        assert_eq!(l0.evaluate(omega.pow_small(4)), from_const(0));
3784        assert_eq!(l0.evaluate(omega.pow_small(5)), from_const(0));
3785        assert_eq!(l0.evaluate(omega.pow_small(6)), from_const(0));
3786        assert_eq!(l0.evaluate(omega.pow_small(7)), from_const(0));
3787    }
3788
3789    #[test]
3790    fn test_lagrange0_three_adic_1() {
3791        let n = 1;
3792        let l0 = Polynomial::lagrange0_3(n);
3793        assert_eq!(l0.evaluate(from_const(1)), from_const(1));
3794    }
3795
3796    #[test]
3797    fn test_lagrange0_three_adic_3() {
3798        let n = 3;
3799        let omega = Polynomial::domain_element3(1, n);
3800        let l0 = Polynomial::lagrange0_3(n);
3801        assert_eq!(l0.evaluate(from_const(1)), from_const(1));
3802        assert_eq!(l0.evaluate(omega), from_const(0));
3803        assert_eq!(l0.evaluate(omega.square()), from_const(0));
3804    }
3805
3806    #[test]
3807    fn test_lagrange0_three_adic_9() {
3808        let n = 9;
3809        let omega = Polynomial::domain_element3(1, n);
3810        let l0 = Polynomial::lagrange0_3(n);
3811        assert_eq!(l0.evaluate(from_const(1)), from_const(1));
3812        assert_eq!(l0.evaluate(omega), from_const(0));
3813        assert_eq!(l0.evaluate(omega.pow_small(2)), from_const(0));
3814        assert_eq!(l0.evaluate(omega.pow_small(3)), from_const(0));
3815        assert_eq!(l0.evaluate(omega.pow_small(4)), from_const(0));
3816        assert_eq!(l0.evaluate(omega.pow_small(5)), from_const(0));
3817        assert_eq!(l0.evaluate(omega.pow_small(6)), from_const(0));
3818        assert_eq!(l0.evaluate(omega.pow_small(7)), from_const(0));
3819        assert_eq!(l0.evaluate(omega.pow_small(8)), from_const(0));
3820    }
3821}