1use alloc::{format, string::String, vec::Vec};
4use zeroize::Zeroizing;
5
6use crate::{
7 error::{Error, Result},
8 keygen::{ClientKeyShare, ServerKeyShare},
9 params::Params,
10};
11
12pub trait SecretStore {
15 fn put(&self, key: &str, value: &[u8]) -> Result<()>;
16 fn get(&self, key: &str) -> Result<Option<Zeroizing<Vec<u8>>>>;
17 fn delete(&self, key: &str) -> Result<()>;
18}
19
20fn client_key(wallet_id: &str) -> String {
21 format!("tecdsa/client-share/{wallet_id}")
22}
23
24fn server_key(wallet_id: &str) -> String {
25 format!("tecdsa/server-share/{wallet_id}")
26}
27
28impl ClientKeyShare {
29 pub fn save(&self, store: &dyn SecretStore, wallet_id: &str) -> Result<()> {
31 store.put(&client_key(wallet_id), &self.export_secret())
32 }
33
34 pub fn load(store: &dyn SecretStore, wallet_id: &str, params: &Params) -> Result<Self> {
35 let bytes = store.get(&client_key(wallet_id))?.ok_or(Error::NotFound)?;
36 Self::import_secret(&bytes, params)
37 }
38}
39
40impl ServerKeyShare {
41 pub fn save(&self, store: &dyn SecretStore, wallet_id: &str) -> Result<()> {
42 store.put(&server_key(wallet_id), &self.export_secret())
43 }
44
45 pub fn load(store: &dyn SecretStore, wallet_id: &str, params: &Params) -> Result<Self> {
46 let bytes = store.get(&server_key(wallet_id))?.ok_or(Error::NotFound)?;
47 Self::import_secret(&bytes, params)
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 extern crate std;
54 use super::*;
55 use crate::testutil::{keygen, params};
56 use core::cell::RefCell;
57 use std::collections::BTreeMap;
58
59 #[derive(Default)]
60 struct MemStore(RefCell<BTreeMap<String, Vec<u8>>>);
61
62 impl SecretStore for MemStore {
63 fn put(&self, key: &str, value: &[u8]) -> Result<()> {
64 self.0.borrow_mut().insert(key.into(), value.to_vec());
65 Ok(())
66 }
67 fn get(&self, key: &str) -> Result<Option<Zeroizing<Vec<u8>>>> {
68 Ok(self.0.borrow().get(key).map(|v| Zeroizing::new(v.clone())))
69 }
70 fn delete(&self, key: &str) -> Result<()> {
71 self.0.borrow_mut().remove(key);
72 Ok(())
73 }
74 }
75
76 #[test]
77 fn shares_roundtrip_through_store() {
78 let (c, s) = keygen(41);
79 let store = MemStore::default();
80 c.save(&store, "w1").unwrap();
81 s.save(&store, "w1").unwrap();
82 let c2 = ClientKeyShare::load(&store, "w1", ¶ms()).unwrap();
83 let s2 = ServerKeyShare::load(&store, "w1", ¶ms()).unwrap();
84 assert_eq!(c2.key_id(), c.key_id());
85 assert_eq!(s2.key_id(), s.key_id());
86 assert_eq!(
87 ClientKeyShare::load(&store, "missing", ¶ms()).unwrap_err(),
88 Error::NotFound
89 );
90 store.delete(&client_key("w1")).unwrap();
91 assert!(ClientKeyShare::load(&store, "w1", ¶ms()).is_err());
92 }
93}