Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
15 changes: 15 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ serde = { version = "1", default-features = false, optional = true }
zeroize = { version = "1", default-features = false, optional = true }

[dev-dependencies]
crypto-primitives = { workspace = true, features = ["crypto_bigint"] }
criterion = { workspace = true }
proptest = { workspace = true }
rand = { workspace = true, features = ["std_rng"] }

Expand All @@ -47,6 +49,17 @@ ark_ff = ["ark_std", "num_bigint", "zeroize", "dep:ark-ff", "dep:ark-serialize"]
crypto_bigint = ["dep:crypto-bigint", "crypto-bigint/alloc"]
num_bigint = ["dep:num-bigint"]

[[bench]]
name = "boxed_monty_field_benches"
harness = false

[[bench]]
name = "const_monty_field_benches"
harness = false

[[bench]]
name = "monty_field_benches"
harness = false

#
# Workspace configuration
Expand All @@ -64,10 +77,12 @@ license = "Apache-2.0"
publish = false

[workspace.dependencies]
crypto-primitives = { path = "." }
crypto-primitives-proc-macros = { path = "proc-macros" }
num-traits = { version = "0.2", default-features = false }
proptest = { version = "1", default-features = false, features = ["alloc"] }
rand = { version = "0.10.0-rc.1", default-features = false }
criterion = "0.7.0"

[workspace.lints.rust]
missing_docs = "allow" # FIXME
Expand Down
27 changes: 27 additions & 0 deletions benches/boxed_monty_field_benches.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![allow(non_local_definitions)]
#![allow(clippy::eq_op)]

mod field_ops_bench_common;

use criterion::{Criterion, criterion_group, criterion_main};
use crypto_bigint::{Odd, modular::BoxedMontyParams};
use crypto_primitives::crypto_bigint_boxed_monty::BoxedMontyField;

use crate::field_ops_bench_common::field_benchmarks;

fn bench_config() -> BoxedMontyParams {
let modulus = crypto_bigint::BoxedUint::from_be_hex(
"0000000000000000000000000000000000860995AE68FC80E1B1BD1E39D54B33",
256,
)
.unwrap();
let modulus = Odd::new(modulus).expect("modulus should be odd");
BoxedMontyParams::new(modulus)
}

pub fn boxed_monty_benches(c: &mut Criterion) {
field_benchmarks::<BoxedMontyField>(c, "Boxed Monty Field Arithmetic", &bench_config());
}

criterion_group!(benches, boxed_monty_benches);
criterion_main!(benches);
23 changes: 23 additions & 0 deletions benches/const_monty_field_benches.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#![allow(non_local_definitions)]
#![allow(clippy::eq_op)]

mod field_ops_bench_common;

use criterion::{Criterion, criterion_group, criterion_main};
use crypto_bigint::{U256, const_monty_params};
use crypto_primitives::crypto_bigint_const_monty::ConstMontyField;

use crate::field_ops_bench_common::field_benchmarks;

const_monty_params!(
Params,
U256,
"0000000000000000000000000000000000860995AE68FC80E1B1BD1E39D54B33"
);

pub fn const_monty_benches(c: &mut Criterion) {
field_benchmarks::<ConstMontyField<Params, _>>(c, "Const Monty Field Arithmetic", &());
}

criterion_group!(benches, const_monty_benches);
criterion_main!(benches);
240 changes: 240 additions & 0 deletions benches/field_ops_bench_common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
#![allow(non_local_definitions)]
#![allow(clippy::eq_op)]

use std::{
hint::black_box,
ops::{Add, Div, Mul},
};

use criterion::{AxisScale, BatchSize, BenchmarkId, Criterion, PlotConfiguration};
use crypto_primitives::FromPrimitiveWithConfig;

