nula_core/lib.rs
1//! Protocol primitives for the [Nostr] protocol used across the `nula` workspace.
2//!
3//! `nula-core` is the lowest layer of the workspace. It defines the on-the-wire
4//! data model (events, filters, tags, messages), the cryptographic identity
5//! (keys, signatures), and a small set of shared value types. It performs no
6//! I/O, has no async runtime dependency, and is safe to reuse from tests,
7//! relays, signers, and offline tooling.
8//!
9//! Higher-level crates layer pool management, transports, databases, gossip,
10//! signers, and relay servers on top of these primitives.
11//!
12//! # Hard limits
13//!
14//! Every byte size, length cap, and tunable bound the protocol mandates lives
15//! in [`limits`]. The table below summarises the most common values; consult
16//! the cited NIPs for the binding spec text.
17//!
18//! | Constant | Value | Spec |
19//! |---|---|---|
20//! | [`limits::EVENT_ID_BYTES`] | `32` | [NIP-01] §`id` |
21//! | [`limits::SIGNATURE_BYTES`] | `64` | [NIP-01] §`sig` |
22//! | [`limits::PUBLIC_KEY_BYTES`] | `32` | [BIP-340] |
23//! | [`limits::SECRET_KEY_BYTES`] | `32` | [BIP-340] |
24//! | [`limits::SUBSCRIPTION_ID_MAX_CHARS`] | `64` | [NIP-01] §`<subscription_id>` |
25//! | [`limits::NIP19_MAX_LENGTH`] | `5_000` | [NIP-19] §guards |
26//! | [`limits::NIP44_MIN_PLAINTEXT_BYTES`] | `1` | [NIP-44] §plaintext |
27//! | [`limits::NIP44_MAX_PLAINTEXT_BYTES`] | `65_535` | [NIP-44] §plaintext |
28//! | [`limits::NIP44_MAX_PAYLOAD_BYTES`] | `65_603` | [NIP-44] §payload |
29//! | [`limits::NIP49_SALT_BYTES`] | `16` | [NIP-49] §scrypt |
30//! | [`limits::NIP49_NONCE_BYTES`] | `24` | [NIP-49] §XChaCha20 |
31//! | [`limits::NIP49_MAX_LOG_N`] | `30` | [NIP-49] §scrypt cost cap |
32//!
33//! [Nostr]: https://github.com/nostr-protocol/nostr
34//! [NIP-01]: https://github.com/nostr-protocol/nips/blob/master/01.md
35//! [NIP-19]: https://github.com/nostr-protocol/nips/blob/master/19.md
36//! [NIP-44]: https://github.com/nostr-protocol/nips/blob/master/44.md
37//! [NIP-49]: https://github.com/nostr-protocol/nips/blob/master/49.md
38//! [BIP-340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
39
40#![cfg_attr(docsrs, feature(doc_cfg))]
41#![doc(html_root_url = "https://docs.rs/nula-core")]
42#![forbid(unsafe_code)]
43#![cfg_attr(
44 test,
45 allow(
46 clippy::unwrap_used,
47 clippy::expect_used,
48 clippy::panic,
49 clippy::indexing_slicing,
50 clippy::missing_panics_doc,
51 clippy::missing_assert_message,
52 clippy::missing_errors_doc,
53 clippy::tests_outside_test_module,
54 reason = "test code may use panicking and indexing idioms for brevity"
55 )
56)]
57
58pub mod boxed;
59pub mod event;
60pub mod filter;
61pub mod key;
62pub mod limits;
63pub mod message;
64pub mod metadata;
65pub mod nips;
66pub mod observe;
67pub mod parser;
68pub mod prelude;
69pub mod signer;
70pub mod types;
71pub mod util;
72
73// `zeroize` is consumed across NIP-44, NIP-49 and the `Keys` Drop
74// impls; the unconditional placeholder keeps `--no-default-features`
75// warning-clean even when only [`SecretKey`]'s zeroize call site is
76// active.
77// `criterion` is wired in `dev-dependencies` for the `benches/`
78// targets only; lib unit tests never reach for it. The placeholder
79// keeps `cargo build --tests` warning-clean under
80// `unused-crate-dependencies`.
81#[cfg(test)]
82use criterion as _;
83// `proptest` backs `tests/property.rs` only; hedge it so the lib build
84// stays warning-clean under `unused-crate-dependencies`.
85#[cfg(test)]
86use proptest as _;
87use zeroize as _;
88
89// Crate-root re-exports: only the small set of types that callers reach
90// for *by name* on every interaction with Nostr (events, keys, filters,
91// messages, the JSON helper, the signer trait). Everything else lives one
92// explicit `use` away inside its module — in particular, every `*Error`
93// stays under its module path with a descriptive prefix
94// (`nula_core::nip02::ContactListError`, `nula_core::signer::SignerError`,
95// …). The prefix matches the v0.1 convention and avoids the
96// `clippy::error_impl_error` warning while keeping the error names
97// disambiguated when callers `use nula_core::*Error`.
98// See `prelude` for the curated import-everything view.
99pub use self::boxed::{BoxFuture, BoxStream};
100pub use self::event::{
101 Coordinate, Event, EventBuilder, EventId, Kind, SingleLetterTag, Tag, TagKind, Tags,
102 UnsignedEvent, compute_event_id,
103};
104pub use self::filter::Filter;
105pub use self::key::{Keys, PublicKey, SecretKey};
106pub use self::message::{ClientMessage, RelayMessage, SubscriptionId};
107pub use self::metadata::Metadata;
108pub use self::nips::nip19::{FromBech32, Nip19Entity, ToBech32};
109pub use self::signer::NostrSigner;
110pub use self::types::{ImageDimensions, RelayUrl, Timestamp, Url};
111pub use self::util::JsonUtil;