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

Add DivRemLimb and RemLimb traits #496

Merged
merged 5 commits into from
Dec 23, 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
46 changes: 10 additions & 36 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ zeroize = { version = "1", optional = true, default-features = false }
bincode = "1"
criterion = { version = "0.5", features = ["html_reports"] }
hex-literal = "0.4"
num-bigint = { package = "num-bigint-dig", version = "0.8" }
num-bigint = "0.4"
num-integer = "0.1"
num-modular = { version = "0.5", features = ["num-bigint"] }
proptest = "1"
rand_core = { version = "0.6", features = ["std"] }
rand_chacha = "0.3"
Expand Down
30 changes: 28 additions & 2 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub use num_traits::{

pub(crate) use sealed::PrecomputeInverterWithAdjuster;

use crate::{Limb, NonZero, Odd};
use crate::{Limb, NonZero, Odd, Reciprocal};
use core::fmt::Debug;
use core::ops::{
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
Expand Down Expand Up @@ -110,11 +110,13 @@ pub trait Integer:
+ for<'a> Div<&'a NonZero<Self>, Output = Self>
+ DivAssign<NonZero<Self>>
+ for<'a> DivAssign<&'a NonZero<Self>>
+ DivRemLimb
+ Eq
+ From<u8>
+ From<u16>
+ From<u32>
+ From<u64>
+ From<Limb>
+ Mul<Output = Self>
+ for<'a> Mul<&'a Self, Output = Self>
+ MulMod<Output = Self>
Expand All @@ -123,6 +125,7 @@ pub trait Integer:
+ Ord
+ Rem<NonZero<Self>, Output = Self>
+ for<'a> Rem<&'a NonZero<Self>, Output = Self>
+ RemLimb
+ Send
+ Sized
+ Shl<u32, Output = Self>
Expand Down Expand Up @@ -452,6 +455,29 @@ pub trait SquareAssign {
fn square_assign(&mut self);
}

/// Support for optimized division by a single limb.
pub trait DivRemLimb: Sized {
/// Computes `self / rhs` using a pre-made reciprocal,
/// returns the quotient (q) and remainder (r).
fn div_rem_limb(&self, rhs: NonZero<Limb>) -> (Self, Limb) {
self.div_rem_limb_with_reciprocal(&Reciprocal::new(rhs))
}

/// Computes `self / rhs`, returns the quotient (q) and remainder (r).
fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb);
}

/// Support for optimized division by a single limb.
pub trait RemLimb: Sized {
/// Computes `self % rhs` using a pre-made reciprocal.
fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
self.rem_limb_with_reciprocal(&Reciprocal::new(rhs))
}

/// Computes `self % rhs`.
fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb;
}

/// Constant-time exponentiation.
pub trait Pow<Exponent> {
/// Raises to the `exponent` power.
Expand Down Expand Up @@ -561,7 +587,7 @@ pub trait Monty:
type Integer: Integer<Monty = Self>;

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

/// Create the precomputed data for Montgomery representation of integers modulo `modulus`.
fn new_params(modulus: Odd<Self::Integer>) -> Self::Params;
Expand Down
31 changes: 28 additions & 3 deletions src/uint/boxed/div.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
//! [`BoxedUint`] division operations.

use crate::{
uint::boxed, BoxedUint, CheckedDiv, ConstantTimeSelect, Limb, NonZero, Reciprocal, Wrapping,
uint::boxed, BoxedUint, CheckedDiv, ConstantTimeSelect, DivRemLimb, Limb, NonZero, Reciprocal,
RemLimb, Wrapping,
};
use core::ops::{Div, DivAssign, Rem, RemAssign};
use subtle::{Choice, ConstantTimeEq, ConstantTimeLess, CtOption};

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

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

/// Computes `self % rhs` using a pre-made reciprocal.
#[inline(always)]
pub fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
boxed::div_limb::rem_limb_with_reciprocal(self, reciprocal)
}

/// Computes `self % rhs`.
#[inline(always)]
pub fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
boxed::div_limb::rem_limb_with_reciprocal(self, &Reciprocal::new(rhs))
}

/// Computes self / rhs, returns the quotient, remainder.
pub fn div_rem(&self, rhs: &NonZero<Self>) -> (Self, Self) {
// Since `rhs` is nonzero, this should always hold.
Expand Down Expand Up @@ -295,6 +308,18 @@ impl RemAssign<NonZero<BoxedUint>> for BoxedUint {
}
}

impl DivRemLimb for BoxedUint {
fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) {
Self::div_rem_limb_with_reciprocal(self, reciprocal)
}
}

impl RemLimb for BoxedUint {
fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
Self::rem_limb_with_reciprocal(self, reciprocal)
}
}

