From 06d7007e437116937d0cff44f245929242ef044a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20P=C3=A9rez?= <37264926+CPerezz@users.noreply.github.com> Date: Tue, 27 Feb 2024 09:22:05 +0100 Subject: [PATCH] Remove/best {fft/multiexp} & other unused arithmetic functions (#288) * remove: best_{fft/multiexp} and use halo2curves We remove duplicated code from `halo2` which now is externalized (and more optimal) in `halo2curves`. This is a followup of #282 * remove: Unused functions from arithmetic * remove: FFT & MSM benches As these are now handled by halo2curves. There's no need to bench here. --- halo2_backend/src/arithmetic.rs | 189 +----------------- halo2_backend/src/poly/domain.rs | 3 +- halo2_backend/src/poly/ipa/commitment.rs | 3 +- .../src/poly/ipa/commitment/prover.rs | 5 +- halo2_backend/src/poly/ipa/msm.rs | 3 +- halo2_backend/src/poly/ipa/strategy.rs | 2 +- halo2_backend/src/poly/kzg/commitment.rs | 3 +- halo2_backend/src/poly/kzg/msm.rs | 6 +- halo2_proofs/Cargo.toml | 8 - halo2_proofs/benches/arithmetic.rs | 38 ---- halo2_proofs/benches/fft.rs | 26 --- halo2_proofs/src/lib.rs | 4 +- 12 files changed, 16 insertions(+), 274 deletions(-) delete mode 100644 halo2_proofs/benches/arithmetic.rs delete mode 100644 halo2_proofs/benches/fft.rs diff --git a/halo2_backend/src/arithmetic.rs b/halo2_backend/src/arithmetic.rs index 86ed7474de..4fb09deecd 100644 --- a/halo2_backend/src/arithmetic.rs +++ b/halo2_backend/src/arithmetic.rs @@ -3,12 +3,12 @@ use group::{ ff::{BatchInvert, PrimeField}, - Curve, Group, GroupOpsOwned, ScalarMulOwned, + Curve, GroupOpsOwned, ScalarMulOwned, }; use halo2_common::multicore; pub use halo2_middleware::ff::Field; -use halo2curves::msm::multiexp_serial; +use halo2curves::fft::best_fft; pub use halo2curves::{CurveAffine, CurveExt}; /// This represents an element of a group with basic operations that can be @@ -26,179 +26,6 @@ where { } -/// Performs a small multi-exponentiation operation. -/// Uses the double-and-add algorithm with doublings shared across points. -pub fn small_multiexp(coeffs: &[C::Scalar], bases: &[C]) -> C::Curve { - let coeffs: Vec<_> = coeffs.iter().map(|a| a.to_repr()).collect(); - let mut acc = C::Curve::identity(); - - // for byte idx - for byte_idx in (0..((C::Scalar::NUM_BITS as usize + 7) / 8)).rev() { - // for bit idx - for bit_idx in (0..8).rev() { - acc = acc.double(); - // for each coeff - for coeff_idx in 0..coeffs.len() { - let byte = coeffs[coeff_idx].as_ref()[byte_idx]; - if ((byte >> bit_idx) & 1) != 0 { - acc += bases[coeff_idx]; - } - } - } - } - - acc -} - -/// Performs a multi-exponentiation operation. -/// -/// This function will panic if coeffs and bases have a different length. -/// -/// This will use multithreading if beneficial. -pub fn best_multiexp(coeffs: &[C::Scalar], bases: &[C]) -> C::Curve { - assert_eq!(coeffs.len(), bases.len()); - - let num_threads = multicore::current_num_threads(); - if coeffs.len() > num_threads { - let chunk = coeffs.len() / num_threads; - let num_chunks = coeffs.chunks(chunk).len(); - let mut results = vec![C::Curve::identity(); num_chunks]; - multicore::scope(|scope| { - let chunk = coeffs.len() / num_threads; - - for ((coeffs, bases), acc) in coeffs - .chunks(chunk) - .zip(bases.chunks(chunk)) - .zip(results.iter_mut()) - { - scope.spawn(move |_| { - multiexp_serial(coeffs, bases, acc); - }); - } - }); - results.iter().fold(C::Curve::identity(), |a, b| a + b) - } else { - let mut acc = C::Curve::identity(); - multiexp_serial(coeffs, bases, &mut acc); - acc - } -} - -/// Performs a radix-$2$ Fast-Fourier Transformation (FFT) on a vector of size -/// $n = 2^k$, when provided `log_n` = $k$ and an element of multiplicative -/// order $n$ called `omega` ($\omega$). The result is that the vector `a`, when -/// interpreted as the coefficients of a polynomial of degree $n - 1$, is -/// transformed into the evaluations of this polynomial at each of the $n$ -/// distinct powers of $\omega$. This transformation is invertible by providing -/// $\omega^{-1}$ in place of $\omega$ and dividing each resulting field element -/// by $n$. -/// -/// This will use multithreading if beneficial. -pub fn best_fft>(a: &mut [G], omega: Scalar, log_n: u32) { - fn bitreverse(mut n: usize, l: usize) -> usize { - let mut r = 0; - for _ in 0..l { - r = (r << 1) | (n & 1); - n >>= 1; - } - r - } - - let threads = multicore::current_num_threads(); - let log_threads = log2_floor(threads); - let n = a.len(); - assert_eq!(n, 1 << log_n); - - for k in 0..n { - let rk = bitreverse(k, log_n as usize); - if k < rk { - a.swap(rk, k); - } - } - - // precompute twiddle factors - let twiddles: Vec<_> = (0..(n / 2)) - .scan(Scalar::ONE, |w, _| { - let tw = *w; - *w *= ω - Some(tw) - }) - .collect(); - - if log_n <= log_threads { - let mut chunk = 2_usize; - let mut twiddle_chunk = n / 2; - for _ in 0..log_n { - a.chunks_mut(chunk).for_each(|coeffs| { - let (left, right) = coeffs.split_at_mut(chunk / 2); - - // case when twiddle factor is one - let (a, left) = left.split_at_mut(1); - let (b, right) = right.split_at_mut(1); - let t = b[0]; - b[0] = a[0]; - a[0] += &t; - b[0] -= &t; - - left.iter_mut() - .zip(right.iter_mut()) - .enumerate() - .for_each(|(i, (a, b))| { - let mut t = *b; - t *= &twiddles[(i + 1) * twiddle_chunk]; - *b = *a; - *a += &t; - *b -= &t; - }); - }); - chunk *= 2; - twiddle_chunk /= 2; - } - } else { - recursive_butterfly_arithmetic(a, n, 1, &twiddles) - } -} - -/// This perform recursive butterfly arithmetic -pub fn recursive_butterfly_arithmetic>( - a: &mut [G], - n: usize, - twiddle_chunk: usize, - twiddles: &[Scalar], -) { - if n == 2 { - let t = a[1]; - a[1] = a[0]; - a[0] += &t; - a[1] -= &t; - } else { - let (left, right) = a.split_at_mut(n / 2); - multicore::join( - || recursive_butterfly_arithmetic(left, n / 2, twiddle_chunk * 2, twiddles), - || recursive_butterfly_arithmetic(right, n / 2, twiddle_chunk * 2, twiddles), - ); - - // case when twiddle factor is one - let (a, left) = left.split_at_mut(1); - let (b, right) = right.split_at_mut(1); - let t = b[0]; - b[0] = a[0]; - a[0] += &t; - b[0] -= &t; - - left.iter_mut() - .zip(right.iter_mut()) - .enumerate() - .for_each(|(i, (a, b))| { - let mut t = *b; - t *= &twiddles[(i + 1) * twiddle_chunk]; - *b = *a; - *a += &t; - *b -= &t; - }); - } -} - /// Convert coefficient bases group elements to lagrange basis by inverse FFT. pub fn g_to_lagrange(g_projective: Vec, k: u32) -> Vec { let n_inv = C::Scalar::TWO_INV.pow_vartime([k as u64, 0, 0, 0]); @@ -344,18 +171,6 @@ pub fn parallelize(v: &mu }); } -fn log2_floor(num: usize) -> u32 { - assert!(num > 0); - - let mut pow = 0; - - while (1 << (pow + 1)) <= num { - pow += 1; - } - - pow -} - /// Returns coefficients of an n - 1 degree polynomial given a set of n points /// and their evaluations. This function will panic if two values in `points` /// are the same. diff --git a/halo2_backend/src/poly/domain.rs b/halo2_backend/src/poly/domain.rs index 09c9f9c794..dabc797da4 100644 --- a/halo2_backend/src/poly/domain.rs +++ b/halo2_backend/src/poly/domain.rs @@ -1,12 +1,13 @@ //! Contains utilities for performing polynomial arithmetic over an evaluation //! domain that is of a suitable size for the application. -use crate::arithmetic::{best_fft, parallelize}; +use crate::arithmetic::parallelize; use super::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial}; use group::ff::{BatchInvert, Field}; use halo2_middleware::ff::WithSmallOrderMulGroup; use halo2_middleware::poly::Rotation; +use halo2curves::fft::best_fft; use std::marker::PhantomData; diff --git a/halo2_backend/src/poly/ipa/commitment.rs b/halo2_backend/src/poly/ipa/commitment.rs index 388adfa0a4..7f75dc1269 100644 --- a/halo2_backend/src/poly/ipa/commitment.rs +++ b/halo2_backend/src/poly/ipa/commitment.rs @@ -3,13 +3,14 @@ //! //! [halo]: https://eprint.iacr.org/2019/1021 -use crate::arithmetic::{best_multiexp, g_to_lagrange, parallelize, CurveAffine, CurveExt}; +use crate::arithmetic::{g_to_lagrange, parallelize, CurveAffine, CurveExt}; use crate::helpers::CurveRead; use crate::poly::commitment::{Blind, CommitmentScheme, Params, ParamsProver, ParamsVerifier}; use crate::poly::ipa::msm::MSMIPA; use crate::poly::{Coeff, LagrangeCoeff, Polynomial}; use group::{Curve, Group}; +use halo2curves::msm::best_multiexp; use std::marker::PhantomData; mod prover; diff --git a/halo2_backend/src/poly/ipa/commitment/prover.rs b/halo2_backend/src/poly/ipa/commitment/prover.rs index 3a23cd152a..b7f6009794 100644 --- a/halo2_backend/src/poly/ipa/commitment/prover.rs +++ b/halo2_backend/src/poly/ipa/commitment/prover.rs @@ -1,10 +1,9 @@ use halo2_middleware::ff::Field; +use halo2curves::msm::best_multiexp; use rand_core::RngCore; use super::ParamsIPA; -use crate::arithmetic::{ - best_multiexp, compute_inner_product, eval_polynomial, parallelize, CurveAffine, -}; +use crate::arithmetic::{compute_inner_product, eval_polynomial, parallelize, CurveAffine}; use crate::poly::commitment::ParamsProver; use crate::poly::{commitment::Blind, Coeff, Polynomial}; diff --git a/halo2_backend/src/poly/ipa/msm.rs b/halo2_backend/src/poly/ipa/msm.rs index 0154bdef31..497ebb6bd6 100644 --- a/halo2_backend/src/poly/ipa/msm.rs +++ b/halo2_backend/src/poly/ipa/msm.rs @@ -1,7 +1,8 @@ -use crate::arithmetic::{best_multiexp, CurveAffine}; +use crate::arithmetic::CurveAffine; use crate::poly::{commitment::MSM, ipa::commitment::ParamsVerifierIPA}; use group::Group; use halo2_middleware::ff::Field; +use halo2curves::msm::best_multiexp; use std::collections::BTreeMap; /// A multiscalar multiplication in the polynomial commitment scheme diff --git a/halo2_backend/src/poly/ipa/strategy.rs b/halo2_backend/src/poly/ipa/strategy.rs index 6900981f01..b95668594e 100644 --- a/halo2_backend/src/poly/ipa/strategy.rs +++ b/halo2_backend/src/poly/ipa/strategy.rs @@ -2,7 +2,6 @@ use super::commitment::{IPACommitmentScheme, ParamsIPA}; use super::msm::MSMIPA; use super::multiopen::VerifierIPA; use crate::{ - arithmetic::best_multiexp, plonk::Error, poly::{ commitment::MSM, @@ -11,6 +10,7 @@ use crate::{ }; use group::Curve; use halo2_middleware::ff::Field; +use halo2curves::msm::best_multiexp; use halo2curves::CurveAffine; use rand_core::OsRng; diff --git a/halo2_backend/src/poly/kzg/commitment.rs b/halo2_backend/src/poly/kzg/commitment.rs index c9d2285a09..7f25c17d7a 100644 --- a/halo2_backend/src/poly/kzg/commitment.rs +++ b/halo2_backend/src/poly/kzg/commitment.rs @@ -1,4 +1,4 @@ -use crate::arithmetic::{best_multiexp, g_to_lagrange, parallelize}; +use crate::arithmetic::{g_to_lagrange, parallelize}; use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::{Blind, CommitmentScheme, Params, ParamsProver, ParamsVerifier}; use crate::poly::{Coeff, LagrangeCoeff, Polynomial}; @@ -6,6 +6,7 @@ use crate::SerdeFormat; use group::{prime::PrimeCurveAffine, Curve, Group}; use halo2_middleware::ff::{Field, PrimeField}; +use halo2curves::msm::best_multiexp; use halo2curves::pairing::Engine; use halo2curves::CurveExt; use rand_core::{OsRng, RngCore}; diff --git a/halo2_backend/src/poly/kzg/msm.rs b/halo2_backend/src/poly/kzg/msm.rs index 2c0fa4a6e3..a086ecf08b 100644 --- a/halo2_backend/src/poly/kzg/msm.rs +++ b/halo2_backend/src/poly/kzg/msm.rs @@ -1,12 +1,10 @@ use std::fmt::Debug; use super::commitment::ParamsKZG; -use crate::{ - arithmetic::{best_multiexp, parallelize}, - poly::commitment::MSM, -}; +use crate::{arithmetic::parallelize, poly::commitment::MSM}; use group::{Curve, Group}; use halo2curves::{ + msm::best_multiexp, pairing::{Engine, MillerLoopResult, MultiMillerLoop}, CurveAffine, CurveExt, }; diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index 8bf059790b..4a1d8892aa 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -24,10 +24,6 @@ keywords = ["halo", "proofs", "zkp", "zkSNARKs"] all-features = true rustdoc-args = ["--cfg", "docsrs", "--html-in-header", "katex-header.html"] -[[bench]] -name = "arithmetic" -harness = false - [[bench]] name = "commit_zk" harness = false @@ -44,10 +40,6 @@ harness = false name = "dev_lookup" harness = false -[[bench]] -name = "fft" -harness = false - [dependencies] halo2_middleware = { path = "../halo2_middleware" } halo2_common = { path = "../halo2_common" } diff --git a/halo2_proofs/benches/arithmetic.rs b/halo2_proofs/benches/arithmetic.rs deleted file mode 100644 index 4ae88af137..0000000000 --- a/halo2_proofs/benches/arithmetic.rs +++ /dev/null @@ -1,38 +0,0 @@ -#[macro_use] -extern crate criterion; - -use crate::arithmetic::small_multiexp; -use crate::halo2curves::pasta::{EqAffine, Fp}; -use group::ff::Field; -use halo2_proofs::*; - -use halo2_proofs::poly::{commitment::ParamsProver, ipa::commitment::ParamsIPA}; - -use criterion::{black_box, Criterion}; -use rand_core::OsRng; - -fn criterion_benchmark(c: &mut Criterion) { - let rng = OsRng; - - // small multiexp - { - let params: ParamsIPA = ParamsIPA::new(5); - let g = &mut params.get_g().to_vec(); - let len = g.len() / 2; - let (g_lo, g_hi) = g.split_at_mut(len); - - let coeff_1 = Fp::random(rng); - let coeff_2 = Fp::random(rng); - - c.bench_function("double-and-add", |b| { - b.iter(|| { - for (g_lo, g_hi) in g_lo.iter().zip(g_hi.iter()) { - small_multiexp(&[black_box(coeff_1), black_box(coeff_2)], &[*g_lo, *g_hi]); - } - }) - }); - } -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); diff --git a/halo2_proofs/benches/fft.rs b/halo2_proofs/benches/fft.rs deleted file mode 100644 index 0de72a0380..0000000000 --- a/halo2_proofs/benches/fft.rs +++ /dev/null @@ -1,26 +0,0 @@ -#[macro_use] -extern crate criterion; - -use crate::arithmetic::best_fft; -use group::ff::Field; -use halo2_proofs::*; -use halo2curves::pasta::Fp; - -use criterion::{BenchmarkId, Criterion}; -use rand_core::OsRng; - -fn criterion_benchmark(c: &mut Criterion) { - let mut group = c.benchmark_group("fft"); - for k in 3..19 { - group.bench_function(BenchmarkId::new("k", k), |b| { - let mut a = (0..(1 << k)).map(|_| Fp::random(OsRng)).collect::>(); - let omega = Fp::random(OsRng); // would be weird if this mattered - b.iter(|| { - best_fft(&mut a, omega, k as u32); - }); - }); - } -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); diff --git a/halo2_proofs/src/lib.rs b/halo2_proofs/src/lib.rs index 4f72856a10..8a8b8bbb13 100644 --- a/halo2_proofs/src/lib.rs +++ b/halo2_proofs/src/lib.rs @@ -23,9 +23,7 @@ pub mod circuit { /// This module provides common utilities, traits and structures for group, /// field and polynomial arithmetic. pub mod arithmetic { - pub use halo2_backend::arithmetic::{ - best_fft, parallelize, small_multiexp, CurveAffine, CurveExt, Field, - }; + pub use halo2_backend::arithmetic::{parallelize, CurveAffine, CurveExt, Field}; } /// Tools for developing circuits. pub mod dev {