1use crate::traits::*;
2
3#[cfg(feature = "check-secret-independence")]
4mod classify_secret;
5#[cfg(feature = "check-secret-independence")]
7mod secret_integers;
8#[cfg(feature = "check-secret-independence")]
9pub use secret_integers::*;
10
11#[cfg(not(feature = "check-secret-independence"))]
13mod classify_public;
14#[cfg(not(feature = "check-secret-independence"))]
15mod public_integers;
16#[cfg(not(feature = "check-secret-independence"))]
17pub use public_integers::*;
18
19macro_rules! impl_new {
21 ($name:ident, $t:ty, $st:ty) => {
22 #[allow(non_snake_case)]
23 #[inline(always)]
24 pub const fn $name(v: $t) -> $st {
25 secret(v)
26 }
27 };
28}
29impl_new!(U8, u8, U8);
30impl_new!(U16, u16, U16);
31impl_new!(U32, u32, U32);
32impl_new!(U64, u64, U64);
33
34#[cfg(not(eurydice))]
35impl_new!(U128, u128, U128);
36
37impl_new!(I8, i8, I8);
38impl_new!(I16, i16, I16);
39impl_new!(I32, i32, I32);
40impl_new!(I64, i64, I64);
41
42#[cfg(not(eurydice))]
43impl_new!(I128, i128, I128);
44
45pub trait CastOps {
47 fn as_u8(self) -> U8;
48 fn as_i8(self) -> I8;
49 fn as_u16(self) -> U16;
50 fn as_i16(self) -> I16;
51 fn as_u32(self) -> U32;
52 fn as_i32(self) -> I32;
53 fn as_u64(self) -> U64;
54 fn as_i64(self) -> I64;
55
56 #[cfg(not(eurydice))]
57 fn as_u128(self) -> U128;
58 #[cfg(not(eurydice))]
59 fn as_i128(self) -> I128;
60}
61
62macro_rules! impl_cast_ops {
64 ($name:ident) => {
65 impl CastOps for $name {
66 #[inline(always)]
67 fn as_u8(self) -> U8 {
68 (self.declassify() as u8).classify()
69 }
70 #[inline(always)]
71 fn as_i8(self) -> I8 {
72 (self.declassify() as i8).classify()
73 }
74 #[inline(always)]
75 fn as_u16(self) -> U16 {
76 (self.declassify() as u16).classify()
77 }
78 #[inline(always)]
79 fn as_i16(self) -> I16 {
80 (self.declassify() as i16).classify()
81 }
82 #[inline(always)]
83 fn as_u32(self) -> U32 {
84 (self.declassify() as u32).classify()
85 }
86 #[inline(always)]
87 fn as_i32(self) -> I32 {
88 (self.declassify() as i32).classify()
89 }
90 #[inline(always)]
91 fn as_u64(self) -> U64 {
92 (self.declassify() as u64).classify()
93 }
94 #[inline(always)]
95 fn as_i64(self) -> I64 {
96 (self.declassify() as i64).classify()
97 }
98
99 #[cfg(not(eurydice))]
100 #[inline(always)]
101 fn as_u128(self) -> U128 {
102 (self.declassify() as u128).classify()
103 }
104 #[cfg(not(eurydice))]
105 #[inline(always)]
106 fn as_i128(self) -> I128 {
107 (self.declassify() as i128).classify()
108 }
109 }
110 };
111}
112impl_cast_ops!(U8);
113impl_cast_ops!(U16);
114impl_cast_ops!(U32);
115impl_cast_ops!(U64);
116
117#[cfg(not(eurydice))]
118impl_cast_ops!(U128);
119
120impl_cast_ops!(I8);
121impl_cast_ops!(I16);
122impl_cast_ops!(I32);
123impl_cast_ops!(I64);
124
125#[cfg(not(eurydice))]
126impl_cast_ops!(I128);
127
128pub trait Swap {
130 fn cswap(&mut self, other: &mut Self, selector: U8);
134}
135
136pub trait Select {
138 fn select(&mut self, other: &Self, selector: U8);
144}
145
146#[cfg(any(hax, not(target_arch = "aarch64")))]
147mod portable {
148 use super::{Select, Swap};
149 use crate::{traits::Declassify, U8};
150 #[cfg(feature = "check-secret-independence")]
151 use crate::{traits::*, U16, U32, U64};
152
153 #[inline(never)]
155 fn is_non_zero_32(selector: u8) -> u32 {
156 core::hint::black_box(
157 ((!(core::hint::black_box(selector) as u32)).wrapping_add(1) >> 31) & 1,
158 )
159 }
160
161 #[inline(never)]
163 fn is_non_zero_64(selector: u8) -> u64 {
164 core::hint::black_box(
165 ((!(core::hint::black_box(selector) as u64)).wrapping_add(1) >> 63) & 1,
166 )
167 }
168
169 macro_rules! impl_select {
172 ($ty:ty, $secret_ty:ty, $is_non_zero:ident) => {
173 impl Select for [$ty] {
174 fn select(&mut self, other: &Self, selector: crate::U8) {
175 let mask = ($is_non_zero(selector.declassify()) as $ty).wrapping_sub(1);
176 for i in 0..self.len() {
177 self[i] = (self[i] & mask) | (other[i] & !mask);
178 }
179 }
180 }
181
182 #[cfg(feature = "check-secret-independence")]
183 impl Select for [$secret_ty] {
184 fn select(&mut self, other: &Self, selector: crate::U8) {
185 let lhs = self.declassify_ref_mut();
186 let rhs = other.declassify_ref();
187 lhs.select(rhs, selector);
188 }
189 }
190 };
191 }
192
193 impl_select!(u8, U8, is_non_zero_32);
194 impl_select!(u16, U16, is_non_zero_32);
195 impl_select!(u32, U32, is_non_zero_32);
196 impl_select!(u64, U64, is_non_zero_64);
197
198 macro_rules! swap64 {
199 ($t:ty, $lhs:expr, $rhs:expr, $selector:expr) => {
200 let mask = core::hint::black_box(
201 ((((!($selector as u64)).wrapping_add(1) >> 63) & 1) as $t).wrapping_sub(1),
202 );
203 for i in 0..$lhs.len() {
204 let dummy = !mask & ($lhs[i] ^ $rhs[i]);
205 $lhs[i] ^= dummy;
206 $rhs[i] ^= dummy;
207 }
208 };
209 }
210
211 macro_rules! swap32 {
212 ($t:ty, $lhs:expr, $rhs:expr, $selector:expr) => {
213 let mask = core::hint::black_box(
214 ((((!(core::hint::black_box($selector) as u32)).wrapping_add(1) >> 31) & 1) as $t)
215 .wrapping_sub(1),
216 );
217 for i in 0..$lhs.len() {
218 let dummy = !mask & ($lhs[i] ^ $rhs[i]);
219 $lhs[i] ^= dummy;
220 $rhs[i] ^= dummy;
221 }
222 };
223 }
224
225 macro_rules! impl_swap {
228 ($ty:ty, $secret_ty:ty, $swap:ident) => {
229 impl Swap for [$ty] {
230 #[inline]
231 fn cswap(&mut self, other: &mut Self, selector: U8) {
232 debug_assert_eq!(self.len(), other.len());
233 $swap!($ty, self, other, selector.declassify());
234 }
235 }
236
237 #[cfg(feature = "check-secret-independence")]
238 impl Swap for [$secret_ty] {
239 #[inline]
240 fn cswap(&mut self, other: &mut Self, selector: U8) {
241 debug_assert_eq!(self.len(), other.len());
242 let lhs = self.declassify_ref_mut();
243 let rhs = other.declassify_ref_mut();
244 $swap!($ty, lhs, rhs, selector.declassify());
245 }
246 }
247 };
248 }
249
250 impl_swap!(u8, U8, swap32);
251 impl_swap!(u16, U16, swap32);
252 impl_swap!(u32, U32, swap32);
253 impl_swap!(u64, U64, swap64);
254}
255
256#[cfg(all(not(hax), target_arch = "aarch64"))]
257mod aarch64 {
258 use core::arch::asm;
259
260 use super::*;
261
262 macro_rules! select64 {
263 ($lhs:expr, $rhs:expr, $selector:expr) => {
264 #[allow(unsafe_code)]
266 unsafe {
267 asm! {
268 "cmp {cond:w}, 0",
269 "csel {lhs:x}, {rhs:x}, {lhs:x}, NE",
270 cond = in(reg) $selector,
271 lhs = inlateout(reg) *$lhs,
272 rhs = in(reg) *$rhs,
273 options(nostack),
274 };
275 }
276 };
277 }
278
279 macro_rules! select32 {
280 ($lhs:expr, $rhs:expr, $selector:expr) => {
281 #[allow(unsafe_code)]
283 unsafe {
284 asm! {
285 "cmp {cond:w}, 0",
286 "csel {lhs:w}, {rhs:w}, {lhs:w}, NE",
287 cond = in(reg) $selector,
288 lhs = inlateout(reg) *$lhs,
289 rhs = in(reg) *$rhs,
290 options(nostack),
291 };
292 }
293 };
294 }
295
296 macro_rules! impl_select {
301 ($ty:ty, $secret_ty:ty, $select:ident) => {
302 impl Select for $ty {
303 #[inline]
304 fn select(&mut self, other: &Self, selector: U8) {
305 $select!(self, other, selector.declassify());
306 }
307 }
308
309 #[cfg(feature = "check-secret-independence")]
310 impl Select for $secret_ty {
311 #[inline]
312 fn select(&mut self, other: &Self, selector: U8) {
313 let lhs = self.declassify_ref_mut();
314 let rhs = other.declassify_ref();
315 lhs.select(rhs, selector);
316 }
317 }
318 };
319 }
320
321 impl<T: Select> Select for [T] {
322 #[inline]
323 fn select(&mut self, other: &Self, selector: U8) {
324 debug_assert_eq!(self.len(), other.len());
325 for i in 0..self.len() {
326 (&mut self[i]).select(&other[i], selector);
327 }
328 }
329 }
330
331 impl_select!(u8, U8, select32);
332 impl_select!(u16, U16, select32);
333 impl_select!(u32, U32, select32);
334 impl_select!(u64, U64, select64);
335
336 macro_rules! swap64 {
337 ($lhs:expr, $rhs:expr, $selector:expr) => {
338 #[allow(unsafe_code)]
340 unsafe {
341 asm! {
342 "cmp {cond:w}, 0",
343 "csel {tmp}, {b:x}, {a:x}, NE",
344 "csel {b:x}, {a:x}, {b:x}, NE",
345 "mov {a:x}, {tmp}",
346 cond = in(reg) $selector,
347 a = inout(reg) *$lhs,
348 b = inout(reg) *$rhs,
349 tmp = out(reg) _,
350 options(nostack),
351 };
352 }
353 };
354 }
355
356 macro_rules! swap32 {
357 ($lhs:expr, $rhs:expr, $selector:expr) => {
358 #[allow(unsafe_code)]
360 unsafe {
361 asm! {
362 "cmp {cond:w}, 0",
363 "csel {tmp:w}, {b:w}, {a:w}, NE",
364 "csel {b:w}, {a:w}, {b:w}, NE",
365 "mov {a:w}, {tmp:w}",
366 cond = in(reg) $selector,
367 a = inout(reg) *$lhs,
368 b = inout(reg) *$rhs,
369 tmp = out(reg) _,
370 options(nostack),
371 };
372 }
373 };
374 }
375
376 macro_rules! impl_swap {
381 ($ty:ty, $secret_ty:ty, $swap:ident) => {
382 impl Swap for $ty {
383 #[inline]
384 fn cswap(&mut self, other: &mut Self, selector: U8) {
385 $swap!(self, other, selector.declassify());
386 }
387 }
388
389 #[cfg(feature = "check-secret-independence")]
390 impl Swap for $secret_ty {
391 #[inline]
392 fn cswap(&mut self, other: &mut Self, selector: U8) {
393 let lhs = self.declassify_ref_mut();
394 let rhs = other.declassify_ref_mut();
395 lhs.cswap(rhs, selector);
396 }
397 }
398 };
399 }
400
401 impl_swap!(u8, U8, swap32);
402 impl_swap!(u16, U16, swap32);
403 impl_swap!(u32, U32, swap32);
404 impl_swap!(u64, U64, swap64);
405
406 impl<T: Swap> Swap for [T] {
407 #[inline]
408 fn cswap(&mut self, other: &mut Self, selector: U8) {
409 for i in 0..self.len() {
410 (&mut self[i]).cswap(&mut other[i], selector);
411 }
412 }
413 }
414}
415
416#[cfg(test)]
417mod select {
418 extern crate std;
419 use core::fmt::Debug;
420
421 use rand::{rng, Fill, Rng, RngExt};
422
423 use super::*;
424
425 fn test<T: Classify + Default + Copy + PartialEq + Eq + Debug + Fill>(rng: &mut impl Rng)
426 where
427 [T]: Select,
428 {
429 let selector: u8 = rng.random::<u8>() & 1;
430 let mut lhs = [T::default(); 256];
433 rng.fill(&mut lhs);
434 let mut rhs = [T::default(); 256];
435 rng.fill(&mut rhs);
436
437 let expected = if selector == 0 {
438 lhs.clone()
439 } else {
440 rhs.clone()
441 };
442
443 lhs.select(&rhs, selector.classify());
444
445 assert_eq!(
446 lhs, expected,
447 "\nother: {:?}\nselector: {}\n",
448 rhs, selector
449 );
450 }
451
452 #[test]
453 fn correctness() {
454 let mut rng = rng();
455 const ITERATIONS: usize = 1_000;
456
457 for _ in 0..ITERATIONS {
458 test::<u8>(&mut rng);
459 test::<u16>(&mut rng);
460 test::<u32>(&mut rng);
461 test::<u64>(&mut rng);
462 }
463 }
464
465 #[test]
466 #[cfg(feature = "check-secret-independence")]
467 fn correctness_secret() {
468 macro_rules! secret_test {
469 ($ty:ty, $rng:expr) => {{
470 let selector: u8 = $rng.random::<u8>() & 1;
471 let mut lhs = [<$ty>::default(); 256];
474 $rng.fill(&mut lhs);
475 let mut rhs = [<$ty>::default(); 256];
476 $rng.fill(&mut rhs);
477
478 let expected = if selector == 0 {
479 lhs.clone()
480 } else {
481 rhs.clone()
482 };
483
484 let mut lhs = lhs.classify();
485 let rhs = rhs.classify();
486
487 lhs.select(&rhs, selector.classify());
488
489 assert_eq!(
490 lhs.declassify(),
491 expected,
492 "\nother: {:?}\nselector: {}\n",
493 rhs.declassify(),
494 selector
495 );
496 }};
497 }
498 let mut rng = rng();
499 const ITERATIONS: usize = 1_000;
500
501 for _ in 0..ITERATIONS {
502 secret_test!(u8, rng);
503 secret_test!(u16, rng);
504 secret_test!(u32, rng);
505 secret_test!(u64, rng);
506 }
507 }
508}
509
510#[cfg(test)]
511mod swap {
512 extern crate std;
513 use core::fmt::Debug;
514
515 use rand::{rng, Fill, Rng, RngExt};
516
517 use super::*;
518
519 fn test<T: Default + Copy + PartialEq + Eq + Debug + Fill>(rng: &mut impl Rng)
521 where
522 [T]: Swap,
523 {
524 let selector = rng.random::<u8>() & 1;
525 let mut lhs = [T::default(); 256];
528 rng.fill(&mut lhs);
529 let mut rhs = [T::default(); 256];
530 rng.fill(&mut rhs);
531
532 let (expected_lhs, expected_rhs) = if selector == 0 {
533 (lhs.clone(), rhs.clone())
534 } else {
535 (rhs.clone(), lhs.clone())
536 };
537
538 lhs.cswap(&mut rhs, selector.classify());
539
540 assert_eq!(lhs, expected_lhs, "\nlhs / selector: {}\n", selector);
541 assert_eq!(rhs, expected_rhs, "\nrhs / selector: {}\n", selector);
542 }
543
544 #[test]
545 fn correctness() {
546 let mut rng = rng();
547 const ITERATIONS: usize = 1_000;
548
549 for _ in 0..ITERATIONS {
550 test::<u8>(&mut rng);
551 test::<u16>(&mut rng);
552 test::<u32>(&mut rng);
553 test::<u64>(&mut rng);
554 }
555 }
556
557 #[test]
559 #[cfg(feature = "check-secret-independence")]
560 fn correctness_secret() {
561 macro_rules! secret_test {
562 ($ty:ty, $rng:expr) => {{
563 let selector = $rng.random::<u8>() & 1;
564 let mut lhs = [<$ty>::default(); 256];
567 $rng.fill(&mut lhs);
568 let mut rhs = [<$ty>::default(); 256];
569 $rng.fill(&mut rhs);
570
571 let (expected_lhs, expected_rhs) = if selector == 0 {
572 (lhs.clone(), rhs.clone())
573 } else {
574 (rhs.clone(), lhs.clone())
575 };
576
577 let mut lhs = lhs.classify();
578 let mut rhs = rhs.classify();
579 lhs.cswap(&mut rhs, selector.classify());
580
581 assert_eq!(
582 lhs.declassify(),
583 expected_lhs,
584 "\nlhs / selector: {}\n",
585 selector
586 );
587 assert_eq!(
588 rhs.declassify(),
589 expected_rhs,
590 "\nrhs / selector: {}\n",
591 selector
592 );
593 }};
594 }
595 let mut rng = rng();
596 const ITERATIONS: usize = 1_000;
597
598 for _ in 0..ITERATIONS {
599 secret_test!(u8, rng);
600 secret_test!(u16, rng);
601 secret_test!(u32, rng);
602 secret_test!(u64, rng);
603 }
604 }
605}