Skip to main content

crypto_bigint/limb/
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, word};
4use ctutils::{CtAssignSlice, CtEqSlice};
5
6impl Limb {
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(word::select(a.0, b.0, c))
11    }
12
13    /// Swap the values of `a` and `b` if `c` is truthy, otherwise do nothing.
14    #[inline]
15    pub(crate) const fn ct_conditional_swap(a: &mut Self, b: &mut Self, c: Choice) {
16        (*a, *b) = (
17            Self(word::select(a.0, b.0, c)),
18            Self(word::select(b.0, a.0, c)),
19        );
20    }
21}
22
23impl CtAssign for Limb {
24    fn ct_assign(&mut self, other: &Self, choice: Choice) {
25        self.0.ct_assign(&other.0, choice);
26    }
27}
28
29impl CtAssignSlice for Limb {
30    fn ct_assign_slice(dst: &mut [Self], src: &[Self], choice: Choice) {
31        Self::slice_as_mut_words(dst).ct_assign(Self::slice_as_words(src), choice);
32    }
33}
34
35impl CtEq for Limb {
36    #[inline]
37    fn ct_eq(&self, other: &Self) -> Choice {
38        CtEq::ct_eq(&self.0, &other.0)
39    }
40
41    #[inline]
42    fn ct_ne(&self, other: &Self) -> Choice {
43        CtEq::ct_ne(&self.0, &other.0)
44    }
45}
46
47impl CtEqSlice for Limb {
48    fn ct_eq_slice(a: &[Self], b: &[Self]) -> Choice {
49        Self::slice_as_words(a).ct_eq(Self::slice_as_words(b))
50    }
51}
52
53impl CtGt for Limb {
54    #[inline]
55    fn ct_gt(&self, other: &Self) -> Choice {
56        word::choice_from_gt(self.0, other.0)
57    }
58}
59
60impl CtLt for Limb {
61    #[inline]
62    fn ct_lt(&self, other: &Self) -> Choice {
63        word::choice_from_lt(self.0, other.0)
64    }
65}
66
67impl CtSelect for Limb {
68    #[inline]
69    fn ct_select(&self, other: &Self, choice: Choice) -> Self {
70        Self(self.0.ct_select(&other.0, choice))
71    }
72}
73
74#[cfg(feature = "subtle")]
75impl subtle::ConditionallySelectable for Limb {
76    #[inline]
77    fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
78        a.ct_select(b, choice.into())
79    }
80}
81
82#[cfg(feature = "subtle")]
83impl subtle::ConstantTimeEq for Limb {
84    #[inline]
85    fn ct_eq(&self, other: &Self) -> subtle::Choice {
86        CtEq::ct_eq(self, other).into()
87    }
88
89    #[inline]
90    fn ct_ne(&self, other: &Self) -> subtle::Choice {
91        CtEq::ct_ne(self, other).into()
92    }
93}
94
95#[cfg(feature = "subtle")]
96impl subtle::ConstantTimeGreater for Limb {
97    #[inline]
98    fn ct_gt(&self, other: &Self) -> subtle::Choice {
99        CtGt::ct_gt(self, other).into()
100    }
101}
102
103#[cfg(feature = "subtle")]
104impl subtle::ConstantTimeLess for Limb {
105    #[inline]
106    fn ct_lt(&self, other: &Self) -> subtle::Choice {
107        CtLt::ct_lt(self, other).into()
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use crate::{CtEq, CtGt, CtLt, Limb};
114
115    #[test]
116    fn ct_eq() {
117        let a = Limb::ZERO;
118        let b = Limb::MAX;
119
120        assert!(a.ct_eq(&a).to_bool());
121        assert!(!a.ct_eq(&b).to_bool());
122        assert!(!b.ct_eq(&a).to_bool());
123        assert!(b.ct_eq(&b).to_bool());
124    }
125
126    #[test]
127    fn ct_gt() {
128        let a = Limb::ZERO;
129        let b = Limb::ONE;
130        let c = Limb::MAX;
131
132        assert!(b.ct_gt(&a).to_bool());
133        assert!(c.ct_gt(&a).to_bool());
134        assert!(c.ct_gt(&b).to_bool());
135
136        assert!(!a.ct_gt(&a).to_bool());
137        assert!(!b.ct_gt(&b).to_bool());
138        assert!(!c.ct_gt(&c).to_bool());
139
140        assert!(!a.ct_gt(&b).to_bool());
141        assert!(!a.ct_gt(&c).to_bool());
142        assert!(!b.ct_gt(&c).to_bool());
143    }
144
145    #[test]
146    fn ct_lt() {
147        let a = Limb::ZERO;
148        let b = Limb::ONE;
149        let c = Limb::MAX;
150
151        assert!(a.ct_lt(&b).to_bool());
152        assert!(a.ct_lt(&c).to_bool());
153        assert!(b.ct_lt(&c).to_bool());
154
155        assert!(!a.ct_lt(&a).to_bool());
156        assert!(!b.ct_lt(&b).to_bool());
157        assert!(!c.ct_lt(&c).to_bool());
158
159        assert!(!b.ct_lt(&a).to_bool());
160        assert!(!c.ct_lt(&a).to_bool());
161        assert!(!c.ct_lt(&b).to_bool());
162    }
163}