veridian_kernel/crypto/
constant_time.rs1#![allow(dead_code)]
8use core::sync::atomic::{compiler_fence, Ordering};
14
15#[inline(never)]
19pub(crate) fn ct_eq_bytes(a: &[u8], b: &[u8]) -> u8 {
20 if a.len() != b.len() {
21 return 0;
22 }
23
24 let mut result = 0u8;
25
26 for i in 0..a.len() {
28 result |= a[i] ^ b[i];
29 }
30
31 compiler_fence(Ordering::SeqCst);
33
34 ((!result & (result.wrapping_sub(1))) >> 7) & 1
36}
37
38#[inline(always)]
43pub(crate) fn ct_select_u8(condition: u8, a: u8, b: u8) -> u8 {
44 let mask = condition.wrapping_neg();
45 (a & mask) | (b & !mask)
46}
47
48#[inline(always)]
50pub(crate) fn ct_select_u32(condition: u8, a: u32, b: u32) -> u32 {
51 let mask = (condition as u32).wrapping_neg();
52 (a & mask) | (b & !mask)
53}
54
55#[inline(always)]
57pub(crate) fn ct_select_u64(condition: u8, a: u64, b: u64) -> u64 {
58 let mask = (condition as u64).wrapping_neg();
59 (a & mask) | (b & !mask)
60}
61
62#[inline(never)]
67pub(crate) fn ct_copy(dst: &mut [u8], src: &[u8], condition: u8) {
68 assert_eq!(dst.len(), src.len());
69
70 for i in 0..dst.len() {
71 dst[i] = ct_select_u8(condition, src[i], dst[i]);
72 }
73
74 compiler_fence(Ordering::SeqCst);
75}
76
77#[inline(never)]
81pub(crate) fn ct_zero(data: &mut [u8]) {
82 for byte in data.iter_mut() {
83 unsafe {
88 core::ptr::write_volatile(byte, 0);
89 }
90 }
91
92 compiler_fence(Ordering::SeqCst);
93}
94
95#[inline(always)]
99pub(crate) fn ct_lt_u32(a: u32, b: u32) -> u8 {
100 let diff = a ^ ((a ^ b) | ((a.wrapping_sub(b)) ^ b));
101 ((diff >> 31) & 1) as u8
102}
103
104#[inline(never)]
108pub(crate) fn ct_cmp_bytes(a: &[u8], b: &[u8]) -> i8 {
109 assert_eq!(a.len(), b.len());
110
111 let mut greater = 0u8;
112 let mut less = 0u8;
113
114 for i in 0..a.len() {
115 let gt = ct_lt_u32(b[i] as u32, a[i] as u32);
116 let lt = ct_lt_u32(a[i] as u32, b[i] as u32);
117
118 greater |= gt & !less & !greater;
119 less |= lt & !greater & !less;
120 }
121
122 compiler_fence(Ordering::SeqCst);
123
124 if greater != 0 {
125 1
126 } else if less != 0 {
127 -1
128 } else {
129 0
130 }
131}
132
133#[inline(always)]
135pub(crate) fn memory_barrier() {
136 compiler_fence(Ordering::SeqCst);
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn test_ct_eq_bytes() {
145 let a = [1u8, 2, 3, 4];
146 let b = [1u8, 2, 3, 4];
147 let c = [1u8, 2, 3, 5];
148
149 assert_eq!(ct_eq_bytes(&a, &b), 1);
150 assert_eq!(ct_eq_bytes(&a, &c), 0);
151 }
152
153 #[test]
154 fn test_ct_select() {
155 assert_eq!(ct_select_u8(1, 0xAA, 0x55), 0xAA);
156 assert_eq!(ct_select_u8(0, 0xAA, 0x55), 0x55);
157
158 assert_eq!(ct_select_u32(1, 0x12345678, 0xABCDEF00), 0x12345678);
159 assert_eq!(ct_select_u32(0, 0x12345678, 0xABCDEF00), 0xABCDEF00);
160 }
161
162 #[test]
163 fn test_ct_copy() {
164 let mut dst = [0u8; 4];
165 let src = [1u8, 2, 3, 4];
166
167 ct_copy(&mut dst, &src, 1);
168 assert_eq!(dst, [1, 2, 3, 4]);
169
170 ct_copy(&mut dst, &[5, 6, 7, 8], 0);
171 assert_eq!(dst, [1, 2, 3, 4]); }
173
174 #[test]
175 fn test_ct_cmp() {
176 let a = [1u8, 2, 3];
177 let b = [1u8, 2, 3];
178 let c = [1u8, 2, 4];
179
180 assert_eq!(ct_cmp_bytes(&a, &b), 0);
181 assert_eq!(ct_cmp_bytes(&a, &c), -1);
182 assert_eq!(ct_cmp_bytes(&c, &a), 1);
183 }
184}