insectbox 0.1.0

OpenSSH inspired in-memory key security.
Documentation
use std::ptr;

/// Fills a region of memory with the given byte
///
/// Fills `count` bytes from `start` with `val`.
///
/// Because this function uses [`ptr::write_volatile`] it is supposed not to 
/// be optimized by the compiler.
///
/// # Safety
/// The same safety requirements as for [`ptr::write`] apply.
#[inline(never)]
pub unsafe fn memset(start: *mut u8, val: u8, count: usize) {
    let start = ptr::read_volatile(&start);
    let val = ptr::read_volatile(&val);
    let count = ptr::read_volatile(&count);

    for i in 0..count {
        ptr::write(start.add(i), val);
    }

    let _ = ptr::read_volatile(&start);
}

/// An "alias" for [`memset`] with `val = 0`
#[inline]
pub unsafe fn memzero(start: *mut u8, count: usize) {
    memset(start, 0, count)
}


/// Checks for equality in constant time
///
/// Checks if `count` bytes starting at `x` are the same as `count` bytes 
/// starting at `y`.
#[inline(never)]
pub unsafe fn memeq(x: *const u8, y: *const u8, count: usize) -> bool {
    (0..count)
        .map(|i| ptr::read_volatile(x.add(i)) ^ ptr::read_volatile(y.add(i)))
        .fold(0, |acc, val| acc | val)
        .eq(&0)
}

/// Compare memory in constant time
///
/// This function is a constant time implementation of C's 
/// [`memcmp`](https://en.cppreference.com/w/c/string/byte/memcmp).
#[inline(never)]
pub unsafe fn memcmp(x: *const u8, y: *const u8, count: usize) -> i32 {
    let mut res = 0;
    for i in (0..count).rev() {
        let diff =
            i32::from(ptr::read_volatile(x.add(i))) - i32::from(ptr::read_volatile(y.add(i)));
        res = (res & (((diff - 1) & !diff) >> 8)) | diff;
    }
    ((res - 1) >> 8) + (res >> 8) + 1
}