Skip to main content

starkom_poly/
poly.rs

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