Skip to main content

HIDE Protocol — 0.5, experimental

Human-friendly Identity & Data Encryption. The goal is to encrypt to a person, not to a key. This repository implements the file format engine and a hybrid signature scheme on top of it: one identity can encrypt, sign a file, prove possession to a live verifier, and act as an ssh-agent.

Do not use this for sensitive data. The protocol is a draft, the code is unaudited, no external security review has happened, and the hybrid KEM tracks a moving IETF draft.

What is verified today

Every claim below was produced by a command in this repository, on Rust 1.97.1.

  • Encrypt/decrypt round-trips across chunk boundaries (0 B, 1 B, 64 KiB ± 1, multi-chunk).
  • One payload, many recipients: the file is encrypted once; only the content key is wrapped per recipient.
  • Tamper detection: flipping any single byte of a container makes decryption fail (cargo test -p hide-object --test vectors).
  • Truncation, chunk reordering, duplication, deletion and trailing bytes are all rejected.
  • Independent interoperability: a separate Node implementation (@hpke/hybridkem-x-wing, cbor, Node crypto) decrypts the Rust vectors, and Rust decrypts Node's container byte-identically.
  • Cross-OS: the full suite passes on Windows 11 and on Linux (WSL2 Ubuntu 24.04), and a Linux build opens a container produced on Windows.
  • Degenerate recipient keys are refused: an X25519 component of small order would silently remove the classical half of the hybrid, so all seven such points are rejected before use.
  • Property tests (proptest) assert the parser never panics on arbitrary input, that any single-byte mutation of a container fails to decrypt, and that truncation or appended bytes always fail.
  • Hybrid signatures: Ed25519 + ML-DSA-65, concatenated; a signature verifies only if both halves do, so neither a quantum nor a classical break of one is enough.
  • Signatures cross surfaces: a signature made in WASM verifies in Node and vice versa, and every SDK returns the same verdict on the same bytes (node conformance/cross-surface/verify.mjs).
  • OpenSSH accepts our agent: ssh-add -l lists the key, ssh-keygen -Y sign obtains a signature through it, and ssh-keygen -Y verify reports it good — verified by OpenSSH's own tools, not ours.
  • Replay is refused: a challenge answer is accepted once; presenting the identical valid signature again is rejected, as is one given for a different audience or after its expiry.

Measured performance

On this machine (release build, 256 MiB payload):

Metric Value
Encrypt / decrypt (in memory) ~1250 / ~1550 MiB/s
Peak RSS for a 256 MB file 7 MB — constant, independent of input size
Size overhead 0.033% (~85 KB, dominated by the 1120-byte hybrid encapsulation)
hide.exe 675 KB

Streaming reuses two fixed 64 KiB buffers and one expanded AEAD instance, so there is no per-chunk allocation or rekeying. cargo run --release -p hide-object --example throughput reproduces the numbers.

What is NOT implemented or guaranteed

Being explicit here matters more than the feature list.

  • No identity, directory or key transparency. Recipients are raw test key files that you must exchange over a channel you already trust. Nothing proves a key belongs to a particular person.
  • Sender authentication only when the container is signed. For an unsigned container, a successful decryption proves it was not altered; it does not prove who created it. A signed container binds a signing key to the recipient set, the metadata and the exact plaintext — but it attests to a key, and nothing yet proves that key belongs to a particular person.
  • No forward secrecy for stored objects: anyone who later obtains the recipient secret can decrypt previously captured containers. Device revocation cannot retroactively protect data an attacker already holds.
  • No hardware protection. Secret keys are sealed with a passphrase (Argon2id + ChaCha20-Poly1305), but there is no Keychain, TPM, Secure Enclave or Keystore integration, and --insecure-plaintext still writes an unencrypted key on request.
  • Recipient privacy is limited. Stanzas carry no identifiers, but the recipient count and the ciphertext size are visible, and metadata is encrypted rather than hidden. A public signature also reveals the signer's key to anyone holding the file; the confidential placement avoids this.
  • Signing is not streaming. A signature commits to the plaintext, so signing buffers the payload.
  • SSH authentication is not post-quantum. hide agent offers the Ed25519 half of an identity and nothing more. OpenSSH accepts only ssh-ed25519, sk-* and RSA for user authentication; post-quantum algorithms exist there only in key exchange. What this buys is one sealed identity instead of a plaintext private key sitting in ~/.ssh, not quantum resistance.
  • An agent is a signing oracle. Anything that can reach the endpoint can ask for a signature. That is why confirmation is the default and --no-confirm must be asked for.
  • Not yet built: identity state, device enrollment, recovery, revocation, key transparency, MLS messaging.

