Add more benchmarks

This commit is contained in:
Jacob Zhong
2022-04-18 10:30:23 -04:00
parent c1e530eeda
commit 46ea4af775
4 changed files with 176 additions and 7 deletions
+1
View File
@@ -18,6 +18,7 @@ num-primes = { version = "0.3.0", optional = true }
primal-check = "0.3.1"
number-theory = "0.0.6"
is_prime = "2.0.7"
glass_pumpkin = "1.2.0"
[features]
default = ["num-primes"]
+152 -1
View File
@@ -1,11 +1,15 @@
#[macro_use]
extern crate criterion;
use std::iter::repeat_with;
use criterion::{Criterion, SamplingMode};
use num_bigint::RandBigInt;
use num_prime::{nt_funcs, RandPrime};
#[cfg(feature = "num-primes")]
use num_primes::{Generator, Verification};
use primal_check::miller_rabin;
use number_theory::NumberTheory;
use glass_pumpkin::{prime as gprime, safe_prime as safe_gprime};
pub fn bench_is_prime(c: &mut Criterion) {
const N0: u64 = 1_000_000;
@@ -17,7 +21,7 @@ pub fn bench_is_prime(c: &mut Criterion) {
.step_by(STEP)
.chain((N1..N2).step_by(STEP));
let mut group = c.benchmark_group("is_prime (u64)");
let mut group = c.benchmark_group("primality check (u64)");
group.bench_function("num-prime (this crate)", |b| {
b.iter(|| {
@@ -34,6 +38,13 @@ pub fn bench_is_prime(c: &mut Criterion) {
.count()
})
});
group.bench_function("glass_pumpkin", |b| {
b.iter(|| {
numbers()
.filter(|&n| gprime::check(&n.into()))
.count()
})
});
group.bench_function("primal-check", |b| {
b.iter(|| {
numbers()
@@ -52,6 +63,140 @@ pub fn bench_is_prime(c: &mut Criterion) {
// we can add a markdown of performance after figuring out this
group.finish();
////// 256 bits Bigint /////
let mut rng = rand::thread_rng();
let numbers: Vec<_> = repeat_with(|| rng.gen_biguint(256)).take(32).collect();
let mut group = c.benchmark_group("primality check (u256)");
group.bench_function("num-prime (this crate)", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| nt_funcs::is_prime(n, None).probably())
.count()
})
});
group.bench_function("num-primes", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| Verification::is_prime(&num_primes::BigUint::from_bytes_le(&n.to_bytes_le())))
.count()
})
});
group.bench_function("glass_pumpkin", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| gprime::check(n))
.count()
})
});
group.bench_function("glass_pumpkin (BPSW)", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| gprime::strong_check(n))
.count()
})
});
group.finish();
let mut group = c.benchmark_group("safe primality check (u256)");
group.bench_function("num-prime (this crate)", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| nt_funcs::is_safe_prime(n).probably())
.count()
})
});
group.bench_function("num-primes", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| Verification::is_safe_prime(&num_primes::BigUint::from_bytes_le(&n.to_bytes_le())))
.count()
})
});
group.bench_function("glass_pumpkin", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| safe_gprime::check(n))
.count()
})
});
group.bench_function("glass_pumpkin (BPSW)", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| safe_gprime::strong_check(n))
.count()
})
});
group.finish();
////// 2048 bits Bigint /////
let mut rng = rand::thread_rng();
let numbers: Vec<_> = repeat_with(|| rng.gen_biguint(2048)).take(8).collect();
let mut group = c.benchmark_group("primality check (u2048)");
group.bench_function("num-prime (this crate)", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| nt_funcs::is_prime(n, None).probably())
.count()
})
});
group.bench_function("num-primes", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| Verification::is_prime(&num_primes::BigUint::from_bytes_le(&n.to_bytes_le())))
.count()
})
});
group.bench_function("glass_pumpkin", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| gprime::check(n))
.count()
})
});
group.bench_function("glass_pumpkin (BPSW)", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| gprime::strong_check(n))
.count()
})
});
group.finish();
let mut group = c.benchmark_group("safe primality check (u2048)");
group.bench_function("num-prime (this crate)", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| nt_funcs::is_safe_prime(n).probably())
.count()
})
});
group.bench_function("num-primes", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| Verification::is_safe_prime(&num_primes::BigUint::from_bytes_le(&n.to_bytes_le())))
.count()
})
});
group.bench_function("glass_pumpkin", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| safe_gprime::check(n))
.count()
})
});
group.bench_function("glass_pumpkin (BPSW)", |b| {
b.iter(|| {
numbers.iter()
.filter(|&n| safe_gprime::strong_check(n))
.count()
})
});
group.finish();
}
pub fn bench_factorization(c: &mut Criterion) {
@@ -94,6 +239,9 @@ pub fn bench_prime_gen(c: &mut Criterion) {
group.bench_function("num-primes", |b| {
b.iter(|| Generator::new_prime(256))
});
group.bench_function("glass_pumpkin", |b| {
b.iter(|| gprime::from_rng(256, &mut gen))
});
group.finish();
let mut group = c.benchmark_group("safe prime generation (256 bits)");
@@ -106,6 +254,9 @@ pub fn bench_prime_gen(c: &mut Criterion) {
group.bench_function("num-primes", |b| {
b.iter(|| Generator::safe_prime(256))
});
group.bench_function("glass_pumpkin", |b| {
b.iter(|| safe_gprime::from_rng(256, &mut gen))
});
group.finish();
}
+20 -6
View File
@@ -553,6 +553,8 @@ where
{
let buf = NaiveBuffer::new();
let config = Some(PrimalityTestConfig::strict());
// TODO: use miller-rabin for large numbers (more than 256 bits?), as BPSW could be too slow
// the NIST recommends 5 rounds for 512 and 1024 bits. For 1536 bits, the recommendation is 4 rounds.
// test (n-1)/2 first since its smaller
let sophie_p = buf.is_prime(&(target >> 1), config);
@@ -712,7 +714,7 @@ macro_rules! impl_randprime_prim {
panic!("The given bit size limit exceeded the capacity of the integer type!")
}
let t: $T = self.gen();
let t = t >> (<$T>::BITS - bit_size as u32);
let t = (t >> (<$T>::BITS - bit_size as u32)) | 1; // filter even numbers
if is_prime64(t as u64) {
t
} else {
@@ -755,7 +757,7 @@ impl<R: Rng> RandPrime<u128> for R {
panic!("The given bit size limit exceeded the capacity of the integer type!")
}
let t: u128 = self.gen();
let t = t >> (u128::BITS - bit_size as u32);
let t = (t >> (u128::BITS - bit_size as u32)) | 1; // filter even numbers
if is_prime(&t, config).probably() {
t
} else {
@@ -783,11 +785,11 @@ impl<R: Rng> RandPrime<u128> for R {
}
}
#[cfg(feature = "big-int")]
#[cfg(feature = "num-bigint")]
impl<R: Rng> RandPrime<BigUint> for R {
#[inline]
fn gen_prime(&mut self, bit_size: usize, config: Option<PrimalityTestConfig>) -> BigUint {
let t = self.gen_biguint(bit_size as u64);
let t = self.gen_biguint(bit_size as u64) | BigUint::from(1u8); // filter even numbers
if is_prime(&t, config).probably() {
t
} else {
@@ -967,6 +969,18 @@ mod tests {
}
}
#[test]
#[cfg(feature = "big-int")]
fn is_prime_test() {
#[cfg(feature = "num-bigint")]
{
use num_bigint::BigUint;
// https://github.com/AtropineTears/num-primes/issues/1#issuecomment-934629597
let p = BigUint::parse_bytes(b"169511182982703321453314585423962898651587669459838234386506572286328885534468792292646838949809616446341407457141008401355628947670484184607678853094537849610289912805960069455687743151708433319901176932959509872662610091644590437761688516626993416011399330087939042347256922771590903190536793274742859624657", 10).unwrap();
assert!(is_prime(&p, None).probably());
}
}
#[test]
fn is_safe_prime_test() {
// OEIS:A005385
@@ -1181,12 +1195,12 @@ mod tests {
let p: u128 = rng.gen_safe_prime(128);
assert!(is_safe_prime(&p).probably());
#[cfg(feature = "big-int")]
#[cfg(feature = "num-bigint")]
{
let p: BigUint = rng.gen_prime(512, None);
assert!(is_prime(&p, None).probably());
let p: BigUint = rng.gen_safe_prime(192);
assert!(is_prime(&p, None).probably());
assert!(is_safe_prime(&p).probably());
}
// test bit size limit
+3
View File
@@ -33,6 +33,7 @@ pub enum Primality {
impl Primality {
/// Check whether the resule indicates that the number is
/// (very) probably a prime. Return false only on [Primality::No]
#[inline(always)]
pub fn probably(self) -> bool {
match self {
Primality::No => false,
@@ -276,4 +277,6 @@ pub trait RandPrime<T> {
/// Generate a random (Sophie German) safe prime within the given bit size limit. The generated prime
/// is guaranteed to pass the [is_safe_prime][crate::nt_funcs::is_safe_prime] test
fn gen_safe_prime(&mut self, bit_size: usize) -> T;
// TODO: add gen_prime_exact and gen_safe_prime_exact for generating primes with exact this bit size
}