Skip to content

Commit

Permalink
Use ark_ff::batch_inversion for point normalization
Browse files Browse the repository at this point in the history
  • Loading branch information
Pratyush committed Dec 11, 2020
1 parent 299eac3 commit 0fc71b6
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 74 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
- #115 (ark-ff) Add parallel implementation of `batch_inversion`.
- #122 (ark-poly) Add infrastructure for benchmarking `FFT`s.
- #125 (ark-poly) Add parallelization to applying coset shifts within `coset_fft`.
- #126 (ark-ec) Use `ark_ff::batch_inversion` for point normalization

### Bug fixes
- #36 (ark-ec) In Short-Weierstrass curves, include an infinity bit in `ToConstraintField`.
Expand Down
51 changes: 14 additions & 37 deletions ec/src/models/short_weierstrass_jacobian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,51 +399,28 @@ impl<P: Parameters> ProjectiveCurve for GroupProjective<P> {

#[inline]
fn batch_normalization(v: &mut [Self]) {
// Montgomery’s Trick and Fast Implementation of Masked AES
// Genelle, Prouff and Quisquater
// Section 3.2

// First pass: compute [a, ab, abc, ...]
let mut prod = Vec::with_capacity(v.len());
let mut tmp = P::BaseField::one();
for g in v.iter_mut()
// Ignore normalized elements
let mut z_s = v
.iter()
.filter(|g| !g.is_normalized())
{
tmp *= &g.z;
prod.push(tmp);
}

// Invert `tmp`.
tmp = tmp.inverse().unwrap(); // Guaranteed to be nonzero.

// Second pass: iterate backwards to compute inverses
for (g, s) in v.iter_mut()
// Backwards
.rev()
// Ignore normalized elements
.filter(|g| !g.is_normalized())
// Backwards, skip last element, fill in one for last term.
.zip(prod.into_iter().rev().skip(1).chain(Some(P::BaseField::one())))
{
// tmp := tmp * g.z; g.z := tmp * s = 1/z
let newtmp = tmp * &g.z;
g.z = tmp * &s;
tmp = newtmp;
}
.map(|g| g.z)
.collect::<Vec<_>>();
ark_ff::batch_inversion(&mut z_s);

#[cfg(not(feature = "parallel"))]
let v_iter = v.iter_mut();
#[cfg(feature = "parallel")]
let v_iter = v.par_iter_mut();

// Perform affine transformations
v_iter.filter(|g| !g.is_normalized()).for_each(|g| {
let z2 = g.z.square(); // 1/z
g.x *= &z2; // x/z^2
g.y *= &(z2 * &g.z); // y/z^3
g.z = P::BaseField::one(); // z = 1
});
v_iter
.filter(|g| !g.is_normalized())
.zip(z_s)
.for_each(|(g, z)| {
let z2 = z.square(); // 1/z
g.x *= &z2; // x/z^2
g.y *= &(z2 * &z); // y/z^3
g.z = P::BaseField::one(); // z = 1
});
}

fn double_in_place(&mut self) -> &mut Self {
Expand Down
51 changes: 14 additions & 37 deletions ec/src/models/twisted_edwards_extended.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,51 +444,28 @@ impl<P: Parameters> ProjectiveCurve for GroupProjective<P> {
}

fn batch_normalization(v: &mut [Self]) {
// Montgomery’s Trick and Fast Implementation of Masked AES
// Genelle, Prouff and Quisquater
// Section 3.2

// First pass: compute [a, ab, abc, ...]
let mut prod = Vec::with_capacity(v.len());
let mut tmp = P::BaseField::one();
for g in v.iter_mut()
// Ignore normalized elements
let mut z_s = v
.iter()
.filter(|g| !g.is_normalized())
{
tmp *= &g.z;
prod.push(tmp);
}

// Invert `tmp`.
tmp = tmp.inverse().unwrap(); // Guaranteed to be nonzero.

// Second pass: iterate backwards to compute inverses
for (g, s) in v.iter_mut()
// Backwards
.rev()
// Ignore normalized elements
.filter(|g| !g.is_normalized())
// Backwards, skip last element, fill in one for last term.
.zip(prod.into_iter().rev().skip(1).chain(Some(P::BaseField::one())))
{
// tmp := tmp * g.z; g.z := tmp * s = 1/z
let newtmp = tmp * &g.z;
g.z = tmp * &s;
tmp = newtmp;
}
.map(|g| g.z)
.collect::<Vec<_>>();
ark_ff::batch_inversion(&mut z_s);

#[cfg(not(feature = "parallel"))]
let v_iter = v.iter_mut();
#[cfg(feature = "parallel")]
let v_iter = v.par_iter_mut();

// Perform affine transformations
v_iter.filter(|g| !g.is_normalized()).for_each(|g| {
g.x *= &g.z; // x/z
g.y *= &g.z;
g.t *= &g.z;
g.z = P::BaseField::one(); // z = 1
});
v_iter
.filter(|g| !g.is_normalized())
.zip(z_s)
.for_each(|(g, z)| {
g.x *= &z; // x/z
g.y *= &z;
g.t *= &z;
g.z = P::BaseField::one(); // z = 1
});
}

fn double_in_place(&mut self) -> &mut Self {
Expand Down

0 comments on commit 0fc71b6

Please sign in to comment.