primitives/types/identifiers/
peer_id.rs1use std::ops::BitXor;
2
3use derive_more::derive::AsRef;
4use ed25519_dalek::{
5 pkcs8::{DecodePrivateKey, DecodePublicKey},
6 SigningKey,
7 Verifier,
8 VerifyingKey,
9};
10use quinn::rustls::{server::ParsedCertificate, Error as RustlsError};
11pub use rand::Rng;
12#[cfg(any(test, feature = "dev"))]
13use rand::{distributions::Standard, prelude::Distribution};
14use rustls_pki_types::CertificateDer;
15use serde::{Deserialize, Serialize};
16use wincode::{SchemaRead, SchemaWrite};
17
18use crate::{errors::PrimitiveError, izip_eq};
19pub const PEER_ID_LENGTH: usize = ed25519_dalek::PUBLIC_KEY_LENGTH; #[derive(
22 Copy,
23 Clone,
24 Serialize,
25 Deserialize,
26 SchemaRead,
27 SchemaWrite,
28 PartialEq,
29 Eq,
30 Hash,
31 PartialOrd,
32 Ord,
33 AsRef,
34)]
35#[as_ref([u8])]
36#[repr(transparent)]
37pub struct PeerId([u8; PEER_ID_LENGTH]);
40
41impl Verifier<ed25519_dalek::Signature> for PeerId {
42 fn verify(
43 &self,
44 message: &[u8],
45 signature: &ed25519_dalek::Signature,
46 ) -> Result<(), ed25519_dalek::SignatureError> {
47 let public_key =
48 VerifyingKey::try_from(*self).map_err(ed25519_dalek::SignatureError::from_source)?;
49 public_key.verify_strict(message, signature)
50 }
51}
52
53#[cfg(not(any(test, feature = "dev")))]
54impl std::fmt::Display for PeerId {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 write!(f, "{}", hex::encode(self.0))
57 }
58}
59
60#[cfg(not(any(test, feature = "dev")))]
61impl std::fmt::Debug for PeerId {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 write!(f, "{}", hex::encode(self.0))
64 }
65}
66
67#[cfg(any(test, feature = "dev"))]
68impl std::fmt::Display for PeerId {
69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 write!(f, "{}", &hex::encode(self.0)[0..6])
71 }
72}
73
74#[cfg(any(test, feature = "dev"))]
75impl std::fmt::Debug for PeerId {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 write!(f, "{}", &hex::encode(self.0)[0..6])
78 }
79}
80
81impl<'pid> From<&'pid PeerId> for &'pid [u8; PEER_ID_LENGTH] {
84 fn from(peer_id: &'pid PeerId) -> Self {
85 &peer_id.0
86 }
87}
88
89impl From<PeerId> for [u8; PEER_ID_LENGTH] {
90 fn from(peer_id: PeerId) -> Self {
91 peer_id.0
92 }
93}
94
95impl From<&PeerId> for String {
96 fn from(peer_id: &PeerId) -> String {
97 hex::encode(peer_id.0)
98 }
99}
100
101impl From<VerifyingKey> for PeerId {
102 fn from(verifying_key: VerifyingKey) -> PeerId {
103 Self(verifying_key.to_bytes())
104 }
105}
106
107impl TryFrom<PeerId> for VerifyingKey {
108 type Error = PrimitiveError;
109
110 fn try_from(peer_id: PeerId) -> Result<VerifyingKey, PrimitiveError> {
111 VerifyingKey::from_bytes(&peer_id.0).map_err(|_| PrimitiveError::InvalidPeerId(peer_id))
112 }
113}
114
115impl From<&SigningKey> for PeerId {
116 fn from(signing_key: &SigningKey) -> PeerId {
117 Self(signing_key.verifying_key().to_bytes())
118 }
119}
120
121impl TryFrom<&[u8; PEER_ID_LENGTH]> for PeerId {
124 type Error = PrimitiveError;
125
126 fn try_from(bytes: &[u8; PEER_ID_LENGTH]) -> Result<Self, Self::Error> {
127 let public_key = VerifyingKey::from_bytes(bytes).map_err(|_| {
128 PrimitiveError::InvalidParameters(
129 "Could not convert it to an ed25519 public key".to_string(),
130 )
131 })?;
132 Ok(Self(public_key.to_bytes()))
133 }
134}
135
136impl TryFrom<CertificateDer<'static>> for PeerId {
137 type Error = PrimitiveError;
138
139 fn try_from(certificate: CertificateDer<'static>) -> Result<Self, Self::Error> {
140 Self::from_certificate(certificate)
141 }
142}
143
144impl TryFrom<&quinn::Connection> for PeerId {
145 type Error = PrimitiveError;
146
147 fn try_from(connection: &quinn::Connection) -> Result<Self, Self::Error> {
148 Self::from_connection(connection)
149 }
150}
151
152impl PeerId {
153 #[cfg(any(test, feature = "dev"))]
157 pub const fn from_bytes_unchecked(bytes: [u8; PEER_ID_LENGTH]) -> Self {
158 Self(bytes)
159 }
160
161 pub fn from_keypair(keypair: &rcgen::KeyPair) -> Result<Self, PrimitiveError> {
163 if keypair.algorithm() != &rcgen::PKCS_ED25519 {
164 return Err(PrimitiveError::InvalidParameters(
165 "Keypair is not Ed25519".to_string(),
166 ));
167 }
168 let public_key_bytes: [u8; PEER_ID_LENGTH] =
169 keypair.public_key_raw().to_vec().try_into().unwrap();
170 Ok(Self(public_key_bytes))
171 }
172
173 pub fn from_secret_key_der(bytes: &[u8]) -> Result<Self, PrimitiveError> {
175 let secret_key = SigningKey::from_pkcs8_der(bytes).map_err(|e| {
176 PrimitiveError::InvalidParameters(format!(
177 "Failed to decode secret key in DER format: {e}",
178 ))
179 })?;
180 Ok(Self(*secret_key.verifying_key().as_bytes()))
181 }
182
183 pub fn from_public_key_der(bytes: &[u8]) -> Result<Self, PrimitiveError> {
185 let public_key = VerifyingKey::from_public_key_der(bytes).map_err(|e| {
186 PrimitiveError::InvalidParameters(format!(
187 "Failed to decode public key in DER format: {e}",
188 ))
189 })?;
190 Ok(Self(public_key.to_bytes()))
191 }
192
193 pub(crate) fn from_certificate(
195 certificate: CertificateDer<'static>,
196 ) -> Result<Self, PrimitiveError> {
197 let cert = ParsedCertificate::try_from(&certificate)?;
198 let spki = cert.subject_public_key_info();
199
200 Self::from_public_key_der(spki.as_ref())
202 }
203
204 pub fn from_connection(connection: &quinn::Connection) -> Result<Self, PrimitiveError> {
206 let certificate = connection
207 .peer_identity()
208 .ok_or(RustlsError::NoCertificatesPresented)?
209 .downcast::<Vec<CertificateDer<'static>>>()
210 .map_err(|_| RustlsError::General("Peer identity didn't downcast to a certificate. Check quinn session (should be default rustls).".to_string()))?
211 .into_iter()
212 .next()
213 .ok_or(RustlsError::NoCertificatesPresented)?;
214 Self::from_certificate(certificate)
215 }
216}
217
218#[macros::op_variants(owned, borrowed, flipped_commutative)]
219impl BitXor<&PeerId> for PeerId {
220 type Output = PeerId;
221
222 fn bitxor(mut self, rhs: &Self) -> Self::Output {
223 izip_eq!(self.0.iter_mut(), rhs.0.iter()).for_each(|(a, b)| {
224 *a ^= *b;
225 });
226 self
227 }
228}
229
230#[cfg(any(test, feature = "dev"))]
231impl Distribution<PeerId> for Standard {
232 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> PeerId {
233 let mut secret_key = <[u8; PEER_ID_LENGTH]>::default();
234 rng.fill_bytes(&mut secret_key);
235 let public_key = SigningKey::from_bytes(&secret_key)
236 .verifying_key()
237 .to_bytes();
238 PeerId(public_key)
239 }
240}
241
242#[cfg(test)]
243mod tests {
244 use ed25519_dalek::{pkcs8::DecodePrivateKey, Signer, SigningKey, Verifier};
245 use rand::SeedableRng;
246
247 use super::*;
248 use crate::random::BaseRng;
249
250 const SAMPLE_CERTIFICATE_DER: &str = "3082011d3081d0a00302010202146403206e30248a32e568a26239c434d23df91131300506032b65703021311f301d06035504030c16726367656e2073656c66207369676e656420636572743020170d3735303130313030303030305a180f34303936303130313030303030305a3021311f301d06035504030c16726367656e2073656c66207369676e65642063657274302a300506032b6570032100a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593dea318301630140603551d11040d300b82096173796e632d6d7063300506032b657003410014ff443071b7ad0a0f540f3e5a083f5873d045f2a7302a63c171da750dea288b216beb1f599ca5db2696b7236f6d69652ab46a0845a5a6b6aa73608fb439010e";
251 const SAMPLE_SKEY_DER: &str = "3051020101300506032b657004220420c66ea2001a6b5b4e0b4ef51265c74829bb34e1952e9ed399c4158acf8df4521f812100a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593de";
252 const SAMPLE_PKEY_DER: &str =
253 "302a300506032b6570032100a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593de";
254 const SAMPLE_SKEY_BYTES: &str =
255 "c66ea2001a6b5b4e0b4ef51265c74829bb34e1952e9ed399c4158acf8df4521f";
256 const SAMPLE_PKEY_BYTES: &str =
257 "a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593de";
258
259 #[test]
260 fn test_happypath_peer_id_from_keys() {
261 let secret_key =
263 SigningKey::from_bytes(&hex::decode(SAMPLE_SKEY_BYTES).unwrap().try_into().unwrap());
264 let message = b"Hello, world!";
265 let signature = secret_key.sign(message);
266
267 let pkey_bytes: [u8; 32] = hex::decode(SAMPLE_PKEY_BYTES).unwrap().try_into().unwrap();
269 let peer_id = PeerId::try_from(&pkey_bytes).unwrap();
270 peer_id.verify(message, &signature).unwrap();
271 assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
272
273 let pkey =
275 VerifyingKey::from_public_key_der(&hex::decode(SAMPLE_PKEY_DER).unwrap()).unwrap();
276 let peer_id = PeerId::from(pkey);
277 peer_id.verify(message, &signature).unwrap();
278 assert_eq!(secret_key.verifying_key().as_bytes(), peer_id.as_ref());
279 assert_eq!(secret_key.verifying_key(), peer_id.try_into().unwrap());
280
281 let skey = SigningKey::from_pkcs8_der(&hex::decode(SAMPLE_SKEY_DER).unwrap()).unwrap();
283 let peer_id = PeerId::from(&skey);
284 peer_id.verify(message, &signature).unwrap();
285 assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
286 }
287
288 #[test]
289 fn test_happypath_peer_id_from_serialized_keys() {
290 let secret_key =
292 SigningKey::from_bytes(&hex::decode(SAMPLE_SKEY_BYTES).unwrap().try_into().unwrap());
293 let message = b"Hello, serialized keys!";
294 let signature = secret_key.sign(message);
295
296 let peer_id = PeerId::from_secret_key_der(&hex::decode(SAMPLE_SKEY_DER).unwrap()).unwrap();
298 peer_id.verify(message, &signature).unwrap();
299 assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
300
301 let peer_id = PeerId::from_secret_key_der(&hex::decode(SAMPLE_SKEY_DER).unwrap()).unwrap();
303 peer_id.verify(message, &signature).unwrap();
304 assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
305 }
306
307 #[test]
308 fn test_happypath_peer_id_from_certificate() {
309 let secret_key =
311 SigningKey::from_bytes(&hex::decode(SAMPLE_SKEY_BYTES).unwrap().try_into().unwrap());
312 let message = b"Hello, certificate!";
313 let signature = secret_key.sign(message);
314
315 let certificate = CertificateDer::from(hex::decode(SAMPLE_CERTIFICATE_DER).unwrap());
317 let peer_id = PeerId::from_certificate(certificate).unwrap();
318 peer_id.verify(message, &signature).unwrap();
319 assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
320 }
321
322 #[test]
323 fn test_happypath_two_peer_ids_cross_verify() {
324 let mut rng = BaseRng::from_seed(*b"Look Sam, the eagles are coming!");
325 let secret_key_1 = SigningKey::generate(&mut rng);
326 let secret_key_2 = SigningKey::generate(&mut rng);
327
328 let message = b"Hello, cross verify!";
329
330 let signature_1 = secret_key_1.sign(message);
331 let signature_2 = secret_key_2.sign(message);
332
333 let peer_id_1 = PeerId::from(&secret_key_1);
334 let peer_id_2 = PeerId::from(&secret_key_2);
335 assert_eq!(peer_id_1.as_ref(), secret_key_1.verifying_key().as_bytes());
336 assert_eq!(peer_id_2.as_ref(), secret_key_2.verifying_key().as_bytes());
337
338 peer_id_1.verify(message, &signature_1).unwrap();
339 peer_id_2.verify(message, &signature_2).unwrap();
340
341 peer_id_2.verify(message, &signature_1).unwrap_err();
342 peer_id_1.verify(message, &signature_2).unwrap_err();
343 }
344
345 #[test]
346 fn test_invalid_deserialized_peer_id_verify_never_panics() {
347 let mut rng = BaseRng::from_seed(*b"Look Sam, the eagles are coming!");
348 let signing_key = SigningKey::generate(&mut rng);
349 let message = b"Hello, invalid peer id!";
350 let signature = signing_key.sign(message);
351
352 let invalid_peer_id_bytes = [0xFFu8; PEER_ID_LENGTH];
354
355 fn assert_no_panic_verify_error<E>(
356 decoded: Result<PeerId, E>,
357 message: &[u8],
358 signature: &ed25519_dalek::Signature,
359 ) {
360 if let Ok(invalid_peer_id) = decoded {
363 let verify_result =
364 std::panic::catch_unwind(|| invalid_peer_id.verify(message, signature));
365 assert!(
366 verify_result.is_ok(),
367 "verify() must return an error instead of panicking for invalid PeerId bytes"
368 );
369 assert!(verify_result.unwrap().is_err());
370 }
371 }
372
373 let bincode_encoded = bincode::serialize(&invalid_peer_id_bytes).unwrap();
374 let bincode_decoded: Result<PeerId, _> = bincode::deserialize(&bincode_encoded);
375 assert_no_panic_verify_error(bincode_decoded, message, &signature);
376
377 let wincode_encoded = wincode::serialize(&invalid_peer_id_bytes).unwrap();
378 let wincode_decoded: Result<PeerId, _> = wincode::deserialize(&wincode_encoded);
379 assert_no_panic_verify_error(wincode_decoded, message, &signature);
380 }
381}