Skip to content

Commit 7c65c66

Browse files
authored
Add DivRemLimb and RemLimb traits (#496)
* Add more bounds for Monty::Params * Use num-bigint instead of num-bigint-dig * Add From<Limb> bound for Integer * Fix vartime method usage in constant-time methods
1 parent 90432fc commit 7c65c66

File tree

11 files changed

+146
-59
lines changed

11 files changed

+146
-59
lines changed

Cargo.lock

Lines changed: 10 additions & 36 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ zeroize = { version = "1", optional = true, default-features = false }
3232
bincode = "1"
3333
criterion = { version = "0.5", features = ["html_reports"] }
3434
hex-literal = "0.4"
35-
num-bigint = { package = "num-bigint-dig", version = "0.8" }
35+
num-bigint = "0.4"
3636
num-integer = "0.1"
37+
num-modular = { version = "0.5", features = ["num-bigint"] }
3738
proptest = "1"
3839
rand_core = { version = "0.6", features = ["std"] }
3940
rand_chacha = "0.3"

src/traits.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub use num_traits::{
88

99
pub(crate) use sealed::PrecomputeInverterWithAdjuster;
1010

11-
use crate::{Limb, NonZero, Odd};
11+
use crate::{Limb, NonZero, Odd, Reciprocal};
1212
use core::fmt::Debug;
1313
use core::ops::{
1414
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
@@ -110,11 +110,13 @@ pub trait Integer:
110110
+ for<'a> Div<&'a NonZero<Self>, Output = Self>
111111
+ DivAssign<NonZero<Self>>
112112
+ for<'a> DivAssign<&'a NonZero<Self>>
113+
+ DivRemLimb
113114
+ Eq
114115
+ From<u8>
115116
+ From<u16>
116117
+ From<u32>
117118
+ From<u64>
119+
+ From<Limb>
118120
+ Mul<Output = Self>
119121
+ for<'a> Mul<&'a Self, Output = Self>
120122
+ MulMod<Output = Self>
@@ -123,6 +125,7 @@ pub trait Integer:
123125
+ Ord
124126
+ Rem<NonZero<Self>, Output = Self>
125127
+ for<'a> Rem<&'a NonZero<Self>, Output = Self>
128+
+ RemLimb
126129
+ Send
127130
+ Sized
128131
+ Shl<u32, Output = Self>
@@ -452,6 +455,29 @@ pub trait SquareAssign {
452455
fn square_assign(&mut self);
453456
}
454457

458+
/// Support for optimized division by a single limb.
459+
pub trait DivRemLimb: Sized {
460+
/// Computes `self / rhs` using a pre-made reciprocal,
461+
/// returns the quotient (q) and remainder (r).
462+
fn div_rem_limb(&self, rhs: NonZero<Limb>) -> (Self, Limb) {
463+
self.div_rem_limb_with_reciprocal(&Reciprocal::new(rhs))
464+
}
465+
466+
/// Computes `self / rhs`, returns the quotient (q) and remainder (r).
467+
fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb);
468+
}
469+
470+
/// Support for optimized division by a single limb.
471+
pub trait RemLimb: Sized {
472+
/// Computes `self % rhs` using a pre-made reciprocal.
473+
fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
474+
self.rem_limb_with_reciprocal(&Reciprocal::new(rhs))
475+
}
476+
477+
/// Computes `self % rhs`.
478+
fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb;
479+
}
480+
455481
/// Constant-time exponentiation.
456482
pub trait Pow<Exponent> {
457483
/// Raises to the `exponent` power.
@@ -561,7 +587,7 @@ pub trait Monty:
561587
type Integer: Integer<Monty = Self>;
562588

563589
/// The precomputed data needed for this representation.
564-
type Params: Clone;
590+
type Params: 'static + Clone + Debug + Eq + Sized + Send + Sync;
565591

566592
/// Create the precomputed data for Montgomery representation of integers modulo `modulus`.
567593
fn new_params(modulus: Odd<Self::Integer>) -> Self::Params;

src/uint/boxed/div.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,36 @@
11
//! [`BoxedUint`] division operations.
22
33
use crate::{
4-
uint::boxed, BoxedUint, CheckedDiv, ConstantTimeSelect, Limb, NonZero, Reciprocal, Wrapping,
4+
uint::boxed, BoxedUint, CheckedDiv, ConstantTimeSelect, DivRemLimb, Limb, NonZero, Reciprocal,
5+
RemLimb, Wrapping,
56
};
67
use core::ops::{Div, DivAssign, Rem, RemAssign};
78
use subtle::{Choice, ConstantTimeEq, ConstantTimeLess, CtOption};
89

910
impl BoxedUint {
10-
/// Computes `self` / `rhs` using a pre-made reciprocal,
11+
/// Computes `self / rhs` using a pre-made reciprocal,
1112
/// returns the quotient (q) and remainder (r).
1213
pub fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) {
1314
boxed::div_limb::div_rem_limb_with_reciprocal(self, reciprocal)
1415
}
1516

16-
/// Computes `self` / `rhs`, returns the quotient (q) and remainder (r).
17+
/// Computes `self / rhs`, returns the quotient (q) and remainder (r).
1718
pub fn div_rem_limb(&self, rhs: NonZero<Limb>) -> (Self, Limb) {
1819
boxed::div_limb::div_rem_limb_with_reciprocal(self, &Reciprocal::new(rhs))
1920
}
2021

22+
/// Computes `self % rhs` using a pre-made reciprocal.
23+
#[inline(always)]
24+
pub fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
25+
boxed::div_limb::rem_limb_with_reciprocal(self, reciprocal)
26+
}
27+
28+
/// Computes `self % rhs`.
29+
#[inline(always)]
30+
pub fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
31+
boxed::div_limb::rem_limb_with_reciprocal(self, &Reciprocal::new(rhs))
32+
}
33+
2134
/// Computes self / rhs, returns the quotient, remainder.
2235
pub fn div_rem(&self, rhs: &NonZero<Self>) -> (Self, Self) {
2336
// Since `rhs` is nonzero, this should always hold.
@@ -295,6 +308,18 @@ impl RemAssign<NonZero<BoxedUint>> for BoxedUint {
295308
}
296309
}
297310

