Skip to content

Commit 3a45eda

Browse files
committed
Use Integer and Monty instead of Uint
1 parent 2379c91 commit 3a45eda

File tree

13 files changed

+433
-332
lines changed

13 files changed

+433
-332
lines changed

.github/workflows/crypto-primes.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
strategy:
1818
matrix:
1919
rust:
20-
- 1.65.0 # MSRV
20+
- 1.73.0 # MSRV
2121
- stable
2222
target:
2323
- wasm32-unknown-unknown
@@ -134,6 +134,6 @@ jobs:
134134
- uses: actions/checkout@v3
135135
- uses: actions-rs/toolchain@v1
136136
with:
137-
toolchain: 1.65.0
137+
toolchain: 1.73.0
138138
profile: minimal
139139
- run: cargo build --all-features --benches

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ description = "Random prime number generation and primality checking library"
77
repository = "https://github.com/entropyxyz/crypto-primes"
88
readme = "README.md"
99
categories = ["cryptography", "no-std"]
10-
rust-version = "1.65"
10+
rust-version = "1.73"
1111

1212
[dependencies]
13-
crypto-bigint = { version = "0.5.4", default-features = false, features = ["rand_core"] }
13+
crypto-bigint = { git = "https://github.com/RustCrypto/crypto-bigint.git", default-features = false, features = ["alloc", "rand_core"], commit = "bc061383cb4f63d69b89b23232fdce3e5b0d898c" }
1414
rand_core = { version = "0.6.4", default-features = false }
1515
openssl = { version = "0.10.39", optional = true, features = ["vendored"] }
1616
rug = { version = "1.18", default-features = false, features = ["integer"], optional = true }

benches/bench.rs

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
2-
use crypto_bigint::{nlimbs, Uint, U1024};
2+
use crypto_bigint::{nlimbs, Odd, Uint, U1024};
33
use rand_chacha::ChaCha8Rng;
44
use rand_core::{CryptoRngCore, OsRng, SeedableRng};
55

@@ -22,27 +22,27 @@ fn make_rng() -> ChaCha8Rng {
2222
ChaCha8Rng::from_seed(*b"01234567890123456789012345678901")
2323
}
2424

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

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

3535
fn bench_sieve(c: &mut Criterion) {
3636
let mut group = c.benchmark_group("Sieve");
3737

3838
group.bench_function("(U128) random start", |b| {
39-
b.iter(|| random_odd_uint::<{ nlimbs!(128) }>(&mut OsRng, 128))
39+
b.iter(|| random_odd_uint::<Uint<{ nlimbs!(128) }>>(&mut OsRng, 128))
4040
});
4141

4242
group.bench_function("(U128) creation", |b| {
4343
b.iter_batched(
44-
|| random_odd_uint::<{ nlimbs!(128) }>(&mut OsRng, 128),
45-
|start| Sieve::new(&start, 128, false),
44+
|| random_odd_uint::<Uint<{ nlimbs!(128) }>>(&mut OsRng, 128),
45+
|start| Sieve::new(start.as_ref(), 128, false),
4646
BatchSize::SmallInput,
4747
)
4848
});
@@ -57,13 +57,13 @@ fn bench_sieve(c: &mut Criterion) {
5757
});
5858

5959
group.bench_function("(U1024) random start", |b| {
60-
b.iter(|| random_odd_uint::<{ nlimbs!(1024) }>(&mut OsRng, 1024))
60+
b.iter(|| random_odd_uint::<Uint<{ nlimbs!(1024) }>>(&mut OsRng, 1024))
6161
});
6262

