//! Key and signature types for API version response format use std::{fmt, str::FromStr}; use anyhow::{Context, bail}; use ed25519_dalek::ed25519::signature::Signer; use serde::{Deserialize, Serialize}; use zeroize::Zeroize; /// ed25519 secret/signing key #[derive(Clone, PartialEq, zeroize::ZeroizeOnDrop)] #[cfg_attr(test, derive(Debug))] pub struct SecretKey(ed25519_dalek::SigningKey); impl SecretKey { /// Generate a new secret ed25519 key #[cfg(feature = "sign")] pub fn generate() -> Self { let key = ed25519_dalek::SigningKey::generate(&mut rand08::thread_rng()); SecretKey(key) } pub fn pubkey(&self) -> VerifyingKey { VerifyingKey(self.0.verifying_key()) } /// Sign data using this key pub fn sign(&self, msg: &[u8]) -> Signature { Signature(self.0.sign(msg)) } /// Convert bytes to a signing key, and zero the original bytes fn from_bytes(mut key: [u8; ed25519_dalek::SECRET_KEY_LENGTH]) -> Self { let secret = ed25519_dalek::SigningKey::from_bytes(&key); key.zeroize(); SecretKey(secret) } } impl fmt::Display for SecretKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", hex::encode(self.0.as_bytes())) } } impl<'de> Deserialize<'de> for SecretKey { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let mut key_s = String::deserialize(deserializer)?; let key = bytes_from_hex::<{ ed25519_dalek::SECRET_KEY_LENGTH }>(&key_s) .map_err(|err| serde::de::Error::custom(err.to_string()))?; key_s.zeroize(); Ok(SecretKey::from_bytes(key)) } } impl FromStr for SecretKey { type Err = anyhow::Error; fn from_str(s: &str) -> Result { let bytes = bytes_from_hex::<{ ed25519_dalek::SECRET_KEY_LENGTH }>(s)?; Ok(Self::from_bytes(bytes)) } } impl Serialize for SecretKey { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.serialize_str(&hex::encode(self.0.as_bytes())) } } /// ed25519 verifying key #[derive(Debug, PartialEq, Eq, Clone)] pub struct VerifyingKey(pub ed25519_dalek::VerifyingKey); impl fmt::Display for VerifyingKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", hex::encode(self.0.as_bytes())) } } impl VerifyingKey { pub fn from_hex(s: &str) -> anyhow::Result { let bytes = bytes_from_hex::<{ ed25519_dalek::PUBLIC_KEY_LENGTH }>(s)?; Ok(Self( ed25519_dalek::VerifyingKey::from_bytes(&bytes).context("Invalid ed25519 key")?, )) } } impl<'de> Deserialize<'de> for VerifyingKey { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let bytes = String::deserialize(deserializer)?; let bytes = bytes_from_hex::<{ ed25519_dalek::PUBLIC_KEY_LENGTH }>(&bytes) .map_err(|err| serde::de::Error::custom(err.to_string()))?; let key = ed25519_dalek::VerifyingKey::from_bytes(&bytes).map_err(|_err| { serde::de::Error::invalid_value( serde::de::Unexpected::Other("invalid verifying key"), &"valid ed25519 key", ) })?; Ok(VerifyingKey(key)) } } impl Serialize for VerifyingKey { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.serialize_str(&hex::encode(self.0.as_bytes())) } } /// ed25519 signature #[derive(Debug, PartialEq)] pub struct Signature(pub ed25519_dalek::Signature); impl Signature { pub fn from_hex(s: &str) -> anyhow::Result { let bytes = bytes_from_hex::<{ ed25519_dalek::SIGNATURE_LENGTH }>(s)?; Ok(Self(ed25519_dalek::Signature::from_bytes(&bytes))) } } impl<'de> Deserialize<'de> for Signature { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let bytes = String::deserialize(deserializer)?; let bytes = bytes_from_hex::<{ ed25519_dalek::SIGNATURE_LENGTH }>(&bytes) .map_err(|err| serde::de::Error::custom(err.to_string()))?; Ok(Signature(ed25519_dalek::Signature::from_bytes(&bytes))) } } impl Serialize for Signature { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.serialize_str(&hex::encode(self.0.to_bytes())) } } /// Deserialize a hex-encoded string to a bytes array of an exact size fn bytes_from_hex(key: &str) -> anyhow::Result<[u8; SIZE]> { let bytes = hex::decode(key).context("invalid hex")?; if bytes.len() != SIZE { bail!( "expected hex-encoded string of {SIZE} bytes, found {} bytes", bytes.len() ); } let mut key = [0u8; SIZE]; key.copy_from_slice(&bytes); Ok(key) } #[cfg(test)] mod test { use rand::RngCore; use super::*; #[test] fn test_serialization_and_deserialization() { let mut secret = [0u8; 32]; rand::rng().fill_bytes(&mut secret); let secret_hex = hex::encode(secret); let secret = SecretKey::from_str(&hex::encode(secret)).unwrap(); let pubkey = secret.pubkey(); let pubkey_hex = hex::encode(pubkey.0); // Test serialization let actual = serde_json::json!({ "secret": secret, "key": pubkey, }); let expected: serde_json::Value = serde_json::from_str(&format!( r#"{{ "secret": "{secret_hex}", "key": "{pubkey_hex}" }}"# )) .unwrap(); assert_eq!(actual, expected); // Test deserialization let secret_obj = actual.as_object().unwrap().get("secret").unwrap().clone(); let deserialized_secret: SecretKey = serde_json::from_value(secret_obj).unwrap(); let pubkey_obj = actual.as_object().unwrap().get("key").unwrap().clone(); let deserialized_pubkey: VerifyingKey = serde_json::from_value(pubkey_obj).unwrap(); assert_eq!(deserialized_secret, secret); assert_eq!(deserialized_pubkey, pubkey); } }