pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
let mut result = 0u8;
for (x, y) in a.iter().zip(b.iter()) {
result |= x ^ y;
}
result == 0
}
pub fn constant_time_select(choice: u8, a: u8, b: u8) -> u8 {
let mask = 0u8.wrapping_sub(choice);
(a & mask) | (b & !mask)
}
pub fn constant_time_copy(choice: u8, dst: &mut [u8], src: &[u8]) {
if dst.len() != src.len() {
return;
}
let mask = 0u8.wrapping_sub(choice);
for (d, s) in dst.iter_mut().zip(src.iter()) {
*d = (*d & !mask) | (*s & mask);
}
}
pub fn constant_time_swap(choice: u8, a: &mut [u8], b: &mut [u8]) {
if a.len() != b.len() {
return;
}
let mask = 0u8.wrapping_sub(choice);
for (a_elem, b_elem) in a.iter_mut().zip(b.iter_mut()) {
let temp = *a_elem;
*a_elem = (*a_elem & !mask) | (*b_elem & mask);
*b_elem = (*b_elem & !mask) | (temp & mask);
}
}
pub fn constant_time_zero(choice: u8, data: &mut [u8]) {
let mask = 0u8.wrapping_sub(choice);
for byte in data.iter_mut() {
*byte &= !mask;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_constant_time_eq() {
let a = b"hello";
let b = b"hello";
let c = b"world";
let d = b"hell";
assert!(constant_time_eq(a, b));
assert!(!constant_time_eq(a, c));
assert!(!constant_time_eq(a, d));
assert!(!constant_time_eq(b"", b"a"));
}
#[test]
fn test_constant_time_select() {
assert_eq!(constant_time_select(1, 0xFF, 0x00), 0xFF);
assert_eq!(constant_time_select(0, 0xFF, 0x00), 0x00);
}
#[test]
fn test_constant_time_copy() {
let mut dst = [0u8; 4];
let src = [1u8, 2u8, 3u8, 4u8];
constant_time_copy(1, &mut dst, &src);
assert_eq!(dst, src);
constant_time_copy(0, &mut dst, &[5u8, 6u8, 7u8, 8u8]);
assert_eq!(dst, src); }
#[test]
fn test_constant_time_swap() {
let mut a = [1u8, 2u8, 3u8, 4u8];
let mut b = [5u8, 6u8, 7u8, 8u8];
let a_orig = a;
let b_orig = b;
constant_time_swap(1, &mut a, &mut b);
assert_eq!(a, b_orig);
assert_eq!(b, a_orig);
constant_time_swap(0, &mut a, &mut b);
assert_eq!(a, b_orig); assert_eq!(b, a_orig); }
#[test]
fn test_constant_time_zero() {
let mut data = [1u8, 2u8, 3u8, 4u8];
constant_time_zero(1, &mut data);
assert_eq!(data, [0u8, 0u8, 0u8, 0u8]);
data = [1u8, 2u8, 3u8, 4u8];
constant_time_zero(0, &mut data);
assert_eq!(data, [1u8, 2u8, 3u8, 4u8]); }
}