Skip to content
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
9 changes: 9 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ macro_rules! nlimbs {
};
}

/// Calculate the number of 62-bit unsaturated limbs required to represent the given number of bits when performing
/// Bernstein-Yang inversions.
// TODO(tarcieri): replace with `generic_const_exprs` (rust-lang/rust#76560) when stable
macro_rules! bernstein_yang_nlimbs {
($bits:expr) => {
(($bits / 64) + (($bits / 64) * 2).div_ceil(64) + 1)
};
}

#[cfg(test)]
mod tests {
#[cfg(target_pointer_width = "32")]
Expand Down
20 changes: 12 additions & 8 deletions src/modular/bernstein_yang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#![allow(clippy::needless_range_loop)]

use crate::{Uint, Word};
use crate::{Inverter, Limb, Uint, Word};

/// Type of the modular multiplicative inverter based on the Bernstein-Yang method.
/// The inverter can be created for a specified modulus M and adjusting parameter A
Expand Down Expand Up @@ -56,7 +56,7 @@ impl<const SAT_LIMBS: usize, const UNSAT_LIMBS: usize>
/// Creates the inverter for specified modulus and adjusting parameter.
#[allow(trivial_numeric_casts)]
pub const fn new(modulus: &Uint<SAT_LIMBS>, adjuster: &Uint<SAT_LIMBS>) -> Self {
if UNSAT_LIMBS != unsat_nlimbs(SAT_LIMBS) {
if UNSAT_LIMBS != bernstein_yang_nlimbs!(SAT_LIMBS * Limb::BITS as usize) {
panic!("BernsteinYangInverter has incorrect number of limbs");
}

Expand Down Expand Up @@ -209,6 +209,16 @@ impl<const SAT_LIMBS: usize, const UNSAT_LIMBS: usize>
}
}

impl<const SAT_LIMBS: usize, const UNSAT_LIMBS: usize> Inverter
for BernsteinYangInverter<SAT_LIMBS, UNSAT_LIMBS>
{
type Output = Uint<SAT_LIMBS>;

fn invert(&self, value: &Uint<SAT_LIMBS>) -> Option<Self::Output> {
self.invert(value)
}
}

/// Returns the multiplicative inverse of the argument modulo 2^62. The implementation is based
/// on the Hurchalla's method for computing the multiplicative inverse modulo a power of two.
/// For better understanding the implementation, the following paper is recommended:
Expand Down Expand Up @@ -296,12 +306,6 @@ const fn unsat_to_sat<const S: usize>(input: &[u64]) -> [Word; S] {
impl_limb_convert!(u64, 62, Word, Word::BITS as usize, S, input)
}

/// Compute the number of unsaturated limbs needed to represent a value with the given number of saturated limbs.
const fn unsat_nlimbs(mut sat_nlimbs: usize) -> usize {
sat_nlimbs /= (64 / Word::BITS) as usize;
sat_nlimbs + (sat_nlimbs * 2).div_ceil(64) + 1
}

/// `Uint`-like (62 * LIMBS)-bit integer type, whose variables store numbers in the two's complement code as arrays of
/// 62-bit limbs.
///
Expand Down
40 changes: 30 additions & 10 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,27 +138,47 @@ pub trait Integer:
}
}

/// Fixed-width integers.
pub trait FixedInteger: Bounded + ConditionallySelectable + Constants + Copy + Integer {
/// The number of limbs used on this platform.
const LIMBS: usize;
}

