#![allow(unsafe_code)]
use {bssl, c, error, private, rand, signature};
use untrusted;
pub struct EdDSAParameters;
pub struct Ed25519KeyPair {
private_public: [u8; 64],
}
pub struct Ed25519KeyPairBytes {
pub private_key: [u8; 32],
pub public_key: [u8; 32],
}
impl<'a> Ed25519KeyPair {
pub fn generate(rng: &rand::SecureRandom)
-> Result<Ed25519KeyPair, error::Unspecified> {
Ed25519KeyPair::generate_serializable(rng)
.map(|(key_pair, _)| key_pair)
}
pub fn generate_serializable(rng: &rand::SecureRandom)
-> Result<(Ed25519KeyPair, Ed25519KeyPairBytes),
error::Unspecified> {
let mut bytes = Ed25519KeyPairBytes {
private_key: [0; 32],
public_key: [0; 32],
};
try!(rng.fill(&mut bytes.private_key));
unsafe {
GFp_ed25519_public_from_private(bytes.public_key.as_mut_ptr(),
bytes.private_key.as_ptr());
}
let key_pair =
try!(Ed25519KeyPair::from_bytes_unchecked(&bytes.private_key,
&bytes.public_key));
Ok((key_pair, bytes))
}
pub fn from_bytes(private_key: &[u8], public_key: &[u8])
-> Result<Ed25519KeyPair, error::Unspecified> {
let pair =
try!(Ed25519KeyPair::from_bytes_unchecked(private_key, public_key));
let mut public_key_check = [0; 32];
unsafe {
GFp_ed25519_public_from_private(public_key_check.as_mut_ptr(),
pair.private_public.as_ptr());
}
if public_key != public_key_check {
return Err(error::Unspecified);
}
Ok(pair)
}
fn from_bytes_unchecked(private_key: &[u8], public_key: &[u8])
-> Result<Ed25519KeyPair, error::Unspecified> {
if private_key.len() != 32 {
return Err(error::Unspecified);
}
if public_key.len() != 32 {
return Err(error::Unspecified);
}
let mut pair = Ed25519KeyPair { private_public: [0; 64] };
for i in 0..32 {
pair.private_public[i] = private_key[i];
pair.private_public[32 + i] = public_key[i];
}
Ok(pair)
}
pub fn public_key_bytes(&'a self) -> &'a [u8] {
&self.private_public[32..]
}
pub fn sign(&self, msg: &[u8]) -> signature::Signature {
let mut signature_bytes = [0u8; 64];
unsafe {
GFp_ed25519_sign(signature_bytes.as_mut_ptr(), msg.as_ptr(),
msg.len(), self.private_public.as_ptr());
}
signature::Signature::new(signature_bytes)
}
}
pub static ED25519: EdDSAParameters = EdDSAParameters { };
impl signature::VerificationAlgorithm for EdDSAParameters {
fn verify(&self, public_key: untrusted::Input, msg: untrusted::Input,
signature: untrusted::Input) -> Result<(), error::Unspecified> {
let public_key = public_key.as_slice_less_safe();
if public_key.len() != 32 || signature.len() != 64 {
return Err(error::Unspecified);
}
let msg = msg.as_slice_less_safe();
let signature = signature.as_slice_less_safe();
bssl::map_result(unsafe {
GFp_ed25519_verify(msg.as_ptr(), msg.len(), signature.as_ptr(),
public_key.as_ptr())
})
}
}
impl private::Private for EdDSAParameters { }
extern {
fn GFp_ed25519_public_from_private(out: *mut u8,
in_: *const u8);
fn GFp_ed25519_sign(out_sig: *mut u8, message: *const u8,
message_len: c::size_t, private_key: *const u8);
fn GFp_ed25519_verify(message: *const u8, message_len: c::size_t,
signature: *const u8,
public_key: *const u8) -> c::int;
}
#[cfg(test)]
mod tests {
use {test, rand, signature};
use super::Ed25519KeyPair;
use untrusted;
#[test]
fn test_signature_ed25519() {
test::from_file("src/ec/ed25519_tests.txt", |section, test_case| {
assert_eq!(section, "");
let private_key = test_case.consume_bytes("PRIV");
assert_eq!(64, private_key.len());
let public_key = test_case.consume_bytes("PUB");
assert_eq!(32, public_key.len());
let msg = test_case.consume_bytes("MESSAGE");
let expected_sig = test_case.consume_bytes("SIG");
let key_pair = Ed25519KeyPair::from_bytes(&private_key[..32],
&public_key).unwrap();
let actual_sig = key_pair.sign(&msg);
assert_eq!(&expected_sig[..], actual_sig.as_slice());
let public_key = untrusted::Input::from(&public_key);
let msg = untrusted::Input::from(&msg);
let expected_sig = untrusted::Input::from(&expected_sig);
assert!(signature::verify(&signature::ED25519, public_key,
msg, expected_sig).is_ok());
Ok(())
});
}
#[test]
fn test_ed25519_from_bytes_misuse() {
let rng = rand::SystemRandom::new();
let (_, bytes) =
Ed25519KeyPair::generate_serializable(&rng).unwrap();
assert!(Ed25519KeyPair::from_bytes(&bytes.private_key,
&bytes.public_key).is_ok());
assert!(Ed25519KeyPair::from_bytes(&bytes.private_key[..31],
&bytes.public_key).is_err());
assert!(Ed25519KeyPair::from_bytes(&bytes.private_key,
&bytes.public_key[..31]).is_err());
assert!(Ed25519KeyPair::from_bytes(&bytes.public_key,
&bytes.private_key).is_err());
}
}