Skip to content

Commit 6cedf62

Browse files
committed
Impl Wrapping* traits from num-traits
Until now we have used traits defined in this crate, primarily because many of these traits are predicates that return `bool` and in constant-time code we want those to return `Choice`/`CtOption`. `Wrapping*` is an example of the sort of trait we'd want to incorporate unchanged, and there are potentially others, so this adds `num-traits` as a hard dependency (previously our only hard dependency was `subtle`). Note that `num-traits` itself has no transitive dependencies (or rather, they're optional but not enabled). The `Wrapping*` traits have bounds on the corresponding op traits being impl'd with `Self` operands e.g. `WrappingAdd: Add<Self, Output = Self>` so this PR also adds impls of those traits. We've previously avoided these as in `std` they panic on overflow/underflow in debug builds and silently wrap in release builds. This PR always panics. This required some changes to the `Mul` impls which were conditional on `ConcatMixed` and implicitly widened. To accomodate impls which are always available and require no bounds (in order to allow us to impl `WideningMul`), and renames the following: - `Uint::mul` -> `Uint::widening_mul` - `Uint::mul_wide` -> `Uint::widening_mul_split`
1 parent d5c8dad commit 6cedf62

File tree

16 files changed

+268
-103
lines changed

16 files changed

+268
-103
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ subtle = { version = "2.5", default-features = false }
2222
# optional dependencies
2323
der = { version = "0.7", optional = true, default-features = false }
2424
generic-array = { version = "0.14", optional = true }
25+
num-traits = { version = "0.2", default-features = false }
2526
rand_core = { version = "0.6.4", optional = true }
2627
rlp = { version = "0.5", optional = true, default-features = false }
2728
serdect = { version = "0.2", optional = true, default-features = false }
@@ -33,7 +34,6 @@ criterion = { version = "0.5", features = ["html_reports"] }
3334
hex-literal = "0.4"
3435
num-bigint = { package = "num-bigint-dig", version = "0.8" }
3536
num-integer = "0.1"
36-
num-traits = "0.2"
3737
proptest = "1"
3838
rand_core = { version = "0.6", features = ["std"] }
3939
rand_chacha = "0.3"