fn bench_random_field<F: FromPrimitiveWithConfig>(
group: &mut criterion::BenchmarkGroup<criterion::measurement::WallTime>,
num: u64,
config: &F::Config,
) where
for<'a> &'a F: Add<&'a F>,
for<'a> &'a F: Mul<&'a F>,
for<'a> &'a F: Div<&'a F>,
{
let field_elem = F::from_with_cfg(num, config);
let param = format!("Param = {}", num);

group.bench_with_input(
BenchmarkId::new("Mul owned by owned", &param),
&field_elem,
|b, unop_elem| {
b.iter_batched(
|| {
(
vec![unop_elem.clone(); 10000],
vec![unop_elem.clone(); 10000],
)
},
|(lhs, rhs)| {
for (lhs, rhs) in lhs.into_iter().zip(rhs.into_iter()) {
let _ = black_box(lhs * rhs);
}
},
BatchSize::SmallInput,
);
},
);

group.bench_with_input(
BenchmarkId::new("Mul owned by ref", &param),
&field_elem,
|b, unop_elem| {
b.iter_batched(
|| {
(
vec![unop_elem.clone(); 10000],
vec![unop_elem.clone(); 10000],
)
},
|(lhs, rhs)| {
for (lhs, rhs) in lhs.into_iter().zip(rhs.into_iter()) {
let _ = black_box(lhs * &rhs);
}
},
BatchSize::SmallInput,
);
},
);

group.bench_with_input(
BenchmarkId::new("Mul ref by ref", &param),
&field_elem,
|b, unop_elem| {
b.iter(|| {
for _ in 0..10000 {
let _ = black_box(unop_elem * unop_elem);
}
});
},
);

group.bench_with_input(
BenchmarkId::new("Add owned to owned", &param),
&field_elem,
|b, unop_elem| {
b.iter_batched(
|| {
(
vec![unop_elem.clone(); 10000],
vec![unop_elem.clone(); 10000],
)
},
|(lhs, rhs)| {
for (lhs, rhs) in lhs.into_iter().zip(rhs.into_iter()) {
let _ = black_box(lhs + rhs);
}
},
BatchSize::SmallInput,
);
},
);

group.bench_with_input(
BenchmarkId::new("Add owned to ref", &param),
&field_elem,
|b, unop_elem| {
b.iter_batched(
|| {
(
vec![unop_elem.clone(); 10000],
vec![unop_elem.clone(); 10000],
)
},
|(lhs, rhs)| {
for (lhs, rhs) in lhs.into_iter().zip(rhs.into_iter()) {
let _ = black_box(lhs + &rhs);
}
},
BatchSize::SmallInput,
);
},
);

group.bench_with_input(
BenchmarkId::new("Add ref to ref", &param),
&field_elem,
|b, unop_elem| {
b.iter(|| {
for _ in 0..10000 {
let _ = black_box(unop_elem + unop_elem);
}
});
},
);

group.bench_with_input(
BenchmarkId::new("Div owned by owned", &param),
&field_elem,
|b, unop_elem| {
b.iter_batched(
|| {
(
vec![unop_elem.clone(); 10000],
vec![unop_elem.clone(); 10000],
)
},
|(lhs, rhs)| {
for (lhs, rhs) in lhs.into_iter().zip(rhs.into_iter()) {
let _ = black_box(lhs / rhs);
}
},
BatchSize::SmallInput,
);
},
);

group.bench_with_input(
BenchmarkId::new("Div owned by ref", &param),
&field_elem,
|b, unop_elem| {
b.iter_batched(
|| {
(
vec![unop_elem.clone(); 10000],
vec![unop_elem.clone(); 10000],
)
},
|(lhs, rhs)| {
for (lhs, rhs) in lhs.into_iter().zip(rhs.into_iter()) {
let _ = black_box(lhs / &rhs);
}
},
BatchSize::SmallInput,
);
},
);

group.bench_with_input(
BenchmarkId::new("Div ref by ref", &param),
&field_elem,
|b, unop_elem| {
b.iter(|| {
for _ in 0..10000 {
let _ = black_box(unop_elem / unop_elem);
}
});
},
);

group.bench_with_input(
BenchmarkId::new("Negation", &param),
&field_elem,
|b, unop_elem| {
b.iter_batched(
|| vec![unop_elem.clone(); 10000],
|unop_elem| {
for x in unop_elem.into_iter() {
let _ = black_box(-x);
}
},
BatchSize::SmallInput,
);
},
);

let v = vec![field_elem; 10];

group.bench_with_input(BenchmarkId::new("Sum", &param), &v, |b, v| {
b.iter(|| {
for _ in 0..10000 {
let _ = black_box(F::sum(v.iter()));
}
});
});

group.bench_with_input(BenchmarkId::new("Product", &param), &v, |b, v| {
b.iter(|| {
for _ in 0..10000 {
let _ = black_box(F::product(v.iter()));
}
});
});
}

