Skip to main content

nula_core/
limits.rs

1//! Hard limits enforced by the Nostr protocol primitives.
2//!
3//! Centralising every spec-mandated byte length, length cap, and
4//! tunable cost ceiling in a single namespace makes it easy to:
5//!
6//! - bound caller-side validation against the same numbers the
7//!   parsers and validators use internally;
8//! - audit the surface for drift relative to the cited NIPs;
9//! - cite the value in user-facing documentation without chasing the
10//!   constant down through nested modules.
11//!
12//! Each entry below is either a re-export of the canonical constant
13//! that lives next to its consumer, or a `pub const` defined here when
14//! the source value is currently `pub(crate)` / private but still
15//! protocol-binding.
16//!
17//! # Stability
18//!
19//! Removing a constant from this module is a breaking change. Adding
20//! new constants is additive. Renaming requires a deprecation cycle.
21
22/// Length, in bytes, of the SHA-256 event id mandated by NIP-01.
23pub use crate::event::id::EVENT_ID_SIZE as EVENT_ID_BYTES;
24/// Length, in bytes, of a serialised BIP-340 Schnorr signature.
25pub use crate::key::keys::SIGNATURE_SIZE as SIGNATURE_BYTES;
26/// Length, in bytes, of an x-only BIP-340 public key.
27pub use crate::key::public_key::PUBLIC_KEY_SIZE as PUBLIC_KEY_BYTES;
28/// Length, in bytes, of a BIP-340 secret key.
29pub use crate::key::secret_key::SECRET_KEY_SIZE as SECRET_KEY_BYTES;
30/// Maximum length of a [`crate::message::SubscriptionId`], measured
31/// in Unicode scalar values.
32pub use crate::message::subscription_id::MAX_LENGTH as SUBSCRIPTION_ID_MAX_CHARS;
33/// Maximum length, in characters, of a NIP-19 bech32 string the
34/// decoder will accept before rejecting the input outright.
35pub use crate::nips::nip19::MAX_NIP19_LENGTH as NIP19_MAX_LENGTH;
36
37/// Smallest plaintext length the NIP-44 v2 encryptor accepts.
38///
39/// Spec: <https://github.com/nostr-protocol/nips/blob/master/44.md#encryption>.
40pub const NIP44_MIN_PLAINTEXT_BYTES: usize = 1;
41
42/// Largest plaintext length the NIP-44 v2 encryptor accepts.
43///
44/// Spec: <https://github.com/nostr-protocol/nips/blob/master/44.md#encryption>.
45pub const NIP44_MAX_PLAINTEXT_BYTES: usize = 65_535;
46
47/// Largest *raw* payload length (header + nonce + ciphertext + MAC)
48/// the NIP-44 v2 decoder will accept before base64 encoding.
49///
50/// Spec: <https://github.com/nostr-protocol/nips/blob/master/44.md#decoding>.
51pub const NIP44_MAX_PAYLOAD_BYTES: usize = 65_603;
52
53/// Largest `log_n` (scrypt cost factor) the encoder will accept.
54///
55/// `log_n = 30` corresponds to ~1 GiB of working memory and many
56/// minutes of CPU on commodity hardware — far above any sane
57/// production setting. The cap exists to keep accidentally-pathological
58/// values from wedging a decryptor.
59#[cfg(feature = "nip49")]
60#[cfg_attr(docsrs, doc(cfg(feature = "nip49")))]
61pub use crate::nips::nip49::MAX_LOG_N as NIP49_MAX_LOG_N;
62/// Length, in bytes, of the XChaCha20-Poly1305 nonce embedded in
63/// an `ncryptsec`.
64#[cfg(feature = "nip49")]
65#[cfg_attr(docsrs, doc(cfg(feature = "nip49")))]
66pub use crate::nips::nip49::NONCE_BYTES as NIP49_NONCE_BYTES;
67/// Length, in bytes, of the scrypt salt embedded in an `ncryptsec`.
68#[cfg(feature = "nip49")]
69#[cfg_attr(docsrs, doc(cfg(feature = "nip49")))]
70pub use crate::nips::nip49::SALT_BYTES as NIP49_SALT_BYTES;
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    /// Drift detector: every spec value is repeated here so a future
77    /// refactor that silently changes a constant (e.g. through a
78    /// rebase mishap) trips this test before it reaches a release.
79    #[test]
80    fn pinned_values_match_spec() {
81        assert_eq!(EVENT_ID_BYTES, 32);
82        assert_eq!(SIGNATURE_BYTES, 64);
83        assert_eq!(PUBLIC_KEY_BYTES, 32);
84        assert_eq!(SECRET_KEY_BYTES, 32);
85        assert_eq!(SUBSCRIPTION_ID_MAX_CHARS, 64);
86        assert_eq!(NIP19_MAX_LENGTH, 5_000);
87        assert_eq!(NIP44_MIN_PLAINTEXT_BYTES, 1);
88        assert_eq!(NIP44_MAX_PLAINTEXT_BYTES, 65_535);
89        assert_eq!(NIP44_MAX_PAYLOAD_BYTES, 65_603);
90        #[cfg(feature = "nip49")]
91        {
92            assert_eq!(NIP49_SALT_BYTES, 16);
93            assert_eq!(NIP49_NONCE_BYTES, 24);
94            assert_eq!(NIP49_MAX_LOG_N, 30);
95        }
96    }
97}