Skip to main content

primitives/types/identifiers/
peer_id.rs

1use 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; // 32 Bytes
20
21#[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)]
37/// A unique identifier for a peer in the network.
38/// It corresponds to the ed25519 public key of the peer in big-endian format.
39pub 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
81// ------------- Failsafe Conversions -------------- //
82
83#[cfg(any(test, feature = "dev"))]
84impl From<[u8; PEER_ID_LENGTH]> for PeerId {
85    fn from(bytes: [u8; PEER_ID_LENGTH]) -> Self {
86        Self(bytes)
87    }
88}
89
90impl<'pid> From<&'pid PeerId> for &'pid [u8; PEER_ID_LENGTH] {
91    fn from(peer_id: &'pid PeerId) -> Self {
92        &peer_id.0
93    }
94}
95
96impl From<PeerId> for [u8; PEER_ID_LENGTH] {
97    fn from(peer_id: PeerId) -> Self {
98        peer_id.0
99    }
100}
101
102impl From<&PeerId> for String {
103    fn from(peer_id: &PeerId) -> String {
104        hex::encode(peer_id.0)
105    }
106}
107
108impl From<VerifyingKey> for PeerId {
109    fn from(verifying_key: VerifyingKey) -> PeerId {
110        Self(verifying_key.to_bytes())
111    }
112}
113
114impl TryFrom<PeerId> for VerifyingKey {
115    type Error = PrimitiveError;
116
117    fn try_from(peer_id: PeerId) -> Result<VerifyingKey, PrimitiveError> {
118        VerifyingKey::from_bytes(&peer_id.0).map_err(|_| PrimitiveError::InvalidPeerId(peer_id))
119    }
120}
121
122impl From<&SigningKey> for PeerId {
123    fn from(signing_key: &SigningKey) -> PeerId {
124        Self(signing_key.verifying_key().to_bytes())
125    }
126}
127
128// ------------- Conversions -------------- //
129
130impl TryFrom<&[u8; 32]> for PeerId {
131    type Error = PrimitiveError;
132
133    fn try_from(bytes: &[u8; 32]) -> Result<Self, Self::Error> {
134        let public_key = VerifyingKey::from_bytes(bytes).map_err(|_| {
135            PrimitiveError::InvalidParameters(
136                "Could not convert it to an ed25519 public key".to_string(),
137            )
138        })?;
139        Ok(Self(public_key.to_bytes()))
140    }
141}
142
143impl TryFrom<CertificateDer<'static>> for PeerId {
144    type Error = PrimitiveError;
145
146    fn try_from(certificate: CertificateDer<'static>) -> Result<Self, Self::Error> {
147        Self::from_certificate(certificate)
148    }
149}
150
151impl TryFrom<&quinn::Connection> for PeerId {
152    type Error = PrimitiveError;
153
154    fn try_from(connection: &quinn::Connection) -> Result<Self, Self::Error> {
155        Self::from_connection(connection)
156    }
157}
158
159impl PeerId {
160    /// Construct a peer ID from the given Ed25519 public key in an rcgen keypair.
161    pub fn from_keypair(keypair: &rcgen::KeyPair) -> Result<Self, PrimitiveError> {
162        if keypair.algorithm() != &rcgen::PKCS_ED25519 {
163            return Err(PrimitiveError::InvalidParameters(
164                "Keypair is not Ed25519".to_string(),
165            ));
166        }
167        let public_key_bytes: [u8; PEER_ID_LENGTH] =
168            keypair.public_key_raw().to_vec().try_into().unwrap();
169        Ok(Self(public_key_bytes))
170    }
171
172    /// Construct a peer ID from the given secret key in DER format.
173    pub fn from_secret_key_der(bytes: &[u8]) -> Result<Self, PrimitiveError> {
174        let secret_key = SigningKey::from_pkcs8_der(bytes).map_err(|e| {
175            PrimitiveError::InvalidParameters(format!(
176                "Failed to decode secret key in DER format: {e}",
177            ))
178        })?;
179        Ok(Self(*secret_key.verifying_key().as_bytes()))
180    }
181
182    /// Construct a peer ID from the given public key in DER format.
183    pub fn from_public_key_der(bytes: &[u8]) -> Result<Self, PrimitiveError> {
184        let public_key = VerifyingKey::from_public_key_der(bytes).map_err(|e| {
185            PrimitiveError::InvalidParameters(format!(
186                "Failed to decode public key in DER format: {e}",
187            ))
188        })?;
189        Ok(Self(public_key.to_bytes()))
190    }
191
192    /// Construct a peer ID from the given Rustls certificate in DER format.
193    pub(crate) fn from_certificate(
194        certificate: CertificateDer<'static>,
195    ) -> Result<Self, PrimitiveError> {
196        let cert = ParsedCertificate::try_from(&certificate)?;
197        let spki = cert.subject_public_key_info();
198
199        // Decode the SPKI to obtain the PeerId
200        Self::from_public_key_der(spki.as_ref())
201    }
202
203    /// Retrieve the peer ID corresponding to the given quinn connection.
204    pub fn from_connection(connection: &quinn::Connection) -> Result<Self, PrimitiveError> {
205        let certificate = connection
206            .peer_identity()
207            .ok_or(RustlsError::NoCertificatesPresented)?
208            .downcast::<Vec<CertificateDer<'static>>>()
209            .map_err(|_| RustlsError::General("Peer identity didn't downcast to a certificate. Check quinn session (should be default rustls).".to_string()))?
210            .into_iter()
211            .next()
212            .ok_or(RustlsError::NoCertificatesPresented)?;
213        Self::from_certificate(certificate)
214    }
215}
216
217#[macros::op_variants(owned, borrowed, flipped_commutative)]
218impl BitXor<&PeerId> for PeerId {
219    type Output = PeerId;
220
221    fn bitxor(mut self, rhs: &Self) -> Self::Output {
222        izip_eq!(self.0.iter_mut(), rhs.0.iter()).for_each(|(a, b)| {
223            *a ^= *b;
224        });
225        self
226    }
227}
228
229#[cfg(any(test, feature = "dev"))]
230impl Distribution<PeerId> for Standard {
231    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> PeerId {
232        let mut secret_key = <[u8; PEER_ID_LENGTH]>::default();
233        rng.fill_bytes(&mut secret_key);
234        let public_key = SigningKey::from_bytes(&secret_key)
235            .verifying_key()
236            .to_bytes();
237        PeerId(public_key)
238    }
239}
240
241#[cfg(test)]
242mod tests {
243    use ed25519_dalek::{pkcs8::DecodePrivateKey, Signer, SigningKey, Verifier};
244    use rand::SeedableRng;
245
246    use super::*;
247    use crate::random::BaseRng;
248
249    const SAMPLE_CERTIFICATE_DER: &str = "3082011d3081d0a00302010202146403206e30248a32e568a26239c434d23df91131300506032b65703021311f301d06035504030c16726367656e2073656c66207369676e656420636572743020170d3735303130313030303030305a180f34303936303130313030303030305a3021311f301d06035504030c16726367656e2073656c66207369676e65642063657274302a300506032b6570032100a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593dea318301630140603551d11040d300b82096173796e632d6d7063300506032b657003410014ff443071b7ad0a0f540f3e5a083f5873d045f2a7302a63c171da750dea288b216beb1f599ca5db2696b7236f6d69652ab46a0845a5a6b6aa73608fb439010e";
250    const SAMPLE_SKEY_DER: &str = "3051020101300506032b657004220420c66ea2001a6b5b4e0b4ef51265c74829bb34e1952e9ed399c4158acf8df4521f812100a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593de";
251    const SAMPLE_PKEY_DER: &str =
252        "302a300506032b6570032100a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593de";
253    const SAMPLE_SKEY_BYTES: &str =
254        "c66ea2001a6b5b4e0b4ef51265c74829bb34e1952e9ed399c4158acf8df4521f";
255    const SAMPLE_PKEY_BYTES: &str =
256        "a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593de";
257
258    #[test]
259    fn test_happypath_peer_id_from_keys() {
260        // Load the secret key and sign a message
261        let secret_key =
262            SigningKey::from_bytes(&hex::decode(SAMPLE_SKEY_BYTES).unwrap().try_into().unwrap());
263        let message = b"Hello, world!";
264        let signature = secret_key.sign(message);
265
266        // Create a PeerId from the public key bytes and verify the signature
267        let pkey_bytes: [u8; 32] = hex::decode(SAMPLE_PKEY_BYTES).unwrap().try_into().unwrap();
268        let peer_id = PeerId::try_from(&pkey_bytes).unwrap();
269        peer_id.verify(message, &signature).unwrap();
270        assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
271
272        // Create a PeerId from the ed25519 public key and verify the signature
273        let pkey =
274            VerifyingKey::from_public_key_der(&hex::decode(SAMPLE_PKEY_DER).unwrap()).unwrap();
275        let peer_id = PeerId::from(pkey);
276        peer_id.verify(message, &signature).unwrap();
277        assert_eq!(secret_key.verifying_key().as_bytes(), peer_id.as_ref());
278        assert_eq!(secret_key.verifying_key(), peer_id.try_into().unwrap());
279
280        // Create a PeerId from the ed25519 secret key and verify the signature
281        let skey = SigningKey::from_pkcs8_der(&hex::decode(SAMPLE_SKEY_DER).unwrap()).unwrap();
282        let peer_id = PeerId::from(&skey);
283        peer_id.verify(message, &signature).unwrap();
284        assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
285    }
286
287    #[test]
288    fn test_happypath_peer_id_from_serialized_keys() {
289        // Load the secret key and sign a message
290        let secret_key =
291            SigningKey::from_bytes(&hex::decode(SAMPLE_SKEY_BYTES).unwrap().try_into().unwrap());
292        let message = b"Hello, serialized keys!";
293        let signature = secret_key.sign(message);
294
295        // Create a PeerId from the serialized public key in DER format and verify the signature
296        let peer_id = PeerId::from_secret_key_der(&hex::decode(SAMPLE_SKEY_DER).unwrap()).unwrap();
297        peer_id.verify(message, &signature).unwrap();
298        assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
299
300        // Create a PeerId from the serialized secret key in DER format and verify the signature
301        let peer_id = PeerId::from_secret_key_der(&hex::decode(SAMPLE_SKEY_DER).unwrap()).unwrap();
302        peer_id.verify(message, &signature).unwrap();
303        assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
304    }
305
306    #[test]
307    fn test_happypath_peer_id_from_certificate() {
308        // Load the secret key and sign a message
309        let secret_key =
310            SigningKey::from_bytes(&hex::decode(SAMPLE_SKEY_BYTES).unwrap().try_into().unwrap());
311        let message = b"Hello, certificate!";
312        let signature = secret_key.sign(message);
313
314        // Create a PeerId from the certificate and verify the signature
315        let certificate = CertificateDer::from(hex::decode(SAMPLE_CERTIFICATE_DER).unwrap());
316        let peer_id = PeerId::from_certificate(certificate).unwrap();
317        peer_id.verify(message, &signature).unwrap();
318        assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
319    }
320
321    #[test]
322    fn test_happypath_two_peer_ids_cross_verify() {
323        let mut rng = BaseRng::from_seed(*b"Look Sam, the eagles are coming!");
324        let secret_key_1 = SigningKey::generate(&mut rng);
325        let secret_key_2 = SigningKey::generate(&mut rng);
326
327        let message = b"Hello, cross verify!";
328
329        let signature_1 = secret_key_1.sign(message);
330        let signature_2 = secret_key_2.sign(message);
331
332        let peer_id_1 = PeerId::from(&secret_key_1);
333        let peer_id_2 = PeerId::from(&secret_key_2);
334        assert_eq!(peer_id_1.as_ref(), secret_key_1.verifying_key().as_bytes());
335        assert_eq!(peer_id_2.as_ref(), secret_key_2.verifying_key().as_bytes());
336
337        peer_id_1.verify(message, &signature_1).unwrap();
338        peer_id_2.verify(message, &signature_2).unwrap();
339
340        peer_id_2.verify(message, &signature_1).unwrap_err();
341        peer_id_1.verify(message, &signature_2).unwrap_err();
342    }
343
344    #[test]
345    fn test_invalid_deserialized_peer_id_verify_never_panics() {
346        let mut rng = BaseRng::from_seed(*b"Look Sam, the eagles are coming!");
347        let signing_key = SigningKey::generate(&mut rng);
348        let message = b"Hello, invalid peer id!";
349        let signature = signing_key.sign(message);
350
351        // Invalid compressed Edwards-Y encoding for an Ed25519 public key.
352        let invalid_peer_id_bytes = [0xFFu8; PEER_ID_LENGTH];
353
354        fn assert_no_panic_verify_error<E>(
355            decoded: Result<PeerId, E>,
356            message: &[u8],
357            signature: &ed25519_dalek::Signature,
358        ) {
359            // If deserialization is tightened later, rejecting invalid bytes directly is also
360            // acceptable for this test.
361            if let Ok(invalid_peer_id) = decoded {
362                let verify_result =
363                    std::panic::catch_unwind(|| invalid_peer_id.verify(message, signature));
364                assert!(
365                    verify_result.is_ok(),
366                    "verify() must return an error instead of panicking for invalid PeerId bytes"
367                );
368                assert!(verify_result.unwrap().is_err());
369            }
370        }
371
372        let bincode_encoded = bincode::serialize(&invalid_peer_id_bytes).unwrap();
373        let bincode_decoded: Result<PeerId, _> = bincode::deserialize(&bincode_encoded);
374        assert_no_panic_verify_error(bincode_decoded, message, &signature);
375
376        let wincode_encoded = wincode::serialize(&invalid_peer_id_bytes).unwrap();
377        let wincode_decoded: Result<PeerId, _> = wincode::deserialize(&wincode_encoded);
378        assert_no_panic_verify_error(wincode_decoded, message, &signature);
379    }
380}