pub fn field_benchmarks<F: FromPrimitiveWithConfig>(
c: &mut Criterion,
name: &str,
config: &F::Config,
) where
for<'a> &'a F: Add<&'a F>,
for<'a> &'a F: Mul<&'a F>,
for<'a> &'a F: Div<&'a F>,
{
let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic);

let mut group = c.benchmark_group(name);
group.plot_config(plot_config);

bench_random_field::<F>(&mut group, 695962179703_u64, config);
bench_random_field::<F>(&mut group, 2345695962179703_u64, config);
bench_random_field::<F>(&mut group, 111111111111111111_u64, config);
bench_random_field::<F>(&mut group, 12345678124578658568_u64, config);
group.finish();
}
27 changes: 27 additions & 0 deletions benches/monty_field_benches.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![allow(non_local_definitions)]
#![allow(clippy::eq_op)]

mod field_ops_bench_common;

use criterion::{Criterion, criterion_group, criterion_main};
use crypto_bigint::{Odd, modular::MontyParams};
use crypto_primitives::crypto_bigint_monty::MontyField;

use crate::field_ops_bench_common::field_benchmarks;

const LIMBS: usize = 4;

fn bench_config() -> MontyParams<LIMBS> {
let modulus = crypto_bigint::Uint::<LIMBS>::from_be_hex(
"0000000000000000000000000000000000860995AE68FC80E1B1BD1E39D54B33",
);
let modulus = Odd::new(modulus).expect("modulus should be odd");
MontyParams::new(modulus)
}

fn monty_field_benches(c: &mut Criterion) {
field_benchmarks::<MontyField<_>>(c, "Monty Field Arithmetic", &bench_config());
}

criterion_group!(benches, monty_field_benches);
criterion_main!(benches);
23 changes: 10 additions & 13 deletions src/field/crypto_bigint_boxed_monty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,15 @@ impl Inv for BoxedMontyField {
type Output = Option<Self>;

fn inv(self) -> Self::Output {
let result = self.0.invert_vartime();
if result.is_some().into() {
Some(Self(result.unwrap()))
} else {
None
}
Some(Self(Option::from(self.0.invert_vartime())?))
}
}

impl Inv for &BoxedMontyField {
type Output = Option<BoxedMontyField>;

fn inv(self) -> Self::Output {
Some(BoxedMontyField(Option::from(self.0.invert_vartime())?))
}
}

Expand All @@ -180,13 +183,7 @@ impl Inv for BoxedMontyField {
impl CheckedDiv for BoxedMontyField {
#[allow(clippy::arithmetic_side_effects)] // False alert
fn checked_div(&self, rhs: &Self) -> Option<Self> {
let inv = rhs.0.invert();
if inv.is_none().into() {
return None; // Division by zero
}
// Safe to unwrap since we checked for None above
let inv = inv.unwrap();
Some(Self(BoxedMontyForm::mul(&self.0, &inv)))
Some(self * rhs.inv()?)
}
}

Expand Down
Loading