rusted_nostr_tools/functions/
event_methods.rs1use chrono::NaiveDateTime;
2use secp256k1::{
3 schnorr::Signature, Error, KeyPair, Message, Secp256k1, SecretKey, XOnlyPublicKey,
4};
5use serde::{Deserialize, Serialize};
6use serde_json::json;
7use sha2::{Digest, Sha256};
8
9#[derive(Debug, Serialize)]
10pub struct UnsignedEvent {
11 pub content: String,
12 pub created_at: i64,
13 pub kind: u64,
14 pub pubkey: String,
15 pub tags: Vec<Vec<String>>,
16}
17
18#[derive(Debug, Deserialize, Serialize)]
19pub struct SignedEvent {
20 pub content: String,
21 pub created_at: i64,
22 pub id: String,
23 pub kind: u64,
24 pub pubkey: String,
25 pub sig: String,
26 pub tags: Vec<Vec<String>>,
27}
28
29pub fn get_event_hash(event: &UnsignedEvent) -> Result<String, String> {
30 let commitment_string = serialize_event(&event)?;
31
32 let mut hasher = Sha256::new();
33
34 hasher.update(commitment_string.as_bytes());
35
36 let hash = hasher.finalize();
37 Ok(hex::encode(hash))
38}
39
40pub fn serialize_event(evt: &UnsignedEvent) -> Result<String, String> {
41 if !validate_event(evt) {
42 return Err("Invalid event".to_string());
43 }
44 Ok(json!([
45 0,
46 evt.pubkey,
47 evt.created_at,
48 evt.kind,
49 evt.tags,
50 evt.content
51 ])
52 .to_string())
53}
54
55pub fn sign_event(event: &UnsignedEvent, key: &str) -> Result<SignedEvent, Error> {
56 let secp = Secp256k1::new();
57 let secret_key =
58 SecretKey::from_slice(&hex::decode(key).expect("FailedToDecodeHexPrivateKey"))?;
59 let pair = KeyPair::from_seckey_slice(&secp, &secret_key.secret_bytes())
60 .expect("Failed to generate keypair from secret key");
61
62 let message = Message::from_slice(
63 Sha256::digest(&serialize_event(event).unwrap().as_bytes()).as_slice(),
64 )?;
65 let sig = hex::encode(secp.sign_schnorr_no_aux_rand(&message, &pair).as_ref());
66
67 let id = get_event_hash(event).unwrap();
68
69 Ok(SignedEvent {
70 content: event.content.clone(),
71 created_at: event.created_at,
72 id,
73 kind: event.kind,
74 pubkey: event.pubkey.clone(),
75 sig,
76 tags: event.tags.clone(),
77 })
78}
79
80pub fn validate_event(event: &UnsignedEvent) -> bool {
81 if !matches!(event, &UnsignedEvent { .. }) {
82 return false;
83 }
84
85 let datetime_opt = NaiveDateTime::from_timestamp_opt(event.created_at as i64, 0);
87 if datetime_opt.is_none() {
88 return false;
89 }
90
91 if !matches!(event.pubkey, _ if event.pubkey.len() == 64 && event.pubkey.chars().all(|c| c.is_ascii_hexdigit()))
92 {
93 return false;
94 }
95
96 true
97}
98
99pub fn verify_signature(signature: &str, pubkey: &str, id: &str) -> Result<(), Error> {
100 let secp = Secp256k1::new();
101
102 let public_key =
103 XOnlyPublicKey::from_slice(&hex::decode(pubkey).expect("FailedToDecodePubkey"))?;
104 let message =
105 Message::from_slice(&hex::decode(id).expect("UnableToDecodeHexMessageForSigning"))?;
106
107 let sig = Signature::from_slice(&hex::decode(signature).expect("FailedToDecodeSignature"))
108 .expect("FailedToParseSignature");
109
110 secp.verify_schnorr(&sig, &message, &public_key)
111}