1use subtle::{Choice, CtOption};
2
3use crate::{modular::SafeGcdInverter, Int, Limb, NonZero, Odd, Uint, WideWord, Word};
4
5#[derive(Debug, Copy, Clone)]
9pub struct ConstChoice(Word);
10
11impl ConstChoice {
12 pub const FALSE: Self = Self(0);
14
15 pub const TRUE: Self = Self(Word::MAX);
17
18 #[inline]
19 #[allow(trivial_numeric_casts)]
20 pub(crate) const fn as_u32_mask(&self) -> u32 {
21 self.0 as u32
22 }
23
24 #[inline]
25 #[cfg(target_pointer_width = "32")]
26 pub(crate) const fn as_u64_mask(&self) -> u64 {
27 ((self.0 as u64) << 32) | (self.0 as u64)
28 }
29
30 #[inline]
31 #[cfg(target_pointer_width = "64")]
32 pub(crate) const fn as_u64_mask(&self) -> u64 {
33 self.0
34 }
35
36 #[inline]
39 pub(crate) const fn from_word_mask(value: Word) -> Self {
40 debug_assert!(value == Self::FALSE.0 || value == Self::TRUE.0);
41 Self(value)
42 }
43
44 #[inline]
47 pub(crate) const fn from_word_lsb(value: Word) -> Self {
48 debug_assert!(value == 0 || value == 1);
49 Self(value.wrapping_neg())
50 }
51
52 #[inline]
55 pub(crate) const fn from_word_msb(value: Word) -> Self {
56 Self::from_word_lsb(value >> (Word::BITS - 1))
57 }
58
59 #[inline]
62 pub(crate) const fn from_wide_word_lsb(value: WideWord) -> Self {
63 debug_assert!(value == 0 || value == 1);
64 Self(value.wrapping_neg() as Word)
65 }
66
67 #[inline]
68 pub(crate) const fn from_u32_lsb(value: u32) -> Self {
69 debug_assert!(value == 0 || value == 1);
70 #[allow(trivial_numeric_casts)]
71 Self((value as Word).wrapping_neg())
72 }
73
74 #[inline]
75 pub(crate) const fn from_u64_lsb(value: u64) -> Self {
76 debug_assert!(value == 0 || value == 1);
77 #[allow(trivial_numeric_casts)]
78 Self((value as Word).wrapping_neg())
79 }
80
81 #[inline]
83 pub(crate) const fn from_u32_nonzero(value: u32) -> Self {
84 Self::from_u32_lsb((value | value.wrapping_neg()) >> (u32::BITS - 1))
85 }
86
87 #[inline]
89 pub(crate) const fn from_u64_nonzero(value: u64) -> Self {
90 Self::from_u64_lsb((value | value.wrapping_neg()) >> (u64::BITS - 1))
91 }
92
93 #[inline]
95 pub(crate) const fn from_word_nonzero(value: Word) -> Self {
96 Self::from_word_lsb((value | value.wrapping_neg()) >> (Word::BITS - 1))
97 }
98
99 #[inline]
101 pub(crate) const fn from_u32_eq(x: u32, y: u32) -> Self {
102 Self::from_u32_nonzero(x ^ y).not()
103 }
104
105 #[inline]
107 pub(crate) const fn from_u64_eq(x: u64, y: u64) -> Self {
108 Self::from_u64_nonzero(x ^ y).not()
109 }
110
111 #[inline]
113 pub(crate) const fn from_word_eq(x: Word, y: Word) -> Self {
114 Self::from_word_nonzero(x ^ y).not()
115 }
116
117 #[inline]
119 pub(crate) const fn from_word_lt(x: Word, y: Word) -> Self {
120 let bit = (((!x) & y) | (((!x) | y) & (x.wrapping_sub(y)))) >> (Word::BITS - 1);
122 Self::from_word_lsb(bit)
123 }
124
125 #[inline]
127 pub(crate) const fn from_word_gt(x: Word, y: Word) -> Self {
128 Self::from_word_lt(y, x)
129 }
130
131 #[inline]
133 pub(crate) const fn from_u32_lt(x: u32, y: u32) -> Self {
134 let bit = (((!x) & y) | (((!x) | y) & (x.wrapping_sub(y)))) >> (u32::BITS - 1);
136 Self::from_u32_lsb(bit)
137 }
138
139 #[inline]
141 pub(crate) const fn from_word_le(x: Word, y: Word) -> Self {
142 let bit = (((!x) | y) & ((x ^ y) | !(y.wrapping_sub(x)))) >> (Word::BITS - 1);
144 Self::from_word_lsb(bit)
145 }
146
147 #[inline]
149 pub(crate) const fn from_wide_word_le(x: WideWord, y: WideWord) -> Self {
150 let bit = (((!x) | y) & ((x ^ y) | !(y.wrapping_sub(x)))) >> (WideWord::BITS - 1);
152 Self::from_wide_word_lsb(bit)
153 }
154
155 #[inline]
157 pub(crate) const fn from_u32_le(x: u32, y: u32) -> Self {
158 let bit = (((!x) | y) & ((x ^ y) | !(y.wrapping_sub(x)))) >> (u32::BITS - 1);
160 Self::from_u32_lsb(bit)
161 }
162
163 #[inline]
165 pub(crate) const fn from_u64_lt(x: u64, y: u64) -> Self {
166 let bit = (((!x) & y) | (((!x) | y) & (x.wrapping_sub(y)))) >> (u64::BITS - 1);
168 Self::from_u64_lsb(bit)
169 }
170
171 #[inline]
173 pub(crate) const fn from_u64_gt(x: u64, y: u64) -> Self {
174 Self::from_u64_lt(y, x)
175 }
176
177 #[inline]
178 pub(crate) const fn not(&self) -> Self {
179 Self(!self.0)
180 }
181
182 #[inline]
183 pub(crate) const fn or(&self, other: Self) -> Self {
184 Self(self.0 | other.0)
185 }
186
187 #[inline]
188 pub(crate) const fn and(&self, other: Self) -> Self {
189 Self(self.0 & other.0)
190 }
191
192 #[inline]
193 pub(crate) const fn xor(&self, other: Self) -> Self {
194 Self(self.0 ^ other.0)
195 }
196
197 #[inline]
198 pub(crate) const fn ne(&self, other: Self) -> Self {
199 Self::xor(self, other)
200 }
201
202 #[inline]
203 pub(crate) const fn eq(&self, other: Self) -> Self {
204 Self::ne(self, other).not()
205 }
206
207 #[inline]
209 pub(crate) const fn select_word(&self, a: Word, b: Word) -> Word {
210 a ^ (self.0 & (a ^ b))
211 }
212
213 #[inline]
215 pub(crate) const fn select_wide_word(&self, a: WideWord, b: WideWord) -> WideWord {
216 let mask = ((self.0 as WideWord) << Word::BITS) | (self.0 as WideWord);
217 a ^ (mask & (a ^ b))
218 }
219
220 #[inline]
222 pub(crate) const fn select_u32(&self, a: u32, b: u32) -> u32 {
223 a ^ (self.as_u32_mask() & (a ^ b))
224 }
225
226 #[inline]
228 pub(crate) const fn select_u64(&self, a: u64, b: u64) -> u64 {
229 a ^ (self.as_u64_mask() & (a ^ b))
230 }
231
232 #[inline]
234 pub(crate) const fn if_true_word(&self, x: Word) -> Word {
235 x & self.0
236 }
237
238 #[inline]
240 pub(crate) const fn if_true_u32(&self, x: u32) -> u32 {
241 x & self.as_u32_mask()
242 }
243
244 #[inline]
245 pub(crate) const fn is_true_vartime(&self) -> bool {
246 self.0 == ConstChoice::TRUE.0
247 }
248
249 #[inline]
250 pub(crate) const fn to_u8(self) -> u8 {
251 (self.0 as u8) & 1
252 }
253
254 #[inline]
256 pub(crate) const fn to_bool_vartime(self) -> bool {
257 self.to_u8() != 0
258 }
259}
260
261impl From<ConstChoice> for Choice {
262 #[inline]
263 fn from(choice: ConstChoice) -> Self {
264 Choice::from(choice.to_u8())
265 }
266}
267
268impl From<Choice> for ConstChoice {
269 #[inline]
270 fn from(choice: Choice) -> Self {
271 ConstChoice::from_word_lsb(choice.unwrap_u8() as Word)
272 }
273}
274
275impl From<ConstChoice> for bool {
276 fn from(choice: ConstChoice) -> Self {
277 choice.is_true_vartime()
278 }
279}
280
281impl PartialEq for ConstChoice {
282 fn eq(&self, other: &Self) -> bool {
283 self.0 == other.0
284 }
285}
286
287#[derive(Debug, Clone)]
289pub struct ConstCtOption<T> {
290 value: T,
291 is_some: ConstChoice,
292}
293
294impl<T> ConstCtOption<T> {
295 #[inline]
296 pub(crate) const fn new(value: T, is_some: ConstChoice) -> Self {
297 Self { value, is_some }
298 }
299
300 #[inline]
301 pub(crate) const fn some(value: T) -> Self {
302 Self {
303 value,
304 is_some: ConstChoice::TRUE,
305 }
306 }
307
308 #[inline]
309 pub(crate) const fn none(dummy_value: T) -> Self {
310 Self {
311 value: dummy_value,
312 is_some: ConstChoice::FALSE,
313 }
314 }
315
316 #[inline]
320 pub(crate) const fn components_ref(&self) -> (&T, ConstChoice) {
321 (&self.value, self.is_some)
325 }
326
327 #[inline]
329 pub const fn is_some(&self) -> ConstChoice {
330 self.is_some
331 }
332
333 #[inline]
335 pub const fn is_none(&self) -> ConstChoice {
336 self.is_some.not()
337 }
338
339 #[inline]
341 pub fn unwrap(self) -> T {
342 assert!(self.is_some.is_true_vartime());
343 self.value
344 }
345
346 #[inline]
348 pub(crate) const fn and_choice(mut self, is_some: ConstChoice) -> Self {
349 self.is_some = self.is_some.and(is_some);
350 self
351 }
352}
353
354impl<T> From<ConstCtOption<T>> for CtOption<T> {
355 #[inline]
356 fn from(value: ConstCtOption<T>) -> Self {
357 CtOption::new(value.value, value.is_some.into())
358 }
359}
360
361impl<T> From<ConstCtOption<T>> for Option<T> {
362 #[inline]
363 fn from(value: ConstCtOption<T>) -> Self {
364 if value.is_some.into() {
365 Some(value.value)
366 } else {
367 None
368 }
369 }
370}
371
372impl<const LIMBS: usize> ConstCtOption<Uint<LIMBS>> {
377 #[inline]
379 pub const fn unwrap_or(self, def: Uint<LIMBS>) -> Uint<LIMBS> {
380 Uint::select(&def, &self.value, self.is_some)
381 }
382
383 #[inline]
390 pub const fn expect(self, msg: &str) -> Uint<LIMBS> {
391 assert!(self.is_some.is_true_vartime(), "{}", msg);
392 self.value
393 }
394
395 #[inline]
397 pub const fn as_int(&self) -> ConstCtOption<Int<LIMBS>> {
398 ConstCtOption::new(self.value.as_int(), self.is_some)
399 }
400}
401
402impl<const LIMBS: usize> ConstCtOption<(Uint<LIMBS>, Uint<LIMBS>)> {
403 #[inline]
410 pub const fn expect(self, msg: &str) -> (Uint<LIMBS>, Uint<LIMBS>) {
411 assert!(self.is_some.is_true_vartime(), "{}", msg);
412 self.value
413 }
414}
415
416impl<const LIMBS: usize> ConstCtOption<NonZero<Uint<LIMBS>>> {
417 #[inline]
424 pub const fn expect(self, msg: &str) -> NonZero<Uint<LIMBS>> {
425 assert!(self.is_some.is_true_vartime(), "{}", msg);
426 self.value
427 }
428}
429
430impl<const LIMBS: usize> ConstCtOption<Odd<Uint<LIMBS>>> {
431 #[inline]
438 pub const fn expect(self, msg: &str) -> Odd<Uint<LIMBS>> {
439 assert!(self.is_some.is_true_vartime(), "{}", msg);
440 self.value
441 }
442}
443
444impl<const LIMBS: usize> ConstCtOption<Int<LIMBS>> {
445 #[inline]
447 pub const fn unwrap_or(self, def: Int<LIMBS>) -> Int<LIMBS> {
448 Int::select(&def, &self.value, self.is_some)
449 }
450
451 #[inline]
458 pub const fn expect(self, msg: &str) -> Int<LIMBS> {
459 assert!(self.is_some.is_true_vartime(), "{}", msg);
460 self.value
461 }
462}
463
464impl ConstCtOption<NonZero<Limb>> {
465 #[inline]
472 pub const fn expect(self, msg: &str) -> NonZero<Limb> {
473 assert!(self.is_some.is_true_vartime(), "{}", msg);
474 self.value
475 }
476}
477
478impl<const SAT_LIMBS: usize, const UNSAT_LIMBS: usize>
479 ConstCtOption<SafeGcdInverter<SAT_LIMBS, UNSAT_LIMBS>>
480{
481 #[inline]
488 pub const fn expect(self, msg: &str) -> SafeGcdInverter<SAT_LIMBS, UNSAT_LIMBS> {
489 assert!(self.is_some.is_true_vartime(), "{}", msg);
490 self.value
491 }
492}
493
494#[cfg(test)]
495mod tests {
496 use crate::{WideWord, Word};
497
498 use super::ConstChoice;
499
500 #[test]
501 fn from_u64_lsb() {
502 assert_eq!(ConstChoice::from_u64_lsb(0), ConstChoice::FALSE);
503 assert_eq!(ConstChoice::from_u64_lsb(1), ConstChoice::TRUE);
504 }
505
506 #[test]
507 fn from_word_lt() {
508 assert_eq!(ConstChoice::from_word_lt(4, 5), ConstChoice::TRUE);
509 assert_eq!(ConstChoice::from_word_lt(5, 5), ConstChoice::FALSE);
510 assert_eq!(ConstChoice::from_word_lt(6, 5), ConstChoice::FALSE);
511 }
512
513 #[test]
514 fn from_word_gt() {
515 assert_eq!(ConstChoice::from_word_gt(4, 5), ConstChoice::FALSE);
516 assert_eq!(ConstChoice::from_word_gt(5, 5), ConstChoice::FALSE);
517 assert_eq!(ConstChoice::from_word_gt(6, 5), ConstChoice::TRUE);
518 }
519
520 #[test]
521 fn from_wide_word_le() {
522 assert_eq!(ConstChoice::from_wide_word_le(4, 5), ConstChoice::TRUE);
523 assert_eq!(ConstChoice::from_wide_word_le(5, 5), ConstChoice::TRUE);
524 assert_eq!(ConstChoice::from_wide_word_le(6, 5), ConstChoice::FALSE);
525 }
526
527 #[test]
528 fn select_u32() {
529 let a: u32 = 1;
530 let b: u32 = 2;
531 assert_eq!(ConstChoice::TRUE.select_u32(a, b), b);
532 assert_eq!(ConstChoice::FALSE.select_u32(a, b), a);
533 }
534
535 #[test]
536 fn select_u64() {
537 let a: u64 = 1;
538 let b: u64 = 2;
539 assert_eq!(ConstChoice::TRUE.select_u64(a, b), b);
540 assert_eq!(ConstChoice::FALSE.select_u64(a, b), a);
541 }
542
543 #[test]
544 fn select_word() {
545 let a: Word = 1;
546 let b: Word = 2;
547 assert_eq!(ConstChoice::TRUE.select_word(a, b), b);
548 assert_eq!(ConstChoice::FALSE.select_word(a, b), a);
549 }
550
551 #[test]
552 fn select_wide_word() {
553 let a: WideWord = (1 << Word::BITS) + 1;
554 let b: WideWord = (3 << Word::BITS) + 4;
555 assert_eq!(ConstChoice::TRUE.select_wide_word(a, b), b);
556 assert_eq!(ConstChoice::FALSE.select_wide_word(a, b), a);
557 }
558}