311+
impl DivRemLimb for BoxedUint {
312+
fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) {
313+
Self::div_rem_limb_with_reciprocal(self, reciprocal)
314+
}
315+
}
316+
317+
impl RemLimb for BoxedUint {
318+
fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
319+
Self::rem_limb_with_reciprocal(self, reciprocal)
320+
}
321+
}
322+
298323
#[cfg(test)]
299324
mod tests {
300325
use super::{BoxedUint, NonZero};

src/uint/boxed/div_limb.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,18 @@ pub(crate) fn div_rem_limb_with_reciprocal(
2323
}
2424
(BoxedUint { limbs: q.into() }, Limb(r >> reciprocal.shift()))
2525
}
26+
27+
/// Divides `u` by the divisor encoded in the `reciprocal`, and returns the remainder.
28+
#[inline(always)]
29+
pub(crate) fn rem_limb_with_reciprocal(u: &BoxedUint, reciprocal: &Reciprocal) -> Limb {
30+
let (u_shifted, u_hi) = u.shl_limb(reciprocal.shift());
31+
let mut r = u_hi.0;
32+
33+
let mut j = u.limbs.len();
34+
while j > 0 {
35+
j -= 1;
36+
let (_, rj) = div2by1(r, u_shifted.as_limbs()[j].0, reciprocal);
37+
r = rj;
38+
}
39+
Limb(r >> reciprocal.shift())
40+
}

src/uint/div.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
11
//! [`Uint`] division operations.
22
3-
use super::div_limb::{div_rem_limb_with_reciprocal, Reciprocal};
4-
use crate::{CheckedDiv, ConstChoice, Limb, NonZero, Uint, Word, Wrapping};
3+
use super::div_limb::{div_rem_limb_with_reciprocal, rem_limb_with_reciprocal, Reciprocal};
4+
use crate::{CheckedDiv, ConstChoice, DivRemLimb, Limb, NonZero, RemLimb, Uint, Word, Wrapping};
55
use core::ops::{Div, DivAssign, Rem, RemAssign};
66
use subtle::CtOption;
77

88
impl<const LIMBS: usize> Uint<LIMBS> {
9-
/// Computes `self` / `rhs` using a pre-made reciprocal,
9+
/// Computes `self / rhs` using a pre-made reciprocal,
1010
/// returns the quotient (q) and remainder (r).
1111
#[inline(always)]
1212
pub const fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) {
1313
div_rem_limb_with_reciprocal(self, reciprocal)
1414
}
1515

16-
/// Computes `self` / `rhs`, returns the quotient (q) and remainder (r).
16+
/// Computes `self / rhs`, returns the quotient (q) and remainder (r).
1717
#[inline(always)]
1818
pub const fn div_rem_limb(&self, rhs: NonZero<Limb>) -> (Self, Limb) {
1919
div_rem_limb_with_reciprocal(self, &Reciprocal::new(rhs))
2020
}
2121

