Add `{mul,add,sub}_extended` and `rotate_extended` methods to `EvaluationDomain`.

This commit is contained in:
Sean Bowe 2021-07-12 11:44:09 -06:00
parent d8df7a12d5
commit 55424c8c2f
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
1 changed files with 105 additions and 5 deletions

View File

@ -247,7 +247,7 @@ impl<G: Group> EvaluationDomain<G> {
if rotation.0 == 0 { if rotation.0 == 0 {
// In this special case, the powers of zeta repeat so we do not need // In this special case, the powers of zeta repeat so we do not need
// to compute them. // to compute them.
Self::distribute_powers_zeta(&mut a.values); Self::distribute_powers_zeta(&mut a.values, true);
} else { } else {
let mut g = self.g_coset; let mut g = self.g_coset;
if rotation.0 > 0 { if rotation.0 > 0 {
@ -268,6 +268,102 @@ impl<G: Group> EvaluationDomain<G> {
} }
} }
fn op_extended(
&self,
mut left: Polynomial<G, ExtendedLagrangeCoeff>,
right: &Polynomial<G, ExtendedLagrangeCoeff>,
rotation: Rotation,
op: impl Fn(&mut G, &G) + Send + Sync + 'static,
) -> Polynomial<G, ExtendedLagrangeCoeff>
where
G: Field,
{
// Rotation while in the extended domain is simply exaggerated by how
// much larger the extended domain is compared to the original domain.
let rotation = (1 << (self.extended_k - self.k)) * rotation.0;
parallelize(&mut left.values, |lhs, start| {
let start = ((((start + self.extended_len()) as i32) + rotation) as usize)
% self.extended_len();
for (lhs, rhs) in lhs
.iter_mut()
.zip(right.values[start..].iter().chain(right.values.iter()))
{
op(lhs, rhs);
}
});
left
}
/// Multiply two polynomials in the extended domain, rotating the latter
/// polynomial over the original domain first.
pub fn mul_extended(
&self,
left: Polynomial<G, ExtendedLagrangeCoeff>,
right: &Polynomial<G, ExtendedLagrangeCoeff>,
rotation: Rotation,
) -> Polynomial<G, ExtendedLagrangeCoeff>
where
G: Field,
{
self.op_extended(left, right, rotation, |lhs, rhs| {
*lhs *= *rhs;
})
}
/// Add two polynomials in the extended domain, rotating the latter
/// polynomial over the original domain first.
pub fn add_extended(
&self,
left: Polynomial<G, ExtendedLagrangeCoeff>,
right: &Polynomial<G, ExtendedLagrangeCoeff>,
rotation: Rotation,
) -> Polynomial<G, ExtendedLagrangeCoeff>
where
G: Field,
{
self.op_extended(left, right, rotation, |lhs, rhs| {
*lhs += *rhs;
})
}
/// Subtract a polynomial from another in the extended domain, rotating the
/// former polynomial over the original domain first.
pub fn sub_extended(
&self,
left: Polynomial<G, ExtendedLagrangeCoeff>,
right: &Polynomial<G, ExtendedLagrangeCoeff>,
rotation: Rotation,
) -> Polynomial<G, ExtendedLagrangeCoeff>
where
G: Field,
{
self.op_extended(left, right, rotation, |lhs, rhs| {
*lhs -= *rhs;
})
}
/// Rotate the extended domain polynomial over the original domain.
pub fn rotate_extended(
&self,
poly: &Polynomial<G, ExtendedLagrangeCoeff>,
rotation: Rotation,
) -> Polynomial<G, ExtendedLagrangeCoeff> {
let new_rotation = ((1 << (self.extended_k - self.k)) * rotation.0.abs()) as usize;
let mut poly = poly.clone();
if rotation.0 >= 0 {
poly.values.rotate_left(new_rotation);
} else {
poly.values.rotate_right(new_rotation);
}
poly
}
/// This takes us from the extended evaluation domain and gets us the /// This takes us from the extended evaluation domain and gets us the
/// quotient polynomial coefficients. /// quotient polynomial coefficients.
/// ///
@ -287,7 +383,7 @@ impl<G: Group> EvaluationDomain<G> {
// Distribute powers to move from coset; opposite from the // Distribute powers to move from coset; opposite from the
// transformation we performed earlier. // transformation we performed earlier.
Self::distribute_powers(&mut a.values, self.g_coset_inv); Self::distribute_powers_zeta(&mut a.values, false);
// Truncate it to match the size of the quotient polynomial; the // Truncate it to match the size of the quotient polynomial; the
// evaluation domain might be slightly larger than necessary because // evaluation domain might be slightly larger than necessary because
@ -325,11 +421,15 @@ impl<G: Group> EvaluationDomain<G> {
// `[a_0, [zeta]a_1, [zeta^2]a_2, a_3, [zeta]a_4, [zeta^2]a_5, a_6, ...]`, // `[a_0, [zeta]a_1, [zeta^2]a_2, a_3, [zeta]a_4, [zeta^2]a_5, a_6, ...]`,
// where zeta is a cube root of unity in the multiplicative subgroup with // where zeta is a cube root of unity in the multiplicative subgroup with
// order (p - 1), i.e. zeta^3 = 1. // order (p - 1), i.e. zeta^3 = 1.
fn distribute_powers_zeta(mut a: &mut [G]) { fn distribute_powers_zeta(mut a: &mut [G], direction: bool) {
let coset_powers = [G::Scalar::ZETA, G::Scalar::ZETA.square()]; let coset_powers = if direction {
[G::Scalar::ZETA, G::Scalar::ZETA.square()]
} else {
[G::Scalar::ZETA.square(), G::Scalar::ZETA]
};
parallelize(&mut a, |a, mut index| { parallelize(&mut a, |a, mut index| {
for a in a { for a in a {
// Distribute powers to move into coset // Distribute powers to move into/from coset
let i = index % (coset_powers.len() + 1); let i = index % (coset_powers.len() + 1);
if i != 0 { if i != 0 {
a.group_scale(&coset_powers[i - 1]); a.group_scale(&coset_powers[i - 1]);