Download

Releases carry three kinds of build. Verify any download against SHA256SUMS first.

Build File Use it when
Desktop application HIDE_*-setup.exe, *.dmg, *.deb, *.AppImage You want a window, not a terminal.
Portable hide-portable-* You want one executable, no installation, keys kept beside it.
Command line hide-* You want to script it.

The portable build writes nothing outside its own folder: keys go into a hide-keys directory next to the executable, so it runs from a USB stick and leaves no trace in your user profile.

Platforms

The CLI is built for Linux (x86-64, ARM64, and a static musl build for Alpine and scratch containers), Windows (x86-64, ARM64) and macOS (Apple silicon, Intel).

Package managers

Manifests for Homebrew, Scoop, WinGet and the AUR live in packaging/ and are generated with the real checksums by the release workflow. None is published yet: putting an unaudited encryption tool in a default package manager reaches people who will not read the warnings, so that step is taken deliberately rather than automatically.

SDKs

Every binding calls the same Rust core through one C ABI (crates/hide-ffi). No language reimplements the cryptography, so there is a single implementation to review, and conformance/cross-surface asserts that what one surface produces every other surface can open.

Language Path How it binds
C / C++ crates/hide-ffi/include/hide.h The ABI itself
Python sdk/python ctypes, so a wheel needs no compiler
TypeScript / Node sdk/node koffi over the same shared library
Browser sdk/wasm WebAssembly, compiled from the same crates
Go sdk/go cgo
Java / Kotlin sdk/java Foreign Function & Memory API, no JNI shim
Ruby sdk/ruby stdlib fiddle, no native gem to build
PHP sdk/php ext-ffi
.NET / C# sdk/dotnet Source-generated LibraryImport

Secret keys never cross into the host language: each SDK holds an opaque handle, and there is deliberately no function that exports key material.

import hide_protocol as hide

with hide.SecretKey.generate() as secret:
  box = hide.encrypt(b"hello", [secret.public_key()])
  assert hide.decrypt(box, secret).data == b"hello"

A browser is a weaker place to hold a key than a desktop: any script on the page shares the heap, so an XSS bug is equivalent to key theft. Prefer the CLI or the desktop application for keys that matter.

Try it

cargo test --workspace --all-features

# A key pair. The secret is sealed with a passphrase unless you opt out.
cargo run -p hide-cli -- --experimental keygen --secret alice.hide-key --public alice.hide-pub

# Files.
cargo run -p hide-cli -- --experimental encrypt report.pdf --recipient alice.hide-pub --output report.pdf.hide
cargo run -p hide-cli -- --experimental open report.pdf.hide --secret alice.hide-key --output report.pdf

# Sign as you encrypt. The signature is readable only by the recipients unless
# you pass --public-signature.
cargo run -p hide-cli -- --experimental encrypt report.pdf --recipient alice.hide-pub --output report.pdf.hide --sign alice.hide-key

# Or sign a file in place, leaving report.pdf.hide-sig beside it.
cargo run -p hide-cli -- --experimental sign report.pdf --secret alice.hide-key
cargo run -p hide-cli -- --experimental verify report.pdf --signer alice.hide-pub.sign

# Text messages, as a block you can paste into email or chat.
cargo run -p hide-cli -- --experimental seal "meet at six" --recipient alice.hide-pub
cargo run -p hide-cli -- --experimental unseal message.txt --secret alice.hide-key

# What is this file? Answered without decrypting it.
cargo run -p hide-cli -- --experimental info report.pdf.hide

The CLI never overwrites an existing file, writes plaintext to private staging first, and publishes the result only after authentication succeeds. --experimental is mandatory, so the risk is acknowledged explicitly.

keygen writes three files: one secret master seed, and two shareable public keys — alice.hide-pub for encryption and alice.hide-pub.sign for checking signatures. Both derive from the master seed, so there is a single thing to back up, and neither can be computed from the other. A key file created before signatures existed still decrypts; signing with it fails and says so.

A signature proves possession of a key. HIDE has no directory or transparency log, so nothing ties that key to a person — compare a signer's key against one you already trust.

Logging in over SSH

The same identity can act as an ssh-agent, so the key that authenticates you is never written to disk in the clear.

# Print the public line to paste into ~/.ssh/authorized_keys or github.com/settings/keys.
cargo run -p hide-cli -- --experimental ssh-key --secret alice.hide-key

# Serve it. Every signature asks for confirmation unless you pass --no-confirm.
cargo run -p hide-cli -- --experimental agent --secret alice.hide-key