22+
/// Computes `self % rhs` using a pre-made reciprocal.
23+
#[inline(always)]
24+
pub const fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
25+
rem_limb_with_reciprocal(self, reciprocal)
26+
}
27+
28+
/// Computes `self % rhs`.
29+
#[inline(always)]
30+
pub const fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
31+
rem_limb_with_reciprocal(self, &Reciprocal::new(rhs))
32+
}
33+
2234
/// Computes `self` / `rhs`, returns the quotient (q) and the remainder (r)
2335
///
2436
/// This function is constant-time with respect to both `self` and `rhs`.
@@ -84,7 +96,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {
8496

8597
/// Computes `self` % `rhs`, returns the remainder.
8698
pub const fn rem(&self, rhs: &NonZero<Self>) -> Self {
87-
self.div_rem_vartime(rhs).1
99+
self.div_rem(rhs).1
88100
}
89101

90102
/// Computes `self` % `rhs`, returns the remainder in variable-time with respect to `rhs`.
@@ -211,7 +223,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {
211223
/// Perform checked reduction, returning a [`CtOption`] which `is_some`
212224
/// only if the rhs != 0
213225
pub fn checked_rem(&self, rhs: &Self) -> CtOption<Self> {
214-
NonZero::new(*rhs).map(|rhs| self.rem_vartime(&rhs))
226+
NonZero::new(*rhs).map(|rhs| self.rem(&rhs))
215227
}
216228
}
217229

@@ -584,6 +596,18 @@ impl<const LIMBS: usize> RemAssign<&NonZero<Uint<LIMBS>>> for Wrapping<Uint<LIMB
584596
}
585597
}
586598

599+
impl<const LIMBS: usize> DivRemLimb for Uint<LIMBS> {
600+
fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) {
601+
Self::div_rem_limb_with_reciprocal(self, reciprocal)
602+
}
603+
}
604+
605+
impl<const LIMBS: usize> RemLimb for Uint<LIMBS> {
606+
fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
607+
Self::rem_limb_with_reciprocal(self, reciprocal)
608+
}
609+
}
610+
587611
#[cfg(test)]
588612
mod tests {
589613
use crate::{Limb, NonZero, Uint, Word, U256};

src/uint/div_limb.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,24 @@ pub(crate) const fn div_rem_limb_with_reciprocal<const L: usize>(
236236
(Uint::<L>::new(q), Limb(r >> reciprocal.shift))
237237
}
238238

239+
/// Divides `u` by the divisor encoded in the `reciprocal`, and returns the remainder.
240+
#[inline(always)]
241+
pub(crate) const fn rem_limb_with_reciprocal<const L: usize>(
242+
u: &Uint<L>,
243+
reciprocal: &Reciprocal,
244+
) -> Limb {
245+
let (u_shifted, u_hi) = u.shl_limb(reciprocal.shift);
246+
let mut r = u_hi.0;
247+
248+
let mut j = L;
249+
while j > 0 {
250+
j -= 1;
251+
let (_, rj) = div2by1(r, u_shifted.as_limbs()[j].0, reciprocal);
252+
r = rj;
253+
}
254+
Limb(r >> reciprocal.shift)
255+
}
256+
239257
#[cfg(test)]
240258
mod tests {
241259
use super::{div2by1, Reciprocal};

tests/boxed_monty_form.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use crypto_bigint::{
66
modular::{BoxedMontyForm, BoxedMontyParams},
77
BoxedUint, Integer, Inverter, Limb, NonZero, Odd, PrecomputeInverter,
88
};
9-
use num_bigint::{BigUint, ModInverse};
9+
use num_bigint::BigUint;
10+
use num_modular::ModularUnaryOps;
1011
use proptest::prelude::*;
1112
use std::cmp::Ordering;
1213

@@ -84,7 +85,7 @@ proptest! {
8485

8586
let x_bi = retrieve_biguint(&x);
8687
let n_bi = to_biguint(n.modulus());
87-
let expected = x_bi.mod_inverse(&n_bi);
88+
let expected = x_bi.invm(&n_bi);
8889

8990
match (expected, actual) {
9091
(Some(exp), Some(act)) => prop_assert_eq!(exp, to_biguint(&act).into()),
@@ -101,7 +102,7 @@ proptest! {
101102

102103
let x_bi = retrieve_biguint(&x);
103104
let n_bi = to_biguint(n.modulus());
104-
let expected = x_bi.mod_inverse(&n_bi);
105+
let expected = x_bi.invm(&n_bi);
105106

106107
match (expected, actual) {
107108
(Some(exp), Some(act)) => {

0 commit comments

Comments
 (0)