use ed25519_dalek::{
SecretKey, Signature, SignatureError, Signer, SigningKey, Verifier, VerifyingKey,
};
use std::{
fmt::{self, Debug, Display, Formatter},
hash::Hash,
str::FromStr,
};
use serde::{Deserialize, Serialize};
#[derive(Clone, PartialEq, Eq)]
pub struct Keypair(pub(crate) SigningKey);
impl Keypair {
pub fn random() -> Keypair {
let mut bytes = [0u8; 32];
getrandom::fill(&mut bytes).expect("getrandom failed");
let signing_key: SigningKey = SigningKey::from_bytes(&bytes);
Keypair(signing_key)
}
pub fn from_secret_key(secret_key: &SecretKey) -> Keypair {
Keypair(SigningKey::from_bytes(secret_key))
}
pub fn sign(&self, message: &[u8]) -> Signature {
self.0.sign(message)
}
pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
self.0.verify(message, signature)
}
pub fn secret_key(&self) -> SecretKey {
self.0.to_bytes()
}
pub fn public_key(&self) -> PublicKey {
PublicKey(self.0.verifying_key())
}
pub fn to_z32(&self) -> String {
self.public_key().to_string()
}
pub fn to_uri_string(&self) -> String {
self.public_key().to_uri_string()
}
}
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct PublicKey(pub(crate) VerifyingKey);
impl PublicKey {
pub fn to_z32(&self) -> String {
self.to_string()
}
pub fn to_uri_string(&self) -> String {
format!("pk:{self}")
}
pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
self.0.verify(message, signature)
}
pub fn verifying_key(&self) -> &VerifyingKey {
&self.0
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
pub fn as_bytes(&self) -> &[u8; 32] {
self.0.as_bytes()
}
}
impl AsRef<Keypair> for Keypair {
fn as_ref(&self) -> &Keypair {
self
}
}
impl AsRef<PublicKey> for PublicKey {
fn as_ref(&self) -> &PublicKey {
self
}
}
impl TryFrom<&[u8]> for PublicKey {
type Error = PublicKeyError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let bytes_32: &[u8; 32] = bytes
.try_into()
.map_err(|_| PublicKeyError::InvalidPublicKeyLength(bytes.len()))?;
Ok(Self(
VerifyingKey::from_bytes(bytes_32)
.map_err(|_| PublicKeyError::InvalidEd25519PublicKey)?,
))
}
}
impl TryFrom<&[u8; 32]> for PublicKey {
type Error = PublicKeyError;
fn try_from(public: &[u8; 32]) -> Result<Self, Self::Error> {
Ok(Self(
VerifyingKey::from_bytes(public)
.map_err(|_| PublicKeyError::InvalidEd25519PublicKey)?,
))
}
}
impl From<VerifyingKey> for PublicKey {
fn from(verifying_key: VerifyingKey) -> Self {
Self(verifying_key)
}
}
impl FromStr for PublicKey {
type Err = PublicKeyError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut s = s;
if s.len() > 52 {
s = s.split_once(':').map(|tuple| tuple.1).unwrap_or(s);
if s.len() > 52 {
s = s.strip_prefix("//").unwrap_or(s);
if s.len() > 52 {
s = s.split_once('@').map(|tuple| tuple.1).unwrap_or(s);
if s.len() > 52 {
s = s.split_once(':').map(|tuple| tuple.0).unwrap_or(s);
if s.len() > 52 {
s = s.split_once('/').map(|tuple| tuple.0).unwrap_or(s);
if s.len() > 52 {
s = s.split_once('?').map(|tuple| tuple.0).unwrap_or(s);
if s.len() > 52 {
s = s.split_once('#').map(|tuple| tuple.0).unwrap_or(s);
if s.len() > 52 {
if s.ends_with('.') {
s = s.trim_matches('.');
}
s = s.rsplit_once('.').map(|tuple| tuple.1).unwrap_or(s);
}
}
}
}
}
}
}
}
let bytes = if let Some(v) = base32::decode(base32::Alphabet::Z, s) {
Ok(v)
} else {
Err(PublicKeyError::InvalidPublicKeyEncoding)
}?;
bytes.as_slice().try_into()
}
}
impl TryFrom<&str> for PublicKey {
type Error = PublicKeyError;
fn try_from(s: &str) -> Result<PublicKey, PublicKeyError> {
PublicKey::from_str(s)
}
}
impl TryFrom<String> for PublicKey {
type Error = PublicKeyError;
fn try_from(s: String) -> Result<PublicKey, PublicKeyError> {
s.as_str().try_into()
}
}
impl TryFrom<&String> for PublicKey {
type Error = PublicKeyError;
fn try_from(s: &String) -> Result<PublicKey, PublicKeyError> {
s.as_str().try_into()
}
}
impl Display for PublicKey {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
base32::encode(base32::Alphabet::Z, self.0.as_bytes())
)
}
}
impl Display for Keypair {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.public_key())
}
}
impl Debug for Keypair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Keypair({})", self.public_key())
}
}
impl Debug for PublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "PublicKey({self})")
}
}
impl Serialize for PublicKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let bytes = self.to_bytes();
bytes.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for PublicKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let bytes: [u8; 32] = Deserialize::deserialize(deserializer)?;
(&bytes).try_into().map_err(serde::de::Error::custom)
}
}
#[derive(thiserror::Error, Debug, PartialEq, Eq)]
pub enum PublicKeyError {
#[error("Invalid PublicKey length, expected 32 bytes but got: {0}")]
InvalidPublicKeyLength(usize),
#[error("Invalid Ed25519 publickey; Cannot decompress Edwards point")]
InvalidEd25519PublicKey,
#[error("Invalid PublicKey encoding")]
InvalidPublicKeyEncoding,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pkarr_key_generate() {
let key1 = Keypair::random();
let key2 = Keypair::from_secret_key(&key1.secret_key());
assert_eq!(key1.public_key(), key2.public_key())
}
#[test]
fn zbase32() {
let key1 = Keypair::random();
let _z32 = key1.public_key().to_string();
let key2 = Keypair::from_secret_key(&key1.secret_key());
assert_eq!(key1.public_key(), key2.public_key())
}
#[test]
fn sign_verify() {
let keypair = Keypair::random();
let message = b"Hello, world!";
let signature = keypair.sign(message);
assert!(keypair.verify(message, &signature).is_ok());
let public_key = keypair.public_key();
assert!(public_key.verify(message, &signature).is_ok());
}
#[test]
fn from_string() {
let str = "yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no";
let expected = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let public_key: PublicKey = str.try_into().unwrap();
assert_eq!(public_key.verifying_key().as_bytes(), &expected);
}
#[test]
fn to_uri() {
let bytes = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let expected = "pk:yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no";
let public_key: PublicKey = (&bytes).try_into().unwrap();
assert_eq!(public_key.to_uri_string(), expected);
}
#[test]
fn from_uri() {
let str = "pk:yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no";
let expected = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let public_key: PublicKey = str.try_into().unwrap();
assert_eq!(public_key.verifying_key().as_bytes(), &expected);
}
#[test]
fn from_uri_with_path() {
let str = "https://yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no///foo/bar";
let expected = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let public_key: PublicKey = str.try_into().unwrap();
assert_eq!(public_key.verifying_key().as_bytes(), &expected);
}
#[test]
fn from_uri_with_query() {
let str = "https://yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no?foo=bar";
let expected = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let public_key: PublicKey = str.try_into().unwrap();
assert_eq!(public_key.verifying_key().as_bytes(), &expected);
}
#[test]
fn from_uri_with_hash() {
let str = "https://yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no#foo";
let expected = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let public_key: PublicKey = str.try_into().unwrap();
assert_eq!(public_key.verifying_key().as_bytes(), &expected);
}
#[test]
fn from_uri_with_subdomain() {
let str = "https://foo.bar.yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no#foo";
let expected = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let public_key: PublicKey = str.try_into().unwrap();
assert_eq!(public_key.verifying_key().as_bytes(), &expected);
}
#[test]
fn from_uri_with_trailing_dot() {
let str = "https://foo.yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no.";
let expected = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let public_key: PublicKey = str.try_into().unwrap();
assert_eq!(public_key.verifying_key().as_bytes(), &expected);
}
#[test]
fn from_uri_with_username() {
let str = "https://foo@yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no#foo";
let expected = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let public_key: PublicKey = str.try_into().unwrap();
assert_eq!(public_key.verifying_key().as_bytes(), &expected);
}
#[test]
fn from_uri_with_port() {
let str = "https://yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no:8888";
let expected = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let public_key: PublicKey = str.try_into().unwrap();
assert_eq!(public_key.verifying_key().as_bytes(), &expected);
}
#[test]
fn from_uri_complex() {
let str =
"https://foo@bar.yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no.:8888?q=v&a=b#foo";
let expected = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let public_key: PublicKey = str.try_into().unwrap();
assert_eq!(public_key.verifying_key().as_bytes(), &expected);
}
#[test]
fn serde() {
let str = "yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no";
let expected = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let public_key: PublicKey = str.try_into().unwrap();
let bytes = postcard::to_allocvec(&public_key).unwrap();
assert_eq!(bytes, expected)
}
#[test]
fn from_uri_multiple_pkarr() {
let str =
"https://o4dksfbqk85ogzdb5osziw6befigbuxmuxkuxq8434q89uj56uyy.yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no";
let expected = [
1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254, 14,
207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
];
let public_key: PublicKey = str.try_into().unwrap();
assert_eq!(public_key.verifying_key().as_bytes(), &expected);
}
#[cfg(all(not(target_family = "wasm"), feature = "tls"))]
#[test]
fn pkcs8() {
let str = "yg4gxe7z1r7mr6orids9fh95y7gxhdsxjqi6nngsxxtakqaxr5no";
let public_key: PublicKey = str.try_into().unwrap();
let der = public_key.to_public_key_der();
assert_eq!(
der.as_bytes(),
[
48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 1, 180, 103, 163, 183, 145, 58, 178, 122, 4, 168, 237, 242, 243, 251, 7, 76, 254,
14, 207, 75, 171, 225, 8, 214, 123, 227, 133, 59, 15, 38, 197,
]
)
}
#[cfg(all(not(target_family = "wasm"), feature = "tls"))]
#[test]
fn certificate() {
use rustls::SignatureAlgorithm;
let keypair = Keypair::from_secret_key(&[0; 32]);
let certified_key = keypair.to_rpk_certified_key();
assert_eq!(certified_key.key.algorithm(), SignatureAlgorithm::ED25519);
assert_eq!(
certified_key.end_entity_cert().unwrap().as_ref(),
[
48, 42, 48, 5, 6, 3, 43, 101, 112, 3, 33, 0, 59, 106, 39, 188, 206, 182, 164, 45,
98, 163, 168, 208, 42, 111, 13, 115, 101, 50, 21, 119, 29, 226, 67, 166, 58, 192,
72, 161, 139, 89, 218, 41,
]
)
}
#[test]
fn invalid_key() {
let key = "c1bkg8tfsyy8wcedtmw4fwhdmm7bbzhgg3z58tf43m5ow8w9mbus";
assert_eq!(
PublicKey::try_from(key),
Err(PublicKeyError::InvalidEd25519PublicKey)
);
}
}