#[inline]
pub fn ct_eq(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
let mut diff: u8 = 0;
for i in 0..a.len() {
diff |= a[i] ^ b[i];
}
diff == 0
}
#[inline]
pub fn ct_eq_full(a: &[u8], b: &[u8]) -> bool {
let max_len = a.len().max(b.len());
let mut diff: u16 = (a.len() ^ b.len()) as u16;
for i in 0..max_len {
let av = if i < a.len() { a[i] } else { 0 };
let bv = if i < b.len() { b[i] } else { 0 };
diff |= (av ^ bv) as u16;
}
diff == 0
}
#[inline]
pub fn ct_select(a: u8, b: u8, select: u8) -> u8 {
let mask = (0i8.wrapping_sub((select & 1) as i8)) as u8;
(a & !mask) | (b & mask)
}
#[inline]
pub fn ct_select_slice(out: &mut [u8], a: &[u8], b: &[u8], select: u8) {
assert_eq!(a.len(), b.len());
assert_eq!(a.len(), out.len());
let mask = (0i8.wrapping_sub((select & 1) as i8)) as u8;
for i in 0..out.len() {
out[i] = (a[i] & !mask) | (b[i] & mask);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ct_eq_equal() {
assert!(ct_eq(&[1, 2, 3, 4], &[1, 2, 3, 4]));
}
#[test]
fn ct_eq_unequal() {
assert!(!ct_eq(&[1, 2, 3, 4], &[1, 2, 3, 5]));
}
#[test]
fn ct_eq_different_length() {
assert!(!ct_eq(&[1, 2, 3], &[1, 2, 3, 4]));
assert!(!ct_eq(&[1, 2, 3, 4], &[1, 2, 3]));
}
#[test]
fn ct_eq_empty() {
assert!(ct_eq(&[], &[]));
}
#[test]
fn ct_eq_single_diff() {
assert!(!ct_eq(&[0xFF, 0, 0, 0], &[0xFE, 0, 0, 0]));
assert!(!ct_eq(&[0, 0, 0, 0xFF], &[0, 0, 0, 0xFE]));
}
#[test]
fn ct_eq_full_equal() {
assert!(ct_eq_full(&[1, 2, 3], &[1, 2, 3]));
}
#[test]
fn ct_eq_full_different_length() {
assert!(!ct_eq_full(&[1, 2, 3], &[1, 2, 3, 4]));
}
#[test]
fn ct_select_chooses_a() {
assert_eq!(ct_select(0xAA, 0xBB, 0), 0xAA);
}
#[test]
fn ct_select_chooses_b() {
assert_eq!(ct_select(0xAA, 0xBB, 1), 0xBB);
}
#[test]
fn ct_select_slice_basic() {
let mut out = [0u8; 4];
let a = [0x11, 0x22, 0x33, 0x44];
let b = [0xAA, 0xBB, 0xCC, 0xDD];
ct_select_slice(&mut out, &a, &b, 0);
assert_eq!(out, a);
ct_select_slice(&mut out, &a, &b, 1);
assert_eq!(out, b);
}
}