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, from_const};
978    use starkom_ff::Field;
979
980    type Polynomial = super::Polynomial<Scalar>;
981
982    #[inline(always)]
983    fn get_random_scalar() -> Scalar {
984        Scalar::random_default()
985    }
986
987    fn from_roots(roots: &[Scalar]) -> Polynomial {
988        Polynomial::from_roots(roots, get_random_scalar()).unwrap()
989    }
990
991    #[test]
992    fn test_constant() {
993        let p = Polynomial::constant(from_const(42));
994        assert_eq!(p.evaluate(from_const(12)), from_const(42));
995        assert_eq!(p.evaluate(from_const(34)), from_const(42));
996        assert_eq!(p.evaluate(from_const(42)), from_const(42));
997    }
998
999    #[test]
1000    fn test_zero() {
1001        let p = Polynomial::with_coefficients(vec![]);
1002        assert_eq!(p, Polynomial::default());
1003        assert_eq!(p.len(), 0);
1004        assert_eq!(p.degree_bound(), 0);
1005        assert_eq!(p.evaluate(from_const(42)), from_const(0));
1006    }
1007
1008    #[test]
1009    fn test_with_coefficients() {
1010        let p = Polynomial::with_coefficients(vec![from_const(12), from_const(34), from_const(56)]);
1011        assert_eq!(p.len(), 3);
1012        assert_eq!(p.degree_bound(), 3);
1013        assert_eq!(
1014            p.take(),
1015            vec![from_const(12), from_const(34), from_const(56)]
1016        );
1017    }
1018
1019    #[test]
1020    fn test_low_degree() {
1021        let p = Polynomial::with_coefficients(vec![
1022            from_const(12),
1023            from_const(34),
1024            from_const(56),
1025            from_const(0),
1026            from_const(0),
1027        ]);
1028        assert_eq!(p.len(), 5);
1029        assert_eq!(p.degree_bound(), 3);
1030    }
1031
1032    #[test]
1033    fn test_skip_degree() {
1034        let p = Polynomial::with_coefficients(vec![
1035            from_const(0),
1036            from_const(0),
1037            from_const(12),
1038            from_const(34),
1039            from_const(56),
1040        ]);
1041        assert_eq!(p.len(), 5);
1042        assert_eq!(p.degree_bound(), 5);
1043    }
1044
1045    #[test]
1046    fn test_trim_degree() {
1047        let mut p = Polynomial::with_coefficients(vec![
1048            from_const(12),
1049            from_const(34),
1050            from_const(56),
1051            from_const(0),
1052            from_const(0),
1053        ]);
1054        p.trim();
1055        assert_eq!(p.len(), 3);
1056        assert_eq!(p.degree_bound(), 3);
1057    }
1058
1059    #[test]
1060    fn test_no_trim() {
1061        let mut p = Polynomial::with_coefficients(vec![
1062            from_const(0),
1063            from_const(0),
1064            from_const(12),
1065            from_const(34),
1066            from_const(56),
1067        ]);
1068        p.trim();
1069        assert_eq!(p.len(), 5);
1070        assert_eq!(p.degree_bound(), 5);
1071    }
1072
1073    #[test]
1074    fn test_trim_all_zero() {
1075        let mut p =
1076            Polynomial::with_coefficients(vec![from_const(0), from_const(0), from_const(0)]);
1077        p.trim();
1078        assert_eq!(p.len(), p.degree_bound());
1079        assert_eq!(p, Polynomial::default());
1080    }
1081
1082    #[test]
1083    fn test_pad_extends() {
1084        let mut p = Polynomial::with_coefficients(vec![from_const(12), from_const(34)]);
1085        p.pad(5);
1086        assert_eq!(p.len(), 5);
1087        assert_eq!(
1088            p.take(),
1089            vec![
1090                from_const(12),
1091                from_const(34),
1092                from_const(0),
1093                from_const(0),
1094                from_const(0)
1095            ]
1096        );
1097    }
1098
1099    #[test]
1100    fn test_pad_exact() {
1101        let mut p =
1102            Polynomial::with_coefficients(vec![from_const(12), from_const(34), from_const(56)]);
1103        p.pad(3);
1104        assert_eq!(p.len(), 3);
1105        assert_eq!(
1106            p.take(),
1107            vec![from_const(12), from_const(34), from_const(56)]
1108        );
1109    }
1110
1111    #[test]
1112    fn test_pad_no_shrink() {
1113        let mut p = Polynomial::with_coefficients(vec![
1114            from_const(12),
1115            from_const(34),
1116            from_const(56),
1117            from_const(78),
1118        ]);
1119        p.pad(2);
1120        assert_eq!(p.len(), 4);
1121        assert_eq!(
1122            p.take(),
1123            vec![
1124                from_const(12),
1125                from_const(34),
1126                from_const(56),
1127                from_const(78)
1128            ]
1129        );
1130    }
1131
1132    #[test]
1133    fn test_pad_empty() {
1134        let mut p = Polynomial::default();
1135        p.pad(3);
1136        assert_eq!(p.len(), 3);
1137        assert_eq!(p.take(), vec![from_const(0), from_const(0), from_const(0)]);
1138    }
1139
1140    #[test]
1141    fn test_pad_zero_bound() {
1142        let mut p = Polynomial::with_coefficients(vec![from_const(12), from_const(34)]);
1143        p.pad(0);
1144        assert_eq!(p.len(), 2);
1145        assert_eq!(p.take(), vec![from_const(12), from_const(34)]);
1146    }
1147
1148    #[test]
1149    fn test_pad_preserves_evaluation() {
1150        let mut p =
1151            Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
1152        let before = p.evaluate(from_const(7));
1153        p.pad(6);
1154        assert_eq!(p.evaluate(from_const(7)), before);
1155    }
1156
1157    #[test]
1158    fn test_no_roots() {
1159        let p = from_roots(&[]);
1160        assert_eq!(p.len(), 1);
1161        assert_eq!(p.degree_bound(), 1);
1162        assert_ne!(p.evaluate(from_const(12)), from_const(0));
1163        assert_ne!(p.evaluate(from_const(34)), from_const(0));
1164        assert_ne!(p.evaluate(from_const(56)), from_const(0));
1165        assert_ne!(p.evaluate(from_const(78)), from_const(0));
1166        assert_ne!(p.evaluate(from_const(90)), from_const(0));
1167        assert_ne!(p.evaluate(from_const(13)), from_const(0));
1168        assert_ne!(p.evaluate(from_const(57)), from_const(0));
1169        assert_ne!(p.evaluate(from_const(92)), from_const(0));
1170        assert_ne!(p.evaluate(from_const(46)), from_const(0));
1171        assert_ne!(p.evaluate(from_const(80)), from_const(0));
1172    }
1173
1174    #[test]
1175    fn test_one_root() {
1176        let p = from_roots(&[from_const(12)]);
1177        assert_eq!(p.len(), 2);
1178        assert_eq!(p.degree_bound(), 2);
1179        assert_eq!(p.evaluate(from_const(12)), from_const(0));
1180        assert_ne!(p.evaluate(from_const(34)), from_const(0));
1181        assert_ne!(p.evaluate(from_const(56)), from_const(0));
1182        assert_ne!(p.evaluate(from_const(78)), from_const(0));
1183        assert_ne!(p.evaluate(from_const(90)), from_const(0));
1184        assert_ne!(p.evaluate(from_const(13)), from_const(0));
1185        assert_ne!(p.evaluate(from_const(57)), from_const(0));
1186        assert_ne!(p.evaluate(from_const(92)), from_const(0));
1187        assert_ne!(p.evaluate(from_const(46)), from_const(0));
1188        assert_ne!(p.evaluate(from_const(80)), from_const(0));
1189        let (q, v) = p.horner(from_const(12));
1190        assert_eq!(q.len(), 1);
1191        assert_eq!(q.degree_bound(), 1);
1192        assert_eq!(v, from_const(0));
1193        let (q, v) = p.horner(from_const(34));
1194        assert_eq!(q.len(), 1);
1195        assert_eq!(q.degree_bound(), 1);
1196        assert_ne!(v, from_const(0));
1197    }
1198
1199    #[test]
1200    fn test_three_roots() {
1201        let p = from_roots(&[from_const(12), from_const(34), from_const(56)]);
1202        assert_eq!(p.len(), 4);
1203        assert_eq!(p.degree_bound(), 4);
1204        assert_eq!(p.evaluate(from_const(12)), from_const(0));
1205        assert_eq!(p.evaluate(from_const(34)), from_const(0));
1206        assert_eq!(p.evaluate(from_const(56)), from_const(0));
1207        assert_ne!(p.evaluate(from_const(78)), from_const(0));
1208        assert_ne!(p.evaluate(from_const(90)), from_const(0));
1209        assert_ne!(p.evaluate(from_const(13)), from_const(0));
1210        assert_ne!(p.evaluate(from_const(57)), from_const(0));
1211        assert_ne!(p.evaluate(from_const(92)), from_const(0));
1212        assert_ne!(p.evaluate(from_const(46)), from_const(0));
1213        assert_ne!(p.evaluate(from_const(80)), from_const(0));
1214        let (q, v) = p.horner(from_const(12));
1215        assert_eq!(q.len(), 3);
1216        assert_eq!(q.degree_bound(), 3);
1217        assert_eq!(v, from_const(0));
1218        let (q, v) = q.horner(from_const(34));
1219        assert_eq!(q.len(), 2);
1220        assert_eq!(q.degree_bound(), 2);
1221        assert_eq!(v, from_const(0));
1222        let (q, v) = q.horner(from_const(56));
1223        assert_eq!(q.len(), 1);
1224        assert_eq!(q.degree_bound(), 1);
1225        assert_eq!(v, from_const(0));
1226        let (q, v) = p.horner(from_const(78));
1227        assert_eq!(q.len(), 3);
1228        assert_eq!(q.degree_bound(), 3);
1229        assert_ne!(v, from_const(0));
1230        let (q, v) = p.horner(from_const(90));
1231        assert_eq!(q.len(), 3);
1232        assert_eq!(q.degree_bound(), 3);
1233        assert_ne!(v, from_const(0));
1234    }
1235
1236    #[test]
1237    fn test_three_roots_reverse_order() {
1238        let p = from_roots(&[from_const(56), from_const(34), from_const(12)]);
1239        assert_eq!(p.len(), 4);
1240        assert_eq!(p.degree_bound(), 4);
1241        assert_eq!(p.evaluate(from_const(12)), from_const(0));
1242        assert_eq!(p.evaluate(from_const(34)), from_const(0));
1243        assert_eq!(p.evaluate(from_const(56)), from_const(0));
1244        assert_ne!(p.evaluate(from_const(78)), from_const(0));
1245        assert_ne!(p.evaluate(from_const(90)), from_const(0));
1246        assert_ne!(p.evaluate(from_const(13)), from_const(0));
1247        assert_ne!(p.evaluate(from_const(57)), from_const(0));
1248        assert_ne!(p.evaluate(from_const(92)), from_const(0));
1249        assert_ne!(p.evaluate(from_const(46)), from_const(0));
1250        assert_ne!(p.evaluate(from_const(80)), from_const(0));
1251        let (q, v) = p.horner(from_const(12));
1252        assert_eq!(q.len(), 3);
1253        assert_eq!(q.degree_bound(), 3);
1254        assert_eq!(v, from_const(0));
1255        let (q, v) = q.horner(from_const(34));
1256        assert_eq!(q.len(), 2);
1257        assert_eq!(q.degree_bound(), 2);
1258        assert_eq!(v, from_const(0));
1259        let (q, v) = q.horner(from_const(56));
1260        assert_eq!(q.len(), 1);
1261        assert_eq!(q.degree_bound(), 1);
1262        assert_eq!(v, from_const(0));
1263        let (q, v) = p.horner(from_const(78));
1264        assert_eq!(q.len(), 3);
1265        assert_eq!(q.degree_bound(), 3);
1266        assert_ne!(v, from_const(0));
1267        let (q, v) = p.horner(from_const(90));
1268        assert_eq!(q.len(), 3);
1269        assert_eq!(q.degree_bound(), 3);
1270        assert_ne!(v, from_const(0));
1271    }
1272
1273    #[test]
1274    fn test_seven_roots() {
1275        let p = from_roots(&[
1276            from_const(12),
1277            from_const(34),
1278            from_const(56),
1279            from_const(78),
1280            from_const(90),
1281            from_const(13),
1282            from_const(57),
1283        ]);
1284        assert_eq!(p.len(), 8);
1285        assert_eq!(p.degree_bound(), 8);
1286        assert_eq!(p.evaluate(from_const(12)), from_const(0));
1287        assert_eq!(p.evaluate(from_const(34)), from_const(0));
1288        assert_eq!(p.evaluate(from_const(56)), from_const(0));
1289        assert_eq!(p.evaluate(from_const(78)), from_const(0));
1290        assert_eq!(p.evaluate(from_const(90)), from_const(0));
1291        assert_eq!(p.evaluate(from_const(13)), from_const(0));
1292        assert_eq!(p.evaluate(from_const(57)), from_const(0));
1293        assert_ne!(p.evaluate(from_const(92)), from_const(0));
1294        assert_ne!(p.evaluate(from_const(46)), from_const(0));
1295        assert_ne!(p.evaluate(from_const(80)), from_const(0));
1296    }
1297
1298    #[test]
1299    fn test_seven_roots_reverse_order() {
1300        let p = from_roots(&[
1301            from_const(57),
1302            from_const(13),
1303            from_const(90),
1304            from_const(78),
1305            from_const(56),
1306            from_const(34),
1307            from_const(12),
1308        ]);
1309        assert_eq!(p.len(), 8);
1310        assert_eq!(p.degree_bound(), 8);
1311        assert_eq!(p.evaluate(from_const(12)), from_const(0));
1312        assert_eq!(p.evaluate(from_const(34)), from_const(0));
1313        assert_eq!(p.evaluate(from_const(56)), from_const(0));
1314        assert_eq!(p.evaluate(from_const(78)), from_const(0));
1315        assert_eq!(p.evaluate(from_const(90)), from_const(0));
1316        assert_eq!(p.evaluate(from_const(13)), from_const(0));
1317        assert_eq!(p.evaluate(from_const(57)), from_const(0));
1318        assert_ne!(p.evaluate(from_const(92)), from_const(0));
1319        assert_ne!(p.evaluate(from_const(46)), from_const(0));
1320        assert_ne!(p.evaluate(from_const(80)), from_const(0));
1321    }
1322
1323    #[test]
1324    fn test_duplicate_roots() {
1325        assert!(
1326            Polynomial::from_roots(
1327                &[
1328                    from_const(12),
1329                    from_const(34),
1330                    from_const(56),
1331                    from_const(12),
1332                    from_const(90),
1333                    from_const(12),
1334                    from_const(57),
1335                ],
1336                get_random_scalar()
1337            )
1338            .is_err()
1339        );
1340    }
1341
1342    #[test]
1343    fn test_interpolate_zero_points() {
1344        let p = Polynomial::interpolate(&[]).unwrap();
1345        assert_eq!(p, Polynomial::default());
1346    }
1347
1348    #[test]
1349    fn test_interpolate_one_point1() {
1350        let p = Polynomial::interpolate(&[(from_const(12), from_const(34))]).unwrap();
1351        assert_eq!(p.len(), 1);
1352        assert_eq!(p.degree_bound(), 1);
1353        assert_eq!(p.evaluate(from_const(12)), from_const(34));
1354    }
1355
1356    #[test]
1357    fn test_interpolate_one_point2() {
1358        let p = Polynomial::interpolate(&[(from_const(34), from_const(56))]).unwrap();
1359        assert_eq!(p.len(), 1);
1360        assert_eq!(p.degree_bound(), 1);
1361        assert_eq!(p.evaluate(from_const(34)), from_const(56));
1362    }
1363
1364    #[test]
1365    fn test_interpolate_two_points1() {
1366        let p = Polynomial::interpolate(&[
1367            (from_const(12), from_const(34)),
1368            (from_const(56), from_const(78)),
1369        ])
1370        .unwrap();
1371        assert_eq!(p.len(), 2);
1372        assert_eq!(p.degree_bound(), 2);
1373        assert_eq!(p.evaluate(from_const(12)), from_const(34));
1374        assert_eq!(p.evaluate(from_const(56)), from_const(78));
1375    }
1376
1377    #[test]
1378    fn test_interpolate_two_points2() {
1379        let p = Polynomial::interpolate(&[
1380            (from_const(34), from_const(12)),
1381            (from_const(78), from_const(56)),
1382        ])
1383        .unwrap();
1384        assert_eq!(p.len(), 2);
1385        assert_eq!(p.degree_bound(), 2);
1386        assert_eq!(p.evaluate(from_const(34)), from_const(12));
1387        assert_eq!(p.evaluate(from_const(78)), from_const(56));
1388    }
1389
1390    #[test]
1391    fn test_interpolate_three_points1() {
1392        let p = Polynomial::interpolate(&[
1393            (from_const(12), from_const(34)),
1394            (from_const(56), from_const(78)),
1395            (from_const(90), from_const(12)),
1396        ])
1397        .unwrap();
1398        assert_eq!(p.len(), 3);
1399        assert_eq!(p.degree_bound(), 3);
1400        assert_eq!(p.evaluate(from_const(12)), from_const(34));
1401        assert_eq!(p.evaluate(from_const(56)), from_const(78));
1402        assert_eq!(p.evaluate(from_const(90)), from_const(12));
1403    }
1404
1405    #[test]
1406    fn test_interpolate_three_points2() {
1407        let p = Polynomial::interpolate(&[
1408            (from_const(34), from_const(12)),
1409            (from_const(78), from_const(56)),
1410            (from_const(12), from_const(90)),
1411        ])
1412        .unwrap();
1413        assert_eq!(p.len(), 3);
1414        assert_eq!(p.degree_bound(), 3);
1415        assert_eq!(p.evaluate(from_const(34)), from_const(12));
1416        assert_eq!(p.evaluate(from_const(78)), from_const(56));
1417        assert_eq!(p.evaluate(from_const(12)), from_const(90));
1418    }
1419
1420    #[test]
1421    fn test_duplicate_coordinates() {
1422        assert!(
1423            Polynomial::interpolate(&[
1424                (from_const(12), from_const(34)),
1425                (from_const(56), from_const(78)),
1426                (from_const(12), from_const(90)),
1427            ])
1428            .is_err()
1429        );
1430    }
1431
1432    #[test]
1433    fn test_encode2_one_value_1() {
1434        let p1 = Polynomial::encode2(vec![from_const(42)]);
1435        let p2 = Polynomial::encode2(vec![from_const(42)]);
1436        assert_eq!(p1, p2);
1437        assert_eq!(p1.len(), 1);
1438        assert_eq!(p1.degree_bound(), 1);
1439        assert_eq!(p2.len(), 1);
1440        assert_eq!(p2.degree_bound(), 1);
1441        assert_eq!(
1442            p1.evaluate(Polynomial::domain_element2(0, 1)),
1443            from_const(42)
1444        );
1445        assert_eq!(p1.evaluate_on_two_adic_domain(0, 1), from_const(42));
1446        assert_eq!(
1447            p2.evaluate(Polynomial::domain_element2(0, 1)),
1448            from_const(42)
1449        );
1450        assert_eq!(p2.evaluate_on_two_adic_domain(0, 1), from_const(42));
1451    }
1452
1453    #[test]
1454    fn test_encode2_one_value_2() {
1455        let p1 = Polynomial::encode2(vec![from_const(42)]);
1456        let p2 = Polynomial::encode2(vec![from_const(123)]);
1457        assert_eq!(p2.len(), 1);
1458        assert_eq!(p2.degree_bound(), 1);
1459        assert_ne!(p1, p2);
1460        assert_eq!(
1461            p2.evaluate(Polynomial::domain_element2(0, 1)),
1462            from_const(123)
1463        );
1464        assert_eq!(p2.evaluate_on_two_adic_domain(0, 1), from_const(123));
1465    }
1466
1467    #[test]
1468    fn test_encode2_two_values_1() {
1469        let p1 = Polynomial::encode2(vec![from_const(12), from_const(34)]);
1470        let p2 = Polynomial::encode2(vec![from_const(12), from_const(34)]);
1471        assert_eq!(p1, p2);
1472        assert_eq!(p1.len(), 2);
1473        assert_eq!(p1.degree_bound(), 2);
1474        assert_eq!(p2.len(), 2);
1475        assert_eq!(p2.degree_bound(), 2);
1476        assert_eq!(
1477            p1.evaluate(Polynomial::domain_element2(0, 2)),
1478            from_const(12)
1479        );
1480        assert_eq!(p1.evaluate_on_two_adic_domain(0, 2), from_const(12));
1481        assert_eq!(
1482            p1.evaluate(Polynomial::domain_element2(1, 2)),
1483            from_const(34)
1484        );
1485        assert_eq!(p1.evaluate_on_two_adic_domain(1, 2), from_const(34));
1486        assert_eq!(
1487            p2.evaluate(Polynomial::domain_element2(0, 2)),
1488            from_const(12)
1489        );
1490        assert_eq!(p2.evaluate_on_two_adic_domain(0, 2), from_const(12));
1491        assert_eq!(
1492            p2.evaluate(Polynomial::domain_element2(1, 2)),
1493            from_const(34)
1494        );
1495        assert_eq!(p2.evaluate_on_two_adic_domain(1, 2), from_const(34));
1496    }
1497
1498    #[test]
1499    fn test_encode2_two_values_2() {
1500        let p1 = Polynomial::encode2(vec![from_const(12), from_const(34)]);
1501        let p2 = Polynomial::encode2(vec![from_const(78), from_const(56)]);
1502        assert_eq!(p1.len(), 2);
1503        assert_eq!(p1.degree_bound(), 2);
1504        assert_eq!(p2.len(), 2);
1505        assert_eq!(p2.degree_bound(), 2);
1506        assert_ne!(p1, p2);
1507        assert_eq!(
1508            p2.evaluate(Polynomial::domain_element2(0, 2)),
1509            from_const(78)
1510        );
1511        assert_eq!(p2.evaluate_on_two_adic_domain(0, 2), from_const(78));
1512        assert_eq!(
1513            p2.evaluate(Polynomial::domain_element2(1, 2)),
1514            from_const(56)
1515        );
1516        assert_eq!(p2.evaluate_on_two_adic_domain(1, 2), from_const(56));
1517    }
1518
1519    #[test]
1520    fn test_encode2_three_values_1() {
1521        let p1 = Polynomial::encode2(vec![from_const(12), from_const(34), from_const(56)]);
1522        let p2 = Polynomial::encode2(vec![from_const(12), from_const(34), from_const(56)]);
1523        assert_eq!(p1, p2);
1524        assert_eq!(p1.len(), 4);
1525        assert_eq!(p1.degree_bound(), 4);
1526        assert_eq!(p2.len(), 4);
1527        assert_eq!(p2.degree_bound(), 4);
1528        assert_eq!(
1529            p1.evaluate(Polynomial::domain_element2(0, 3)),
1530            from_const(12)
1531        );
1532        assert_eq!(p1.evaluate_on_two_adic_domain(0, 3), from_const(12));
1533        assert_eq!(
1534            p1.evaluate(Polynomial::domain_element2(0, 4)),
1535            from_const(12)
1536        );
1537        assert_eq!(p1.evaluate_on_two_adic_domain(0, 4), from_const(12));
1538        assert_eq!(
1539            p1.evaluate(Polynomial::domain_element2(1, 3)),
1540            from_const(34)
1541        );
1542        assert_eq!(p1.evaluate_on_two_adic_domain(1, 3), from_const(34));
1543        assert_eq!(
1544            p1.evaluate(Polynomial::domain_element2(1, 4)),
1545            from_const(34)
1546        );
1547        assert_eq!(p1.evaluate_on_two_adic_domain(1, 4), from_const(34));
1548        assert_eq!(
1549            p1.evaluate(Polynomial::domain_element2(2, 3)),
1550            from_const(56)
1551        );
1552        assert_eq!(p1.evaluate_on_two_adic_domain(2, 3), from_const(56));
1553        assert_eq!(
1554            p1.evaluate(Polynomial::domain_element2(2, 4)),
1555            from_const(56)
1556        );
1557        assert_eq!(p1.evaluate_on_two_adic_domain(2, 4), from_const(56));
1558        assert_eq!(
1559            p1.evaluate(Polynomial::domain_element2(3, 4)),
1560            from_const(0)
1561        );
1562        assert_eq!(p1.evaluate_on_two_adic_domain(3, 4), from_const(0));
1563        assert_eq!(
1564            p2.evaluate(Polynomial::domain_element2(0, 3)),
1565            from_const(12)
1566        );
1567        assert_eq!(p2.evaluate_on_two_adic_domain(0, 3), from_const(12));
1568        assert_eq!(
1569            p2.evaluate(Polynomial::domain_element2(0, 4)),
1570            from_const(12)
1571        );
1572        assert_eq!(p2.evaluate_on_two_adic_domain(0, 4), from_const(12));
1573        assert_eq!(
1574            p2.evaluate(Polynomial::domain_element2(1, 3)),
1575            from_const(34)
1576        );
1577        assert_eq!(p2.evaluate_on_two_adic_domain(1, 3), from_const(34));
1578        assert_eq!(
1579            p2.evaluate(Polynomial::domain_element2(1, 4)),
1580            from_const(34)
1581        );
1582        assert_eq!(p2.evaluate_on_two_adic_domain(1, 4), from_const(34));
1583        assert_eq!(
1584            p2.evaluate(Polynomial::domain_element2(2, 3)),
1585            from_const(56)
1586        );
1587        assert_eq!(p2.evaluate_on_two_adic_domain(2, 3), from_const(56));
1588        assert_eq!(
1589            p2.evaluate(Polynomial::domain_element2(2, 4)),
1590            from_const(56)
1591        );
1592        assert_eq!(p2.evaluate_on_two_adic_domain(2, 4), from_const(56));
1593        assert_eq!(
1594            p2.evaluate(Polynomial::domain_element2(3, 4)),
1595            from_const(0)
1596        );
1597        assert_eq!(p2.evaluate_on_two_adic_domain(3, 4), from_const(0));
1598    }
1599
1600    #[test]
1601    fn test_encode2_three_values_2() {
1602        let p1 = Polynomial::encode2(vec![from_const(12), from_const(34), from_const(56)]);
1603        let p2 = Polynomial::encode2(vec![from_const(90), from_const(78), from_const(34)]);
1604        assert_eq!(p1.len(), 4);
1605        assert_eq!(p1.degree_bound(), 4);
1606        assert_eq!(p2.len(), 4);
1607        assert_eq!(p2.degree_bound(), 4);
1608        assert_ne!(p1, p2);
1609        assert_eq!(
1610            p2.evaluate(Polynomial::domain_element2(0, 3)),
1611            from_const(90)
1612        );
1613        assert_eq!(p2.evaluate_on_two_adic_domain(0, 3), from_const(90));
1614        assert_eq!(
1615            p2.evaluate(Polynomial::domain_element2(0, 4)),
1616            from_const(90)
1617        );
1618        assert_eq!(p2.evaluate_on_two_adic_domain(0, 4), from_const(90));
1619        assert_eq!(
1620            p2.evaluate(Polynomial::domain_element2(1, 3)),
1621            from_const(78)
1622        );
1623        assert_eq!(p2.evaluate_on_two_adic_domain(1, 3), from_const(78));
1624        assert_eq!(
1625            p2.evaluate(Polynomial::domain_element2(1, 4)),
1626            from_const(78)
1627        );
1628        assert_eq!(p2.evaluate_on_two_adic_domain(1, 4), from_const(78));
1629        assert_eq!(
1630            p2.evaluate(Polynomial::domain_element2(2, 3)),
1631            from_const(34)
1632        );
1633        assert_eq!(p2.evaluate_on_two_adic_domain(2, 3), from_const(34));
1634        assert_eq!(
1635            p2.evaluate(Polynomial::domain_element2(2, 4)),
1636            from_const(34)
1637        );
1638        assert_eq!(p2.evaluate_on_two_adic_domain(2, 4), from_const(34));
1639        assert_eq!(
1640            p2.evaluate(Polynomial::domain_element2(3, 4)),
1641            from_const(0)
1642        );
1643        assert_eq!(p2.evaluate_on_two_adic_domain(3, 4), from_const(0));
1644    }
1645
1646    #[test]
1647    fn test_encode2_four_values() {
1648        let p = Polynomial::encode2(vec![
1649            from_const(12),
1650            from_const(34),
1651            from_const(56),
1652            from_const(78),
1653        ]);
1654        assert_eq!(p.len(), 4);
1655        assert_eq!(p.degree_bound(), 4);
1656        assert_eq!(
1657            p.evaluate(Polynomial::domain_element2(0, 4)),
1658            from_const(12)
1659        );
1660        assert_eq!(p.evaluate_on_two_adic_domain(0, 4), from_const(12));
1661        assert_eq!(
1662            p.evaluate(Polynomial::domain_element2(1, 4)),
1663            from_const(34)
1664        );
1665        assert_eq!(p.evaluate_on_two_adic_domain(1, 4), from_const(34));
1666        assert_eq!(
1667            p.evaluate(Polynomial::domain_element2(2, 4)),
1668            from_const(56)
1669        );
1670        assert_eq!(p.evaluate_on_two_adic_domain(2, 4), from_const(56));
1671        assert_eq!(
1672            p.evaluate(Polynomial::domain_element2(3, 4)),
1673            from_const(78)
1674        );
1675        assert_eq!(p.evaluate_on_two_adic_domain(3, 4), from_const(78));
1676    }
1677
1678    #[test]
1679    fn test_decode2_one_value() {
1680        let values = vec![from_const(42)];
1681        let polynomial = Polynomial::encode2(values.clone());
1682        assert_eq!(polynomial.decode2(), values);
1683    }
1684
1685    #[test]
1686    fn test_decode2_two_values() {
1687        let values = vec![from_const(12), from_const(34)];
1688        let polynomial = Polynomial::encode2(values.clone());
1689        assert_eq!(polynomial.decode2(), values);
1690    }
1691
1692    #[test]
1693    fn test_decode2_three_values() {
1694        let polynomial = Polynomial::encode2(vec![from_const(12), from_const(34), from_const(56)]);
1695        assert_eq!(
1696            polynomial.decode2(),
1697            vec![
1698                from_const(12),
1699                from_const(34),
1700                from_const(56),
1701                from_const(0)
1702            ]
1703        );
1704    }
1705
1706    #[test]
1707    fn test_decode2_four_values() {
1708        let values = vec![
1709            from_const(12),
1710            from_const(34),
1711            from_const(56),
1712            from_const(78),
1713        ];
1714        let polynomial = Polynomial::encode2(values.clone());
1715        assert_eq!(polynomial.decode2(), values);
1716    }
1717
1718    #[test]
1719    fn test_encode3_one_value_1() {
1720        let p1 = Polynomial::encode3(vec![from_const(42)]);
1721        let p2 = Polynomial::encode3(vec![from_const(42)]);
1722        assert_eq!(p1, p2);
1723        assert_eq!(p1.len(), 1);
1724        assert_eq!(p1.degree_bound(), 1);
1725        assert_eq!(p2.len(), 1);
1726        assert_eq!(p2.degree_bound(), 1);
1727        assert_eq!(
1728            p1.evaluate(Polynomial::domain_element3(0, 1)),
1729            from_const(42)
1730        );
1731        assert_eq!(p1.evaluate_on_three_adic_domain(0, 1), from_const(42));
1732        assert_eq!(
1733            p2.evaluate(Polynomial::domain_element3(0, 1)),
1734            from_const(42)
1735        );
1736        assert_eq!(p2.evaluate_on_three_adic_domain(0, 1), from_const(42));
1737    }
1738
1739    #[test]
1740    fn test_encode3_one_value_2() {
1741        let p1 = Polynomial::encode3(vec![from_const(42)]);
1742        let p2 = Polynomial::encode3(vec![from_const(123)]);
1743        assert_eq!(p2.len(), 1);
1744        assert_eq!(p2.degree_bound(), 1);
1745        assert_ne!(p1, p2);
1746        assert_eq!(
1747            p2.evaluate(Polynomial::domain_element3(0, 1)),
1748            from_const(123)
1749        );
1750        assert_eq!(p2.evaluate_on_three_adic_domain(0, 1), from_const(123));
1751    }
1752
1753    #[test]
1754    fn test_encode3_two_values_1() {
1755        let p1 = Polynomial::encode3(vec![from_const(12), from_const(34)]);
1756        let p2 = Polynomial::encode3(vec![from_const(12), from_const(34)]);
1757        assert_eq!(p1, p2);
1758        assert_eq!(p1.len(), 3);
1759        assert_eq!(p1.degree_bound(), 3);
1760        assert_eq!(p2.len(), 3);
1761        assert_eq!(p2.degree_bound(), 3);
1762        assert_eq!(
1763            p1.evaluate(Polynomial::domain_element3(0, 2)),
1764            from_const(12)
1765        );
1766        assert_eq!(p1.evaluate_on_three_adic_domain(0, 2), from_const(12));
1767        assert_eq!(
1768            p1.evaluate(Polynomial::domain_element3(0, 3)),
1769            from_const(12)
1770        );
1771        assert_eq!(p1.evaluate_on_three_adic_domain(0, 3), from_const(12));
1772        assert_eq!(
1773            p1.evaluate(Polynomial::domain_element3(1, 2)),
1774            from_const(34)
1775        );
1776        assert_eq!(p1.evaluate_on_three_adic_domain(1, 2), from_const(34));
1777        assert_eq!(
1778            p1.evaluate(Polynomial::domain_element3(1, 3)),
1779            from_const(34)
1780        );
1781        assert_eq!(p1.evaluate_on_three_adic_domain(1, 3), from_const(34));
1782        assert_eq!(
1783            p1.evaluate(Polynomial::domain_element3(2, 3)),
1784            from_const(0)
1785        );
1786        assert_eq!(p1.evaluate_on_three_adic_domain(2, 3), from_const(0));
1787        assert_eq!(
1788            p2.evaluate(Polynomial::domain_element3(0, 2)),
1789            from_const(12)
1790        );
1791        assert_eq!(p2.evaluate_on_three_adic_domain(0, 2), from_const(12));
1792        assert_eq!(
1793            p2.evaluate(Polynomial::domain_element3(0, 3)),
1794            from_const(12)
1795        );
1796        assert_eq!(p2.evaluate_on_three_adic_domain(0, 3), from_const(12));
1797        assert_eq!(
1798            p2.evaluate(Polynomial::domain_element3(1, 2)),
1799            from_const(34)
1800        );
1801        assert_eq!(p2.evaluate_on_three_adic_domain(1, 2), from_const(34));
1802        assert_eq!(
1803            p2.evaluate(Polynomial::domain_element3(1, 3)),
1804            from_const(34)
1805        );
1806        assert_eq!(p2.evaluate_on_three_adic_domain(1, 3), from_const(34));
1807        assert_eq!(
1808            p2.evaluate(Polynomial::domain_element3(2, 3)),
1809            from_const(0)
1810        );
1811        assert_eq!(p2.evaluate_on_three_adic_domain(2, 3), from_const(0));
1812    }
1813
1814    #[test]
1815    fn test_encode3_two_values_2() {
1816        let p1 = Polynomial::encode3(vec![from_const(12), from_const(34)]);
1817        let p2 = Polynomial::encode3(vec![from_const(78), from_const(56)]);
1818        assert_eq!(p1.len(), 3);
1819        assert_eq!(p1.degree_bound(), 3);
1820        assert_eq!(p2.len(), 3);
1821        assert_eq!(p2.degree_bound(), 3);
1822        assert_ne!(p1, p2);
1823        assert_eq!(
1824            p2.evaluate(Polynomial::domain_element3(0, 2)),
1825            from_const(78)
1826        );
1827        assert_eq!(p2.evaluate_on_three_adic_domain(0, 2), from_const(78));
1828        assert_eq!(
1829            p2.evaluate(Polynomial::domain_element3(1, 2)),
1830            from_const(56)
1831        );
1832        assert_eq!(p2.evaluate_on_three_adic_domain(1, 2), from_const(56));
1833        assert_eq!(
1834            p2.evaluate(Polynomial::domain_element3(2, 3)),
1835            from_const(0)
1836        );
1837        assert_eq!(p2.evaluate_on_three_adic_domain(2, 3), from_const(0));
1838    }
1839
1840    #[test]
1841    fn test_encode3_three_values_1() {
1842        let p1 = Polynomial::encode3(vec![from_const(12), from_const(34), from_const(56)]);
1843        let p2 = Polynomial::encode3(vec![from_const(12), from_const(34), from_const(56)]);
1844        assert_eq!(p1, p2);
1845        assert_eq!(p1.len(), 3);
1846        assert_eq!(p1.degree_bound(), 3);
1847        assert_eq!(p2.len(), 3);
1848        assert_eq!(p2.degree_bound(), 3);
1849        assert_eq!(
1850            p1.evaluate(Polynomial::domain_element3(0, 3)),
1851            from_const(12)
1852        );
1853        assert_eq!(p1.evaluate_on_three_adic_domain(0, 3), from_const(12));
1854        assert_eq!(
1855            p1.evaluate(Polynomial::domain_element3(1, 3)),
1856            from_const(34)
1857        );
1858        assert_eq!(p1.evaluate_on_three_adic_domain(1, 3), from_const(34));
1859        assert_eq!(
1860            p1.evaluate(Polynomial::domain_element3(2, 3)),
1861            from_const(56)
1862        );
1863        assert_eq!(p1.evaluate_on_three_adic_domain(2, 3), from_const(56));
1864        assert_eq!(
1865            p2.evaluate(Polynomial::domain_element3(0, 3)),
1866            from_const(12)
1867        );
1868        assert_eq!(p2.evaluate_on_three_adic_domain(0, 3), from_const(12));
1869        assert_eq!(
1870            p2.evaluate(Polynomial::domain_element3(1, 3)),
1871            from_const(34)
1872        );
1873        assert_eq!(p2.evaluate_on_three_adic_domain(1, 3), from_const(34));
1874        assert_eq!(
1875            p2.evaluate(Polynomial::domain_element3(2, 3)),
1876            from_const(56)
1877        );
1878        assert_eq!(p2.evaluate_on_three_adic_domain(2, 3), from_const(56));
1879    }
1880
1881    #[test]
1882    fn test_encode3_three_values_2() {
1883        let p1 = Polynomial::encode3(vec![from_const(12), from_const(34), from_const(56)]);
1884        let p2 = Polynomial::encode3(vec![from_const(90), from_const(78), from_const(34)]);
1885        assert_eq!(p1.len(), 3);
1886        assert_eq!(p1.degree_bound(), 3);
1887        assert_eq!(p2.len(), 3);
1888        assert_eq!(p2.degree_bound(), 3);
1889        assert_ne!(p1, p2);
1890        assert_eq!(
1891            p2.evaluate(Polynomial::domain_element3(0, 3)),
1892            from_const(90)
1893        );
1894        assert_eq!(p2.evaluate_on_three_adic_domain(0, 3), from_const(90));
1895        assert_eq!(
1896            p2.evaluate(Polynomial::domain_element3(1, 3)),
1897            from_const(78)
1898        );
1899        assert_eq!(p2.evaluate_on_three_adic_domain(1, 3), from_const(78));
1900        assert_eq!(
1901            p2.evaluate(Polynomial::domain_element3(2, 3)),
1902            from_const(34)
1903        );
1904        assert_eq!(p2.evaluate_on_three_adic_domain(2, 3), from_const(34));
1905    }
1906
1907    #[test]
1908    fn test_encode3_nine_values3() {
1909        let p = Polynomial::encode3(vec![
1910            from_const(12),
1911            from_const(34),
1912            from_const(56),
1913            from_const(78),
1914            from_const(90),
1915            from_const(11),
1916            from_const(22),
1917            from_const(33),
1918            from_const(44),
1919        ]);
1920        assert_eq!(p.len(), 9);
1921        assert_eq!(p.degree_bound(), 9);
1922        assert_eq!(
1923            p.evaluate(Polynomial::domain_element3(0, 9)),
1924            from_const(12)
1925        );
1926        assert_eq!(p.evaluate_on_three_adic_domain(0, 9), from_const(12));
1927        assert_eq!(
1928            p.evaluate(Polynomial::domain_element3(1, 9)),
1929            from_const(34)
1930        );
1931        assert_eq!(p.evaluate_on_three_adic_domain(1, 9), from_const(34));
1932        assert_eq!(
1933            p.evaluate(Polynomial::domain_element3(2, 9)),
1934            from_const(56)
1935        );
1936        assert_eq!(p.evaluate_on_three_adic_domain(2, 9), from_const(56));
1937        assert_eq!(
1938            p.evaluate(Polynomial::domain_element3(3, 9)),
1939            from_const(78)
1940        );
1941        assert_eq!(p.evaluate_on_three_adic_domain(3, 9), from_const(78));
1942        assert_eq!(
1943            p.evaluate(Polynomial::domain_element3(4, 9)),
1944            from_const(90)
1945        );
1946        assert_eq!(p.evaluate_on_three_adic_domain(4, 9), from_const(90));
1947        assert_eq!(
1948            p.evaluate(Polynomial::domain_element3(5, 9)),
1949            from_const(11)
1950        );
1951        assert_eq!(p.evaluate_on_three_adic_domain(5, 9), from_const(11));
1952        assert_eq!(
1953            p.evaluate(Polynomial::domain_element3(6, 9)),
1954            from_const(22)
1955        );
1956        assert_eq!(p.evaluate_on_three_adic_domain(6, 9), from_const(22));
1957        assert_eq!(
1958            p.evaluate(Polynomial::domain_element3(7, 9)),
1959            from_const(33)
1960        );
1961        assert_eq!(p.evaluate_on_three_adic_domain(7, 9), from_const(33));
1962        assert_eq!(
1963            p.evaluate(Polynomial::domain_element3(8, 9)),
1964            from_const(44)
1965        );
1966        assert_eq!(p.evaluate_on_three_adic_domain(8, 9), from_const(44));
1967    }
1968
1969    #[test]
1970    fn test_decode3_one_value() {
1971        let values = vec![from_const(42)];
1972        let polynomial = Polynomial::encode3(values.clone());
1973        assert_eq!(polynomial.decode3(), values);
1974    }
1975
1976    #[test]
1977    fn test_decode3_two_values() {
1978        let values = vec![from_const(12), from_const(34)];
1979        let polynomial = Polynomial::encode3(values.clone());
1980        assert_eq!(
1981            polynomial.decode3(),
1982            vec![from_const(12), from_const(34), from_const(0)]
1983        );
1984    }
1985
1986    #[test]
1987    fn test_decode3_three_values() {
1988        let values = vec![from_const(12), from_const(34), from_const(56)];
1989        let polynomial = Polynomial::encode3(values.clone());
1990        assert_eq!(polynomial.decode3(), values);
1991    }
1992
1993    #[test]
1994    fn test_decode3_nine_values() {
1995        let values = vec![
1996            from_const(12),
1997            from_const(34),
1998            from_const(56),
1999            from_const(78),
2000            from_const(90),
2001            from_const(11),
2002            from_const(22),
2003            from_const(33),
2004            from_const(44),
2005        ];
2006        let polynomial = Polynomial::encode3(values.clone());
2007        assert_eq!(polynomial.decode3(), values);
2008    }
2009
2010    #[test]
2011    fn test_add_same_length() {
2012        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2013        let p2 =
2014            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2015        assert_eq!(
2016            p1 + p2,
2017            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(33)])
2018        );
2019    }
2020
2021    #[test]
2022    fn test_add_lhs_longer() {
2023        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2024        let p2 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2025        assert_eq!(
2026            p1 + p2,
2027            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(3)])
2028        );
2029    }
2030
2031    #[test]
2032    fn test_add_rhs_longer() {
2033        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2034        let p2 =
2035            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2036        assert_eq!(
2037            p1 + p2,
2038            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(30)])
2039        );
2040    }
2041
2042    #[test]
2043    fn test_add_commutative() {
2044        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2045        let p2 =
2046            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2047        assert_eq!(p1.clone() + p2.clone(), p2 + p1);
2048    }
2049
2050    #[test]
2051    fn test_add_assign_same_length() {
2052        let mut p1 =
2053            Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2054        let p2 =
2055            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2056        p1 += p2;
2057        assert_eq!(
2058            p1,
2059            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(33)])
2060        );
2061    }
2062
2063    #[test]
2064    fn test_add_assign_lhs_longer() {
2065        let mut p1 =
2066            Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2067        let p2 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2068        p1 += p2;
2069        assert_eq!(
2070            p1,
2071            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(3)])
2072        );
2073    }
2074
2075    #[test]
2076    fn test_add_assign_rhs_longer() {
2077        let mut p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2078        let p2 =
2079            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2080        p1 += p2;
2081        assert_eq!(
2082            p1,
2083            Polynomial::with_coefficients(vec![from_const(11), from_const(22), from_const(30)])
2084        );
2085    }
2086
2087    #[test]
2088    fn test_add_assign_consistent_with_add() {
2089        let p1 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2090        let p2 =
2091            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2092        let mut p1_assign = p1.clone();
2093        p1_assign += p2.clone();
2094        assert_eq!(p1_assign, p1 + p2);
2095    }
2096
2097    #[test]
2098    fn test_sub_same_length() {
2099        let p1 =
2100            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2101        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2102        assert_eq!(
2103            p1 - p2,
2104            Polynomial::with_coefficients(vec![from_const(9), from_const(18), from_const(27)])
2105        );
2106    }
2107
2108    #[test]
2109    fn test_sub_lhs_longer() {
2110        let p1 =
2111            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2112        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2113        assert_eq!(
2114            p1 - p2,
2115            Polynomial::with_coefficients(vec![from_const(9), from_const(18), from_const(30)])
2116        );
2117    }
2118
2119    #[test]
2120    fn test_sub_rhs_longer() {
2121        let p1 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2122        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2123        assert_eq!(
2124            p1 - p2,
2125            Polynomial::with_coefficients(vec![from_const(9), from_const(18), -from_const(3)])
2126        );
2127    }
2128
2129    #[test]
2130    fn test_sub_anticommutative() {
2131        let p1 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2132        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2133        assert_eq!(p1.clone() - p2.clone(), -(p2 - p1));
2134    }
2135
2136    #[test]
2137    fn test_sub_assign_same_length() {
2138        let mut p1 =
2139            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2140        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2141        p1 -= p2;
2142        assert_eq!(
2143            p1,
2144            Polynomial::with_coefficients(vec![from_const(9), from_const(18), from_const(27)])
2145        );
2146    }
2147
2148    #[test]
2149    fn test_sub_assign_lhs_longer() {
2150        let mut p1 =
2151            Polynomial::with_coefficients(vec![from_const(10), from_const(20), from_const(30)]);
2152        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2153        p1 -= p2;
2154        assert_eq!(
2155            p1,
2156            Polynomial::with_coefficients(vec![from_const(9), from_const(18), from_const(30)])
2157        );
2158    }
2159
2160    #[test]
2161    fn test_sub_assign_rhs_longer() {
2162        let mut p1 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2163        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2164        p1 -= p2;
2165        assert_eq!(
2166            p1,
2167            Polynomial::with_coefficients(vec![from_const(9), from_const(18), -from_const(3)])
2168        );
2169    }
2170
2171    #[test]
2172    fn test_sub_assign_consistent_with_sub() {
2173        let p1 = Polynomial::with_coefficients(vec![from_const(10), from_const(20)]);
2174        let p2 = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2175        let mut p1_assign = p1.clone();
2176        p1_assign -= p2.clone();
2177        assert_eq!(p1_assign, p1 - p2);
2178    }
2179
2180    #[test]
2181    fn test_multiply_empty() {
2182        let p1 = Polynomial::default();
2183        let p2 = Polynomial::default();
2184        assert_eq!(p1.multiply(p2), Polynomial::default());
2185    }
2186
2187    #[test]
2188    fn test_multiply_empty_by_non_empty() {
2189        let p1 = Polynomial::default();
2190        let p2 = Polynomial {
2191            coefficients: vec![from_const(12), from_const(34)],
2192        };
2193        assert_eq!(p1.multiply(p2), Polynomial::default());
2194    }
2195
2196    #[test]
2197    fn test_multiply_non_empty_by_empty() {
2198        let p1 = Polynomial {
2199            coefficients: vec![from_const(56), from_const(78)],
2200        };
2201        let p2 = Polynomial::default();
2202        assert_eq!(p1.multiply(p2), Polynomial::default());
2203    }
2204
2205    #[test]
2206    fn test_multiply_constant() {
2207        let p1 = Polynomial {
2208            coefficients: vec![from_const(3)],
2209        };
2210        let p2 = Polynomial {
2211            coefficients: vec![from_const(12), from_const(34), from_const(56)],
2212        };
2213        assert_eq!(
2214            p1.multiply(p2),
2215            Polynomial {
2216                coefficients: vec![from_const(36), from_const(102), from_const(168)]
2217            }
2218        );
2219    }
2220
2221    #[test]
2222    fn test_multiply_by_constant() {
2223        let p1 = Polynomial {
2224            coefficients: vec![from_const(12), from_const(34), from_const(56)],
2225        };
2226        let p2 = Polynomial {
2227            coefficients: vec![from_const(3)],
2228        };
2229        assert_eq!(
2230            p1.multiply(p2),
2231            Polynomial {
2232                coefficients: vec![from_const(36), from_const(102), from_const(168)]
2233            }
2234        );
2235    }
2236
2237    #[test]
2238    fn test_multiply_constant_by_constant() {
2239        let p1 = Polynomial {
2240            coefficients: vec![from_const(12)],
2241        };
2242        let p2 = Polynomial {
2243            coefficients: vec![from_const(34)],
2244        };
2245        assert_eq!(
2246            p1.multiply(p2),
2247            Polynomial {
2248                coefficients: vec![from_const(408)]
2249            }
2250        );
2251    }
2252
2253    #[test]
2254    fn test_multiply_polynomials1() {
2255        let p1 = Polynomial {
2256            coefficients: vec![from_const(1), from_const(2)],
2257        };
2258        let p2 = Polynomial {
2259            coefficients: vec![from_const(3), from_const(4)],
2260        };
2261        let result = Polynomial {
2262            coefficients: vec![from_const(3), from_const(10), from_const(8)],
2263        };
2264        assert_eq!(p1.clone().multiply(p2.clone()), result);
2265        assert_eq!(p2.multiply(p1), result);
2266    }
2267
2268    #[test]
2269    fn test_multiply_polynomials2() {
2270        let p1 = Polynomial {
2271            coefficients: vec![from_const(1), from_const(2)],
2272        };
2273        let p2 = Polynomial {
2274            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2275        };
2276        let result = Polynomial {
2277            coefficients: vec![
2278                from_const(3),
2279                from_const(10),
2280                from_const(13),
2281                from_const(10),
2282            ],
2283        };
2284        assert_eq!(p1.clone().multiply(p2.clone()), result);
2285        assert_eq!(p2.multiply(p1), result);
2286    }
2287
2288    #[test]
2289    fn test_polynomial_mul_op() {
2290        let p1 = Polynomial {
2291            coefficients: vec![from_const(1), from_const(2)],
2292        };
2293        let p2 = Polynomial {
2294            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2295        };
2296        let result = Polynomial {
2297            coefficients: vec![
2298                from_const(3),
2299                from_const(10),
2300                from_const(13),
2301                from_const(10),
2302            ],
2303        };
2304        assert_eq!(p1.clone() * p2.clone(), result);
2305        assert_eq!(p2 * p1, result);
2306    }
2307
2308    #[test]
2309    fn test_polynomial_mul_assign() {
2310        let mut p1 = Polynomial {
2311            coefficients: vec![from_const(1), from_const(2)],
2312        };
2313        let p2 = Polynomial {
2314            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2315        };
2316        p1 *= p2;
2317        assert_eq!(
2318            p1,
2319            Polynomial {
2320                coefficients: vec![
2321                    from_const(3),
2322                    from_const(10),
2323                    from_const(13),
2324                    from_const(10)
2325                ],
2326            }
2327        );
2328    }
2329
2330    #[test]
2331    fn test_multiply_one_polynomial() {
2332        let p = Polynomial {
2333            coefficients: vec![from_const(12), from_const(34)],
2334        };
2335        assert_eq!(Polynomial::multiply_many([p.clone()]), p);
2336    }
2337
2338    #[test]
2339    fn test_multiply_two_polynomials() {
2340        let p1 = Polynomial {
2341            coefficients: vec![from_const(1), from_const(2)],
2342        };
2343        let p2 = Polynomial {
2344            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2345        };
2346        let result = Polynomial {
2347            coefficients: vec![
2348                from_const(3),
2349                from_const(10),
2350                from_const(13),
2351                from_const(10),
2352            ],
2353        };
2354        assert_eq!(Polynomial::multiply_many([p1.clone(), p2.clone()]), result);
2355        assert_eq!(Polynomial::multiply_many([p2, p1]), result);
2356    }
2357
2358    #[test]
2359    fn test_multiply_three_polynomials() {
2360        let p1 = Polynomial {
2361            coefficients: vec![from_const(1), from_const(2)],
2362        };
2363        let p2 = Polynomial {
2364            coefficients: vec![from_const(3), from_const(4), from_const(5)],
2365        };
2366        let p3 = Polynomial {
2367            coefficients: vec![from_const(6), from_const(7), from_const(8), from_const(9)],
2368        };
2369        let result = Polynomial {
2370            coefficients: vec![
2371                from_const(18),
2372                from_const(81),
2373                from_const(172),
2374                from_const(258),
2375                from_const(264),
2376                from_const(197),
2377                from_const(90),
2378            ],
2379        };
2380        assert_eq!(
2381            Polynomial::multiply_many([p1.clone(), p2.clone(), p3.clone()]),
2382            result
2383        );
2384        assert_eq!(
2385            Polynomial::multiply_many([p1.clone(), p3.clone(), p2.clone()]),
2386            result
2387        );
2388        assert_eq!(
2389            Polynomial::multiply_many([p2.clone(), p1.clone(), p3.clone()]),
2390            result
2391        );
2392        assert_eq!(
2393            Polynomial::multiply_many([p2.clone(), p3.clone(), p1.clone()]),
2394            result
2395        );
2396        assert_eq!(
2397            Polynomial::multiply_many([p3.clone(), p1.clone(), p2.clone()]),
2398            result
2399        );
2400        assert_eq!(
2401            Polynomial::multiply_many([p3.clone(), p2.clone(), p1.clone()]),
2402            result
2403        );
2404    }
2405
2406    #[test]
2407    fn test_multiply_four_polynomials() {
2408        let p1 = Polynomial {
2409            coefficients: vec![from_const(1), from_const(2)],
2410        };
2411        let p2 = Polynomial {
2412            coefficients: vec![from_const(3), from_const(4)],
2413        };
2414        let p3 = Polynomial {
2415            coefficients: vec![from_const(5), from_const(6)],
2416        };
2417        let p4 = Polynomial {
2418            coefficients: vec![from_const(7), from_const(8)],
2419        };
2420        let result = Polynomial {
2421            coefficients: vec![
2422                from_const(105),
2423                from_const(596),
2424                from_const(1244),
2425                from_const(1136),
2426                from_const(384),
2427            ],
2428        };
2429        assert_eq!(
2430            Polynomial::multiply_many([p1.clone(), p2.clone(), p3.clone(), p4.clone()]),
2431            result
2432        );
2433        assert_eq!(
2434            Polynomial::multiply_many([p1.clone(), p2.clone(), p4.clone(), p3.clone()]),
2435            result
2436        );
2437        assert_eq!(
2438            Polynomial::multiply_many([p1.clone(), p3.clone(), p2.clone(), p4.clone()]),
2439            result
2440        );
2441        assert_eq!(
2442            Polynomial::multiply_many([p1.clone(), p3.clone(), p4.clone(), p2.clone()]),
2443            result
2444        );
2445        // okay, not gonna try all permutations -- too much typing for too little gain.
2446    }
2447
2448    #[test]
2449    fn test_divide_zero_by_zero() {
2450        let z = Polynomial {
2451            coefficients: vec![
2452                -from_const(1),
2453                from_const(0),
2454                from_const(0),
2455                from_const(0),
2456                from_const(1),
2457            ],
2458        };
2459        assert_eq!(
2460            z.divide_by_zero(4).unwrap(),
2461            Polynomial {
2462                coefficients: vec![from_const(1)]
2463            }
2464        );
2465    }
2466
2467    #[test]
2468    fn test_non_trivial_quotient1() {
2469        let ql = Polynomial::encode2(vec![
2470            from_const(0),
2471            from_const(0),
2472            from_const(1),
2473            from_const(1),
2474        ]);
2475        let qr = Polynomial::encode2(vec![
2476            from_const(0),
2477            from_const(0),
2478            from_const(1),
2479            from_const(1),
2480        ]);
2481        let qo = Polynomial::encode2(vec![-from_const(1); 4]);
2482        let qm = Polynomial::encode2(vec![
2483            from_const(1),
2484            from_const(1),
2485            from_const(0),
2486            from_const(0),
2487        ]);
2488        let qc = Polynomial::encode2(vec![from_const(0); 4]);
2489        let l = Polynomial::encode2(vec![
2490            from_const(3),
2491            from_const(9),
2492            from_const(3),
2493            from_const(30),
2494        ]);
2495        let r = Polynomial::encode2(vec![
2496            from_const(3),
2497            from_const(3),
2498            from_const(27),
2499            from_const(5),
2500        ]);
2501        let o = Polynomial::encode2(vec![
2502            from_const(9),
2503            from_const(27),
2504            from_const(30),
2505            from_const(35),
2506        ]);
2507        let lr = l.clone().multiply(r.clone());
2508        let p = ql.multiply(l) + qr.multiply(r) + qo.multiply(o) + qm.multiply(lr) + qc;
2509        let q = p.divide_by_zero(4).unwrap();
2510        assert_eq!(q.len(), 6);
2511        assert_eq!(q.degree_bound(), 6);
2512    }
2513
2514    #[test]
2515    fn test_non_trivial_quotient2() {
2516        let ql = Polynomial::encode2(vec![
2517            from_const(0),
2518            from_const(0),
2519            from_const(1),
2520            from_const(1),
2521        ]);
2522        let qr = Polynomial::encode2(vec![
2523            from_const(0),
2524            from_const(0),
2525            from_const(1),
2526            from_const(5),
2527        ]);
2528        let qo = Polynomial::encode2(vec![-from_const(1); 4]);
2529        let qm = Polynomial::encode2(vec![
2530            from_const(1),
2531            from_const(1),
2532            from_const(0),
2533            from_const(0),
2534        ]);
2535        let qc = Polynomial::encode2(vec![from_const(0); 4]);
2536        let l = Polynomial::encode2(vec![
2537            from_const(3),
2538            from_const(9),
2539            from_const(3),
2540            from_const(30),
2541        ]);
2542        let r = Polynomial::encode2(vec![
2543            from_const(3),
2544            from_const(3),
2545            from_const(27),
2546            from_const(1),
2547        ]);
2548        let o = Polynomial::encode2(vec![
2549            from_const(9),
2550            from_const(27),
2551            from_const(30),
2552            from_const(35),
2553        ]);
2554        let lr = l.clone().multiply(r.clone());
2555        let p = ql.multiply(l) + qr.multiply(r) + qo.multiply(o) + qm.multiply(lr) + qc;
2556        let q = p.divide_by_zero(4).unwrap();
2557        assert_eq!(q.len(), 6);
2558        assert_eq!(q.degree_bound(), 6);
2559    }
2560
2561    #[test]
2562    fn test_shift_domain2() {
2563        let values = vec![
2564            from_const(12),
2565            from_const(34),
2566            from_const(56),
2567            from_const(78),
2568        ];
2569        let p = Polynomial::encode2(values);
2570        let shifted = p.clone().shift_domain();
2571        assert_eq!(
2572            shifted.evaluate_on_two_adic_domain(0, 4),
2573            p.evaluate_on_two_adic_coset(0, 4)
2574        );
2575        assert_eq!(
2576            shifted.evaluate_on_two_adic_domain(1, 4),
2577            p.evaluate_on_two_adic_coset(1, 4)
2578        );
2579        assert_eq!(
2580            shifted.evaluate_on_two_adic_domain(2, 4),
2581            p.evaluate_on_two_adic_coset(2, 4)
2582        );
2583        assert_eq!(
2584            shifted.evaluate_on_two_adic_domain(3, 4),
2585            p.evaluate_on_two_adic_coset(3, 4)
2586        );
2587    }
2588
2589    #[test]
2590    fn test_shift_domain3() {
2591        let values = vec![from_const(12), from_const(34), from_const(56)];
2592        let p = Polynomial::encode3(values);
2593        let shifted = p.clone().shift_domain();
2594        assert_eq!(
2595            shifted.evaluate_on_three_adic_domain(0, 3),
2596            p.evaluate_on_three_adic_coset(0, 3)
2597        );
2598        assert_eq!(
2599            shifted.evaluate_on_three_adic_domain(1, 3),
2600            p.evaluate_on_three_adic_coset(1, 3)
2601        );
2602        assert_eq!(
2603            shifted.evaluate_on_three_adic_domain(2, 3),
2604            p.evaluate_on_three_adic_coset(2, 3)
2605        );
2606    }
2607
2608    #[test]
2609    fn test_lde2_blowup2() {
2610        let values = vec![
2611            from_const(12),
2612            from_const(34),
2613            from_const(56),
2614            from_const(78),
2615        ];
2616        let p = Polynomial::encode2(values);
2617        let lde = p.clone().lde2(8);
2618        assert_eq!(
2619            lde,
2620            vec![
2621                p.evaluate_on_two_adic_domain(0, 8),
2622                p.evaluate_on_two_adic_domain(1, 8),
2623                p.evaluate_on_two_adic_domain(2, 8),
2624                p.evaluate_on_two_adic_domain(3, 8),
2625                p.evaluate_on_two_adic_domain(4, 8),
2626                p.evaluate_on_two_adic_domain(5, 8),
2627                p.evaluate_on_two_adic_domain(6, 8),
2628                p.evaluate_on_two_adic_domain(7, 8),
2629            ]
2630        );
2631    }
2632
2633    #[test]
2634    fn test_lde2_blowup4() {
2635        let values = vec![from_const(1), from_const(2), from_const(3), from_const(4)];
2636        let p = Polynomial::encode2(values);
2637        let lde = p.clone().lde2(16);
2638        assert_eq!(
2639            lde,
2640            vec![
2641                p.evaluate_on_two_adic_domain(0, 16),
2642                p.evaluate_on_two_adic_domain(1, 16),
2643                p.evaluate_on_two_adic_domain(2, 16),
2644                p.evaluate_on_two_adic_domain(3, 16),
2645                p.evaluate_on_two_adic_domain(4, 16),
2646                p.evaluate_on_two_adic_domain(5, 16),
2647                p.evaluate_on_two_adic_domain(6, 16),
2648                p.evaluate_on_two_adic_domain(7, 16),
2649                p.evaluate_on_two_adic_domain(8, 16),
2650                p.evaluate_on_two_adic_domain(9, 16),
2651                p.evaluate_on_two_adic_domain(10, 16),
2652                p.evaluate_on_two_adic_domain(11, 16),
2653                p.evaluate_on_two_adic_domain(12, 16),
2654                p.evaluate_on_two_adic_domain(13, 16),
2655                p.evaluate_on_two_adic_domain(14, 16),
2656                p.evaluate_on_two_adic_domain(15, 16),
2657            ]
2658        );
2659    }
2660
2661    #[test]
2662    fn test_lde2_shorter_polynomial() {
2663        let values = vec![from_const(42), from_const(42)];
2664        let p = Polynomial::encode2(values);
2665        assert_eq!(p.len(), 1);
2666        assert_eq!(p.degree_bound(), 1);
2667        let lde = p.clone().lde2(4);
2668        assert_eq!(
2669            lde,
2670            vec![
2671                p.evaluate_on_two_adic_domain(0, 4),
2672                p.evaluate_on_two_adic_domain(1, 4),
2673                p.evaluate_on_two_adic_domain(2, 4),
2674                p.evaluate_on_two_adic_domain(3, 4),
2675            ]
2676        );
2677    }
2678
2679    #[test]
2680    fn test_lde3_blowup3() {
2681        let values = vec![from_const(12), from_const(34), from_const(56)];
2682        let p = Polynomial::encode3(values);
2683        let lde = p.clone().lde3(9);
2684        assert_eq!(
2685            lde,
2686            vec![
2687                p.evaluate_on_three_adic_domain(0, 9),
2688                p.evaluate_on_three_adic_domain(1, 9),
2689                p.evaluate_on_three_adic_domain(2, 9),
2690                p.evaluate_on_three_adic_domain(3, 9),
2691                p.evaluate_on_three_adic_domain(4, 9),
2692                p.evaluate_on_three_adic_domain(5, 9),
2693                p.evaluate_on_three_adic_domain(6, 9),
2694                p.evaluate_on_three_adic_domain(7, 9),
2695                p.evaluate_on_three_adic_domain(8, 9),
2696            ]
2697        );
2698    }
2699
2700    #[test]
2701    fn test_lde3_blowup9() {
2702        let values = vec![from_const(1), from_const(2), from_const(3)];
2703        let p = Polynomial::encode3(values);
2704        let lde = p.clone().lde3(27);
2705        assert_eq!(
2706            lde,
2707            vec![
2708                p.evaluate_on_three_adic_domain(0, 27),
2709                p.evaluate_on_three_adic_domain(1, 27),
2710                p.evaluate_on_three_adic_domain(2, 27),
2711                p.evaluate_on_three_adic_domain(3, 27),
2712                p.evaluate_on_three_adic_domain(4, 27),
2713                p.evaluate_on_three_adic_domain(5, 27),
2714                p.evaluate_on_three_adic_domain(6, 27),
2715                p.evaluate_on_three_adic_domain(7, 27),
2716                p.evaluate_on_three_adic_domain(8, 27),
2717                p.evaluate_on_three_adic_domain(9, 27),
2718                p.evaluate_on_three_adic_domain(10, 27),
2719                p.evaluate_on_three_adic_domain(11, 27),
2720                p.evaluate_on_three_adic_domain(12, 27),
2721                p.evaluate_on_three_adic_domain(13, 27),
2722                p.evaluate_on_three_adic_domain(14, 27),
2723                p.evaluate_on_three_adic_domain(15, 27),
2724                p.evaluate_on_three_adic_domain(16, 27),
2725                p.evaluate_on_three_adic_domain(17, 27),
2726                p.evaluate_on_three_adic_domain(18, 27),
2727                p.evaluate_on_three_adic_domain(19, 27),
2728                p.evaluate_on_three_adic_domain(20, 27),
2729                p.evaluate_on_three_adic_domain(21, 27),
2730                p.evaluate_on_three_adic_domain(22, 27),
2731                p.evaluate_on_three_adic_domain(23, 27),
2732                p.evaluate_on_three_adic_domain(24, 27),
2733                p.evaluate_on_three_adic_domain(25, 27),
2734                p.evaluate_on_three_adic_domain(26, 27),
2735            ]
2736        );
2737    }
2738
2739    #[test]
2740    fn test_lde3_nine_values_blowup3() {
2741        let values = (1u64..=9).map(Scalar::from).collect();
2742        let p = Polynomial::encode3(values);
2743        let lde = p.clone().lde3(27);
2744        assert_eq!(
2745            lde,
2746            vec![
2747                p.evaluate_on_three_adic_domain(0, 27),
2748                p.evaluate_on_three_adic_domain(1, 27),
2749                p.evaluate_on_three_adic_domain(2, 27),
2750                p.evaluate_on_three_adic_domain(3, 27),
2751                p.evaluate_on_three_adic_domain(4, 27),
2752                p.evaluate_on_three_adic_domain(5, 27),
2753                p.evaluate_on_three_adic_domain(6, 27),
2754                p.evaluate_on_three_adic_domain(7, 27),
2755                p.evaluate_on_three_adic_domain(8, 27),
2756                p.evaluate_on_three_adic_domain(9, 27),
2757                p.evaluate_on_three_adic_domain(10, 27),
2758                p.evaluate_on_three_adic_domain(11, 27),
2759                p.evaluate_on_three_adic_domain(12, 27),
2760                p.evaluate_on_three_adic_domain(13, 27),
2761                p.evaluate_on_three_adic_domain(14, 27),
2762                p.evaluate_on_three_adic_domain(15, 27),
2763                p.evaluate_on_three_adic_domain(16, 27),
2764                p.evaluate_on_three_adic_domain(17, 27),
2765                p.evaluate_on_three_adic_domain(18, 27),
2766                p.evaluate_on_three_adic_domain(19, 27),
2767                p.evaluate_on_three_adic_domain(20, 27),
2768                p.evaluate_on_three_adic_domain(21, 27),
2769                p.evaluate_on_three_adic_domain(22, 27),
2770                p.evaluate_on_three_adic_domain(23, 27),
2771                p.evaluate_on_three_adic_domain(24, 27),
2772                p.evaluate_on_three_adic_domain(25, 27),
2773                p.evaluate_on_three_adic_domain(26, 27),
2774            ]
2775        );
2776    }
2777
2778    #[test]
2779    fn test_lde3_shorter_poly() {
2780        let values = vec![from_const(7), from_const(7), from_const(7)];
2781        let p = Polynomial::encode3(values);
2782        assert_eq!(p.len(), 1);
2783        assert_eq!(p.degree_bound(), 1);
2784        let lde = p.clone().lde3(9);
2785        assert_eq!(
2786            lde,
2787            vec![
2788                p.evaluate_on_three_adic_domain(0, 9),
2789                p.evaluate_on_three_adic_domain(1, 9),
2790                p.evaluate_on_three_adic_domain(2, 9),
2791                p.evaluate_on_three_adic_domain(3, 9),
2792                p.evaluate_on_three_adic_domain(4, 9),
2793                p.evaluate_on_three_adic_domain(5, 9),
2794                p.evaluate_on_three_adic_domain(6, 9),
2795                p.evaluate_on_three_adic_domain(7, 9),
2796                p.evaluate_on_three_adic_domain(8, 9),
2797            ]
2798        );
2799    }
2800
2801    #[test]
2802    fn test_fold2_degree_zero() {
2803        let p = Polynomial::with_coefficients(vec![from_const(5)]);
2804        assert_eq!(p.clone().fold2(from_const(2)).take(), vec![from_const(5)]);
2805        assert_eq!(p.fold2(from_const(3)).take(), vec![from_const(5)]);
2806    }
2807
2808    #[test]
2809    fn test_fold2_degree_one() {
2810        let p = Polynomial::with_coefficients(vec![from_const(2), from_const(3)]);
2811        assert_eq!(p.clone().fold2(from_const(2)).take(), vec![from_const(8)]);
2812        assert_eq!(p.fold2(from_const(3)).take(), vec![from_const(11)]);
2813    }
2814
2815    #[test]
2816    fn test_fold2_degree_two() {
2817        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2818        assert_eq!(
2819            p.clone().fold2(from_const(2)).take(),
2820            vec![from_const(5), from_const(3)],
2821        );
2822        assert_eq!(
2823            p.fold2(from_const(3)).take(),
2824            vec![from_const(7), from_const(3)],
2825        );
2826    }
2827
2828    #[test]
2829    fn test_fold2_degree_three() {
2830        let p = Polynomial::with_coefficients(vec![
2831            from_const(1),
2832            from_const(2),
2833            from_const(3),
2834            from_const(4),
2835        ]);
2836        assert_eq!(
2837            p.clone().fold2(from_const(2)).take(),
2838            vec![from_const(5), from_const(11)],
2839        );
2840        assert_eq!(
2841            p.fold2(from_const(3)).take(),
2842            vec![from_const(7), from_const(15)],
2843        );
2844    }
2845
2846    #[test]
2847    fn test_fold3_degree_zero() {
2848        let p = Polynomial::with_coefficients(vec![from_const(5)]);
2849        assert_eq!(p.clone().fold3(from_const(2)).take(), vec![from_const(5)]);
2850        assert_eq!(p.fold3(from_const(3)).take(), vec![from_const(5)]);
2851    }
2852
2853    #[test]
2854    fn test_fold3_degree_two() {
2855        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
2856        assert_eq!(p.clone().fold3(from_const(2)).take(), vec![from_const(17)]);
2857        assert_eq!(p.fold3(from_const(3)).take(), vec![from_const(34)]);
2858    }
2859
2860    #[test]
2861    fn test_fold3_degree_three() {
2862        let p = Polynomial::with_coefficients(vec![
2863            from_const(1),
2864            from_const(2),
2865            from_const(3),
2866            from_const(4),
2867        ]);
2868        assert_eq!(
2869            p.clone().fold3(from_const(2)).take(),
2870            vec![from_const(17), from_const(4)],
2871        );
2872        assert_eq!(
2873            p.fold3(from_const(3)).take(),
2874            vec![from_const(34), from_const(4)],
2875        );
2876    }
2877
2878    #[test]
2879    fn test_fold3_degree_five() {
2880        let p = Polynomial::with_coefficients(vec![
2881            from_const(1),
2882            from_const(2),
2883            from_const(3),
2884            from_const(4),
2885            from_const(5),
2886            from_const(6),
2887        ]);
2888        assert_eq!(
2889            p.clone().fold3(from_const(2)).take(),
2890            vec![from_const(17), from_const(38)],
2891        );
2892        assert_eq!(
2893            p.fold3(from_const(3)).take(),
2894            vec![from_const(34), from_const(73)],
2895        );
2896    }
2897
2898    #[test]
2899    fn test_multiply_values2_same_constant() {
2900        let lhs = vec![from_const(42), from_const(42)];
2901        let rhs = vec![from_const(42), from_const(42)];
2902        let result = Polynomial::multiply_values2(lhs, rhs);
2903        assert_eq!(result, vec![from_const(1764)]);
2904    }
2905
2906    #[test]
2907    fn test_multiply_values2_different_constants() {
2908        let lhs = vec![from_const(3), from_const(3)];
2909        let rhs = vec![from_const(7), from_const(7)];
2910        let result = Polynomial::multiply_values2(lhs, rhs);
2911        assert_eq!(result, vec![from_const(21)]);
2912    }
2913
2914    #[test]
2915    fn test_multiply_values2_two_linear_polynomials() {
2916        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2917        let q = Polynomial::with_coefficients(vec![from_const(3), from_const(4)]);
2918        let lhs = vec![
2919            p.evaluate_on_two_adic_domain(0, 2),
2920            p.evaluate_on_two_adic_domain(1, 2),
2921        ];
2922        let rhs = vec![
2923            q.evaluate_on_two_adic_domain(0, 2),
2924            q.evaluate_on_two_adic_domain(1, 2),
2925        ];
2926        let product = p.multiply(q);
2927        let result = Polynomial::multiply_values2(lhs, rhs);
2928        assert_eq!(
2929            result,
2930            vec![
2931                product.evaluate_on_two_adic_domain(0, 4),
2932                product.evaluate_on_two_adic_domain(1, 4),
2933                product.evaluate_on_two_adic_domain(2, 4),
2934                product.evaluate_on_two_adic_domain(3, 4),
2935            ]
2936        );
2937    }
2938
2939    #[test]
2940    fn test_multiply_values2_four_values() {
2941        let p = Polynomial::with_coefficients(vec![
2942            from_const(1),
2943            from_const(2),
2944            from_const(3),
2945            from_const(4),
2946        ]);
2947        let q = Polynomial::with_coefficients(vec![
2948            from_const(5),
2949            from_const(6),
2950            from_const(7),
2951            from_const(8),
2952        ]);
2953        let lhs = vec![
2954            p.evaluate_on_two_adic_domain(0, 4),
2955            p.evaluate_on_two_adic_domain(1, 4),
2956            p.evaluate_on_two_adic_domain(2, 4),
2957            p.evaluate_on_two_adic_domain(3, 4),
2958        ];
2959        let rhs = vec![
2960            q.evaluate_on_two_adic_domain(0, 4),
2961            q.evaluate_on_two_adic_domain(1, 4),
2962            q.evaluate_on_two_adic_domain(2, 4),
2963            q.evaluate_on_two_adic_domain(3, 4),
2964        ];
2965        let product = p.multiply(q);
2966        let result = Polynomial::multiply_values2(lhs, rhs);
2967        assert_eq!(
2968            result,
2969            vec![
2970                product.evaluate_on_two_adic_domain(0, 8),
2971                product.evaluate_on_two_adic_domain(1, 8),
2972                product.evaluate_on_two_adic_domain(2, 8),
2973                product.evaluate_on_two_adic_domain(3, 8),
2974                product.evaluate_on_two_adic_domain(4, 8),
2975                product.evaluate_on_two_adic_domain(5, 8),
2976                product.evaluate_on_two_adic_domain(6, 8),
2977                product.evaluate_on_two_adic_domain(7, 8),
2978            ]
2979        );
2980    }
2981
2982    #[test]
2983    fn test_multiply_values2_commutative() {
2984        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
2985        let q = Polynomial::with_coefficients(vec![from_const(3), from_const(4)]);
2986        let values_p = vec![
2987            p.evaluate_on_two_adic_domain(0, 2),
2988            p.evaluate_on_two_adic_domain(1, 2),
2989        ];
2990        let values_q = vec![
2991            q.evaluate_on_two_adic_domain(0, 2),
2992            q.evaluate_on_two_adic_domain(1, 2),
2993        ];
2994        let result_pq = Polynomial::multiply_values2(values_p.clone(), values_q.clone());
2995        let result_qp = Polynomial::multiply_values2(values_q, values_p);
2996        assert_eq!(result_pq, result_qp);
2997    }
2998
2999    #[test]
3000    fn test_multiply_values2_round_trip() {
3001        let p = Polynomial::with_coefficients(vec![
3002            from_const(1),
3003            from_const(2),
3004            from_const(3),
3005            from_const(4),
3006        ]);
3007        let q = Polynomial::with_coefficients(vec![
3008            from_const(5),
3009            from_const(6),
3010            from_const(7),
3011            from_const(8),
3012        ]);
3013        let lhs = vec![
3014            p.evaluate_on_two_adic_domain(0, 4),
3015            p.evaluate_on_two_adic_domain(1, 4),
3016            p.evaluate_on_two_adic_domain(2, 4),
3017            p.evaluate_on_two_adic_domain(3, 4),
3018        ];
3019        let rhs = vec![
3020            q.evaluate_on_two_adic_domain(0, 4),
3021            q.evaluate_on_two_adic_domain(1, 4),
3022            q.evaluate_on_two_adic_domain(2, 4),
3023            q.evaluate_on_two_adic_domain(3, 4),
3024        ];
3025        let product = p.clone().multiply(q.clone());
3026        let result = Polynomial::encode2(Polynomial::multiply_values2(lhs, rhs));
3027        assert_eq!(result, product);
3028    }
3029
3030    #[test]
3031    fn test_multiply_values3_same_constant() {
3032        let lhs = vec![from_const(42), from_const(42), from_const(42)];
3033        let rhs = vec![from_const(42), from_const(42), from_const(42)];
3034        let result = Polynomial::multiply_values3(lhs, rhs);
3035        assert_eq!(result, vec![from_const(1764)]);
3036    }
3037
3038    #[test]
3039    fn test_multiply_values3_different_constants() {
3040        let lhs = vec![from_const(3), from_const(3), from_const(3)];
3041        let rhs = vec![from_const(7), from_const(7), from_const(7)];
3042        let result = Polynomial::multiply_values3(lhs, rhs);
3043        assert_eq!(result, vec![from_const(21)]);
3044    }
3045
3046    #[test]
3047    fn test_multiply_values3_two_linear_polynomials() {
3048        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
3049        let q = Polynomial::with_coefficients(vec![from_const(3), from_const(4)]);
3050        let lhs = vec![
3051            p.evaluate_on_three_adic_domain(0, 3),
3052            p.evaluate_on_three_adic_domain(1, 3),
3053            p.evaluate_on_three_adic_domain(2, 3),
3054        ];
3055        let rhs = vec![
3056            q.evaluate_on_three_adic_domain(0, 3),
3057            q.evaluate_on_three_adic_domain(1, 3),
3058            q.evaluate_on_three_adic_domain(2, 3),
3059        ];
3060        let product = p.multiply(q);
3061        let result = Polynomial::multiply_values3(lhs, rhs);
3062        assert_eq!(
3063            result,
3064            vec![
3065                product.evaluate_on_three_adic_domain(0, 3),
3066                product.evaluate_on_three_adic_domain(1, 3),
3067                product.evaluate_on_three_adic_domain(2, 3),
3068            ]
3069        );
3070    }
3071
3072    #[test]
3073    fn test_multiply_values3_nine_values() {
3074        let p = Polynomial::with_coefficients(vec![
3075            from_const(1),
3076            from_const(2),
3077            from_const(3),
3078            from_const(4),
3079            from_const(5),
3080            from_const(6),
3081            from_const(7),
3082            from_const(8),
3083            from_const(9),
3084        ]);
3085        let q = Polynomial::with_coefficients(vec![
3086            from_const(10),
3087            from_const(11),
3088            from_const(12),
3089            from_const(13),
3090            from_const(14),
3091            from_const(15),
3092            from_const(16),
3093            from_const(17),
3094            from_const(18),
3095        ]);
3096        let lhs = vec![
3097            p.evaluate_on_three_adic_domain(0, 9),
3098            p.evaluate_on_three_adic_domain(1, 9),
3099            p.evaluate_on_three_adic_domain(2, 9),
3100            p.evaluate_on_three_adic_domain(3, 9),
3101            p.evaluate_on_three_adic_domain(4, 9),
3102            p.evaluate_on_three_adic_domain(5, 9),
3103            p.evaluate_on_three_adic_domain(6, 9),
3104            p.evaluate_on_three_adic_domain(7, 9),
3105            p.evaluate_on_three_adic_domain(8, 9),
3106        ];
3107        let rhs = vec![
3108            q.evaluate_on_three_adic_domain(0, 9),
3109            q.evaluate_on_three_adic_domain(1, 9),
3110            q.evaluate_on_three_adic_domain(2, 9),
3111            q.evaluate_on_three_adic_domain(3, 9),
3112            q.evaluate_on_three_adic_domain(4, 9),
3113            q.evaluate_on_three_adic_domain(5, 9),
3114            q.evaluate_on_three_adic_domain(6, 9),
3115            q.evaluate_on_three_adic_domain(7, 9),
3116            q.evaluate_on_three_adic_domain(8, 9),
3117        ];
3118        let product = p.multiply(q);
3119        let result = Polynomial::multiply_values3(lhs, rhs);
3120        assert_eq!(
3121            result,
3122            vec![
3123                product.evaluate_on_three_adic_domain(0, 27),
3124                product.evaluate_on_three_adic_domain(1, 27),
3125                product.evaluate_on_three_adic_domain(2, 27),
3126                product.evaluate_on_three_adic_domain(3, 27),
3127                product.evaluate_on_three_adic_domain(4, 27),
3128                product.evaluate_on_three_adic_domain(5, 27),
3129                product.evaluate_on_three_adic_domain(6, 27),
3130                product.evaluate_on_three_adic_domain(7, 27),
3131                product.evaluate_on_three_adic_domain(8, 27),
3132                product.evaluate_on_three_adic_domain(9, 27),
3133                product.evaluate_on_three_adic_domain(10, 27),
3134                product.evaluate_on_three_adic_domain(11, 27),
3135                product.evaluate_on_three_adic_domain(12, 27),
3136                product.evaluate_on_three_adic_domain(13, 27),
3137                product.evaluate_on_three_adic_domain(14, 27),
3138                product.evaluate_on_three_adic_domain(15, 27),
3139                product.evaluate_on_three_adic_domain(16, 27),
3140                product.evaluate_on_three_adic_domain(17, 27),
3141                product.evaluate_on_three_adic_domain(18, 27),
3142                product.evaluate_on_three_adic_domain(19, 27),
3143                product.evaluate_on_three_adic_domain(20, 27),
3144                product.evaluate_on_three_adic_domain(21, 27),
3145                product.evaluate_on_three_adic_domain(22, 27),
3146                product.evaluate_on_three_adic_domain(23, 27),
3147                product.evaluate_on_three_adic_domain(24, 27),
3148                product.evaluate_on_three_adic_domain(25, 27),
3149                product.evaluate_on_three_adic_domain(26, 27),
3150            ]
3151        );
3152    }
3153
3154    #[test]
3155    fn test_multiply_values3_commutative() {
3156        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2)]);
3157        let q = Polynomial::with_coefficients(vec![from_const(3), from_const(4)]);
3158        let values_p = vec![
3159            p.evaluate_on_three_adic_domain(0, 3),
3160            p.evaluate_on_three_adic_domain(1, 3),
3161            p.evaluate_on_three_adic_domain(2, 3),
3162        ];
3163        let values_q = vec![
3164            q.evaluate_on_three_adic_domain(0, 3),
3165            q.evaluate_on_three_adic_domain(1, 3),
3166            q.evaluate_on_three_adic_domain(2, 3),
3167        ];
3168        let result_pq = Polynomial::multiply_values3(values_p.clone(), values_q.clone());
3169        let result_qp = Polynomial::multiply_values3(values_q, values_p);
3170        assert_eq!(result_pq, result_qp);
3171    }
3172
3173    #[test]
3174    fn test_multiply_values3_round_trip() {
3175        let p = Polynomial::with_coefficients(vec![from_const(1), from_const(2), from_const(3)]);
3176        let q = Polynomial::with_coefficients(vec![from_const(4), from_const(5), from_const(6)]);
3177        let lhs = vec![
3178            p.evaluate_on_three_adic_domain(0, 3),
3179            p.evaluate_on_three_adic_domain(1, 3),
3180            p.evaluate_on_three_adic_domain(2, 3),
3181        ];
3182        let rhs = vec![
3183            q.evaluate_on_three_adic_domain(0, 3),
3184            q.evaluate_on_three_adic_domain(1, 3),
3185            q.evaluate_on_three_adic_domain(2, 3),
3186        ];
3187        let product = p.clone().multiply(q.clone());
3188        let result = Polynomial::encode3(Polynomial::multiply_values3(lhs, rhs));
3189        assert_eq!(result, product);
3190    }
3191
3192    #[test]
3193    fn test_lagrange0_1() {
3194        let n = 1;
3195        let l0 = Polynomial::lagrange0(n);
3196        assert_eq!(l0.evaluate(from_const(1)), from_const(1));
3197    }
3198
3199    #[test]
3200    fn test_lagrange0_2() {
3201        let n = 2;
3202        let omega = Polynomial::domain_element2(1, n);
3203        let l0 = Polynomial::lagrange0(n);
3204        assert_eq!(l0.evaluate(from_const(1)), from_const(1));
3205        assert_eq!(l0.evaluate(omega), from_const(0));
3206    }
3207
3208    #[test]
3209    fn test_lagrange0_4() {
3210        let n = 4;
3211        let omega = Polynomial::domain_element2(1, n);
3212        let l0 = Polynomial::lagrange0(n);
3213        assert_eq!(l0.evaluate(from_const(1)), from_const(1));
3214        assert_eq!(l0.evaluate(omega), from_const(0));
3215        assert_eq!(l0.evaluate(omega.square()), from_const(0));
3216        assert_eq!(l0.evaluate(omega.cube()), from_const(0));
3217    }
3218
3219    #[test]
3220    fn test_lagrange0_8() {
3221        let n = 8;
3222        let omega = Polynomial::domain_element2(1, n);
3223        let l0 = Polynomial::lagrange0(n);
3224        assert_eq!(l0.evaluate(from_const(1)), from_const(1));
3225        assert_eq!(l0.evaluate(omega), from_const(0));
3226        assert_eq!(l0.evaluate(omega.pow_small(2)), from_const(0));
3227        assert_eq!(l0.evaluate(omega.pow_small(3)), from_const(0));
3228        assert_eq!(l0.evaluate(omega.pow_small(4)), from_const(0));
3229        assert_eq!(l0.evaluate(omega.pow_small(5)), from_const(0));
3230        assert_eq!(l0.evaluate(omega.pow_small(6)), from_const(0));
3231        assert_eq!(l0.evaluate(omega.pow_small(7)), from_const(0));
3232    }
3233}