Skip to main content

crypto_bigint/int/
ct.rs

1//! Constant-time support: impls of `Ct*` traits and constant-time `const fn` operations.
2
3use crate::{Choice, CtAssign, CtEq, CtGt, CtLt, CtSelect, Int, Uint};
4use ctutils::{CtAssignSlice, CtEqSlice};
5
6impl<const LIMBS: usize> Int<LIMBS> {
7    /// Return `b` if `c` is truthy, otherwise return `a`.
8    #[inline]
9    pub(crate) const fn select(a: &Self, b: &Self, c: Choice) -> Self {
10        Self(Uint::select(&a.0, &b.0, c))
11    }
12}
13
14impl<const LIMBS: usize> CtAssign for Int<LIMBS> {
15    #[inline]
16    fn ct_assign(&mut self, other: &Self, choice: Choice) {
17        self.0.ct_assign(&other.0, choice);
18    }
19}
20impl<const LIMBS: usize> CtAssignSlice for Int<LIMBS> {}
21
22impl<const LIMBS: usize> CtEq for Int<LIMBS> {
23    #[inline]
24    fn ct_eq(&self, other: &Self) -> Choice {
25        CtEq::ct_eq(&self.0, &other.0)
26    }
27}
28impl<const LIMBS: usize> CtEqSlice for Int<LIMBS> {}
29
30impl<const LIMBS: usize> CtGt for Int<LIMBS> {
31    #[inline]
32    fn ct_gt(&self, other: &Self) -> Choice {
33        Int::gt(self, other)
34    }
35}
36
37impl<const LIMBS: usize> CtLt for Int<LIMBS> {
38    #[inline]
39    fn ct_lt(&self, other: &Self) -> Choice {
40        Int::lt(self, other)
41    }
42}
43
44impl<const LIMBS: usize> CtSelect for Int<LIMBS> {
45    #[inline]
46    fn ct_select(&self, other: &Self, choice: Choice) -> Self {
47        Self(self.0.ct_select(&other.0, choice))
48    }
49}
50
51#[cfg(feature = "subtle")]
52impl<const LIMBS: usize> subtle::ConditionallySelectable for Int<LIMBS> {
53    #[inline]
54    fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
55        a.ct_select(b, choice.into())
56    }
57}
58
59#[cfg(feature = "subtle")]
60impl<const LIMBS: usize> subtle::ConstantTimeEq for Int<LIMBS> {
61    #[inline]
62    fn ct_eq(&self, other: &Self) -> subtle::Choice {
63        CtEq::ct_eq(self, other).into()
64    }
65}
66
67#[cfg(feature = "subtle")]
68impl<const LIMBS: usize> subtle::ConstantTimeGreater for Int<LIMBS> {
69    #[inline]
70    fn ct_gt(&self, other: &Self) -> subtle::Choice {
71        CtGt::ct_gt(self, other).into()
72    }
73}
74
75#[cfg(feature = "subtle")]
76impl<const LIMBS: usize> subtle::ConstantTimeLess for Int<LIMBS> {
77    #[inline]
78    fn ct_lt(&self, other: &Self) -> subtle::Choice {
79        Int::lt(self, other).into()
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use crate::{Choice, CtGt, CtLt, CtSelect, I128};
86
87    #[test]
88    fn ct_gt() {
89        let a = I128::MIN;
90        let b = I128::ZERO;
91        let c = I128::MAX;
92
93        assert!(b.ct_gt(&a).to_bool());
94        assert!(c.ct_gt(&a).to_bool());
95        assert!(c.ct_gt(&b).to_bool());
96
97        assert!(!a.ct_gt(&a).to_bool());
98        assert!(!b.ct_gt(&b).to_bool());
99        assert!(!c.ct_gt(&c).to_bool());
100
101        assert!(!a.ct_gt(&b).to_bool());
102        assert!(!a.ct_gt(&c).to_bool());
103        assert!(!b.ct_gt(&c).to_bool());
104    }
105
106    #[test]
107    fn ct_lt() {
108        let a = I128::ZERO;
109        let b = I128::ONE;
110        let c = I128::MAX;
111
112        assert!(a.ct_lt(&b).to_bool());
113        assert!(a.ct_lt(&c).to_bool());
114        assert!(b.ct_lt(&c).to_bool());
115
116        assert!(!a.ct_lt(&a).to_bool());
117        assert!(!b.ct_lt(&b).to_bool());
118        assert!(!c.ct_lt(&c).to_bool());
119
120        assert!(!b.ct_lt(&a).to_bool());
121        assert!(!c.ct_lt(&a).to_bool());
122        assert!(!c.ct_lt(&b).to_bool());
123    }
124
125    #[test]
126    fn ct_select() {
127        let a = I128::from_be_hex("00002222444466668888AAAACCCCEEEE");
128        let b = I128::from_be_hex("11113333555577779999BBBBDDDDFFFF");
129
130        let select_0 = I128::ct_select(&a, &b, Choice::FALSE);
131        assert_eq!(a, select_0);
132
133        let select_1 = I128::ct_select(&a, &b, Choice::TRUE);
134        assert_eq!(b, select_1);
135    }
136}