use crate::{
ContentEncryptionAlgorithm, DelegationConditions, EncryptedPrivateKey, Error, Event, EventKind,
EventV1, EventV2, Id, KeySecurity, KeySigner, Metadata, PreEvent, PreEventV2, PrivateKey,
PublicKey, PublicKeyHex, Rumor, RumorV1, RumorV2, Signature, Tag, TagV1, TagV2, Unixtime,
};
use rand::Rng;
use rand_core::OsRng;
use std::fmt;
use std::sync::atomic::{AtomicBool, AtomicU64, AtomicU8, Ordering};
use std::sync::mpsc::Sender;
use std::sync::Arc;
use std::thread;
use std::thread::JoinHandle;
pub trait Signer: fmt::Debug {
fn is_locked(&self) -> bool;
fn unlock(&mut self, password: &str) -> Result<(), Error>;
fn lock(&mut self);
fn change_passphrase(&mut self, old: &str, new: &str, log_n: u8) -> Result<(), Error>;
fn upgrade(&mut self, pass: &str, log_n: u8) -> Result<(), Error>;
fn public_key(&self) -> PublicKey;
fn encrypted_private_key(&self) -> Option<&EncryptedPrivateKey>;
fn sign_id(&self, id: Id) -> Result<Signature, Error>;
fn sign(&self, message: &[u8]) -> Result<Signature, Error>;
fn encrypt(
&self,
other: &PublicKey,
plaintext: &str,
algo: ContentEncryptionAlgorithm,
) -> Result<String, Error>;
fn decrypt(&self, other: &PublicKey, ciphertext: &str) -> Result<String, Error>;
fn nip44_conversation_key(&self, other: &PublicKey) -> Result<[u8; 32], Error>;
fn export_private_key_in_hex(&mut self, pass: &str, log_n: u8)
-> Result<(String, bool), Error>;
fn export_private_key_in_bech32(
&mut self,
pass: &str,
log_n: u8,
) -> Result<(String, bool), Error>;
fn key_security(&self) -> Result<KeySecurity, Error>;
fn generate_delegation_signature(
&self,
delegated_pubkey: PublicKey,
delegation_conditions: &DelegationConditions,
) -> Result<Signature, Error> {
let input = format!(
"nostr:delegation:{}:{}",
delegated_pubkey.as_hex_string(),
delegation_conditions.as_string()
);
self.sign(input.as_bytes())
}
fn verify_delegation_signature(
&self,
delegated_pubkey: PublicKey,
delegation_conditions: &DelegationConditions,
signature: &Signature,
) -> Result<(), Error> {
let input = format!(
"nostr:delegation:{}:{}",
delegated_pubkey.as_hex_string(),
delegation_conditions.as_string()
);
self.public_key().verify(input.as_bytes(), signature)
}
fn sign_event(&self, input: PreEvent) -> Result<Event, Error> {
if input.pubkey != self.public_key() {
return Err(Error::InvalidPrivateKey);
}
let id = input.hash()?;
let signature = self.sign_id(id)?;
Ok(Event {
id,
pubkey: input.pubkey,
created_at: input.created_at,
kind: input.kind,
tags: input.tags,
content: input.content,
sig: signature,
})
}
fn sign_event2(&self, input: PreEventV2) -> Result<EventV2, Error> {
if input.pubkey != self.public_key() {
return Err(Error::InvalidPrivateKey);
}
let id = input.hash()?;
let signature = self.sign_id(id)?;
Ok(EventV2 {
id,
pubkey: input.pubkey,
created_at: input.created_at,
kind: input.kind,
tags: input.tags,
content: input.content,
sig: signature,
})
}
fn sign_event_with_pow(
&self,
mut input: PreEvent,
zero_bits: u8,
work_sender: Option<Sender<u8>>,
) -> Result<Event, Error> {
let target = format!("{zero_bits}");
if input.pubkey != self.public_key() {
return Err(Error::InvalidPrivateKey);
}
input.tags.retain(|t| t.tagname() != "nonce");
input.tags.push(Tag::new(&["nonce", "0", &target]));
let index = input.tags.len() - 1;
let cores = num_cpus::get();
let quitting = Arc::new(AtomicBool::new(false));
let nonce = Arc::new(AtomicU64::new(0)); let best_work = Arc::new(AtomicU8::new(0));
let mut join_handles: Vec<JoinHandle<_>> = Vec::with_capacity(cores);
for core in 0..cores {
let mut attempt: u64 = core as u64 * (u64::MAX / cores as u64);
let mut input = input.clone();
let quitting = quitting.clone();
let nonce = nonce.clone();
let best_work = best_work.clone();
let work_sender = work_sender.clone();
let join_handle = thread::spawn(move || {
loop {
let _ = thread_priority::set_current_thread_priority(
thread_priority::ThreadPriority::Min,
);
if quitting.load(Ordering::Relaxed) {
break;
}
input.tags[index].set_index(1, format!("{attempt}"));
let Id(id) = input.hash().unwrap();
let leading_zeroes = crate::get_leading_zero_bits(&id);
if leading_zeroes >= zero_bits {
nonce.store(attempt, Ordering::Relaxed);
quitting.store(true, Ordering::Relaxed);
if let Some(sender) = work_sender.clone() {
sender.send(leading_zeroes).unwrap();
}
break;
} else if leading_zeroes > best_work.load(Ordering::Relaxed) {
best_work.store(leading_zeroes, Ordering::Relaxed);
if let Some(sender) = work_sender.clone() {
sender.send(leading_zeroes).unwrap();
}
}
attempt += 1;
}
});
join_handles.push(join_handle);
}
for joinhandle in join_handles {
let _ = joinhandle.join();
}
input.tags[index].set_index(1, format!("{}", nonce.load(Ordering::Relaxed)));
let id = input.hash().unwrap();
let signature = self.sign_id(id)?;
Ok(Event {
id,
pubkey: input.pubkey,
created_at: input.created_at,
kind: input.kind,
tags: input.tags,
content: input.content,
sig: signature,
})
}
fn giftwrap(&self, input: PreEvent, pubkey: PublicKey) -> Result<Event, Error> {
let sender_pubkey = input.pubkey;
if sender_pubkey != self.public_key() {
return Err(Error::InvalidPrivateKey);
}
let seal_backdate = Unixtime(
input.created_at.0
- OsRng.sample(rand::distributions::Uniform::new(30, 60 * 60 * 24 * 2)),
);
let giftwrap_backdate = Unixtime(
input.created_at.0
- OsRng.sample(rand::distributions::Uniform::new(30, 60 * 60 * 24 * 2)),
);
let seal = {
let rumor = Rumor::new(input)?;
let rumor_json = serde_json::to_string(&rumor)?;
let encrypted_rumor_json =
self.encrypt(&pubkey, &rumor_json, ContentEncryptionAlgorithm::Nip44v2)?;
let pre_seal = PreEvent {
pubkey: sender_pubkey,
created_at: seal_backdate,
kind: EventKind::Seal,
content: encrypted_rumor_json,
tags: vec![],
};
self.sign_event(pre_seal)?
};
let random_signer = {
let random_private_key = PrivateKey::generate();
KeySigner::from_private_key(random_private_key, "", 1)
}?;
let seal_json = serde_json::to_string(&seal)?;
let encrypted_seal_json =
random_signer.encrypt(&pubkey, &seal_json, ContentEncryptionAlgorithm::Nip44v2)?;
let pre_giftwrap = PreEvent {
pubkey: random_signer.public_key(),
created_at: giftwrap_backdate,
kind: EventKind::GiftWrap,
content: encrypted_seal_json,
tags: vec![Tag::new_pubkey(pubkey, None, None)],
};
random_signer.sign_event(pre_giftwrap)
}
fn giftwrap2(&self, input: PreEventV2, pubkey: PublicKey) -> Result<EventV2, Error> {
let sender_pubkey = input.pubkey;
if sender_pubkey != self.public_key() {
return Err(Error::InvalidPrivateKey);
}
let seal_backdate = Unixtime(
input.created_at.0
- OsRng.sample(rand::distributions::Uniform::new(30, 60 * 60 * 24 * 2)),
);
let giftwrap_backdate = Unixtime(
input.created_at.0
- OsRng.sample(rand::distributions::Uniform::new(30, 60 * 60 * 24 * 2)),
);
let seal = {
let rumor = RumorV2::new(input)?;
let rumor_json = serde_json::to_string(&rumor)?;
let encrypted_rumor_json =
self.encrypt(&pubkey, &rumor_json, ContentEncryptionAlgorithm::Nip44v2)?;
let pre_seal = PreEventV2 {
pubkey: sender_pubkey,
created_at: seal_backdate,
kind: EventKind::Seal,
content: encrypted_rumor_json,
tags: vec![],
};
self.sign_event2(pre_seal)?
};
let random_signer = {
let random_private_key = PrivateKey::generate();
KeySigner::from_private_key(random_private_key, "", 1)
}?;
let seal_json = serde_json::to_string(&seal)?;
let encrypted_seal_json =
random_signer.encrypt(&pubkey, &seal_json, ContentEncryptionAlgorithm::Nip44v2)?;
let pre_giftwrap = PreEventV2 {
pubkey: random_signer.public_key(),
created_at: giftwrap_backdate,
kind: EventKind::GiftWrap,
content: encrypted_seal_json,
tags: vec![TagV2::Pubkey {
pubkey: pubkey.into(),
recommended_relay_url: None,
petname: None,
trailing: vec![],
}],
};
random_signer.sign_event2(pre_giftwrap)
}
fn create_metadata_event(
&self,
mut input: PreEvent,
metadata: Metadata,
) -> Result<Event, Error> {
input.kind = EventKind::Metadata;
input.content = serde_json::to_string(&metadata)?;
self.sign_event(input)
}
fn create_zap_request_event(
&self,
recipient_pubkey: PublicKey,
zapped_event: Option<Id>,
millisatoshis: u64,
relays: Vec<String>,
content: String,
) -> Result<Event, Error> {
let mut relays_tag = Tag::new(&["relays"]);
relays_tag.push_values(relays);
let mut pre_event = PreEvent {
pubkey: self.public_key(),
created_at: Unixtime::now(),
kind: EventKind::ZapRequest,
tags: vec![
Tag::new_pubkey(recipient_pubkey, None, None),
relays_tag,
Tag::new(&["amount", &format!("{millisatoshis}")]),
],
content,
};
if let Some(ze) = zapped_event {
pre_event.tags.push(Tag::new_event(ze, None, None, None));
}
self.sign_event(pre_event)
}
fn decrypt_event_contents(&self, event: &Event) -> Result<String, Error> {
if !event.kind.contents_are_encrypted() {
return Err(Error::WrongEventKind);
}
let pubkey = if event.pubkey == self.public_key() {
event
.people()
.iter()
.filter_map(|(pk, _, _)| if *pk != event.pubkey { Some(*pk) } else { None })
.nth(0)
.unwrap_or(event.pubkey) } else {
event.pubkey
};
self.decrypt(&pubkey, &event.content)
}
fn unwrap_giftwrap(&self, event: &Event) -> Result<Rumor, Error> {
if event.kind != EventKind::GiftWrap {
return Err(Error::WrongEventKind);
}
let mut tagged = false;
for t in event.tags.iter() {
if let Ok((pubkey, _, _)) = t.parse_pubkey() {
if pubkey == self.public_key() {
tagged = true;
}
}
}
if !tagged {
return Err(Error::InvalidRecipient);
}
let content = self.decrypt(&event.pubkey, &event.content)?;
let seal: Event = serde_json::from_str(&content)?;
if seal.kind != EventKind::Seal {
return Err(Error::WrongEventKind);
}
let author = seal.pubkey;
let content = self.decrypt(&seal.pubkey, &seal.content)?;
let rumor: Rumor = serde_json::from_str(&content)?;
if rumor.pubkey != author {
return Err(Error::InvalidPublicKey);
}
Ok(rumor)
}
fn unwrap_giftwrap2(&self, event: &EventV2) -> Result<RumorV2, Error> {
if event.kind != EventKind::GiftWrap {
return Err(Error::WrongEventKind);
}
let pkhex: PublicKeyHex = self.public_key().into();
let mut tagged = false;
for t in event.tags.iter() {
if let TagV2::Pubkey { pubkey, .. } = t {
if *pubkey == pkhex {
tagged = true;
}
}
}
if !tagged {
return Err(Error::InvalidRecipient);
}
let content = self.decrypt(&event.pubkey, &event.content)?;
let seal: EventV2 = serde_json::from_str(&content)?;
if seal.kind != EventKind::Seal {
return Err(Error::WrongEventKind);
}
let author = seal.pubkey;
let content = self.decrypt(&seal.pubkey, &seal.content)?;
let rumor: RumorV2 = serde_json::from_str(&content)?;
if rumor.pubkey != author {
return Err(Error::InvalidPublicKey);
}
Ok(rumor)
}
fn unwrap_giftwrap1(&self, event: &EventV1) -> Result<RumorV1, Error> {
if event.kind != EventKind::GiftWrap {
return Err(Error::WrongEventKind);
}
let pkhex: PublicKeyHex = self.public_key().into();
let mut tagged = false;
for t in event.tags.iter() {
if let TagV1::Pubkey { pubkey, .. } = t {
if *pubkey == pkhex {
tagged = true;
}
}
}
if !tagged {
return Err(Error::InvalidRecipient);
}
let content = self.decrypt(&event.pubkey, &event.content)?;
let seal: EventV1 = serde_json::from_str(&content)?;
if seal.kind != EventKind::Seal {
return Err(Error::WrongEventKind);
}
let author = seal.pubkey;
let content = self.decrypt(&seal.pubkey, &seal.content)?;
let rumor: RumorV1 = serde_json::from_str(&content)?;
if rumor.pubkey != author {
return Err(Error::InvalidPublicKey);
}
Ok(rumor)
}
}