use core::fmt;
use base64::prelude::*;
use x25519_dalek::PublicKey as XPublicKey;
use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::WireguardError;
use super::PrivateKey;
#[derive(Clone, PartialEq, Zeroize, ZeroizeOnDrop)]
pub struct PublicKey(XPublicKey);
impl PublicKey {
#[inline]
#[must_use]
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
#[inline]
#[must_use]
pub fn as_bytes(&self) -> &[u8; 32] {
self.0.as_bytes()
}
}
impl fmt::Debug for PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("PublicKey").field(&self.to_string()).finish()
}
}
impl fmt::Display for PublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", BASE64_STANDARD.encode(self.as_bytes()))
}
}
impl TryFrom<&str> for PublicKey {
type Error = WireguardError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let bytes: [u8; 32] = BASE64_STANDARD
.decode(value)
.map_err(|_| WireguardError::InvalidPublicKey)?
.try_into()
.map_err(|_| WireguardError::InvalidPublicKey)?;
Ok(Self(XPublicKey::from(bytes)))
}
}
impl TryFrom<String> for PublicKey {
type Error = WireguardError;
fn try_from(value: String) -> Result<Self, Self::Error> {
Self::try_from(value.as_str())
}
}
impl From<[u8; 32]> for PublicKey {
fn from(value: [u8; 32]) -> Self {
Self(XPublicKey::from(value))
}
}
impl From<&PrivateKey> for PublicKey {
fn from(value: &PrivateKey) -> Self {
Self(XPublicKey::from(&value.0))
}
}
#[cfg(feature = "serde")]
mod serde_impl {
use super::PublicKey;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
impl Serialize for PublicKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
serializer.serialize_str(&self.to_string())
} else {
serializer.serialize_bytes(self.as_bytes())
}
}
}
impl<'de> Deserialize<'de> for PublicKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
if deserializer.is_human_readable() {
let data = String::deserialize(deserializer)?;
PublicKey::try_from(data.as_str()).map_err(|_| {
de::Error::invalid_value(de::Unexpected::Str(&data), &"a public key")
})
} else {
let bytes = <[u8; 32]>::deserialize(deserializer)?;
Ok(PublicKey::from(bytes))
}
}
}
}