/// Obtain a precomputed inverter for efficiently computing modular inversions for a given modulus.
pub trait Inverter: Integer {
pub trait PrecomputeInverter {
/// Inverter type for integers of this size.
type Inverter: Sized;
type Inverter: Inverter<Output = Self::Output> + Sized;

/// Output produced by the inverter.
type Output;

/// Obtain a precomputed inverter for `&self` as the modulus, using `Self::one()` as an adjusting parameter.
///
/// Returns `None` if `self` is even.
fn inverter(&self) -> Self::Inverter {
Self::inverter_with_adjuster(self, &Self::one())
}
fn precompute_inverter(&self) -> Self::Inverter;

/// Obtain a precomputed inverter for `&self` as the modulus, supplying a custom adjusting parameter (e.g. R^2 for
/// when computing inversions in Montgomery form).
fn inverter_with_adjuster(&self, adjuster: &Self) -> Self::Inverter;
fn precompute_inverter_with_adjuster(&self, adjuster: &Self) -> Self::Inverter;
}

/// Fixed-width integers.
pub trait FixedInteger: Bounded + ConditionallySelectable + Constants + Copy + Integer {
/// The number of limbs used on this platform.
const LIMBS: usize;
/// Trait impl'd by precomputed modular inverters.
pub trait Inverter {
/// Output of an inversion.
type Output;

/// Compute a modular inversion, returning `None` if `value` is zero.
// TODO(tarcieri): return `CtOption` instead?
fn invert(&self, value: &Self::Output) -> Option<Self::Output>;

/// Compute a modular inversion of a non-zero input.
fn invert_nz(&self, value: &NonZero<Self::Output>) -> Self::Output
where
Self::Output: Zero,
{
self.invert(&value.0)
.expect("non-zero inputs are always invertable")
}
}

/// Zero values.
Expand Down
4 changes: 2 additions & 2 deletions src/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ pub(crate) mod boxed;
mod rand;

use crate::{
modular::BernsteinYangInverter, Bounded, Constants, Encoding, FixedInteger, Integer, Inverter,
Limb, Word, ZeroConstant,
modular::BernsteinYangInverter, Bounded, Constants, Encoding, FixedInteger, Integer, Limb,
PrecomputeInverter, Word, ZeroConstant,
};
use core::fmt;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
Expand Down
20 changes: 8 additions & 12 deletions src/uint/macros.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
//! Macros used to define traits on aliases of `Uint`.

/// Calculate the number of 62-bit unsaturated limbs required to represent the given number of bits when performing
/// Bernstein-Yang inversions.
// TODO(tarcieri): replace with `generic_const_exprs` (rust-lang/rust#76560) when stable
#[macro_export]
macro_rules! bernstein_yang_nlimbs {
($bits:expr) => {
(($bits / 64) + (($bits / 64) * 2).div_ceil(64) + 1)
};
}

/// Impl the `Inverter` trait, where we need to compute the number of unsaturated limbs for a given number of bits.
macro_rules! impl_inverter_trait {
($name:ident, $bits:expr) => {
impl Inverter for $name {
impl PrecomputeInverter for $name {
#[allow(trivial_numeric_casts)]
type Inverter = BernsteinYangInverter<
{ nlimbs!($bits) },
{ bernstein_yang_nlimbs!($bits as usize) },
>;

fn inverter_with_adjuster(&self, adjuster: &Self) -> Self::Inverter {
type Output = $name;

fn precompute_inverter(&self) -> Self::Inverter {
Self::precompute_inverter_with_adjuster(self, &Self::ONE)
}

fn precompute_inverter_with_adjuster(&self, adjuster: &Self) -> Self::Inverter {
Self::Inverter::new(self, adjuster)
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/bernstein_yang_proptests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Equivalence tests for Bernstein-Yang inversions.

use crypto_bigint::{Encoding, Inverter, U256};
use crypto_bigint::{Encoding, PrecomputeInverter, U256};
use num_bigint::BigUint;
use num_integer::Integer;
use num_traits::One;
Expand Down Expand Up @@ -32,7 +32,7 @@ proptest! {
let p_bi = to_biguint(&P);

let expected_is_some = x_bi.gcd(&p_bi) == BigUint::one();
let inverter = P.inverter();
let inverter = P.precompute_inverter();
let actual = inverter.invert(&x);

prop_assert_eq!(bool::from(expected_is_some), actual.is_some());
Expand Down