1use anyhow::{Result, bail};
6use bip39::Mnemonic;
7use blake2::{Blake2s, Digest, digest, digest::typenum::ToInt};
8use ed25519_dalek::{Signer, Verifier};
9use rand::{CryptoRng, RngCore, SeedableRng, rngs::StdRng};
10use serde::{Deserialize, Serialize};
11use std::fmt;
12use zeroize::Zeroizing;
13
14const ENTROPY_LEN: usize = 16;
15type Entropy = [u8; ENTROPY_LEN];
16
17pub struct SigningKey {
19 key: ed25519_dalek::SigningKey,
20 entropy: Zeroizing<Entropy>,
21}
22
23type SigHasher = Blake2s<digest::consts::U32>;
25
26impl Default for SigningKey {
27 fn default() -> Self {
28 let mut rng = StdRng::from_os_rng();
29 Self::from_crypto_rng(&mut rng)
30 }
31}
32
33impl SigningKey {
34 pub fn from_phrase<S>(phrase: S) -> Result<Self>
36 where
37 S: AsRef<str>,
38 {
39 let mnemonic = Mnemonic::from_phrase(phrase.as_ref(), Default::default())?;
40 if mnemonic.entropy().len() != ENTROPY_LEN {
41 bail!("Invalid passphrase length");
42 }
43
44 let mut entropy = Entropy::default();
45 entropy.copy_from_slice(mnemonic.entropy());
46 Ok(Self::from_entropy(entropy))
47 }
48
49 pub fn sign<T>(&self, msg: &T) -> Signature
51 where
52 T: Serialize,
53 {
54 let mut hasher = SigHasher::new();
55 bincode::serialize_into(&mut hasher, msg).expect("should serialize to hasher");
56 Signature(self.key.sign(&hasher.finalize()))
57 }
58
59 pub fn phrase(&self) -> String {
61 Mnemonic::from_entropy(self.entropy.as_ref(), Default::default())
63 .unwrap()
64 .phrase()
65 .to_string()
66 }
67
68 pub fn verifying_key(&self) -> VerifyingKey {
70 VerifyingKey(self.key.verifying_key())
71 }
72
73 fn from_crypto_rng<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
74 let mut entropy = Entropy::default();
75 rng.fill_bytes(&mut entropy);
76 Self::from_entropy(entropy)
77 }
78
79 fn from_entropy(entropy: Entropy) -> Self {
80 let key_hash = SigHasher::digest(entropy);
82 let key = ed25519_dalek::SigningKey::from_bytes(&key_hash.into());
83 let entropy = Zeroizing::new(entropy);
84 Self { key, entropy }
85 }
86}
87
88impl fmt::Debug for SigningKey {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 write!(
91 f,
92 "SigningKey({})",
93 bs58::encode(self.key.as_bytes()).into_string()
94 )
95 }
96}
97
98#[derive(Clone, Copy, Serialize, Deserialize)]
100pub struct Signature(ed25519_dalek::Signature);
101
102impl fmt::Debug for Signature {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 write!(
105 f,
106 "Signature({})",
107 bs58::encode(&self.0.to_bytes()).into_string()
108 )
109 }
110}
111
112#[derive(Clone, Copy, Serialize, Deserialize)]
114pub struct VerifyingKey(ed25519_dalek::VerifyingKey);
115
116impl VerifyingKey {
117 pub fn verify<T>(&self, msg: &T, signature: &Signature) -> bool
119 where
120 T: Serialize,
121 {
122 let mut hasher = SigHasher::new();
123 bincode::serialize_into(&mut hasher, msg).expect("should serialize to hasher");
124 self.0.verify(&hasher.finalize(), &signature.0).is_ok()
125 }
126
127 pub fn peer_id(&self) -> PeerId {
129 let mut hasher = Blake2s::<digest::consts::U16>::new();
130 hasher.update(self.0.as_bytes());
131 PeerId(hasher.finalize().into())
132 }
133}
134
135impl fmt::Debug for VerifyingKey {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 write!(
138 f,
139 "VerifyingKey({})",
140 bs58::encode(self.0.as_bytes()).into_string()
141 )
142 }
143}
144
145#[derive(Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
147pub struct PeerId([u8; digest::consts::U16::INT]);
148
149impl PeerId {
150 pub fn digits(&self) -> String {
152 self.0
153 .iter()
154 .fold(String::with_capacity(32), |mut output, b| {
155 output.push_str(&format!("{b:02X}"));
156 output
157 })
158 }
159}
160
161impl fmt::Debug for PeerId {
162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163 write!(f, "PeerId({})", self.digits())
164 }
165}
166
167impl fmt::Display for PeerId {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 write!(f, "{}", self.digits())
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn keypair_phrase() {
179 let sk = SigningKey::default();
180 let from_phrase = SigningKey::from_phrase(sk.phrase()).unwrap();
181 assert_eq!(sk.key, from_phrase.key);
182 }
183
184 #[test]
185 fn sign() {
186 #[derive(Serialize)]
187 struct Point {
188 x: f32,
189 y: f32,
190 }
191
192 let msg = Point { x: 10.2, y: 4.3 };
193
194 let sk = SigningKey::default();
195 let sig = sk.sign(&msg);
196
197 let vk = sk.verifying_key();
199 assert!(vk.verify(&msg, &sig));
200
201 let msg = Point { x: 10.2001, y: 4.3 };
203 assert!(!vk.verify(&msg, &sig));
204 }
205}