Skip to main content

Authenticated event

Scope and identity

This shared contract covers the trust transition from untrusted private-event bytes to an authenticated logical event. It applies to the Rust implementation used by Android. Wire details remain owned by the NIP-59 profile and cryptographic policy.

Supported behavior

Layered authentication

shared.authentication.layered — A route parsed from an outer wrapper selects a candidate account; it does not authenticate the inner message. Rust must validate the outer event, recipient route, both encrypted layers, seal, rumor ID and author binding before exposing the inner event. For a chat event, the authenticated outer recipient must also belong to the inner conversation.

A valid encrypted wrapper addressed to the local account does not grant its sender permission to edit or delete somebody else's message. The owning semantic contract adds that authorization check.

Ciphertext validation

shared.authentication.crypto — NIP-44 payloads must meet the pinned cryptographic profile and input bounds. Invalid authentication, padding or encoding must fail through the stable redacted error boundary. Independent valid and invalid vectors are checked at this shared layer; higher-level message scenarios reuse it.

Persistence semantics

Authentication is a prerequisite to storing accepted protocol truth. An outer wrapper and its inner logical event have different identities. Their retention and deduplication follow account storage. Rejected input must not create an accepted message merely because bytes arrived. Quarantine is a separate bounded diagnostic/storage outcome.

For the account transport, a valid outer signature with invalid private content must not terminate the account runtime or leave a pending ingestion reservation behind. Live ingestion discards the rejected event and can continue with a valid one. A rejected requested sync event must not advance a successful checkpoint; the transport takes its bounded recovery path.

Observable behavior

A caller receives an authenticated value or a stable failure. Routing metadata is not a decrypted message. An application must not display unauthenticated plaintext, log secret material, or reconstruct authorization from wrapper recipient tags.

Verification and limits

The mapped Rust cases exercise invalid routes, kinds, seal shapes, ciphertext, IDs, author binding, conversation membership, official NIP-44 vectors, extended payloads and size limits. They do not establish interoperability of every released client or every live relay configuration. No new cipher implementation or duplicate per-message vector corpus is introduced by this contract set.

No execution report is bundled with this documentation. Linked test cases describe verification scope; their existence is not a passing result.

InvariantRequired environmentsExecution evidence
shared.authentication.layered
rust-core
rust-hostmissing
4 mapped test cases
  • envelope::tests::rejects_invalid_routes_kinds_seals_ciphertext_ids_and_author_bindingsemantic; sdk, cargo:softchat
  • runtime::tests::incoming_chat_binds_outer_recipient_to_inner_participantssemantic; sdk, cargo:softchat
  • account_transport::tests::transport_invalid_inner_event_does_not_poison_live_ingestionsemantic; sdk, cargo:softchat
  • account_transport::tests::transport_invalid_sync_event_recovers_without_advancing_checkpointsemantic; sdk, cargo:softchat
shared.authentication.crypto
rust-core
rust-hostmissing
3 mapped test cases
  • nip44_profile::tests::decrypts_every_official_payload_and_rejects_invalid_vectorssemantic; sdk, cargo:softchat
  • nip44_profile::tests::decrypts_independent_extended_prefix_fixturesemantic; sdk, cargo:softchat
  • nip44_profile::tests::enforces_writer_and_reader_boundssemantic; sdk, cargo:softchat