use anyhow::Result;
use bip32::Mnemonic;
use blake2::{Blake2s, Digest, digest, digest::typenum::ToInt};
use ed25519_dalek::{SecretKey, Signer, Verifier};
use rand::{CryptoRng, RngCore, SeedableRng, rngs::StdRng};
use serde::{Deserialize, Serialize};
use std::fmt;
pub struct SigningKey(ed25519_dalek::SigningKey);
type SigHasher = Blake2s<digest::consts::U32>;
impl Default for SigningKey {
fn default() -> Self {
let mut rng = StdRng::from_os_rng();
Self::from_crypto_rng(&mut rng)
}
}
impl SigningKey {
pub fn from_phrase<S>(phrase: S) -> Result<Self>
where
S: AsRef<str>,
{
let mnemonic = Mnemonic::new(phrase, Default::default())?;
Ok(Self(ed25519_dalek::SigningKey::from_bytes(
mnemonic.entropy(),
)))
}
pub fn sign<T>(&self, msg: &T) -> Signature
where
T: Serialize,
{
let mut hasher = SigHasher::new();
bincode::serialize_into(&mut hasher, msg).expect("should serialize to hasher");
Signature(self.0.sign(&hasher.finalize()))
}
pub fn phrase(&self) -> String {
let mnemonic = Mnemonic::from_entropy(*self.0.as_bytes(), Default::default());
mnemonic.phrase().to_string()
}
pub fn verifying_key(&self) -> VerifyingKey {
VerifyingKey(self.0.verifying_key())
}
fn from_crypto_rng<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let mut key = SecretKey::default();
rng.fill_bytes(&mut key);
Self(ed25519_dalek::SigningKey::from_bytes(&key))
}
}
impl fmt::Debug for SigningKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"SigningKey({})",
bs58::encode(self.0.as_bytes()).into_string()
)
}
}
#[derive(Clone, Copy, Serialize, Deserialize)]
pub struct Signature(ed25519_dalek::Signature);
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Signature({})",
bs58::encode(&self.0.to_bytes()).into_string()
)
}
}
#[derive(Clone, Copy, Serialize, Deserialize)]
pub struct VerifyingKey(ed25519_dalek::VerifyingKey);
impl VerifyingKey {
pub fn verify<T>(&self, msg: &T, signature: &Signature) -> bool
where
T: Serialize,
{
let mut hasher = SigHasher::new();
bincode::serialize_into(&mut hasher, msg).expect("should serialize to hasher");
self.0.verify(&hasher.finalize(), &signature.0).is_ok()
}
pub fn peer_id(&self) -> PeerId {
let mut hasher = Blake2s::<digest::consts::U16>::new();
hasher.update(self.0.as_bytes());
PeerId(hasher.finalize().into())
}
}
impl fmt::Debug for VerifyingKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VerifyingKey({})",
bs58::encode(self.0.as_bytes()).into_string()
)
}
}
#[derive(Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
pub struct PeerId([u8; digest::consts::U16::INT]);
impl PeerId {
pub fn digits(&self) -> String {
self.0
.iter()
.fold(String::with_capacity(32), |mut output, b| {
output.push_str(&format!("{b:02X}"));
output
})
}
}
impl fmt::Debug for PeerId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "PeerId({})", self.digits())
}
}
impl fmt::Display for PeerId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.digits())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn keypair_phrase() {
let sk = SigningKey::default();
let from_phrase = SigningKey::from_phrase(sk.phrase()).unwrap();
assert_eq!(sk.0, from_phrase.0);
}
#[test]
fn sign() {
#[derive(Serialize)]
struct Point {
x: f32,
y: f32,
}
let msg = Point { x: 10.2, y: 4.3 };
let sk = SigningKey::default();
let sig = sk.sign(&msg);
let vk = sk.verifying_key();
assert!(vk.verify(&msg, &sig));
let msg = Point { x: 10.2001, y: 4.3 };
assert!(!vk.verify(&msg, &sig));
}
}