Skip to content

Commit

Permalink
Merge pull request #36 from fjarri/uint-traits
Browse files Browse the repository at this point in the history
Transition to `Integer` trait
  • Loading branch information
fjarri authored Dec 28, 2023
2 parents 45152ad + 265696b commit 752bdee
Show file tree
Hide file tree
Showing 11 changed files with 302 additions and 312 deletions.
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Bumped `crypto-bigint` to 0.6.0-pre.5. ([#38])
- Bumped `crypto-bigint` to 0.6.0-pre.6. ([#38])
- Bumped MSRV to 1.73. (#[38])
- `MillerRabin::new()` takes an `Odd`-wrapped integer by value. `random_odd_uint()` returns an `Odd`-wrapped integer. `LucasBase::generate()` takes an `Odd`-wrapped integer. `lucas_test` takes an `Odd`-wrapped integer. (#[38])
- `MillerRabin::new()` takes an `Odd`-wrapped integer. `random_odd_uint()` is renamed to `random_odd_integer()`, takes a `NonZeroU32` for `bit_length`, and returns an `Odd`-wrapped integer. `LucasBase::generate()` takes an `Odd`-wrapped integer. `lucas_test` takes an `Odd`-wrapped integer. (#[38])
- All bit length-type parameters take `u32` instead of `usize`. (#[38])
- All the API is based on the `Integer` trait instead of `Uint` specifically. (#[38])


[#35]: https://github.com/entropyxyz/crypto-primes/pull/38
[#36]: https://github.com/entropyxyz/crypto-primes/pull/36
[#38]: https://github.com/entropyxyz/crypto-primes/pull/38


## [0.5.0] - 2023-08-20
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ categories = ["cryptography", "no-std"]
rust-version = "1.73"

[dependencies]
crypto-bigint = { version = "0.6.0-pre.5", default-features = false, features = ["rand_core"] }
crypto-bigint = { version = "0.6.0-pre.6", default-features = false, features = ["rand_core"] }
rand_core = { version = "0.6.4", default-features = false }
openssl = { version = "0.10.39", optional = true, features = ["vendored"] }
rug = { version = "1.18", default-features = false, features = ["integer"], optional = true }
Expand Down
73 changes: 41 additions & 32 deletions benches/bench.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
use core::num::NonZeroU32;

use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use crypto_bigint::{nlimbs, Odd, Uint, U1024};
use crypto_bigint::{nlimbs, Integer, Odd, RandomBits, Uint, U1024, U128, U256};
use rand_chacha::ChaCha8Rng;
use rand_core::{CryptoRngCore, OsRng, SeedableRng};

#[cfg(feature = "tests-gmp")]
use rug::{integer::Order, Integer};
use rug::{integer::Order, Integer as GmpInteger};

#[cfg(feature = "tests-openssl")]
use openssl::bn::BigNum;

use crypto_primes::{
generate_prime_with_rng, generate_safe_prime_with_rng,
hazmat::{
lucas_test, random_odd_uint, AStarBase, BruteForceBase, LucasCheck, MillerRabin,
lucas_test, random_odd_integer, AStarBase, BruteForceBase, LucasCheck, MillerRabin,
SelfridgeBase, Sieve,
},
is_prime_with_rng, is_safe_prime_with_rng,
Expand All @@ -22,9 +24,16 @@ fn make_rng() -> ChaCha8Rng {
ChaCha8Rng::from_seed(*b"01234567890123456789012345678901")
}

fn make_sieve<const L: usize>(rng: &mut impl CryptoRngCore) -> Sieve<L> {
let start = random_odd_uint::<L>(rng, Uint::<L>::BITS);
Sieve::new(&start, Uint::<L>::BITS, false)
fn random_odd_uint<T: RandomBits + Integer>(
rng: &mut impl CryptoRngCore,
bit_length: u32,
) -> Odd<T> {
random_odd_integer::<T>(rng, NonZeroU32::new(bit_length).unwrap())
}

fn make_sieve<const L: usize>(rng: &mut impl CryptoRngCore) -> Sieve<Uint<L>> {
let start = random_odd_uint::<Uint<L>>(rng, Uint::<L>::BITS);
Sieve::new(&start, NonZeroU32::new(Uint::<L>::BITS).unwrap(), false)
}

fn make_presieved_num<const L: usize>(rng: &mut impl CryptoRngCore) -> Odd<Uint<L>> {
Expand All @@ -36,13 +45,13 @@ fn bench_sieve(c: &mut Criterion) {
let mut group = c.benchmark_group("Sieve");

group.bench_function("(U128) random start", |b| {
b.iter(|| random_odd_uint::<{ nlimbs!(128) }>(&mut OsRng, 128))
b.iter(|| random_odd_uint::<U128>(&mut OsRng, 128))
});

group.bench_function("(U128) creation", |b| {
b.iter_batched(
|| random_odd_uint::<{ nlimbs!(128) }>(&mut OsRng, 128),
|start| Sieve::new(&start, 128, false),
|| random_odd_uint::<U128>(&mut OsRng, 128),
|start| Sieve::new(start.as_ref(), NonZeroU32::new(128).unwrap(), false),
BatchSize::SmallInput,
)
});
Expand All @@ -57,13 +66,13 @@ fn bench_sieve(c: &mut Criterion) {
});

group.bench_function("(U1024) random start", |b| {
b.iter(|| random_odd_uint::<{ nlimbs!(1024) }>(&mut OsRng, 1024))
b.iter(|| random_odd_uint::<U1024>(&mut OsRng, 1024))
});

group.bench_function("(U1024) creation", |b| {
b.iter_batched(
|| random_odd_uint::<{ nlimbs!(1024) }>(&mut OsRng, 1024),
|start| Sieve::new(&start, 1024, false),
|| random_odd_uint::<U1024>(&mut OsRng, 1024),
|start| Sieve::new(start.as_ref(), NonZeroU32::new(1024).unwrap(), false),
BatchSize::SmallInput,
)
});
Expand All @@ -84,31 +93,31 @@ fn bench_miller_rabin(c: &mut Criterion) {

group.bench_function("(U128) creation", |b| {
b.iter_batched(
|| random_odd_uint::<{ nlimbs!(128) }>(&mut OsRng, 128),
MillerRabin::new,
|| random_odd_uint::<U128>(&mut OsRng, 128),
|n| MillerRabin::new(&n),
BatchSize::SmallInput,
)
});

group.bench_function("(U128) random base test (pre-sieved)", |b| {
b.iter_batched(
|| MillerRabin::new(make_presieved_num::<{ nlimbs!(128) }>(&mut OsRng)),
|| MillerRabin::new(&make_presieved_num::<{ nlimbs!(128) }>(&mut OsRng)),
|mr| mr.test_random_base(&mut OsRng),
BatchSize::SmallInput,
)
});

group.bench_function("(U1024) creation", |b| {
b.iter_batched(
|| random_odd_uint::<{ nlimbs!(1024) }>(&mut OsRng, 1024),
MillerRabin::new,
|| random_odd_uint::<U1024>(&mut OsRng, 1024),
|n| MillerRabin::new(&n),
BatchSize::SmallInput,
)
});

group.bench_function("(U1024) random base test (pre-sieved)", |b| {
b.iter_batched(
|| MillerRabin::new(make_presieved_num::<{ nlimbs!(1024) }>(&mut OsRng)),
|| MillerRabin::new(&make_presieved_num::<{ nlimbs!(1024) }>(&mut OsRng)),
|mr| mr.test_random_base(&mut OsRng),
BatchSize::SmallInput,
)
Expand Down Expand Up @@ -193,39 +202,39 @@ fn bench_presets(c: &mut Criterion) {

group.bench_function("(U128) Prime test", |b| {
b.iter_batched(
|| random_odd_uint::<{ nlimbs!(128) }>(&mut OsRng, 128),
|num| is_prime_with_rng(&mut OsRng, &num),
|| random_odd_uint::<U128>(&mut OsRng, 128),
|num| is_prime_with_rng(&mut OsRng, num.as_ref()),
BatchSize::SmallInput,
)
});

group.bench_function("(U128) Safe prime test", |b| {
b.iter_batched(
|| random_odd_uint::<{ nlimbs!(128) }>(&mut OsRng, 128),
|num| is_safe_prime_with_rng(&mut OsRng, &num),
|| random_odd_uint::<U128>(&mut OsRng, 128),
|num| is_safe_prime_with_rng(&mut OsRng, num.as_ref()),
BatchSize::SmallInput,
)
});

let mut rng = make_rng();
group.bench_function("(U128) Random prime", |b| {
b.iter(|| generate_prime_with_rng::<{ nlimbs!(128) }>(&mut rng, None))
b.iter(|| generate_prime_with_rng::<U128>(&mut rng, 128))
});

let mut rng = make_rng();
group.bench_function("(U1024) Random prime", |b| {
b.iter(|| generate_prime_with_rng::<{ nlimbs!(1024) }>(&mut rng, None))
b.iter(|| generate_prime_with_rng::<U1024>(&mut rng, 1024))
});

let mut rng = make_rng();
group.bench_function("(U128) Random safe prime", |b| {
b.iter(|| generate_safe_prime_with_rng::<{ nlimbs!(128) }>(&mut rng, None))
b.iter(|| generate_safe_prime_with_rng::<U128>(&mut rng, 128))
});

group.sample_size(20);
let mut rng = make_rng();
group.bench_function("(U1024) Random safe prime", |b| {
b.iter(|| generate_safe_prime_with_rng::<{ nlimbs!(1024) }>(&mut rng, None))
b.iter(|| generate_safe_prime_with_rng::<U1024>(&mut rng, 1024))
});

group.finish();
Expand All @@ -235,19 +244,19 @@ fn bench_presets(c: &mut Criterion) {

let mut rng = make_rng();
group.bench_function("(U128) Random safe prime", |b| {
b.iter(|| generate_safe_prime_with_rng::<{ nlimbs!(128) }>(&mut rng, None))
b.iter(|| generate_safe_prime_with_rng::<U128>(&mut rng, 128))
});

// The performance should scale with the prime size, not with the Uint size.
// So we should strive for this test's result to be as close as possible
// to that of the previous one and as far away as possible from the next one.
group.bench_function("(U256) Random 128 bit safe prime", |b| {
b.iter(|| generate_safe_prime_with_rng::<{ nlimbs!(256) }>(&mut rng, Some(128)))
b.iter(|| generate_safe_prime_with_rng::<U256>(&mut rng, 128))
});

// The upper bound for the previous test.
group.bench_function("(U256) Random 256 bit safe prime", |b| {
b.iter(|| generate_safe_prime_with_rng::<{ nlimbs!(256) }>(&mut rng, None))
b.iter(|| generate_safe_prime_with_rng::<U256>(&mut rng, 256))
});

group.finish();
Expand All @@ -257,9 +266,9 @@ fn bench_presets(c: &mut Criterion) {
fn bench_gmp(c: &mut Criterion) {
let mut group = c.benchmark_group("GMP");

fn random<const L: usize>(rng: &mut impl CryptoRngCore) -> Integer {
let num = random_odd_uint::<L>(rng, Uint::<L>::BITS);
Integer::from_digits(num.as_words(), Order::Lsf)
fn random<const L: usize>(rng: &mut impl CryptoRngCore) -> GmpInteger {
let num = random_odd_uint::<Uint<L>>(rng, Uint::<L>::BITS).get();
GmpInteger::from_digits(num.as_words(), Order::Lsf)
}

group.bench_function("(U128) Random prime", |b| {
Expand Down
2 changes: 1 addition & 1 deletion src/hazmat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ mod sieve;

pub use lucas::{lucas_test, AStarBase, BruteForceBase, LucasBase, LucasCheck, SelfridgeBase};
pub use miller_rabin::MillerRabin;
pub use sieve::{random_odd_uint, Sieve};
pub use sieve::{random_odd_integer, Sieve};

/// Possible results of various primality tests.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
Expand Down
8 changes: 4 additions & 4 deletions src/hazmat/gcd.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use crypto_bigint::{Limb, NonZero, Uint, Word};
use crypto_bigint::{Integer, Limb, NonZero, Word};

/// Calculates the greatest common divisor of `n` and `m`.
/// By definition, `gcd(0, m) == m`.
/// `n` must be non-zero.
pub(crate) fn gcd_vartime<const L: usize>(n: &Uint<L>, m: Word) -> Word {
pub(crate) fn gcd_vartime<T: Integer>(n: &T, m: Word) -> Word {
// This is an internal function, and it will never be called with `m = 0`.
// Allowing `m = 0` would require us to have the return type of `Uint<L>`
// (since `gcd(n, 0) = n`).
debug_assert!(m != 0);

// This we can check since it doesn't affect the return type,
// even though `n` will not be 0 either in the application.
if n == &Uint::<L>::ZERO {
if n.is_zero().into() {
return m;
}

Expand All @@ -23,7 +23,7 @@ pub(crate) fn gcd_vartime<const L: usize>(n: &Uint<L>, m: Word) -> Word {
} else {
// In this branch `n` is `Word::BITS` bits or shorter,
// so we can safely take the first limb.
let n = n.as_words()[0];
let n = n.as_ref()[0].0;
if n > m {
(n, m)
} else {
Expand Down
Loading

0 comments on commit 752bdee

Please sign in to comment.