fluence_keypair/
key_pair.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//! A node's network identity keys.
22use crate::ed25519;
23use crate::error::{DecodingError, Error, SigningError, VerificationError};
24use crate::public_key::PublicKey;
25#[cfg(not(target_arch = "wasm32"))]
26use crate::rsa;
27use crate::secp256k1;
28use crate::signature::Signature;
29use libp2p_identity::{KeyType, Keypair, PeerId};
30use std::convert::TryFrom;
31use std::str::FromStr;
32
33/// Identity keypair of a node.
34///
35/// # Example: Generating RSA keys with OpenSSL
36///
37/// ```text
38/// openssl genrsa -out private.pem 2048
39/// openssl pkcs8 -in private.pem -inform PEM -topk8 -out private.pk8 -outform DER -nocrypt
40/// rm private.pem      # optional
41/// ```
42///
43/// Loading the keys:
44///
45/// ```text
46/// let mut bytes = std::fs::read("private.pk8").unwrap();
47/// let keypair = Keypair::rsa_from_pkcs8(&mut bytes);
48/// ```
49///
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub enum KeyFormat {
52    Ed25519,
53    #[cfg(not(target_arch = "wasm32"))]
54    Rsa,
55    Secp256k1,
56}
57
58impl FromStr for KeyFormat {
59    type Err = Error;
60
61    #[inline]
62    fn from_str(s: &str) -> Result<Self, Self::Err> {
63        match s {
64            "ed25519" => Ok(KeyFormat::Ed25519),
65            "secp256k1" => Ok(KeyFormat::Secp256k1),
66            #[cfg(not(target_arch = "wasm32"))]
67            "rsa" => Ok(KeyFormat::Rsa),
68            _ => Err(Error::InvalidKeyFormat(s.to_string())),
69        }
70    }
71}
72
73impl TryFrom<u8> for KeyFormat {
74    type Error = DecodingError;
75
76    fn try_from(value: u8) -> Result<Self, Self::Error> {
77        match value {
78            0 => Ok(KeyFormat::Ed25519),
79            #[cfg(not(target_arch = "wasm32"))]
80            1 => Ok(KeyFormat::Rsa),
81            2 => Ok(KeyFormat::Secp256k1),
82            _ => Err(DecodingError::InvalidTypeByte),
83        }
84    }
85}
86
87impl From<KeyFormat> for u8 {
88    fn from(kf: KeyFormat) -> Self {
89        match kf {
90            KeyFormat::Ed25519 => 0,
91            #[cfg(not(target_arch = "wasm32"))]
92            KeyFormat::Rsa => 1,
93            KeyFormat::Secp256k1 => 2,
94        }
95    }
96}
97
98impl From<KeyFormat> for String {
99    fn from(kf: KeyFormat) -> Self {
100        match kf {
101            KeyFormat::Ed25519 => "ed25519".to_string(),
102            #[cfg(not(target_arch = "wasm32"))]
103            KeyFormat::Rsa => "rsa".to_string(),
104            KeyFormat::Secp256k1 => "secp256k1".to_string(),
105        }
106    }
107}
108
109#[derive(Clone)]
110pub enum KeyPair {
111    /// An Ed25519 keypair.
112    Ed25519(ed25519::Keypair),
113    #[cfg(not(target_arch = "wasm32"))]
114    /// An RSA keypair.
115    Rsa(rsa::Keypair),
116    /// A Secp256k1 keypair.
117    Secp256k1(secp256k1::Keypair),
118}
119
120impl KeyPair {
121    pub fn generate(format: KeyFormat) -> KeyPair {
122        match format {
123            KeyFormat::Ed25519 => KeyPair::generate_ed25519(),
124            KeyFormat::Secp256k1 => KeyPair::generate_secp256k1(),
125            #[cfg(not(target_arch = "wasm32"))]
126            KeyFormat::Rsa => todo!("rsa generation is not supported yet!"),
127        }
128    }
129
130    /// Generate a new Ed25519 keypair.
131    pub fn generate_ed25519() -> KeyPair {
132        KeyPair::Ed25519(ed25519::Keypair::generate())
133    }
134
135    /// Generate a new Secp256k1 keypair.
136    pub fn generate_secp256k1() -> KeyPair {
137        KeyPair::Secp256k1(secp256k1::Keypair::generate())
138    }
139
140    /// Decode an keypair from a DER-encoded secret key in PKCS#8 PrivateKeyInfo
141    /// format (i.e. unencrypted) as defined in [RFC5208].
142    ///
143    /// [RFC5208]: https://tools.ietf.org/html/rfc5208#section-5
144    #[cfg(not(target_arch = "wasm32"))]
145    pub fn rsa_from_pkcs8(pkcs8_der: &mut [u8]) -> Result<KeyPair, DecodingError> {
146        rsa::Keypair::from_pkcs8(pkcs8_der).map(KeyPair::Rsa)
147    }
148
149    /// Decode a keypair from a DER-encoded Secp256k1 secret key in an ECPrivateKey
150    /// structure as defined in [RFC5915].
151    ///
152    /// [RFC5915]: https://tools.ietf.org/html/rfc5915
153    pub fn secp256k1_from_der(der: &mut [u8]) -> Result<KeyPair, DecodingError> {
154        secp256k1::SecretKey::from_der(der)
155            .map(|sk| KeyPair::Secp256k1(secp256k1::Keypair::from(sk)))
156    }
157
158    /// Sign a message using the private key of this keypair, producing
159    /// a signature that can be verified using the corresponding public key.
160    pub fn sign(&self, msg: &[u8]) -> Result<Signature, SigningError> {
161        use KeyPair::*;
162        match self {
163            Ed25519(ref pair) => Ok(Signature::Ed25519(ed25519::Signature(pair.sign(msg)?))),
164            #[cfg(not(target_arch = "wasm32"))]
165            Rsa(ref pair) => Ok(Signature::Rsa(rsa::Signature(pair.sign(msg)?))),
166            Secp256k1(ref pair) => Ok(Signature::Secp256k1(secp256k1::Signature(
167                pair.secret().sign(msg)?,
168            ))),
169        }
170    }
171
172    /// Get the key format of this keypair.
173    pub fn key_format(&self) -> KeyFormat {
174        use KeyPair::*;
175
176        match self {
177            Ed25519(_) => KeyFormat::Ed25519,
178            #[cfg(not(target_arch = "wasm32"))]
179            Rsa(_) => KeyFormat::Rsa,
180            Secp256k1(_) => KeyFormat::Secp256k1,
181        }
182    }
183
184    /// Get the public key of this keypair.
185    pub fn public(&self) -> PublicKey {
186        use KeyPair::*;
187        match self {
188            Ed25519(pair) => PublicKey::Ed25519(pair.public()),
189            #[cfg(not(target_arch = "wasm32"))]
190            Rsa(pair) => PublicKey::Rsa(pair.public()),
191            Secp256k1(pair) => PublicKey::Secp256k1(pair.public().clone()),
192        }
193    }
194
195    pub fn secret(&self) -> eyre::Result<Vec<u8>> {
196        use KeyPair::*;
197        match self {
198            Ed25519(pair) => Ok(pair.secret().0.to_vec()),
199            #[cfg(not(target_arch = "wasm32"))]
200            Rsa(_) => Err(eyre::eyre!("secret key is not available for RSA")),
201            Secp256k1(pair) => Ok(pair.secret().to_bytes().to_vec()),
202        }
203    }
204
205    /// Verify the signature on a message using the public key.
206    pub fn verify(
207        pk: &PublicKey,
208        msg: &[u8],
209        signature: &Signature,
210    ) -> Result<(), VerificationError> {
211        pk.verify(msg, signature)
212    }
213
214    pub fn to_vec(&self) -> Vec<u8> {
215        use KeyPair::*;
216        match self {
217            Ed25519(kp) => kp.encode().to_vec(),
218            #[cfg(not(target_arch = "wasm32"))]
219            Rsa(_) => todo!("rsa encoding is not supported yet!"),
220            Secp256k1(kp) => kp.secret().to_bytes().to_vec(),
221        }
222    }
223
224    pub fn from_vec(mut bytes: Vec<u8>, format: KeyFormat) -> Result<Self, DecodingError> {
225        use KeyPair::*;
226
227        match format {
228            KeyFormat::Ed25519 => Ok(Ed25519(ed25519::Keypair::decode(&mut bytes)?)),
229            KeyFormat::Secp256k1 => Ok(Secp256k1(secp256k1::SecretKey::from_bytes(bytes)?.into())),
230            #[cfg(not(target_arch = "wasm32"))]
231            KeyFormat::Rsa => Err(DecodingError::KeypairDecodingIsNotSupported),
232        }
233    }
234
235    pub fn from_secret_key(bytes: Vec<u8>, format: KeyFormat) -> Result<Self, DecodingError> {
236        use KeyPair::*;
237
238        match format {
239            KeyFormat::Ed25519 => Ok(Ed25519(ed25519::SecretKey::from_bytes(bytes)?.into())),
240            KeyFormat::Secp256k1 => Ok(Secp256k1(secp256k1::SecretKey::from_bytes(bytes)?.into())),
241            #[cfg(not(target_arch = "wasm32"))]
242            KeyFormat::Rsa => Err(DecodingError::KeypairDecodingIsNotSupported),
243        }
244    }
245
246    pub fn get_peer_id(&self) -> PeerId {
247        self.public().to_peer_id()
248    }
249}
250
251impl From<libp2p_identity::Keypair> for KeyPair {
252    fn from(key: libp2p_identity::Keypair) -> Self {
253        fn convert_keypair(key: Keypair) -> eyre::Result<KeyPair> {
254            match key.key_type() {
255                KeyType::Ed25519 => {
256                    let kp = key.try_into_ed25519()?;
257                    let raw_kp = ed25519::Keypair::decode(&mut kp.to_bytes())?;
258                    Ok(KeyPair::Ed25519(raw_kp))
259                }
260                #[cfg(not(target_arch = "wasm32"))]
261                KeyType::RSA => {
262                    let kp = key.try_into_rsa()?;
263                    let raw_kp = unsafe {
264                        std::mem::transmute::<libp2p_identity::rsa::Keypair, rsa::Keypair>(kp)
265                    };
266                    Ok(KeyPair::Rsa(raw_kp))
267                }
268                KeyType::Secp256k1 => {
269                    let kp = key.try_into_secp256k1()?;
270                    let raw_kp = secp256k1::SecretKey::from_bytes(kp.secret().to_bytes())?;
271                    Ok(KeyPair::Secp256k1(secp256k1::Keypair::from(raw_kp)))
272                }
273                _ => unreachable!(),
274            }
275        }
276
277        convert_keypair(key).expect("Could not convert keypair")
278    }
279}
280
281impl From<KeyPair> for libp2p_identity::Keypair {
282    fn from(key: KeyPair) -> Self {
283        fn convert_keypair(key: KeyPair) -> eyre::Result<libp2p_identity::Keypair> {
284            match key {
285                KeyPair::Ed25519(kp) => {
286                    // for some reason, libp2p takes SecretKey's 32 bytes here instead of Keypair's 64 bytes
287                    let secret_bytes = kp.secret().0;
288                    let kp = libp2p_identity::Keypair::ed25519_from_bytes(secret_bytes)?;
289                    Ok(kp)
290                }
291                #[cfg(not(target_arch = "wasm32"))]
292                // safety: these Keypair structures are identical
293                KeyPair::Rsa(kp) => {
294                    let kp = unsafe {
295                        std::mem::transmute::<rsa::Keypair, libp2p_identity::rsa::Keypair>(kp)
296                    };
297                    let kp = Keypair::from(kp);
298                    Ok(kp)
299                }
300                KeyPair::Secp256k1(kp) => {
301                    let sk = libp2p_identity::secp256k1::SecretKey::try_from_bytes(
302                        kp.secret().to_bytes(),
303                    )?;
304                    let kp = libp2p_identity::secp256k1::Keypair::from(sk);
305                    let kp = Keypair::from(kp);
306                    Ok(kp)
307                }
308            }
309        }
310        convert_keypair(key).expect("Could not convert key pair")
311    }
312}