6363
group.bench_function("(U1024) creation", |b| {
6464
b.iter_batched(
65-
|| random_odd_uint::<{ nlimbs!(1024) }>(&mut OsRng, 1024),
66-
|start| Sieve::new(&start, 1024, false),
65+
|| random_odd_uint::<Uint<{ nlimbs!(1024) }>>(&mut OsRng, 1024),
66+
|start| Sieve::new(start.as_ref(), 1024, false),
6767
BatchSize::SmallInput,
6868
)
6969
});
@@ -84,7 +84,7 @@ fn bench_miller_rabin(c: &mut Criterion) {
8484

8585
group.bench_function("(U128) creation", |b| {
8686
b.iter_batched(
87-
|| random_odd_uint::<{ nlimbs!(128) }>(&mut OsRng, 128),
87+
|| random_odd_uint::<Uint<{ nlimbs!(128) }>>(&mut OsRng, 128),
8888
|start| MillerRabin::new(&start),
8989
BatchSize::SmallInput,
9090
)
@@ -100,7 +100,7 @@ fn bench_miller_rabin(c: &mut Criterion) {
100100

101101
group.bench_function("(U1024) creation", |b| {
102102
b.iter_batched(
103-
|| random_odd_uint::<{ nlimbs!(1024) }>(&mut OsRng, 1024),
103+
|| random_odd_uint::<Uint<{ nlimbs!(1024) }>>(&mut OsRng, 1024),
104104
|start| MillerRabin::new(&start),
105105
BatchSize::SmallInput,
106106
)
@@ -122,7 +122,7 @@ fn bench_lucas(c: &mut Criterion) {
122122
group.bench_function("(U128) Selfridge base, strong check (pre-sieved)", |b| {
123123
b.iter_batched(
124124
|| make_presieved_num::<{ nlimbs!(128) }>(&mut rng),
125-
|n| lucas_test(&n, SelfridgeBase, LucasCheck::Strong),
125+
|n| lucas_test(n.as_ref(), SelfridgeBase, LucasCheck::Strong),
126126
BatchSize::SmallInput,
127127
)
128128
});
@@ -131,7 +131,7 @@ fn bench_lucas(c: &mut Criterion) {
131131
group.bench_function("(U1024) Selfridge base, strong check (pre-sieved)", |b| {
132132
b.iter_batched(
133133
|| make_presieved_num::<{ nlimbs!(1024) }>(&mut rng),
134-
|n| lucas_test(&n, SelfridgeBase, LucasCheck::Strong),
134+
|n| lucas_test(n.as_ref(), SelfridgeBase, LucasCheck::Strong),
135135
BatchSize::SmallInput,
136136
)
137137
});
@@ -140,7 +140,7 @@ fn bench_lucas(c: &mut Criterion) {
140140
group.bench_function("(U1024) A* base, Lucas-V check (pre-sieved)", |b| {
141141
b.iter_batched(
142142
|| make_presieved_num::<{ nlimbs!(1024) }>(&mut rng),
143-
|n| lucas_test(&n, AStarBase, LucasCheck::LucasV),
143+
|n| lucas_test(n.as_ref(), AStarBase, LucasCheck::LucasV),
144144
BatchSize::SmallInput,
145145
)
146146
});
@@ -151,7 +151,7 @@ fn bench_lucas(c: &mut Criterion) {
151151
|b| {
152152
b.iter_batched(
153153
|| make_presieved_num::<{ nlimbs!(1024) }>(&mut rng),
154-
|n| lucas_test(&n, BruteForceBase, LucasCheck::AlmostExtraStrong),
154+
|n| lucas_test(n.as_ref(), BruteForceBase, LucasCheck::AlmostExtraStrong),
155155
BatchSize::SmallInput,
156156
)
157157
},
@@ -161,7 +161,7 @@ fn bench_lucas(c: &mut Criterion) {
161161
group.bench_function("(U1024) brute force base, extra strong (pre-sieved)", |b| {
162162
b.iter_batched(
163163
|| make_presieved_num::<{ nlimbs!(1024) }>(&mut rng),
164-
|n| lucas_test(&n, BruteForceBase, LucasCheck::ExtraStrong),
164+
|n| lucas_test(n.as_ref(), BruteForceBase, LucasCheck::ExtraStrong),
165165
BatchSize::SmallInput,
166166
)
167167
});
@@ -192,39 +192,39 @@ fn bench_presets(c: &mut Criterion) {
192192

193193
group.bench_function("(U128) Prime test", |b| {
194194
b.iter_batched(
195-
|| random_odd_uint::<{ nlimbs!(128) }>(&mut OsRng, 128),
196-
|num| is_prime_with_rng(&mut OsRng, &num),
195+
|| random_odd_uint::<Uint<{ nlimbs!(128) }>>(&mut OsRng, 128),
196+
|num| is_prime_with_rng(&mut OsRng, num.as_ref()),
197197
BatchSize::SmallInput,
198198
)
199199
});
200200

201201
group.bench_function("(U128) Safe prime test", |b| {
202202
b.iter_batched(
203-
|| random_odd_uint::<{ nlimbs!(128) }>(&mut OsRng, 128),
204-
|num| is_safe_prime_with_rng(&mut OsRng, &num),
203+
|| random_odd_uint::<Uint<{ nlimbs!(128) }>>(&mut OsRng, 128),
204+
|num| is_safe_prime_with_rng(&mut OsRng, num.as_ref()),
205205
BatchSize::SmallInput,
206206
)
207207
});
208208

209209
let mut rng = make_rng();
210210
group.bench_function("(U128) Random prime", |b| {
211-
b.iter(|| generate_prime_with_rng::<{ nlimbs!(128) }>(&mut rng, None))
211+
b.iter(|| generate_prime_with_rng::<Uint<{ nlimbs!(128) }>>(&mut rng, 128))
212212
});
213213

214214
let mut rng = make_rng();
215215
group.bench_function("(U1024) Random prime", |b| {
216-
b.iter(|| generate_prime_with_rng::<{ nlimbs!(1024) }>(&mut rng, None))
216+
b.iter(|| generate_prime_with_rng::<Uint<{ nlimbs!(1024) }>>(&mut rng, 1024))
217217
});
218218

219219
let mut rng = make_rng();
220220
group.bench_function("(U128) Random safe prime", |b| {
221-
b.iter(|| generate_safe_prime_with_rng::<{ nlimbs!(128) }>(&mut rng, None))
221+
b.iter(|| generate_safe_prime_with_rng::<Uint<{ nlimbs!(128) }>>(&mut rng, 128))
222222
});
223223

224224
group.sample_size(20);
225225
let mut rng = make_rng();
226226
group.bench_function("(U1024) Random safe prime", |b| {
227-
b.iter(|| generate_safe_prime_with_rng::<{ nlimbs!(1024) }>(&mut rng, None))
227+
b.iter(|| generate_safe_prime_with_rng::<Uint<{ nlimbs!(1024) }>>(&mut rng, 1024))
228228
});
229229

230230
group.finish();
@@ -234,19 +234,19 @@ fn bench_presets(c: &mut Criterion) {
234234

235235
let mut rng = make_rng();
236236
group.bench_function("(U128) Random safe prime", |b| {
237-
b.iter(|| generate_safe_prime_with_rng::<{ nlimbs!(128) }>(&mut rng, None))
237+
b.iter(|| generate_safe_prime_with_rng::<Uint<{ nlimbs!(128) }>>(&mut rng, 128))
238238
});
239239

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

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

252252
group.finish();
@@ -257,7 +257,7 @@ fn bench_gmp(c: &mut Criterion) {
257257
let mut group = c.benchmark_group("GMP");
258258

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

src/hazmat/gcd.rs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
1-
use crypto_bigint::{Limb, NonZero, Uint};
1+
use crypto_bigint::{Integer, Limb, NonZero};
22

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

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

18-
// Normalize input: the resulting (a, b) are both small, a >= b, and b != 0.
19-
let (mut a, mut b): (u32, u32) = if n.bits() > (u32::BITS as usize) {
17+
// Normalize input: the resulting (a, b) are both small, `a >= b`, and `b != 0`.
18+
let (mut a, mut b): (u32, u32) = if n.bits_vartime() > u32::BITS {
2019
// `m` is non-zero, so we can unwrap.
21-
let (_quo, n) = n.div_rem_limb(NonZero::new(Limb::from(m)).unwrap());
22-
// `n` is a remainder of a division by `u32`, so it can be safely cast to `u32`.
23-
let b: u32 = n.0.try_into().unwrap();
20+
let r = n.rem_limb(NonZero::new(Limb::from(m)).unwrap());
21+
// `r` is a remainder of a division by `u32`, so it can be safely cast to `u32`.
22+
let b: u32 = r.0.try_into().unwrap();
2423
(m, b)
2524
} else {
2625
// In this branch `n` is 32 bits or shorter,
2726
// so we can safely take the first limb and cast it to u32.
28-
let n: u32 = n.as_words()[0].try_into().unwrap();
27+
let n: u32 = n.as_ref()[0].0.try_into().unwrap();
2928
if n > m {
3029
(n, m)
3130
} else {
@@ -47,19 +46,22 @@ pub(crate) fn gcd<const L: usize>(n: &Uint<L>, m: u32) -> u32 {
4746

4847
#[cfg(test)]
4948
mod tests {
50-
use crypto_bigint::{Encoding, U128};
49+
use crypto_bigint::U128;
5150
use num_bigint::BigUint;
5251
use num_integer::Integer;
5352
use proptest::prelude::*;
5453

55-
use super::gcd;
54+
use super::gcd_vartime;
5655

5756
#[test]
5857
fn corner_cases() {
59-
assert_eq!(gcd(&U128::from(0u64), 5), 5);
60-
assert_eq!(gcd(&U128::from(1u64), 11 * 13 * 19), 1);
61-
assert_eq!(gcd(&U128::from(7u64 * 11 * 13), 1), 1);
62-
assert_eq!(gcd(&U128::from(7u64 * 11 * 13), 11 * 13 * 19), 11 * 13);
58+
assert_eq!(gcd_vartime(&U128::from(0u64), 5), 5);
59+
assert_eq!(gcd_vartime(&U128::from(1u64), 11 * 13 * 19), 1);
60+
assert_eq!(gcd_vartime(&U128::from(7u64 * 11 * 13), 1), 1);
61+
assert_eq!(
62+
gcd_vartime(&U128::from(7u64 * 11 * 13), 11 * 13 * 19),
63+
11 * 13
64+
);
6365
}
6466

6567
prop_compose! {
@@ -79,7 +81,7 @@ mod tests {
7981
let n_bi = BigUint::from_bytes_be(n.to_be_bytes().as_ref());
8082
let gcd_ref: u32 = n_bi.gcd(&m_bi).try_into().unwrap();
8183

82-
let gcd_test = gcd(&n, m);
84+
let gcd_test = gcd_vartime(&n, m);
8385
assert_eq!(gcd_test, gcd_ref);
8486
}
8587
}

0 commit comments

Comments
 (0)