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
26 changes: 26 additions & 0 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,10 @@ pub trait Integer:
+ Sized
+ Shl<u32, Output = Self>
+ ShlAssign<u32>
+ ShlVartime
+ Shr<u32, Output = Self>
+ ShrAssign<u32>
+ ShrVartime
+ Sub<Output = Self>
+ for<'a> Sub<&'a Self, Output = Self>
+ SubMod<Output = Self>
Expand Down Expand Up @@ -563,6 +565,30 @@ pub trait WideningMul<Rhs = Self>: 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<Self>;

/// 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<Self>;

/// 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
Expand Down
16 changes: 14 additions & 2 deletions src/uint/boxed/shl.rs
Original file line number Diff line number Diff line change
@@ -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`.
Expand Down Expand Up @@ -214,6 +216,16 @@ impl WrappingShl for BoxedUint {
}
}

impl ShlVartime for BoxedUint {
fn overflowing_shl_vartime(&self, shift: u32) -> CtOption<Self> {
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;
Expand Down
14 changes: 12 additions & 2 deletions src/uint/boxed/shr.rs
Original file line number Diff line number Diff line change
@@ -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`.
Expand Down Expand Up @@ -192,6 +192,16 @@ impl WrappingShr for BoxedUint {
}
}

impl ShrVartime for BoxedUint {
fn overflowing_shr_vartime(&self, shift: u32) -> CtOption<Self> {
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;
Expand Down
21 changes: 14 additions & 7 deletions src/uint/shl.rs
Original file line number Diff line number Diff line change
@@ -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<const LIMBS: usize> Uint<LIMBS> {
/// Computes `self << shift`.
Expand All @@ -14,8 +15,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// 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<Self> {
// `floor(log2(BITS - 1))` is the number of bits in the representation of `shift`
// (which lies in range `0 <= shift < BITS`).
Expand All @@ -41,8 +41,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// 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*.
///
Expand Down Expand Up @@ -85,8 +84,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// 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*.
///
Expand Down Expand Up @@ -218,6 +216,15 @@ impl<const LIMBS: usize> WrappingShl for Uint<LIMBS> {
}
}

impl<const LIMBS: usize> ShlVartime for Uint<LIMBS> {
fn overflowing_shl_vartime(&self, shift: u32) -> CtOption<Self> {
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};
Expand Down
21 changes: 14 additions & 7 deletions src/uint/shr.rs
Original file line number Diff line number Diff line change
@@ -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<const LIMBS: usize> Uint<LIMBS> {
/// Computes `self >> shift`.
Expand All @@ -14,8 +15,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// 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<Self> {
// `floor(log2(BITS - 1))` is the number of bits in the representation of `shift`
// (which lies in range `0 <= shift < BITS`).
Expand All @@ -41,8 +41,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// 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*.
///
Expand Down Expand Up @@ -84,8 +83,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// 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*.
///
Expand Down Expand Up @@ -193,6 +191,15 @@ impl<const LIMBS: usize> WrappingShr for Uint<LIMBS> {
}
}

impl<const LIMBS: usize> ShrVartime for Uint<LIMBS> {
fn overflowing_shr_vartime(&self, shift: u32) -> CtOption<Self> {
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};
Expand Down