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