Skip to content

Commit f2dde0d

Browse files
authored
Add ShrVartime and ShlVartime traits (#509)
1 parent 1e7cb73 commit f2dde0d

File tree

5 files changed

+80
-18
lines changed

5 files changed

+80
-18
lines changed

src/traits.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,10 @@ pub trait Integer:
130130
+ Sized
131131
+ Shl<u32, Output = Self>
132132
+ ShlAssign<u32>
133+
+ ShlVartime
133134
+ Shr<u32, Output = Self>
134135
+ ShrAssign<u32>
136+
+ ShrVartime
135137
+ Sub<Output = Self>
136138
+ for<'a> Sub<&'a Self, Output = Self>
137139
+ SubMod<Output = Self>
@@ -563,6 +565,30 @@ pub trait WideningMul<Rhs = Self>: Sized {
563565
fn widening_mul(&self, rhs: Rhs) -> Self::Output;
564566
}
565567

568+
/// Left shifts, variable time in `shift`.
569+
pub trait ShlVartime: Sized {
570+
/// Computes `self << shift`.
571+
///
572+
/// Returns `None` if `shift >= self.bits_precision()`.
573+
fn overflowing_shl_vartime(&self, shift: u32) -> CtOption<Self>;
574+
575+
/// Computes `self << shift` in a panic-free manner, masking off bits of `shift`
576+
/// which would cause the shift to exceed the type's width.
577+
fn wrapping_shl_vartime(&self, shift: u32) -> Self;
578+
}
579+
580+
/// Right shifts, variable time in `shift`.
581+
pub trait ShrVartime: Sized {
582+
/// Computes `self >> shift`.
583+
///
584+
/// Returns `None` if `shift >= self.bits_precision()`.
585+
fn overflowing_shr_vartime(&self, shift: u32) -> CtOption<Self>;
586+
587+
/// Computes `self >> shift` in a panic-free manner, masking off bits of `shift`
588+
/// which would cause the shift to exceed the type's width.
589+
fn wrapping_shr_vartime(&self, shift: u32) -> Self;
590+
}
591+
566592
/// A representation of an integer optimized for the performance of modular operations.
567593
pub trait Monty:
568594
'static

src/uint/boxed/shl.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//! [`BoxedUint`] bitwise left shift operations.
22
3-
use crate::{BoxedUint, ConstChoice, ConstantTimeSelect, Limb, Word, WrappingShl, Zero};
3+
use crate::{
4+
BoxedUint, ConstChoice, ConstantTimeSelect, Limb, ShlVartime, Word, WrappingShl, Zero,
5+
};
46
use core::ops::{Shl, ShlAssign};
5-
use subtle::{Choice, ConstantTimeLess};
7+
use subtle::{Choice, ConstantTimeLess, CtOption};
68

79
impl BoxedUint {
810
/// Computes `self << shift`.
@@ -214,6 +216,16 @@ impl WrappingShl for BoxedUint {
214216
}
215217
}
216218

219+
impl ShlVartime for BoxedUint {
220+
fn overflowing_shl_vartime(&self, shift: u32) -> CtOption<Self> {
221+
let (result, overflow) = self.overflowing_shl(shift);
222+
CtOption::new(result, !overflow)
223+
}
224+
fn wrapping_shl_vartime(&self, shift: u32) -> Self {
225+
self.wrapping_shl(shift)
226+
}
227+
}
228+
217229
#[cfg(test)]
218230
mod tests {
219231
use super::BoxedUint;

src/uint/boxed/shr.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! [`BoxedUint`] bitwise right shift operations.
22
3-
use crate::{BoxedUint, ConstantTimeSelect, Limb, WrappingShr, Zero};
3+
use crate::{BoxedUint, ConstantTimeSelect, Limb, ShrVartime, WrappingShr, Zero};
44
use core::ops::{Shr, ShrAssign};
5-
use subtle::{Choice, ConstantTimeLess};
5+
use subtle::{Choice, ConstantTimeLess, CtOption};
66

77
impl BoxedUint {
88
/// Computes `self >> shift`.
@@ -192,6 +192,16 @@ impl WrappingShr for BoxedUint {
192192
}
193193
}
194194

195+
impl ShrVartime for BoxedUint {
196+
fn overflowing_shr_vartime(&self, shift: u32) -> CtOption<Self> {
197+
let (result, overflow) = self.overflowing_shr(shift);
198+
CtOption::new(result, !overflow)
199+
}
200+
fn wrapping_shr_vartime(&self, shift: u32) -> Self {
201+
self.wrapping_shr(shift)
202+
}
203+
}
204+
195205
#[cfg(test)]
196206
mod tests {
197207
use super::BoxedUint;

src/uint/shl.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! [`Uint`] bitwise left shift operations.
22
3-
use crate::{ConstChoice, ConstCtOption, Limb, Uint, Word, WrappingShl};
3+
use crate::{ConstChoice, ConstCtOption, Limb, ShlVartime, Uint, Word, WrappingShl};
44
use core::ops::{Shl, ShlAssign};
5+
use subtle::CtOption;
56

67
impl<const LIMBS: usize> Uint<LIMBS> {
78
/// Computes `self << shift`.
@@ -14,8 +15,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {
1415

1516
/// Computes `self << shift`.
1617
///
17-
/// If `shift >= Self::BITS`, returns zero as the first tuple element,
18-
/// and `ConstChoice::TRUE` as the second element.
18+
/// Returns `None` if `shift >= Self::BITS`.
1919
pub const fn overflowing_shl(&self, shift: u32) -> ConstCtOption<Self> {
2020
// `floor(log2(BITS - 1))` is the number of bits in the representation of `shift`
2121
// (which lies in range `0 <= shift < BITS`).
@@ -41,8 +41,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {
4141

4242
/// Computes `self << shift`.
4343
///
44-
/// If `shift >= Self::BITS`, returns zero as the first tuple element,
45-
/// and `ConstChoice::TRUE` as the second element.
44+
/// Returns `None` if `shift >= Self::BITS`.
4645
///
4746
/// NOTE: this operation is variable time with respect to `shift` *ONLY*.
4847
///
@@ -85,8 +84,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {
8584

8685
/// Computes a left shift on a wide input as `(lo, hi)`.
8786
///
88-
/// If `shift >= Self::BITS`, returns a tuple of zeros as the first element,
89-
/// and `ConstChoice::TRUE` as the second element.
87+
/// Returns `None` if `shift >= Self::BITS`.
9088
///
9189
/// NOTE: this operation is variable time with respect to `shift` *ONLY*.
9290
///
@@ -218,6 +216,15 @@ impl<const LIMBS: usize> WrappingShl for Uint<LIMBS> {
218216
}
219217
}
220218

219+
impl<const LIMBS: usize> ShlVartime for Uint<LIMBS> {
220+
fn overflowing_shl_vartime(&self, shift: u32) -> CtOption<Self> {
221+
self.overflowing_shl(shift).into()
222+
}
223+
fn wrapping_shl_vartime(&self, shift: u32) -> Self {
224+
self.wrapping_shl(shift)
225+
}
226+
}
227+
221228
#[cfg(test)]
222229
mod tests {
223230
use crate::{Limb, Uint, U128, U256};

src/uint/shr.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! [`Uint`] bitwise right shift operations.
22
3-
use crate::{ConstChoice, ConstCtOption, Limb, Uint, WrappingShr};
3+
use crate::{ConstChoice, ConstCtOption, Limb, ShrVartime, Uint, WrappingShr};
44
use core::ops::{Shr, ShrAssign};
5+
use subtle::CtOption;
56

67
impl<const LIMBS: usize> Uint<LIMBS> {
78
/// Computes `self >> shift`.
@@ -14,8 +15,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {
1415

1516
/// Computes `self >> shift`.
1617
///
17-
/// If `shift >= Self::BITS`, returns zero as the first tuple element,
18-
/// and `ConstChoice::TRUE` as the second element.
18+
/// Returns `None` if `shift >= Self::BITS`.
1919
pub const fn overflowing_shr(&self, shift: u32) -> ConstCtOption<Self> {
2020
// `floor(log2(BITS - 1))` is the number of bits in the representation of `shift`
2121
// (which lies in range `0 <= shift < BITS`).
@@ -41,8 +41,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {
4141

4242
/// Computes `self >> shift`.
4343
///
44-
/// If `shift >= Self::BITS`, returns zero as the first tuple element,
45-
/// and `ConstChoice::TRUE` as the second element.
44+
/// Returns `None` if `shift >= Self::BITS`.
4645
///
4746
/// NOTE: this operation is variable time with respect to `shift` *ONLY*.
4847
///
@@ -84,8 +83,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {
8483

8584
/// Computes a right shift on a wide input as `(lo, hi)`.
8685
///
87-
/// If `shift >= Self::BITS`, returns a tuple of zeros as the first element,
88-
/// and `ConstChoice::TRUE` as the second element.
86+
/// Returns `None` if `shift >= Self::BITS`.
8987
///
9088
/// NOTE: this operation is variable time with respect to `shift` *ONLY*.
9189
///
@@ -193,6 +191,15 @@ impl<const LIMBS: usize> WrappingShr for Uint<LIMBS> {
193191
}
194192
}
195193

194+
impl<const LIMBS: usize> ShrVartime for Uint<LIMBS> {
195+
fn overflowing_shr_vartime(&self, shift: u32) -> CtOption<Self> {
196+
self.overflowing_shr(shift).into()
197+
}
198+
fn wrapping_shr_vartime(&self, shift: u32) -> Self {
199+
self.wrapping_shr(shift)
200+
}
201+
}
202+
196203
#[cfg(test)]
197204
mod tests {
198205
use crate::{Uint, U128, U256};

0 commit comments

Comments
 (0)