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, SignatureError};
13use ed25519_dalek::{SigningKey, VerifyingKey};
14use nested_enum_utils::common_fields;
15use rand_core::CryptoRngCore;
16use serde::{Deserialize, Serialize};
17use snafu::{Backtrace, Snafu};
18
19/// A public key.
20///
21/// The key itself is stored as the `CompressedEdwards` y coordinate of the public key
22/// It is verified to decompress into a valid key when created.
23#[derive(Clone, Copy, PartialEq, Eq)]
24#[repr(transparent)]
25pub struct PublicKey(CompressedEdwardsY);
26
27impl Borrow<[u8; 32]> for PublicKey {
28    fn borrow(&self) -> &[u8; 32] {
29        self.as_bytes()
30    }
31}
32
33impl PartialOrd for PublicKey {
34    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
35        Some(self.cmp(other))
36    }
37}
38
39impl Ord for PublicKey {
40    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
41        self.0.as_bytes().cmp(other.0.as_bytes())
42    }
43}
44
45/// The identifier for a node in the (iroh) network.
46///
47/// Each node in iroh has a unique identifier created as a cryptographic key.  This can be
48/// used to globally identify a node.  Since it is also a cryptographic key it is also the
49/// mechanism by which all traffic is always encrypted for a specific node only.
50///
51/// This is equivalent to [`PublicKey`].  By convention we will (or should) use `PublicKey`
52/// as type name when performing cryptographic operations, but use `NodeId` when referencing
53/// a node.  E.g.:
54///
55/// - `encrypt(key: PublicKey)`
56/// - `send_to(node: NodeId)`
57pub type NodeId = PublicKey;
58
59impl Hash for PublicKey {
60    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
61        self.0.hash(state);
62    }
63}
64
65impl Serialize for PublicKey {
66    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
67    where
68        S: serde::Serializer,
69    {
70        if serializer.is_human_readable() {
71            serializer.serialize_str(&self.to_string())
72        } else {
73            self.0.as_bytes().serialize(serializer)
74        }
75    }
76}
77
78impl<'de> Deserialize<'de> for PublicKey {
79    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
80    where
81        D: serde::Deserializer<'de>,
82    {
83        if deserializer.is_human_readable() {
84            let s = String::deserialize(deserializer)?;
85            Self::from_str(&s).map_err(serde::de::Error::custom)
86        } else {
87            let data: [u8; 32] = serde::Deserialize::deserialize(deserializer)?;
88            Self::try_from(data.as_ref()).map_err(serde::de::Error::custom)
89        }
90    }
91}
92
93impl PublicKey {
94    /// Get this public key as a byte array.
95    pub fn as_bytes(&self) -> &[u8; 32] {
96        self.0.as_bytes()
97    }
98
99    /// Returns the [`VerifyingKey`] for this `PublicKey`.
100    pub fn public(&self) -> VerifyingKey {
101        VerifyingKey::from_bytes(self.0.as_bytes()).expect("already verified")
102    }
103
104    /// Construct a `PublicKey` from a slice of bytes.
105    ///
106    /// # Warning
107    ///
108    /// This will return a [`SignatureError`] if the bytes passed into this method do not represent
109    /// a valid `ed25519_dalek` curve point. Will never fail for bytes return from [`Self::as_bytes`].
110    /// See [`VerifyingKey::from_bytes`] for details.
111    pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, SignatureError> {
112        let key = VerifyingKey::from_bytes(bytes)?;
113        let y = CompressedEdwardsY(key.to_bytes());
114        Ok(Self(y))
115    }
116
117    /// Verify a signature on a message with this secret key's public key.
118    ///
119    /// # Return
120    ///
121    /// Returns `Ok(())` if the signature is valid, and `Err` otherwise.
122    pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> {
123        self.public().verify_strict(message, signature)
124    }
125
126    /// Convert to a hex string limited to the first 5 bytes for a friendly string
127    /// representation of the key.
128    pub fn fmt_short(&self) -> String {
129        data_encoding::HEXLOWER.encode(&self.as_bytes()[..5])
130    }
131
132    /// The length of an ed25519 `PublicKey`, in bytes.
133    pub const LENGTH: usize = ed25519_dalek::PUBLIC_KEY_LENGTH;
134}
135
136impl TryFrom<&[u8]> for PublicKey {
137    type Error = SignatureError;
138
139    #[inline]
140    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
141        let vk = VerifyingKey::try_from(bytes)?;
142        Ok(Self(CompressedEdwardsY(vk.to_bytes())))
143    }
144}
145
146impl TryFrom<&[u8; 32]> for PublicKey {
147    type Error = SignatureError;
148
149    #[inline]
150    fn try_from(bytes: &[u8; 32]) -> Result<Self, Self::Error> {
151        Self::from_bytes(bytes)
152    }
153}
154
155impl AsRef<[u8]> for PublicKey {
156    fn as_ref(&self) -> &[u8] {
157        self.as_bytes()
158    }
159}
160
161impl From<VerifyingKey> for PublicKey {
162    fn from(verifying_key: VerifyingKey) -> Self {
163        let key = verifying_key.to_bytes();
164        PublicKey(CompressedEdwardsY(key))
165    }
166}
167
168impl Debug for PublicKey {
169    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170        write!(
171            f,
172            "PublicKey({})",
173            data_encoding::HEXLOWER.encode(self.as_bytes())
174        )
175    }
176}
177
178impl Display for PublicKey {
179    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180        write!(f, "{}", data_encoding::HEXLOWER.encode(self.as_bytes()))
181    }
182}
183
184/// Error when deserialising a [`PublicKey`] or a [`SecretKey`].
185#[common_fields({
186    backtrace: Option<Backtrace>,
187    #[snafu(implicit)]
188    span_trace: n0_snafu::SpanTrace,
189})]
190#[derive(Snafu, Debug)]
191#[allow(missing_docs)]
192#[snafu(visibility(pub(crate)))]
193pub enum KeyParsingError {
194    /// Error when decoding.
195    #[snafu(transparent)]
196    Decode { source: data_encoding::DecodeError },
197    /// Error when decoding the public key.
198    #[snafu(transparent)]
199    Key {
200        source: ed25519_dalek::SignatureError,
201    },
202    /// The encoded information had the wrong length.
203    #[snafu(display("invalid length"))]
204    DecodeInvalidLength {},
205}
206
207/// Deserialises the [`PublicKey`] from it's base32 encoding.
208///
209/// [`Display`] is capable of serialising this format.
210impl FromStr for PublicKey {
211    type Err = KeyParsingError;
212
213    fn from_str(s: &str) -> Result<Self, Self::Err> {
214        let bytes = decode_base32_hex(s)?;
215
216        Ok(Self::from_bytes(&bytes)?)
217    }
218}
219
220/// A secret key.
221#[derive(Clone)]
222pub struct SecretKey {
223    secret: SigningKey,
224}
225
226impl Debug for SecretKey {
227    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228        write!(f, "SecretKey(..)")
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(DecodeInvalidLengthSnafu.build());
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(DecodeInvalidLengthSnafu.build());
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_from_str() {
387        let key = SecretKey::generate(&mut rand::thread_rng());
388        assert_eq!(
389            SecretKey::from_str(&HEXLOWER.encode(&key.to_bytes()))
390                .unwrap()
391                .to_bytes(),
392            key.to_bytes()
393        );
394
395        assert_eq!(
396            PublicKey::from_str(&key.public().to_string()).unwrap(),
397            key.public()
398        );
399    }
400
401    #[test]
402    fn test_regression_parse_node_id_panic() {
403        let not_a_node_id = "foobarbaz";
404        assert!(PublicKey::from_str(not_a_node_id).is_err());
405    }
406}