mod ed25519;
use std;
use shared;
pub const PUBLIC_KEY_BYTES: usize = 32;
pub const SECRET_KEY_BYTES: usize = 64;
pub const SIGN_BYTES: usize = 64;
pub const SIGNATURE_LENGTH: usize = 64;
new_type! {
secret SecretKey(SECRET_KEY_BYTES);
}
new_type! {
public PublicKey(PUBLIC_KEY_BYTES);
}
new_type! {
public Signature(SIGNATURE_LENGTH);
}
pub struct Keypair {
pub public: PublicKey,
pub secret: SecretKey
}
impl Keypair {
pub fn new() -> Keypair {
let mut pk = [0u8; PUBLIC_KEY_BYTES];
let mut sk = [0u8; SECRET_KEY_BYTES];
ed25519::crypto_sign_keypair(&mut pk, &mut sk);
Keypair { public: PublicKey(pk), secret: SecretKey(sk) }
}
pub fn sign(&self, data: &[u8]) -> SignedData {
let mut signed = std::iter::repeat(0).take(data.len() + SIGN_BYTES).collect::<Vec<_>>();
let secret_key = self.secret.clone();
let public_key = self.public.clone();
ed25519::crypto_sign(&mut signed, data, &secret_key.0);
SignedData {public_key: public_key, signed: signed}
}
}
pub struct SignedData {
pub public_key: PublicKey,
pub signed: Vec<u8>
}
impl SignedData {
pub fn verify(&self) -> Option<Vec<u8>> {
let public_key : PublicKey = self.public_key;
let mut msg = std::iter::repeat(0).take(self.signed.len()).collect::<Vec<_>>();
match ed25519::crypto_sign_open(&mut msg, &self.signed, &public_key.0) {
Some(msg_len) => {
println!("msg_len: {}", msg_len);
unsafe {msg.set_len(msg_len as usize);}
Some(msg)
},
None => None,
}
}
}
pub fn signature(data: &[u8], key: &SecretKey) -> Vec<u8> {
let mut signed = std::iter::repeat(0).take(data.len() + SIGN_BYTES).collect::<Vec<_>>();
ed25519::crypto_sign(&mut signed, data, &key.0);
let mut tmp = signed.as_slice();
tmp = &tmp[..SIGNATURE_LENGTH];
let tmp1 = tmp.to_vec();
tmp1
}
pub fn verify_signature(data: &[u8], signature: &[u8], key: &PublicKey) -> bool {
let mut signed = Vec::new();
signed.extend(signature.iter().cloned());
signed.extend(data.iter().cloned());
let mut msg = std::iter::repeat(0).take(signed.len()).collect::<Vec<_>>();
match ed25519::crypto_sign_open(&mut msg, &signed, &key.0) {
Some(_) => true,
None => false
}
}
#[test]
fn test_sign_sanity() {
use std::iter::repeat;
for i in 1..2 {
let keypair = Keypair::new();
let msg: Vec<u8> = repeat(i as u8).take(i * 4).collect();
let sig = keypair.sign(&msg);
let desig = sig.verify();
println!("msg:\t{:?}\nsig:\t{:?}\ndesig:\t{:?}", msg, sig.signed, desig);
assert!(desig.unwrap() == msg);
}
}
#[test]
fn test_sign_fail_sanity() {
let key1 = Keypair::new();
let key2 = Keypair::new();
let msg = b"some message";
let sig = key1.sign(msg);
let altered_sig = SignedData { public_key: key2.public, signed: sig.signed.clone() };
let desig = altered_sig.verify();
println!("msg:\t{:?}\nsig:\t{:?}\ndesig:\t{:?}", msg, sig.signed, desig);
assert!(desig.is_none());
}
#[test]
fn test_sign_verify() {
for i in 0..2usize {
let key = Keypair::new();
let message = shared::random_data_test_helper(i);
let sig = key.sign(&message);
let desig = sig.verify();
assert!(desig.unwrap() == message);
}
}
#[test]
fn test_sign_verify_tamper() {
for i in 0..2usize {
let key = Keypair::new();
let message = shared::random_data_test_helper(i);
let mut sig = key.sign(&message);
let len = sig.signed.len();
for j in 0..len {
sig.signed[j] ^= 0x20;
let desig = sig.verify();
assert!(desig.is_none());
sig.signed[j] ^= 0x20;
}
}
}
#[test]
fn test_sign_verify_detached() {
for i in 10..20usize {
let key = Keypair::new();
let message = shared::random_data_test_helper(i);
let sig = signature(&message, &key.secret);
let b = verify_signature(&message, &sig, &key.public);
assert!(b);
}
}
#[test]
fn test_sign_verify_detached_tamper() {
for i in 0..2usize {
let key = Keypair::new();
let message = shared::random_data_test_helper(i);
let mut sig = signature(&message, &key.secret);
let len = sig.len();
for j in 0..len {
sig[j] ^= 0x20;
let b = verify_signature(&message, &sig, &key.public);
println!("{:?}", b);
assert!(!b);
sig[j] ^= 0x20;
}
}
}
#[test]
fn test_sign_verify_seed() {
for i in 0..2usize {
let mut seedbuf = [0; 32];
super::randombytes(&mut seedbuf);
let seed = seedbuf;
let mut pk = [0u8; PUBLIC_KEY_BYTES];
let mut sk = [0u8; SECRET_KEY_BYTES];
ed25519::crypto_sign_keypair_seed(&mut pk, &mut sk, &seed);
let pk = PublicKey(pk);
let sk = SecretKey(sk);
let key = Keypair{
public: pk,
secret: sk,
};
let message = shared::random_data_test_helper(i);
let mut sig = key.sign(&message);
let desig = sig.verify();
assert!(desig.unwrap() == message);
}
}
#[test]
fn test_sign_verify_tamper_seed() {
for i in 0..2usize {
let mut seedbuf = [0; 32];
super::randombytes(&mut seedbuf);
let seed = seedbuf;
let mut pk = [0u8; PUBLIC_KEY_BYTES];
let mut sk = [0u8; SECRET_KEY_BYTES];
ed25519::crypto_sign_keypair_seed(&mut pk, &mut sk, &seed);
let pk = PublicKey(pk);
let sk = SecretKey(sk);
let key = Keypair{
public: pk,
secret: sk,
};
let message = shared::random_data_test_helper(i);
let mut sig = key.sign(&message);
let len = sig.signed.len();
for j in 0..len {
sig.signed[j] ^= 0x20;
let desig = sig.verify();
assert!(desig.is_none());
sig.signed[j] ^= 0x20;
}
}
}
#[test]
fn test_sign_vectors() {
use rustc_serialize::hex::{FromHex, ToHex};
use std::fs::File;
use std::io::{BufRead, BufReader};
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!(x0[..64].from_hex());
assert!(seed_bytes.len() == 32);
let mut seedbuf = [0u8; 32];
for (s, b) in seedbuf.iter_mut().zip(seed_bytes.iter()) {
*s = *b
}
let seed = seedbuf;
let mut pk = [0u8; PUBLIC_KEY_BYTES];
let mut sk = [0u8; SECRET_KEY_BYTES];
ed25519::crypto_sign_keypair_seed(&mut pk, &mut sk, &seed);
let m = unwrap!(x2.from_hex());
let mut sm = std::iter::repeat(0).take(m.len() + SIGN_BYTES).collect::<Vec<_>>();
ed25519::crypto_sign(&mut sm, &m, &sk);
let smp = sm.clone();
let sg = SignedData {public_key: PublicKey(pk), signed: smp};
assert!(unwrap!(sg.verify()) == m);
assert!(x1 == pk.to_hex());
assert!(x3 == sm.to_hex());
}
}
#[test]
fn test_sign_vectors_detached() {
use rustc_serialize::hex::{FromHex, ToHex};
use std::fs::File;
use std::io::{BufRead, BufReader};
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!(x0[..64].from_hex());
assert!(seed_bytes.len() == 32);
let mut seedbuf = [0u8; 32];
for (s, b) in seedbuf.iter_mut().zip(seed_bytes.iter()) {
*s = *b
}
let seed = seedbuf;
let mut pk = [0u8; PUBLIC_KEY_BYTES];
let mut sk = [0u8; SECRET_KEY_BYTES];
ed25519::crypto_sign_keypair_seed(&mut pk, &mut sk, &seed);
let m = unwrap!(x2.from_hex());
let sk = SecretKey(sk);
let sig = signature(&m, &sk);
let pk = PublicKey(pk);
let b = verify_signature(&m, &sig, &pk);
assert!(b);
assert!(x1 == pk.0.to_hex());
let mut sm = Vec::new();
sm.extend(sig.iter().cloned());
sm.extend(m.iter().cloned());
assert!(x3 == sm.to_hex());
}
}