1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
//! Public key signature functions
//!
//! [Official documentation](https://monocypher.org/manual/sign)

use ffi;
use std::mem;

pub fn check(signature: [u8; 64], public_key: [u8; 32], message: &[u8]) -> Result<(), String> {
    unsafe {
        if ffi::crypto_check(
            signature.as_ptr(),
            public_key.as_ptr(),
            message.as_ptr(),
            message.len(),
        ) == 0
            {
                return Ok(());
            }
        Err("Forged message detected.".to_owned())
    }
}

pub struct Context(ffi::crypto_check_ctx);

impl Context {
    #[inline]
    pub fn new(signature: [u8; 64], public_key: [u8; 32]) -> Context {
        unsafe {
            let mut ctx = mem::uninitialized();
            ffi::crypto_check_init(&mut ctx, signature.as_ptr(), public_key.as_ptr());
            Context(ctx)
        }
    }

    #[inline]
    pub fn update(&mut self, message: &[u8]) {
        unsafe {
            ffi::crypto_check_update(&mut self.0, message.as_ptr(), message.len());
        }
    }

    #[inline]
    pub fn finalize(&mut self) -> Result<(), String> {
        unsafe {
            if ffi::crypto_check_final(&mut self.0) == 0 {
                return Ok(());
            }
            Err("Message corrupted, aborting.".to_owned())
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use ::pubkey::sign;

    #[test]
    fn check() {
        let secret_key = [2u8; 32];
        let public_key = ::pubkey::sign::public_key(secret_key);

        let sig = sign::sign(secret_key, public_key, "test".as_bytes());

        let ret = ::pubkey::check::check(sig, public_key, "test".as_bytes());

        assert_eq!(ret.is_ok(), true)
    }

    #[test]
    fn check_forged() {
        let secret_key = [2u8; 32];
        let public_key = sign::public_key(secret_key);

        let sig = sign::sign(secret_key, public_key, "test".as_bytes());

        let ret = ::pubkey::check::check(sig, public_key, "not_test".as_bytes());

        assert_eq!(ret.is_err(), true)
    }

    #[test]
    fn ctx() {
        let secret_key = [2u8; 32];
        let public_key = ::pubkey::sign::public_key(secret_key);

        let sig = sign::sign(secret_key, public_key, "test".as_bytes());

        let mut ctx = Context::new(sig, public_key);
        ctx.update("test".as_bytes());
        let ret = ctx.finalize();

        assert_eq!(ret.is_ok(), true)
    }

    #[test]
    fn ctx_fail() {
        let secret_key = [2u8; 32];
        let public_key = ::pubkey::sign::public_key(secret_key);

        let sig = sign::sign(secret_key, public_key, "test".as_bytes());

        let mut ctx = Context::new(sig, public_key);
        ctx.update("not_test".as_bytes());
        let ret = ctx.finalize();

        assert_eq!(ret.is_err(), true);
        assert_eq!(ret.err().unwrap(), "Message corrupted, aborting.".to_owned());
    }
}