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;
12use rustls_pki_types::CertificateDer;
13use serde::{Deserialize, Serialize};
14
15#[cfg(any(test, feature = "dev"))]
16use crate::random::{CryptoRngCore, Random};
17use crate::{errors::PrimitiveError, izip_eq};
18pub const PEER_ID_LENGTH: usize = ed25519_dalek::PUBLIC_KEY_LENGTH; #[derive(Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord, AsRef)]
21#[as_ref([u8])]
22#[repr(transparent)]
23pub struct PeerId([u8; PEER_ID_LENGTH]);
26
27impl Verifier<ed25519_dalek::Signature> for PeerId {
28 fn verify(
29 &self,
30 message: &[u8],
31 signature: &ed25519_dalek::Signature,
32 ) -> Result<(), ed25519_dalek::SignatureError> {
33 let public_key =
34 VerifyingKey::try_from(*self).map_err(ed25519_dalek::SignatureError::from_source)?;
35 public_key.verify_strict(message, signature)
36 }
37}
38
39#[cfg(not(any(test, feature = "dev")))]
40impl std::fmt::Display for PeerId {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 write!(f, "{}", hex::encode(self.0))
43 }
44}
45
46#[cfg(not(any(test, feature = "dev")))]
47impl std::fmt::Debug for PeerId {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 write!(f, "{}", hex::encode(self.0))
50 }
51}
52
53#[cfg(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)[0..6])
57 }
58}
59
60#[cfg(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)[0..6])
64 }
65}
66
67impl<'pid> From<&'pid PeerId> for &'pid [u8; PEER_ID_LENGTH] {
70 fn from(peer_id: &'pid PeerId) -> Self {
71 &peer_id.0
72 }
73}
74
75impl From<PeerId> for [u8; PEER_ID_LENGTH] {
76 fn from(peer_id: PeerId) -> Self {
77 peer_id.0
78 }
79}
80
81impl From<&PeerId> for String {
82 fn from(peer_id: &PeerId) -> String {
83 hex::encode(peer_id.0)
84 }
85}
86
87impl From<VerifyingKey> for PeerId {
88 fn from(verifying_key: VerifyingKey) -> PeerId {
89 Self(verifying_key.to_bytes())
90 }
91}
92
93impl TryFrom<PeerId> for VerifyingKey {
94 type Error = PrimitiveError;
95
96 fn try_from(peer_id: PeerId) -> Result<VerifyingKey, PrimitiveError> {
97 VerifyingKey::from_bytes(&peer_id.0).map_err(|_| PrimitiveError::InvalidPeerId(peer_id))
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
107impl TryFrom<&[u8; PEER_ID_LENGTH]> for PeerId {
110 type Error = PrimitiveError;
111
112 fn try_from(bytes: &[u8; PEER_ID_LENGTH]) -> 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 #[cfg(any(test, feature = "dev"))]
143 pub const fn from_bytes_unchecked(bytes: [u8; PEER_ID_LENGTH]) -> Self {
144 Self(bytes)
145 }
146
147 pub fn from_keypair(keypair: &rcgen::KeyPair) -> Result<Self, PrimitiveError> {
149 if keypair.algorithm() != &rcgen::PKCS_ED25519 {
150 return Err(PrimitiveError::InvalidParameters(
151 "Keypair is not Ed25519".to_string(),
152 ));
153 }
154 let public_key_bytes: [u8; PEER_ID_LENGTH] =
155 keypair.public_key_raw().to_vec().try_into().unwrap();
156 Ok(Self(public_key_bytes))
157 }
158
159 pub fn from_secret_key_der(bytes: &[u8]) -> Result<Self, PrimitiveError> {
161 let secret_key = SigningKey::from_pkcs8_der(bytes).map_err(|e| {
162 PrimitiveError::InvalidParameters(format!(
163 "Failed to decode secret key in DER format: {e}",
164 ))
165 })?;
166 Ok(Self(*secret_key.verifying_key().as_bytes()))
167 }
168
169 pub fn from_public_key_der(bytes: &[u8]) -> Result<Self, PrimitiveError> {
171 let public_key = VerifyingKey::from_public_key_der(bytes).map_err(|e| {
172 PrimitiveError::InvalidParameters(format!(
173 "Failed to decode public key in DER format: {e}",
174 ))
175 })?;
176 Ok(Self(public_key.to_bytes()))
177 }
178
179 pub(crate) fn from_certificate(
181 certificate: CertificateDer<'static>,
182 ) -> Result<Self, PrimitiveError> {
183 let cert = ParsedCertificate::try_from(&certificate)?;
184 let spki = cert.subject_public_key_info();
185
186 Self::from_public_key_der(spki.as_ref())
188 }
189
190 pub fn from_connection(connection: &quinn::Connection) -> Result<Self, PrimitiveError> {
192 let certificate = connection
193 .peer_identity()
194 .ok_or(RustlsError::NoCertificatesPresented)?
195 .downcast::<Vec<CertificateDer<'static>>>()
196 .map_err(|_| RustlsError::General("Peer identity didn't downcast to a certificate. Check quinn session (should be default rustls).".to_string()))?
197 .into_iter()
198 .next()
199 .ok_or(RustlsError::NoCertificatesPresented)?;
200 Self::from_certificate(certificate)
201 }
202}
203
204#[macros::op_variants(owned, borrowed, flipped_commutative)]
205impl BitXor<&PeerId> for PeerId {
206 type Output = PeerId;
207
208 fn bitxor(mut self, rhs: &Self) -> Self::Output {
209 izip_eq!(self.0.iter_mut(), rhs.0.iter()).for_each(|(a, b)| {
210 *a ^= *b;
211 });
212 self
213 }
214}
215
216#[cfg(any(test, feature = "dev"))]
217impl Random for PeerId {
218 fn random(mut rng: impl CryptoRngCore) -> Self {
219 let mut secret_key = <[u8; PEER_ID_LENGTH]>::default();
220 rng.fill_bytes(&mut secret_key);
221 let public_key = SigningKey::from_bytes(&secret_key)
222 .verifying_key()
223 .to_bytes();
224 PeerId(public_key)
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use ed25519_dalek::{pkcs8::DecodePrivateKey, Signer, SigningKey, Verifier};
231 use rand::SeedableRng;
232
233 use super::*;
234 use crate::{random::BaseRng, utils::codec::bincode_io};
235
236 const SAMPLE_CERTIFICATE_DER: &str = "3082011d3081d0a00302010202146403206e30248a32e568a26239c434d23df91131300506032b65703021311f301d06035504030c16726367656e2073656c66207369676e656420636572743020170d3735303130313030303030305a180f34303936303130313030303030305a3021311f301d06035504030c16726367656e2073656c66207369676e65642063657274302a300506032b6570032100a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593dea318301630140603551d11040d300b82096173796e632d6d7063300506032b657003410014ff443071b7ad0a0f540f3e5a083f5873d045f2a7302a63c171da750dea288b216beb1f599ca5db2696b7236f6d69652ab46a0845a5a6b6aa73608fb439010e";
237 const SAMPLE_SKEY_DER: &str = "3051020101300506032b657004220420c66ea2001a6b5b4e0b4ef51265c74829bb34e1952e9ed399c4158acf8df4521f812100a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593de";
238 const SAMPLE_PKEY_DER: &str =
239 "302a300506032b6570032100a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593de";
240 const SAMPLE_SKEY_BYTES: &str =
241 "c66ea2001a6b5b4e0b4ef51265c74829bb34e1952e9ed399c4158acf8df4521f";
242 const SAMPLE_PKEY_BYTES: &str =
243 "a965eea43375c9ecff6ac3a324ee77cd3d0ceca3b1a203881bc61a16203593de";
244
245 #[test]
246 fn test_happypath_peer_id_from_keys() {
247 let secret_key =
249 SigningKey::from_bytes(&hex::decode(SAMPLE_SKEY_BYTES).unwrap().try_into().unwrap());
250 let message = b"Hello, world!";
251 let signature = secret_key.sign(message);
252
253 let pkey_bytes: [u8; 32] = hex::decode(SAMPLE_PKEY_BYTES).unwrap().try_into().unwrap();
255 let peer_id = PeerId::try_from(&pkey_bytes).unwrap();
256 peer_id.verify(message, &signature).unwrap();
257 assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
258
259 let pkey =
261 VerifyingKey::from_public_key_der(&hex::decode(SAMPLE_PKEY_DER).unwrap()).unwrap();
262 let peer_id = PeerId::from(pkey);
263 peer_id.verify(message, &signature).unwrap();
264 assert_eq!(secret_key.verifying_key().as_bytes(), peer_id.as_ref());
265 assert_eq!(secret_key.verifying_key(), peer_id.try_into().unwrap());
266
267 let skey = SigningKey::from_pkcs8_der(&hex::decode(SAMPLE_SKEY_DER).unwrap()).unwrap();
269 let peer_id = PeerId::from(&skey);
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_serialized_keys() {
276 let secret_key =
278 SigningKey::from_bytes(&hex::decode(SAMPLE_SKEY_BYTES).unwrap().try_into().unwrap());
279 let message = b"Hello, serialized keys!";
280 let signature = secret_key.sign(message);
281
282 let peer_id = PeerId::from_secret_key_der(&hex::decode(SAMPLE_SKEY_DER).unwrap()).unwrap();
284 peer_id.verify(message, &signature).unwrap();
285 assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
286
287 let peer_id = PeerId::from_secret_key_der(&hex::decode(SAMPLE_SKEY_DER).unwrap()).unwrap();
289 peer_id.verify(message, &signature).unwrap();
290 assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
291 }
292
293 #[test]
294 fn test_happypath_peer_id_from_certificate() {
295 let secret_key =
297 SigningKey::from_bytes(&hex::decode(SAMPLE_SKEY_BYTES).unwrap().try_into().unwrap());
298 let message = b"Hello, certificate!";
299 let signature = secret_key.sign(message);
300
301 let certificate = CertificateDer::from(hex::decode(SAMPLE_CERTIFICATE_DER).unwrap());
303 let peer_id = PeerId::from_certificate(certificate).unwrap();
304 peer_id.verify(message, &signature).unwrap();
305 assert_eq!(peer_id.as_ref(), secret_key.verifying_key().as_bytes());
306 }
307
308 #[test]
309 fn test_happypath_two_peer_ids_cross_verify() {
310 let mut rng = BaseRng::from_seed(*b"Look Sam, the eagles are coming!");
311 let secret_key_1 = SigningKey::generate(&mut rng);
312 let secret_key_2 = SigningKey::generate(&mut rng);
313
314 let message = b"Hello, cross verify!";
315
316 let signature_1 = secret_key_1.sign(message);
317 let signature_2 = secret_key_2.sign(message);
318
319 let peer_id_1 = PeerId::from(&secret_key_1);
320 let peer_id_2 = PeerId::from(&secret_key_2);
321 assert_eq!(peer_id_1.as_ref(), secret_key_1.verifying_key().as_bytes());
322 assert_eq!(peer_id_2.as_ref(), secret_key_2.verifying_key().as_bytes());
323
324 peer_id_1.verify(message, &signature_1).unwrap();
325 peer_id_2.verify(message, &signature_2).unwrap();
326
327 peer_id_2.verify(message, &signature_1).unwrap_err();
328 peer_id_1.verify(message, &signature_2).unwrap_err();
329 }
330
331 #[test]
332 fn test_invalid_deserialized_peer_id_verify_never_panics() {
333 let mut rng = BaseRng::from_seed(*b"Look Sam, the eagles are coming!");
334 let signing_key = SigningKey::generate(&mut rng);
335 let message = b"Hello, invalid peer id!";
336 let signature = signing_key.sign(message);
337
338 let invalid_peer_id_bytes = [0xFFu8; PEER_ID_LENGTH];
340
341 fn assert_no_panic_verify_error<E>(
342 decoded: Result<PeerId, E>,
343 message: &[u8],
344 signature: &ed25519_dalek::Signature,
345 ) {
346 if let Ok(invalid_peer_id) = decoded {
349 let verify_result =
350 std::panic::catch_unwind(|| invalid_peer_id.verify(message, signature));
351 assert!(
352 verify_result.is_ok(),
353 "verify() must return an error instead of panicking for invalid PeerId bytes"
354 );
355 assert!(verify_result.unwrap().is_err());
356 }
357 }
358
359 let bincode_encoded = bincode_io::serialize(&invalid_peer_id_bytes).unwrap();
360 let bincode_decoded: Result<PeerId, _> = bincode_io::deserialize(&bincode_encoded);
361 assert_no_panic_verify_error(bincode_decoded, message, &signature);
362 }
363}