Skip to main content

crypto_bigint/uint/
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, Limb, Uint, UintRef};
4use ctutils::{CtAssignSlice, CtEqSlice};
5
6impl<const LIMBS: usize> Uint<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        let mut limbs = [Limb::ZERO; LIMBS];
11
12        let mut i = 0;
13        while i < LIMBS {
14            limbs[i] = Limb::select(a.limbs[i], b.limbs[i], c);
15            i += 1;
16        }
17
18        Uint { limbs }
19    }
20
21    /// Swap `a` and `b` if `c` is truthy, otherwise, do nothing.
22    #[inline]
23    pub(crate) const fn conditional_swap(a: &mut Self, b: &mut Self, c: Choice) {
24        let mut i = 0;
25        let a = a.as_mut_limbs();
26        let b = b.as_mut_limbs();
27        while i < LIMBS {
28            Limb::ct_conditional_swap(&mut a[i], &mut b[i], c);
29            i += 1;
30        }
31    }
32
33    /// Swap `a` and `b`
34    #[inline]
35    pub(crate) const fn swap(a: &mut Self, b: &mut Self) {
36        Self::conditional_swap(a, b, Choice::TRUE);
37    }
38}
39
40impl<const LIMBS: usize> CtAssign for Uint<LIMBS> {
41    #[inline]
42    fn ct_assign(&mut self, other: &Self, choice: Choice) {
43        self.limbs.ct_assign(&other.limbs, choice);
44    }
45}
46impl<const LIMBS: usize> CtAssignSlice for Uint<LIMBS> {}
47
48impl<const LIMBS: usize, Rhs: AsRef<UintRef> + ?Sized> CtEq<Rhs> for Uint<LIMBS> {
49    #[inline]
50    fn ct_eq(&self, other: &Rhs) -> Choice {
51        self.as_uint_ref().ct_eq(other)
52    }
53}
54impl<const LIMBS: usize> CtEqSlice for Uint<LIMBS> {}
55
56impl<const LIMBS: usize> CtGt for Uint<LIMBS> {
57    #[inline]
58    fn ct_gt(&self, other: &Self) -> Choice {
59        Self::gt(self, other)
60    }
61}
62
63impl<const LIMBS: usize> CtLt for Uint<LIMBS> {
64    #[inline]
65    fn ct_lt(&self, other: &Self) -> Choice {
66        Self::lt(self, other)
67    }
68}
69
70impl<const LIMBS: usize> CtSelect for Uint<LIMBS> {
71    #[inline]
72    fn ct_select(&self, other: &Self, choice: Choice) -> Self {
73        Self::from_words(self.as_words().ct_select(other.as_words(), choice))
74    }
75}
76
77#[cfg(feature = "subtle")]
78impl<const LIMBS: usize> subtle::ConditionallySelectable for Uint<LIMBS> {
79    #[inline]
80    fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
81        a.ct_select(b, choice.into())
82    }
83}
84
85#[cfg(feature = "subtle")]
86impl<const LIMBS: usize> subtle::ConstantTimeEq for Uint<LIMBS> {
87    #[inline]
88    fn ct_eq(&self, other: &Self) -> subtle::Choice {
89        CtEq::ct_eq(self, other).into()
90    }
91
92    #[inline]
93    fn ct_ne(&self, other: &Self) -> subtle::Choice {
94        CtEq::ct_ne(self, other).into()
95    }
96}
97
98#[cfg(feature = "subtle")]
99impl<const LIMBS: usize> subtle::ConstantTimeGreater for Uint<LIMBS> {
100    #[inline]
101    fn ct_gt(&self, other: &Self) -> subtle::Choice {
102        CtGt::ct_gt(self, other).into()
103    }
104}
105
106#[cfg(feature = "subtle")]
107impl<const LIMBS: usize> subtle::ConstantTimeLess for Uint<LIMBS> {
108    #[inline]
109    fn ct_lt(&self, other: &Self) -> subtle::Choice {
110        Uint::lt(self, other).into()
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use crate::{Choice, CtEq, CtGt, CtLt, CtSelect, U128};
117
118    #[test]
119    fn ct_eq() {
120        let a = U128::ZERO;
121        let b = U128::MAX;
122
123        assert!(a.ct_eq(&a).to_bool());
124        assert!(!a.ct_eq(&b).to_bool());
125        assert!(!b.ct_eq(&a).to_bool());
126        assert!(b.ct_eq(&b).to_bool());
127    }
128
129    #[test]
130    fn ct_gt() {
131        let a = U128::ZERO;
132        let b = U128::ONE;
133        let c = U128::MAX;
134
135        assert!(b.ct_gt(&a).to_bool());
136        assert!(c.ct_gt(&a).to_bool());
137        assert!(c.ct_gt(&b).to_bool());
138
139        assert!(!a.ct_gt(&a).to_bool());
140        assert!(!b.ct_gt(&b).to_bool());
141        assert!(!c.ct_gt(&c).to_bool());
142
143        assert!(!a.ct_gt(&b).to_bool());
144        assert!(!a.ct_gt(&c).to_bool());
145        assert!(!b.ct_gt(&c).to_bool());
146    }
147
148    #[test]
149    fn ct_lt() {
150        let a = U128::ZERO;
151        let b = U128::ONE;
152        let c = U128::MAX;
153
154        assert!(a.ct_lt(&b).to_bool());
155        assert!(a.ct_lt(&c).to_bool());
156        assert!(b.ct_lt(&c).to_bool());
157
158        assert!(!a.ct_lt(&a).to_bool());
159        assert!(!b.ct_lt(&b).to_bool());
160        assert!(!c.ct_lt(&c).to_bool());
161
162        assert!(!b.ct_lt(&a).to_bool());
163        assert!(!c.ct_lt(&a).to_bool());
164        assert!(!c.ct_lt(&b).to_bool());
165    }
166
167    #[test]
168    fn ct_select() {
169        let a = U128::from_be_hex("00002222444466668888AAAACCCCEEEE");
170        let b = U128::from_be_hex("11113333555577779999BBBBDDDDFFFF");
171
172        let select_0 = U128::ct_select(&a, &b, Choice::FALSE);
173        assert_eq!(a, select_0);
174
175        let select_1 = U128::ct_select(&a, &b, Choice::TRUE);
176        assert_eq!(b, select_1);
177    }
178}