skymd 0.1.10

Rust bindings for hacl*
use rand_core::{OsRng, RngCore};
use zeroize::Zeroize;

use crate::ffi::{EverCrypt_Curve25519_ecdh, EverCrypt_Curve25519_secret_to_public};

pub const KEY_LEN: usize = 32;

#[derive(Debug, Default)]
pub struct PublicKey {
    key: [u8; KEY_LEN],
}

#[derive(Debug, Default)]
pub struct PrivateKey {
    key: [u8; KEY_LEN],
}

#[derive(Debug)]
pub struct SharedSecret {
    key: [u8; KEY_LEN],
}

impl Drop for PrivateKey {
    fn drop(&mut self) {
        self.key.zeroize();
    }
}

impl Drop for SharedSecret {
    fn drop(&mut self) {
        self.key.zeroize();
    }
}

pub fn keypair() -> (PublicKey, PrivateKey) {
    let priv_key = PrivateKey::new();
    let mut pub_key = [0u8; KEY_LEN];

    unsafe {
        EverCrypt_Curve25519_secret_to_public(pub_key.as_mut_ptr(), priv_key.key.as_ptr());
    }

    let pub_key = PublicKey { key: pub_key };

    (pub_key, priv_key)
}

impl SharedSecret {
    pub fn as_bytes(&self) -> &[u8] {
        &self.key
    }
}

impl PublicKey {
    pub fn as_bytes(&self) -> &[u8] {
        &self.key
    }
}

impl PrivateKey {
    pub fn new() -> Self {
        let mut buf = [0u8; KEY_LEN];

        OsRng.fill_bytes(&mut buf);
        PrivateKey::scalar(&mut buf);

        Self { key: buf }
    }

    fn scalar(buf: &mut [u8; KEY_LEN]) {
        buf[0] &= 248;
        buf[31] &= 127;
        buf[31] |= 64;
    }

    pub fn as_bytes(&self) -> &[u8] {
        &self.key
    }

    pub fn from_slice(mut slice: [u8; KEY_LEN]) -> Self {
        PrivateKey::scalar(&mut slice);
        Self { key: slice }
    }

    pub fn ecdh(&self, public_key: &PublicKey) -> SharedSecret {
        let mut ss = [0u8; KEY_LEN];
        unsafe {
            EverCrypt_Curve25519_ecdh(ss.as_mut_ptr(), self.key.as_ptr(), public_key.key.as_ptr());
        }
        SharedSecret { key: ss }
    }
}

impl From<[u8; KEY_LEN]> for PrivateKey {
    fn from(pk: [u8; KEY_LEN]) -> PrivateKey {
        let mut pk = PrivateKey { key: pk };
        PrivateKey::scalar(&mut pk.key);
        pk
    }
}

impl From<[u8; KEY_LEN]> for PublicKey {
    fn from(pk: [u8; KEY_LEN]) -> PublicKey {
        PublicKey { key: pk }
    }
}

impl From<&PrivateKey> for PublicKey {
    fn from(privkey: &PrivateKey) -> PublicKey {
        let mut pubkey = PublicKey { key: [0; KEY_LEN] };
        unsafe {
            EverCrypt_Curve25519_secret_to_public(pubkey.key.as_mut_ptr(), privkey.key.as_ptr());
        }
        pubkey
    }
}

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

    #[test]
    fn ecdh_test() {
        crate::skymd_init();
        let (pub_key1, priv_key1) = keypair();
        let (pub_key2, priv_key2) = keypair();
        assert_eq!(priv_key1.ecdh(&pub_key2).key, priv_key2.ecdh(&pub_key1).key);
    }
}