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