use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
pub fn ct_eq<A, B>(a: A, b: B) -> bool
where
A: AsRef<[u8]>,
B: AsRef<[u8]>,
{
let a = a.as_ref();
let b = b.as_ref();
if a.len() != b.len() {
return false;
}
a.ct_eq(b).into()
}
pub fn ct_select<T>(a: T, b: T, condition: bool) -> T
where
T: ConditionallySelectable,
{
let choice = Choice::from(condition as u8);
T::conditional_select(&a, &b, choice)
}
pub fn ct_assign(dst: &mut [u8], src: &[u8], condition: bool) {
assert_eq!(dst.len(), src.len());
let choice = Choice::from(condition as u8);
for i in 0..dst.len() {
dst[i] = u8::conditional_select(&dst[i], &src[i], choice);
}
}
pub trait ConstantTimeEquals {
fn ct_equals(&self, other: &Self) -> bool;
}
impl<T: AsRef<[u8]>> ConstantTimeEquals for T {
fn ct_equals(&self, other: &Self) -> bool {
ct_eq(self.as_ref(), other.as_ref())
}
}
pub fn ct_eq_choice<A, B>(a: A, b: B) -> Choice
where
A: AsRef<[u8]>,
B: AsRef<[u8]>,
{
let a = a.as_ref();
let b = b.as_ref();
if a.len() != b.len() {
return Choice::from(0);
}
a.ct_eq(b)
}
pub fn ct_and<const N: usize>(a: &[u8; N], b: &[u8; N]) -> [u8; N] {
let mut result = [0u8; N];
for i in 0..N {
result[i] = a[i] & b[i];
}
result
}
pub fn ct_or<const N: usize>(a: &[u8; N], b: &[u8; N]) -> [u8; N] {
let mut result = [0u8; N];
for i in 0..N {
result[i] = a[i] | b[i];
}
result
}
pub fn ct_xor<const N: usize>(a: &[u8; N], b: &[u8; N]) -> [u8; N] {
let mut result = [0u8; N];
for i in 0..N {
result[i] = a[i] ^ b[i];
}
result
}
pub fn ct_op<const N: usize, F>(a: &[u8; N], b: &[u8; N], condition: bool, op: F) -> [u8; N]
where
F: Fn(u8, u8) -> u8,
{
let choice = Choice::from(condition as u8);
let mut result = [0u8; N];
for i in 0..N {
let operated = op(a[i], b[i]);
result[i] = u8::conditional_select(&a[i], &operated, choice);
}
result
}
pub fn ct_mask(condition: bool) -> u8 {
0u8.wrapping_sub(condition as u8)
}