libhydrogen 0.4.1

A modern and easy to use cryptography library
Documentation
use super::ensure_initialized;
use crate::ffi;
use crate::utils;
use crate::{errors::*, random};
use core::mem::{self, size_of_val, MaybeUninit};

pub const BYTES: usize = ffi::hydro_sign_BYTES as usize;
pub const CONTEXTBYTES: usize = ffi::hydro_sign_CONTEXTBYTES as usize;
pub const PUBLICKEYBYTES: usize = ffi::hydro_sign_PUBLICKEYBYTES as usize;
pub const SECRETKEYBYTES: usize = ffi::hydro_sign_SECRETKEYBYTES as usize;
pub const SEEDBYTES: usize = ffi::hydro_sign_SEEDBYTES as usize;

#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
pub struct Context([u8; CONTEXTBYTES]);

#[derive(Debug, Copy, PartialEq, Eq, Clone)]
pub struct PublicKey([u8; PUBLICKEYBYTES]);

#[derive(Clone)]
pub struct SecretKey([u8; SECRETKEYBYTES]);

#[derive(Clone)]
pub struct KeyPair {
    pub public_key: PublicKey,
    pub secret_key: SecretKey,
}

#[derive(Debug, Clone)]
pub struct Seed([u8; SEEDBYTES]);

#[derive(Debug, Clone)]
pub struct State(ffi::hydro_sign_state);

#[derive(Copy, Clone)]
pub struct Signature([u8; BYTES]);

pub struct Sign {
    state: State,
}

impl Drop for Seed {
    fn drop(&mut self) {
        utils::memzero(self)
    }
}

impl From<[u8; SEEDBYTES]> for Seed {
    #[inline]
    fn from(seed: [u8; SEEDBYTES]) -> Seed {
        Seed(seed)
    }
}

impl Into<[u8; SEEDBYTES]> for Seed {
    #[inline]
    fn into(self) -> [u8; SEEDBYTES] {
        self.0
    }
}

impl AsRef<[u8]> for Seed {
    fn as_ref(&self) -> &[u8] {
        &self.0 as &[u8]
    }
}

impl PartialEq for Seed {
    fn eq(&self, other: &Self) -> bool {
        utils::equal(self, other)
    }
}

impl Eq for Seed {}

impl Seed {
    pub fn gen() -> Seed {
        let mut seed_inner = [0u8; SEEDBYTES];
        random::buf_into(&mut seed_inner);
        Seed(seed_inner)
    }
}

impl Sign {
    fn new(context: &Context) -> Sign {
        unsafe {
            let mut state = MaybeUninit::<State>::uninit();
            ffi::hydro_sign_init(&mut (*state.as_mut_ptr()).0, context.0.as_ptr() as *const _);
            Sign {
                state: state.assume_init(),
            }
        }
    }

    #[inline]
    pub fn update(&mut self, input: &[u8]) {
        unsafe {
            ffi::hydro_sign_update(&mut self.state.0, input.as_ptr() as *const _, input.len());
        }
    }

    pub fn finish_create(mut self, secret_key: &SecretKey) -> Result<Signature, HydroError> {
        unsafe {
            let mut signature = MaybeUninit::<Signature>::uninit();
            if ffi::hydro_sign_final_create(
                &mut self.state.0,
                (*signature.as_mut_ptr()).0.as_mut_ptr(),
                secret_key.0.as_ptr(),
            ) != 0
            {
                return Err(HydroError::InvalidKey);
            }
            Ok(signature.assume_init())
        }
    }

    pub fn finish_verify(
        mut self,
        signature: &Signature,
        public_key: &PublicKey,
    ) -> Result<(), HydroError> {
        if unsafe {
            ffi::hydro_sign_final_verify(
                &mut self.state.0,
                signature.0.as_ptr(),
                public_key.0.as_ptr(),
            )
        } != 0
        {
            return Err(HydroError::InvalidSignature);
        }
        Ok(())
    }
}

#[inline]
pub fn init(context: &Context) -> Sign {
    Sign::new(context)
}

pub fn create(
    input: &[u8],
    context: &Context,
    secret_key: &SecretKey,
) -> Result<Signature, HydroError> {
    let mut sign = init(context);
    sign.update(input);
    sign.finish_create(secret_key)
}

pub fn verify(
    signature: &Signature,
    input: &[u8],
    context: &Context,
    public_key: &PublicKey,
) -> Result<(), HydroError> {
    let mut sign = init(context);
    sign.update(input);
    sign.finish_verify(signature, public_key)
}

impl Drop for State {
    fn drop(&mut self) {
        utils::memzero(self)
    }
}

impl Drop for SecretKey {
    fn drop(&mut self) {
        utils::memzero(self)
    }
}

impl From<[u8; SECRETKEYBYTES]> for SecretKey {
    #[inline]
    fn from(key: [u8; SECRETKEYBYTES]) -> SecretKey {
        SecretKey(key)
    }
}

impl Into<[u8; SECRETKEYBYTES]> for SecretKey {
    #[inline]
    fn into(self) -> [u8; SECRETKEYBYTES] {
        self.0
    }
}

impl AsRef<[u8]> for SecretKey {
    fn as_ref(&self) -> &[u8] {
        &self.0 as &[u8]
    }
}

