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!: add compile time flags to disable rayon #240

Merged
merged 10 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"bindings/nim/rust_code",
"bindings/csharp/rust_code",
"eip7594",
"maybe_rayon",
"cryptography/bls12_381",
"cryptography/kzg_multi_open",
"cryptography/polynomial",
Expand All @@ -31,6 +32,7 @@ bls12_381 = { package = "crate_crypto_internal_eth_kzg_bls12_381", version = "0.
polynomial = { package = "crate_crypto_internal_eth_kzg_polynomial", version = "0.4.1", path = "cryptography/polynomial" }
erasure_codes = { package = "crate_crypto_internal_eth_kzg_erasure_codes", version = "0.4.1", path = "cryptography/erasure_codes" }
rust_eth_kzg = { version = "0.4.1", path = "eip7594" }
maybe_rayon = { package = "crate_crypto_internal_eth_kzg_maybe_rayon", version = "0.4.1", path = "maybe_rayon" }
kzg_multi_open = { package = "crate_crypto_kzg_multi_open_fk20", version = "0.4.1", path = "cryptography/kzg_multi_open" }
c_eth_kzg = { version = "0.4.1", path = "bindings/c" }
hex = "0.4.3"
Expand Down
2 changes: 1 addition & 1 deletion bindings/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ napi = { version = "2.12.2", default-features = false, features = [
"async",
] }
napi-derive = "2.12.2"
rust_eth_kzg = { workspace = true }
rust_eth_kzg = { workspace = true, features = ["multithreading"] }

[build-dependencies]
napi-build = "2.0.1"
3 changes: 3 additions & 0 deletions cryptography/bls12_381/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ subtle = { version = ">=2.5.0, <3.0" }
criterion = "0.5.1"
rand = "0.8.4"

[features]
blst-no-threads = ["blst/no-threads"]

[[bench]]
name = "benchmark"
harness = false
6 changes: 5 additions & 1 deletion cryptography/kzg_multi_open/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@ repository = { workspace = true }
[dependencies]
bls12_381 = { workspace = true }
polynomial = { workspace = true }
maybe_rayon = { workspace = true }
hex = { workspace = true }
rayon = { workspace = true }
sha2 = "0.10.8"

[dev-dependencies]
criterion = "0.5.1"
rand = "0.8.4"

[features]
singlethreading = ["bls12_381/blst-no-threads"]
multithreading = ["maybe_rayon/multithreading"]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should standardize this to single-thread, multi-thread


[[bench]]
name = "benchmark"
harness = false
17 changes: 9 additions & 8 deletions cryptography/kzg_multi_open/src/fk20/batch_toeplitz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use bls12_381::{
fixed_base_msm::{FixedBaseMSM, UsePrecomp},
g1_batch_normalize, G1Point, G1Projective,
};
use maybe_rayon::prelude::*;
use polynomial::domain::Domain;
use rayon::prelude::*;

/// BatchToeplitzMatrixVecMul allows one to compute multiple matrix vector multiplications
/// and sum them together.
Expand Down Expand Up @@ -43,7 +43,7 @@ impl BatchToeplitzMatrixVecMul {

// Precompute the FFT of the vectors, since they do not change per matrix-vector multiplication
let vectors: Vec<Vec<G1Point>> = vectors
.into_par_iter()
.maybe_par_iter()
.map(|vector| {
let vector_projective = vector
.iter()
Expand All @@ -61,7 +61,7 @@ impl BatchToeplitzMatrixVecMul {
//
// This is a trade-off between storage and computation, where storage grows exponentially.
let precomputed_table: Vec<_> = transposed_msm_vectors
.into_par_iter()
.maybe_into_par_iter()
.map(|v| FixedBaseMSM::new(v, use_precomp))
.collect();

Expand All @@ -87,22 +87,23 @@ impl BatchToeplitzMatrixVecMul {
);

// Embed Toeplitz matrices into circulant matrices
let circulant_matrices = matrices.into_iter().map(CirculantMatrix::from_toeplitz);
let circulant_matrices = matrices
.maybe_into_par_iter()
.map(CirculantMatrix::from_toeplitz);

// Perform circulant matrix-vector multiplication between all of the matrices and vectors
// and sum them together.
//
// Transpose the circulant matrices so that we convert a group of hadamard products into a group of
// inner products.
let col_ffts: Vec<_> = circulant_matrices
.into_iter()
.maybe_into_par_iter()
.map(|matrix| self.circulant_domain.fft_scalars(matrix.row))
.collect();
let msm_scalars = transpose(col_ffts);

let result: Vec<_> = self
.precomputed_fft_vectors
.iter()
let result: Vec<_> = (&self.precomputed_fft_vectors)
.maybe_par_iter()
.zip(msm_scalars)
.map(|(points, scalars)| points.msm(scalars))
.collect();
Expand Down
6 changes: 5 additions & 1 deletion eip7594/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ kzg_multi_open = { workspace = true }
bls12_381 = { workspace = true }
hex = { workspace = true }
erasure_codes = { workspace = true }
rayon = { workspace = true }
rayon = { workspace = true, optional = true }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

[features]
multithreading = ["rayon"]
kevaundray marked this conversation as resolved.
Show resolved Hide resolved

[dev-dependencies]
criterion = "0.5.1"
rand = "0.8.4"
Expand All @@ -28,3 +31,4 @@ serde_yaml = "0.9.34"
[[bench]]
name = "benchmark"
harness = false
required-features = ["multithreading"]
43 changes: 38 additions & 5 deletions eip7594/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ mod prover;
mod serialization;
mod trusted_setup;
mod verifier;
#[macro_use]
pub(crate) mod macros;

pub use bls12_381::fixed_base_msm::UsePrecomp;
// Exported types
Expand Down Expand Up @@ -54,9 +56,12 @@ pub type CellIndex = kzg_multi_open::CosetIndex;

use constants::{BYTES_PER_BLOB, BYTES_PER_CELL, BYTES_PER_COMMITMENT};
use prover::ProverContext;
use verifier::VerifierContext;

#[cfg(feature = "multithreading")]
use rayon::ThreadPool;
#[cfg(feature = "multithreading")]
use std::sync::Arc;
use verifier::VerifierContext;

/// ThreadCount indicates whether we want to use a single thread or multiple threads
#[derive(Debug, Copy, Clone)]
Expand All @@ -65,19 +70,23 @@ pub enum ThreadCount {
Single,
/// Initializes the threadpool with the number of threads
/// denoted by this enum variant.
#[cfg(feature = "multithreading")]
Multi(usize),
/// Initializes the threadpool with a sensible default number of
/// threads. This is currently set to `RAYON_NUM_THREADS`.
#[cfg(feature = "multithreading")]
SensibleDefault,
}

impl From<ThreadCount> for usize {
fn from(value: ThreadCount) -> Self {
match value {
ThreadCount::Single => 1,
#[cfg(feature = "multithreading")]
ThreadCount::Multi(num_threads) => num_threads,
// Setting this to `0` will tell ThreadPool to use
// `RAYON_NUM_THREADS`.
#[cfg(feature = "multithreading")]
ThreadCount::SensibleDefault => 0,
}
}
Expand All @@ -86,29 +95,37 @@ impl From<ThreadCount> for usize {
/// The context that will be used to create and verify opening proofs.
#[derive(Debug)]
pub struct DASContext {
#[cfg(feature = "multithreading")]
thread_pool: Arc<ThreadPool>,
pub prover_ctx: ProverContext,
pub verifier_ctx: VerifierContext,
}

#[cfg(feature = "multithreading")]
impl Default for DASContext {
fn default() -> Self {
let trusted_setup = TrustedSetup::default();
const DEFAULT_NUM_THREADS: ThreadCount = ThreadCount::Single;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might make sense to make the default SensibleDefault and then have that use the global threadpool

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In terms of defaults, single-thread, global threadpool and then a feature flag for local threadpool with threadcount might be the best, or just ask users to import threadpool in their own crate and set the threadpool amount themselves

DASContext::with_threads(&trusted_setup, DEFAULT_NUM_THREADS, UsePrecomp::No)
}
}
#[cfg(not(feature = "multithreading"))]
impl Default for DASContext {
fn default() -> Self {
let trusted_setup = TrustedSetup::default();

DASContext::new(&trusted_setup, UsePrecomp::No)
}
}

impl DASContext {
#[cfg(feature = "multithreading")]
pub fn with_threads(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename this to new so that when users switch from single to multithread, they just need to modify the number of parameters

trusted_setup: &TrustedSetup,
num_threads: ThreadCount,
// This parameter indicates whether we should allocate memory
// in order to speed up proof creation. Heuristics show that
// if pre-computations are desired, one should set the
// width value to `8` for optimal storage and performance tradeoffs.
use_precomp: UsePrecomp,
) -> Self {
#[cfg(feature = "multithreading")]
let thread_pool = std::sync::Arc::new(
rayon::ThreadPoolBuilder::new()
.num_threads(num_threads.into())
Expand All @@ -117,12 +134,28 @@ impl DASContext {
);

DASContext {
#[cfg(feature = "multithreading")]
thread_pool,
prover_ctx: ProverContext::new(trusted_setup, use_precomp),
verifier_ctx: VerifierContext::new(trusted_setup),
}
}

#[cfg(not(feature = "multithreading"))]
pub fn new(
trusted_setup: &TrustedSetup,
// This parameter indicates whether we should allocate memory
// in order to speed up proof creation. Heuristics show that
// if pre-computations are desired, one should set the
// width value to `8` for optimal storage and performance tradeoffs.
use_precomp: UsePrecomp,
) -> Self {
DASContext {
prover_ctx: ProverContext::new(trusted_setup, use_precomp),
verifier_ctx: VerifierContext::new(trusted_setup),
}
}

pub fn prover_ctx(&self) -> &ProverContext {
&self.prover_ctx
}
Expand Down
13 changes: 13 additions & 0 deletions eip7594/src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#[macro_export]
macro_rules! with_optional_threadpool {
($self:expr, $body:expr) => {{
#[cfg(feature = "multithreading")]
{
$self.thread_pool.install(|| $body)
}
#[cfg(not(feature = "multithreading"))]
{
$body
}
}};
}
9 changes: 5 additions & 4 deletions eip7594/src/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use crate::{
deserialize_blob_to_scalars, serialize_cells_and_proofs, serialize_g1_compressed,
},
trusted_setup::TrustedSetup,
BlobRef, Cell, CellIndex, CellRef, DASContext, KZGCommitment, KZGProof,
with_optional_threadpool, BlobRef, Cell, CellIndex, CellRef, DASContext, KZGCommitment,
KZGProof,
};

/// Context object that is used to call functions in the prover API.
Expand Down Expand Up @@ -64,7 +65,7 @@ impl DASContext {
///
/// The matching function in the specs is: https://github.com/ethereum/consensus-specs/blob/13ac373a2c284dc66b48ddd2ef0a10537e4e0de6/specs/deneb/polynomial-commitments.md#blob_to_kzg_commitment
pub fn blob_to_kzg_commitment(&self, blob: BlobRef) -> Result<KZGCommitment, Error> {
self.thread_pool.install(|| {
with_optional_threadpool!(self, {
// Deserialize the blob into scalars.
let scalars = deserialize_blob_to_scalars(blob)?;

Expand All @@ -86,7 +87,7 @@ impl DASContext {
&self,
blob: BlobRef,
) -> Result<([Cell; CELLS_PER_EXT_BLOB], [KZGProof; CELLS_PER_EXT_BLOB]), Error> {
self.thread_pool.install(|| {
with_optional_threadpool!(self, {
// Deserialization
//
let scalars = deserialize_blob_to_scalars(blob)?;
Expand Down Expand Up @@ -116,7 +117,7 @@ impl DASContext {
cell_indices: Vec<CellIndex>,
cells: Vec<CellRef>,
) -> Result<([Cell; CELLS_PER_EXT_BLOB], [KZGProof; CELLS_PER_EXT_BLOB]), Error> {
self.thread_pool.install(|| {
with_optional_threadpool!(self, {
// Recover polynomial
//
let poly_coeff = self.recover_polynomial_coeff(cell_indices, cells)?;
Expand Down
4 changes: 2 additions & 2 deletions eip7594/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
errors::Error,
serialization::{deserialize_cells, deserialize_compressed_g1_points},
trusted_setup::TrustedSetup,
Bytes48Ref, CellIndex, CellRef, DASContext,
with_optional_threadpool, Bytes48Ref, CellIndex, CellRef, DASContext,
};
use bls12_381::Scalar;
use erasure_codes::{BlockErasureIndices, ReedSolomon};
Expand Down Expand Up @@ -103,7 +103,7 @@ impl DASContext {
cells: Vec<CellRef>,
proofs_bytes: Vec<Bytes48Ref>,
) -> Result<(), Error> {
self.thread_pool.install(|| {
with_optional_threadpool!(self, {
let (deduplicated_commitments, row_indices) = deduplicate_with_indices(commitments);
// Validation
//
Expand Down
15 changes: 15 additions & 0 deletions maybe_rayon/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "crate_crypto_internal_eth_kzg_maybe_rayon"
description = "This crate provides an implementation of a wrapper around the rayon crate"
version = { workspace = true }
authors = { workspace = true }
edition = { workspace = true }
license = { workspace = true }
rust-version = { workspace = true }
repository = { workspace = true }

[dependencies]
rayon = { workspace = true, optional = true }

[features]
multithreading = ["rayon"]
17 changes: 17 additions & 0 deletions maybe_rayon/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#[cfg(feature = "multithreading")]
mod multi_threaded;
#[cfg(not(feature = "multithreading"))]
mod single_threaded;

#[cfg(feature = "multithreading")]
pub use multi_threaded::*;
#[cfg(not(feature = "multithreading"))]
pub use single_threaded::*;

pub mod prelude {
pub use crate::MaybeParallelRefExt;
pub use crate::MaybeParallelRefMutExt;
pub use crate::*;
#[cfg(feature = "multithreading")]
pub use rayon::prelude::*;
}
29 changes: 29 additions & 0 deletions maybe_rayon/src/multi_threaded.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
pub use rayon::iter::IntoParallelIterator;
pub use rayon::iter::IntoParallelRefIterator;
pub use rayon::iter::IntoParallelRefMutIterator;
pub use rayon::iter::ParallelIterator;

pub trait MaybeParallelExt: IntoParallelIterator {
fn maybe_into_par_iter(self) -> <Self as IntoParallelIterator>::Iter
where
Self: Sized,
{
self.into_par_iter()
}
}

pub trait MaybeParallelRefExt: for<'a> IntoParallelRefIterator<'a> {
fn maybe_par_iter(&self) -> <Self as IntoParallelRefIterator>::Iter {
self.par_iter()
}
}

pub trait MaybeParallelRefMutExt: for<'a> IntoParallelRefMutIterator<'a> {
fn maybe_par_iter_mut(&mut self) -> <Self as IntoParallelRefMutIterator>::Iter {
self.par_iter_mut()
}
}

impl<T: IntoParallelIterator> MaybeParallelExt for T {}
impl<T: for<'a> IntoParallelRefIterator<'a>> MaybeParallelRefExt for T {}
impl<T: for<'a> IntoParallelRefMutIterator<'a>> MaybeParallelRefMutExt for T {}
Loading
Loading