dcrypt_internal/
constant_time.rs1use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
4
5pub fn ct_eq<A, B>(a: A, b: B) -> bool
10where
11 A: AsRef<[u8]>,
12 B: AsRef<[u8]>,
13{
14 let a = a.as_ref();
15 let b = b.as_ref();
16
17 if a.len() != b.len() {
18 return false;
19 }
20
21 a.ct_eq(b).into()
22}
23
24pub fn ct_select<T>(a: T, b: T, condition: bool) -> T
29where
30 T: ConditionallySelectable,
31{
32 let choice = Choice::from(condition as u8);
33 T::conditional_select(&a, &b, choice)
34}
35
36pub fn ct_assign(dst: &mut [u8], src: &[u8], condition: bool) {
41 assert_eq!(dst.len(), src.len());
42
43 let choice = Choice::from(condition as u8);
44
45 for i in 0..dst.len() {
46 dst[i] = u8::conditional_select(&dst[i], &src[i], choice);
47 }
48}
49
50pub trait ConstantTimeEquals {
52 fn ct_equals(&self, other: &Self) -> bool;
54}
55
56impl<T: AsRef<[u8]>> ConstantTimeEquals for T {
58 fn ct_equals(&self, other: &Self) -> bool {
59 ct_eq(self.as_ref(), other.as_ref())
60 }
61}
62
63pub fn ct_eq_choice<A, B>(a: A, b: B) -> Choice
65where
66 A: AsRef<[u8]>,
67 B: AsRef<[u8]>,
68{
69 let a = a.as_ref();
70 let b = b.as_ref();
71
72 if a.len() != b.len() {
73 return Choice::from(0);
74 }
75
76 a.ct_eq(b)
77}
78
79pub fn ct_and<const N: usize>(a: &[u8; N], b: &[u8; N]) -> [u8; N] {
81 let mut result = [0u8; N];
82 for i in 0..N {
83 result[i] = a[i] & b[i];
84 }
85 result
86}
87
88pub fn ct_or<const N: usize>(a: &[u8; N], b: &[u8; N]) -> [u8; N] {
90 let mut result = [0u8; N];
91 for i in 0..N {
92 result[i] = a[i] | b[i];
93 }
94 result
95}
96
97pub fn ct_xor<const N: usize>(a: &[u8; N], b: &[u8; N]) -> [u8; N] {
99 let mut result = [0u8; N];
100 for i in 0..N {
101 result[i] = a[i] ^ b[i];
102 }
103 result
104}
105
106pub fn ct_op<const N: usize, F>(a: &[u8; N], b: &[u8; N], condition: bool, op: F) -> [u8; N]
111where
112 F: Fn(u8, u8) -> u8,
113{
114 let choice = Choice::from(condition as u8);
115 let mut result = [0u8; N];
116
117 for i in 0..N {
118 let operated = op(a[i], b[i]);
120 result[i] = u8::conditional_select(&a[i], &operated, choice);
121 }
122
123 result
124}
125
126pub fn ct_mask(condition: bool) -> u8 {
130 0u8.wrapping_sub(condition as u8)
131}