mirror of https://github.com/zcash/halo2.git
Simplify `EvaluationDomain` to only accept field elements
We do not use `EvaluationDomain` with group elements, so there is no need to directly use the FFT `Group` abstraction trait here.
This commit is contained in:
parent
0ba0e40b87
commit
93af730c6c
|
@ -2,13 +2,13 @@
|
|||
//! domain that is of a suitable size for the application.
|
||||
|
||||
use crate::{
|
||||
arithmetic::{best_fft, parallelize, FieldExt, Group},
|
||||
arithmetic::{best_fft, parallelize, FieldExt},
|
||||
plonk::Assigned,
|
||||
};
|
||||
|
||||
use super::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, Rotation};
|
||||
|
||||
use group::ff::{BatchInvert, Field, PrimeField};
|
||||
use group::ff::{BatchInvert, Field};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
@ -16,24 +16,24 @@ use std::marker::PhantomData;
|
|||
/// performing operations on an evaluation domain of size $2^k$ and an extended
|
||||
/// domain of size $2^{k} * j$ with $j \neq 0$.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EvaluationDomain<G: Group> {
|
||||
pub struct EvaluationDomain<F: FieldExt> {
|
||||
n: u64,
|
||||
k: u32,
|
||||
extended_k: u32,
|
||||
omega: G::Scalar,
|
||||
omega_inv: G::Scalar,
|
||||
extended_omega: G::Scalar,
|
||||
extended_omega_inv: G::Scalar,
|
||||
g_coset: G::Scalar,
|
||||
g_coset_inv: G::Scalar,
|
||||
omega: F,
|
||||
omega_inv: F,
|
||||
extended_omega: F,
|
||||
extended_omega_inv: F,
|
||||
g_coset: F,
|
||||
g_coset_inv: F,
|
||||
quotient_poly_degree: u64,
|
||||
ifft_divisor: G::Scalar,
|
||||
extended_ifft_divisor: G::Scalar,
|
||||
t_evaluations: Vec<G::Scalar>,
|
||||
barycentric_weight: G::Scalar,
|
||||
ifft_divisor: F,
|
||||
extended_ifft_divisor: F,
|
||||
t_evaluations: Vec<F>,
|
||||
barycentric_weight: F,
|
||||
}
|
||||
|
||||
impl<G: Group> EvaluationDomain<G> {
|
||||
impl<F: FieldExt> EvaluationDomain<F> {
|
||||
/// This constructs a new evaluation domain object based on the provided
|
||||
/// values $j, k$.
|
||||
pub fn new(j: u32, k: u32) -> Self {
|
||||
|
@ -51,12 +51,12 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
extended_k += 1;
|
||||
}
|
||||
|
||||
let mut extended_omega = G::Scalar::root_of_unity();
|
||||
let mut extended_omega = F::root_of_unity();
|
||||
|
||||
// Get extended_omega, the 2^{extended_k}'th root of unity
|
||||
// The loop computes extended_omega = omega^{2 ^ (S - extended_k)}
|
||||
// Notice that extended_omega ^ {2 ^ extended_k} = omega ^ {2^S} = 1.
|
||||
for _ in extended_k..G::Scalar::S {
|
||||
for _ in extended_k..F::S {
|
||||
extended_omega = extended_omega.square();
|
||||
}
|
||||
let extended_omega = extended_omega;
|
||||
|
@ -78,14 +78,14 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
// already.
|
||||
// The coset evaluation domain is:
|
||||
// zeta {1, extended_omega, extended_omega^2, ..., extended_omega^{(2^extended_k) - 1}}
|
||||
let g_coset = G::Scalar::ZETA;
|
||||
let g_coset = F::ZETA;
|
||||
let g_coset_inv = g_coset.square();
|
||||
|
||||
let mut t_evaluations = Vec::with_capacity(1 << (extended_k - k));
|
||||
{
|
||||
// Compute the evaluations of t(X) = X^n - 1 in the coset evaluation domain.
|
||||
// We don't have to compute all of them, because it will repeat.
|
||||
let orig = G::Scalar::ZETA.pow_vartime(&[n as u64, 0, 0, 0]);
|
||||
let orig = F::ZETA.pow_vartime(&[n as u64, 0, 0, 0]);
|
||||
let step = extended_omega.pow_vartime(&[n as u64, 0, 0, 0]);
|
||||
let mut cur = orig;
|
||||
loop {
|
||||
|
@ -99,19 +99,19 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
|
||||
// Subtract 1 from each to give us t_evaluations[i] = t(zeta * extended_omega^i)
|
||||
for coeff in &mut t_evaluations {
|
||||
*coeff -= &G::Scalar::one();
|
||||
*coeff -= &F::one();
|
||||
}
|
||||
|
||||
// Invert, because we're dividing by this polynomial.
|
||||
// We invert in a batch, below.
|
||||
}
|
||||
|
||||
let mut ifft_divisor = G::Scalar::from(1 << k); // Inversion computed later
|
||||
let mut extended_ifft_divisor = G::Scalar::from(1 << extended_k); // Inversion computed later
|
||||
let mut ifft_divisor = F::from(1 << k); // Inversion computed later
|
||||
let mut extended_ifft_divisor = F::from(1 << extended_k); // Inversion computed later
|
||||
|
||||
// The barycentric weight of 1 over the evaluation domain
|
||||
// 1 / \prod_{i != 0} (1 - omega^i)
|
||||
let mut barycentric_weight = G::Scalar::from(n); // Inversion computed later
|
||||
let mut barycentric_weight = F::from(n); // Inversion computed later
|
||||
|
||||
// Compute batch inversion
|
||||
t_evaluations
|
||||
|
@ -144,7 +144,7 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
/// Obtains a polynomial in Lagrange form when given a vector of Lagrange
|
||||
/// coefficients of size `n`; panics if the provided vector is the wrong
|
||||
/// length.
|
||||
pub fn lagrange_from_vec(&self, values: Vec<G>) -> Polynomial<G, LagrangeCoeff> {
|
||||
pub fn lagrange_from_vec(&self, values: Vec<F>) -> Polynomial<F, LagrangeCoeff> {
|
||||
assert_eq!(values.len(), self.n as usize);
|
||||
|
||||
Polynomial {
|
||||
|
@ -156,7 +156,7 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
/// Obtains a polynomial in coefficient form when given a vector of
|
||||
/// coefficients of size `n`; panics if the provided vector is the wrong
|
||||
/// length.
|
||||
pub fn coeff_from_vec(&self, values: Vec<G>) -> Polynomial<G, Coeff> {
|
||||
pub fn coeff_from_vec(&self, values: Vec<F>) -> Polynomial<F, Coeff> {
|
||||
assert_eq!(values.len(), self.n as usize);
|
||||
|
||||
Polynomial {
|
||||
|
@ -166,35 +166,32 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
}
|
||||
|
||||
/// Returns an empty (zero) polynomial in the coefficient basis
|
||||
pub fn empty_coeff(&self) -> Polynomial<G, Coeff> {
|
||||
pub fn empty_coeff(&self) -> Polynomial<F, Coeff> {
|
||||
Polynomial {
|
||||
values: vec![G::group_zero(); self.n as usize],
|
||||
values: vec![F::zero(); self.n as usize],
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an empty (zero) polynomial in the Lagrange coefficient basis
|
||||
pub fn empty_lagrange(&self) -> Polynomial<G, LagrangeCoeff> {
|
||||
pub fn empty_lagrange(&self) -> Polynomial<F, LagrangeCoeff> {
|
||||
Polynomial {
|
||||
values: vec![G::group_zero(); self.n as usize],
|
||||
values: vec![F::zero(); self.n as usize],
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an empty (zero) polynomial in the Lagrange coefficient basis, with
|
||||
/// deferred inversions.
|
||||
pub(crate) fn empty_lagrange_assigned(&self) -> Polynomial<Assigned<G>, LagrangeCoeff>
|
||||
where
|
||||
G: Field,
|
||||
{
|
||||
pub(crate) fn empty_lagrange_assigned(&self) -> Polynomial<Assigned<F>, LagrangeCoeff> {
|
||||
Polynomial {
|
||||
values: vec![G::group_zero().into(); self.n as usize],
|
||||
values: vec![F::zero().into(); self.n as usize],
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a constant polynomial in the Lagrange coefficient basis
|
||||
pub fn constant_lagrange(&self, scalar: G) -> Polynomial<G, LagrangeCoeff> {
|
||||
pub fn constant_lagrange(&self, scalar: F) -> Polynomial<F, LagrangeCoeff> {
|
||||
Polynomial {
|
||||
values: vec![scalar; self.n as usize],
|
||||
_marker: PhantomData,
|
||||
|
@ -203,16 +200,16 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
|
||||
/// Returns an empty (zero) polynomial in the extended Lagrange coefficient
|
||||
/// basis
|
||||
pub fn empty_extended(&self) -> Polynomial<G, ExtendedLagrangeCoeff> {
|
||||
pub fn empty_extended(&self) -> Polynomial<F, ExtendedLagrangeCoeff> {
|
||||
Polynomial {
|
||||
values: vec![G::group_zero(); self.extended_len()],
|
||||
values: vec![F::zero(); self.extended_len()],
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a constant polynomial in the extended Lagrange coefficient
|
||||
/// basis
|
||||
pub fn constant_extended(&self, scalar: G) -> Polynomial<G, ExtendedLagrangeCoeff> {
|
||||
pub fn constant_extended(&self, scalar: F) -> Polynomial<F, ExtendedLagrangeCoeff> {
|
||||
Polynomial {
|
||||
values: vec![scalar; self.extended_len()],
|
||||
_marker: PhantomData,
|
||||
|
@ -223,7 +220,7 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
///
|
||||
/// This function will panic if the provided vector is not the correct
|
||||
/// length.
|
||||
pub fn lagrange_to_coeff(&self, mut a: Polynomial<G, LagrangeCoeff>) -> Polynomial<G, Coeff> {
|
||||
pub fn lagrange_to_coeff(&self, mut a: Polynomial<F, LagrangeCoeff>) -> Polynomial<F, Coeff> {
|
||||
assert_eq!(a.values.len(), 1 << self.k);
|
||||
|
||||
// Perform inverse FFT to obtain the polynomial in coefficient form
|
||||
|
@ -239,12 +236,12 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
/// evaluation domain, rotating by `rotation` if desired.
|
||||
pub fn coeff_to_extended(
|
||||
&self,
|
||||
mut a: Polynomial<G, Coeff>,
|
||||
) -> Polynomial<G, ExtendedLagrangeCoeff> {
|
||||
mut a: Polynomial<F, Coeff>,
|
||||
) -> Polynomial<F, ExtendedLagrangeCoeff> {
|
||||
assert_eq!(a.values.len(), 1 << self.k);
|
||||
|
||||
self.distribute_powers_zeta(&mut a.values, true);
|
||||
a.values.resize(self.extended_len(), G::group_zero());
|
||||
a.values.resize(self.extended_len(), F::zero());
|
||||
best_fft(&mut a.values, self.extended_omega, self.extended_k);
|
||||
|
||||
Polynomial {
|
||||
|
@ -256,9 +253,9 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
/// Rotate the extended domain polynomial over the original domain.
|
||||
pub fn rotate_extended(
|
||||
&self,
|
||||
poly: &Polynomial<G, ExtendedLagrangeCoeff>,
|
||||
poly: &Polynomial<F, ExtendedLagrangeCoeff>,
|
||||
rotation: Rotation,
|
||||
) -> Polynomial<G, ExtendedLagrangeCoeff> {
|
||||
) -> Polynomial<F, ExtendedLagrangeCoeff> {
|
||||
let new_rotation = ((1 << (self.extended_k - self.k)) * rotation.0.abs()) as usize;
|
||||
|
||||
let mut poly = poly.clone();
|
||||
|
@ -284,11 +281,11 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
/// ```
|
||||
pub(crate) fn get_chunk_of_rotated_extended(
|
||||
&self,
|
||||
poly: &Polynomial<G, ExtendedLagrangeCoeff>,
|
||||
poly: &Polynomial<F, ExtendedLagrangeCoeff>,
|
||||
rotation: Rotation,
|
||||
chunk_size: usize,
|
||||
chunk_index: usize,
|
||||
) -> Vec<G> {
|
||||
) -> Vec<F> {
|
||||
let new_rotation = ((1 << (self.extended_k - self.k)) * rotation.0.abs()) as usize;
|
||||
poly.get_chunk_of_rotated_helper(rotation.0 < 0, new_rotation, chunk_size, chunk_index)
|
||||
}
|
||||
|
@ -299,7 +296,7 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
/// This function will panic if the provided vector is not the correct
|
||||
/// length.
|
||||
// TODO/FIXME: caller should be responsible for truncating
|
||||
pub fn extended_to_coeff(&self, mut a: Polynomial<G, ExtendedLagrangeCoeff>) -> Vec<G> {
|
||||
pub fn extended_to_coeff(&self, mut a: Polynomial<F, ExtendedLagrangeCoeff>) -> Vec<F> {
|
||||
assert_eq!(a.values.len(), self.extended_len());
|
||||
|
||||
// Inverse FFT
|
||||
|
@ -327,15 +324,15 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
/// polynomial of the $2^k$ size domain.
|
||||
pub fn divide_by_vanishing_poly(
|
||||
&self,
|
||||
mut a: Polynomial<G, ExtendedLagrangeCoeff>,
|
||||
) -> Polynomial<G, ExtendedLagrangeCoeff> {
|
||||
mut a: Polynomial<F, ExtendedLagrangeCoeff>,
|
||||
) -> Polynomial<F, ExtendedLagrangeCoeff> {
|
||||
assert_eq!(a.values.len(), self.extended_len());
|
||||
|
||||
// Divide to obtain the quotient polynomial in the coset evaluation
|
||||
// domain.
|
||||
parallelize(&mut a.values, |h, mut index| {
|
||||
for h in h {
|
||||
h.group_scale(&self.t_evaluations[index % self.t_evaluations.len()]);
|
||||
*h *= &self.t_evaluations[index % self.t_evaluations.len()];
|
||||
index += 1;
|
||||
}
|
||||
});
|
||||
|
@ -353,7 +350,7 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
///
|
||||
/// `into_coset` should be set to `true` when moving into the coset,
|
||||
/// and `false` when moving out. This toggles the choice of `zeta`.
|
||||
fn distribute_powers_zeta(&self, a: &mut [G], into_coset: bool) {
|
||||
fn distribute_powers_zeta(&self, a: &mut [F], into_coset: bool) {
|
||||
let coset_powers = if into_coset {
|
||||
[self.g_coset, self.g_coset_inv]
|
||||
} else {
|
||||
|
@ -364,19 +361,19 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
// Distribute powers to move into/from coset
|
||||
let i = index % (coset_powers.len() + 1);
|
||||
if i != 0 {
|
||||
a.group_scale(&coset_powers[i - 1]);
|
||||
*a *= &coset_powers[i - 1];
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn ifft(a: &mut [G], omega_inv: G::Scalar, log_n: u32, divisor: G::Scalar) {
|
||||
fn ifft(a: &mut [F], omega_inv: F, log_n: u32, divisor: F) {
|
||||
best_fft(a, omega_inv, log_n);
|
||||
parallelize(a, |a, _| {
|
||||
for a in a {
|
||||
// Finish iFFT
|
||||
a.group_scale(&divisor);
|
||||
*a *= &divisor;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -387,24 +384,24 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
}
|
||||
|
||||
/// Get $\omega$, the generator of the $2^k$ order multiplicative subgroup.
|
||||
pub fn get_omega(&self) -> G::Scalar {
|
||||
pub fn get_omega(&self) -> F {
|
||||
self.omega
|
||||
}
|
||||
|
||||
/// Get $\omega^{-1}$, the inverse of the generator of the $2^k$ order
|
||||
/// multiplicative subgroup.
|
||||
pub fn get_omega_inv(&self) -> G::Scalar {
|
||||
pub fn get_omega_inv(&self) -> F {
|
||||
self.omega_inv
|
||||
}
|
||||
|
||||
/// Get the generator of the extended domain's multiplicative subgroup.
|
||||
pub fn get_extended_omega(&self) -> G::Scalar {
|
||||
pub fn get_extended_omega(&self) -> F {
|
||||
self.extended_omega
|
||||
}
|
||||
|
||||
/// Multiplies a value by some power of $\omega$, essentially rotating over
|
||||
/// the domain.
|
||||
pub fn rotate_omega(&self, value: G::Scalar, rotation: Rotation) -> G::Scalar {
|
||||
pub fn rotate_omega(&self, value: F, rotation: Rotation) -> F {
|
||||
let mut point = value;
|
||||
if rotation.0 >= 0 {
|
||||
point *= &self.get_omega().pow_vartime(&[rotation.0 as u64]);
|
||||
|
@ -445,23 +442,23 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
/// which is the barycentric weight of $\omega^i$.
|
||||
pub fn l_i_range<I: IntoIterator<Item = i32> + Clone>(
|
||||
&self,
|
||||
x: G::Scalar,
|
||||
xn: G::Scalar,
|
||||
x: F,
|
||||
xn: F,
|
||||
rotations: I,
|
||||
) -> Vec<G::Scalar> {
|
||||
) -> Vec<F> {
|
||||
let mut results;
|
||||
{
|
||||
let rotations = rotations.clone().into_iter();
|
||||
results = Vec::with_capacity(rotations.size_hint().1.unwrap_or(0));
|
||||
for rotation in rotations {
|
||||
let rotation = Rotation(rotation);
|
||||
let result = x - self.rotate_omega(G::Scalar::one(), rotation);
|
||||
let result = x - self.rotate_omega(F::one(), rotation);
|
||||
results.push(result);
|
||||
}
|
||||
results.iter_mut().batch_invert();
|
||||
}
|
||||
|
||||
let common = (xn - G::Scalar::one()) * self.barycentric_weight;
|
||||
let common = (xn - F::one()) * self.barycentric_weight;
|
||||
for (rotation, result) in rotations.into_iter().zip(results.iter_mut()) {
|
||||
let rotation = Rotation(rotation);
|
||||
*result = self.rotate_omega(*result * common, rotation);
|
||||
|
@ -478,7 +475,7 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
/// Obtain a pinned version of this evaluation domain; a structure with the
|
||||
/// minimal parameters needed to determine the rest of the evaluation
|
||||
/// domain.
|
||||
pub fn pinned(&self) -> PinnedEvaluationDomain<'_, G> {
|
||||
pub fn pinned(&self) -> PinnedEvaluationDomain<'_, F> {
|
||||
PinnedEvaluationDomain {
|
||||
k: &self.k,
|
||||
extended_k: &self.extended_k,
|
||||
|
@ -490,10 +487,10 @@ impl<G: Group> EvaluationDomain<G> {
|
|||
/// Represents the minimal parameters that determine an `EvaluationDomain`.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct PinnedEvaluationDomain<'a, G: Group> {
|
||||
pub struct PinnedEvaluationDomain<'a, F: Field> {
|
||||
k: &'a u32,
|
||||
extended_k: &'a u32,
|
||||
omega: &'a G::Scalar,
|
||||
omega: &'a F,
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Reference in New Issue