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