use core::arch::asm;
#[inline(always)]
pub fn ct_select_u8(a: u8, b: u8, condition: u8) -> u8 {
let result: u32;
unsafe {
asm!(
"negs {mask}, {cond}", "asrs {mask}, {mask}, #31", "ands {t}, {a}, {mask}", "bics {out}, {b}, {mask}", "orrs {out}, {out}, {t}", a = in(reg) a as u32,
b = in(reg) b as u32,
cond = in(reg) condition as u32,
mask = out(reg) _,
t = out(reg) _,
out = out(reg) result,
options(pure, nomem, nostack),
);
}
result as u8
}
#[inline(always)]
pub fn ct_select_i16(a: i16, b: i16, condition: u8) -> i16 {
let result: u32;
unsafe {
asm!(
"negs {mask}, {cond}",
"asrs {mask}, {mask}, #31",
"ands {t}, {a}, {mask}",
"bics {out}, {b}, {mask}",
"orrs {out}, {out}, {t}",
a = in(reg) a as u32,
b = in(reg) b as u32,
cond = in(reg) condition as u32,
mask = out(reg) _,
t = out(reg) _,
out = out(reg) result,
options(pure, nomem, nostack),
);
}
result as i16
}
#[inline(always)]
pub fn ct_select_i32(a: i32, b: i32, condition: u8) -> i32 {
let result: u32;
unsafe {
asm!(
"negs {mask}, {cond}",
"asrs {mask}, {mask}, #31",
"ands {t}, {a}, {mask}",
"bics {out}, {b}, {mask}",
"orrs {out}, {out}, {t}",
a = in(reg) a as u32,
b = in(reg) b as u32,
cond = in(reg) condition as u32,
mask = out(reg) _,
t = out(reg) _,
out = out(reg) result,
options(pure, nomem, nostack),
);
}
result as i32
}
#[inline(always)]
pub fn ct_eq_u32(a: u32, b: u32) -> u8 {
let diff = a ^ b;
let mask = (diff | diff.wrapping_neg()) >> 31;
((mask as u8) ^ 1) & 1
}
#[inline(never)]
pub fn ct_eq(a: &[u8], b: &[u8]) -> u8 {
if a.len() != b.len() {
return 0;
}
let mut diff = 0u8;
for i in 0..a.len() {
diff |= a[i] ^ b[i];
}
let d32 = diff as u32;
let result: u32;
unsafe {
asm!(
"negs {t}, {d}", "orrs {t}, {t}, {d}", "lsrs {t}, {t}, #31", "movs {out}, #1",
"subs {out}, {out}, {t}", d = in(reg) d32,
t = out(reg) _,
out = out(reg) result,
options(pure, nomem, nostack),
);
}
result as u8
}
#[inline(never)]
pub fn ct_copy(dst: &mut [u8], src: &[u8], condition: u8) {
let len = dst.len().min(src.len());
for i in 0..len {
dst[i] = ct_select_u8(src[i], dst[i], condition);
}
}
#[inline(never)]
pub fn ct_select_bytes(out: &mut [u8], a: &[u8], b: &[u8], condition: u8) {
let len = out.len().min(a.len()).min(b.len());
for i in 0..len {
out[i] = ct_select_u8(a[i], b[i], condition);
}
}
#[inline(never)]
pub fn ct_zeroize(buf: &mut [u8]) {
for byte in buf.iter_mut() {
unsafe { core::ptr::write_volatile(byte, 0) };
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
#[inline(never)]
pub fn ct_zeroize_i16(buf: &mut [i16]) {
for val in buf.iter_mut() {
unsafe { core::ptr::write_volatile(val, 0) };
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}