Then point SSH at it with SSH_AUTH_SOCK — the socket path on Unix, the pipe path on Windows ($env:SSH_AUTH_SOCK = '\\.\pipe\hide-agent'). OpenSSH for Windows 9.5p2 ignores -o IdentityAgent, so use the environment variable on both platforms.

This offers the Ed25519 half of the identity only. SSH cannot carry the post-quantum half, so an SSH login is not post-quantum; what it avoids is a plaintext private key on disk. Treat the endpoint as sensitive: anything that can reach it can ask for a signature.

Building the desktop application

cd apps/hide-desktop
pnpm install --ignore-workspace
pnpm tauri build        # installer
pnpm build:portable     # single portable executable

The application calls the same Rust crates as the CLI; it contains no separate cryptographic code. Key material never reaches the user interface layer. A test in src-tauri/tests/interop.rs asserts that each surface can open what the other produced, so they cannot silently diverge.

Repository layout

Path Purpose
crates/hide-format Preamble, bounded canonical CBOR, portable-filename metadata
crates/hide-crypto HPKE X-Wing wrapping, HKDF, HMAC, ChaCha20-Poly1305; secrets zeroize and cannot be printed
crates/hide-object Envelope encryption and authenticated 64 KiB streaming
crates/hide-keyring Passphrase-sealed key files (Argon2id) and public-key armor
crates/hide-ffi The C ABI every language binding calls
crates/hide-wasm WebAssembly bindings for the browser
apps/hide-cli hide binary
apps/hide-desktop Desktop application (Tauri) and the portable build
sdk/ Python, Node, WASM, Go and Java packages
packaging/ Homebrew, Scoop, WinGet and AUR manifests
conformance/ Frozen vectors plus the independent Node verifier
spec/hide-0.1.md Wire format

Cryptography

Suite 1 is HPKE base mode with the X-Wing hybrid KEM (X25519 + ML-KEM-768), HKDF-SHA256 and ChaCha20-Poly1305, via the hpke and RustCrypto crates. No primitive is implemented here. Because X-Wing and HPKE-PQ are still drafts, the wire format is pinned to exact dependency versions and will change; vectors will be regenerated when the upstream construction changes.

License

Apache-2.0 — the specification and vectors are freely implementable, with no requirement to use any particular server or service.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

hide_protocol-0.5.0-py3-none-win_amd64.whl (291.3 kB view details)

Uploaded Python 3Windows x86-64

hide_protocol-0.5.0-py3-none-manylinux_2_28_x86_64.whl (397.2 kB view details)

Uploaded Python 3manylinux: glibc 2.28+ x86-64

hide_protocol-0.5.0-py3-none-macosx_11_0_arm64.whl (332.4 kB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file hide_protocol-0.5.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: hide_protocol-0.5.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 291.3 kB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for hide_protocol-0.5.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 cf8595468af4044e0197b4bc18d2bbb8db2957207e81e9d90229f8e47f9fc141
MD5 781a79a700b11a45155a0c0522a20491
BLAKE2b-256 c3930f50b27c6d8ff2edeb8f44d0294c45084193230e47e421a57f2350878557

See more details on using hashes here.

Provenance

The following attestation bundles were made for hide_protocol-0.5.0-py3-none-win_amd64.whl:

Publisher: publish-sdks.yml on hide-protocol/hide

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hide_protocol-0.5.0-py3-none-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for hide_protocol-0.5.0-py3-none-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 84671223a030e5e9a131f2fd90e598468e9e28a97344a1129869fc9f984e4066
MD5 dfbc2b2499509c11ed6941459798a0c7
BLAKE2b-256 9bf10a08980f7ee26308d32a241a3dbeefbc3d90faa44dcc25cf0ed2ea6b3790

See more details on using hashes here.

Provenance

The following attestation bundles were made for hide_protocol-0.5.0-py3-none-manylinux_2_28_x86_64.whl:

Publisher: publish-sdks.yml on hide-protocol/hide

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hide_protocol-0.5.0-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for hide_protocol-0.5.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 db29922ff226be9280663e8c8d9969d5ea8adcc50805dcb85040d9e15a55c4c2
MD5 a8d80935fbd7154469e1ff047fab2027
BLAKE2b-256 0ab556c1e1de49fd6ba82f04999663c984dedf00ba5fdd46136f128353c00255

See more details on using hashes here.

Provenance

The following attestation bundles were made for hide_protocol-0.5.0-py3-none-macosx_11_0_arm64.whl:

Publisher: publish-sdks.yml on hide-protocol/hide

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.7.0

3 files

0.6.2

3 files

0.6.1

3 files

0.6.0

3 files

This release

0.5.0 This release

3 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page