Skip to content

Commit

Permalink
Merge pull request #38 from fjarri/update-crypto-bigint
Browse files Browse the repository at this point in the history
Bump `crypto-bigint` to 0.6.0-pre.5
  • Loading branch information
fjarri authored Dec 24, 2023
2 parents 2379c91 + 685a6ee commit 45152ad
Show file tree
Hide file tree
Showing 12 changed files with 429 additions and 307 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/crypto-primes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
strategy:
matrix:
rust:
- 1.65.0 # MSRV
- 1.73.0 # MSRV
- stable
target:
- wasm32-unknown-unknown
Expand Down Expand Up @@ -134,6 +134,6 @@ jobs:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.65.0
toolchain: 1.73.0
profile: minimal
- run: cargo build --all-features --benches
11 changes: 7 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [0.5.1] - Unreleased
## [0.6.0-pre.0] - Unreleased

### Fixed
### Changed

- Bumped `crypto-bigint` to 0.5.4. ([#35])
- Bumped `crypto-bigint` to 0.6.0-pre.5. ([#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])
- All bit length-type parameters take `u32` instead of `usize`. (#[38])


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


## [0.5.0] - 2023-08-20
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
[package]
name = "crypto-primes"
version = "0.5.0"
version = "0.6.0-pre.0"
edition = "2021"
license = "Apache-2.0 OR MIT"
description = "Random prime number generation and primality checking library"
repository = "https://github.com/entropyxyz/crypto-primes"
readme = "README.md"
categories = ["cryptography", "no-std"]
rust-version = "1.65"
rust-version = "1.73"

[dependencies]
crypto-bigint = { version = "0.5.4", default-features = false, features = ["rand_core"] }
crypto-bigint = { version = "0.6.0-pre.5", 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
23 changes: 12 additions & 11 deletions benches/bench.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use crypto_bigint::{nlimbs, Uint, U1024};
use crypto_bigint::{nlimbs, Odd, Uint, U1024};
use rand_chacha::ChaCha8Rng;
use rand_core::{CryptoRngCore, OsRng, SeedableRng};

Expand All @@ -23,13 +23,13 @@ fn make_rng() -> ChaCha8Rng {
}

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

fn make_presieved_num<const L: usize>(rng: &mut impl CryptoRngCore) -> Uint<L> {
fn make_presieved_num<const L: usize>(rng: &mut impl CryptoRngCore) -> Odd<Uint<L>> {
let mut sieve = make_sieve(rng);
sieve.next().unwrap()
Odd::new(sieve.next().unwrap()).unwrap()
}

fn bench_sieve(c: &mut Criterion) {
Expand Down Expand Up @@ -85,14 +85,14 @@ fn bench_miller_rabin(c: &mut Criterion) {
group.bench_function("(U128) creation", |b| {
b.iter_batched(
|| random_odd_uint::<{ nlimbs!(128) }>(&mut OsRng, 128),
|start| MillerRabin::new(&start),
MillerRabin::new,
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,
)
Expand All @@ -101,14 +101,14 @@ fn bench_miller_rabin(c: &mut Criterion) {
group.bench_function("(U1024) creation", |b| {
b.iter_batched(
|| random_odd_uint::<{ nlimbs!(1024) }>(&mut OsRng, 1024),
|start| MillerRabin::new(&start),
MillerRabin::new,
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 @@ -171,12 +171,13 @@ fn bench_lucas(c: &mut Criterion) {
// - V_{d * 2^t} checked for t == 0..s-1, but no V = 0 found
// - s = 5, so the previous step has multiple checks
// - Q != 1 (since we're using Selfridge base)
let slow_path = U1024::from_be_hex(concat![
let slow_path = Odd::new(U1024::from_be_hex(concat![
"D1CB9F1B6F3414A4B40A7E51C53C6AE4689DFCDC49FF875E7066A229D704EA8E",
"6B674231D8C5974001673C3CE7FF9D377C8564E5182165A23434BC7B7E6C0419",
"FD25C9921B0E9C90AF2570DB0772E1A9C82ACABBC8FC0F0864CE8A12124FA29B",
"7F870924041DFA13EE5F5541C1BF96CA679EFAE2C96F5F4E9DF6007185198F5F"
]);
]))
.unwrap();

group.bench_function("(U1024) Selfridge base, strong check, slow path", |b| {
b.iter(|| {
Expand Down Expand Up @@ -257,7 +258,7 @@ 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: Uint<L> = random_odd_uint(rng, Uint::<L>::BITS);
let num = random_odd_uint::<L>(rng, Uint::<L>::BITS);
Integer::from_digits(num.as_words(), Order::Lsf)
}

Expand Down
39 changes: 20 additions & 19 deletions src/hazmat/gcd.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crypto_bigint::{Limb, NonZero, Uint};
use crypto_bigint::{Limb, NonZero, Uint, 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<const L: usize>(n: &Uint<L>, m: u32) -> u32 {
pub(crate) fn gcd_vartime<const L: usize>(n: &Uint<L>, 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`).
Expand All @@ -16,16 +16,14 @@ pub(crate) fn gcd<const L: usize>(n: &Uint<L>, m: u32) -> u32 {
}

// Normalize input: the resulting (a, b) are both small, a >= b, and b != 0.
let (mut a, mut b): (u32, u32) = if n.bits() > (u32::BITS as usize) {
let (mut a, mut b): (Word, Word) = if n.bits() > Word::BITS {
// `m` is non-zero, so we can unwrap.
let (_quo, n) = n.div_rem_limb(NonZero::new(Limb::from(m)).unwrap());
// `n` is a remainder of a division by `u32`, so it can be safely cast to `u32`.
let b: u32 = n.0.try_into().unwrap();
(m, b)
let r = n.rem_limb(NonZero::new(Limb::from(m)).expect("divisor should be non-zero here"));
(m, r.0)
} else {
// In this branch `n` is 32 bits or shorter,
// so we can safely take the first limb and cast it to u32.
let n: u32 = n.as_words()[0].try_into().unwrap();
// In this branch `n` is `Word::BITS` bits or shorter,
// so we can safely take the first limb.
let n = n.as_words()[0];
if n > m {
(n, m)
} else {
Expand All @@ -47,19 +45,22 @@ pub(crate) fn gcd<const L: usize>(n: &Uint<L>, m: u32) -> u32 {

#[cfg(test)]
mod tests {
use crypto_bigint::{Encoding, U128};
use crypto_bigint::{Word, U128};
use num_bigint::BigUint;
use num_integer::Integer;
use proptest::prelude::*;

use super::gcd;
use super::gcd_vartime;

#[test]
fn corner_cases() {
assert_eq!(gcd(&U128::from(0u64), 5), 5);
assert_eq!(gcd(&U128::from(1u64), 11 * 13 * 19), 1);
assert_eq!(gcd(&U128::from(7u64 * 11 * 13), 1), 1);
assert_eq!(gcd(&U128::from(7u64 * 11 * 13), 11 * 13 * 19), 11 * 13);
assert_eq!(gcd_vartime(&U128::from(0u64), 5), 5);
assert_eq!(gcd_vartime(&U128::from(1u64), 11 * 13 * 19), 1);
assert_eq!(gcd_vartime(&U128::from(7u64 * 11 * 13), 1), 1);
assert_eq!(
gcd_vartime(&U128::from(7u64 * 11 * 13), 11 * 13 * 19),
11 * 13
);
}

prop_compose! {
Expand All @@ -70,16 +71,16 @@ mod tests {

proptest! {
#[test]
fn fuzzy(m in any::<u32>(), n in uint()) {
fn fuzzy(m in any::<Word>(), n in uint()) {
if m == 0 {
return Ok(());
}

let m_bi = BigUint::from(m);
let n_bi = BigUint::from_bytes_be(n.to_be_bytes().as_ref());
let gcd_ref: u32 = n_bi.gcd(&m_bi).try_into().unwrap();
let gcd_ref: Word = n_bi.gcd(&m_bi).try_into().unwrap();

let gcd_test = gcd(&n, m);
let gcd_test = gcd_vartime(&n, m);
assert_eq!(gcd_test, gcd_ref);
}
}
Expand Down
Loading

0 comments on commit 45152ad

Please sign in to comment.