iroh_base/
key.rs

1//! Cryptographic key handling for `iroh`.
2
3use std::{
4    borrow::Borrow,
5    cmp::{Ord, PartialOrd},
6    fmt::{Debug, Display},
7    hash::Hash,
8    ops::Deref,
9    str::FromStr,
10};
11
12use curve25519_dalek::edwards::CompressedEdwardsY;
13pub use ed25519_dalek::{Signature, SignatureError};
14use ed25519_dalek::{SigningKey, VerifyingKey};
15use nested_enum_utils::common_fields;
16use rand_core::CryptoRngCore;
17use serde::{Deserialize, Serialize};
18use snafu::{Backtrace, Snafu};
19
20/// A public key.
21///
22/// The key itself is stored as the `CompressedEdwards` y coordinate of the public key
23/// It is verified to decompress into a valid key when created.
24#[derive(Clone, Copy, PartialEq, Eq)]
25#[repr(transparent)]
26pub struct PublicKey(CompressedEdwardsY);
27
28impl Borrow<[u8; 32]> for PublicKey {
29    fn borrow(&self) -> &[u8; 32] {
30        self.as_bytes()
31    }
32}
33
34impl Deref for PublicKey {
35    type Target = [u8; 32];
36
37    fn deref(&self) -> &Self::Target {
38        self.as_bytes()
39    }
40}
41
42impl PartialOrd for PublicKey {
43    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
44        Some(self.cmp(other))
45    }
46}
47
48impl Ord for PublicKey {
49    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
50        self.0.as_bytes().cmp(other.0.as_bytes())
51    }
52}
53
54/// The identifier for a node in the (iroh) network.
55///
56/// Each node in iroh has a unique identifier created as a cryptographic key.  This can be
57/// used to globally identify a node.  Since it is also a cryptographic key it is also the
58/// mechanism by which all traffic is always encrypted for a specific node only.
59///
60/// This is equivalent to [`PublicKey`].  By convention we will (or should) use `PublicKey`
61/// as type name when performing cryptographic operations, but use `NodeId` when referencing
62/// a node.  E.g.:
63///
64/// - `encrypt(key: PublicKey)`
65/// - `send_to(node: NodeId)`
66pub type NodeId = PublicKey;
67
68impl Hash for PublicKey {
69    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
70        self.0.hash(state);
71    }
72}
73
74impl Serialize for PublicKey {
75    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
76    where
77        S: serde::Serializer,
78    {
79        if serializer.is_human_readable() {
80            serializer.serialize_str(&self.to_string())
81        } else {
82            self.0.as_bytes().serialize(serializer)
83        }
84    }
85}
86
87impl<'de> Deserialize<'de> for PublicKey {
88    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89    where
90        D: serde::Deserializer<'de>,
91    {
92        if deserializer.is_human_readable() {
93            let s = String::deserialize(deserializer)?;
94            Self::from_str(&s).map_err(serde::de::Error::custom)
95        } else {
96            let data: [u8; 32] = serde::Deserialize::deserialize(deserializer)?;
97            Self::try_from(data.as_ref()).map_err(serde::de::Error::custom)
98        }
99    }
100}
101
102impl PublicKey {
103    /// Get this public key as a byte array.
104    pub fn as_bytes(&self) -> &[u8; 32] {
105        self.0.as_bytes()
106    }
107
108    /// Returns the [`VerifyingKey`] for this `PublicKey`.
109    pub fn public(&self) -> VerifyingKey {
110        VerifyingKey::from_bytes(self.0.as_bytes()).expect("already verified")
111    }
112
113    /// Construct a `PublicKey` from a slice of bytes.
114    ///
115    /// # Warning
116    ///
117    /// This will return a [`SignatureError`] if the bytes passed into this method do not represent
118    /// a valid `ed25519_dalek` curve point. Will never fail for bytes return from [`Self::as_bytes`].
119    /// See [`VerifyingKey::from_bytes`] for details.
120    pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, SignatureError> {
121        let key = VerifyingKey::from_bytes(bytes)?;
122        let y = CompressedEdwardsY(key.to_bytes());
123        Ok(Self(y))
124    }
125
126    /// Verify a signature on a message with this secret key's public key.
127    ///
128    /// # Return
129    ///
130    /// Returns `Ok(())` if the signature is valid, and `Err` otherwise.
131    pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
132        self.public().verify_strict(message, signature)
133    }
134
135    /// Convert to a hex string limited to the first 5 bytes for a friendly string
136    /// representation of the key.
137    pub fn fmt_short(&self) -> impl Display + 'static {
138        PublicKeyShort(
139            self.0.as_bytes()[0..5]
140                .try_into()
141                .expect("slice with incorrect length"),
142        )
143    }
144
145    /// The length of an ed25519 `PublicKey`, in bytes.
146    pub const LENGTH: usize = ed25519_dalek::PUBLIC_KEY_LENGTH;
147}
148
149struct PublicKeyShort([u8; 5]);
150
151impl Display for PublicKeyShort {
152    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153        data_encoding::HEXLOWER.encode_write(&self.0, f)
154    }
155}
156
157impl TryFrom<&[u8]> for PublicKey {
158    type Error = SignatureError;
159
160    #[inline]
161    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
162        let vk = VerifyingKey::try_from(bytes)?;
163        Ok(Self(CompressedEdwardsY(vk.to_bytes())))
164    }
165}
166
167impl TryFrom<&[u8; 32]> for PublicKey {
168    type Error = SignatureError;
169
170    #[inline]
171    fn try_from(bytes: &[u8; 32]) -> Result<Self, Self::Error> {
172        Self::from_bytes(bytes)
173    }
174}
175
176impl AsRef<[u8]> for PublicKey {
177    fn as_ref(&self) -> &[u8] {
178        self.as_bytes()
179    }
180}
181
182impl From<VerifyingKey> for PublicKey {
183    fn from(verifying_key: VerifyingKey) -> Self {
184        let key = verifying_key.to_bytes();
185        PublicKey(CompressedEdwardsY(key))
186    }
187}
188
189impl Debug for PublicKey {
190    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
191        write!(
192            f,
193            "PublicKey({})",
194            data_encoding::HEXLOWER.encode(self.as_bytes())
195        )
196    }
197}
198
199impl Display for PublicKey {
200    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201        write!(f, "{}", data_encoding::HEXLOWER.encode(self.as_bytes()))
202    }
203}
204
205/// Error when deserialising a [`PublicKey`] or a [`SecretKey`].
206#[common_fields({
207    backtrace: Option<Backtrace>,
208    #[snafu(implicit)]
209    span_trace: n0_snafu::SpanTrace,
210})]
211#[derive(Snafu, Debug)]
212#[allow(missing_docs)]
213#[snafu(visibility(pub(crate)))]
214pub enum KeyParsingError {
215    /// Error when decoding.
216    #[snafu(transparent)]
217    Decode { source: data_encoding::DecodeError },
218    /// Error when decoding the public key.
219    #[snafu(transparent)]
220    Key {
221        source: ed25519_dalek::SignatureError,
222    },
223    /// The encoded information had the wrong length.
224    #[snafu(display("invalid length"))]
225    DecodeInvalidLength {},
226}
227
228/// Deserialises the [`PublicKey`] from it's base32 encoding.
229///
230/// [`Display`] is capable of serialising this format.
231impl FromStr for PublicKey {
232    type Err = KeyParsingError;
233
234    fn from_str(s: &str) -> Result<Self, Self::Err> {
235        let bytes = decode_base32_hex(s)?;
236
237        Ok(Self::from_bytes(&bytes)?)
238    }
239}
240
241/// A secret key.
242#[derive(Clone)]
243pub struct SecretKey {
244    secret: SigningKey,
245}
246
247impl Debug for SecretKey {
248    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249        write!(f, "SecretKey(..)")
250    }
251}
252
253impl FromStr for SecretKey {
254    type Err = KeyParsingError;
255
256    fn from_str(s: &str) -> Result<Self, Self::Err> {
257        let bytes = decode_base32_hex(s)?;
258        Ok(SecretKey::from(bytes))
259    }
260}
261
262impl Serialize for SecretKey {
263    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
264    where
265        S: serde::Serializer,
266    {
267        self.secret.serialize(serializer)
268    }
269}
270
271impl<'de> Deserialize<'de> for SecretKey {
272    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
273    where
274        D: serde::Deserializer<'de>,
275    {
276        let secret = SigningKey::deserialize(deserializer)?;
277        Ok(secret.into())
278    }
279}
280
281impl SecretKey {
282    /// The public key of this [`SecretKey`].
283    pub fn public(&self) -> PublicKey {
284        self.secret.verifying_key().into()
285    }
286
287    /// Generate a new [`SecretKey`] with a randomness generator.
288    ///
289    /// ```rust
290    /// // use the OsRng option for OS depedndent most secure RNG.
291    /// let mut rng = rand::rngs::OsRng;
292    /// let _key = iroh_base::SecretKey::generate(&mut rng);
293    /// ```
294    pub fn generate<R: CryptoRngCore>(mut csprng: R) -> Self {
295        let secret = SigningKey::generate(&mut csprng);
296
297        Self { secret }
298    }
299
300    /// Sign the given message and return a digital signature
301    pub fn sign(&self, msg: &[u8]) -> Signature {
302        use ed25519_dalek::Signer;
303
304        self.secret.sign(msg)
305    }
306
307    /// Convert this to the bytes representing the secret part.
308    /// The public part can always be recovered.
309    pub fn to_bytes(&self) -> [u8; 32] {
310        self.secret.to_bytes()
311    }
312
313    /// Create a secret key from its byte representation.
314    pub fn from_bytes(bytes: &[u8; 32]) -> Self {
315        let secret = SigningKey::from_bytes(bytes);
316        secret.into()
317    }
318
319    /// Returns the [`SigningKey`] for this `SecretKey`.
320    pub fn secret(&self) -> &SigningKey {
321        &self.secret
322    }
323}
324
325impl From<SigningKey> for SecretKey {
326    fn from(secret: SigningKey) -> Self {
327        SecretKey { secret }
328    }
329}
330
331impl From<[u8; 32]> for SecretKey {
332    fn from(value: [u8; 32]) -> Self {
333        Self::from_bytes(&value)
334    }
335}
336
337impl TryFrom<&[u8]> for SecretKey {
338    type Error = SignatureError;
339
340    #[inline]
341    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
342        let secret = SigningKey::try_from(bytes)?;
343        Ok(secret.into())
344    }
345}
346
347fn decode_base32_hex(s: &str) -> Result<[u8; 32], KeyParsingError> {
348    let mut bytes = [0u8; 32];
349
350    let res = if s.len() == PublicKey::LENGTH * 2 {
351        // hex
352        data_encoding::HEXLOWER.decode_mut(s.as_bytes(), &mut bytes)
353    } else {
354        let input = s.to_ascii_uppercase();
355        let input = input.as_bytes();
356        if data_encoding::BASE32_NOPAD.decode_len(input.len())? != bytes.len() {
357            return Err(DecodeInvalidLengthSnafu.build());
358        }
359        data_encoding::BASE32_NOPAD.decode_mut(input, &mut bytes)
360    };
361    match res {
362        Ok(len) => {
363            if len != PublicKey::LENGTH {
364                return Err(DecodeInvalidLengthSnafu.build());
365            }
366        }
367        Err(partial) => return Err(partial.error.into()),
368    }
369    Ok(bytes)
370}
371
372#[cfg(test)]
373mod tests {
374    use data_encoding::HEXLOWER;
375
376    use super::*;
377
378    #[test]
379    fn test_public_key_postcard() {
380        let public_key =
381            PublicKey::from_str("ae58ff8833241ac82d6ff7611046ed67b5072d142c588d0063e942d9a75502b6")
382                .unwrap();
383        let bytes = postcard::to_stdvec(&public_key).unwrap();
384        let expected = HEXLOWER
385            .decode(b"ae58ff8833241ac82d6ff7611046ed67b5072d142c588d0063e942d9a75502b6")
386            .unwrap();
387        assert_eq!(bytes, expected);
388    }
389
390    #[test]
391    fn public_key_postcard() {
392        let key = PublicKey::from_bytes(&[0; 32]).unwrap();
393        let bytes = postcard::to_stdvec(&key).unwrap();
394        let key2: PublicKey = postcard::from_bytes(&bytes).unwrap();
395        assert_eq!(key, key2);
396    }
397
398    #[test]
399    fn public_key_json() {
400        let key = PublicKey::from_bytes(&[0; 32]).unwrap();
401        let bytes = serde_json::to_string(&key).unwrap();
402        let key2: PublicKey = serde_json::from_str(&bytes).unwrap();
403        assert_eq!(key, key2);
404    }
405
406    #[test]
407    fn test_from_str() {
408        let key = SecretKey::generate(&mut rand::thread_rng());
409        assert_eq!(
410            SecretKey::from_str(&HEXLOWER.encode(&key.to_bytes()))
411                .unwrap()
412                .to_bytes(),
413            key.to_bytes()
414        );
415
416        assert_eq!(
417            PublicKey::from_str(&key.public().to_string()).unwrap(),
418            key.public()
419        );
420    }
421
422    #[test]
423    fn test_regression_parse_node_id_panic() {
424        let not_a_node_id = "foobarbaz";
425        assert!(PublicKey::from_str(not_a_node_id).is_err());
426    }
427}