HIDE is experimental and has not been audited by a third party. See audit-status.md.
This document says what may change while the version is 0.x, how a change is announced, and what has to be true before 1.0. It applies to the wire format, the Rust crates, the C ABI, the SDKs and the CLI. The normative wire format is ../spec/hide-1.md; 0.9.0 is its release candidate.
These are the HIDE 1 wire format (../spec/hide-1.md, "Frozen vs implementation-defined"). From 0.9.0 they change only if a security flaw forces it, and such a change is recorded in the spec's change log (Appendix B) and in ../CHANGELOG.md with the release that made it.
- The container (spec §1–§7): preamble, protected header, recipient and signature stanzas, key schedule, metadata, payload, both signature transcripts, and the read rules for legacy minor 2.
- HIDE-Sign (§8): key derivation, the signed payload framing, verification rules.
- Key files (§9): the unprotected 32-byte master seed, the protected
HIDE-KEYfile, the recipient and signing public key files. - The identity log (§10), including the read rule for the 0.6–0.8 six-item entry head.
- The epoch chain (§11).
- Transparency hashing and proof verification (§12).
- The MLS credential binding (§13).
- Every domain-separation label and registry (spec Appendix A).
Described in spec §14 so other tools can interoperate with the reference implementation, but they may change in any release without a format version:
- ASCII armor for messages and public keys.
- The challenge format (
hide_sign::Challenge). - The detached-signature file (
<file>.hide-sig). - The epoch keystore file (
HIDE-EPK). It holds one holder's secrets for that holder's own tool and is never exchanged; epochs interoperate through the public, frozen epoch chain. - CLI commands and flags, SDK and C ABI functions, and the text of error messages. Their own stability is governed by the tables below, not by the format.
- The preamble minor is a non-breaking revision number. Writers of HIDE 1 write minor 1. A reader accepts any minor except 0 and processes minor ≥ 3 exactly as minor 1; the minor is inside the header MAC and the signature transcript, so it cannot be altered undetected. Minor 2 is the legacy HIDE/0.5–0.8 signed form: still read, with its own transcript, never written. Minor 0 is refused.
- Every preamble flag is critical. A reader refuses a container with a flag it does not know. Flag
0x01(SIGNED) marks a signed container; a stripped or unexpected signature is refused. - Extension ranges. Header and metadata keys 64–65535 are ignorable byte-string extensions (at most 16, each at most 64 KiB): a reader that does not understand one keeps its bytes, which are authenticated and signed, and opens the container. Keys 6–63 are critical and refused while unassigned. Unknown recipient stanza types are skipped (a container with only unknown stanzas has no matching recipient); unknown signature stanzas are refused.
- What this means in practice. A later 1.x can add optional data that a 0.9.0 reader opens, or a critical feature that a 0.9.0 reader refuses explicitly. It cannot add something an old reader silently misreads. HIDE 1 writers emit no extensions, so an unsigned HIDE 1 container without extensions is structurally identical to HIDE/0.1 and opens in every 0.x reader; a signed HIDE 1 container (flag
0x01) does not open in 0.1–0.8 readers. - Old files keep opening. Every container, key file and identity log written by 0.1–0.8 remains readable. The frozen vectors under
conformance/vectors/are tested byte-for-byte on every commit, in Rust and in the independent Node implementation, andconformance/vectors/manifest.jsonlists every vector with its expected outcome and SHA-256 (../conformance/vectors/README.md). A release that cannot open them is not made. - Vectors are frozen artifacts. The generators refuse to rewrite an existing vector with different bytes; changing one is a protocol change and is done only deliberately, never as a side effect.
- Upstream drafts. X-Wing's byte format has been stable across
draft-ietf-hpke-pqrevisions and its KEM id0x647Ais IANA-allocated. If the final RFC changed the construction, HIDE would add a new suite id rather than alter suite 1; existing containers would keep opening. - Before 0.9.0 the format changed in minor releases (0.5.0 signatures, 0.6.0 identity logs and epochs, 0.7.0 one signature and the MLS binding). That is history; see the spec change log.
| Crate | Status | Meaning |
|---|---|---|
hide-object |
stable-intent | encrypt, encrypt_signed, decrypt, the Decrypted type. Signatures may gain optional parameters; existing calls keep compiling within a minor except when a format change forces otherwise |
hide-crypto |
stable-intent | RecipientPublic, RecipientSecret, Identity::from_seed. Secret types will never gain Debug, Clone or Serialize |
hide-sign |
stable-intent | SigningIdentity, sign, verify, challenge–response, SpentNonces |
hide-keyring |
stable-intent | open, protect, unprotect_seed, KeyPurpose. Argon2id parameters may be raised; the floor may be raised (which refuses weaker files). Since 0.8.0 open also enforces ceilings (memory 8–256 MiB, parallelism ≤ 4, passes 1–64), which may be adjusted |
hide-ffi (C ABI) |
stable-intent | Functions and error codes in include/hide.h. Additions only; a removed function breaks every SDK at import, so it will not happen in a patch |
hide-format |
evolving | Parser internals; used by hide-object, not intended for direct use |
hide-identity |
evolving | The log's bytes are frozen (spec §10); the Rust event types and Membership may still change shape |
hide-epoch |
evolving | The chain's bytes are frozen (spec §11); the in-memory EpochChain API may change. Epoch secrets persist in hide-keyring's implementation-defined EpochStore |
hide-transparency |
evolving | Proof types follow RFC 6962 and are unlikely to change; the checkpoint format may gain a signature |
hide-mls |
evolving | New in 0.6/0.7; follows mls-rs 0.56, whose own API is 0.x |
hide-wasm |
evolving | Browser surface; not published to crates.io |
hide-cli |
internal | The binary is the interface; the crate has no library API. Command names and flags are stable-intent (below) |
"Stable-intent" means: we intend not to break it before 1.0, and if we must, it is a minor bump with a changelog entry and a migration note. "Evolving" means a minor bump may change it without a migration note. "Internal" means no guarantee.
| Bump | May include | Never includes |
|---|---|---|
| Minor (0.9 → 0.10) | API changes in any crate, new features, MSRV bump, dependency major bumps, removed deprecated items, changes to implementation-defined formats | A change to a frozen format, unless a security flaw forces it (then recorded in the spec change log) |
| Patch (0.6.1 → 0.6.2) | Bug fixes, security fixes, packaging fixes, documentation, new SDK platform targets | Format changes, API breaks, MSRV bump, removal of anything |
All crates in the workspace share one version (Cargo.toml [workspace.package]) and are released together; scripts/set-version.ps1 -Check runs in CI so the version cannot drift across the 23 files in seven ecosystems that carry it.
MSRV is 1.85 (rust-version in Cargo.toml), verified in CI by the minimum-supported-rust job. Raising it is a minor bump and is listed in the changelog. The toolchain used for development is whatever rust-toolchain.toml pins.
An item scheduled for removal is marked #[deprecated] (Rust) or documented as deprecated (C header, SDKs, CLI) for two minor releases before removal. Example: hide test-keygen was deprecated in 0.2.0 and still works; it remains until at least two minors after its deprecation note. A deprecation is not a break; the removal is, and happens only in a minor.
| Surface | Covered by this policy | Notes |
|---|---|---|
C header crates/hide-ffi/include/hide.h |
Yes — stable-intent | The single seam every binding uses; the c_abi test asserts header constants equal the Rust ones |
Python hide_protocol |
Yes — stable-intent for the public names in __init__.py |
Underscore-prefixed modules are internal |
Node hide-protocol |
Yes — stable-intent for exports of index.ts |
Platform packages @hide-protocol/<platform> are internal to the loader |
WASM @hide-protocol/wasm |
Evolving | Function signatures differ from Node (positional, concatenated recipients) and may converge |
Go sdk/go |
Stable-intent | Exported identifiers only |
Java org.hide-protocol:hide |
Evolving | Not yet on Maven Central |
Ruby hide-protocol |
Stable-intent | Public methods of Hide |
PHP hide-protocol/hide |
Evolving | Not yet on Packagist |
.NET HideProtocol |
Stable-intent | Public types in the HideProtocol namespace |
CLI hide |
Stable-intent | Subcommand names and long flags; output text is not stable and should not be parsed |
| Desktop app | Not an API | Opens what the CLI writes; enforced by src-tauri/tests/interop.rs |
Cross-surface agreement is enforced by conformance/cross-surface/verify.mjs: each surface must open every other surface's output and the frozen vectors, and a missing surface fails rather than skips.
All of the following, in this order of dependency:
- A third-party audit of the container format, the key schedule, the authenticated streaming and the signature transcript (items 1–4 in audit-status.md), with every finding fixed or documented as a known limitation, and the report published unredacted.
- One year of frozen container format after the last format change to suite 1, measured from the release that made it.
- Two independent implementations passing the full vector set in
conformance/vectors/manifest.json, including the rejection vectors. The Rust crates are one; the Node verifier underconformance/node(verify.mjsfor the container and signatures,subsystems.mjsfor identity logs, epoch chains and transparency proofs) is written in this repository by the same maintainers, so an implementation maintained outside it is still wanted. - The HPKE-PQ specification carrying X-Wing published as an RFC, or a documented decision to freeze on the draft with a HIDE-owned suite id.
- Epoch secrets persisted, so forward security by erasure is operational rather than demonstrable.
- The stability table above with no "evolving" row among the crates a container depends on.
The one-year clock in criterion 2 starts at 0.9.0, the format release candidate. Meeting the format freeze alone does not make 1.0: every criterion above must hold. Current status of each: audit-status.md.
1.0 does not require post-quantum MLS, a key directory, hardware key storage, or formal verification. Those remain out of scope and are listed as such in threat-model.md.