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
83impl<'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
121// ------------- Conversions -------------- //
122
123impl 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    /// Construct a peer ID from raw bytes without validating Ed25519 encoding.
154    ///
155    /// Prefer `TryFrom<&[u8; 32]>` when the bytes come from untrusted input.
156    #[cfg(any(test, feature = "dev"))]
157    pub const fn from_bytes_unchecked(bytes: [u8; PEER_ID_LENGTH]) -> Self {
158        Self(bytes)
159    }
160
161    /// Construct a peer ID from the given Ed25519 public key in an rcgen keypair.
162    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    /// Construct a peer ID from the given secret key in DER format.
174    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    /// Construct a peer ID from the given public key in DER format.
184    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    /// Construct a peer ID from the given Rustls certificate in DER format.
194    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        // Decode the SPKI to obtain the PeerId
201        Self::from_public_key_der(spki.as_ref())
202    }
203
204    /// Retrieve the peer ID corresponding to the given quinn connection.
205    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        // Load the secret key and sign a message
262        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        // Create a PeerId from the public key bytes and verify the signature
268        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        // Create a PeerId from the ed25519 public key and verify the signature
274        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        // Create a PeerId from the ed25519 secret key and verify the signature
282        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        // Load the secret key and sign a message
291        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        // Create a PeerId from the serialized public key in DER format and verify the signature
297        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        // Create a PeerId from the serialized secret key in DER format and verify the signature
302        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        // Load the secret key and sign a message
310        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        // Create a PeerId from the certificate and verify the signature
316        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        // Invalid compressed Edwards-Y encoding for an Ed25519 public key.
353        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 deserialization is tightened later, rejecting invalid bytes directly is also
361            // acceptable for this test.
362            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}