impl PartialEq for SecretKey {
    fn eq(&self, other: &Self) -> bool {
        utils::equal(self, other)
    }
}

impl Eq for SecretKey {}

impl From<[u8; BYTES]> for Signature {
    #[inline]
    fn from(key: [u8; BYTES]) -> Signature {
        Signature(key)
    }
}

impl Into<[u8; BYTES]> for Signature {
    #[inline]
    fn into(self) -> [u8; BYTES] {
        self.0
    }
}

impl AsRef<[u8]> for Signature {
    fn as_ref(&self) -> &[u8] {
        &self.0 as &[u8]
    }
}

impl PartialEq for Signature {
    fn eq(&self, other: &Self) -> bool {
        utils::equal(self, other)
    }
}

impl Eq for Signature {}

impl From<[u8; PUBLICKEYBYTES]> for PublicKey {
    #[inline]
    fn from(key: [u8; PUBLICKEYBYTES]) -> PublicKey {
        PublicKey(key)
    }
}

impl Into<[u8; PUBLICKEYBYTES]> for PublicKey {
    #[inline]
    fn into(self) -> [u8; PUBLICKEYBYTES] {
        self.0
    }
}

impl AsRef<[u8]> for PublicKey {
    fn as_ref(&self) -> &[u8] {
        &self.0 as &[u8]
    }
}

impl KeyPair {
    pub fn gen() -> KeyPair {
        ensure_initialized();
        unsafe {
            let mut keypair_c = MaybeUninit::<ffi::hydro_sign_keypair>::uninit();
            ffi::hydro_sign_keygen(keypair_c.as_mut_ptr());
            let mut keypair_c = keypair_c.assume_init();
            let mut keypair = MaybeUninit::<KeyPair>::uninit();
            (*keypair.as_mut_ptr())
                .public_key
                .0
                .copy_from_slice(&keypair_c.pk);
            (*keypair.as_mut_ptr())
                .secret_key
                .0
                .copy_from_slice(&keypair_c.sk);
            ffi::hydro_memzero(
                &mut keypair_c as *mut _ as *mut _,
                mem::size_of_val(&keypair_c),
            );
            keypair.assume_init()
        }
    }

    pub fn gen_deterministic(seed: &Seed) -> KeyPair {
        ensure_initialized();
        unsafe {
            let mut keypair_c = MaybeUninit::<ffi::hydro_sign_keypair>::uninit();
            ffi::hydro_sign_keygen_deterministic(keypair_c.as_mut_ptr(), seed.0.as_ptr());
            KeyPair::from(keypair_c)
        }
    }
}

impl From<&'static str> for Context {
    fn from(context_str: &'static str) -> Context {
        let context_str_u8 = context_str.as_bytes();
        let context_str_u8_len = context_str_u8.len();
        if context_str_u8_len > CONTEXTBYTES {
            panic!("Context too long");
        }
        let mut context = Context::default();
        context.0[..context_str_u8_len].copy_from_slice(context_str_u8);
        context
    }
}

impl From<[u8; CONTEXTBYTES]> for Context {
    #[inline]
    fn from(context: [u8; CONTEXTBYTES]) -> Context {
        Context(context)
    }
}

impl Into<[u8; CONTEXTBYTES]> for Context {
    #[inline]
    fn into(self) -> [u8; CONTEXTBYTES] {
        self.0
    }
}

impl From<MaybeUninit<ffi::hydro_sign_keypair>> for KeyPair {
    fn from(keypair_c: MaybeUninit<ffi::hydro_sign_keypair>) -> KeyPair {
        unsafe {
            let mut keypair_c = keypair_c.assume_init();
            let mut keypair = MaybeUninit::<KeyPair>::uninit();
            (*keypair.as_mut_ptr())
                .public_key
                .0
                .copy_from_slice(&keypair_c.pk);
            (*keypair.as_mut_ptr())
                .secret_key
                .0
                .copy_from_slice(&keypair_c.sk);
            ffi::hydro_memzero(&mut keypair_c as *mut _ as *mut _, size_of_val(&keypair_c));
            keypair.assume_init()
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::*;

    #[test]
    fn test_signature() {
        init().unwrap();

        let context = "tests".into();
        let keypair = sign::KeyPair::gen();

        let mut s = sign::init(&context);
        s.update(b"test message");
        let signature = s.finish_create(&keypair.secret_key).unwrap();

        let mut s = sign::init(&context);
        s.update(b"test message");
        s.finish_verify(&signature, &keypair.public_key).unwrap();

        let signature = sign::create(b"test message", &context, &keypair.secret_key).unwrap();
        sign::verify(&signature, b"test message", &context, &keypair.public_key).unwrap();

        let contextx: [u8; sign::CONTEXTBYTES] = context.into();
        let contexty: sign::Context = contextx.into();
        assert_eq!(context, contexty);

        let keypair = sign::KeyPair::gen_deterministic(&sign::Seed::gen());
        let s = sign::init(&context);
        let signature = s.finish_create(&keypair.secret_key).unwrap();
        let s = sign::init(&context);
        s.finish_verify(&signature, &keypair.public_key).unwrap();
    }
}