Skip to content

Commit 709a16d

Browse files
committed
Add DivRemLimb and RemLimb traits
1 parent 68a2287 commit 709a16d

File tree

5 files changed

+115
-8
lines changed

5 files changed

+115
-8
lines changed

src/traits.rs

Lines changed: 26 additions & 1 deletion
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,6 +110,7 @@ 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>
@@ -124,6 +125,7 @@ pub trait Integer:
124125
+ Ord
125126
+ Rem<NonZero<Self>, Output = Self>
126127
+ for<'a> Rem<&'a NonZero<Self>, Output = Self>
128+
+ RemLimb
127129
+ Send
128130
+ Sized
129131
+ Shl<u32, Output = Self>
@@ -453,6 +455,29 @@ pub trait SquareAssign {
453455
fn square_assign(&mut self);
454456
}
455457

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+
456481
/// Constant-time exponentiation.
457482
pub trait Pow<Exponent> {
458483
/// Raises to the `exponent` power.

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: 28 additions & 4 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`.
@@ -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};

0 commit comments

Comments
 (0)