nostr_types/types/
signer.rs

1use crate::{
2    ContentEncryptionAlgorithm, DelegationConditions, EncryptedPrivateKey, Error, Event, EventKind,
3    Id, KeySecurity, KeySigner, Metadata, ParsedTag, PreEvent, PrivateKey, PublicKey, Rumor,
4    Signature, Tag, Unixtime,
5};
6use async_trait::async_trait;
7use rand::Rng;
8use rand_core::OsRng;
9use std::fmt;
10use std::sync::atomic::{AtomicBool, AtomicU64, AtomicU8, Ordering};
11use std::sync::mpsc::Sender;
12use std::sync::Arc;
13use std::thread;
14use std::thread::JoinHandle;
15
16/// Signer operations
17#[async_trait]
18pub trait Signer: fmt::Debug + Send + Sync {
19    /// What is the signer's public key?
20    fn public_key(&self) -> PublicKey;
21
22    /// What is the signer's encrypted private key?
23    fn encrypted_private_key(&self) -> Option<EncryptedPrivateKey>;
24
25    /// Sign an event
26    async fn sign_event(&self, input: PreEvent) -> Result<Event, Error>;
27
28    /*
29    /// Sign an event
30    async fn sign_event(&self, input: PreEvent) -> Result<Event, Error> {
31        // Verify the pubkey matches
32        if input.pubkey != self.public_key() {
33            return Err(Error::InvalidPrivateKey);
34        }
35
36        // Generate Id
37        let id = input.hash()?;
38
39        // Generate Signature
40        let signature = self.sign_id(id).await?;
41
42        Ok(Event {
43            id,
44            pubkey: input.pubkey,
45            created_at: input.created_at,
46            kind: input.kind,
47            tags: input.tags,
48            content: input.content,
49            sig: signature,
50        })
51    }
52     */
53
54    /// Encrypt
55    async fn encrypt(
56        &self,
57        other: &PublicKey,
58        plaintext: &str,
59        algo: ContentEncryptionAlgorithm,
60    ) -> Result<String, Error>;
61
62    /// Decrypt NIP-04 or NIP-44
63    async fn decrypt(&self, other: &PublicKey, ciphertext: &str) -> Result<String, Error>;
64
65    /// Get the security level of the private key
66    fn key_security(&self) -> Result<KeySecurity, Error>;
67
68    /// Giftwrap an event
69    async fn giftwrap(&self, input: PreEvent, pubkey: PublicKey) -> Result<Event, Error> {
70        let sender_pubkey = input.pubkey;
71
72        // Verify the pubkey matches
73        if sender_pubkey != self.public_key() {
74            return Err(Error::InvalidPrivateKey);
75        }
76
77        let seal_backdate = Unixtime(
78            input.created_at.0
79                - OsRng.sample(rand::distributions::Uniform::new(30, 60 * 60 * 24 * 2)),
80        );
81        let giftwrap_backdate = Unixtime(
82            input.created_at.0
83                - OsRng.sample(rand::distributions::Uniform::new(30, 60 * 60 * 24 * 2)),
84        );
85
86        let seal = {
87            let rumor = Rumor::new(input)?;
88            let rumor_json = serde_json::to_string(&rumor)?;
89            let encrypted_rumor_json = self
90                .encrypt(&pubkey, &rumor_json, ContentEncryptionAlgorithm::Nip44v2)
91                .await?;
92
93            let pre_seal = PreEvent {
94                pubkey: sender_pubkey,
95                created_at: seal_backdate,
96                kind: EventKind::Seal,
97                content: encrypted_rumor_json,
98                tags: vec![],
99            };
100
101            self.sign_event(pre_seal).await?
102        };
103
104        // Generate a random keypair for the gift wrap
105        let random_signer = {
106            let random_private_key = PrivateKey::generate();
107            KeySigner::from_private_key(random_private_key, "", 1)
108        }?;
109
110        let seal_json = serde_json::to_string(&seal)?;
111        let encrypted_seal_json = random_signer
112            .encrypt(&pubkey, &seal_json, ContentEncryptionAlgorithm::Nip44v2)
113            .await?;
114
115        let pre_giftwrap = PreEvent {
116            pubkey: random_signer.public_key(),
117            created_at: giftwrap_backdate,
118            kind: EventKind::GiftWrap,
119            content: encrypted_seal_json,
120            tags: vec![ParsedTag::Pubkey {
121                pubkey,
122                recommended_relay_url: None,
123                petname: None,
124            }
125            .into_tag()],
126        };
127
128        random_signer.sign_event(pre_giftwrap).await
129    }
130
131    /// Create an event that sets Metadata
132    async fn create_metadata_event(
133        &self,
134        mut input: PreEvent,
135        metadata: Metadata,
136    ) -> Result<Event, Error> {
137        input.kind = EventKind::Metadata;
138        input.content = serde_json::to_string(&metadata)?;
139        self.sign_event(input).await
140    }
141
142    /// Create a ZapRequest event
143    /// These events are not published to nostr, they are sent to a lnurl.
144    async fn create_zap_request_event(
145        &self,
146        recipient_pubkey: PublicKey,
147        zapped_event: Option<Id>,
148        millisatoshis: u64,
149        relays: Vec<String>,
150        content: String,
151    ) -> Result<Event, Error> {
152        let mut relays_tag = Tag::new(&["relays"]);
153        relays_tag.push_values(relays);
154
155        let mut pre_event = PreEvent {
156            pubkey: self.public_key(),
157            created_at: Unixtime::now(),
158            kind: EventKind::ZapRequest,
159            tags: vec![
160                ParsedTag::Pubkey {
161                    pubkey: recipient_pubkey,
162                    recommended_relay_url: None,
163                    petname: None,
164                }
165                .into_tag(),
166                relays_tag,
167                Tag::new(&["amount", &format!("{millisatoshis}")]),
168            ],
169            content,
170        };
171
172        if let Some(ze) = zapped_event {
173            pre_event.tags.push(
174                ParsedTag::Event {
175                    id: ze,
176                    recommended_relay_url: None,
177                    marker: None,
178                    author_pubkey: None,
179                }
180                .into_tag(),
181            );
182        }
183
184        self.sign_event(pre_event).await
185    }
186
187    /// Decrypt the contents of an event
188    async fn decrypt_event_contents(&self, event: &Event) -> Result<String, Error> {
189        if !event.kind.contents_are_encrypted() {
190            return Err(Error::WrongEventKind);
191        }
192
193        let pubkey = if event.pubkey == self.public_key() {
194            // If you are the author, get the other pubkey from the tags
195            event
196                .people()
197                .iter()
198                .filter_map(|(pk, _, _)| if *pk != event.pubkey { Some(*pk) } else { None })
199                .nth(0)
200                .unwrap_or(event.pubkey) // in case you sent it to yourself.
201        } else {
202            event.pubkey
203        };
204
205        self.decrypt(&pubkey, &event.content).await
206    }
207
208    /// If a gift wrap event, unwrap and return the inner Rumor
209    async fn unwrap_giftwrap(&self, event: &Event) -> Result<Rumor, Error> {
210        if event.kind != EventKind::GiftWrap {
211            return Err(Error::WrongEventKind);
212        }
213
214        // Verify you are tagged
215        let mut tagged = false;
216        for t in event.tags.iter() {
217            if let Ok(ParsedTag::Pubkey { pubkey, .. }) = t.parse() {
218                if pubkey == self.public_key() {
219                    tagged = true;
220                }
221            }
222        }
223        if !tagged {
224            return Err(Error::InvalidRecipient);
225        }
226
227        // Decrypt the content
228        let content = self.decrypt(&event.pubkey, &event.content).await?;
229
230        // Translate into a seal Event
231        let seal: Event = serde_json::from_str(&content)?;
232
233        // Verify it is a Seal
234        if seal.kind != EventKind::Seal {
235            return Err(Error::WrongEventKind);
236        }
237
238        // Veirfy the signature of the seal
239        seal.verify(None)?;
240
241        // Note the author
242        let author = seal.pubkey;
243
244        // Decrypt the content
245        let content = self.decrypt(&seal.pubkey, &seal.content).await?;
246
247        // Translate into a Rumor
248        let rumor: Rumor = serde_json::from_str(&content)?;
249
250        // Compare the author
251        if rumor.pubkey != author {
252            return Err(Error::InvalidPublicKey);
253        }
254
255        // Return the Rumor
256        Ok(rumor)
257    }
258}
259
260/// Extended Signer operations
261///
262/// These enable NIP-26 delegation, signing an event with PoW,
263/// signing of anything (not just events) and access to the NIP44 conversation key.
264/// none of which is available using NIP-07 (browser) or NIP-46 (bunker) signers.
265#[async_trait]
266pub trait SignerExt: Signer {
267    /// Sign a 32-bit hash asynchronously
268    async fn sign_id(&self, id: Id) -> Result<Signature, Error>;
269
270    /// Sign a message asynchronously (this hashes with SHA-256 first internally)
271    async fn sign(&self, message: &[u8]) -> Result<Signature, Error>;
272
273    /// Get NIP-44 conversation key
274    async fn nip44_conversation_key(&self, other: &PublicKey) -> Result<[u8; 32], Error>;
275
276    /// Generate delegation signature
277    async fn generate_delegation_signature(
278        &self,
279        delegated_pubkey: PublicKey,
280        delegation_conditions: &DelegationConditions,
281    ) -> Result<Signature, Error> {
282        let input = format!(
283            "nostr:delegation:{}:{}",
284            delegated_pubkey.as_hex_string(),
285            delegation_conditions.as_string()
286        );
287
288        self.sign(input.as_bytes()).await
289    }
290
291    /// Verify delegation signature
292    fn verify_delegation_signature(
293        &self,
294        delegated_pubkey: PublicKey,
295        delegation_conditions: &DelegationConditions,
296        signature: &Signature,
297    ) -> Result<(), Error> {
298        let input = format!(
299            "nostr:delegation:{}:{}",
300            delegated_pubkey.as_hex_string(),
301            delegation_conditions.as_string()
302        );
303
304        self.public_key().verify(input.as_bytes(), signature)
305    }
306
307    /// Sign an event with Proof-of-Work
308    async fn sign_event_with_pow(
309        &self,
310        mut input: PreEvent,
311        zero_bits: u8,
312        work_sender: Option<Sender<u8>>,
313    ) -> Result<Event, Error> {
314        let target = format!("{zero_bits}");
315
316        // Verify the pubkey matches
317        if input.pubkey != self.public_key() {
318            return Err(Error::InvalidPrivateKey);
319        }
320
321        // Strip any pre-existing nonce tags
322        input.tags.retain(|t| t.tagname() != "nonce");
323
324        // Add nonce tag to the end
325        input.tags.push(Tag::new(&["nonce", "0", &target]));
326        let index = input.tags.len() - 1;
327
328        let cores = num_cpus::get();
329
330        let quitting = Arc::new(AtomicBool::new(false));
331        let nonce = Arc::new(AtomicU64::new(0)); // will store the nonce that works
332        let best_work = Arc::new(AtomicU8::new(0));
333
334        let mut join_handles: Vec<JoinHandle<_>> = Vec::with_capacity(cores);
335
336        for core in 0..cores {
337            let mut attempt: u64 = core as u64 * (u64::MAX / cores as u64);
338            let mut input = input.clone();
339            let quitting = quitting.clone();
340            let nonce = nonce.clone();
341            let best_work = best_work.clone();
342            let work_sender = work_sender.clone();
343            let join_handle = thread::spawn(move || {
344                loop {
345                    // Lower the thread priority so other threads aren't starved
346                    let _ = thread_priority::set_current_thread_priority(
347                        thread_priority::ThreadPriority::Min,
348                    );
349
350                    if quitting.load(Ordering::Relaxed) {
351                        break;
352                    }
353
354                    input.tags[index].set_index(1, format!("{attempt}"));
355
356                    let Id(id) = input.hash().unwrap();
357
358                    let leading_zeroes = crate::get_leading_zero_bits(&id);
359                    if leading_zeroes >= zero_bits {
360                        nonce.store(attempt, Ordering::Relaxed);
361                        quitting.store(true, Ordering::Relaxed);
362                        if let Some(sender) = work_sender.clone() {
363                            sender.send(leading_zeroes).unwrap();
364                        }
365                        break;
366                    } else if leading_zeroes > best_work.load(Ordering::Relaxed) {
367                        best_work.store(leading_zeroes, Ordering::Relaxed);
368                        if let Some(sender) = work_sender.clone() {
369                            sender.send(leading_zeroes).unwrap();
370                        }
371                    }
372
373                    attempt += 1;
374
375                    // We don't update created_at, which is a bit tricky to synchronize.
376                }
377            });
378            join_handles.push(join_handle);
379        }
380
381        for joinhandle in join_handles {
382            let _ = joinhandle.join();
383        }
384
385        // We found the nonce. Do it for reals
386        input.tags[index].set_index(1, format!("{}", nonce.load(Ordering::Relaxed)));
387        let id = input.hash().unwrap();
388
389        // Signature
390        let signature = self.sign_id(id).await?;
391
392        Ok(Event {
393            id,
394            pubkey: input.pubkey,
395            created_at: input.created_at,
396            kind: input.kind,
397            tags: input.tags,
398            content: input.content,
399            sig: signature,
400        })
401    }
402}
403
404/// Any `Signer` that can be locked and unlocked with a passphrase
405pub trait LockableSigner: Signer {
406    /// Is the signer locked?
407    fn is_locked(&self) -> bool;
408
409    /// Try to unlock access to the private key
410    fn unlock(&self, password: &str) -> Result<(), Error>;
411
412    /// Lock access to the private key
413    fn lock(&self);
414
415    /// Change the passphrase used for locking access to the private key
416    fn change_passphrase(&self, old: &str, new: &str, log_n: u8) -> Result<(), Error>;
417
418    /// Upgrade the encrypted private key to the latest format
419    fn upgrade(&self, pass: &str, log_n: u8) -> Result<(), Error>;
420}
421
422/// Any `Signer` that allows the secret to be exported (with interior mutability
423/// or no mutability necessary)
424#[async_trait]
425pub trait ExportableSigner: Signer {
426    /// Export the private key in hex.
427    ///
428    /// This returns a boolean indicating if the key security was downgraded. If it was,
429    /// the caller should save the new self.encrypted_private_key()
430    ///
431    /// We need the password and log_n parameters to possibly rebuild
432    /// the EncryptedPrivateKey when downgrading key security
433    async fn export_private_key_in_hex(
434        &self,
435        pass: &str,
436        log_n: u8,
437    ) -> Result<(String, bool), Error>;
438
439    /// Export the private key in bech32.
440    ///
441    /// This returns a boolean indicating if the key security was downgraded. If it was,
442    /// the caller should save the new self.encrypted_private_key()
443    ///
444    /// We need the password and log_n parameters to possibly rebuild
445    /// the EncryptedPrivateKey when downgrading key security
446    async fn export_private_key_in_bech32(
447        &self,
448        pass: &str,
449        log_n: u8,
450    ) -> Result<(String, bool), Error>;
451}
452
453/// Any `Signer` that allows the secret to be exported, but requires Self to be mutable
454/// to do so.
455#[async_trait]
456pub trait MutExportableSigner: Signer {
457    /// Export the private key in hex.
458    ///
459    /// This returns a boolean indicating if the key security was downgraded. If it was,
460    /// the caller should save the new self.encrypted_private_key()
461    ///
462    /// We need the password and log_n parameters to possibly rebuild
463    /// the EncryptedPrivateKey when downgrading key security
464    async fn export_private_key_in_hex(
465        &mut self,
466        pass: &str,
467        log_n: u8,
468    ) -> Result<(String, bool), Error>;
469
470    /// Export the private key in bech32.
471    ///
472    /// This returns a boolean indicating if the key security was downgraded. If it was,
473    /// the caller should save the new self.encrypted_private_key()
474    ///
475    /// We need the password and log_n parameters to possibly rebuild
476    /// the EncryptedPrivateKey when downgrading key security
477    async fn export_private_key_in_bech32(
478        &mut self,
479        pass: &str,
480        log_n: u8,
481    ) -> Result<(String, bool), Error>;
482}