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