use crate::{Error, PrivateKey};
use bech32::{FromBase32, ToBase32};
use derive_more::{AsMut, AsRef, Deref, Display, From, FromStr, Into};
use k256::schnorr::VerifyingKey;
use serde::de::{Deserializer, Visitor};
use serde::ser::Serializer;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::hash::{Hash, Hasher};
#[derive(AsMut, AsRef, Copy, Clone, Debug, Deref, Eq, From, Into, PartialEq)]
pub struct PublicKey(pub VerifyingKey);
impl PublicKey {
pub fn as_hex_string(&self) -> String {
hex::encode(self.0.to_bytes())
}
pub fn try_from_hex_string(v: &str) -> Result<PublicKey, Error> {
let vec: Vec<u8> = hex::decode(v)?;
Ok(PublicKey(VerifyingKey::from_bytes(&vec)?))
}
pub fn try_as_bech32_string(&self) -> Result<String, Error> {
Ok(bech32::encode(
"npub",
self.0.to_bytes().to_vec().to_base32(),
bech32::Variant::Bech32,
)?)
}
pub fn try_from_bech32_string(s: &str) -> Result<PublicKey, Error> {
let data = bech32::decode(s)?;
if data.0 != "npub" {
Err(Error::WrongBech32("npub".to_string(), data.0))
} else {
let decoded = Vec::<u8>::from_base32(&data.1)?;
Ok(PublicKey(VerifyingKey::from_bytes(&decoded)?))
}
}
#[allow(dead_code)]
pub(crate) fn mock() -> PublicKey {
PrivateKey::generate().public_key()
}
}
impl Serialize for PublicKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&format!("{:x}", self.0.to_bytes()))
}
}
impl<'de> Deserialize<'de> for PublicKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(PublicKeyVisitor)
}
}
struct PublicKeyVisitor;
impl Visitor<'_> for PublicKeyVisitor {
type Value = PublicKey;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "a hexadecimal string representing 32 bytes")
}
fn visit_str<E>(self, v: &str) -> Result<PublicKey, E>
where
E: serde::de::Error,
{
let vec: Vec<u8> =
hex::decode(v).map_err(|e| serde::de::Error::custom(format!("{}", e)))?;
if vec.len() != 32 {
return Err(serde::de::Error::custom("Public key is not 32 bytes long"));
}
Ok(PublicKey(
VerifyingKey::from_bytes(&vec)
.map_err(|e| serde::de::Error::custom(format!("{}", e)))?,
))
}
}
#[allow(clippy::derive_hash_xor_eq)]
impl Hash for PublicKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_hex_string().hash(state);
}
}
#[derive(
AsMut,
AsRef,
Clone,
Debug,
Deref,
Deserialize,
Display,
Eq,
From,
FromStr,
Hash,
Into,
PartialEq,
Serialize,
)]
pub struct PublicKeyHex(pub String);
impl PublicKeyHex {
#[allow(dead_code)]
pub(crate) fn mock() -> PublicKeyHex {
From::from(PublicKey::mock())
}
}
impl From<PublicKey> for PublicKeyHex {
fn from(pk: PublicKey) -> PublicKeyHex {
PublicKeyHex(pk.as_hex_string())
}
}
impl TryFrom<PublicKeyHex> for PublicKey {
type Error = Error;
fn try_from(pkh: PublicKeyHex) -> Result<PublicKey, Error> {
PublicKey::try_from_hex_string(&pkh.0)
}
}
#[cfg(test)]
mod test {
use super::*;
test_serde! {PublicKey, test_public_key_serde}
#[test]
fn test_pubkey_bech32() {
let pk = PublicKey::mock();
let encoded = pk.try_as_bech32_string().unwrap();
println!("bech32: {}", encoded);
let decoded = PublicKey::try_from_bech32_string(&encoded).unwrap();
assert_eq!(pk, decoded);
}
}