use core::fmt;
use rst_common::with_cryptography::hex;
use rst_common::with_cryptography::rand::{rngs::adapter::ReseedingRng, SeedableRng};
use rst_common::with_cryptography::rand_chacha::{rand_core::OsRng, ChaCha20Core};
use rst_common::with_cryptography::x25519_dalek::{PublicKey as ECDHPublicKey, StaticSecret};
use crate::keysecure::types::constants::CONTEXT_X25519;
use crate::keysecure::types::errors::KeySecureError;
use crate::keysecure::types::ToKeySecure;
use crate::keysecure::builder::Builder;
use crate::keysecure::KeySecure;
use crate::ecdh::pubkey::PublicKey;
use crate::ecdh::secret::Secret;
use crate::ecdh::types::errors::*;
use crate::ecdh::types::ECDHPrivateKeyBytes;
pub struct KeyPair {
secret: StaticSecret,
}
impl fmt::Debug for KeyPair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("KeyPairs")
.field("secret_in_hex", &self.to_hex())
.finish()
}
}
impl std::clone::Clone for KeyPair {
fn clone(&self) -> Self {
let in_bytes = self.to_bytes();
let from_bytes = KeyPair::from_bytes(in_bytes);
from_bytes
}
}
impl KeyPair {
pub fn generate() -> Self {
let prng = ChaCha20Core::from_entropy();
let mut reseeding_rng = ReseedingRng::new(prng, 0, OsRng);
let secret = StaticSecret::random_from_rng(&mut reseeding_rng);
Self { secret }
}
pub fn pub_key(&self) -> PublicKey {
PublicKey::new(ECDHPublicKey::from(&self.secret))
}
pub fn secret(self, peer_hex: &String) -> Secret {
Secret::new(self.secret, peer_hex.into())
}
pub fn to_hex(&self) -> String {
hex::encode(self.to_bytes())
}
pub fn from_hex(val: String) -> Result<Self, EcdhError> {
let decoded = hex::decode(val)
.map_err(|err| EcdhError::Common(CommonError::ParseHexError(err.to_string())))?;
let valid_bytes: Result<[u8; 32], _> = decoded.try_into();
valid_bytes
.map(|val| Self {
secret: StaticSecret::from(val),
})
.map_err(|_| EcdhError::ParseBytesError("unable to parse decode bytes".to_string()))
}
pub fn to_bytes(&self) -> ECDHPrivateKeyBytes {
self.secret.to_bytes()
}
pub fn from_bytes(val: ECDHPrivateKeyBytes) -> Self {
Self {
secret: StaticSecret::from(val),
}
}
}
impl ToKeySecure for KeyPair {
fn to_keysecure(&self, password: String) -> Result<KeySecure, KeySecureError> {
let priv_key_hex = self.to_hex();
let keysecure_builder = Builder::new(CONTEXT_X25519.to_string(), password);
let keysecure = keysecure_builder.secure(priv_key_hex)?;
Ok(keysecure)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gen_pub_key_from_hex() {
let keypair = KeyPair::generate();
let pubkey = keypair.pub_key();
let pubkeyhex = pubkey.to_hex();
let pubkey_decode = PublicKey::from_hex(&pubkeyhex);
assert!(!pubkey_decode.is_err());
assert_eq!(pubkey_decode.unwrap(), pubkey)
}
#[test]
fn test_gen_pub_key_from_hex_error() {
let given = b"test";
let given_hex = hex::encode(given);
let pubkey_decode = PublicKey::from_hex(&given_hex);
assert!(pubkey_decode.is_err());
assert!(matches!(
pubkey_decode,
Err(EcdhError::ParsePublicKeyError(_))
))
}
#[test]
fn test_gen_shared_secret() {
let keypair_alice = KeyPair::generate();
let keypair_bob = KeyPair::generate();
let pubkey_alice = keypair_alice.pub_key();
let pubkey_bob = keypair_bob.pub_key();
let public_alice_hex = pubkey_alice.to_hex();
let public_bob_hex = pubkey_bob.to_hex();
let secret_alice = keypair_alice.secret(&public_bob_hex);
let secret_bob = keypair_bob.secret(&public_alice_hex);
let shared_secret_alice_blake3 = secret_alice.to_blake3();
let shared_secret_bob_blake3 = secret_bob.to_blake3();
assert!(!&shared_secret_alice_blake3.is_err());
assert!(!&shared_secret_bob_blake3.is_err());
assert_eq!(
shared_secret_alice_blake3.unwrap(),
shared_secret_bob_blake3.unwrap()
)
}
#[test]
fn test_serialize_deserialize() {
let keypair = KeyPair::generate();
let pubkey = keypair.pub_key();
let pubkey_hex = pubkey.to_hex();
let bytes_serialized = keypair.to_bytes();
let keypair_from_bytes = KeyPair::from_bytes(bytes_serialized);
let pubkey_from_bytes = keypair_from_bytes.pub_key();
let pubkey_from_bytes_hex = pubkey_from_bytes.to_hex();
assert_eq!(pubkey_hex, pubkey_from_bytes_hex)
}
#[test]
fn test_to_keyseucre() {
let keypair = KeyPair::generate();
let try_keysecure = keypair.to_keysecure("test".to_string());
assert!(!try_keysecure.is_err());
let keysecure = try_keysecure.unwrap();
let keysecure_json = keysecure.to_json();
assert!(!keysecure_json.is_err());
}
#[test]
fn test_secret_from_hex() {
let keypair = KeyPair::generate();
let pubkey = keypair.pub_key();
let pubkey_hex = pubkey.to_hex();
let keypair_hex = keypair.to_hex();
let keypair_from_hex = KeyPair::from_hex(keypair_hex);
assert!(!keypair_from_hex.is_err());
let keypair_generated = keypair_from_hex.unwrap();
let pubkey_generated = keypair_generated.pub_key();
let pubkey_generated_hex = pubkey_generated.to_hex();
assert_eq!(pubkey_hex, pubkey_generated_hex)
}
}