use std::num::Wrapping as W;
pub type Gf = [i64;16];
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;
}
((W(1) & ((W(d) - W(1)) >> 8)) - W(1)).0 as isize }
pub fn verify_16(x: &[u8;16], y: &[u8;16]) -> bool { vn(&x[..], &y[..]) == 0 }
pub fn verify_32(x: &[u8;32], y: &[u8;32]) -> bool { vn(&x[..], &y[..]) == 0 }
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;
}
pub fn sel25519(p: &mut Gf,q: &mut Gf, b: isize ) {
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;
}
}
pub fn gf_add(o: &mut Gf, a: Gf, b: Gf) {
for i in 0..16 {
o[i]=a[i]+b[i];
}
}
pub fn gf_subtract(o: &mut Gf, a: Gf, b: Gf) {
for i in 0..16 {
o[i]=a[i]-b[i];
}
}
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;
}
}
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);
}
pub fn gf_square(o: &mut Gf, a: Gf) {
gf_multiply(o,a,a);
}
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() {
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];
}
}
pub fn pack25519(o: &mut [u8;32], n: Gf) {
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);
let b : isize = ((m[15]>>16)&1) as isize;
m[14]&=0xffff;
sel25519(&mut t, &mut m, 1-b as isize);
}
for i in 0..16 {
o[2*i]= t[i] as u8; o[2*i+1]= (t[i]>>8) as u8;
}
}
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))
}
}
}
use memsec;
use std::{cmp, mem};
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
}
}
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 {
let x = super::get_random_bytes(i);
assert!(memcmp(&x, &x));
let mut y = x.clone();
assert!(memcmp(&x, &y));
y.push(0);
assert!(!memcmp(&x, &y));
assert!(!memcmp(&y, &x));
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]);
}