Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow batch_inverse to take a scratchpad as input #268

Merged
merged 7 commits into from
Sep 24, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions cryptography/bls12_381/src/batch_inversion.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
/// Given a vector of field elements {v_i}, compute the vector {v_i^(-1)}
///
/// Panics if any of the elements are zero
pub fn batch_inverse<F: ff::Field>(v: &mut [F]) {
// Montgomery’s Trick and Fast Implementation of Masked AES
let mut scratch_pad = Vec::with_capacity(v.len());
batch_inverse_scratch_pad(v, &mut scratch_pad);
}

/// Given a vector of field elements {v_i}, compute the vector {v_i^(-1)}
///
/// A scratchpad is used to avoid excessive allocations in the case that this method is
/// called repeatedly.
///
/// Panics if any of the elements are zero
pub fn batch_inverse_scratch_pad<F: ff::Field>(v: &mut [F], scratchpad: &mut Vec<F>) {
// Montgomery's Trick and Fast Implementation of Masked AES
// Genelle, Prouff and Quisquater
// Section 3.2
// but with an optimization to multiply every element in the returned vector by coeff

// Clear the scratchpad and ensure it has enough capacity
scratchpad.clear();
scratchpad.reserve(v.len());

// First pass: compute [a, ab, abc, ...]
let mut prod = Vec::with_capacity(v.len());
let mut tmp = F::ONE;
for f in v.iter().filter(|f| !f.is_zero_vartime()) {
for f in v.iter() {
tmp.mul_assign(f);
prod.push(tmp);
scratchpad.push(tmp);
}

assert_eq!(prod.len(), v.len(), "inversion by zero is not allowed");

// Invert `tmp`.
tmp = tmp
.invert()
Expand All @@ -25,14 +39,12 @@ pub fn batch_inverse<F: ff::Field>(v: &mut [F]) {
.iter_mut()
// Backwards
.rev()
// Ignore normalized elements
.filter(|f| !f.is_zero_vartime())
// Backwards, skip last element, fill in one for last term.
.zip(prod.into_iter().rev().skip(1).chain(Some(F::ONE)))
.zip(scratchpad.iter().rev().skip(1).chain(Some(&F::ONE)))
{
// tmp := tmp * f; f := tmp * s = 1/f
let new_tmp = tmp * *f;
*f = tmp * s;
*f = tmp * *s;
tmp = new_tmp;
}
}
Expand Down
Loading