libp2p_identity/
ed25519.rs

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