litep2p/crypto/
ed25519.rs

1// Copyright 2019 Parity Technologies (UK) Ltd.
2// Copyright 2023 litep2p developers
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22//! Ed25519 keys.
23
24use crate::{
25    error::{Error, ParseError},
26    PeerId,
27};
28
29use ed25519_dalek::{self as ed25519, Signer as _, Verifier as _};
30use std::fmt;
31use zeroize::Zeroize;
32
33/// An Ed25519 keypair.
34#[derive(Clone)]
35pub struct Keypair(ed25519::SigningKey);
36
37impl Keypair {
38    /// Generate a new random Ed25519 keypair.
39    pub fn generate() -> Keypair {
40        Keypair::from(SecretKey::generate())
41    }
42
43    /// Convert the keypair into a byte array by concatenating the bytes
44    /// of the secret scalar and the compressed public point,
45    /// an informal standard for encoding Ed25519 keypairs.
46    pub fn to_bytes(&self) -> [u8; 64] {
47        self.0.to_keypair_bytes()
48    }
49
50    /// Try to parse a keypair from the [binary format](https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.5)
51    /// produced by [`Keypair::to_bytes`], zeroing the input on success.
52    ///
53    /// Note that this binary format is the same as `ed25519_dalek`'s and `ed25519_zebra`'s.
54    pub fn try_from_bytes(kp: &mut [u8]) -> Result<Keypair, Error> {
55        let bytes = <[u8; 64]>::try_from(&*kp)
56            .map_err(|e| Error::Other(format!("Failed to parse ed25519 keypair: {e}")))?;
57
58        ed25519::SigningKey::from_keypair_bytes(&bytes)
59            .map(|k| {
60                kp.zeroize();
61                Keypair(k)
62            })
63            .map_err(|e| Error::Other(format!("Failed to parse ed25519 keypair: {e}")))
64    }
65
66    /// Sign a message using the private key of this keypair.
67    pub fn sign(&self, msg: &[u8]) -> Vec<u8> {
68        self.0.sign(msg).to_bytes().to_vec()
69    }
70
71    /// Get the public key of this keypair.
72    pub fn public(&self) -> PublicKey {
73        PublicKey(self.0.verifying_key())
74    }
75
76    /// Get the secret key of this keypair.
77    pub fn secret(&self) -> SecretKey {
78        SecretKey(self.0.to_bytes())
79    }
80}
81
82impl fmt::Debug for Keypair {
83    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84        f.debug_struct("Keypair").field("public", &self.0.verifying_key()).finish()
85    }
86}
87
88/// Demote an Ed25519 keypair to a secret key.
89impl From<Keypair> for SecretKey {
90    fn from(kp: Keypair) -> SecretKey {
91        SecretKey(kp.0.to_bytes())
92    }
93}
94
95/// Promote an Ed25519 secret key into a keypair.
96impl From<SecretKey> for Keypair {
97    fn from(sk: SecretKey) -> Keypair {
98        let signing = ed25519::SigningKey::from_bytes(&sk.0);
99        Keypair(signing)
100    }
101}
102
103/// An Ed25519 public key.
104#[derive(Eq, Clone)]
105pub struct PublicKey(ed25519::VerifyingKey);
106
107impl fmt::Debug for PublicKey {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        f.write_str("PublicKey(compressed): ")?;
110        for byte in self.0.as_bytes() {
111            write!(f, "{byte:x}")?;
112        }
113        Ok(())
114    }
115}
116
117impl PartialEq for PublicKey {
118    fn eq(&self, other: &Self) -> bool {
119        self.0.as_bytes().eq(other.0.as_bytes())
120    }
121}
122
123impl PublicKey {
124    /// Verify the Ed25519 signature on a message using the public key.
125    pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool {
126        ed25519::Signature::try_from(sig).and_then(|s| self.0.verify(msg, &s)).is_ok()
127    }
128
129    /// Convert the public key to a byte array in compressed form, i.e.
130    /// where one coordinate is represented by a single bit.
131    pub fn to_bytes(&self) -> [u8; 32] {
132        self.0.to_bytes()
133    }
134
135    /// Get the public key as a byte slice.
136    pub fn as_bytes(&self) -> &[u8] {
137        self.0.as_bytes()
138    }
139
140    /// Try to parse a public key from a byte array containing the actual key as produced by
141    /// `to_bytes`.
142    pub fn try_from_bytes(k: &[u8]) -> Result<PublicKey, ParseError> {
143        let k = <[u8; 32]>::try_from(k).map_err(|_| ParseError::InvalidPublicKey)?;
144
145        // The error type of the verifying key is deliberately opaque as to avoid side-channel
146        // leakage. We can't provide a more specific error type here.
147        ed25519::VerifyingKey::from_bytes(&k)
148            .map_err(|_| ParseError::InvalidPublicKey)
149            .map(PublicKey)
150    }
151
152    /// Convert public key to `PeerId`.
153    pub fn to_peer_id(&self) -> PeerId {
154        crate::crypto::PublicKey::Ed25519(self.clone()).into()
155    }
156}
157
158/// An Ed25519 secret key.
159#[derive(Clone)]
160pub struct SecretKey(ed25519::SecretKey);
161
162/// View the bytes of the secret key.
163impl AsRef<[u8]> for SecretKey {
164    fn as_ref(&self) -> &[u8] {
165        &self.0[..]
166    }
167}
168
169impl fmt::Debug for SecretKey {
170    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171        write!(f, "SecretKey")
172    }
173}
174
175impl SecretKey {
176    /// Generate a new Ed25519 secret key.
177    pub fn generate() -> SecretKey {
178        let signing = ed25519::SigningKey::generate(&mut rand::rngs::OsRng);
179        SecretKey(signing.to_bytes())
180    }
181    /// Try to parse an Ed25519 secret key from a byte slice
182    /// containing the actual key, zeroing the input on success.
183    /// If the bytes do not constitute a valid Ed25519 secret key, an error is
184    /// returned.
185    pub fn try_from_bytes(mut sk_bytes: impl AsMut<[u8]>) -> crate::Result<SecretKey> {
186        let sk_bytes = sk_bytes.as_mut();
187        let secret = <[u8; 32]>::try_from(&*sk_bytes)
188            .map_err(|e| Error::Other(format!("Failed to parse ed25519 secret key: {e}")))?;
189        sk_bytes.zeroize();
190        Ok(SecretKey(secret))
191    }
192
193    /// Convert this secret key to a byte array.
194    pub fn to_bytes(&self) -> [u8; 32] {
195        self.0
196    }
197}
198
199#[cfg(test)]
200mod tests {
201    use super::*;
202    use quickcheck::*;
203
204    fn eq_keypairs(kp1: &Keypair, kp2: &Keypair) -> bool {
205        kp1.public() == kp2.public() && kp1.0.to_bytes() == kp2.0.to_bytes()
206    }
207
208    #[test]
209    fn ed25519_keypair_encode_decode() {
210        fn prop() -> bool {
211            let kp1 = Keypair::generate();
212            let mut kp1_enc = kp1.to_bytes();
213            let kp2 = Keypair::try_from_bytes(&mut kp1_enc).unwrap();
214            eq_keypairs(&kp1, &kp2) && kp1_enc.iter().all(|b| *b == 0)
215        }
216        QuickCheck::new().tests(10).quickcheck(prop as fn() -> _);
217    }
218
219    #[test]
220    fn ed25519_keypair_from_secret() {
221        fn prop() -> bool {
222            let kp1 = Keypair::generate();
223            let mut sk = kp1.0.to_bytes();
224            let kp2 = Keypair::from(SecretKey::try_from_bytes(&mut sk).unwrap());
225            eq_keypairs(&kp1, &kp2) && sk == [0u8; 32]
226        }
227        QuickCheck::new().tests(10).quickcheck(prop as fn() -> _);
228    }
229
230    #[test]
231    fn ed25519_signature() {
232        let kp = Keypair::generate();
233        let pk = kp.public();
234
235        let msg = "hello world".as_bytes();
236        let sig = kp.sign(msg);
237        assert!(pk.verify(msg, &sig));
238
239        let mut invalid_sig = sig.clone();
240        invalid_sig[3..6].copy_from_slice(&[10, 23, 42]);
241        assert!(!pk.verify(msg, &invalid_sig));
242
243        let invalid_msg = "h3ll0 w0rld".as_bytes();
244        assert!(!pk.verify(invalid_msg, &sig));
245    }
246
247    #[test]
248    fn secret_key() {
249        let _ = tracing_subscriber::fmt()
250            .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
251            .try_init();
252
253        let key = Keypair::generate();
254        tracing::trace!("keypair: {:?}", key);
255        tracing::trace!("secret: {:?}", key.secret());
256        tracing::trace!("public: {:?}", key.public());
257
258        let new_key = Keypair::from(key.secret());
259        assert_eq!(new_key.secret().as_ref(), key.secret().as_ref());
260        assert_eq!(new_key.public(), key.public());
261
262        let new_secret = SecretKey::from(new_key.clone());
263        assert_eq!(new_secret.as_ref(), new_key.secret().as_ref());
264
265        let cloned_secret = new_secret.clone();
266        assert_eq!(cloned_secret.as_ref(), new_secret.as_ref());
267    }
268}