Skip to main content

linera_wallet_json/
keystore.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! A keystore backed by a JSON file holding the client's signing keys.
5
6use std::path::Path;
7
8use linera_base::{
9    crypto::{AccountPublicKey, AccountSignature, CryptoHash, InMemorySigner, Signer},
10    identifiers::AccountOwner,
11};
12use linera_persistent::{self as persistent, Persist as _};
13
14/// A persistent keystore backed by a JSON file with exclusive locking.
15pub struct Keystore(persistent::File<InMemorySigner>);
16
17impl Signer for Keystore {
18    type Error = <InMemorySigner as Signer>::Error;
19
20    async fn sign(
21        &self,
22        owner: &AccountOwner,
23        value: &CryptoHash,
24    ) -> Result<AccountSignature, Self::Error> {
25        (*self.0).sign(owner, value).await
26    }
27
28    async fn contains_key(&self, owner: &AccountOwner) -> Result<bool, Self::Error> {
29        (*self.0).contains_key(owner).await
30    }
31}
32
33impl Keystore {
34    /// Reads an existing keystore from disk.
35    pub fn read(path: &Path) -> Result<Self, persistent::file::Error> {
36        Ok(Self(persistent::File::read(path)?))
37    }
38
39    /// Creates a new keystore at `path`. If `testing_prng_seed` is provided,
40    /// uses deterministic key generation.
41    pub fn create(
42        path: &Path,
43        testing_prng_seed: Option<u64>,
44    ) -> Result<Self, persistent::file::Error> {
45        Ok(Self(persistent::File::read_or_create(path, || {
46            Ok(InMemorySigner::new(testing_prng_seed))
47        })?))
48    }
49
50    /// Generates a new key pair, persists the keystore, and returns the public key.
51    pub async fn generate_key(&mut self) -> Result<AccountPublicKey, persistent::file::Error> {
52        let key = self.0.generate_new();
53        self.0.persist().await?;
54        Ok(key)
55    }
56
57    /// Generates `count` new key pairs, persists the keystore, and returns the public keys.
58    pub async fn generate_keys(
59        &mut self,
60        count: usize,
61    ) -> Result<Vec<AccountPublicKey>, persistent::file::Error> {
62        let keys: Vec<_> = std::iter::repeat_with(|| self.0.generate_new())
63            .take(count)
64            .collect();
65        self.0.persist().await?;
66        Ok(keys)
67    }
68
69    /// Saves the keystore to disk.
70    pub async fn save(&mut self) -> Result<(), persistent::file::Error> {
71        self.0.persist().await
72    }
73
74    /// Consumes the keystore and returns the inner signer.
75    pub fn into_signer(self) -> InMemorySigner {
76        self.0.into_value()
77    }
78}