src/modular.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ mod tests {
135135
// Reducing xR should return x
136136
let x =
137137
U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56");
138-
let product = x.mul_wide(&Modulus2::R);
138+
let product = x.widening_mul_split(&Modulus2::R);
139139
assert_eq!(
140140
montgomery_reduction::<{ Modulus2::LIMBS }>(
141141
&product,
@@ -151,10 +151,10 @@ mod tests {
151151
// Reducing xR^2 should return xR
152152
let x =
153153
U256::from_be_hex("44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56");
154-
let product = x.mul_wide(&Modulus2::R2);
154+
let product = x.widening_mul_split(&Modulus2::R2);
155155

156156
// Computing xR mod modulus without Montgomery reduction
157-
let (lo, hi) = x.mul_wide(&Modulus2::R);
157+
let (lo, hi) = x.widening_mul_split(&Modulus2::R);
158158
let c = hi.concat(&lo);
159159
let red = c.rem(&NonZero::new(U256::ZERO.concat(&Modulus2::MODULUS)).unwrap());
160160
let (hi, lo) = red.split();

src/modular/dyn_residue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ pub struct DynResidue<const LIMBS: usize> {
119119
impl<const LIMBS: usize> DynResidue<LIMBS> {
120120
/// Instantiates a new `Residue` that represents this `integer` mod `MOD`.
121121
pub const fn new(integer: &Uint<LIMBS>, residue_params: DynResidueParams<LIMBS>) -> Self {
122-
let product = integer.mul_wide(&residue_params.r2);
122+
let product = integer.widening_mul_split(&residue_params.r2);
123123
let montgomery_form = montgomery_reduction(
124124
&product,
125125
&residue_params.modulus,

src/modular/inv.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub const fn inv_montgomery_form<const LIMBS: usize>(
88
) -> (Uint<LIMBS>, ConstChoice) {
99
let (inverse, is_some) = x.inv_odd_mod(modulus);
1010
(
11-
montgomery_reduction(&inverse.mul_wide(r3), modulus, mod_neg_inv),
11+
montgomery_reduction(&inverse.widening_mul_split(r3), modulus, mod_neg_inv),
1212
is_some,
1313
)
1414
}

src/modular/mul.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub(crate) const fn mul_montgomery_form<const LIMBS: usize>(
88
modulus: &Uint<LIMBS>,
99
mod_neg_inv: Limb,
1010
) -> Uint<LIMBS> {
11-
let product = a.mul_wide(b);
11+
let product = a.widening_mul_split(b);
1212
montgomery_reduction::<LIMBS>(&product, modulus, mod_neg_inv)
1313
}
1414

src/modular/residue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
8484

8585
/// Internal helper function to generate a residue; this lets us cleanly wrap the constructors.
8686
const fn generate_residue(integer: &Uint<LIMBS>) -> Self {
87-
let product = integer.mul_wide(&MOD::R2);
87+
let product = integer.widening_mul_split(&MOD::R2);
8888
let montgomery_form =
8989
montgomery_reduction::<LIMBS>(&product, &MOD::MODULUS.0, MOD::MOD_NEG_INV);
9090

src/traits.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
//! Traits provided by this crate
22
3+
pub use num_traits::{
4+
WrappingAdd, WrappingMul, WrappingNeg, WrappingShl, WrappingShr, WrappingSub,
5+
};
6+
37
use crate::{Limb, NonZero};
48
use core::fmt::Debug;
59
use core::ops::{
@@ -71,6 +75,9 @@ pub trait Integer:
7175
+ ShrAssign<u32>
7276
+ SubMod
7377
+ Sync
78+
+ WrappingAdd
79+
+ WrappingSub
80+
+ WrappingMul
7481
+ Zero
7582
{
7683
/// The value `1`.

src/uint/add.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! [`Uint`] addition operations.
22
3-
use crate::{Checked, CheckedAdd, ConstChoice, Limb, Uint, Wrapping, Zero};
3+
use crate::{Checked, CheckedAdd, ConstChoice, Limb, Uint, Wrapping, WrappingAdd, Zero};
44
use core::ops::{Add, AddAssign};
55
use subtle::CtOption;
66

@@ -45,12 +45,20 @@ impl<const LIMBS: usize> Uint<LIMBS> {
4545
}
4646
}
4747

48-
impl<const LIMBS: usize> CheckedAdd<&Uint<LIMBS>> for Uint<LIMBS> {
48+
impl<const LIMBS: usize> Add for Uint<LIMBS> {
4949
type Output = Self;
5050

51-
fn checked_add(&self, rhs: &Self) -> CtOption<Self> {
52-
let (result, carry) = self.adc(rhs, Limb::ZERO);
53-
CtOption::new(result, carry.is_zero())
51+
fn add(self, rhs: Self) -> Self {
52+
self.add(&rhs)
53+
}
54+
}
55+
56+
impl<const LIMBS: usize> Add<&Uint<LIMBS>> for Uint<LIMBS> {
57+
type Output = Self;
58+
59+
fn add(self, rhs: &Self) -> Self {
60+
self.checked_add(rhs)
61+
.expect("attempted to add with overflow")
5462
}
5563
}
5664

@@ -154,6 +162,21 @@ impl<const LIMBS: usize> AddAssign<&Checked<Uint<LIMBS>>> for Checked<Uint<LIMBS
154162
}
155163
}
156164

165+
impl<const LIMBS: usize> CheckedAdd<&Uint<LIMBS>> for Uint<LIMBS> {
166+
type Output = Self;
167+
168+
fn checked_add(&self, rhs: &Self) -> CtOption<Self> {
169+
let (result, carry) = self.adc(rhs, Limb::ZERO);
170+
CtOption::new(result, carry.is_zero())
171+
}
172+
}
173+
174+
impl<const LIMBS: usize> WrappingAdd for Uint<LIMBS> {
175+
fn wrapping_add(&self, v: &Self) -> Self {
176+
self.wrapping_add(v)
177+
}
178+
}
179+
157180
#[cfg(test)]
158181
mod tests {
159182
use crate::{CheckedAdd, Limb, U128};

src/uint/boxed/add.rs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
//! [`BoxedUint`] addition operations.
22
3+
use crate::{BoxedUint, CheckedAdd, Limb, Wrapping, WrappingAdd, Zero};
34
use core::ops::{Add, AddAssign};
4-
5-
use crate::{BoxedUint, CheckedAdd, Limb, Wrapping, Zero};
65
use subtle::{Choice, ConditionallySelectable, CtOption};
76

87
impl BoxedUint {
@@ -51,12 +50,28 @@ impl BoxedUint {
5150
}
5251
}
5352

54-
impl CheckedAdd<&BoxedUint> for BoxedUint {
53+
impl Add for BoxedUint {
5554
type Output = Self;
5655

57-
fn checked_add(&self, rhs: &Self) -> CtOption<Self> {
58-
let (result, carry) = self.adc(rhs, Limb::ZERO);
59-
CtOption::new(result, carry.is_zero())
56+
fn add(self, rhs: Self) -> Self {
57+
self.add(&rhs)
58+
}
59+
}
60+
61+
impl Add<&BoxedUint> for BoxedUint {
62+
type Output = Self;
63+
64+
fn add(self, rhs: &Self) -> Self {
65+
Add::add(&self, rhs)
66+
}
67+
}
68+
69+
impl Add<&BoxedUint> for &BoxedUint {
70+
type Output = BoxedUint;
71+
72+
fn add(self, rhs: &BoxedUint) -> BoxedUint {
73+
self.checked_add(rhs)
74+
.expect("attempted to add with overflow")
6075
}
6176
}
6277

@@ -104,6 +119,21 @@ impl AddAssign<&Wrapping<BoxedUint>> for Wrapping<BoxedUint> {
104119
}
105120
}
106121

122+
impl CheckedAdd<&BoxedUint> for BoxedUint {
123+
type Output = Self;
124+
125+
fn checked_add(&self, rhs: &Self) -> CtOption<Self> {
126+
let (result, carry) = self.adc(rhs, Limb::ZERO);
127+
CtOption::new(result, carry.is_zero())
128+
}
129+
}
130+
131+
impl WrappingAdd for BoxedUint {
132+
fn wrapping_add(&self, v: &Self) -> Self {
133+
self.wrapping_add(v)
134+
}
135+
}
136+
107137
#[cfg(test)]
108138
#[allow(clippy::unwrap_used)]
109139
mod tests {

src/uint/boxed/mul.rs

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! [`BoxedUint`] multiplication operations.
22
3-
use crate::{uint::mul::mul_limbs, BoxedUint, CheckedMul, Limb, WideningMul, Wrapping, Zero};
3+
use crate::{
4+
uint::mul::mul_limbs, BoxedUint, CheckedMul, Limb, WideningMul, Wrapping, WrappingMul, Zero,
5+
};
46
use core::ops::{Mul, MulAssign};
57
use subtle::{Choice, CtOption};
68

@@ -51,21 +53,36 @@ impl CheckedMul<&BoxedUint> for BoxedUint {
5153
}
5254
}
5355

54-
impl WideningMul for BoxedUint {
55-
type Output = Self;
56+
impl Mul<BoxedUint> for BoxedUint {
57+
type Output = BoxedUint;
5658

57-
#[inline]
58-
fn widening_mul(&self, rhs: BoxedUint) -> Self {
59-
self.mul(&rhs)
59+
fn mul(self, rhs: BoxedUint) -> Self {
60+
BoxedUint::mul(&self, &rhs)
6061
}
6162
}
6263

63-
impl WideningMul<&BoxedUint> for BoxedUint {
64-
type Output = Self;
64+
impl Mul<&BoxedUint> for BoxedUint {
65+
type Output = BoxedUint;
6566

66-
#[inline]
67-
fn widening_mul(&self, rhs: &BoxedUint) -> Self {
68-
self.mul(rhs)
67+
fn mul(self, rhs: &BoxedUint) -> Self {
68+
BoxedUint::mul(&self, rhs)
69+
}
70+
}
71+
72+
impl Mul<BoxedUint> for &BoxedUint {
73+
type Output = BoxedUint;
74+
75+
fn mul(self, rhs: BoxedUint) -> Self::Output {
76+
BoxedUint::mul(self, &rhs)
77+
}
78+
}
79+
80+
impl Mul<&BoxedUint> for &BoxedUint {
81+
type Output = BoxedUint;
82+
83+
fn mul(self, rhs: &BoxedUint) -> Self::Output {
84+
self.checked_mul(rhs)
85+
.expect("attempted to multiply with overflow")
6986
}
7087
}
7188

@@ -113,6 +130,30 @@ impl MulAssign<&Wrapping<BoxedUint>> for Wrapping<BoxedUint> {
113130
}
114131
}
115132

133+
impl WideningMul for BoxedUint {
134+
type Output = Self;
135+
136+
#[inline]
137+
fn widening_mul(&self, rhs: BoxedUint) -> Self {
138+
self.mul(&rhs)
139+
}
140+
}
141+
142+
impl WideningMul<&BoxedUint> for BoxedUint {
143+
type Output = Self;
144+
145+
#[inline]
146+
fn widening_mul(&self, rhs: &BoxedUint) -> Self {
147+
self.mul(rhs)
148+
}
149+
}
150+
151+
impl WrappingMul for BoxedUint {
152+
fn wrapping_mul(&self, v: &Self) -> Self {
153+
self.wrapping_mul(v)
154+
}
155+
}
156+
116157
#[cfg(test)]
117158
mod tests {
118159
use crate::BoxedUint;

0 commit comments

Comments
 (0)