confitul 0.1.4

ConfitUL contains utilities for ConfitDB which is an experimental, distributed, real-time database, giving full control on conflict resolution.
Documentation
use ed25519_dalek;
use sha2::Digest;
use signature;
use std::convert::TryFrom;

pub const CONTEXT: &'static [u8] = env!("CARGO_PKG_HOMEPAGE").as_bytes();

/// Verify that a message is correctly signed.
///
/// The difference between a plain ed25519 verify is that this
/// one uses a specific "context" so that it expects a message
/// signed by same "context" and will not validate the same message
/// signed by another app with the same algorithm.
///
/// # Examples
/// ```
/// use confitul::{sign,verify};
/// use ed25519_dalek::Keypair;
/// use rand07::rngs::OsRng;
///
/// let mut csprng = OsRng {};
/// let keypair: Keypair = Keypair::generate(&mut csprng);
///
/// let foo = "foo foo foo".as_bytes();
/// let sig_foo = sign(&keypair, foo);
/// assert!(matches!(verify(&keypair.public, foo, &sig_foo), Ok(())));
/// ```
pub fn verify(
    key: &ed25519_dalek::PublicKey,
    msg: &[u8],
    sig: &[u8],
) -> Result<(), signature::Error> {
    let sig = ed25519_dalek::Signature::try_from(sig)?;
    if CONTEXT.len() == 0 {
        return Err(signature::Error::new());
    }
    let mut prehashed = ed25519_dalek::Sha512::new();
    prehashed.update(msg);
    key.verify_prehashed(prehashed, Some(CONTEXT), &sig)
}

/// Sign a message.
///
/// The difference between a plain ed25519 sign is that this
/// one uses a specific "context" so that a message signed by
/// another app with the same algorithm does not have the same
/// signature.
///
/// # Examples
/// ```
/// use confitul::{sign,verify};
/// use ed25519_dalek::Keypair;
/// use rand07::rngs::OsRng;
///
/// let mut csprng = OsRng {};
/// let keypair: Keypair = Keypair::generate(&mut csprng);
///
/// let foo = "foo foo foo".as_bytes();
/// let sig_foo = sign(&keypair, foo);
/// assert!(matches!(verify(&keypair.public, foo, &sig_foo), Ok(())));
/// ```
pub fn sign(key: &ed25519_dalek::Keypair, msg: &[u8]) -> Vec<u8> {
    let mut prehashed = ed25519_dalek::Sha512::new();
    prehashed.update(msg);
    key.sign_prehashed(prehashed, Some(CONTEXT))
        .unwrap()
        .to_bytes()
        .into()
}

#[cfg(test)]
mod tests {
    use super::{sign, verify};
    use ed25519_dalek::Keypair;
    use rand07::rngs::OsRng;

    #[test]
    fn test_sign_verify() {
        let mut csprng = OsRng {};
        let keypair: Keypair = Keypair::generate(&mut csprng);

        let foo = "foo".as_bytes();
        let bar = "bar".as_bytes();
        let sig_foo = sign(&keypair, foo);
        let sig_bar = sign(&keypair, bar);

        assert!(matches!(verify(&keypair.public, foo, &sig_foo), Ok(())));
        assert!(matches!(verify(&keypair.public, foo, &sig_bar), Err(_)));
        assert!(matches!(verify(&keypair.public, bar, &sig_bar), Ok(())));
        assert!(matches!(verify(&keypair.public, bar, &sig_foo), Err(_)));
    }

    #[test]
    fn test_export_public() {
        let mut csprng = OsRng {};
        let keypair: Keypair = Keypair::generate(&mut csprng);
        let export = Vec::from(keypair.public.to_bytes());
        let public = ed25519_dalek::PublicKey::from_bytes(&export).unwrap();

        let foo = "foo".as_bytes();
        let bar = "bar".as_bytes();
        let sig_foo = sign(&keypair, foo);
        let sig_bar = sign(&keypair, bar);

        assert!(matches!(verify(&public, foo, &sig_foo), Ok(())));
        assert!(matches!(verify(&public, foo, &sig_bar), Err(_)));
        assert!(matches!(verify(&public, bar, &sig_bar), Ok(())));
        assert!(matches!(verify(&public, bar, &sig_foo), Err(_)));
    }
}