Skip to main content

walletkit_db/
traits.rs

1//! Interfaces for consumer-supplied platform integrations.
2//!
3//! Argument shapes (`Vec<u8>`, owned `String`) mostly mirror `WalletKit`'s
4//! existing uniffi-annotated traits so consumers can bridge with a thin
5//! newtype that just delegates and maps errors. (A blanket impl across
6//! crates is blocked by Rust's orphan rule, so consumers do need a small
7//! wrapper.) `Keystore::seal` is the one exception: it borrows its
8//! plaintext so the secret is never owned by this crate longer than
9//! necessary; a bridge to an owned-only interface (e.g. a uniffi callback)
10//! still needs one copy at that boundary.
11
12use crate::error::StoreResult;
13
14/// Device keystore for sealing and opening secrets under a device-bound key.
15///
16/// Implementations MUST use an AEAD construction (e.g. AES-GCM or
17/// ChaCha20-Poly1305) so that `aad` (additional authenticated data) is
18/// authenticated as part of the seal: any mismatch when opening must fail.
19pub trait Keystore: Send + Sync {
20    /// Seals plaintext under the device-bound key, authenticating `aad`
21    /// (additional authenticated data).
22    ///
23    /// `plaintext` is borrowed rather than owned so that callers holding it
24    /// in a zeroizing buffer (e.g. `Zeroizing<[u8; 32]>`) never have to
25    /// hand ownership of an un-zeroized copy to this trait.
26    ///
27    /// # Errors
28    ///
29    /// Returns an error if the keystore refuses the operation or the seal
30    /// fails.
31    fn seal(&self, aad: &[u8], plaintext: &[u8]) -> StoreResult<Vec<u8>>;
32
33    /// Opens ciphertext under the device-bound key, verifying `aad`. The
34    /// same `aad` supplied at seal time must be supplied here or the open
35    /// operation must fail.
36    ///
37    /// # Errors
38    ///
39    /// Returns an error if authentication fails or the keystore cannot open.
40    fn open_sealed(&self, aad: Vec<u8>, ciphertext: Vec<u8>) -> StoreResult<Vec<u8>>;
41}
42
43/// Atomic blob store for small binary files (e.g. sealed key envelopes).
44///
45/// Provided by the host rather than calling `std::fs` directly for two
46/// reasons:
47///
48/// - **WASM has no `std::fs`.** On `wasm32-unknown-unknown` the runtime
49///   is a Web Worker; the host backs storage with `OPFS`, `IndexedDB`,
50///   or similar.
51/// - **Hosts own where data lives.** iOS sandboxed app-data containers,
52///   Android per-UID data dirs, iCloud-skip flags, atomic-write
53///   semantics — all platform-specific. walletkit-db stays neutral.
54pub trait AtomicBlobStore: Send + Sync {
55    /// Reads the blob at `path`, if present.
56    ///
57    /// # Errors
58    ///
59    /// Returns an error if the read fails.
60    fn read(&self, path: String) -> StoreResult<Option<Vec<u8>>>;
61
62    /// Writes bytes atomically to `path`.
63    ///
64    /// # Errors
65    ///
66    /// Returns an error if the write fails.
67    fn write_atomic(&self, path: String, bytes: Vec<u8>) -> StoreResult<()>;
68
69    /// Deletes the blob at `path`.
70    ///
71    /// # Errors
72    ///
73    /// Returns an error if the delete fails.
74    fn delete(&self, path: String) -> StoreResult<()>;
75}