iroh_base/
key.rs

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