use std::sync::Once;
use std::sync::ONCE_INIT;
static START: Once = ONCE_INIT;
use sodiumoxide;
use sodiumoxide::crypto::sign::ed25519;
pub const PRIVATE_KEY_LEN: usize = 64;
pub const PUBLIC_KEY_LEN: usize = 32;
pub const SIGNATURE_LEN: usize = 64;
pub fn generate_keypair() -> ([u8; PUBLIC_KEY_LEN], [u8; PRIVATE_KEY_LEN]) {
START.call_once(|| { sodiumoxide::init(); });
let (pk, sk) = ed25519::gen_keypair();
let public_key = pk.0;
let private_key = sk.0;
assert_eq!(PUBLIC_KEY_LEN, public_key.len());
assert_eq!(PRIVATE_KEY_LEN, private_key.len());
(public_key, private_key)
}
pub fn sign(data: &[u8], private_key: &[u8]) -> Vec<u8> {
assert_eq!(private_key.len(), PRIVATE_KEY_LEN);
use sodiumoxide::crypto::sign::ed25519::Signature;
let sk = ed25519::SecretKey::from_slice(private_key);
let sk = sk.as_ref().unwrap();
let sig = match ed25519::sign_detached(data, sk) {
Signature(signature) => signature
};
let mut vec = Vec::new();
vec.extend_from_slice(&sig);
vec
}
pub fn verify(data: &[u8], signature: &[u8], public_key: &[u8]) -> bool {
assert_eq!(signature.len(), SIGNATURE_LEN);
assert_eq!(public_key.len(), PUBLIC_KEY_LEN);
let pk = ed25519::PublicKey::from_slice(public_key);
let pk = pk.as_ref().unwrap();
let sig = ed25519::Signature::from_slice(signature);
let sig = sig.as_ref().unwrap();
ed25519::verify_detached(sig, data, pk)
}
#[test]
fn test_ed25519_simple() {
let (pk, sk) = generate_keypair();
let msg = &[0; 128][..];
let mut sig = sign(msg, &sk);
println!("signature: {:?}", sig);
println!("");
sig[0] = ((sig[0] as u16 + 1) % 256) as u8;
assert_eq!(verify(msg, &sig, &pk), false);
sig[0] = ((sig[0] as u16 + 255) % 256) as u8;
assert_eq!(verify(msg, &sig, &pk), true);
}
#[test]
fn test_ed25519_shortmsg() {
let (pk, sk) = generate_keypair();
let msg = &[0; 32][..];
let mut sig = sign(msg, &sk);
println!("signature: {:?}", sig);
println!("");
sig[0] = ((sig[0] as u16 + 1) % 256) as u8;
assert_eq!(verify(msg, &sig, &pk), false);
sig[0] = ((sig[0] as u16 + 255) % 256) as u8;
assert_eq!(verify(msg, &sig, &pk), true);
}
#[test]
fn test_testvectors() {
use rustc_serialize::json;
use bytescontainer::BytesContainer;
let decode = |t| {
let t = json::decode::<BytesContainer>(&format!("\"{}\"", t)).unwrap();
t.get().clone()
};
let prv = decode("b18e1d0045995ec3d010c387ccfeb984d783af8fbb0f40fa7db126d889f6dadd77f48b59cae\
da77751ed138b0ec667ff50f8768c25d48309a8f386a2bad187fb");
let pbl = decode("77f48b59caeda77751ed138b0ec667ff50f8768c25d48309a8f386a2bad187fb");
let msg =
decode("916c7d1d268fc0e77c1bef238432573c39be577bbea0998936add2b50a653171ce18a542b0b7f96c1691a3be6031522894a8634183eda38798a0c5d5d79fbd01dd04a8646d71873b77b221998a81922d8105f892316369d5224c9983372d2313c6b1f4556ea26ba49d46e8b561e0fc76633ac9766e68e21fba7edca93c4c7460376d7f3ac22ff372c18f613f2ae2e856af40");
let sig = decode("6bd710a368c1249923fc7a1610747403040f0cc30815a00f9ff548a896bbda0b4eb2ca19ebc\
f917f0f34200a9edbad3901b64ab09cc5ef7b9bcc3c40c0ff7509");
let sig_my = sign(&msg, &prv);
assert_eq!(&sig_my, &sig);
assert_eq!(true, verify(&msg, &sig_my, &pbl));
}