Files
buzz/crates/buzz-core/src/verification.rs
Will Pfleger d99ad131f1 refactor: rename sprout backend to buzz (#958)
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <wpfleger@block.xyz>
Signed-off-by: Will Pfleger <wpfleger@squareup.com>
Signed-off-by: Will Pfleger <wpfleger96@gmail.com>
Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub1fgdl5qqnh3k3f2xkqrvt7cujalhm623x4s7fdjdj5yrtp5fzjl9qrjpucw <4a1bfa0013bc6d14a8d600d8bf6392efefbd2a26ac3c96c9b2a106b0d12297ca@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub16v54tttfqacx9ycvc3k0ut0npj564ahcuajzy6qjvh57ntmsf4uq4806j2 <d32955ad69077062930cc46cfe2df30ca9aaf6f8e76422681265e9e9af704d78@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: Will Pfleger <wpfleger96@gmail.com>
2026-06-10 19:29:51 -04:00

72 lines
2.2 KiB
Rust

//! `verify_event()` is CPU-bound (Schnorr). In async contexts call it via
//! `tokio::task::spawn_blocking` — never directly on an async task.
use nostr::{Event, EventId};
use crate::error::VerificationError;
/// Verifies the event ID hash and Schnorr signature.
///
/// CPU-bound — call via `tokio::task::spawn_blocking` in async contexts.
pub fn verify_event(event: &Event) -> Result<(), VerificationError> {
if !event.verify_id() {
let computed = EventId::new(
&event.pubkey,
&event.created_at,
&event.kind,
&event.tags,
&event.content,
)
.to_hex();
return Err(VerificationError::InvalidId {
computed,
got: event.id.to_hex(),
});
}
if !event.verify_signature() {
return Err(VerificationError::InvalidSignature);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use nostr::{EventBuilder, JsonUtil, Keys, Kind};
fn make_valid_event() -> Event {
let keys = Keys::generate();
EventBuilder::new(Kind::TextNote, "test content")
.tags([])
.sign_with_keys(&keys)
.expect("sign")
}
#[test]
fn rejects_tampered_id() {
let keys = Keys::generate();
let event = EventBuilder::new(Kind::TextNote, "original")
.tags([])
.sign_with_keys(&keys)
.expect("sign");
let mut json: serde_json::Value = serde_json::from_str(&event.as_json()).expect("parse");
json["content"] = serde_json::Value::String("tampered".to_string());
let tampered = Event::from_json(json.to_string()).expect("parse");
assert!(matches!(
verify_event(&tampered),
Err(VerificationError::InvalidId { .. })
));
}
#[test]
fn rejects_tampered_signature() {
let event = make_valid_event();
let mut json: serde_json::Value = serde_json::from_str(&event.as_json()).expect("parse");
json["sig"] = serde_json::Value::String("0".repeat(128));
let tampered = Event::from_json(json.to_string()).expect("parse");
assert!(verify_event(&tampered).is_err());
}
}