use std::convert::TryInto;
use crypto::keys::x25519;
use crypto::signatures::ed25519;
use zeroize::Zeroize;
use crate::crypto::key::ed25519::ed25519_private_try_from_bytes;
use crate::crypto::KeyType;
use crate::crypto::PrivateKey;
use crate::crypto::PublicKey;
use crate::crypto::X25519;
use crate::error::Result;
#[derive(Clone, Debug)]
pub struct KeyPair {
type_: KeyType,
public: PublicKey,
private: PrivateKey,
}
impl KeyPair {
pub fn new(type_: KeyType) -> Result<Self> {
let (public, private): (PublicKey, PrivateKey) = match type_ {
KeyType::Ed25519 => {
let secret: ed25519::SecretKey = ed25519::SecretKey::generate()?;
let public: ed25519::PublicKey = secret.public_key();
let private: PrivateKey = secret.to_bytes().to_vec().into();
let public: PublicKey = public.to_bytes().to_vec().into();
(public, private)
}
KeyType::X25519 => {
let secret: x25519::SecretKey = x25519::SecretKey::generate()?;
let public: x25519::PublicKey = secret.public_key();
let private: PrivateKey = secret.to_bytes().to_vec().into();
let public: PublicKey = public.to_bytes().to_vec().into();
(public, private)
}
};
Ok(Self { type_, public, private })
}
pub fn try_from_private_key_bytes(key_type: KeyType, private_key_bytes: &[u8]) -> Result<Self> {
let (public, private) = match key_type {
KeyType::Ed25519 => {
let private_key: ed25519::SecretKey = ed25519_private_try_from_bytes(private_key_bytes)?;
let public_key: ed25519::PublicKey = private_key.public_key();
let private: PrivateKey = private_key.to_bytes().to_vec().into();
let public: PublicKey = public_key.to_bytes().to_vec().into();
(public, private)
}
KeyType::X25519 => {
let private_key_bytes: [u8; X25519::PRIVATE_KEY_LENGTH] = private_key_bytes
.try_into()
.map_err(|_| crate::Error::InvalidKeyLength(private_key_bytes.len(), X25519::PRIVATE_KEY_LENGTH))?;
let private_key: x25519::SecretKey = x25519::SecretKey::from_bytes(private_key_bytes);
let public_key: x25519::PublicKey = private_key.public_key();
let private: PrivateKey = private_key.to_bytes().to_vec().into();
let public: PublicKey = public_key.to_bytes().to_vec().into();
(public, private)
}
};
Ok(Self {
type_: key_type,
public,
private,
})
}
pub const fn type_(&self) -> KeyType {
self.type_
}
pub const fn public(&self) -> &PublicKey {
&self.public
}
pub const fn private(&self) -> &PrivateKey {
&self.private
}
}
impl Drop for KeyPair {
fn drop(&mut self) {
self.public.zeroize();
self.private.zeroize();
}
}
impl Zeroize for KeyPair {
fn zeroize(&mut self) {
self.public.zeroize();
self.private.zeroize();
}
}
impl From<(KeyType, PublicKey, PrivateKey)> for KeyPair {
fn from(other: (KeyType, PublicKey, PrivateKey)) -> Self {
Self {
type_: other.0,
public: other.1,
private: other.2,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_ed25519() {
let keypair: KeyPair = KeyPair::new(KeyType::Ed25519).unwrap();
assert_eq!(keypair.type_(), KeyType::Ed25519);
assert_eq!(keypair.public().as_ref().len(), 32);
assert_eq!(keypair.private().as_ref().len(), 32);
}
#[test]
fn test_new_x25519() {
let keypair: KeyPair = KeyPair::new(KeyType::X25519).unwrap();
assert_eq!(keypair.type_(), KeyType::X25519);
assert_eq!(keypair.public().as_ref().len(), 32);
assert_eq!(keypair.private().as_ref().len(), 32);
}
#[test]
fn test_try_from_private_key_bytes() {
for key_type in [KeyType::Ed25519, KeyType::X25519] {
let keypair: KeyPair = KeyPair::new(key_type).unwrap();
let reconstructed: KeyPair = KeyPair::try_from_private_key_bytes(key_type, keypair.private.as_ref()).unwrap();
assert_eq!(keypair.private.as_ref(), reconstructed.private.as_ref());
assert_eq!(keypair.public.as_ref(), reconstructed.public.as_ref());
}
}
}