Skip to main content

webledgers_teller/
sign.rs

1//! Signing a Nostr event with a secret key held in memory.
2//!
3//! `sidestr-nostr`'s signer port seals its [`SignRequest`] to that crate's
4//! own kinds, so an event of a kind it does not know (3700, 30333) is signed
5//! here, by the route that crate leaves open for any outside signer: compute
6//! the template's NIP-01 id, sign it, and hand the signature to
7//! [`UnsignedEvent::with_signature`], which verifies the pair before it
8//! returns the event.
9//!
10//! [`SignRequest`]: sidestr_nostr::event::SignRequest
11
12use bitcoin::secp256k1::{Keypair, Message, SecretKey};
13use sidestr_core::block::secp;
14use sidestr_nostr::event::{Event, UnsignedEvent};
15
16use crate::error::{Error, Result};
17
18/// The x-only public key of a secret, as 64 lowercase hex digits: a Nostr
19/// pubkey and the x of a did:nostr account.
20pub fn pubkey_hex(secret: &SecretKey) -> String {
21    hex::encode(secret.x_only_public_key(secp()).0.serialize())
22}
23
24/// Sign `event` with `secret` (its `pubkey` is set to the secret's), BIP 340
25/// with zero auxiliary randomness as `sidestr-nostr` signs, so an event is a
26/// pure function of its fields and the key.
27pub(crate) fn sign_event(secret: &SecretKey, mut event: UnsignedEvent) -> Result<Event> {
28    event.pubkey = pubkey_hex(secret);
29    let kp = Keypair::from_secret_key(secp(), secret);
30    let msg = Message::from_digest(event.id_bytes());
31    let sig = secp().sign_schnorr_with_aux_rand(&msg, &kp, &[0u8; 32]);
32    event
33        .with_signature(&hex::encode(sig.as_ref()))
34        .map_err(|e| Error::Event(e.to_string()))
35}