microsalt 0.2.21

easy to use rust crypto lib (tweetnacl & FFI bindings to it)
Documentation
//Internal Shared Functions
use std::num::Wrapping as W;

///Typedef: Gf -> i64 [16], representing 256-bit integer in radix 2^16
pub type Gf = [i64;16];
//const gf0 = {0}
const GF0 : Gf = [0; 16];

fn vn(x: &[u8], y: &[u8]) -> isize {
    assert_eq!(x.len(), y.len());
    let mut d = 0u32;
    for i in 0..x.len() {
        d |= (x[i] ^ y[i]) as u32;
    }

    /* FIXME: check this cast. appears this function might be attempting to sign extend. This also
     * affects a bunch of other functions that right now have isize as a return type */
    ((W(1) & ((W(d) - W(1)) >> 8)) - W(1)).0 as isize //(1 & ((d - 1) >> 8)) - 1;
}

/* XXX: public in tweet-nacl */
pub fn verify_16(x: &[u8;16], y: &[u8;16]) -> bool { vn(&x[..], &y[..]) == 0 }

/* XXX: public in tweet-nacl */
pub fn verify_32(x: &[u8;32], y: &[u8;32]) -> bool { vn(&x[..], &y[..]) == 0 }

//load integer mod 2^255 - 19
pub fn unpack25519(o: &mut Gf, n: &[u8]) {
    for i in 0..16 {
        o[i]=n[2*i] as i64+((n[2*i+1] as i64)<<8);
    }
    o[15]&=0x7fff;
}

//256-bit conditional swap
pub fn sel25519(p: &mut Gf,q: &mut Gf, b: isize /* int */) {
    /* XXX: FIXME: check sign extention */
    let c : i64 = !(b - 1) as i64;
    for i in 0..16 {
        let t = c & (p[i]^q[i]);
        p[i]^=t;
        q[i]^=t;
    }
}

//Add 256-bit integers, radix 2^16
pub fn gf_add(o: &mut Gf, a: Gf, b: Gf) {
    for i in 0..16 {
        o[i]=a[i]+b[i];
    }
}

//Subtract 256-bit integers, radix 2^16
pub fn gf_subtract(o: &mut Gf, a: Gf, b: Gf) {
    for i in 0..16 {
        o[i]=a[i]-b[i];
    }
}

//reduce mod 2^255 - 19, radix 2^16
pub fn car25519(o: &mut Gf){
    for i in 0..16 {
        o[i] += 1<<16;
        let c = o[i]>>16;
        o[if i<15 {i+1} else {0}] += c-1 + (if i==15 {37*(c-1)} else {0});
        o[i]-=c<<16;
    }
}

//multiply mod 2^255 - 19, radix 2^16
pub fn gf_multiply(o: &mut Gf, a: Gf, b: Gf) {
    let mut t = [0i64;31];

    for i in 0..16 {
        for j in 0..16 {
            t[i+j] += a[i]*b[j];
        }
    }

    for i in 0..15 {
        t[i] += 38*t[i+16];
    }

    for i in 0..16 {
        o[i]=t[i];
    }
    
    car25519(o);
    car25519(o);
}

//Square mod 2^255 - 19, radix 2^16
pub fn gf_square(o: &mut Gf, a: Gf) {
    gf_multiply(o,a,a);
}

//Power 2^255 - 21 mod 2^255 - 19
pub fn inv25519(o: &mut Gf, i: Gf) {
    let mut c = GF0;
    for a in 0..16 {
        c[a]=i[a];
    }
    for a in (0..254).rev() {
        /* XXX: avoid aliasing with a copy */
        let mut tmp = GF0;
        gf_square(&mut tmp,c);
        if a!=2 && a!=4 {
            gf_multiply(&mut c,tmp,i);
        } else {
            c = tmp;
        }
    }
    for a in 0..16 {
        o[a]=c[a];
    }
}

