rust_ipfs/
keystore.rs

1use std::{
2    collections::{btree_map::Entry, BTreeMap},
3    sync::Arc,
4};
5
6use anyhow::Error;
7use futures::{stream::BoxStream, StreamExt};
8use libp2p::identity::{Keypair, PublicKey};
9use tokio::sync::Mutex;
10use zeroize::Zeroize;
11
12#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
13pub enum KeyType {
14    Ed25519,
15    Ecdsa,
16    Secp256k1,
17}
18
19#[derive(Clone)]
20pub struct Key {
21    key: Vec<u8>,
22}
23
24impl Drop for Key {
25    fn drop(&mut self) {
26        self.zeroize()
27    }
28}
29
30impl Zeroize for Key {
31    fn zeroize(&mut self) {
32        self.key.zeroize()
33    }
34}
35
36impl AsRef<[u8]> for Key {
37    fn as_ref(&self) -> &[u8] {
38        &self.key
39    }
40}
41
42impl From<Vec<u8>> for Key {
43    fn from(key: Vec<u8>) -> Self {
44        Self { key }
45    }
46}
47
48impl From<&[u8]> for Key {
49    fn from(key: &[u8]) -> Self {
50        key.to_vec().into()
51    }
52}
53
54#[derive(Clone)]
55pub struct Keystore {
56    storage: Arc<dyn KeyStorage>,
57}
58
59impl std::fmt::Debug for Keystore {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        f.debug_struct("Keystore").finish()
62    }
63}
64
65impl Keystore {
66    /// Create a new keystore
67    pub fn new(storage: Arc<dyn KeyStorage>) -> Self {
68        Self { storage }
69    }
70
71    /// Create an in-memory keystore
72    pub fn in_memory() -> Self {
73        Self::new(Arc::new(MemoryKeyStorage::default()))
74    }
75
76    /// Import a [`Keypair`] into the keystore
77    /// If `name` is not supplied, the [`crate::PeerId`] will be the used as the name by default
78    pub async fn import_key(
79        &self,
80        keypair: &Keypair,
81        name: Option<&str>,
82    ) -> Result<PublicKey, Error> {
83        let public_key = keypair.public();
84
85        let peer_id = public_key.to_peer_id().to_string();
86
87        let peer_id_str = peer_id.as_str();
88
89        let name = name.unwrap_or(peer_id_str);
90
91        let bytes = Key::from(keypair.to_protobuf_encoding()?);
92
93        self.storage.set(name, bytes.as_ref()).await?;
94
95        Ok(public_key)
96    }
97
98    /// Generate a Ed25519 Keypair
99    /// If `name` is not supplied, the [`crate::PeerId`] will be the used as the name by default
100    pub async fn generate_ed25519(&self, name: Option<&str>) -> Result<PublicKey, Error> {
101        self.generate_key(name, KeyType::Ed25519).await
102    }
103
104    /// Generate a Ecdsa Keypair
105    /// If `name` is not supplied, the [`crate::PeerId`] will be the used as the name by default
106    pub async fn generate_ecdsa(&self, name: Option<&str>) -> Result<PublicKey, Error> {
107        self.generate_key(name, KeyType::Ecdsa).await
108    }
109
110    /// Generate a Secp256k1 Keypair
111    /// If `name` is not supplied, the [`crate::PeerId`] will be the used as the name by default
112    pub async fn generate_secp256k1(&self, name: Option<&str>) -> Result<PublicKey, Error> {
113        self.generate_key(name, KeyType::Secp256k1).await
114    }
115
116    /// Generate a [`Keypair`] based on the [`KeyType`] supplied
117    /// If `name` is not supplied, the [`crate::PeerId`] will be the used as the name by default
118    pub async fn generate_key(
119        &self,
120        name: Option<&str>,
121        key_type: KeyType,
122    ) -> Result<PublicKey, Error> {
123        let keypair = match key_type {
124            KeyType::Ed25519 => Keypair::generate_ed25519(),
125            KeyType::Ecdsa => Keypair::generate_ecdsa(),
126            KeyType::Secp256k1 => Keypair::generate_secp256k1(),
127        };
128        let public_key = keypair.public();
129
130        let peer_id = public_key.to_peer_id().to_string();
131
132        let peer_id_str = peer_id.as_str();
133
134        // We could probably wrap this in `Zeroizing` instead until `KeyStore` is refactored to accept `Key`
135        let bytes = Key::from(keypair.to_protobuf_encoding()?);
136
137        let name = name.unwrap_or(peer_id_str);
138
139        self.storage.set(name, bytes.as_ref()).await?;
140
141        Ok(public_key)
142    }
143
144    /// Get a [`Keypair`] from the [`Keystore`]
145    pub async fn get_keypair(&self, name: &str) -> Result<Keypair, Error> {
146        let key = self.storage.get(name).await?;
147        let keypair = Keypair::from_protobuf_encoding(key.as_ref())?;
148        Ok(keypair)
149    }
150
151    /// Rename a key stored in [`Keystore`]
152    pub async fn rename(&self, name: &str, new_name: &str) -> Result<(), Error> {
153        self.storage.rename(name, new_name).await
154    }
155
156    /// Check to determine if a the [`Keystore`] contains a key
157    pub async fn contains(&self, name: &str) -> Result<bool, Error> {
158        self.storage.contains(name).await
159    }
160}
161
162#[async_trait::async_trait]
163pub trait KeyStorage: Sync + Send + 'static {
164    async fn set(&self, name: &str, key: &[u8]) -> Result<(), Error>;
165    async fn get(&self, name: &str) -> Result<Key, Error>;
166    async fn contains(&self, name: &str) -> Result<bool, Error>;
167    async fn remove(&self, name: &str) -> Result<(), Error>;
168    async fn rename(&self, name: &str, new_name: &str) -> Result<(), Error>;
169    async fn list(&self) -> Result<BoxStream<'static, Key>, Error>;
170    async fn len(&self) -> Result<usize, Error> {
171        let amount = self.list().await?.count().await;
172        Ok(amount)
173    }
174}
175
176#[derive(Default)]
177pub struct MemoryKeyStorage {
178    inner: Mutex<BTreeMap<String, Key>>,
179}
180
181#[async_trait::async_trait]
182impl KeyStorage for MemoryKeyStorage {
183    async fn set(&self, name: &str, key: &[u8]) -> Result<(), Error> {
184        let mut inner = self.inner.lock().await;
185        match inner.entry(name.into()) {
186            Entry::Occupied(mut entry) => {
187                let key_entry = entry.get_mut();
188                *key_entry = key.into();
189            }
190            Entry::Vacant(entry) => {
191                entry.insert(key.into());
192            }
193        };
194
195        Ok(())
196    }
197    async fn get(&self, name: &str) -> Result<Key, Error> {
198        let inner = self.inner.lock().await;
199        inner
200            .get(name)
201            .cloned()
202            .ok_or(anyhow::anyhow!("Key doesnt exist"))
203    }
204    async fn remove(&self, name: &str) -> Result<(), Error> {
205        let mut inner = self.inner.lock().await;
206        inner
207            .remove(name)
208            .map(|_| ())
209            .ok_or(anyhow::anyhow!("Key doesnt exist"))
210    }
211
212    async fn contains(&self, name: &str) -> Result<bool, Error> {
213        let inner = self.inner.lock().await;
214        Ok(inner.contains_key(name))
215    }
216
217    async fn rename(&self, name: &str, new_name: &str) -> Result<(), Error> {
218        let mut inner = self.inner.lock().await;
219        if inner.contains_key(new_name) {
220            anyhow::bail!("{new_name} exist");
221        }
222
223        let key = inner
224            .remove(name)
225            .ok_or(anyhow::anyhow!("Key doesnt exist"))?;
226        inner.insert(new_name.into(), key);
227        Ok(())
228    }
229
230    async fn list(&self) -> Result<BoxStream<'static, Key>, Error> {
231        let inner = self.inner.lock().await.clone();
232        let stream = async_stream::stream! {
233            for (_, key) in inner {
234                yield key;
235            }
236        };
237
238        Ok(stream.boxed())
239    }
240}
241
242#[cfg(test)]
243mod test {
244    use crate::keystore::Keystore;
245
246    #[tokio::test]
247    async fn keystore_with_peerid() -> anyhow::Result<()> {
248        let keystore = Keystore::in_memory();
249        let pkey = keystore.generate_ed25519(None).await?;
250
251        let peer_id = pkey.to_peer_id().to_string();
252
253        let key = keystore.get_keypair(&peer_id).await?;
254
255        assert_eq!(key.public(), pkey);
256        Ok(())
257    }
258
259    #[tokio::test]
260    async fn keystore_with_name() -> anyhow::Result<()> {
261        let keystore = Keystore::in_memory();
262        let pkey = keystore.generate_ed25519(Some("primary")).await?;
263
264        let key = keystore.get_keypair("primary").await?;
265
266        assert_eq!(key.public(), pkey);
267        Ok(())
268    }
269
270    #[tokio::test]
271    async fn keystore_replace_existing() -> anyhow::Result<()> {
272        let keystore = Keystore::in_memory();
273        let public_key_1 = keystore.generate_ed25519(Some("primary")).await?;
274        let public_key_2 = keystore.generate_ed25519(Some("primary")).await?;
275        assert_ne!(public_key_1, public_key_2);
276        Ok(())
277    }
278
279    #[tokio::test]
280    async fn keystore_multiple_keys() -> anyhow::Result<()> {
281        let keystore = Keystore::in_memory();
282        let pkey1 = keystore.generate_ed25519(None).await?;
283        let pkey2 = keystore.generate_ed25519(None).await?;
284
285        let peer_id1 = pkey1.to_peer_id().to_string();
286        let peer_id2 = pkey2.to_peer_id().to_string();
287
288        let key1 = keystore.get_keypair(&peer_id1).await?;
289        let key2 = keystore.get_keypair(&peer_id2).await?;
290
291        assert_ne!(key1.public(), key2.public());
292        Ok(())
293    }
294
295    #[tokio::test]
296    async fn keystore_rename() -> anyhow::Result<()> {
297        let keystore = Keystore::in_memory();
298        let pkey = keystore.generate_ed25519(None).await?;
299
300        let peer_id = pkey.to_peer_id().to_string();
301
302        keystore.rename(&peer_id, "primary").await?;
303
304        let result = keystore.get_keypair(&peer_id).await;
305        assert!(result.is_err());
306
307        let key = keystore.get_keypair("primary").await?;
308
309        assert_eq!(key.public(), pkey);
310
311        Ok(())
312    }
313}