#[cfg(test)]
mod tests {
use super::{BoxedUint, NonZero};
Expand Down
15 changes: 15 additions & 0 deletions src/uint/boxed/div_limb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,18 @@ pub(crate) fn div_rem_limb_with_reciprocal(
}
(BoxedUint { limbs: q.into() }, Limb(r >> reciprocal.shift()))
}

/// Divides `u` by the divisor encoded in the `reciprocal`, and returns the remainder.
#[inline(always)]
pub(crate) fn rem_limb_with_reciprocal(u: &BoxedUint, reciprocal: &Reciprocal) -> Limb {
let (u_shifted, u_hi) = u.shl_limb(reciprocal.shift());
let mut r = u_hi.0;

let mut j = u.limbs.len();
while j > 0 {
j -= 1;
let (_, rj) = div2by1(r, u_shifted.as_limbs()[j].0, reciprocal);
r = rj;
}
Limb(r >> reciprocal.shift())
}
36 changes: 30 additions & 6 deletions src/uint/div.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
//! [`Uint`] division operations.

use super::div_limb::{div_rem_limb_with_reciprocal, Reciprocal};
use crate::{CheckedDiv, ConstChoice, Limb, NonZero, Uint, Word, Wrapping};
use super::div_limb::{div_rem_limb_with_reciprocal, rem_limb_with_reciprocal, Reciprocal};
use crate::{CheckedDiv, ConstChoice, DivRemLimb, Limb, NonZero, RemLimb, Uint, Word, Wrapping};
use core::ops::{Div, DivAssign, Rem, RemAssign};
use subtle::CtOption;

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

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

/// Computes `self % rhs` using a pre-made reciprocal.
#[inline(always)]
pub const fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
rem_limb_with_reciprocal(self, reciprocal)
}

/// Computes `self % rhs`.
#[inline(always)]
pub const fn rem_limb(&self, rhs: NonZero<Limb>) -> Limb {
rem_limb_with_reciprocal(self, &Reciprocal::new(rhs))
}

/// Computes `self` / `rhs`, returns the quotient (q) and the remainder (r)
///
/// This function is constant-time with respect to both `self` and `rhs`.
Expand Down Expand Up @@ -84,7 +96,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {

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

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

Expand Down Expand Up @@ -584,6 +596,18 @@ impl<const LIMBS: usize> RemAssign<&NonZero<Uint<LIMBS>>> for Wrapping<Uint<LIMB
}
}

impl<const LIMBS: usize> DivRemLimb for Uint<LIMBS> {
fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) {
Self::div_rem_limb_with_reciprocal(self, reciprocal)
}
}

impl<const LIMBS: usize> RemLimb for Uint<LIMBS> {
fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb {
Self::rem_limb_with_reciprocal(self, reciprocal)
}
}

#[cfg(test)]
mod tests {
use crate::{Limb, NonZero, Uint, Word, U256};
Expand Down
18 changes: 18 additions & 0 deletions src/uint/div_limb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,24 @@ pub(crate) const fn div_rem_limb_with_reciprocal<const L: usize>(
(Uint::<L>::new(q), Limb(r >> reciprocal.shift))
}

/// Divides `u` by the divisor encoded in the `reciprocal`, and returns the remainder.
#[inline(always)]
pub(crate) const fn rem_limb_with_reciprocal<const L: usize>(
u: &Uint<L>,
reciprocal: &Reciprocal,
) -> Limb {
let (u_shifted, u_hi) = u.shl_limb(reciprocal.shift);
let mut r = u_hi.0;

let mut j = L;
while j > 0 {
j -= 1;
let (_, rj) = div2by1(r, u_shifted.as_limbs()[j].0, reciprocal);
r = rj;
}
Limb(r >> reciprocal.shift)
}

#[cfg(test)]
mod tests {
use super::{div2by1, Reciprocal};
Expand Down
7 changes: 4 additions & 3 deletions tests/boxed_monty_form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use crypto_bigint::{
modular::{BoxedMontyForm, BoxedMontyParams},
BoxedUint, Integer, Inverter, Limb, NonZero, Odd, PrecomputeInverter,
};
use num_bigint::{BigUint, ModInverse};
use num_bigint::BigUint;
use num_modular::ModularUnaryOps;
use proptest::prelude::*;
use std::cmp::Ordering;

Expand Down Expand Up @@ -84,7 +85,7 @@ proptest! {

let x_bi = retrieve_biguint(&x);
let n_bi = to_biguint(n.modulus());
let expected = x_bi.mod_inverse(&n_bi);
let expected = x_bi.invm(&n_bi);

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

let x_bi = retrieve_biguint(&x);
let n_bi = to_biguint(n.modulus());
let expected = x_bi.mod_inverse(&n_bi);
let expected = x_bi.invm(&n_bi);

match (expected, actual) {
(Some(exp), Some(act)) => {
Expand Down
Loading
Loading