Skip to main content

primitives/types/identifiers/
peer_id.rs

1use derive_more::derive::AsRef;
2use ed25519_dalek::{
3    pkcs8::{DecodePrivateKey, DecodePublicKey},
4    SigningKey,
5    Verifier,
6    VerifyingKey,
7};
8use quinn::rustls::{server::ParsedCertificate, Error as RustlsError};
9pub use rand::Rng;
10#[cfg(any(test, feature = "dev"))]
11use rand::{distributions::Standard, prelude::Distribution};
12use rustls_pki_types::CertificateDer;
13use serde::{Deserialize, Serialize};
14
15use crate::errors::PrimitiveError;
16pub const PEER_ID_LENGTH: usize = ed25519_dalek::PUBLIC_KEY_LENGTH; // 32 Bytes
17
18#[derive(Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord, AsRef)]
19#[as_ref([u8])]
20/// A unique identifier for a peer in the network.
21/// It corresponds to the ed25519 public key of the peer in big-endian format.
22pub struct PeerId([u8; PEER_ID_LENGTH]);
23
24impl Verifier<ed25519_dalek::Signature> for PeerId {
25    fn verify(
26        &self,
27        message: &[u8],
28        signature: &ed25519_dalek::Signature,
29    ) -> Result<(), ed25519_dalek::SignatureError> {
30        let public_key = VerifyingKey::from(*self); // Safe, we checked it upon creation
31        public_key.verify_strict(message, signature)
32    }
33}
34
35#[cfg(not(any(test, feature = "dev")))]
36impl std::fmt::Display for PeerId {
37    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38        write!(f, "{}", hex::encode(self.0))
39    }
40}
41
42#[cfg(not(any(test, feature = "dev")))]
43impl std::fmt::Debug for PeerId {
44    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45        write!(f, "{}", hex::encode(self.0))
46    }
47}
48
49#[cfg(any(test, feature = "dev"))]
50impl std::fmt::Display for PeerId {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        write!(f, "{}", &hex::encode(self.0)[0..6])
53    }
54}
55
56#[cfg(any(test, feature = "dev"))]
57impl std::fmt::Debug for PeerId {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        write!(f, "{}", &hex::encode(self.0)[0..6])
60    }
61}
62
63// ------------- Failsafe Conversions -------------- //
64
65#[cfg(any(test, feature = "dev"))]
66impl From<[u8; PEER_ID_LENGTH]> for PeerId {
67    fn from(bytes: [u8; PEER_ID_LENGTH]) -> Self {
68        Self(bytes)
69    }
70}
71
72impl<'pid> From<&'pid PeerId> for &'pid [u8; PEER_ID_LENGTH] {
73    fn from(peer_id: &'pid PeerId) -> Self {
74        &peer_id.0
75    }
76}
77
78impl From<PeerId> for [u8; PEER_ID_LENGTH] {
79    fn from(peer_id: PeerId) -> Self {
80        peer_id.0
81    }
82}
83
84impl From<&PeerId> for String {
85    fn from(peer_id: &PeerId) -> String {
86        hex::encode(peer_id.0)
87    }
88}
89
90impl From<VerifyingKey> for PeerId {
91    fn from(verifying_key: VerifyingKey) -> PeerId {
92        Self(verifying_key.to_bytes())
93    }
94}
95
96impl From<PeerId> for VerifyingKey {
97    fn from(peer_id: PeerId) -> VerifyingKey {
98        VerifyingKey::from_bytes(&peer_id.0).unwrap() // Safe, we checked it upon creation
99    }
100}
101
102impl From<&SigningKey> for PeerId {
103    fn from(signing_key: &SigningKey) -> PeerId {
104        Self(signing_key.verifying_key().to_bytes())
105    }
106}
107
108// ------------- Conversions -------------- //
109
110impl TryFrom<&[u8; 32]> for PeerId {
111    type Error = PrimitiveError;
112
113    fn try_from(bytes: &[u8; 32]) -> Result<Self, Self::Error> {
114        let public_key = VerifyingKey::from_bytes(bytes).map_err(|_| {
115            PrimitiveError::InvalidParameters(
116                "Could not convert it to an ed25519 public key".to_string(),
117            )
118        })?;
119        Ok(Self(public_key.to_bytes()))
120    }
121}
122
123impl TryFrom<CertificateDer<'static>> for PeerId {
124    type Error = PrimitiveError;
125
126    fn try_from(certificate: CertificateDer<'static>) -> Result<Self, Self::Error> {
127        Self::from_certificate(certificate)
128    }
129}
130
131impl TryFrom<&quinn::Connection> for PeerId {
132    type Error = PrimitiveError;
133
134    fn try_from(connection: &quinn::Connection) -> Result<Self, Self::Error> {
135        Self::from_connection(connection)
136    }
137}
138
139impl PeerId {
140    /// Construct a peer ID from the given Ed25519 public key in an rcgen keypair.
141    pub fn from_keypair(keypair: &rcgen::KeyPair) -> Result<Self, PrimitiveError> {
142        if keypair.algorithm() != &rcgen::PKCS_ED25519 {
143            return Err(PrimitiveError::InvalidParameters(
144                "Keypair is not Ed25519".to_string(),
145            ));
146        }
147        let public_key_bytes: [u8; PEER_ID_LENGTH] =
148            keypair.public_key_raw().to_vec().try_into().unwrap();
149        Ok(Self(public_key_bytes))
150    }
151
152    /// Construct a peer ID from the given secret key in DER format.
153    pub fn from_secret_key_der(bytes: &[u8]) -> Result<Self, PrimitiveError> {
154        let secret_key = SigningKey::from_pkcs8_der(bytes).map_err(|e| {
155            PrimitiveError::InvalidParameters(format!(
156                "Failed to decode secret key in DER format: {e}",
157            ))
158        })?;
159        Ok(Self(*secret_key.verifying_key().as_bytes()))
160    }
161
162    /// Construct a peer ID from the given public key in DER format.
163    pub fn from_public_key_der(bytes: &[u8]) -> Result<Self, PrimitiveError> {
164        let public_key = VerifyingKey::from_public_key_der(bytes).map_err(|e| {
165            PrimitiveError::InvalidParameters(format!(
166                "Failed to decode public key in DER format: {e}",
167            ))
168        })?;
169        Ok(Self(public_key.to_bytes()))
170    }
171
172    /// Construct a peer ID from the given Rustls certificate in DER format.
173    pub(crate) fn from_certificate(
174        certificate: CertificateDer<'static>,
175    ) -> Result<Self, PrimitiveError> {
176        let cert = ParsedCertificate::try_from(&certificate)?;
177        let spki = cert.subject_public_key_info();
178
179        // Decode the SPKI to obtain the PeerId
180        Self::from_public_key_der(spki.as_ref())
181    }
182
183    /// Retrieve the peer ID corresponding to the given quinn connection.
184    pub fn from_connection(connection: &quinn::Connection) -> Result<Self, PrimitiveError> {
185        let certificate = connection
186            .peer_identity()
187            .ok_or(RustlsError::NoCertificatesPresented)?
188            .downcast::<Vec<CertificateDer<'static>>>()
189            .map_err(|_| RustlsError::General("Peer identity didn't downcast to a certificate. Check quinn session (should be default rustls).".to_string()))?
190            .into_iter()
191            .next()
192            .ok_or(RustlsError::NoCertificatesPresented)?;
193        Self::from_certificate(certificate)
194    }
195}
196
197#[cfg(any(test, feature = "dev"))]
198impl Distribution<PeerId> for Standard {
199    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> PeerId {
200        let mut secret_key = <[u8; PEER_ID_LENGTH]>::default();
201        rng.fill_bytes(&mut secret_key);
202        let public_key = SigningKey::from_bytes(&secret_key)
203            .verifying_key()
204            .to_bytes();
205        PeerId(public_key)
206    }
207}
208
209#[cfg(test)]
210mod tests {
211    use ed25519_dalek::{pkcs8::DecodePrivateKey, Signer, SigningKey, Verifier};
212    use rand::SeedableRng;
213
214    use super::*;
215    use crate::random::BaseRng;
216
217    const SAMPLE_CERTIFICATE_DER: &str = "3082011d3081d0a00302010202146403206e30248a32e568a26239c434d23df91131300506032b65703021311f301d06035504030c16726367656e2073656c66207369676e656420636572743020170d3735303130313030303030305a180f34303936303130313030303030305a3021311f301d06035504030c16726367656e2073656c66207369676e65642063657274302a300506032b6570032100a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593dea318301630140603551d11040d300b82096173796e632d6d7063300506032b657003410014ff443071b7ad0a0f540f3e5a083f5873d045f2a7302a63c171da750dea288b216beb1f599ca5db2696b7236f6d69652ab46a0845a5a6b6aa73608fb439010e";
218    const SAMPLE_SKEY_DER: &str = "3051020101300506032b657004220420c66ea2001a6b5b4e0b4ef51265c74829bb34e1952e9ed399c4158acf8df4521f812100a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593de";
219    const SAMPLE_PKEY_DER: &str =
220        "302a300506032b6570032100a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593de";
221    const SAMPLE_SKEY_BYTES: &str =
222        "c66ea2001a6b5b4e0b4ef51265c74829bb34e1952e9ed399c4158acf8df4521f";
223    const SAMPLE_PKEY_BYTES: &str =
224        "a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593de";
225
226    #[test]
227    fn test_happypath_peer_id_from_keys() {
228        // Load the secret key and sign a message
229        let secret_key =
230            SigningKey::from_bytes(&hex::decode(SAMPLE_SKEY_BYTES).unwrap().try_into().unwrap());
231        let message = b"Hello, world!";
232        let signature = secret_key.sign(message);
233
234        // Create a PeerId from the public key bytes and verify the signature
235        let pkey_bytes: [u8; 32] = hex::decode(SAMPLE_PKEY_BYTES).unwrap().try_into().unwrap();
236        let peer_id = PeerId::try_from(&pkey_bytes).unwrap();
237        peer_id.verify(message, &signature).unwrap();
238        assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
239
240        // Create a PeerId from the ed25519 public key and verify the signature
241        let pkey =
242            VerifyingKey::from_public_key_der(&hex::decode(SAMPLE_PKEY_DER).unwrap()).unwrap();
243        let peer_id = PeerId::from(pkey);
244        peer_id.verify(message, &signature).unwrap();
245        assert_eq!(secret_key.verifying_key().as_bytes(), peer_id.as_ref());
246        assert_eq!(secret_key.verifying_key(), peer_id.into());
247
248        // Create a PeerId from the ed25519 secret key and verify the signature
249        let skey = SigningKey::from_pkcs8_der(&hex::decode(SAMPLE_SKEY_DER).unwrap()).unwrap();
250        let peer_id = PeerId::from(&skey);
251        peer_id.verify(message, &signature).unwrap();
252        assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
253    }
254
255    #[test]
256    fn test_happypath_peer_id_from_serialized_keys() {
257        // Load the secret key and sign a message
258        let secret_key =
259            SigningKey::from_bytes(&hex::decode(SAMPLE_SKEY_BYTES).unwrap().try_into().unwrap());
260        let message = b"Hello, serialized keys!";
261        let signature = secret_key.sign(message);
262
263        // Create a PeerId from the serialized public key in DER format and verify the signature
264        let peer_id = PeerId::from_secret_key_der(&hex::decode(SAMPLE_SKEY_DER).unwrap()).unwrap();
265        peer_id.verify(message, &signature).unwrap();
266        assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
267
268        // Create a PeerId from the serialized secret key in DER format and verify the signature
269        let peer_id = PeerId::from_secret_key_der(&hex::decode(SAMPLE_SKEY_DER).unwrap()).unwrap();
270        peer_id.verify(message, &signature).unwrap();
271        assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
272    }
273
274    #[test]
275    fn test_happypath_peer_id_from_certificate() {
276        // Load the secret key and sign a message
277        let secret_key =
278            SigningKey::from_bytes(&hex::decode(SAMPLE_SKEY_BYTES).unwrap().try_into().unwrap());
279        let message = b"Hello, certificate!";
280        let signature = secret_key.sign(message);
281
282        // Create a PeerId from the certificate and verify the signature
283        let certificate = CertificateDer::from(hex::decode(SAMPLE_CERTIFICATE_DER).unwrap());
284        let peer_id = PeerId::from_certificate(certificate).unwrap();
285        peer_id.verify(message, &signature).unwrap();
286        assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
287    }
288
289    #[test]
290    fn test_happypath_two_peer_ids_cross_verify() {
291        let mut rng = BaseRng::from_seed(*b"Look Sam, the eagles are coming!");
292        let secret_key_1 = SigningKey::generate(&mut rng);
293        let secret_key_2 = SigningKey::generate(&mut rng);
294
295        let message = b"Hello, cross verify!";
296
297        let signature_1 = secret_key_1.sign(message);
298        let signature_2 = secret_key_2.sign(message);
299
300        let peer_id_1 = PeerId::from(&secret_key_1);
301        let peer_id_2 = PeerId::from(&secret_key_2);
302        assert_eq!(peer_id_1.as_ref(), secret_key_1.verifying_key().as_bytes());
303        assert_eq!(peer_id_2.as_ref(), secret_key_2.verifying_key().as_bytes());
304
305        peer_id_1.verify(message, &signature_1).unwrap();
306        peer_id_2.verify(message, &signature_2).unwrap();
307
308        peer_id_2.verify(message, &signature_1).unwrap_err();
309        peer_id_1.verify(message, &signature_2).unwrap_err();
310    }
311}