fluence_keypair/
public_key.rs

1/*
2 * Copyright 2021 Fluence Labs Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16use crate::ed25519;
17use crate::error::{DecodingError, VerificationError};
18#[cfg(not(target_arch = "wasm32"))]
19use crate::rsa;
20use crate::secp256k1;
21use crate::signature::Signature;
22
23use crate::key_pair::KeyFormat;
24use libp2p_identity::{KeyType, PeerId};
25use serde::{Deserialize, Serialize};
26use std::convert::TryFrom;
27
28/// The public key of a node's identity keypair.
29#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
30pub enum PublicKey {
31    /// A public Ed25519 key.
32    Ed25519(ed25519::PublicKey),
33    #[cfg(not(target_arch = "wasm32"))]
34    /// A public RSA key.
35    Rsa(rsa::PublicKey),
36    /// A public Secp256k1 key.
37    Secp256k1(secp256k1::PublicKey),
38}
39
40impl PublicKey {
41    /// Verify a signature for a message using this public key, i.e. check
42    /// that the signature has been produced by the corresponding
43    /// private key (authenticity), and that the message has not been
44    /// tampered with (integrity).
45    // TODO: add VerificationError
46    pub fn verify(&self, msg: &[u8], sig: &Signature) -> Result<(), VerificationError> {
47        use PublicKey::*;
48        match self {
49            Ed25519(pk) => pk.verify(msg, sig.to_vec()),
50            #[cfg(not(target_arch = "wasm32"))]
51            Rsa(pk) => pk.verify(msg, sig.to_vec()),
52            Secp256k1(pk) => pk.verify(msg, sig.to_vec()),
53        }
54    }
55
56    pub fn encode(&self) -> Vec<u8> {
57        use PublicKey::*;
58        let mut result: Vec<u8> = vec![self.get_prefix()];
59
60        match self {
61            Ed25519(pk) => result.extend(pk.encode().to_vec()),
62            #[cfg(not(target_arch = "wasm32"))]
63            Rsa(pk) => result.extend(pk.to_pkcs1()),
64            Secp256k1(pk) => result.extend(pk.encode().to_vec()),
65        };
66
67        result
68    }
69
70    pub fn decode(bytes: &[u8]) -> Result<PublicKey, DecodingError> {
71        match KeyFormat::try_from(bytes[0])? {
72            KeyFormat::Ed25519 => Ok(PublicKey::Ed25519(ed25519::PublicKey::decode(&bytes[1..])?)),
73            #[cfg(not(target_arch = "wasm32"))]
74            KeyFormat::Rsa => Ok(PublicKey::Rsa(rsa::PublicKey::from_pkcs1(
75                bytes[1..].to_owned(),
76            )?)),
77            KeyFormat::Secp256k1 => Ok(PublicKey::Secp256k1(secp256k1::PublicKey::decode(
78                &bytes[1..],
79            )?)),
80        }
81    }
82
83    fn get_prefix(&self) -> u8 {
84        use PublicKey::*;
85        match self {
86            Ed25519(_) => KeyFormat::Ed25519.into(),
87            #[cfg(not(target_arch = "wasm32"))]
88            Rsa(_) => KeyFormat::Rsa.into(),
89            Secp256k1(_) => KeyFormat::Secp256k1.into(),
90        }
91    }
92
93    pub fn from_base58(str: &str) -> Result<PublicKey, DecodingError> {
94        let bytes = bs58::decode(str)
95            .into_vec()
96            .map_err(DecodingError::Base58DecodeError)?;
97        Self::decode(&bytes)
98    }
99
100    pub fn to_vec(&self) -> Vec<u8> {
101        use PublicKey::*;
102
103        match self {
104            Ed25519(pk) => pk.encode().to_vec(),
105            #[cfg(not(target_arch = "wasm32"))]
106            Rsa(pk) => pk.to_pkcs1().to_vec(),
107            Secp256k1(pk) => pk.encode().to_vec(),
108        }
109    }
110
111    pub fn to_peer_id(&self) -> PeerId {
112        PeerId::from_public_key(&self.clone().into())
113    }
114
115    pub fn get_key_format(&self) -> KeyFormat {
116        use PublicKey::*;
117
118        match self {
119            Ed25519(_) => KeyFormat::Ed25519,
120            #[cfg(not(target_arch = "wasm32"))]
121            Rsa(_) => KeyFormat::Rsa,
122            Secp256k1(_) => KeyFormat::Secp256k1,
123        }
124    }
125}
126
127impl From<libp2p_identity::PublicKey> for PublicKey {
128    fn from(key: libp2p_identity::PublicKey) -> Self {
129        fn convert_key(key: libp2p_identity::PublicKey) -> eyre::Result<PublicKey> {
130            match key.key_type() {
131                KeyType::Ed25519 => {
132                    let pk = key.try_into_ed25519()?;
133                    let raw_pk = ed25519::PublicKey::decode(&pk.to_bytes())?;
134                    Ok(PublicKey::Ed25519(raw_pk))
135                }
136                #[cfg(not(target_arch = "wasm32"))]
137                KeyType::RSA => {
138                    let pk = key.try_into_rsa()?;
139                    let raw_pk = rsa::PublicKey::from_pkcs1(pk.encode_pkcs1())?;
140                    Ok(PublicKey::Rsa(raw_pk))
141                }
142                KeyType::Secp256k1 => {
143                    let pk = key.try_into_secp256k1()?;
144                    let raw_pk = secp256k1::PublicKey::decode(&pk.to_bytes())?;
145                    Ok(PublicKey::Secp256k1(raw_pk))
146                }
147                _ => unreachable!(),
148            }
149        }
150
151        convert_key(key).expect("Could not convert public key")
152    }
153}
154
155impl From<PublicKey> for libp2p_identity::PublicKey {
156    fn from(key: PublicKey) -> Self {
157        fn convert_key(key: PublicKey) -> eyre::Result<libp2p_identity::PublicKey> {
158            match key {
159                PublicKey::Ed25519(key) => {
160                    let raw_pk =
161                        libp2p_identity::ed25519::PublicKey::try_from_bytes(&key.encode())?;
162                    let pk = libp2p_identity::PublicKey::from(raw_pk);
163                    Ok(pk)
164                }
165                #[cfg(not(target_arch = "wasm32"))]
166                PublicKey::Rsa(key) => {
167                    let raw_pk =
168                        libp2p_identity::rsa::PublicKey::try_decode_x509(&key.encode_x509())?;
169                    let pk = libp2p_identity::PublicKey::from(raw_pk);
170                    Ok(pk)
171                }
172                PublicKey::Secp256k1(key) => {
173                    let raw_pk =
174                        libp2p_identity::secp256k1::PublicKey::try_from_bytes(&key.encode())?;
175                    let pk = libp2p_identity::PublicKey::from(raw_pk);
176                    Ok(pk)
177                }
178            }
179        }
180        convert_key(key).expect("Could not convert key")
181    }
182}
183
184impl TryFrom<PeerId> for PublicKey {
185    type Error = DecodingError;
186
187    fn try_from(peer_id: PeerId) -> Result<Self, Self::Error> {
188        Ok(as_public_key(&peer_id)
189            .ok_or_else(|| DecodingError::PublicKeyNotInlined(peer_id.to_base58()))?
190            .into())
191    }
192}
193
194/// Convert PeerId to libp2p's PublicKey
195fn as_public_key(peer_id: &PeerId) -> Option<libp2p_identity::PublicKey> {
196    let mhash = peer_id.as_ref();
197
198    match multihash::Code::try_from(mhash.code()) {
199        Ok(multihash::Code::Identity) => {
200            libp2p_identity::PublicKey::try_decode_protobuf(mhash.digest()).ok()
201        }
202        _ => None,
203    }
204}
205
206#[cfg(test)]
207mod tests {
208    use super::*;
209    use crate::KeyPair;
210
211    #[test]
212    fn public_key_encode_decode_ed25519() {
213        let kp = KeyPair::generate_ed25519();
214        let pk = kp.public();
215        let encoded_pk = pk.encode();
216        assert_eq!(pk, PublicKey::decode(&encoded_pk).unwrap());
217    }
218
219    #[test]
220    fn public_key_encode_decode_secp256k1() {
221        let kp = KeyPair::generate_secp256k1();
222        let pk = kp.public();
223        let encoded_pk = pk.encode();
224        assert_eq!(pk, PublicKey::decode(&encoded_pk).unwrap());
225    }
226
227    #[test]
228    fn public_key_peer_id_conversions() {
229        let kp = KeyPair::generate_secp256k1();
230        let fluence_pk = kp.public();
231        let libp2p_pk: libp2p_identity::PublicKey = fluence_pk.clone().into();
232        let peer_id = PeerId::from_public_key(&libp2p_pk);
233        let fluence_pk_converted = PublicKey::try_from(peer_id).unwrap();
234
235        assert_eq!(fluence_pk, fluence_pk_converted);
236    }
237}