use crate::error::{PhalanxError, Result};
use ed25519_dalek::{SigningKey, VerifyingKey, Signature, Signer, Verifier};
use x25519_dalek::{EphemeralSecret, PublicKey as X25519PublicKey};
use rand::{rngs::OsRng, RngCore, SeedableRng};
use rand_chacha::ChaCha20Rng;
use zeroize::Zeroize;
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
pub struct Identity {
signing_key: SigningKey,
kx_secret: Option<EphemeralSecret>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PublicKey {
pub verify_key: VerifyingKey,
pub kx_public: X25519PublicKey,
}
pub struct PrivateKey {
signing_key: SigningKey,
}
impl Identity {
pub fn generate() -> Self {
let mut rng = OsRng;
let mut secret_bytes = [0u8; 32];
rng.fill_bytes(&mut secret_bytes);
let signing_key = SigningKey::from_bytes(&secret_bytes);
Self {
signing_key,
kx_secret: None,
}
}
pub fn from_bytes(private_key_bytes: &[u8]) -> Result<Self> {
if private_key_bytes.len() != 32 {
return Err(PhalanxError::crypto("Private key must be 32 bytes"));
}
let signing_key = SigningKey::from_bytes(
private_key_bytes.try_into()
.map_err(|_| PhalanxError::crypto("Invalid private key bytes"))?
);
Ok(Self {
signing_key,
kx_secret: None,
})
}
pub fn public_key(&self) -> PublicKey {
let verify_key = self.signing_key.verifying_key();
let kx_public = self.static_public_key();
PublicKey {
verify_key,
kx_public,
}
}
pub fn private_key(&self) -> PrivateKey {
PrivateKey {
signing_key: self.signing_key.clone(),
}
}
pub fn generate_kx_key(&mut self) -> X25519PublicKey {
let secret = EphemeralSecret::random_from_rng(OsRng);
let public = X25519PublicKey::from(&secret);
self.kx_secret = Some(secret);
public
}
pub fn key_exchange(&mut self, other_public: &X25519PublicKey) -> Result<[u8; 32]> {
let secret = self.kx_secret.take()
.ok_or_else(|| PhalanxError::crypto("No key exchange secret available"))?;
let shared_secret = secret.diffie_hellman(other_public);
Ok(*shared_secret.as_bytes())
}
pub fn static_key_exchange(&self, other_public: &X25519PublicKey) -> Result<[u8; 32]> {
let signing_key_bytes = self.signing_key.to_bytes();
let derived_key = blake3::hash(&signing_key_bytes);
let seed: [u8; 32] = *derived_key.as_bytes();
let mut rng = ChaCha20Rng::from_seed(seed);
let static_secret = EphemeralSecret::random_from_rng(&mut rng);
let shared_secret = static_secret.diffie_hellman(other_public);
Ok(*shared_secret.as_bytes())
}
pub fn static_public_key(&self) -> X25519PublicKey {
let signing_key_bytes = self.signing_key.to_bytes();
let derived_key = blake3::hash(&signing_key_bytes);
let seed: [u8; 32] = *derived_key.as_bytes();
let mut rng = ChaCha20Rng::from_seed(seed);
let static_secret = EphemeralSecret::random_from_rng(&mut rng);
X25519PublicKey::from(&static_secret)
}
pub fn sign(&self, message: &[u8]) -> Signature {
self.signing_key.sign(message)
}
pub fn id(&self) -> [u8; 32] {
let public_key = self.public_key();
blake3::hash(&public_key.verify_key.to_bytes()).into()
}
pub fn to_bytes(&self) -> [u8; 32] {
self.signing_key.to_bytes()
}
}
impl PublicKey {
pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<()> {
self.verify_key.verify(message, signature)
.map_err(|e| PhalanxError::auth(format!("Signature verification failed: {}", e)))
}
pub fn id(&self) -> [u8; 32] {
blake3::hash(&self.verify_key.to_bytes()).into()
}
pub fn to_bytes(&self) -> [u8; 64] {
let mut bytes = [0u8; 64];
bytes[..32].copy_from_slice(&self.verify_key.to_bytes());
bytes[32..].copy_from_slice(self.kx_public.as_bytes());
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 64 {
return Err(PhalanxError::crypto("Public key must be 64 bytes"));
}
let verify_key = VerifyingKey::from_bytes(
bytes[..32].try_into()
.map_err(|_| PhalanxError::crypto("Invalid Ed25519 public key"))?
).map_err(|e| PhalanxError::crypto(format!("Invalid Ed25519 key: {}", e)))?;
let kx_bytes: [u8; 32] = bytes[32..].try_into()
.map_err(|_| PhalanxError::crypto("Invalid X25519 public key"))?;
let kx_public = X25519PublicKey::from(kx_bytes);
Ok(Self {
verify_key,
kx_public,
})
}
}
impl PrivateKey {
pub fn sign(&self, message: &[u8]) -> Signature {
self.signing_key.sign(message)
}
pub fn public_key(&self) -> VerifyingKey {
self.signing_key.verifying_key()
}
pub fn to_bytes(&self) -> [u8; 32] {
self.signing_key.to_bytes()
}
}
impl std::fmt::Debug for Identity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Identity")
.field("public_key", &self.public_key())
.field("has_kx_secret", &self.kx_secret.is_some())
.finish()
}
}
impl Clone for Identity {
fn clone(&self) -> Self {
Self {
signing_key: self.signing_key.clone(),
kx_secret: None, }
}
}
impl Clone for PrivateKey {
fn clone(&self) -> Self {
Self {
signing_key: self.signing_key.clone(),
}
}
}
impl Drop for Identity {
fn drop(&mut self) {
let mut bytes = self.signing_key.to_bytes();
bytes.zeroize();
}
}
impl Drop for PrivateKey {
fn drop(&mut self) {
let mut bytes = self.signing_key.to_bytes();
bytes.zeroize();
}
}
impl std::fmt::Debug for PrivateKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PrivateKey")
.field("public_key", &self.public_key())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_identity_generation() {
let identity = Identity::generate();
let public_key = identity.public_key();
let message = b"test message";
let signature = identity.sign(message);
assert!(public_key.verify(message, &signature).is_ok());
}
#[test]
fn test_key_exchange() {
let mut alice = Identity::generate();
let mut bob = Identity::generate();
let alice_public = alice.generate_kx_key();
let bob_public = bob.generate_kx_key();
let alice_shared = alice.key_exchange(&bob_public).unwrap();
let bob_shared = bob.key_exchange(&alice_public).unwrap();
assert_eq!(alice_shared, bob_shared);
}
#[test]
fn test_identity_serialization() {
let identity = Identity::generate();
let bytes = identity.to_bytes();
let recovered = Identity::from_bytes(&bytes).unwrap();
assert_eq!(identity.public_key().id(), recovered.public_key().id());
}
#[test]
fn test_public_key_serialization() {
let identity = Identity::generate();
let public_key = identity.public_key();
let bytes = public_key.to_bytes();
let recovered = PublicKey::from_bytes(&bytes).unwrap();
assert_eq!(public_key.id(), recovered.id());
}
}