From 5d9d97e89f6972ca0f53368b655e2b09c36b09fb Mon Sep 17 00:00:00 2001 From: Awiteb Date: Thu, 26 Mar 2026 22:47:15 +0000 Subject: [PATCH] perf: optimize NIP-21 URI parsing in `PublicKey::parse` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Align NIP-21 parsing performance with standard bech32 parsing. Previously, NIP-21 URIs (which are essentially bech32 strings with a prefix) took ~104% longer to parse than raw bech32 keys. By streamlining the prefix handling, NIP-21 parsing time has been reduced by ~51%, bringing it within the expected margin of standard bech32 performance. Benchmarks: | Bench | Before (ns/iter) | After (ns/iter) | Δ | |-----------------------|------------------|-----------------|--------| | parse_bech32 | 591.20 | 592.77 | ~0% | | parse_nip21_uri | 1,225.93 | 598.44 | -51.2% | Signed-off-by: Awiteb --- crates/nostr/CHANGELOG.md | 1 + crates/nostr/src/key/public_key.rs | 27 ++++++++++----------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/crates/nostr/CHANGELOG.md b/crates/nostr/CHANGELOG.md index bbb06e2b8..ff7d4329e 100644 --- a/crates/nostr/CHANGELOG.md +++ b/crates/nostr/CHANGELOG.md @@ -78,6 +78,7 @@ - Add `a` tag of replaceable and addressable events in `EventBuilder::repost` (https://github.com/rust-nostr/nostr/pull/1184) - Handle legacy events with `mention` marker (https://github.com/rust-nostr/nostr/pull/1193) - Parse "HEAD" as `TagKing::Head` (https://github.com/rust-nostr/nostr/pull/1215) +- Optimize NIP-21 URI parsing in `PublicKey::parse` (https://github.com/rust-nostr/nostr/pull/1308) ## v0.44.2 - 2025/12/04 diff --git a/crates/nostr/src/key/public_key.rs b/crates/nostr/src/key/public_key.rs index 62615cffd..540372b22 100644 --- a/crates/nostr/src/key/public_key.rs +++ b/crates/nostr/src/key/public_key.rs @@ -14,8 +14,8 @@ use secp256k1::{Secp256k1, Signing, XOnlyPublicKey}; use serde::{Deserialize, Deserializer, Serialize}; use super::{Error, SecretKey}; -use crate::nips::nip19::FromBech32; -use crate::nips::nip21::FromNostrUri; +use crate::nips::nip19::{FromBech32, PREFIX_BECH32_PROFILE, PREFIX_BECH32_PUBLIC_KEY}; +use crate::nips::nip21::{FromNostrUri, SCHEME_WITH_COLON}; /// Public Key #[derive(Clone, Copy)] @@ -81,22 +81,15 @@ impl PublicKey { /// Parse from `hex`, `bech32` or [NIP21](https://github.com/nostr-protocol/nips/blob/master/21.md) uri pub fn parse(public_key: &str) -> Result { - // Try from hex - if let Ok(public_key) = Self::from_hex(public_key) { - return Ok(public_key); + if public_key.starts_with(PREFIX_BECH32_PUBLIC_KEY) + || public_key.starts_with(PREFIX_BECH32_PROFILE) + { + Self::from_bech32(public_key).map_err(|_| Error::InvalidPublicKey) + } else if public_key.starts_with(SCHEME_WITH_COLON) { + Self::from_nostr_uri(public_key).map_err(|_| Error::InvalidPublicKey) + } else { + Self::from_hex(public_key).map_err(|_| Error::InvalidPublicKey) } - - // Try from bech32 - if let Ok(public_key) = Self::from_bech32(public_key) { - return Ok(public_key); - } - - // Try from NIP21 URI - if let Ok(public_key) = Self::from_nostr_uri(public_key) { - return Ok(public_key); - } - - Err(Error::InvalidPublicKey) } /// Parse from hex string