use libc::{c_int, c_uchar, c_ulonglong};
use SSError::{self, SIGN, VERIFYSIGNED};
use crypto::utils::secmem;
pub const BYTES: usize = 64;
pub const SEEDBYTES: usize = 32;
pub const PUBLICKEYBYTES: usize = 32;
pub const SECRETKEYBYTES: usize = 64;
extern "C" {
fn crypto_sign(sm: *mut c_uchar,
smlen_p: *mut c_ulonglong,
m: *const c_uchar,
mlen: c_ulonglong,
sk: *const c_uchar) -> c_int;
fn crypto_sign_open(m: *mut c_uchar,
mlen_p: *mut c_ulonglong,
sm: *const c_uchar,
smlen: c_ulonglong,
pk: *const c_uchar) -> c_int;
fn crypto_sign_detached(sig: *mut c_uchar,
siglen_p: *mut c_ulonglong,
m: *const c_uchar,
mlen: c_ulonglong,
sk: *const c_uchar) -> c_int;
fn crypto_sign_verify_detached(sig: *const c_uchar,
m: *const c_uchar,
mlen: c_ulonglong,
pk: *const c_uchar) -> c_int;
}
pub fn sign<'a>(message: &[u8], sk: &[u8]) -> Result<&'a [u8], SSError> {
assert!(sk.len() == SECRETKEYBYTES);
let mut signedmessage = secmem::malloc(BYTES + message.len());
let smlen: u64 = 0;
let res: i32;
unsafe {
res = crypto_sign(signedmessage.as_mut_ptr(),
smlen as *mut c_ulonglong,
message.as_ptr(),
message.len() as c_ulonglong,
sk.as_ptr());
}
if res == 0 {
Ok(signedmessage)
} else {
Err(SIGN("Unable to sign message!"))
}
}
pub fn open<'a>(signedmessage: &[u8],
pk: &[u8]) -> Result<&'a [u8], SSError> {
assert!(pk.len() == PUBLICKEYBYTES);
let mut message = secmem::malloc(signedmessage.len() - BYTES);
let mlen: u64 = 0;
let res: i32;
unsafe {
res = crypto_sign_open(message.as_mut_ptr(),
mlen as *mut c_ulonglong,
signedmessage.as_ptr(),
signedmessage.len() as c_ulonglong,
pk.as_ptr());
}
if res == 0 {
secmem::mprotect_readonly(message);
Ok(message)
} else {
Err(VERIFYSIGNED("Unable to verify signed message!"))
}
}
pub fn sign_detached<'a>(message: &[u8],
sk: &[u8]) -> Result<&'a [u8], SSError> {
assert!(sk.len() == SECRETKEYBYTES);
let mut signature = secmem::malloc(BYTES);
let smlen: u64 = 0;
let res: i32;
unsafe {
res = crypto_sign_detached(signature.as_mut_ptr(),
smlen as *mut c_ulonglong,
message.as_ptr(),
message.len() as c_ulonglong,
sk.as_ptr());
}
if res == 0 {
Ok(signature)
} else {
Err(SIGN("Unable to generate signature!"))
}
}
pub fn open_detached(message: &[u8],
signature: &[u8],
pk: &[u8]) -> i32 {
assert!(signature.len() == BYTES);
assert!(pk.len() == PUBLICKEYBYTES);
let res: i32;
unsafe {
res = crypto_sign_verify_detached(signature.as_ptr(),
message.as_ptr(),
message.len() as c_ulonglong,
pk.as_ptr());
}
res
}