Skip to content

Commit 08e9813

Browse files
committed
Use Integer and Monty instead of Uint
1 parent 45152ad commit 08e9813

File tree

11 files changed

+361
-251
lines changed

11 files changed

+361
-251
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ categories = ["cryptography", "no-std"]
1010
rust-version = "1.73"
1111

1212
[dependencies]
13-
crypto-bigint = { version = "0.6.0-pre.5", default-features = false, features = ["rand_core"] }
13+
crypto-bigint = { version = "0.6.0-pre.5", default-features = false, features = ["alloc", "rand_core"] }
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: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ 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 = random_odd_uint::<L>(rng, Uint::<L>::BITS);
25+
fn make_sieve<const L: usize>(rng: &mut impl CryptoRngCore) -> Sieve<Uint<L>> {
26+
let start = random_odd_uint::<Uint<L>>(rng, Uint::<L>::BITS);
2727
Sieve::new(&start, Uint::<L>::BITS, false)
2828
}
2929

@@ -36,13 +36,13 @@ 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
MillerRabin::new,
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
MillerRabin::new,
105105
BatchSize::SmallInput,
106106
)
@@ -193,39 +193,39 @@ fn bench_presets(c: &mut Criterion) {
193193

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

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

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

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

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

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

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

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

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

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

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

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

src/hazmat/gcd.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
use crypto_bigint::{Limb, NonZero, Uint, Word};
1+
use crypto_bigint::{Integer, Limb, NonZero, Word};
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_vartime<const L: usize>(n: &Uint<L>, m: Word) -> Word {
6+
pub(crate) fn gcd_vartime<T: Integer>(n: &T, m: Word) -> Word {
77
// This is an internal function, and it will never be called with `m = 0`.
88
// Allowing `m = 0` would require us to have the return type of `Uint<L>`
99
// (since `gcd(n, 0) = n`).
1010
debug_assert!(m != 0);
1111

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

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

src/hazmat/jacobi.rs

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Jacobi symbol calculation.
22
3-
use crypto_bigint::{Limb, NonZero, Odd, Uint, Word};
3+
use crypto_bigint::{Integer, Limb, NonZero, Odd, Word};
44

55
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
66
pub(crate) enum JacobiSymbol {
@@ -20,37 +20,13 @@ impl core::ops::Neg for JacobiSymbol {
2020
}
2121
}
2222

23-
// A helper trait to generalize some functions over Word and Uint.
24-
trait SmallMod {
25-
fn mod8(&self) -> Word;
26-
fn mod4(&self) -> Word;
27-
}
28-
29-
impl SmallMod for Word {
30-
fn mod8(&self) -> Word {
31-
self & 7
32-
}
33-
fn mod4(&self) -> Word {
34-
self & 3
35-
}
36-
}
37-
38-
impl<const L: usize> SmallMod for Uint<L> {
39-
fn mod8(&self) -> Word {
40-
self.as_limbs()[0].0 & 7
41-
}
42-
fn mod4(&self) -> Word {
43-
self.as_limbs()[0].0 & 3
44-
}
45-
}
46-
4723
/// Transforms `(a/p)` -> `(r/p)` for odd `p`, where the resulting `r` is odd, and `a = r * 2^s`.
4824
/// Takes a Jacobi symbol value, and returns `r` and the new Jacobi symbol,
4925
/// negated if the transformation changes parity.
5026
///
5127
/// Note that the returned `r` is odd.
52-
fn reduce_numerator<V: SmallMod>(j: JacobiSymbol, a: Word, p: &V) -> (JacobiSymbol, Word) {
53-
let p_mod_8 = p.mod8();
28+
fn apply_reduce_numerator(j: JacobiSymbol, a: Word, p: Word) -> (JacobiSymbol, Word) {
29+
let p_mod_8 = p & 7;
5430
let s = a.trailing_zeros();
5531
let j = if (s & 1) == 1 && (p_mod_8 == 3 || p_mod_8 == 5) {
5632
-j
@@ -60,38 +36,55 @@ fn reduce_numerator<V: SmallMod>(j: JacobiSymbol, a: Word, p: &V) -> (JacobiSymb
6036
(j, a >> s)
6137
}
6238

39+
fn reduce_numerator_long<T: Integer>(j: JacobiSymbol, a: Word, p: &T) -> (JacobiSymbol, Word) {
40+
apply_reduce_numerator(j, a, p.as_ref()[0].0)
41+
}
42+
43+
fn reduce_numerator_short(j: JacobiSymbol, a: Word, p: Word) -> (JacobiSymbol, Word) {
44+
apply_reduce_numerator(j, a, p)
45+
}
46+
6347
/// Transforms `(a/p)` -> `(p/a)` for odd and coprime `a` and `p`.
6448
/// Takes a Jacobi symbol value, and returns the swapped pair and the new Jacobi symbol,
6549
/// negated if the transformation changes parity.
66-
fn swap<T: SmallMod, V: SmallMod>(j: JacobiSymbol, a: T, p: V) -> (JacobiSymbol, V, T) {
67-
let j = if a.mod4() == 1 || p.mod4() == 1 {
50+
fn apply_swap(j: JacobiSymbol, a: Word, p: Word) -> JacobiSymbol {
51+
if a & 3 == 1 || p & 3 == 1 {
6852
j
6953
} else {
7054
-j
71-
};
55+
}
56+
}
57+
58+
fn swap_long<T: Integer>(j: JacobiSymbol, a: Word, p: &Odd<T>) -> (JacobiSymbol, &Odd<T>, Word) {
59+
let j = apply_swap(j, a, p.as_ref().as_ref()[0].0);
60+
(j, p, a)
61+
}
62+
63+
fn swap_short(j: JacobiSymbol, a: Word, p: Word) -> (JacobiSymbol, Word, Word) {
64+
let j = apply_swap(j, a, p);
7265
(j, p, a)
7366
}
7467

7568
/// Returns the Jacobi symbol `(a/p)` given an odd `p`.
76-
pub(crate) fn jacobi_symbol_vartime<const L: usize>(
69+
pub(crate) fn jacobi_symbol_vartime<T: Integer>(
7770
abs_a: Word,
7871
a_is_negative: bool,
79-
p_long: &Odd<Uint<L>>,
72+
p_long: &Odd<T>,
8073
) -> JacobiSymbol {
8174
let result = JacobiSymbol::One; // Keep track of all the sign flips here.
8275

8376
// Deal with a negative `a` first:
8477
// (-a/n) = (-1/n) * (a/n)
8578
// = (-1)^((n-1)/2) * (a/n)
8679
// = (-1 if n = 3 mod 4 else 1) * (a/n)
87-
let result = if a_is_negative && p_long.mod4() == 3 {
80+
let result = if a_is_negative && p_long.as_ref().as_ref()[0].0 & 3 == 3 {
8881
-result
8982
} else {
9083
result
9184
};
9285

9386
// A degenerate case.
94-
if abs_a == 1 || p_long.as_ref() == &Uint::<L>::ONE {
87+
if abs_a == 1 || p_long.as_ref() == &T::one() {
9588
return result;
9689
}
9790

@@ -100,14 +93,14 @@ pub(crate) fn jacobi_symbol_vartime<const L: usize>(
10093
// Normalize input: at the end we want `a < p`, `p` odd, and both fitting into a `Word`.
10194
let (result, a, p): (JacobiSymbol, Word, Word) = if p_long.bits_vartime() <= Limb::BITS {
10295
let a = a_limb.0;
103-
let p = p_long.as_limbs()[0].0;
96+
let p = p_long.as_ref().as_ref()[0].0;
10497
(result, a % p, p)
10598
} else {
106-
let (result, a) = reduce_numerator(result, a_limb.0, p_long.as_ref());
99+
let (result, a) = reduce_numerator_long(result, a_limb.0, p_long.as_ref());
107100
if a == 1 {
108101
return result;
109102
}
110-
let (result, a_long, p) = swap(result, a, p_long.get());
103+
let (result, a_long, p) = swap_long(result, a, p_long);
111104
// Can unwrap here, since `p` is swapped with `a`,
112105
// and `a` would be odd after `reduce_numerator()`.
113106
let a =
@@ -127,7 +120,7 @@ pub(crate) fn jacobi_symbol_vartime<const L: usize>(
127120
// At this point `p` is odd (either coming from outside of the `loop`,
128121
// or from the previous iteration, where a previously reduced `a`
129122
// was swapped into its place), so we can call this.
130-
(result, a) = reduce_numerator(result, a, &p);
123+
(result, a) = reduce_numerator_short(result, a, p);
131124

132125
if a == 1 {
133126
return result;
@@ -138,7 +131,7 @@ pub(crate) fn jacobi_symbol_vartime<const L: usize>(
138131
// Note that technically `swap()` only returns a valid `result` if `a` and `p` are coprime.
139132
// But if they are not, we will return `Zero` eventually,
140133
// which is not affected by any sign changes.
141-
(result, a, p) = swap(result, a, p);
134+
(result, a, p) = swap_short(result, a, p);
142135

143136
a %= p;
144137
}

0 commit comments

Comments
 (0)