1pub fn fixed_time_eq(a: &[u8], b: &[u8]) -> bool {
18 assert!(a.len() == b.len());
19 let count = a.len();
20 let lhs = &a[..count];
21 let rhs = &b[..count];
22
23 let mut r: u8 = 0;
24 for i in 0..count {
25 let mut rs = unsafe { core::ptr::read_volatile(&r) };
26 rs |= lhs[i] ^ rhs[i];
27 unsafe {
28 core::ptr::write_volatile(&mut r, rs);
29 }
30 }
31 {
32 let mut t = unsafe { core::ptr::read_volatile(&r) };
33 t |= t >> 4;
34 unsafe {
35 core::ptr::write_volatile(&mut r, t);
36 }
37 }
38 {
39 let mut t = unsafe { core::ptr::read_volatile(&r) };
40 t |= t >> 2;
41 unsafe {
42 core::ptr::write_volatile(&mut r, t);
43 }
44 }
45 {
46 let mut t = unsafe { core::ptr::read_volatile(&r) };
47 t |= t >> 1;
48 unsafe {
49 core::ptr::write_volatile(&mut r, t);
50 }
51 }
52 unsafe { (::core::ptr::read_volatile(&r) & 1) == 0 }
53}
54
55#[test]
56fn eq_test() {
57 assert!(fixed_time_eq(&[0b00000000], &[0b00000000]));
58 assert!(fixed_time_eq(&[0b00000001], &[0b00000001]));
59 assert!(fixed_time_eq(&[0b00000010], &[0b00000010]));
60 assert!(fixed_time_eq(&[0b00000100], &[0b00000100]));
61 assert!(fixed_time_eq(&[0b00001000], &[0b00001000]));
62 assert!(fixed_time_eq(&[0b00010000], &[0b00010000]));
63 assert!(fixed_time_eq(&[0b00100000], &[0b00100000]));
64 assert!(fixed_time_eq(&[0b01000000], &[0b01000000]));
65 assert!(fixed_time_eq(&[0b10000000], &[0b10000000]));
66 assert!(fixed_time_eq(&[0b11111111], &[0b11111111]));
67
68 assert!(!fixed_time_eq(&[0b00000001], &[0b00000000]));
69 assert!(!fixed_time_eq(&[0b00000001], &[0b11111111]));
70 assert!(!fixed_time_eq(&[0b00000010], &[0b00000000]));
71 assert!(!fixed_time_eq(&[0b00000010], &[0b11111111]));
72 assert!(!fixed_time_eq(&[0b00000100], &[0b00000000]));
73 assert!(!fixed_time_eq(&[0b00000100], &[0b11111111]));
74 assert!(!fixed_time_eq(&[0b00001000], &[0b00000000]));
75 assert!(!fixed_time_eq(&[0b00001000], &[0b11111111]));
76 assert!(!fixed_time_eq(&[0b00010000], &[0b00000000]));
77 assert!(!fixed_time_eq(&[0b00010000], &[0b11111111]));
78 assert!(!fixed_time_eq(&[0b00100000], &[0b00000000]));
79 assert!(!fixed_time_eq(&[0b00100000], &[0b11111111]));
80 assert!(!fixed_time_eq(&[0b01000000], &[0b00000000]));
81 assert!(!fixed_time_eq(&[0b01000000], &[0b11111111]));
82 assert!(!fixed_time_eq(&[0b10000000], &[0b00000000]));
83 assert!(!fixed_time_eq(&[0b10000000], &[0b11111111]));
84
85 assert!(fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000000, 0b00000000]));
86 assert!(!fixed_time_eq(&[0b00000001, 0b00000000], &[0b00000000, 0b00000000]));
87 assert!(!fixed_time_eq(&[0b00000000, 0b00000001], &[0b00000000, 0b00000000]));
88 assert!(!fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000001, 0b00000000]));
89 assert!(!fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000001, 0b00000001]));
90}
91
92#[cfg(bench)]
93mod benches {
94 use test::Bencher;
95
96 use crate::cmp::fixed_time_eq;
97 use crate::{sha256, sha512, Hash};
98
99 #[bench]
100 fn bench_32b_constant_time_cmp_ne(bh: &mut Bencher) {
101 let hash_a = sha256::Hash::hash(&[0; 1]);
102 let hash_b = sha256::Hash::hash(&[1; 1]);
103 bh.iter(|| fixed_time_eq(&hash_a[..], &hash_b[..]))
104 }
105
106 #[bench]
107 fn bench_32b_slice_cmp_ne(bh: &mut Bencher) {
108 let hash_a = sha256::Hash::hash(&[0; 1]);
109 let hash_b = sha256::Hash::hash(&[1; 1]);
110 bh.iter(|| &hash_a[..] == &hash_b[..])
111 }
112
113 #[bench]
114 fn bench_32b_constant_time_cmp_eq(bh: &mut Bencher) {
115 let hash_a = sha256::Hash::hash(&[0; 1]);
116 let hash_b = sha256::Hash::hash(&[0; 1]);
117 bh.iter(|| fixed_time_eq(&hash_a[..], &hash_b[..]))
118 }
119
120 #[bench]
121 fn bench_32b_slice_cmp_eq(bh: &mut Bencher) {
122 let hash_a = sha256::Hash::hash(&[0; 1]);
123 let hash_b = sha256::Hash::hash(&[0; 1]);
124 bh.iter(|| &hash_a[..] == &hash_b[..])
125 }
126
127 #[bench]
128 fn bench_64b_constant_time_cmp_ne(bh: &mut Bencher) {
129 let hash_a = sha512::Hash::hash(&[0; 1]);
130 let hash_b = sha512::Hash::hash(&[1; 1]);
131 bh.iter(|| fixed_time_eq(&hash_a[..], &hash_b[..]))
132 }
133
134 #[bench]
135 fn bench_64b_slice_cmp_ne(bh: &mut Bencher) {
136 let hash_a = sha512::Hash::hash(&[0; 1]);
137 let hash_b = sha512::Hash::hash(&[1; 1]);
138 bh.iter(|| &hash_a[..] == &hash_b[..])
139 }
140
141 #[bench]
142 fn bench_64b_constant_time_cmp_eq(bh: &mut Bencher) {
143 let hash_a = sha512::Hash::hash(&[0; 1]);
144 let hash_b = sha512::Hash::hash(&[0; 1]);
145 bh.iter(|| fixed_time_eq(&hash_a[..], &hash_b[..]))
146 }
147
148 #[bench]
149 fn bench_64b_slice_cmp_eq(bh: &mut Bencher) {
150 let hash_a = sha512::Hash::hash(&[0; 1]);
151 let hash_b = sha512::Hash::hash(&[0; 1]);
152 bh.iter(|| &hash_a[..] == &hash_b[..])
153 }
154}