Skip to main content

vector_core/crypto/
signer.rs

1//! GuardedSigner — a signer backed by a GuardedKey vault.
2//!
3//! Reads the secret key from the memory-hardened vault on every operation, so
4//! the key exists in plaintext only for microseconds during signing.
5//!
6//! Implements the synchronous capability traits as the primary form: a vault
7//! read plus local crypto never awaits, so the async impls just wrap them. The
8//! async side exists only to satisfy `VectorSigner`, which has to stay async for
9//! the bunker and NIP-55 backends.
10
11use nostr_sdk::prelude::*;
12
13use crate::signer::{BoxedFuture, SignerError};
14
15/// A signer backed by the `MY_SECRET_KEY` vault.
16///
17/// The secret key is never stored in this struct — it's fetched from the
18/// GuardedKey vault on every operation and zeroized immediately after use.
19#[derive(Debug, Clone)]
20pub struct GuardedSigner {
21    public_key: PublicKey,
22}
23
24impl GuardedSigner {
25    pub fn new(public_key: PublicKey) -> Self {
26        Self { public_key }
27    }
28
29    fn temp_keys(&self) -> Result<Keys, SignerError> {
30        crate::state::MY_SECRET_KEY
31            .to_keys()
32            .ok_or_else(|| SignerError::from("Secret key not available"))
33    }
34}
35
36// ---------------------------------------------------------------------------
37// Synchronous capabilities
38// ---------------------------------------------------------------------------
39
40impl GetPublicKey for GuardedSigner {
41    type Error = SignerError;
42
43    #[inline]
44    fn get_public_key(&self) -> Result<PublicKey, Self::Error> {
45        Ok(self.public_key)
46    }
47}
48
49impl SignEvent for GuardedSigner {
50    type Error = SignerError;
51
52    fn sign_event(&self, unsigned: UnsignedEvent) -> Result<Event, Self::Error> {
53        let keys = self.temp_keys()?;
54        SignEvent::sign_event(&keys, unsigned).map_err(SignerError::backend)
55    }
56}
57
58impl Nip04 for GuardedSigner {
59    type Error = SignerError;
60
61    fn nip04_encrypt(&self, public_key: &PublicKey, content: &str) -> Result<String, Self::Error> {
62        let keys = self.temp_keys()?;
63        keys.nip04_encrypt(public_key, content)
64            .map_err(SignerError::backend)
65    }
66
67    fn nip04_decrypt(&self, public_key: &PublicKey, payload: &str) -> Result<String, Self::Error> {
68        let keys = self.temp_keys()?;
69        keys.nip04_decrypt(public_key, payload)
70            .map_err(SignerError::backend)
71    }
72}
73
74impl Nip44 for GuardedSigner {
75    type Error = SignerError;
76
77    fn nip44_encrypt(&self, public_key: &PublicKey, content: &str) -> Result<String, Self::Error> {
78        let keys = self.temp_keys()?;
79        keys.nip44_encrypt(public_key, content)
80            .map_err(SignerError::backend)
81    }
82
83    fn nip44_decrypt(&self, public_key: &PublicKey, payload: &str) -> Result<String, Self::Error> {
84        let keys = self.temp_keys()?;
85        keys.nip44_decrypt(public_key, payload)
86            .map_err(SignerError::backend)
87    }
88}
89
90// ---------------------------------------------------------------------------
91// Async forwarding — only so GuardedSigner satisfies `VectorSigner`
92// ---------------------------------------------------------------------------
93
94impl AsyncGetPublicKey for GuardedSigner {
95    type Error = SignerError;
96
97    #[inline]
98    fn get_public_key_async(&self) -> BoxedFuture<'_, Result<PublicKey, Self::Error>> {
99        let res = GetPublicKey::get_public_key(self);
100        Box::pin(async move { res })
101    }
102}
103
104impl AsyncSignEvent for GuardedSigner {
105    type Error = SignerError;
106
107    #[inline]
108    fn sign_event_async(&self, unsigned: UnsignedEvent) -> BoxedFuture<'_, Result<Event, Self::Error>> {
109        let res = SignEvent::sign_event(self, unsigned);
110        Box::pin(async move { res })
111    }
112}
113
114impl AsyncNip04 for GuardedSigner {
115    type Error = SignerError;
116
117    #[inline]
118    fn nip04_encrypt_async<'a>(
119        &'a self,
120        public_key: &'a PublicKey,
121        content: &'a str,
122    ) -> BoxedFuture<'a, Result<String, Self::Error>> {
123        let res = Nip04::nip04_encrypt(self, public_key, content);
124        Box::pin(async move { res })
125    }
126
127    #[inline]
128    fn nip04_decrypt_async<'a>(
129        &'a self,
130        public_key: &'a PublicKey,
131        encrypted_content: &'a str,
132    ) -> BoxedFuture<'a, Result<String, Self::Error>> {
133        let res = Nip04::nip04_decrypt(self, public_key, encrypted_content);
134        Box::pin(async move { res })
135    }
136}
137
138impl AsyncNip44 for GuardedSigner {
139    type Error = SignerError;
140
141    #[inline]
142    fn nip44_encrypt_async<'a>(
143        &'a self,
144        public_key: &'a PublicKey,
145        content: &'a str,
146    ) -> BoxedFuture<'a, Result<String, Self::Error>> {
147        let res = Nip44::nip44_encrypt(self, public_key, content);
148        Box::pin(async move { res })
149    }
150
151    #[inline]
152    fn nip44_decrypt_async<'a>(
153        &'a self,
154        public_key: &'a PublicKey,
155        payload: &'a str,
156    ) -> BoxedFuture<'a, Result<String, Self::Error>> {
157        let res = Nip44::nip44_decrypt(self, public_key, payload);
158        Box::pin(async move { res })
159    }
160}