Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump crypto-bigint to 0.6.0-pre.5 #38

Merged
merged 16 commits into from
Dec 24, 2023
Merged
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
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
Loading