//Freeze integer mod 2^255 - 19 and store
pub fn pack25519(o: &mut [u8;32], n: Gf) {
    /* XXX: uninit in tweet-nacl */
    let mut m : Gf = GF0;
    let mut t : Gf = n;

    for i in 0..16 { t[i] = n[i]; }

    car25519(&mut t);
    car25519(&mut t);
    car25519(&mut t);

    for _ in 0..2 {
        m[0]=t[0]-0xffed;
        for i in 1..15 {
            m[i]=t[i]-0xffff-((m[i-1]>>16)&1);
            m[i-1]&=0xffff;
        }
        m[15]=t[15]-0x7fff-((m[14]>>16)&1);
        /* FIXME: check isize casts here, seems like b is a boolean */
        let b : isize = ((m[15]>>16)&1) as isize;
        m[14]&=0xffff;
        /* FIXME: check isize cast here */
        sel25519(&mut t, &mut m, 1-b as isize);
    }
    for i in 0..16 {
        o[2*i]= t[i] as u8; //o[2*i]=t[i]&0xff; compare these later
        o[2*i+1]= (t[i]>>8) as u8;
    }
}

//random data helper
pub fn random_data_test_helper(len: usize) -> Vec<u8> {
    let mut message = Vec::with_capacity(len);
    super::randombytes(&mut message);
    message
}


#[test]
fn test_verify_16() {
    use super::*;

    for _ in 0usize..256 {
        let mut x = [0u8; 16];
        let mut y = [0u8; 16];
        assert!(verify_16(&x, &y));
        randombytes(&mut x);
        randombytes(&mut y);

        if x == y {
            assert!(verify_16(&x, &y))
        } else {
            assert!(!verify_16(&x, &y))
        }
    }
}


#[test]
fn test_verify_32() {
    use super::*;

    for _ in 0usize..256 {
        let mut x = [0; 32];
        let mut y = [0; 32];
        assert!(verify_32(&x, &y));
        randombytes(&mut x);
        randombytes(&mut y);

        if x == y {
            assert!(verify_32(&x, &y))
        } else {
            assert!(!verify_32(&x, &y))
        }
    }
}


/////////////////////////
//UTILS
////////////////////////
// derived and modified as needed from https://github.com/dnaq/sodiumoxide/blob/master/src/utils.rs
use memsec;
use std::{cmp, mem};

// `memcmp()` returns true if `x[0]`, `x[1]`, ..., `x[len-1]` are the
// same as `y[0]`, `y[1]`, ..., `y[len-1]`. Otherwise it returns `false`.
//
// This function is safe to use for secrets `x[0]`, `x[1]`, ..., `x[len-1]`,
// `y[0]`, `y[1]`, ..., `y[len-1]`. The time taken by `memcmp` is independent
// of the contents of `x[0]`, `x[1]`, ..., `x[len-1]`, `y[0]`, `y[1]`, ..., `y[len-1]`.
// In contrast, the standard C comparison function `memcmp(x,y,len)` takes time
// that depends on the longest matching prefix of `x` and `y`, often allowing easy
// timing attacks.
pub fn memcmp(x: &[u8], y: &[u8]) -> bool {
    if x.len() != y.len() {
        return false
    }
    unsafe {
        memsec::memcmp(x.as_ptr(), y.as_ptr(), x.len()) == 0
    }
}

/// `memzero()` tries to effectively zero out the data in `x` even if
/// optimizations are being applied to the code.
pub fn memzero(x: &mut [u8]) {
    unsafe {
        memsec::memzero(x.as_mut_ptr(), mem::size_of_val(x));
    }
}

#[test]
fn test_memcmp() {
    for i in 0usize..256 {
        //fill x with random bytes
        let x = super::get_random_bytes(i);
        //should be true comapring x with itself
        assert!(memcmp(&x, &x));
        //copy x into y 
        let mut y = x.clone();
        //compare x to y should be same 
        assert!(memcmp(&x, &y));
        //change y 
        y.push(0);
        //now that we changed y should be diff than x 
        assert!(!memcmp(&x, &y));
        assert!(!memcmp(&y, &x));
        //fill y again with new random bytes
        y = super::get_random_bytes(i);
        if x == y {
            assert!(memcmp(&x, &y))
        } else {
            assert!(!memcmp(&x, &y))
        }
    }
}

#[test]
fn test_memzero() {
    let mut x = [1u8; 16];
    memzero(&mut x);
    assert_eq!(x, [0; 16]);
    x.clone_from_slice(&[1; 16]);
    assert_eq!(x, [1; 16]);
    unsafe { memsec::memzero(x[1..11].as_mut_ptr(), 10 * mem::size_of_val(&x[0])) };
    assert_eq!(x, [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1]);
}