linera_base/crypto/
signer.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4pub use in_mem::InMemorySigner;
5
6use super::CryptoHash;
7use crate::{
8    crypto::{AccountPublicKey, AccountSignature},
9    identifiers::AccountOwner,
10};
11
12/// A trait for signing keys.
13#[cfg_attr(not(web), trait_variant::make(Send))]
14pub trait Signer {
15    /// The type of errors arising from operations on this `Signer`.
16    type Error: std::error::Error + Send + Sync + 'static;
17
18    /// Creates a signature for the given `value` using the provided `owner`.
19    // DEV: We sign `CryptoHash` type, rather than `&[u8]` to make sure we don't sign
20    // things accidentally. See [`CryptoHash::new`] for how the type's name is included
21    // in the resulting hash, providing the canonicity of the hashing process.
22    async fn sign(
23        &self,
24        owner: &AccountOwner,
25        value: &CryptoHash,
26    ) -> Result<AccountSignature, Self::Error>;
27
28    /// Returns the public key corresponding to the given `owner`.
29    async fn get_public_key(&self, owner: &AccountOwner) -> Result<AccountPublicKey, Self::Error>;
30
31    /// Returns whether the given `owner` is a known signer.
32    async fn contains_key(&self, owner: &AccountOwner) -> Result<bool, Self::Error>;
33}
34
35/// In-memory implementation of the [`Signer`] trait.
36mod in_mem {
37    use std::{
38        collections::BTreeMap,
39        sync::{Arc, RwLock},
40    };
41
42    use serde::{Deserialize, Serialize};
43
44    #[cfg(with_getrandom)]
45    use crate::crypto::CryptoRng;
46    use crate::{
47        crypto::{AccountPublicKey, AccountSecretKey, AccountSignature, CryptoHash, Signer},
48        identifiers::AccountOwner,
49    };
50
51    #[derive(Debug, thiserror::Error)]
52    pub enum Error {
53        #[error("no key found for the given owner")]
54        NoSuchOwner,
55    }
56
57    /// In-memory signer.
58    #[derive(Clone)]
59    pub struct InMemorySigner(Arc<RwLock<InMemSignerInner>>);
60
61    impl InMemorySigner {
62        /// Creates a new [`InMemorySigner`] seeded with `prng_seed`.
63        /// If `prng_seed` is `None`, an `OsRng` will be used.
64        #[cfg(with_getrandom)]
65        pub fn new(prng_seed: Option<u64>) -> Self {
66            InMemorySigner(Arc::new(RwLock::new(InMemSignerInner::new(prng_seed))))
67        }
68
69        /// Creates a new [`InMemorySigner`].
70        #[cfg(not(with_getrandom))]
71        pub fn new() -> Self {
72            InMemorySigner(Arc::new(RwLock::new(InMemSignerInner::new())))
73        }
74
75        /// Generates a new key pair from Signer's RNG. Use with care.
76        #[cfg(with_getrandom)]
77        pub fn generate_new(&mut self) -> AccountPublicKey {
78            let mut inner = self.0.write().unwrap();
79            let secret = AccountSecretKey::generate_from(&mut inner.rng_state.prng);
80            if inner.rng_state.testing_seed.is_some() {
81                // Generate a new testing seed for the case when we need to store the PRNG state.
82                // It provides a "forward-secrecy" property for the testing seed.
83                // We do not do that for the case when `testing_seed` is `None`, because
84                // we default to the usage of OsRng in that case.
85                inner.rng_state.testing_seed = Some(inner.rng_state.prng.next_u64());
86            }
87            let public = secret.public();
88            let owner = AccountOwner::from(public);
89            inner.keys.insert(owner, secret);
90            public
91        }
92
93        /// Returns the public key corresponding to the given `owner`.
94        pub fn keys(&self) -> Vec<(AccountOwner, Vec<u8>)> {
95            let inner = self.0.read().unwrap();
96            inner.keys()
97        }
98    }
99
100    /// In-memory signer.
101    struct InMemSignerInner {
102        keys: BTreeMap<AccountOwner, AccountSecretKey>,
103        #[cfg(with_getrandom)]
104        rng_state: RngState,
105    }
106
107    #[cfg(with_getrandom)]
108    struct RngState {
109        prng: Box<dyn CryptoRng>,
110        #[cfg(with_getrandom)]
111        testing_seed: Option<u64>,
112    }
113
114    #[cfg(with_getrandom)]
115    impl RngState {
116        fn new(prng_seed: Option<u64>) -> Self {
117            let prng: Box<dyn CryptoRng> = prng_seed.into();
118            RngState {
119                prng,
120                #[cfg(with_getrandom)]
121                testing_seed: prng_seed,
122            }
123        }
124    }
125
126    impl InMemSignerInner {
127        /// Creates a new `InMemSignerInner` seeded with `prng_seed`.
128        /// If `prng_seed` is `None`, an `OsRng` will be used.
129        #[cfg(with_getrandom)]
130        pub fn new(prng_seed: Option<u64>) -> Self {
131            InMemSignerInner {
132                keys: BTreeMap::new(),
133                rng_state: RngState::new(prng_seed),
134            }
135        }
136
137        /// Creates a new `InMemSignerInner`.
138        #[cfg(not(with_getrandom))]
139        pub fn new() -> Self {
140            InMemSignerInner {
141                keys: BTreeMap::new(),
142            }
143        }
144
145        pub fn keys(&self) -> Vec<(AccountOwner, Vec<u8>)> {
146            self.keys
147                .iter()
148                .map(|(owner, secret)| {
149                    (
150                        *owner,
151                        serde_json::to_vec(secret).expect("serialization should not fail"),
152                    )
153                })
154                .collect()
155        }
156    }
157
158    impl Signer for InMemorySigner {
159        type Error = Error;
160
161        /// Creates a signature for the given `value` using the provided `owner`.
162        async fn sign(
163            &self,
164            owner: &AccountOwner,
165            value: &CryptoHash,
166        ) -> Result<AccountSignature, Error> {
167            let inner = self.0.read().unwrap();
168            if let Some(secret) = inner.keys.get(owner) {
169                let signature = secret.sign_prehash(*value);
170                Ok(signature)
171            } else {
172                Err(Error::NoSuchOwner)
173            }
174        }
175
176        /// Returns the public key corresponding to the given `owner`.
177        async fn get_public_key(&self, owner: &AccountOwner) -> Result<AccountPublicKey, Error> {
178            Ok(self
179                .0
180                .read()
181                .unwrap()
182                .keys
183                .get(owner)
184                .ok_or(Error::NoSuchOwner)?
185                .public())
186        }
187
188        /// Returns whether the given `owner` is a known signer.
189        async fn contains_key(&self, owner: &AccountOwner) -> Result<bool, Error> {
190            Ok(self.0.read().unwrap().keys.contains_key(owner))
191        }
192    }
193
194    impl FromIterator<(AccountOwner, AccountSecretKey)> for InMemorySigner {
195        fn from_iter<T>(input: T) -> Self
196        where
197            T: IntoIterator<Item = (AccountOwner, AccountSecretKey)>,
198        {
199            InMemorySigner(Arc::new(RwLock::new(InMemSignerInner {
200                keys: BTreeMap::from_iter(input),
201                #[cfg(with_getrandom)]
202                rng_state: RngState::new(None),
203            })))
204        }
205    }
206
207    impl Default for InMemSignerInner {
208        fn default() -> Self {
209            #[cfg(with_getrandom)]
210            let signer = InMemSignerInner::new(None);
211            #[cfg(not(with_getrandom))]
212            let signer = InMemSignerInner::new();
213            signer
214        }
215    }
216
217    impl Serialize for InMemorySigner {
218        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
219        where
220            S: serde::Serializer,
221        {
222            let inner = self.0.read().unwrap();
223            InMemSignerInner::serialize(&*inner, serializer)
224        }
225    }
226
227    impl<'de> Deserialize<'de> for InMemorySigner {
228        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
229        where
230            D: serde::Deserializer<'de>,
231        {
232            let inner = InMemSignerInner::deserialize(deserializer)?;
233            Ok(InMemorySigner(Arc::new(RwLock::new(inner))))
234        }
235    }
236
237    impl Serialize for InMemSignerInner {
238        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
239        where
240            S: serde::Serializer,
241        {
242            #[derive(Serialize, Debug)]
243            struct Inner<'a> {
244                keys: &'a Vec<(AccountOwner, Vec<u8>)>,
245                #[cfg(with_getrandom)]
246                prng_seed: Option<u64>,
247            }
248
249            #[cfg(with_getrandom)]
250            let prng_seed = self.rng_state.testing_seed;
251
252            let inner = Inner {
253                keys: &self.keys(),
254                #[cfg(with_getrandom)]
255                prng_seed,
256            };
257
258            Inner::serialize(&inner, serializer)
259        }
260    }
261
262    impl<'de> Deserialize<'de> for InMemSignerInner {
263        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
264        where
265            D: serde::Deserializer<'de>,
266        {
267            #[derive(Deserialize)]
268            struct Inner {
269                keys: Vec<(AccountOwner, Vec<u8>)>,
270                #[cfg(with_getrandom)]
271                prng_seed: Option<u64>,
272            }
273
274            let inner = Inner::deserialize(deserializer)?;
275
276            let keys = inner
277                .keys
278                .into_iter()
279                .map(|(owner, secret)| {
280                    let secret =
281                        serde_json::from_slice(&secret).map_err(serde::de::Error::custom)?;
282                    Ok((owner, secret))
283                })
284                .collect::<Result<BTreeMap<_, _>, _>>()?;
285
286            let signer = InMemSignerInner {
287                keys,
288                #[cfg(with_getrandom)]
289                rng_state: RngState::new(inner.prng_seed),
290            };
291            Ok(signer)
292        }
293    }
294}