Skip to main content

miden_client/keystore/
mod.rs

1use alloc::boxed::Box;
2use alloc::collections::BTreeSet;
3use alloc::string::String;
4use alloc::vec::Vec;
5
6use miden_protocol::account::AccountId;
7use miden_protocol::account::auth::{AuthSecretKey, PublicKeyCommitment};
8use miden_tx::auth::TransactionAuthenticator;
9use thiserror::Error;
10
11#[derive(Debug, Error)]
12pub enum KeyStoreError {
13    #[error("storage error: {0}")]
14    StorageError(String),
15    #[error("decoding error: {0}")]
16    DecodingError(String),
17}
18
19/// A trait for managing cryptographic keys and their association with accounts.
20///
21/// This trait extends [`TransactionAuthenticator`] to provide a unified interface for key storage,
22/// retrieval, and account-key mapping.
23#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
24#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
25pub trait Keystore: TransactionAuthenticator {
26    /// Adds a secret key to the keystore and associates it with the given account.
27    ///
28    /// A key can be associated with multiple accounts by calling this method multiple times.
29    async fn add_key(
30        &self,
31        key: &AuthSecretKey,
32        account_id: AccountId,
33    ) -> Result<(), KeyStoreError>;
34
35    /// Removes a key from the keystore by its public key commitment.
36    ///
37    /// This also removes all account associations for this key.
38    async fn remove_key(&self, pub_key: PublicKeyCommitment) -> Result<(), KeyStoreError>;
39
40    /// Retrieves a secret key by its public key commitment.
41    ///
42    /// Returns `Ok(None)` if the key is not found.
43    async fn get_key(
44        &self,
45        pub_key: PublicKeyCommitment,
46    ) -> Result<Option<AuthSecretKey>, KeyStoreError>;
47
48    /// Returns all public key commitments associated with the given account ID.
49    ///
50    /// Returns an empty set if the keystore holds no key for the account. An account can use keys
51    /// that are held elsewhere, so this is a valid state and not an error.
52    async fn get_account_key_commitments(
53        &self,
54        account_id: &AccountId,
55    ) -> Result<BTreeSet<PublicKeyCommitment>, KeyStoreError>;
56
57    /// Returns the account ID associated with a given public key commitment.
58    ///
59    /// Returns `Ok(None)` if no account is found for the commitment.
60    async fn get_account_id_by_key_commitment(
61        &self,
62        pub_key_commitment: PublicKeyCommitment,
63    ) -> Result<Option<AccountId>, KeyStoreError>;
64
65    /// Returns all secret keys associated with the given account ID.
66    ///
67    /// This is a convenience method that calls `get_account_key_commitments` followed by `get_key`
68    /// for each commitment.
69    ///
70    /// Returns an empty vector if the keystore holds no key for the account. Returns an error if
71    /// any key lookup fails.
72    async fn get_keys_for_account(
73        &self,
74        account_id: &AccountId,
75    ) -> Result<Vec<AuthSecretKey>, KeyStoreError> {
76        let commitments = self.get_account_key_commitments(account_id).await?;
77        let mut keys = Vec::with_capacity(commitments.len());
78        for commitment in commitments {
79            if let Some(key) = self.get_key(commitment).await? {
80                keys.push(key);
81            }
82        }
83        Ok(keys)
84    }
85}
86
87#[cfg(feature = "std")]
88mod fs_keystore;
89#[cfg(feature = "std")]
90pub use fs_keystore::{FilesystemKeyStore, StoredKeyInfo};