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
2 changes: 1 addition & 1 deletion ctutils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,4 @@ mod traits;

pub use choice::Choice;
pub use ct_option::CtOption;
pub use traits::{ct_eq::CtEq, ct_select::CtSelect};
pub use traits::{ct_eq::CtEq, ct_gt::CtGt, ct_lt::CtLt, ct_select::CtSelect};
2 changes: 2 additions & 0 deletions ctutils/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
//! on in the same module.

pub(crate) mod ct_eq;
pub(crate) mod ct_gt;
pub(crate) mod ct_lt;
pub(crate) mod ct_select;
57 changes: 57 additions & 0 deletions ctutils/src/traits/ct_gt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use crate::Choice;
use core::cmp;

/// Constant time greater than operation.
pub trait CtGt {
/// Compute whether `self > other` in constant time.
fn ct_gt(&self, other: &Self) -> Choice;
}

// Impl `CtGt` using overflowing subtraction
macro_rules! impl_unsigned_ct_gt {
( $($uint:ty),+ ) => {
$(
impl CtGt for $uint {
#[inline]
fn ct_gt(&self, other: &Self) -> Choice {
let (_, overflow) = other.overflowing_sub(*self);
Choice::new(overflow.into())
}
}
)+
};
}

impl_unsigned_ct_gt!(u8, u16, u32, u64, u128);

impl CtGt for cmp::Ordering {
#[inline]
fn ct_gt(&self, other: &Self) -> Choice {
// No impl of `CtGt` for `i8`, so use `u8`
let a = (*self as i8) + 1;
let b = (*other as i8) + 1;
(a as u8).ct_gt(&(b as u8))
}
}

#[cfg(test)]
mod tests {
use super::CtGt;
use core::cmp::Ordering;

#[test]
fn ct_gt() {
let a = 42u64;
let b = 43u64;
assert!(!a.ct_gt(&a).to_bool());
assert!(!a.ct_gt(&b).to_bool());
assert!(b.ct_gt(&a).to_bool());
}

#[test]
fn ordering() {
assert!(!Ordering::Equal.ct_gt(&Ordering::Equal).to_bool());
assert!(!Ordering::Less.ct_gt(&Ordering::Greater).to_bool());
assert!(Ordering::Greater.ct_gt(&Ordering::Less).to_bool());
}
}
57 changes: 57 additions & 0 deletions ctutils/src/traits/ct_lt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use crate::Choice;
use core::cmp;

/// Constant time less than operation.
pub trait CtLt {
/// Compute whether `self < other` in constant time.
fn ct_lt(&self, other: &Self) -> Choice;
}

// Impl `CtLt` using overflowing subtraction
macro_rules! impl_unsigned_ct_lt {
( $($uint:ty),+ ) => {
$(
impl CtLt for $uint {
#[inline]
fn ct_lt(&self, other: &Self) -> Choice {
let (_, overflow) = self.overflowing_sub(*other);
Choice::new(overflow.into())
}
}
)+
};
}

impl_unsigned_ct_lt!(u8, u16, u32, u64, u128);

impl CtLt for cmp::Ordering {
#[inline]
fn ct_lt(&self, other: &Self) -> Choice {
// No impl of `CtLt` for `i8`, so use `u8`
let a = (*self as i8) + 1;
let b = (*other as i8) + 1;
(a as u8).ct_lt(&(b as u8))
}
}

#[cfg(test)]
mod tests {
use super::CtLt;
use core::cmp::Ordering;

#[test]
fn ct_lt() {
let a = 42u64;
let b = 43u64;
assert!(!a.ct_lt(&a).to_bool());
assert!(a.ct_lt(&b).to_bool());
assert!(!b.ct_lt(&a).to_bool());
}

#[test]
fn ordering() {
assert!(!Ordering::Equal.ct_lt(&Ordering::Equal).to_bool());
assert!(Ordering::Less.ct_lt(&Ordering::Greater).to_bool());
assert!(!Ordering::Greater.ct_lt(&Ordering::Less).to_bool());
}
}