1use crate::{Choice, CtAssign, CtEq, CtGt, CtLt, CtSelect, Limb, word};
4use ctutils::{CtAssignSlice, CtEqSlice};
5
6impl Limb {
7 #[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 #[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}