Skip to content
Open
Show file tree
Hide file tree
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
34 changes: 16 additions & 18 deletions ec/src/models/bls12/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::{
models::{short_weierstrass::SWCurveConfig, CurveConfig},
models::{
parallel_pairing_utils::threshold_chunked_loop, short_weierstrass::SWCurveConfig,
CurveConfig,
},
pairing::{MillerLoopOutput, Pairing, PairingOutput},
AffineRepr,
};
Expand All @@ -12,13 +15,10 @@ use ark_ff::{
},
BitIteratorBE, CyclotomicMultSubgroup, Field, PrimeField,
};
use ark_std::{cfg_chunks_mut, marker::PhantomData, vec::*};
use ark_std::{marker::PhantomData, vec::*};
use educe::Educe;
use num_traits::{One, Zero};

#[cfg(feature = "parallel")]
use rayon::prelude::*;

/// A particular BLS12 group can have G2 being either a multiplicative or a
/// divisive twist.
pub enum TwistType {
Expand Down Expand Up @@ -62,23 +62,21 @@ pub trait Bls12Config: 'static + Sized {
})
.collect::<Vec<_>>();

let mut f = cfg_chunks_mut!(pairs, 4)
.map(|pairs| {
let mut f = <Bls12<Self> as Pairing>::TargetField::one();
for i in BitIteratorBE::without_leading_zeros(Self::X).skip(1) {
f.square_in_place();
let mut f = threshold_chunked_loop(&mut pairs, |pairs| {
let mut f = <Bls12<Self> as Pairing>::TargetField::one();
for i in BitIteratorBE::without_leading_zeros(Self::X).skip(1) {
f.square_in_place();
for (p, coeffs) in pairs.iter_mut() {
Bls12::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}
if i {
for (p, coeffs) in pairs.iter_mut() {
Bls12::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}
if i {
for (p, coeffs) in pairs.iter_mut() {
Bls12::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}
}
}
f
})
.product::<<Bls12<Self> as Pairing>::TargetField>();
}
f
});

if Self::X_IS_NEGATIVE {
f.cyclotomic_inverse_in_place();
Expand Down
42 changes: 20 additions & 22 deletions ec/src/models/bn/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::{
models::{short_weierstrass::SWCurveConfig, CurveConfig},
models::{
parallel_pairing_utils::threshold_chunked_loop, short_weierstrass::SWCurveConfig,
CurveConfig,
},
pairing::{MillerLoopOutput, Pairing, PairingOutput},
};
use ark_ff::{
Expand All @@ -11,14 +14,11 @@ use ark_ff::{
},
CyclotomicMultSubgroup,
};
use ark_std::{cfg_chunks_mut, marker::PhantomData, vec::*};
use ark_std::{marker::PhantomData, vec::*};
use educe::Educe;
use itertools::Itertools;
use num_traits::One;

#[cfg(feature = "parallel")]
use rayon::prelude::*;

pub enum TwistType {
M,
D,
Expand Down Expand Up @@ -64,28 +64,26 @@ pub trait BnConfig: 'static + Sized {
})
.collect::<Vec<_>>();

let mut f = cfg_chunks_mut!(pairs, 4)
.map(|pairs| {
let mut f = <Bn<Self> as Pairing>::TargetField::one();
for i in (1..Self::ATE_LOOP_COUNT.len()).rev() {
if i != Self::ATE_LOOP_COUNT.len() - 1 {
f.square_in_place();
}
let mut f = threshold_chunked_loop(&mut pairs, |pairs| {
let mut f = <Bn<Self> as Pairing>::TargetField::one();
for i in (1..Self::ATE_LOOP_COUNT.len()).rev() {
if i != Self::ATE_LOOP_COUNT.len() - 1 {
f.square_in_place();
}

for (p, coeffs) in pairs.iter_mut() {
Bn::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}

let bit = Self::ATE_LOOP_COUNT[i - 1];
if bit == 1 || bit == -1 {
for (p, coeffs) in pairs.iter_mut() {
Bn::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}

let bit = Self::ATE_LOOP_COUNT[i - 1];
if bit == 1 || bit == -1 {
for (p, coeffs) in pairs.iter_mut() {
Bn::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}
}
}
f
})
.product::<<Bn<Self> as Pairing>::TargetField>();
}
f
});

if Self::X_IS_NEGATIVE {
f.cyclotomic_inverse_in_place();
Expand Down
87 changes: 40 additions & 47 deletions ec/src/models/bw6/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::{
models::{short_weierstrass::SWCurveConfig, CurveConfig},
models::{
parallel_pairing_utils::threshold_chunked_loop, short_weierstrass::SWCurveConfig,
CurveConfig,
},
pairing::{MillerLoopOutput, Pairing, PairingOutput},
};
use ark_ff::{
Expand All @@ -10,16 +13,12 @@ use ark_ff::{
},
BitIteratorBE, CyclotomicMultSubgroup,
};
use ark_std::cfg_chunks_mut;
use educe::Educe;
use itertools::Itertools;
use num_traits::One;

use ark_std::{marker::PhantomData, vec::*};

#[cfg(feature = "parallel")]
use rayon::prelude::*;

pub enum TwistType {
M,
D,
Expand Down Expand Up @@ -102,23 +101,21 @@ pub trait BW6Config: 'static + Eq + Sized {
.unzip::<_, _, Vec<_>, Vec<_>>();

// compute f_u which we can later re-use for the 2nd loop
let mut f_u = cfg_chunks_mut!(pairs_1, 4)
.map(|pairs| {
let mut f = <BW6<Self> as Pairing>::TargetField::one();
for i in BitIteratorBE::without_leading_zeros(Self::ATE_LOOP_COUNT_1).skip(1) {
f.square_in_place();
let mut f_u = threshold_chunked_loop(&mut pairs_1, |pairs| {
let mut f = <BW6<Self> as Pairing>::TargetField::one();
for i in BitIteratorBE::without_leading_zeros(Self::ATE_LOOP_COUNT_1).skip(1) {
f.square_in_place();
for (p, coeffs) in pairs.iter_mut() {
BW6::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}
if i {
for (p, coeffs) in pairs.iter_mut() {
BW6::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}
if i {
for (p, coeffs) in pairs.iter_mut() {
BW6::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}
}
}
f
})
.product::<<BW6<Self> as Pairing>::TargetField>();
}
f
});

let f_u_inv;

Expand All @@ -130,40 +127,36 @@ pub trait BW6Config: 'static + Eq + Sized {
}

// f_1(P) = f_(u+1)(P) = f_u(P) * l([u]q, q)(P)
let mut f_1 = cfg_chunks_mut!(pairs_1, 4)
.map(|pairs| {
pairs.iter_mut().fold(f_u, |mut f, (p, coeffs)| {
BW6::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
f
})
let mut f_1 = threshold_chunked_loop(&mut pairs_1, |pairs| {
pairs.iter_mut().fold(f_u, |mut f, (p, coeffs)| {
BW6::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
f
})
.product::<<BW6<Self> as Pairing>::TargetField>();
});

let mut f_2 = cfg_chunks_mut!(pairs_2, 4)
.map(|pairs| {
let mut f = f_u;
for i in (1..Self::ATE_LOOP_COUNT_2.len()).rev() {
f.square_in_place();
let mut f_2 = threshold_chunked_loop(&mut pairs_2, |pairs| {
let mut f = f_u;
for i in (1..Self::ATE_LOOP_COUNT_2.len()).rev() {
f.square_in_place();

for (p, ref mut coeffs) in pairs.iter_mut() {
BW6::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}
for (p, ref mut coeffs) in pairs.iter_mut() {
BW6::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}

let bit = Self::ATE_LOOP_COUNT_2[i - 1];
if bit == 1 {
f *= &f_u;
} else if bit == -1 {
f *= &f_u_inv;
} else {
continue;
}
for &mut (p, ref mut coeffs) in pairs.iter_mut() {
BW6::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}
let bit = Self::ATE_LOOP_COUNT_2[i - 1];
if bit == 1 {
f *= &f_u;
} else if bit == -1 {
f *= &f_u_inv;
} else {
continue;
}
f
})
.product::<<BW6<Self> as Pairing>::TargetField>();
for &mut (p, ref mut coeffs) in pairs.iter_mut() {
BW6::<Self>::ell(&mut f, &coeffs.next().unwrap(), &p.0);
}
}
f
});

if Self::ATE_LOOP_COUNT_2_IS_NEGATIVE {
f_2.cyclotomic_inverse_in_place();
Expand Down
3 changes: 2 additions & 1 deletion ec/src/models/mnt4/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ pub trait MNT4Config: 'static + Sized {
.zip_eq(b)
.map(|(a, b)| (a.into(), b.into()))
.collect::<Vec<_>>();
let result = ark_std::cfg_into_iter!(pairs)
let result = ark_std::cfg_into_iter!(pairs, 1000)
Copy link
Member

Choose a reason for hiding this comment

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

is there a specific reason for 1000?

Copy link
Member Author

Choose a reason for hiding this comment

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

Just a number I’m trying right now. I think it can be much lower.

.map(|(a, b)| MNT4::ate_miller_loop(&a, &b))
.product();

MillerLoopOutput(result)
}

Expand Down
2 changes: 1 addition & 1 deletion ec/src/models/mnt6/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub trait MNT6Config: 'static + Sized {
.zip_eq(b)
.map(|(a, b)| (a.into(), b.into()))
.collect::<Vec<_>>();
let result = ark_std::cfg_into_iter!(pairs)
let result = ark_std::cfg_into_iter!(pairs, 1000)
.map(|(a, b)| MNT6::ate_miller_loop(&a, &b))
.product();
MillerLoopOutput(result)
Expand Down
2 changes: 2 additions & 0 deletions ec/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ pub mod bw6;
pub mod mnt4;
pub mod mnt6;

mod parallel_pairing_utils;

pub mod double_odd;
pub mod short_weierstrass;
pub mod twisted_edwards;
Expand Down
33 changes: 33 additions & 0 deletions ec/src/models/parallel_pairing_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use ark_std::cfg_chunks_mut;
#[cfg(feature = "parallel")]
use rayon::prelude::*;

/// Executes the function `func` over `data` in parallel if the data length exceeds a threshold,
/// otherwise processes the entire data slice sequentially.
///
/// This is an internal helper function for use in multi-pairing and multi-miller-loop computations.
///
///
/// # Parameters
/// - `data`: A mutable slice of elements to be processed.
/// - `func`: A function that takes mutable chunk of `data` and returns a value of type `R`.
///
/// # Parallelism
/// Uses parallel processing via Rayon if the `parallel` feature is enabled and the data length is greater than 1000.
///
/// # Type Parameters
/// - `T`: The element type of the data slice. Must be `Send`.
/// - `F`: The function type. Must be `Fn(&mut [T]) -> R + Send + Sync`.
/// - `R`: The result type. Must implement `std::iter::Product` and `Send`. In internal usage, is the target field type of the pairing.
pub(super) fn threshold_chunked_loop<T, F, R>(data: &mut [T], func: F) -> R
where
F: Fn(&mut [T]) -> R + Send + Sync,
R: std::iter::Product + Send,

Check failure on line 25 in ec/src/models/parallel_pairing_utils.rs

View workflow job for this annotation

GitHub Actions / Check no_std

failed to resolve: use of unresolved module or unlinked crate `std`
T: Send,
{
if data.len() > 1000 {
cfg_chunks_mut!(data, 32).map(func).product::<R>()
} else {
func(data)
}
}
Loading