1use core::ops::*;
8
9mod sealed {
10 pub(super) trait Sealed {}
11}
12
13struct MaskType<T>(core::marker::PhantomData<T>);
14
15trait SupportedMaskType: sealed::Sealed {}
16
17macro_rules! supported_mask_type {
18 ($($t:ty),+) => {
19 $(
20 impl sealed::Sealed for MaskType<$t> {}
21 impl SupportedMaskType for MaskType<$t> {}
22 )+
23 };
24}
25
26supported_mask_type!(i64, u64);
27
28#[derive(Clone, Copy)]
30#[must_use]
31#[repr(transparent)]
32pub struct Condition<T>(T)
33where
34 MaskType<T>: SupportedMaskType;
35
36impl<T> Condition<T> where MaskType<T>: SupportedMaskType {}
37
38impl Condition<i64> {
39 pub const TRUE: Self = Self(-1);
44 pub const FALSE: Self = Self(0);
46 pub const fn from_bool<const VALUE: bool>() -> Self {
48 Self(-(VALUE as i64))
49 }
50 pub const fn from_bool_var(value: bool) -> Self {
52 Self(-(value as i64))
53 }
54 pub const fn is_bit_set(value: i64, bit: i64) -> Self {
56 Self(-((value >> bit) & 1))
57 }
58 pub const fn is_negative(value: i64) -> Self {
60 Self(value >> 63)
61 }
62 pub const fn is_not_zero(value: i64) -> Self {
64 Self::is_negative(-Self::or_halves(value))
65 }
66 pub const fn is_zero(value: i64) -> Self {
68 Self::is_negative(Self::or_halves(value) - 1)
69 }
70 pub const fn is_equal(x: i64, y: i64) -> Self {
72 Self::is_zero(x ^ y)
73 }
74 pub const fn is_lt(x: i64, y: i64) -> Self {
76 Self::is_negative(x - y)
77 }
78 pub fn is_lte(x: i64, y: i64) -> Self {
81 !Self::is_gt(x, y)
82 }
83 pub const fn is_gt(x: i64, y: i64) -> Self {
85 Self::is_lt(y, x)
86 }
87 pub fn is_gte(x: i64, y: i64) -> Self {
90 !Self::is_lt(x, y)
91 }
92 pub fn is_within_range(value: i64, min: i64, max: i64) -> Self {
94 Self::is_gte(value, min) & Self::is_lte(value, max)
95 }
96 pub fn is_in_list(value: i64, list: &[i64]) -> Self {
98 let mut c = Self::FALSE;
104 for i in 0..list.len() {
105 let diff = value ^ list[i];
106 c |= Condition::<i64>::is_zero(diff);
107 }
108
109 c
110 }
111
112 pub fn mov(self, src: i64, dst: &mut i64) {
114 *dst = self.select(src, *dst);
115 }
116
117 pub const fn negate(self, value: i64) -> i64 {
138 (value ^ self.0).wrapping_sub(self.0)
139 }
140 pub const fn or_halves(value: i64) -> i64 {
142 (value | (value >> 32)) & 0xFFFFFFFF
143 }
144 pub const fn select(self, true_value: i64, false_value: i64) -> i64 {
146 (true_value & self.0) | (false_value & !self.0)
147 }
148 pub const fn swap(self, lhs: i64, rhs: i64) -> (i64, i64) {
150 (self.select(rhs, lhs), self.select(lhs, rhs))
151 }
152 pub const fn to_bool_var(self) -> bool {
154 self.0 != 0
155 }
156}
157
158impl Condition<u64> {
163 pub const TRUE: Self = Self(u64::MAX);
165 pub const FALSE: Self = Self(0);
167
168 pub const fn from_bool<const VALUE: bool>() -> Self {
172 Self(0u64.wrapping_sub(VALUE as u64))
175 }
176 pub fn select(self, a: u64, b: u64) -> u64 {
179 let mask = self.0;
180 (a & mask) | (b & !mask)
181 }
182 pub fn is_true(&self) -> bool {
184 self.0 != 0
185 }
186}
187
188impl<T> BitAnd for Condition<T>
189where
190 MaskType<T>: SupportedMaskType,
191 T: BitAnd<T, Output = T>,
192{
193 type Output = Self;
194 fn bitand(self, rhs: Self) -> Self {
195 Self(self.0 & rhs.0)
196 }
197}
198
199impl<T> BitAndAssign for Condition<T>
200where
201 MaskType<T>: SupportedMaskType,
202 T: BitAndAssign<T>,
203{
204 fn bitand_assign(&mut self, rhs: Self) {
205 self.0 &= rhs.0;
206 }
207}
208
209impl<T> BitOr for Condition<T>
210where
211 MaskType<T>: SupportedMaskType,
212 T: BitOr<T, Output = T>,
213{
214 type Output = Self;
215 fn bitor(self, rhs: Self) -> Self {
216 Self(self.0 | rhs.0)
217 }
218}
219
220impl<T> BitOrAssign for Condition<T>
221where
222 MaskType<T>: SupportedMaskType,
223 T: BitOrAssign<T>,
224{
225 fn bitor_assign(&mut self, rhs: Self) {
226 self.0 |= rhs.0;
227 }
228}
229
230impl<T> BitXor for Condition<T>
231where
232 MaskType<T>: SupportedMaskType,
233 T: BitXor<T, Output = T>,
234{
235 type Output = Self;
236 fn bitxor(self, rhs: Self) -> Self {
237 Self(self.0 ^ rhs.0)
238 }
239}
240
241impl<T> BitXorAssign for Condition<T>
242where
243 MaskType<T>: SupportedMaskType,
244 T: BitXorAssign<T>,
245{
246 fn bitxor_assign(&mut self, rhs: Self) {
247 self.0 ^= rhs.0;
248 }
249}
250
251impl<T> Not for Condition<T>
252where
253 MaskType<T>: SupportedMaskType,
254 T: Not<Output = T>,
255{
256 type Output = Self;
257 fn not(self) -> Self {
258 Self(!self.0)
259 }
260}
261
262pub fn ct_eq_bytes(a: &[u8], b: &[u8]) -> bool {
265 if a.len() != b.len() {
266 return false;
267 }
268 let mut result = 0u8;
269 for i in 0..a.len() {
270 result |= core::hint::black_box(a[i] ^ b[i]);
271 }
272 result == 0
273}
274
275pub fn ct_eq_zero_bytes(a: &[u8]) -> bool {
278 let mut result = 0u8;
279 for i in 0..a.len() {
280 result |= core::hint::black_box(a[i]);
281 }
282 result == 0
283}
284
285pub fn conditional_copy_bytes<const LEN: usize>(
288 a: &[u8; LEN],
289 b: &[u8; LEN],
290 out: &mut [u8; LEN],
291 take_a: bool,
292) {
293 let mask: u8 = (take_a as u8)
297 | (take_a as u8) << 1
298 | (take_a as u8) << 2
299 | (take_a as u8) << 3
300 | (take_a as u8) << 4
301 | (take_a as u8) << 5
302 | (take_a as u8) << 6
303 | (take_a as u8) << 7;
304
305 debug_assert_eq!(mask, if take_a { 0xFF } else { 0x00 });
306
307 for i in 0..LEN {
308 out[i] = core::hint::black_box(a[i] & mask) | core::hint::black_box(b[i] & !mask);
309 }
310}