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;
150 use crate::U8;
151 #[cfg(feature = "check-secret-independence")]
152 use crate::{traits::*, U16, U32, U64};
153
154 #[inline(never)]
156 fn is_non_zero_32(selector: u8) -> u32 {
157 core::hint::black_box(
158 ((!(core::hint::black_box(selector) as u32)).wrapping_add(1) >> 31) & 1,
159 )
160 }
161
162 #[inline(never)]
164 fn is_non_zero_64(selector: u8) -> u64 {
165 core::hint::black_box(
166 ((!(core::hint::black_box(selector) as u64)).wrapping_add(1) >> 63) & 1,
167 )
168 }
169
170 macro_rules! impl_select {
173 ($ty:ty, $secret_ty:ty, $is_non_zero:ident) => {
174 impl Select for [$ty] {
175 fn select(&mut self, other: &Self, selector: crate::U8) {
176 let mask = ($is_non_zero(selector.declassify()) as $ty).wrapping_sub(1);
177 for i in 0..self.len() {
178 self[i] = (self[i] & mask) | (other[i] & !mask);
179 }
180 }
181 }
182
183 #[cfg(feature = "check-secret-independence")]
184 impl Select for [$secret_ty] {
185 fn select(&mut self, other: &Self, selector: crate::U8) {
186 let lhs = self.declassify_ref_mut();
187 let rhs = other.declassify_ref();
188 lhs.select(rhs, selector);
189 }
190 }
191 };
192 }
193
194 impl_select!(u8, U8, is_non_zero_32);
195 impl_select!(u16, U16, is_non_zero_32);
196 impl_select!(u32, U32, is_non_zero_32);
197 impl_select!(u64, U64, is_non_zero_64);
198
199 macro_rules! swap64 {
200 ($t:ty, $lhs:expr, $rhs:expr, $selector:expr) => {
201 let mask = core::hint::black_box(
202 ((((!($selector as u64)).wrapping_add(1) >> 63) & 1) as $t).wrapping_sub(1),
203 );
204 for i in 0..$lhs.len() {
205 let dummy = !mask & ($lhs[i] ^ $rhs[i]);
206 $lhs[i] ^= dummy;
207 $rhs[i] ^= dummy;
208 }
209 };
210 }
211
212 macro_rules! swap32 {
213 ($t:ty, $lhs:expr, $rhs:expr, $selector:expr) => {
214 let mask = core::hint::black_box(
215 ((((!(core::hint::black_box($selector) as u32)).wrapping_add(1) >> 31) & 1) as $t)
216 .wrapping_sub(1),
217 );
218 for i in 0..$lhs.len() {
219 let dummy = !mask & ($lhs[i] ^ $rhs[i]);
220 $lhs[i] ^= dummy;
221 $rhs[i] ^= dummy;
222 }
223 };
224 }
225
226 macro_rules! impl_swap {
229 ($ty:ty, $secret_ty:ty, $swap:ident) => {
230 impl Swap for [$ty] {
231 #[inline]
232 fn cswap(&mut self, other: &mut Self, selector: U8) {
233 debug_assert_eq!(self.len(), other.len());
234 $swap!($ty, self, other, selector.declassify());
235 }
236 }
237
238 #[cfg(feature = "check-secret-independence")]
239 impl Swap for [$secret_ty] {
240 #[inline]
241 fn cswap(&mut self, other: &mut Self, selector: U8) {
242 debug_assert_eq!(self.len(), other.len());
243 let lhs = self.declassify_ref_mut();
244 let rhs = other.declassify_ref_mut();
245 $swap!($ty, lhs, rhs, selector.declassify());
246 }
247 }
248 };
249 }
250
251 impl_swap!(u8, U8, swap32);
252 impl_swap!(u16, U16, swap32);
253 impl_swap!(u32, U32, swap32);
254 impl_swap!(u64, U64, swap64);
255}
256
257#[cfg(all(not(hax), target_arch = "aarch64"))]
258mod aarch64 {
259 use core::arch::asm;
260
261 use super::*;
262
263 macro_rules! select64 {
264 ($lhs:expr, $rhs:expr, $selector:expr) => {
265 #[allow(unsafe_code)]
267 unsafe {
268 asm! {
269 "cmp {cond:w}, 0",
270 "csel {lhs:x}, {rhs:x}, {lhs:x}, NE",
271 cond = in(reg) $selector,
272 lhs = inlateout(reg) *$lhs,
273 rhs = in(reg) *$rhs,
274 options(nostack),
275 };
276 }
277 };
278 }
279
280 macro_rules! select32 {
281 ($lhs:expr, $rhs:expr, $selector:expr) => {
282 #[allow(unsafe_code)]
284 unsafe {
285 asm! {
286 "cmp {cond:w}, 0",
287 "csel {lhs:w}, {rhs:w}, {lhs:w}, NE",
288 cond = in(reg) $selector,
289 lhs = inlateout(reg) *$lhs,
290 rhs = in(reg) *$rhs,
291 options(nostack),
292 };
293 }
294 };
295 }
296
297 macro_rules! impl_select {
302 ($ty:ty, $secret_ty:ty, $select: ident) => {
303 impl Select for $ty {
304 #[inline]
305 fn select(&mut self, other: &Self, selector: U8) {
306 $select!(self, other, selector.declassify());
307 }
308 }
309
310 #[cfg(feature = "check-secret-independence")]
311 impl Select for $secret_ty {
312 #[inline]
313 fn select(&mut self, other: &Self, selector: U8) {
314 let lhs = self.declassify_ref_mut();
315 let rhs = other.declassify_ref();
316 lhs.select(rhs, selector);
317 }
318 }
319 };
320 }
321
322 impl<T: Select> Select for [T] {
323 #[inline]
324 fn select(&mut self, other: &Self, selector: U8) {
325 debug_assert_eq!(self.len(), other.len());
326 for i in 0..self.len() {
327 (&mut self[i]).select(&other[i], selector);
328 }
329 }
330 }
331
332 impl_select!(u8, U8, select32);
333 impl_select!(u16, U16, select32);
334 impl_select!(u32, U32, select32);
335 impl_select!(u64, U64, select64);
336
337 macro_rules! swap64 {
338 ($lhs:expr, $rhs:expr, $selector:expr) => {
339 #[allow(unsafe_code)]
341 unsafe {
342 asm! {
343 "cmp {cond:w}, 0",
344 "csel {tmp}, {b:x}, {a:x}, NE",
345 "csel {b:x}, {a:x}, {b:x}, NE",
346 "mov {a:x}, {tmp}",
347 cond = in(reg) $selector,
348 a = inout(reg) *$lhs,
349 b = inout(reg) *$rhs,
350 tmp = out(reg) _,
351 options(nostack),
352 };
353 }
354 };
355 }
356
357 macro_rules! swap32 {
358 ($lhs:expr, $rhs:expr, $selector:expr) => {
359 #[allow(unsafe_code)]
361 unsafe {
362 asm! {
363 "cmp {cond:w}, 0",
364 "csel {tmp:w}, {b:w}, {a:w}, NE",
365 "csel {b:w}, {a:w}, {b:w}, NE",
366 "mov {a:w}, {tmp:w}",
367 cond = in(reg) $selector,
368 a = inout(reg) *$lhs,
369 b = inout(reg) *$rhs,
370 tmp = out(reg) _,
371 options(nostack),
372 };
373 }
374 };
375 }
376
377 macro_rules! impl_swap {
382 ($ty:ty, $secret_ty:ty, $swap:ident) => {
383 impl Swap for $ty {
384 #[inline]
385 fn cswap(&mut self, other: &mut Self, selector: U8) {
386 $swap!(self, other, selector.declassify());
387 }
388 }
389
390 #[cfg(feature = "check-secret-independence")]
391 impl Swap for $secret_ty {
392 #[inline]
393 fn cswap(&mut self, other: &mut Self, selector: U8) {
394 let lhs = self.declassify_ref_mut();
395 let rhs = other.declassify_ref_mut();
396 lhs.cswap(rhs, selector);
397 }
398 }
399 };
400 }
401
402 impl_swap!(u8, U8, swap32);
403 impl_swap!(u16, U16, swap32);
404 impl_swap!(u32, U32, swap32);
405 impl_swap!(u64, U64, swap64);
406
407 impl<T: Swap> Swap for [T] {
408 #[inline]
409 fn cswap(&mut self, other: &mut Self, selector: U8) {
410 for i in 0..self.len() {
411 (&mut self[i]).cswap(&mut other[i], selector);
412 }
413 }
414 }
415}
416
417#[cfg(test)]
418mod select {
419 extern crate std;
420 use core::fmt::Debug;
421
422 use super::*;
423 use rand::{rng, Fill, Rng, RngCore};
424
425 fn test<T: Classify + Default + Copy + PartialEq + Eq + Debug>(rng: &mut impl RngCore)
426 where
427 [T]: Fill + 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 super::*;
516 use rand::{rng, Fill, Rng, RngCore};
517
518 fn test<T: Default + Copy + PartialEq + Eq + Debug>(rng: &mut impl RngCore)
520 where
521 [T]: Fill + Swap,
522 {
523 let selector = rng.random::<u8>() & 1;
524 let mut lhs = [T::default(); 256];
527 rng.fill(&mut lhs);
528 let mut rhs = [T::default(); 256];
529 rng.fill(&mut rhs);
530
531 let (expected_lhs, expected_rhs) = if selector == 0 {
532 (lhs.clone(), rhs.clone())
533 } else {
534 (rhs.clone(), lhs.clone())
535 };
536
537 lhs.cswap(&mut rhs, selector.classify());
538
539 assert_eq!(lhs, expected_lhs, "\nlhs / selector: {}\n", selector);
540 assert_eq!(rhs, expected_rhs, "\nrhs / selector: {}\n", selector);
541 }
542
543 #[test]
544 fn correctness() {
545 let mut rng = rng();
546 const ITERATIONS: usize = 1_000;
547
548 for _ in 0..ITERATIONS {
549 test::<u8>(&mut rng);
550 test::<u16>(&mut rng);
551 test::<u32>(&mut rng);
552 test::<u64>(&mut rng);
553 }
554 }
555
556 #[test]
558 #[cfg(feature = "check-secret-independence")]
559 fn correctness_secret() {
560 macro_rules! secret_test {
561 ($ty:ty, $rng:expr) => {{
562 let selector = $rng.random::<u8>() & 1;
563 let mut lhs = [<$ty>::default(); 256];
566 $rng.fill(&mut lhs);
567 let mut rhs = [<$ty>::default(); 256];
568 $rng.fill(&mut rhs);
569
570 let (expected_lhs, expected_rhs) = if selector == 0 {
571 (lhs.clone(), rhs.clone())
572 } else {
573 (rhs.clone(), lhs.clone())
574 };
575
576 let mut lhs = lhs.classify();
577 let mut rhs = rhs.classify();
578 lhs.cswap(&mut rhs, selector.classify());
579
580 assert_eq!(
581 lhs.declassify(),
582 expected_lhs,
583 "\nlhs / selector: {}\n",
584 selector
585 );
586 assert_eq!(
587 rhs.declassify(),
588 expected_rhs,
589 "\nrhs / selector: {}\n",
590 selector
591 );
592 }};
593 }
594 let mut rng = rng();
595 const ITERATIONS: usize = 1_000;
596
597 for _ in 0..ITERATIONS {
598 secret_test!(u8, rng);
599 secret_test!(u16, rng);
600 secret_test!(u32, rng);
601 secret_test!(u64, rng);
602 }
603 }
604}