diff --git a/Cargo.toml b/Cargo.toml index 73b486dbb..52abf8147 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,13 @@ thiserror = "1.0" [dev-dependencies] assert_matches = "1.5.0" +criterion = "0.3" modinverse = "0.1.0" num-bigint = "0.4.0" +[[bench]] +name = "fft" +harness = false + [[example]] name = "sum" diff --git a/benches/fft.rs b/benches/fft.rs new file mode 100644 index 000000000..e51276e0a --- /dev/null +++ b/benches/fft.rs @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MPL-2.0 + +use criterion::{criterion_group, criterion_main, Criterion}; + +use prio::benchmarked::{benchmarked_iterative_fft, benchmarked_recursive_fft}; +use prio::finite_field::{Field, FieldElement}; + +pub fn fft(c: &mut Criterion) { + let test_sizes = [16, 256, 1024, 4096]; + for size in test_sizes.iter() { + let mut rng = rand::thread_rng(); + let mut inp = vec![Field::zero(); *size]; + let mut outp = vec![Field::zero(); *size]; + for i in 0..*size { + inp[i] = Field::rand(&mut rng); + } + + c.bench_function(&format!("iterative/{}", *size), |b| { + b.iter(|| { + benchmarked_iterative_fft(&mut outp, &inp); + }) + }); + + c.bench_function(&format!("recursive/{}", *size), |b| { + b.iter(|| { + benchmarked_recursive_fft(&mut outp, &inp); + }) + }); + } +} + +criterion_group!(benches, fft); +criterion_main!(benches); diff --git a/src/benchmarked.rs b/src/benchmarked.rs new file mode 100644 index 000000000..a4d826ed2 --- /dev/null +++ b/src/benchmarked.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MPL-2.0 + +//! This packages provides wrappers around internal components of this crate that we wnat to +//! benchmark, but which we don't want to expose in the public API. + +use crate::fft::discrete_fourier_transform; +use crate::finite_field::{Field, FieldElement}; +use crate::polynomial::{poly_fft, PolyAuxMemory}; + +/// Sets `outp` to the Discrete Fourier Transform (DFT) using an iterative FFT algorithm. +pub fn benchmarked_iterative_fft(outp: &mut [F], inp: &[F]) { + discrete_fourier_transform(outp, inp).expect("encountered unexpected error"); +} + +/// Sets `outp` to the Discrete Fourier Transform (DFT) using a recursive FFT algorithm. +pub fn benchmarked_recursive_fft(outp: &mut [Field], inp: &[Field]) { + let mut mem = PolyAuxMemory::new(inp.len() / 2); + poly_fft( + outp, + inp, + &mem.roots_2n, + inp.len(), + false, + &mut mem.fft_memory, + ) +} diff --git a/src/fft.rs b/src/fft.rs index e4360b509..370ce2fff 100644 --- a/src/fft.rs +++ b/src/fft.rs @@ -67,6 +67,7 @@ pub fn discrete_fourier_transform( } /// Sets `outp` to the inverse of the DFT of `inp`. +#[allow(dead_code)] pub fn discrete_fourier_transform_inv( outp: &mut [F], inp: &[F], diff --git a/src/lib.rs b/src/lib.rs index 2c4e35414..965c8ae50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,9 +9,10 @@ //! //! For now we only support 0 / 1 vectors. +pub mod benchmarked; pub mod client; pub mod encrypt; -pub mod fft; +mod fft; pub mod finite_field; mod fp; mod polynomial;