use crate::ffi;
use libc::c_ulonglong;
pub const SEEDBYTES: usize = ffi::crypto_sign_ed25519_SEEDBYTES as usize;
pub const SECRETKEYBYTES: usize = ffi::crypto_sign_ed25519_SECRETKEYBYTES as usize;
pub const PUBLICKEYBYTES: usize = ffi::crypto_sign_ed25519_PUBLICKEYBYTES as usize;
pub const SIGNATUREBYTES: usize = ffi::crypto_sign_ed25519_BYTES as usize;
new_type! {
secret Seed(SEEDBYTES);
}
new_type! {
secret SecretKey(SECRETKEYBYTES);
}
new_type! {
public PublicKey(PUBLICKEYBYTES);
}
new_type! {
public Signature(SIGNATUREBYTES);
}
pub fn gen_keypair() -> (PublicKey, SecretKey) {
unsafe {
let mut pk = [0u8; PUBLICKEYBYTES];
let mut sk = [0u8; SECRETKEYBYTES];
let _todo_use_result = ffi::crypto_sign_ed25519_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
(PublicKey(pk), SecretKey(sk))
}
}
pub fn keypair_from_seed(&Seed(ref seed): &Seed) -> (PublicKey, SecretKey) {
unsafe {
let mut pk = [0u8; PUBLICKEYBYTES];
let mut sk = [0u8; SECRETKEYBYTES];
let _todo_use_result =
ffi::crypto_sign_ed25519_seed_keypair(pk.as_mut_ptr(), sk.as_mut_ptr(), seed.as_ptr());
(PublicKey(pk), SecretKey(sk))
}
}
pub fn sign(m: &[u8], &SecretKey(ref sk): &SecretKey) -> Vec<u8> {
unsafe {
let mut sm = vec![0u8; m.len() + SIGNATUREBYTES];
let mut smlen = 0;
let _todo_use_result = ffi::crypto_sign_ed25519(
sm.as_mut_ptr(),
&mut smlen,
m.as_ptr(),
m.len() as c_ulonglong,
sk.as_ptr(),
);
sm.truncate(smlen as usize);
sm
}
}
pub fn verify(sm: &[u8], &PublicKey(ref pk): &PublicKey) -> Result<Vec<u8>, ()> {
unsafe {
let mut m = vec![0u8; sm.len()];
let mut mlen = 0;
if ffi::crypto_sign_ed25519_open(
m.as_mut_ptr(),
&mut mlen,
sm.as_ptr(),
sm.len() as c_ulonglong,
pk.as_ptr(),
) == 0
{
m.truncate(mlen as usize);
Ok(m)
} else {
Err(())
}
}
}
pub fn sign_detached(m: &[u8], &SecretKey(ref sk): &SecretKey) -> Signature {
unsafe {
let mut sig = [0u8; SIGNATUREBYTES];
let mut siglen: c_ulonglong = 0;
let _todo_use_result = ffi::crypto_sign_ed25519_detached(
sig.as_mut_ptr(),
&mut siglen,
m.as_ptr(),
m.len() as c_ulonglong,
sk.as_ptr(),
);
assert_eq!(siglen, SIGNATUREBYTES as c_ulonglong);
Signature(sig)
}
}
pub fn verify_detached(
&Signature(ref sig): &Signature,
m: &[u8],
&PublicKey(ref pk): &PublicKey,
) -> bool {
unsafe {
0 == ffi::crypto_sign_ed25519_verify_detached(
sig.as_ptr(),
m.as_ptr(),
m.len() as c_ulonglong,
pk.as_ptr(),
)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_sign_verify() {
use crate::randombytes::randombytes;
unwrap!(crate::init());
for i in 0..256usize {
let (pk, sk) = gen_keypair();
let m = randombytes(i);
let sm = sign(&m, &sk);
let m2 = verify(&sm, &pk);
assert!(Ok(m) == m2);
}
}
#[test]
fn test_sign_verify_tamper() {
use crate::randombytes::randombytes;
unwrap!(crate::init());
for i in 0..32usize {
let (pk, sk) = gen_keypair();
let m = randombytes(i);
let mut sm = sign(&m, &sk);
for j in 0..sm.len() {
sm[j] ^= 0x20;
assert!(Err(()) == verify(&sm, &pk));
sm[j] ^= 0x20;
}
}
}
#[test]
fn test_sign_verify_detached() {
use crate::randombytes::randombytes;
unwrap!(crate::init());
for i in 0..256usize {
let (pk, sk) = gen_keypair();
let m = randombytes(i);
let sig = sign_detached(&m, &sk);
assert!(verify_detached(&sig, &m, &pk));
}
}
#[test]
fn test_sign_verify_detached_tamper() {
use crate::randombytes::randombytes;
unwrap!(crate::init());
for i in 0..32usize {
let (pk, sk) = gen_keypair();
let m = randombytes(i);
let Signature(mut sig) = sign_detached(&m, &sk);
for j in 0..SIGNATUREBYTES {
sig[j] ^= 0x20;
assert!(!verify_detached(&Signature(sig), &m, &pk));
sig[j] ^= 0x20;
}
}
}
#[test]
fn test_sign_verify_seed() {
use crate::randombytes::{randombytes, randombytes_into};
unwrap!(crate::init());
for i in 0..256usize {
let mut seedbuf = [0; 32];
randombytes_into(&mut seedbuf);
let seed = Seed(seedbuf);
let (pk, sk) = keypair_from_seed(&seed);
let m = randombytes(i);
let sm = sign(&m, &sk);
let m2 = verify(&sm, &pk);
assert!(Ok(m) == m2);
}
}
#[test]
fn test_sign_verify_tamper_seed() {
use crate::randombytes::{randombytes, randombytes_into};
unwrap!(crate::init());
for i in 0..32usize {
let mut seedbuf = [0; 32];
randombytes_into(&mut seedbuf);
let seed = Seed(seedbuf);
let (pk, sk) = keypair_from_seed(&seed);
let m = randombytes(i);
let mut sm = sign(&m, &sk);
for j in 0..sm.len() {
sm[j] ^= 0x20;
assert!(Err(()) == verify(&sm, &pk));
sm[j] ^= 0x20;
}
}
}
#[test]
fn test_vectors() {
use hex;
use std::fs::File;
use std::io::{BufRead, BufReader};
unwrap!(crate::init());
let r = BufReader::new(unwrap!(File::open("testvectors/ed25519.input")));
for mline in r.lines() {
let line = unwrap!(mline);
let mut x = line.split(':');
let x0 = unwrap!(x.next());
let x1 = unwrap!(x.next());
let x2 = unwrap!(x.next());
let x3 = unwrap!(x.next());
let seed_bytes = unwrap!(hex::decode(&x0[..64]));
assert!(seed_bytes.len() == SEEDBYTES);
let mut seedbuf = [0u8; SEEDBYTES];
for (s, b) in seedbuf.iter_mut().zip(seed_bytes.iter()) {
*s = *b
}
let seed = Seed(seedbuf);
let (pk, sk) = keypair_from_seed(&seed);
let m = unwrap!(hex::decode(x2));
let sm = sign(&m, &sk);
assert!(unwrap!(verify(&sm, &pk)) == m);
assert!(x1 == hex::encode(&pk[..]));
assert!(x3 == hex::encode(&sm));
}
}
#[test]
fn test_vectors_detached() {
use hex;
use std::fs::File;
use std::io::{BufRead, BufReader};
unwrap!(crate::init());
let r = BufReader::new(unwrap!(File::open("testvectors/ed25519.input")));
for mline in r.lines() {
let line = unwrap!(mline);
let mut x = line.split(':');
let x0 = unwrap!(x.next());
let x1 = unwrap!(x.next());
let x2 = unwrap!(x.next());
let x3 = unwrap!(x.next());
let seed_bytes = unwrap!(hex::decode(&x0[..64]));
assert!(seed_bytes.len() == SEEDBYTES);
let mut seedbuf = [0u8; SEEDBYTES];
for (s, b) in seedbuf.iter_mut().zip(seed_bytes.iter()) {
*s = *b
}
let seed = Seed(seedbuf);
let (pk, sk) = keypair_from_seed(&seed);
let m = unwrap!(hex::decode(&x2));
let sig = sign_detached(&m, &sk);
assert!(verify_detached(&sig, &m, &pk));
assert!(x1 == hex::encode(&pk[..]));
let sm = hex::encode(&sig[..]) + x2; assert!(x3 == sm);
}
}
#[test]
fn test_serialisation() {
use crate::randombytes::randombytes;
use crate::test_utils::round_trip;
unwrap!(crate::init());
for i in 0..256usize {
let (pk, sk) = gen_keypair();
let m = randombytes(i);
let sig = sign_detached(&m, &sk);
round_trip(&pk);
round_trip(&sk);
round_trip(&sig);
}
}
}
#[cfg(feature = "benchmarks")]
#[cfg(test)]
mod bench {
extern crate test;
use super::*;
use crate::randombytes::randombytes;
const BENCH_SIZES: [usize; 14] = [0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096];
#[bench]
fn bench_sign(b: &mut test::Bencher) {
unwrap!(crate::init());
let (_, sk) = gen_keypair();
let ms: Vec<Vec<u8>> = BENCH_SIZES.iter().map(|s| randombytes(*s)).collect();
b.iter(|| {
for m in ms.iter() {
sign(m, &sk);
}
});
}
#[bench]
fn bench_verify(b: &mut test::Bencher) {
unwrap!(crate::init());
let (pk, sk) = gen_keypair();
let sms: Vec<Vec<u8>> = BENCH_SIZES
.iter()
.map(|s| {
let m = randombytes(*s);
sign(&m, &sk)
})
.collect();
b.iter(|| {
for sm in sms.iter() {
verify(sm, &pk);
}
});
}
}