Skip to content

Commit 7052861

Browse files
authored
Runtime moduli (#134)
Extends #130 by adding residues for moduli decided at run-time.
1 parent 5b2e903 commit 7052861

15 files changed

+328
-50
lines changed

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@
109109
//! assert_eq!(b, U256::ZERO);
110110
//! ```
111111
//!
112-
//! It also supports modular arithmetic over constant moduli using `Residue`.
112+
//! It also supports modular arithmetic over constant moduli using `Residue`,
113+
//! and over moduli set at runtime using `DynResidue`.
113114
//! That includes modular exponentiation and multiplicative inverses.
114115
//! These features are described in the [`modular`] module.
115116
//!

src/uint/modular/add.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
use crate::UInt;
22

3-
pub trait AddResidue {
4-
/// Computes the (reduced) sum of two residues.
5-
fn add(&self, rhs: &Self) -> Self;
6-
}
7-
83
pub(crate) const fn add_montgomery_form<const LIMBS: usize>(
94
a: &UInt<LIMBS>,
105
b: &UInt<LIMBS>,

src/uint/modular/constant_mod/const_add.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use core::ops::AddAssign;
22

33
use crate::{
4-
modular::add::{add_montgomery_form, AddResidue},
4+
modular::{add::add_montgomery_form, AddResidue},
55
UInt,
66
};
77

src/uint/modular/constant_mod/const_inv.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use core::marker::PhantomData;
33
use subtle::{Choice, CtOption};
44

55
use crate::{
6-
modular::inv::{inv_montgomery_form, InvResidue},
6+
modular::{inv::inv_montgomery_form, InvResidue},
77
Word,
88
};
99

src/uint/modular/constant_mod/const_mul.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ use core::{
33
ops::{Mul, MulAssign},
44
};
55

6-
use crate::modular::{
7-
mul::{mul_montgomery_form, MulResidue},
8-
reduction::montgomery_reduction,
9-
};
6+
use crate::modular::{mul::mul_montgomery_form, reduction::montgomery_reduction, MulResidue};
107

118
use super::{Residue, ResidueParams};
129

src/uint/modular/constant_mod/const_pow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
modular::pow::{pow_montgomery_form, PowResidue},
2+
modular::{pow::pow_montgomery_form, PowResidue},
33
UInt, Word,
44
};
55

src/uint/modular/inv.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
1-
use subtle::CtOption;
2-
31
use crate::{modular::reduction::montgomery_reduction, Limb, UInt, Word};
42

5-
pub trait InvResidue
6-
where
7-
Self: Sized,
8-
{
9-
/// Computes the (reduced) multiplicative inverse of the residue. Returns CtOption, which is None if the residue was not invertible.
10-
fn inv(self) -> CtOption<Self>;
11-
}
12-
133
pub const fn inv_montgomery_form<const LIMBS: usize>(
144
x: UInt<LIMBS>,
155
modulus: UInt<LIMBS>,

src/uint/modular/mod.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,62 @@
1-
use crate::UInt;
1+
use subtle::CtOption;
22

3-
use self::{add::AddResidue, inv::InvResidue, mul::MulResidue, pow::PowResidue};
3+
use crate::{UInt, Word};
44

55
mod reduction;
66

77
/// Implements `Residue`s, supporting modular arithmetic with a constant modulus.
88
pub mod constant_mod;
9+
/// Implements `DynResidue`s, supporting modular arithmetic with a modulus set at runtime.
10+
pub mod runtime_mod;
911

1012
mod add;
1113
mod inv;
1214
mod mul;
1315
mod pow;
1416

17+
/// Provides a consistent interface to add two residues of the same type together.
18+
pub trait AddResidue {
19+
/// Computes the (reduced) sum of two residues.
20+
fn add(&self, rhs: &Self) -> Self;
21+
}
22+
23+
/// Provides a consistent interface to multiply two residues of the same type together.
24+
pub trait MulResidue
25+
where
26+
Self: Sized,
27+
{
28+
/// Computes the (reduced) product of two residues.
29+
fn mul(&self, rhs: &Self) -> Self;
30+
31+
/// Computes the same as `self.mul(self)`, but may be more efficient.
32+
fn square(&self) -> Self {
33+
self.mul(self)
34+
}
35+
}
36+
37+
/// Provides a consistent interface to exponentiate a residue.
38+
pub trait PowResidue<const LIMBS: usize>
39+
where
40+
Self: Sized,
41+
{
42+
/// Computes the (reduced) exponentiation of a residue.
43+
fn pow(self, exponent: &UInt<LIMBS>) -> Self {
44+
self.pow_specific(exponent, LIMBS * Word::BITS as usize)
45+
}
46+
47+
/// Computes the (reduced) exponentiation of a residue, here `exponent_bits` represents the number of bits to take into account for the exponent. Note that this value is leaked in the time pattern.
48+
fn pow_specific(self, exponent: &UInt<LIMBS>, exponent_bits: usize) -> Self;
49+
}
50+
51+
/// Provides a consistent interface to invert a residue.
52+
pub trait InvResidue
53+
where
54+
Self: Sized,
55+
{
56+
/// Computes the (reduced) multiplicative inverse of the residue. Returns CtOption, which is `None` if the residue was not invertible.
57+
fn inv(self) -> CtOption<Self>;
58+
}
59+
1560
/// The `GenericResidue` trait provides a consistent API for dealing with residues with a constant modulus.
1661
pub trait GenericResidue<const LIMBS: usize>:
1762
AddResidue + MulResidue + PowResidue<LIMBS> + InvResidue

src/uint/modular/mul.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,6 @@ use crate::{Limb, UInt};
22

33
use super::reduction::montgomery_reduction;
44

5-
pub trait MulResidue
6-
where
7-
Self: Sized,
8-
{
9-
/// Computes the (reduced) product of two residues.
10-
fn mul(&self, rhs: &Self) -> Self;
11-
12-
fn square(&self) -> Self {
13-
self.mul(self)
14-
}
15-
}
16-
175
pub(crate) const fn mul_montgomery_form<const LIMBS: usize>(
186
a: &UInt<LIMBS>,
197
b: &UInt<LIMBS>,

src/uint/modular/pow.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,6 @@ use crate::{Limb, UInt, Word};
22

33
use super::mul::{mul_montgomery_form, square_montgomery_form};
44

5-
pub trait PowResidue<const LIMBS: usize>
6-
where
7-
Self: Sized,
8-
{
9-
/// Computes the (reduced) exponentiation of a residue.
10-
fn pow(self, exponent: &UInt<LIMBS>) -> Self {
11-
self.pow_specific(exponent, LIMBS * Word::BITS as usize)
12-
}
13-
14-
/// Computes the (reduced) exponentiation of a residue, here `exponent_bits` represents the number of bits to take into account for the exponent. Note that this value is leaked in the time pattern.
15-
fn pow_specific(self, exponent: &UInt<LIMBS>, exponent_bits: usize) -> Self;
16-
}
17-
185
/// Performs modular exponentiation using Montgomery's ladder. `exponent_bits` represents the number of bits to take into account for the exponent. Note that this value is leaked in the time pattern.
196
pub const fn pow_montgomery_form<const LIMBS: usize>(
207
x: UInt<LIMBS>,

src/uint/modular/runtime_mod/mod.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use crate::{Limb, UInt, Word};
2+
3+
use super::{reduction::montgomery_reduction, GenericResidue};
4+
5+
/// Additions between residues with a modulus set at runtime
6+
mod runtime_add;
7+
/// Multiplicative inverses of residues with a modulus set at runtime
8+
mod runtime_inv;
9+
/// Multiplications between residues with a modulus set at runtime
10+
mod runtime_mul;
11+
/// Exponentiation of residues with a modulus set at runtime
12+
mod runtime_pow;
13+
14+
/// The parameters to efficiently go to and from the Montgomery form for a modulus provided at runtime.
15+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16+
pub struct DynResidueParams<const LIMBS: usize> {
17+
// The constant modulus
18+
modulus: UInt<LIMBS>,
19+
// Parameter used in Montgomery reduction
20+
r: UInt<LIMBS>,
21+
// R^2, used to move into Montgomery form
22+
r2: UInt<LIMBS>,
23+
// R^3, used to compute the multiplicative inverse
24+
r3: UInt<LIMBS>,
25+
// The lowest limbs of -(MODULUS^-1) mod R
26+
// We only need the LSB because during reduction this value is multiplied modulo 2**64.
27+
mod_neg_inv: Limb,
28+
}
29+
30+
impl<const LIMBS: usize> DynResidueParams<LIMBS> {
31+
/// Instantiates a new set of `ResidueParams` representing the given `modulus`.
32+
pub fn new(modulus: UInt<LIMBS>) -> Self {
33+
let r = UInt::MAX.ct_reduce(&modulus).0.wrapping_add(&UInt::ONE);
34+
let r2 = UInt::ct_reduce_wide(r.square_wide(), &modulus).0;
35+
let mod_neg_inv =
36+
Limb(Word::MIN.wrapping_sub(modulus.inv_mod2k(Word::BITS as usize).limbs[0].0));
37+
let r3 = montgomery_reduction(r2.square_wide(), modulus, mod_neg_inv);
38+
39+
Self {
40+
modulus,
41+
r,
42+
r2,
43+
r3,
44+
mod_neg_inv,
45+
}
46+
}
47+
}
48+
49+
/// A residue represented using `LIMBS` limbs. The odd modulus of this residue is set at runtime.
50+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51+
pub struct DynResidue<const LIMBS: usize> {
52+
montgomery_form: UInt<LIMBS>,
53+
residue_params: DynResidueParams<LIMBS>,
54+
}
55+
56+
impl<const LIMBS: usize> DynResidue<LIMBS> {
57+
/// Instantiates a new `Residue` that represents this `integer` mod `MOD`.
58+
pub const fn new(integer: UInt<LIMBS>, residue_params: DynResidueParams<LIMBS>) -> Self {
59+
let mut modular_integer = Self {
60+
montgomery_form: integer,
61+
residue_params,
62+
};
63+
64+
let product = integer.mul_wide(&residue_params.r2);
65+
modular_integer.montgomery_form =
66+
montgomery_reduction(product, residue_params.modulus, residue_params.mod_neg_inv);
67+
68+
modular_integer
69+
}
70+
71+
/// Retrieves the integer currently encoded in this `Residue`, guaranteed to be reduced.
72+
pub const fn retrieve(&self) -> UInt<LIMBS> {
73+
montgomery_reduction(
74+
(self.montgomery_form, UInt::ZERO),
75+
self.residue_params.modulus,
76+
self.residue_params.mod_neg_inv,
77+
)
78+
}
79+
}
80+
81+
impl<const LIMBS: usize> GenericResidue<LIMBS> for DynResidue<LIMBS> {
82+
fn retrieve(&self) -> UInt<LIMBS> {
83+
self.retrieve()
84+
}
85+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
use core::ops::{Add, AddAssign};
2+
3+
use crate::{
4+
modular::{add::add_montgomery_form, AddResidue},
5+
UInt,
6+
};
7+
8+
use super::DynResidue;
9+
10+
impl<const LIMBS: usize> AddResidue for DynResidue<LIMBS> {
11+
fn add(&self, rhs: &Self) -> Self {
12+
debug_assert_eq!(self.residue_params, rhs.residue_params);
13+
Self {
14+
montgomery_form: add_montgomery_form(
15+
&self.montgomery_form,
16+
&rhs.montgomery_form,
17+
&self.residue_params.modulus,
18+
),
19+
residue_params: self.residue_params,
20+
}
21+
}
22+
}
23+
24+
impl<const LIMBS: usize> AddAssign for DynResidue<LIMBS> {
25+
fn add_assign(&mut self, rhs: Self) {
26+
self.montgomery_form = add_montgomery_form(
27+
&self.montgomery_form,
28+
&rhs.montgomery_form,
29+
&self.residue_params.modulus,
30+
);
31+
}
32+
}
33+
34+
impl<const LIMBS: usize> AddAssign<UInt<LIMBS>> for DynResidue<LIMBS> {
35+
fn add_assign(&mut self, rhs: UInt<LIMBS>) {
36+
self.montgomery_form = add_montgomery_form(
37+
&self.montgomery_form,
38+
&DynResidue::new(rhs, self.residue_params).montgomery_form,
39+
&self.residue_params.modulus,
40+
);
41+
}
42+
}
43+
44+
impl<const LIMBS: usize> Add for DynResidue<LIMBS> {
45+
type Output = DynResidue<LIMBS>;
46+
47+
fn add(mut self, rhs: Self) -> Self::Output {
48+
self += rhs;
49+
self
50+
}
51+
}
52+
53+
#[cfg(test)]
54+
mod tests {
55+
use crate::{
56+
modular::runtime_mod::{DynResidue, DynResidueParams},
57+
U256,
58+
};
59+
60+
#[test]
61+
fn add_overflow() {
62+
let params = DynResidueParams::new(U256::from_be_hex(
63+
"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
64+
));
65+
66+
let x =
67+
U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56");
68+
let mut x_mod = DynResidue::new(x, params);
69+
70+
let y =
71+
U256::from_be_hex("d5777c45019673125ad240f83094d4252d829516fac8601ed01979ec1ec1a251");
72+
73+
x_mod += y;
74+
75+
let expected =
76+
U256::from_be_hex("1a2472fde50286541d97ca6a3592dd75beb9c9646e40c511b82496cfc3926956");
77+
78+
assert_eq!(expected, x_mod.retrieve());
79+
}
80+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use subtle::{Choice, CtOption};
2+
3+
use crate::{
4+
modular::{inv::inv_montgomery_form, InvResidue},
5+
Word,
6+
};
7+
8+
use super::DynResidue;
9+
10+
impl<const LIMBS: usize> InvResidue for DynResidue<LIMBS> {
11+
fn inv(self) -> CtOption<Self> {
12+
let (montgomery_form, error) = inv_montgomery_form(
13+
self.montgomery_form,
14+
self.residue_params.modulus,
15+
&self.residue_params.r3,
16+
self.residue_params.mod_neg_inv,
17+
);
18+
19+
let value = Self {
20+
montgomery_form,
21+
residue_params: self.residue_params,
22+
};
23+
24+
CtOption::new(value, Choice::from((error == Word::MAX) as u8))
25+
}
26+
}

0 commit comments

Comments
 (0)