sealed-channel 0.1.0

Transport-agnostic, forward-secret authenticated record channel from a PSK plus an externally-supplied ephemeral DH shared secret (ChaCha20-Poly1305 + HKDF-SHA256).
Documentation
#![no_std]
#![forbid(unsafe_code)]
#![doc = include_str!("../README.md")]
//!
//! # Construction
//!
//! `sealed-channel` is a transport-agnostic, forward-secret authenticated
//! record channel. It performs **pure compute only**: it knows nothing about
//! sockets, WebSockets, JSON, browsers, tokens, or any transport, and it
//! performs **no RNG and no I/O**. The caller supplies all randomness, the
//! ephemeral keys, and the Diffie-Hellman shared secret.
//!
//! Keys are derived with HKDF-SHA256 from the pre-shared secret (PSK), the
//! externally-supplied ephemeral DH shared secret, and a transcript hash that
//! binds the exact bytes of both handshake messages. Records are sealed with
//! ChaCha20-Poly1305, with the cleartext `magic || seq` header used as the
//! AEAD additional authenticated data and a per-direction nonce prefix
//! concatenated with the big-endian sequence number used as the nonce.
//!
//! Forward secrecy comes from the **ephemeral** DH shared secret supplied by
//! the caller: once the ephemeral private keys are discarded, past traffic
//! cannot be decrypted even if the PSK is later compromised.
//!
//! # CRITICAL SECURITY INVARIANT
//!
//! Authentication strength equals the entropy of the PSK. An active
//! man-in-the-middle (e.g. a relay) can perform its own DH with each side and
//! therefore knows both DH shared secrets; the ONLY thing keeping it out is
//! the PSK, which it does not know. The PSK MUST be high-entropy (at least 128
//! bits, 256 recommended). NEVER pass a low-entropy secret such as a PIN or
//! password as the PSK — authenticating a weak secret against an active MITM
//! requires a PAKE (e.g. SPAKE2+ / OPAQUE), which this crate is NOT.

extern crate alloc;

pub mod error;
pub mod record;
pub mod schedule;
pub mod transcript;

pub use error::Error;
pub use record::{RecordOpener, RecordSealer};
pub use schedule::SessionKeys;
pub use transcript::transcript_hash;