Expand description
The pieces both ends of a sealed conversation must agree on.
A phone and a leaf node run different MLS implementations (ADR 0021: the phone runs OpenMLS, a Cortex-M leaf runs mls-rs), but they are not allowed to disagree about anything outside them. The envelope a ciphertext travels in, the derivation that turns an identity key into an address, the byte string a signature is taken over, and the ratchet numbers a session is configured with are all shared rather than implemented twice. This crate is where they live, and it exists because those pieces previously sat in crates a leaf node cannot link.
Each piece is here for the same reason, stated as the failure a second copy causes:
envelope: two copies of the codec are two wire formats the moment one is edited alone, and the symptom is a peer that cannot read a message.derive: two derivations are two identities for one key, and every trust gate in the protocol is a derive-and-compare, so a drifted copy rejects legitimate peers or, worse, accepts a mismatched one.canonical: a verifier that rebuilds a signing payload differently from the signer either rejects every signature or, if the difference is an ambiguity rather than a mismatch, accepts a forged one.constants: a number configured differently on the two ends produces a session that silently stops decrypting under load.freshness: two ends that disagree about how old a signed control frame may be produce a pair that refuses its own traffic in one direction and accepts a replayed frame in the other.
§Why this is not part of offline-protocol-core
Core links no cryptography at all, deliberately, and address derivation is a SHA-256. Core also knows nothing about MLS, and these types name it. Putting them in core would push a hash implementation into every consumer of the protocol’s base types, including a relay-only leaf image that never derives an address. See ADR 0022.
§Building without std
Like offline_protocol_core, this crate compiles for bare-metal targets
with --no-default-features, and alloc is required in both
configurations. Nothing here reads a clock, draws entropy or takes a lock,
so unlike core the no_std configuration loses no functionality: the std
feature only forwards to dependencies.
Re-exports§
pub use canonical::canonical_payload;pub use canonical::control_signing_payload;pub use canonical::control_signing_payload_v2;pub use canonical::gateway_address_proof_payload;pub use canonical::CTRL_PK_META_KEY;pub use canonical::CTRL_SIGN_DOMAIN;pub use canonical::CTRL_SIGN_DOMAIN_V2;pub use canonical::CTRL_SIG_META_KEY;pub use canonical::GATEWAY_ADDR_SIGN_DOMAIN;pub use constants::ACK_FOR_KEY;pub use constants::LEAF_KEY_PACKAGE_LIFETIME;pub use constants::LEAF_KEY_PACKAGE_NOT_BEFORE_BACKDATE_SECONDS;pub use constants::MAX_ACCEPTED_KEY_PACKAGE_LIFETIME;pub use constants::SENDER_RATCHET_MAXIMUM_FORWARD_DISTANCE;pub use constants::SENDER_RATCHET_OUT_OF_ORDER_TOLERANCE;pub use derive::derive_address;pub use derive::ED25519_PUBLIC_KEY_LEN;pub use envelope::EncryptedMessage;pub use envelope::GroupId;pub use envelope::MlsMessageType;pub use envelope::WelcomeMessage;pub use error::Result;pub use error::SealedError;pub use freshness::control_frame_freshness;pub use freshness::Freshness;pub use freshness::CTRL_FRESHNESS_FUTURE_MS;pub use freshness::CTRL_FRESHNESS_PAST_MS;pub use freshness::LEAF_CTRL_FRESHNESS_PAST_MS;pub use keypackage::KeyPackagePayload;pub use keypackage::CTRL_SIGN_V2;pub use keypackage::MLS_ENVELOPE_COMPACT_V1;
Modules§
- canonical
- The house construction for domain-separated signing payloads.
- constants
- Numbers a phone and a leaf node must configure identically.
- derive
- The SDK’s one address derivation.
- envelope
- The sealed envelope: what a payload looks like on the wire, both ways.
- error
- Errors raised by the sealed layer.
- freshness
- How old a signed control frame is allowed to be.
- keypackage
- The key package payload, which is how a peer says who it is and what it can parse.
- prefixes
- The control-frame prefixes a 1:1 sealed conversation is carried on.