lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

README.md (8388B)


      1 # radroots_nostr
      2 
      3 `radroots_nostr` is the portable Nostr protocol adapter for Radroots. It
      4 converts between canonical Radroots identity/event values and Nostr protocol
      5 values, provides typed NIP helpers, and supplies an optional concrete local
      6 implementation of the `radroots_signing` SPI.
      7 
      8 This crate owns no relay client. It owns no sockets, HTTP client, relay pool,
      9 database, account store, retry loop, scheduler, executor, or process-global
     10 state. Live Nostr transport belongs in `radroots_transport_nostr`; application
     11 composition belongs in `radroots_sdk` or an advanced host.
     12 
     13 The authoritative package charter is the
     14 [`radroots_nostr` section of the Release V1 specification](../../contracts/crates/release_v1/radroots_crates_release_v1.toml).
     15 
     16 ## Quick start
     17 
     18 Convert a canonical Radroots public key to and from its NIP-19 `npub`
     19 representation:
     20 
     21 ```rust
     22 use radroots_identity::PublicKey;
     23 use radroots_nostr::key::{public_key_from_npub, public_key_to_npub};
     24 
     25 let public_key = PublicKey::from_hex(
     26     "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
     27 )?;
     28 let npub = public_key_to_npub(public_key)?;
     29 
     30 assert_eq!(public_key_from_npub(&npub)?, public_key);
     31 # Ok::<(), Box<dyn core::error::Error>>(())
     32 ```
     33 
     34 The same flow is available as a standalone example:
     35 
     36 ```sh
     37 cargo run -p radroots_nostr --example identity_conversion
     38 ```
     39 
     40 ## Public boundary
     41 
     42 The durable public modules are organized by responsibility:
     43 
     44 - `event` converts event identifiers, coordinates, and signed NIP-01 values.
     45 - `filter` constructs explicit Nostr subscription filters.
     46 - `key` converts public identities, provides NIP-19 helpers, and—with
     47   `signing`—owns opaque local secret-key handling and NIP-49 operations.
     48 - `tag` converts ordered tag parts and exposes focused tag inspection helpers.
     49 - `signing` implements `radroots_signing::Signer` for local Nostr keys.
     50 - `nip17` wraps and unwraps typed Radroots message events with NIP-17/NIP-59.
     51 - `blossom` signs and verifies BUD-11 HTTP authorization values.
     52 
     53 `Error` is the only intended root export. Protocol representations that must
     54 cross the adapter are exposed from the module that owns the conversion, rather
     55 than through a root prelude or wildcard alias set.
     56 
     57 ## Event model and typed authoring
     58 
     59 Canonical product drafts and verified events belong to `radroots_event`.
     60 Encoding, signature verification, contract admission, and typed inbound
     61 projection belong to `radroots_event_codec`. This crate performs the explicit
     62 translation to or from Nostr protocol values.
     63 
     64 With `events`, typed builders cover the supported Profile, Update,
     65 PhotoUpdate, Ask, Reply, Comment, deletion-request, NIP-52 date/time Event, and
     66 FoodAvailability authoring profiles. Sealed focused builders fix the event kind and canonical
     67 tag model before signer access. Generic builders reject reserved typed kinds;
     68 relaying an already signed event is a transport operation and does not grant a
     69 typed Radroots authoring claim.
     70 
     71 Conversion and verification are deterministic for their inputs. Inbound
     72 admission proves the received event and its typed projection; it does not prove
     73 that referenced events, authors, addresses, relays, or external resources
     74 exist.
     75 
     76 ## Local signing
     77 
     78 The `signing` feature provides an opaque `key::SecretKey` and a concrete local
     79 signer adapter. Secret-bearing values are single-owner, are not serializable,
     80 and always redact `Debug` output. Public identities are converted to the
     81 canonical `radroots_identity::PublicKey` boundary before they leave the
     82 adapter.
     83 
     84 NIP-19 `nsec` export and NIP-49 encryption/decryption are explicit operations.
     85 `secret_key_to_nsec` deliberately returns plaintext secret material; callers
     86 must treat that string as a credential, avoid logs and serialization, and
     87 zeroize or discard it promptly. Password, ciphertext, and plaintext failures
     88 are normalized so error values do not retain caller-supplied secret text.
     89 
     90 ## Side effects, cancellation, and commit points
     91 
     92 This crate performs in-memory parsing, validation, encoding, cryptography, and
     93 local signing only. It never opens a network connection, writes a file or
     94 database, selects an account, publishes an event, or installs a runtime.
     95 
     96 Some cryptographic adapters are async because their upstream protocol
     97 operations are async. Dropping one of those futures cancels local computation
     98 and creates no external durable effect. The crate has no remote publication or
     99 persistence commit point: the only successful result is the value returned to
    100 the caller. A transport or host that later publishes or stores that value owns
    101 its own cancellation and commit semantics.
    102 
    103 The `blossom` module converts exact, verified signer output into and from
    104 signed `Authorization: Nostr` values but never sends an HTTP request. BUD-11
    105 plans remain distinct from relay-authored plans. The `nip17` module creates and
    106 opens gift-wrap events. It does not select relays, deliver events, retry
    107 operations, or persist message state.
    108 
    109 ## Serialization contract
    110 
    111 - Canonical durable Radroots data should be serialized through
    112   `radroots_event`, `radroots_event_codec`, or versioned `radroots_protocol`
    113   contracts.
    114 - Explicit Nostr boundary aliases use the upstream NIP-01 JSON representation.
    115 - `event::ExternalSigningRequest` serializes only as the standard
    116   unsigned Nostr event after reserved-kind and authoring-policy validation.
    117 - Returned externally signed events are accepted only when author, canonical
    118   event ID, and the complete NIP-01 signature verify against the request.
    119 - Secret-bearing key and local-signer values do not implement serialization.
    120 
    121 Deserializing protocol data never establishes product admission, account
    122 authority, upload completion, referenced-event existence, or relay trust.
    123 
    124 ## Security guidance
    125 
    126 - Parse untrusted protocol data through the checked conversion/admission
    127   functions; do not infer Radroots product validity from a syntactically valid
    128   upstream event.
    129 - Treat event content, tags, relay hints, Blossom claims, and NIP-17 plaintext
    130   as untrusted input even after signature verification.
    131 - BUD-11 authorization events are ephemeral credentials for a specific HTTP
    132   operation. This crate does not transmit them or manage replay protection for
    133   a server.
    134 - Typed media descriptors prove bytes and metadata, not successful BUD-02
    135   upload. The composing runtime must establish upload completion separately.
    136 - NIP-49 protects exported key material at rest; callers still own password
    137   handling, ciphertext storage, memory hygiene, and access control.
    138 - The crate forbids unsafe code and does not expose a live Nostr client or an
    139   ambient authority boundary.
    140 
    141 ## Features
    142 
    143 | Feature | Default | Contract |
    144 | --- | --- | --- |
    145 | `std` | yes | Enables standard-library support required by selected upstream protocol operations; it adds no network, storage, runtime, or global initialization. |
    146 | `events` | yes | Enables typed event builders, deterministic Radroots/Nostr event conversion, and verified event adapters. |
    147 | `signing` | no | Adds opaque local secret handling, NIP-49 helpers, draft signing, and the concrete local `radroots_signing::Signer` adapter. |
    148 | `nip17` | no | Adds focused NIP-17/NIP-59 typed message and message-file wrapping/unwrapping; no delivery or persistence. |
    149 | `blossom` | no | Adds BUD-11 signed HTTP authorization value creation and verification; no HTTP client or endpoint operation. |
    150 
    151 Features are additive. `--no-default-features` provides the portable
    152 `no_std + alloc` conversion core.
    153 
    154 ## Intended consumers
    155 
    156 - `radroots_nostr_connect` uses explicit Nostr conversion while owning NIP-46
    157   protocol state.
    158 - `radroots_transport_nostr` performs live relay I/O behind the generic
    159   transport contracts.
    160 - `radroots_sdk` composes local or remote signing, storage, and transport.
    161 - Myc and `radrootsd` consume focused protocol adapters without moving their
    162   host authority into this crate.
    163 - Advanced Rust hosts may use this package directly for offline conversion,
    164   verification, or a local signer adapter.
    165 
    166 Applications that only need ordinary Radroots workflows should normally use
    167 `radroots` or `radroots_sdk`.
    168 
    169 ## Copyright
    170 
    171 Except as otherwise noted, all files in the `radroots_nostr` distribution are
    172 
    173 Copyright (c) 2025 Tyson Lupul
    174 
    175 For information on usage and redistribution, and for a DISCLAIMER OF ALL
    176 WARRANTIES, see LICENSE included in the `radroots_nostr` distribution.