Change FFT methods to accept references (#115)

This commit is contained in:
Daniel Lubarov 2021-07-21 08:26:41 -07:00 committed by GitHub
parent eb18c7ea33
commit 7d8bac7169
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 38 additions and 56 deletions

View File

@ -67,7 +67,7 @@ fn fft_unrolled_root_table<F: Field>(n: usize) -> FftRootTable<F> {
#[inline]
fn fft_dispatch<F: Field>(
input: Vec<F>,
input: &[F],
zero_factor: Option<usize>,
root_table: Option<FftRootTable<F>>,
) -> Vec<F> {
@ -87,13 +87,13 @@ fn fft_dispatch<F: Field>(
}
#[inline]
pub fn fft<F: Field>(poly: PolynomialCoeffs<F>) -> PolynomialValues<F> {
pub fn fft<F: Field>(poly: &PolynomialCoeffs<F>) -> PolynomialValues<F> {
fft_with_options(poly, None, None)
}
#[inline]
pub fn fft_with_options<F: Field>(
poly: PolynomialCoeffs<F>,
poly: &PolynomialCoeffs<F>,
zero_factor: Option<usize>,
root_table: Option<FftRootTable<F>>,
) -> PolynomialValues<F> {
@ -104,12 +104,12 @@ pub fn fft_with_options<F: Field>(
}
#[inline]
pub fn ifft<F: Field>(poly: PolynomialValues<F>) -> PolynomialCoeffs<F> {
pub fn ifft<F: Field>(poly: &PolynomialValues<F>) -> PolynomialCoeffs<F> {
ifft_with_options(poly, None, None)
}
pub fn ifft_with_options<F: Field>(
poly: PolynomialValues<F>,
poly: &PolynomialValues<F>,
zero_factor: Option<usize>,
root_table: Option<FftRootTable<F>>,
) -> PolynomialCoeffs<F> {
@ -139,11 +139,7 @@ pub fn ifft_with_options<F: Field>(
/// The parameter r signifies that the first 1/2^r of the entries of
/// input may be non-zero, but the last 1 - 1/2^r entries are
/// definitely zero.
pub(crate) fn fft_classic<F: Field>(
input: Vec<F>,
r: usize,
root_table: FftRootTable<F>,
) -> Vec<F> {
pub(crate) fn fft_classic<F: Field>(input: &[F], r: usize, root_table: FftRootTable<F>) -> Vec<F> {
let mut values = reverse_index_bits(input);
let n = values.len();
@ -196,7 +192,7 @@ pub(crate) fn fft_classic<F: Field>(
/// The parameter r signifies that the first 1/2^r of the entries of
/// input may be non-zero, but the last 1 - 1/2^r entries are
/// definitely zero.
fn fft_unrolled<F: Field>(input: Vec<F>, r_orig: usize, root_table: FftRootTable<F>) -> Vec<F> {
fn fft_unrolled<F: Field>(input: &[F], r_orig: usize, root_table: FftRootTable<F>) -> Vec<F> {
let n = input.len();
let lg_n = log2_strict(input.len());
@ -325,10 +321,10 @@ mod tests {
}
let coefficients = PolynomialCoeffs::new_padded(coefficients);
let points = fft(coefficients.clone());
let points = fft(&coefficients);
assert_eq!(points, evaluate_naive(&coefficients));
let interpolated_coefficients = ifft(points);
let interpolated_coefficients = ifft(&points);
for i in 0..degree {
assert_eq!(interpolated_coefficients.coeffs[i], coefficients.coeffs[i]);
}
@ -337,12 +333,9 @@ mod tests {
}
for r in 0..4 {
// expand ceofficients by factor 2^r by filling with zeros
let zero_tail = coefficients.clone().lde(r);
assert_eq!(
fft(zero_tail.clone()),
fft_with_options(zero_tail, Some(r), None)
);
// expand coefficients by factor 2^r by filling with zeros
let zero_tail = coefficients.lde(r);
assert_eq!(fft(&zero_tail), fft_with_options(&zero_tail, Some(r), None));
}
}
@ -350,10 +343,7 @@ mod tests {
let degree = coefficients.len();
let degree_padded = 1 << log2_ceil(degree);
let mut coefficients_padded = coefficients.clone();
for _i in degree..degree_padded {
coefficients_padded.coeffs.push(F::ZERO);
}
let coefficients_padded = coefficients.padded(degree_padded);
evaluate_naive_power_of_2(&coefficients_padded)
}

View File

@ -18,7 +18,7 @@ pub(crate) fn interpolant<F: Field>(points: &[(F, F)]) -> PolynomialCoeffs<F> {
.map(|x| interpolate(points, x, &barycentric_weights))
.collect();
let mut coeffs = ifft(PolynomialValues {
let mut coeffs = ifft(&PolynomialValues {
values: subgroup_evals,
});
coeffs.trim();

View File

@ -91,8 +91,7 @@ fn fri_committed_trees<F: Field + Extendable<D>, const D: usize>(
.collect::<Vec<_>>(),
);
shift = shift.exp_u32(arity as u32);
// TODO: Is it faster to interpolate?
values = coeffs.clone().coset_fft(shift.into())
values = coeffs.coset_fft(shift.into())
}
coeffs.trim();

View File

@ -90,7 +90,7 @@ impl<F: Fn(Target) -> usize> TargetPartition<Target, F> {
}
let mut indices = HashMap::new();
// // Here we keep just the Wire targets, filtering out everything else.
// Here we keep just the Wire targets, filtering out everything else.
let partition = partition
.into_values()
.map(|v| {

View File

@ -34,10 +34,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
/// Creates a list polynomial commitment for the polynomials interpolating the values in `values`.
pub fn new(values: Vec<PolynomialValues<F>>, rate_bits: usize, blinding: bool) -> Self {
let degree = values[0].len();
let polynomials = values
.par_iter()
.map(|v| v.clone().ifft())
.collect::<Vec<_>>();
let polynomials = values.par_iter().map(|v| v.ifft()).collect::<Vec<_>>();
let lde_values = timed!(
Self::lde_values(&polynomials, rate_bits, blinding),
"to compute LDE"
@ -92,7 +89,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
.par_iter()
.map(|p| {
assert_eq!(p.len(), degree, "Polynomial degree invalid.");
p.clone().lde(rate_bits).coset_fft(F::coset_shift()).values
p.lde(rate_bits).coset_fft(F::coset_shift()).values
})
.chain(if blinding {
// If blinding, salt with two random elements to each leaf vector.
@ -182,7 +179,7 @@ impl<F: Field> ListPolynomialCommitment<F> {
final_poly += zs_quotient;
let lde_final_poly = final_poly.lde(config.rate_bits);
let lde_final_values = lde_final_poly.clone().coset_fft(F::coset_shift().into());
let lde_final_values = lde_final_poly.coset_fft(F::coset_shift().into());
let fri_proof = fri_proof(
&commitments

View File

@ -88,7 +88,7 @@ impl<F: Field> PolynomialCoeffs<F> {
let root = F::primitive_root_of_unity(log2_strict(a.len()));
// Equals to the evaluation of `a` on `{g.w^i}`.
let mut a_eval = fft(a);
let mut a_eval = fft(&a);
// Compute the denominators `1/(g^n.w^(n*i) - 1)` using batch inversion.
let denominator_g = g.exp(n as u64);
let root_n = root.exp(n as u64);
@ -112,7 +112,7 @@ impl<F: Field> PolynomialCoeffs<F> {
*x *= d;
});
// `p` is the interpolating polynomial of `a_eval` on `{w^i}`.
let mut p = ifft(a_eval);
let mut p = ifft(&a_eval);
// We need to scale it by `g^(-i)` to get the interpolating polynomial of `a_eval` on `{g.w^i}`,
// a.k.a `a/Z_H`.
let g_inv = g.inverse();

View File

@ -33,12 +33,12 @@ impl<F: Field> PolynomialValues<F> {
self.values.len()
}
pub fn ifft(self) -> PolynomialCoeffs<F> {
pub fn ifft(&self) -> PolynomialCoeffs<F> {
ifft(self)
}
/// Returns the polynomial whose evaluation on the coset `shift*H` is `self`.
pub fn coset_ifft(self, shift: F) -> PolynomialCoeffs<F> {
pub fn coset_ifft(&self, shift: F) -> PolynomialCoeffs<F> {
let mut shifted_coeffs = self.ifft();
shifted_coeffs
.coeffs
@ -54,9 +54,9 @@ impl<F: Field> PolynomialValues<F> {
polys.into_iter().map(|p| p.lde(rate_bits)).collect()
}
pub fn lde(self, rate_bits: usize) -> Self {
pub fn lde(&self, rate_bits: usize) -> Self {
let coeffs = ifft(self).lde(rate_bits);
fft_with_options(coeffs, Some(rate_bits), None)
fft_with_options(&coeffs, Some(rate_bits), None)
}
pub fn degree(&self) -> usize {
@ -66,7 +66,7 @@ impl<F: Field> PolynomialValues<F> {
}
pub fn degree_plus_one(&self) -> usize {
self.clone().ifft().degree_plus_one()
self.ifft().degree_plus_one()
}
}
@ -136,7 +136,7 @@ impl<F: Field> PolynomialCoeffs<F> {
.fold(F::ZERO, |acc, &c| acc * x + c)
}
pub fn lde_multiple(polys: Vec<Self>, rate_bits: usize) -> Vec<Self> {
pub fn lde_multiple(polys: Vec<&Self>, rate_bits: usize) -> Vec<Self> {
polys.into_iter().map(|p| p.lde(rate_bits)).collect()
}
@ -194,16 +194,16 @@ impl<F: Field> PolynomialCoeffs<F> {
Self::new(self.trimmed().coeffs.into_iter().rev().collect())
}
pub fn fft(self) -> PolynomialValues<F> {
pub fn fft(&self) -> PolynomialValues<F> {
fft(self)
}
/// Returns the evaluation of the polynomial on the coset `shift*H`.
pub fn coset_fft(self, shift: F) -> PolynomialValues<F> {
pub fn coset_fft(&self, shift: F) -> PolynomialValues<F> {
let modified_poly: Self = shift
.powers()
.zip(self.coeffs)
.map(|(r, c)| r * c)
.zip(&self.coeffs)
.map(|(r, &c)| r * c)
.collect::<Vec<_>>()
.into();
modified_poly.fft()
@ -262,8 +262,7 @@ impl<F: Field> Sub for &PolynomialCoeffs<F> {
fn sub(self, rhs: Self) -> Self::Output {
let len = max(self.len(), rhs.len());
let mut coeffs = self.coeffs.clone();
coeffs.resize(len, F::ZERO);
let mut coeffs = self.padded(len).coeffs;
for (i, &c) in rhs.coeffs.iter().enumerate() {
coeffs[i] -= c;
}
@ -343,7 +342,7 @@ impl<F: Field> Mul for &PolynomialCoeffs<F> {
.zip(b_evals.values)
.map(|(pa, pb)| pa * pb)
.collect();
ifft(mul_evals.into())
ifft(&mul_evals.into())
}
}
@ -390,7 +389,7 @@ mod tests {
let n = 1 << k;
let poly = PolynomialCoeffs::new(F::rand_vec(n));
let shift = F::rand();
let coset_evals = poly.clone().coset_fft(shift).values;
let coset_evals = poly.coset_fft(shift).values;
let generator = F::primitive_root_of_unity(k);
let naive_coset_evals = F::cyclic_subgroup_coset_known_order(generator, shift, n)
@ -411,7 +410,7 @@ mod tests {
let n = 1 << k;
let evals = PolynomialValues::new(F::rand_vec(n));
let shift = F::rand();
let coeffs = evals.clone().coset_ifft(shift);
let coeffs = evals.coset_ifft(shift);
let generator = F::primitive_root_of_unity(k);
let naive_coset_evals = F::cyclic_subgroup_coset_known_order(generator, shift, n)

View File

@ -51,7 +51,7 @@ pub(crate) fn transpose<T: Clone>(matrix: &[Vec<T>]) -> Vec<Vec<T>> {
}
/// Permutes `arr` such that each index is mapped to its reverse in binary.
pub(crate) fn reverse_index_bits<T: Copy>(arr: Vec<T>) -> Vec<T> {
pub(crate) fn reverse_index_bits<T: Copy>(arr: &[T]) -> Vec<T> {
let n = arr.len();
let n_power = log2_strict(n);
@ -99,12 +99,9 @@ mod tests {
#[test]
fn test_reverse_index_bits() {
assert_eq!(reverse_index_bits(&[10, 20, 30, 40]), vec![10, 30, 20, 40]);
assert_eq!(
reverse_index_bits(vec![10, 20, 30, 40]),
vec![10, 30, 20, 40]
);
assert_eq!(
reverse_index_bits(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
reverse_index_bits(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
vec![0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
);
}