event_verify.rs (4541B)
1 #![forbid(unsafe_code)] 2 3 use alloc::vec::Vec; 4 use core::str::FromStr; 5 6 use crate::types::{ 7 RadrootsNostrEvent as RadrootsNostrRawEvent, RadrootsNostrEventId, RadrootsNostrKind, 8 RadrootsNostrPublicKey, RadrootsNostrTag, RadrootsNostrTimestamp, 9 }; 10 use nostr::secp256k1::schnorr::Signature; 11 use radroots_events::RadrootsNostrEvent; 12 13 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 14 pub enum RadrootsNostrEventVerification { 15 Verified, 16 IdVerified, 17 IdMismatch, 18 SignatureInvalid, 19 MalformedEnvelope, 20 } 21 22 pub fn radroots_nostr_verify_event(event: &RadrootsNostrEvent) -> RadrootsNostrEventVerification { 23 let Some(raw_event) = raw_event_from_radroots(event) else { 24 return RadrootsNostrEventVerification::MalformedEnvelope; 25 }; 26 if !raw_event.verify_id() { 27 return RadrootsNostrEventVerification::IdMismatch; 28 } 29 if !raw_event.verify_signature() { 30 return RadrootsNostrEventVerification::SignatureInvalid; 31 } 32 RadrootsNostrEventVerification::Verified 33 } 34 35 pub fn radroots_nostr_verify_event_id( 36 event: &RadrootsNostrEvent, 37 ) -> RadrootsNostrEventVerification { 38 let Some(raw_event) = raw_event_from_radroots(event) else { 39 return RadrootsNostrEventVerification::MalformedEnvelope; 40 }; 41 if raw_event.verify_id() { 42 RadrootsNostrEventVerification::IdVerified 43 } else { 44 RadrootsNostrEventVerification::IdMismatch 45 } 46 } 47 48 fn raw_event_from_radroots(event: &RadrootsNostrEvent) -> Option<RadrootsNostrRawEvent> { 49 let id = RadrootsNostrEventId::from_hex(event.id.as_str()).ok()?; 50 let public_key = RadrootsNostrPublicKey::from_hex(event.author.as_str()).ok()?; 51 let kind_u16 = u16::try_from(event.kind).ok()?; 52 let mut tags = Vec::with_capacity(event.tags.len()); 53 for tag in event.tags.iter().cloned() { 54 tags.push(RadrootsNostrTag::parse(tag).ok()?); 55 } 56 let sig = Signature::from_str(event.sig.as_str()).ok()?; 57 Some(RadrootsNostrRawEvent::new( 58 id, 59 public_key, 60 RadrootsNostrTimestamp::from_secs(u64::from(event.created_at)), 61 RadrootsNostrKind::Custom(kind_u16), 62 tags, 63 event.content.clone(), 64 sig, 65 )) 66 } 67 68 #[cfg(test)] 69 mod tests { 70 use super::*; 71 use crate::event_convert::radroots_event_from_nostr; 72 use crate::events::radroots_nostr_build_event; 73 use crate::test_fixtures::FIXTURE_ALICE; 74 use crate::types::{RadrootsNostrKeys, RadrootsNostrSecretKey}; 75 use radroots_events::kinds::KIND_POST; 76 77 fn fixture_keys() -> RadrootsNostrKeys { 78 let secret_key = 79 RadrootsNostrSecretKey::from_hex(FIXTURE_ALICE.secret_key_hex).expect("secret key"); 80 RadrootsNostrKeys::new(secret_key) 81 } 82 83 fn signed_event() -> RadrootsNostrEvent { 84 let raw_event = radroots_nostr_build_event( 85 KIND_POST, 86 "hello", 87 vec![vec!["t".to_owned(), "soil".to_owned()]], 88 ) 89 .expect("builder") 90 .custom_created_at(RadrootsNostrTimestamp::from_secs(1_700_000_000)) 91 .sign_with_keys(&fixture_keys()) 92 .expect("signed event"); 93 radroots_event_from_nostr(&raw_event) 94 } 95 96 #[test] 97 fn verifies_signed_event_id_and_signature() { 98 let event = signed_event(); 99 100 assert_eq!( 101 radroots_nostr_verify_event(&event), 102 RadrootsNostrEventVerification::Verified 103 ); 104 assert_eq!( 105 radroots_nostr_verify_event_id(&event), 106 RadrootsNostrEventVerification::IdVerified 107 ); 108 } 109 110 #[test] 111 fn reports_id_mismatch_before_signature_checks() { 112 let mut event = signed_event(); 113 event.content = "tampered".to_owned(); 114 115 assert_eq!( 116 radroots_nostr_verify_event(&event), 117 RadrootsNostrEventVerification::IdMismatch 118 ); 119 } 120 121 #[test] 122 fn reports_signature_invalid_for_valid_id_with_wrong_signature() { 123 let mut event = signed_event(); 124 let replacement = if event.sig.starts_with('0') { "1" } else { "0" }; 125 event.sig.replace_range(0..1, replacement); 126 127 assert_eq!( 128 radroots_nostr_verify_event(&event), 129 RadrootsNostrEventVerification::SignatureInvalid 130 ); 131 } 132 133 #[test] 134 fn reports_malformed_envelope_for_unparseable_wire_fields() { 135 let mut event = signed_event(); 136 event.kind = u32::from(u16::MAX) + 1; 137 138 assert_eq!( 139 radroots_nostr_verify_event(&event), 140 RadrootsNostrEventVerification::MalformedEnvelope 141 ); 142 } 143 }