diff --git a/src/traits.rs b/src/traits.rs index 881b16466..a2e8da772 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -130,8 +130,10 @@ pub trait Integer: + Sized + Shl + ShlAssign + + ShlVartime + Shr + ShrAssign + + ShrVartime + Sub + for<'a> Sub<&'a Self, Output = Self> + SubMod @@ -563,6 +565,30 @@ pub trait WideningMul: Sized { fn widening_mul(&self, rhs: Rhs) -> Self::Output; } +/// Left shifts, variable time in `shift`. +pub trait ShlVartime: Sized { + /// Computes `self << shift`. + /// + /// Returns `None` if `shift >= self.bits_precision()`. + fn overflowing_shl_vartime(&self, shift: u32) -> CtOption; + + /// Computes `self << shift` in a panic-free manner, masking off bits of `shift` + /// which would cause the shift to exceed the type's width. + fn wrapping_shl_vartime(&self, shift: u32) -> Self; +} + +/// Right shifts, variable time in `shift`. +pub trait ShrVartime: Sized { + /// Computes `self >> shift`. + /// + /// Returns `None` if `shift >= self.bits_precision()`. + fn overflowing_shr_vartime(&self, shift: u32) -> CtOption; + + /// Computes `self >> shift` in a panic-free manner, masking off bits of `shift` + /// which would cause the shift to exceed the type's width. + fn wrapping_shr_vartime(&self, shift: u32) -> Self; +} + /// A representation of an integer optimized for the performance of modular operations. pub trait Monty: 'static diff --git a/src/uint/boxed/shl.rs b/src/uint/boxed/shl.rs index 44234d4dd..f4657f14d 100644 --- a/src/uint/boxed/shl.rs +++ b/src/uint/boxed/shl.rs @@ -1,8 +1,10 @@ //! [`BoxedUint`] bitwise left shift operations. -use crate::{BoxedUint, ConstChoice, ConstantTimeSelect, Limb, Word, WrappingShl, Zero}; +use crate::{ + BoxedUint, ConstChoice, ConstantTimeSelect, Limb, ShlVartime, Word, WrappingShl, Zero, +}; use core::ops::{Shl, ShlAssign}; -use subtle::{Choice, ConstantTimeLess}; +use subtle::{Choice, ConstantTimeLess, CtOption}; impl BoxedUint { /// Computes `self << shift`. @@ -214,6 +216,16 @@ impl WrappingShl for BoxedUint { } } +impl ShlVartime for BoxedUint { + fn overflowing_shl_vartime(&self, shift: u32) -> CtOption { + let (result, overflow) = self.overflowing_shl(shift); + CtOption::new(result, !overflow) + } + fn wrapping_shl_vartime(&self, shift: u32) -> Self { + self.wrapping_shl(shift) + } +} + #[cfg(test)] mod tests { use super::BoxedUint; diff --git a/src/uint/boxed/shr.rs b/src/uint/boxed/shr.rs index 283971255..84edd1148 100644 --- a/src/uint/boxed/shr.rs +++ b/src/uint/boxed/shr.rs @@ -1,8 +1,8 @@ //! [`BoxedUint`] bitwise right shift operations. -use crate::{BoxedUint, ConstantTimeSelect, Limb, WrappingShr, Zero}; +use crate::{BoxedUint, ConstantTimeSelect, Limb, ShrVartime, WrappingShr, Zero}; use core::ops::{Shr, ShrAssign}; -use subtle::{Choice, ConstantTimeLess}; +use subtle::{Choice, ConstantTimeLess, CtOption}; impl BoxedUint { /// Computes `self >> shift`. @@ -192,6 +192,16 @@ impl WrappingShr for BoxedUint { } } +impl ShrVartime for BoxedUint { + fn overflowing_shr_vartime(&self, shift: u32) -> CtOption { + let (result, overflow) = self.overflowing_shr(shift); + CtOption::new(result, !overflow) + } + fn wrapping_shr_vartime(&self, shift: u32) -> Self { + self.wrapping_shr(shift) + } +} + #[cfg(test)] mod tests { use super::BoxedUint; diff --git a/src/uint/shl.rs b/src/uint/shl.rs index 9d911fe3d..94e6f6e19 100644 --- a/src/uint/shl.rs +++ b/src/uint/shl.rs @@ -1,7 +1,8 @@ //! [`Uint`] bitwise left shift operations. -use crate::{ConstChoice, ConstCtOption, Limb, Uint, Word, WrappingShl}; +use crate::{ConstChoice, ConstCtOption, Limb, ShlVartime, Uint, Word, WrappingShl}; use core::ops::{Shl, ShlAssign}; +use subtle::CtOption; impl Uint { /// Computes `self << shift`. @@ -14,8 +15,7 @@ impl Uint { /// Computes `self << shift`. /// - /// If `shift >= Self::BITS`, returns zero as the first tuple element, - /// and `ConstChoice::TRUE` as the second element. + /// Returns `None` if `shift >= Self::BITS`. pub const fn overflowing_shl(&self, shift: u32) -> ConstCtOption { // `floor(log2(BITS - 1))` is the number of bits in the representation of `shift` // (which lies in range `0 <= shift < BITS`). @@ -41,8 +41,7 @@ impl Uint { /// Computes `self << shift`. /// - /// If `shift >= Self::BITS`, returns zero as the first tuple element, - /// and `ConstChoice::TRUE` as the second element. + /// Returns `None` if `shift >= Self::BITS`. /// /// NOTE: this operation is variable time with respect to `shift` *ONLY*. /// @@ -85,8 +84,7 @@ impl Uint { /// Computes a left shift on a wide input as `(lo, hi)`. /// - /// If `shift >= Self::BITS`, returns a tuple of zeros as the first element, - /// and `ConstChoice::TRUE` as the second element. + /// Returns `None` if `shift >= Self::BITS`. /// /// NOTE: this operation is variable time with respect to `shift` *ONLY*. /// @@ -218,6 +216,15 @@ impl WrappingShl for Uint { } } +impl ShlVartime for Uint { + fn overflowing_shl_vartime(&self, shift: u32) -> CtOption { + self.overflowing_shl(shift).into() + } + fn wrapping_shl_vartime(&self, shift: u32) -> Self { + self.wrapping_shl(shift) + } +} + #[cfg(test)] mod tests { use crate::{Limb, Uint, U128, U256}; diff --git a/src/uint/shr.rs b/src/uint/shr.rs index 5b5305ced..79fed69d3 100644 --- a/src/uint/shr.rs +++ b/src/uint/shr.rs @@ -1,7 +1,8 @@ //! [`Uint`] bitwise right shift operations. -use crate::{ConstChoice, ConstCtOption, Limb, Uint, WrappingShr}; +use crate::{ConstChoice, ConstCtOption, Limb, ShrVartime, Uint, WrappingShr}; use core::ops::{Shr, ShrAssign}; +use subtle::CtOption; impl Uint { /// Computes `self >> shift`. @@ -14,8 +15,7 @@ impl Uint { /// Computes `self >> shift`. /// - /// If `shift >= Self::BITS`, returns zero as the first tuple element, - /// and `ConstChoice::TRUE` as the second element. + /// Returns `None` if `shift >= Self::BITS`. pub const fn overflowing_shr(&self, shift: u32) -> ConstCtOption { // `floor(log2(BITS - 1))` is the number of bits in the representation of `shift` // (which lies in range `0 <= shift < BITS`). @@ -41,8 +41,7 @@ impl Uint { /// Computes `self >> shift`. /// - /// If `shift >= Self::BITS`, returns zero as the first tuple element, - /// and `ConstChoice::TRUE` as the second element. + /// Returns `None` if `shift >= Self::BITS`. /// /// NOTE: this operation is variable time with respect to `shift` *ONLY*. /// @@ -84,8 +83,7 @@ impl Uint { /// Computes a right shift on a wide input as `(lo, hi)`. /// - /// If `shift >= Self::BITS`, returns a tuple of zeros as the first element, - /// and `ConstChoice::TRUE` as the second element. + /// Returns `None` if `shift >= Self::BITS`. /// /// NOTE: this operation is variable time with respect to `shift` *ONLY*. /// @@ -193,6 +191,15 @@ impl WrappingShr for Uint { } } +impl ShrVartime for Uint { + fn overflowing_shr_vartime(&self, shift: u32) -> CtOption { + self.overflowing_shr(shift).into() + } + fn wrapping_shr_vartime(&self, shift: u32) -> Self { + self.wrapping_shr(shift) + } +} + #[cfg(test)] mod tests { use crate::{Uint, U128, U256};