Plain-language reasoning, recommended defaults, and visible security boundaries.
Guide 01
Get started.
Choose the runtime that handles plaintext. Use the standard artifact path to combine compression policy, authenticated encryption, and artifact shaping.
Native Rust-backed server work, buffers, protected artifacts, hashing, compression, and recovery.
Rust
voided-core
Direct source-of-truth APIs, custom native systems, feature selection, and byte-level control.
Default decision
Use protect/open. Use primitive encryption only when your application owns the outer format. Use shell-only Fuse APIs only when your inner bytes are already prepared.
The stateful client creates or loads its key from IndexedDB. Inspection is structural only; treat every returned field as attacker-controlled until open succeeds.
The source tree and docs are at 1.0.0 release-candidate state. macOS arm64 and Linux x64 native packages, browser WASM, CJS, and ESM paths have passed their release gates. The Windows x64 prebuild has verified provenance and hashes; real Windows execution is the final native gate before publication.
Do not pin an unpublished package
Until the 1.0 tags and packages exist, use the audited source commit rather than assuming the npm or crates.io release is live.
Runnable workbench
Interactive lab.
Start with what your application is trying to protect. Each tool explains the choice while it exposes the exact contract underneath.
Resolve ownership, inspect the VOF3 pipeline, compare shell intent, and verify root-wrapper rotation invariants.
Choose the API
Answer three questions. The result updates to the smallest safe surface for your system.
@voideddev/e2ee-client
Use protect/open.
Let the stateful browser client own key persistence and the complete VOF3 artifact lifecycle.
browser.ts
Trace the artifact
Move through one payload. The owner, byte shape, and trust rule change at every boundary.
01
Application bytes
Owner
Your application
Representation
UTF-8 or caller-owned bytes
Define the plaintext trust boundary and size limit before invoking crypto.
Compare Fuse presets
Presets change shell overhead and variation. They do not replace or strengthen the authenticated-encryption primitive.
Balanced · recommended default
Start here.
General-purpose artifact shaping for most applications.
Use the stateful client when Voided should manage the browser key lifecycle. Drop to the crypto namespace when your application needs explicit byte control.
When to use it
Your plaintext is created or consumed in the browser.
You want local IndexedDB-backed key persistence.
You need the VOF3 monolith path through verified WASM.
You want a neutral, customizable Recovery Deck setup component.
Do not move plaintext to a server merely to encrypt it there. Do not use browser storage as a substitute for account recovery, device custody, or cross-tab transaction coordination.
Stateful client
client.ts
import { VoidedE2EEClient } from "@voideddev/e2ee-client";
const client = new VoidedE2EEClient();
const protectedBlob = await client.protect("Private data", {
preset: "balanced",
});
// Metadata is not authenticated yet.
const preview = await client.inspectProtected(protectedBlob);
// Successful open authenticates the artifact.
const plaintext = await client.open(protectedBlob);
Top-level helpers
protect, open, inspectProtected, exportKey, importKey, and rotateKey operate through a default singleton client. Use them for small integrations; hold your own client instance when lifecycle ownership matters.
WASM behavior
Fuse, full-flow artifacts, bounded decompression, and Recovery Deck require the verified Rust/WASM runtime. The browser package does not silently replace those protocols with a TypeScript interpretation.
Fail closed by default
If WASM initialization fails in a browser, the operation throws. Calling forceTypeScriptBackend() is an explicit opt-in for supported primitive browser helpers only.
Use configureWasmLoader before initialization when your bundler or CDN needs an explicit artifact URL. A configured URL is locked to that initialization attempt; a failed configured load does not silently hunt for another binary.
Storage and lifecycle
Only a confirmed null read creates a first-use key. Storage errors fail closed and remain retryable. Each key-dependent operation revalidates persisted authority before taking a stable-key lease.
One lifecycle writer per key ID
Truly concurrent rotations, migrations, replacements, or deletion across tabs require an application-owned transactional lock. The generic storage interface does not pretend to coordinate them.
Fully compromised same-origin JavaScript can observe plaintext and usable keys. CSP, XSS prevention, dependency hygiene, and origin design are part of your security boundary.
Compression
High-level browser encryption defaults to compressionAlgorithm: "none". Compression can reveal secrets through ciphertext length when secret and attacker-controlled inputs share a context.
explicit-compression.ts
// Only when the whole plaintext has one trust boundary.
const blob = await client.encrypt(data, {
compressionAlgorithm: "gzip",
});
Browser support
Voided 1.0 targets current Safari/WebKit and Chromium-based browsers. Firefox is best-effort and is not a release gate.
SDK guide
Node.js.
Native Rust behavior exposed as direct Buffer APIs. No TypeScript crypto fallback and no ambiguity about which implementation protected your bytes.
When to use it
Plaintext already exists in a trusted Node.js process.
You need native protected artifacts, hashing, compression, or recovery.
You want CJS and ESM entry points over the same verified binary.
The normal path returns a complete artifact. Raw encrypt/decrypt returns primitive AEAD fields and leaves outer serialization to you.
Native runtime
Supported release prebuilds are macOS arm64, Linux x64 GNU with glibc 2.34 or newer, and Windows x64 MSVC. The postinstall and runtime loaders verify the selected artifact against the release manifest before loading it.
release checks
npm --prefix packages/enc-server run verify:release:current
npm --prefix packages/enc-server run smoke:package:current
npm --prefix packages/enc-server run test:integration
Another architecture, C library, or older Linux distribution must build from the tagged source and run the native verification suite.
API layers
Layer
Calls
Use when
Full flow
protect/open
Voided should own the standard artifact end to end.
Shell only
fuse/unfuse
You already prepared the inner bytes.
Primitive
encrypt/decrypt
You own the outer format and lifecycle.
SDK guide
Rust.
The implementation of record. Use it directly for native systems, explicit feature control, and the narrowest possible dependency boundary.
Add the crate
Cargo.toml
[dependencies]
voided-core = "1.0"
Use the exact tagged source until the crate is published.
Standard artifact
main.rs
use voided_core::encryption::generate_key;
use voided_core::shell::{
inspect_artifact, open, protect, FusedPreset, ProtectOptions,
};
let key = generate_key();
let protected = protect(
b"hello monolith world",
&key,
Some(ProtectOptions {
preset: FusedPreset::Balanced,
..ProtectOptions::default()
}),
)?;
let info = inspect_artifact(&protected.artifact)?;
let restored = open(&protected.artifact, &key)?;
Feature flags
Feature
Purpose
backend
Default full native feature set.
browser
Browser-compatible subset used by WASM.
compression
Brotli and gzip support.
signing
Ed25519 and P-256 helpers. RSA-PSS wire ID is reserved, not implemented.
std / wasm
Target and runtime integration controls.
No unsafe code
The crate declares #![forbid(unsafe_code)].
Core concept
Artifact model.
Fuse is the stable outer shell. The standard Voided 1.0 product path protects the whole monolith: prepare, authenticate, shape, then open in reverse.
The mental model
Optionally compress under an explicit policy.
Encrypt with authenticated encryption.
Shape the complete plan into the VOF3 artifact.
On open, validate structure and bounds before expensive work.
Authenticate before releasing plaintext.
Fuse is not another cipher
It is an authenticated outer artifact format and shaping layer around already encrypted material.
Choose the API layer
If you need
Use
Why
The normal Voided artifact
protect/open
One contract owns the whole safe sequence.
A shell around prepared bytes
fuse/unfuse
You already control and understand the inner payload.
Only authenticated encryption
encrypt/decrypt
Your system owns serialization and outer format.
Inspection
inspectFused and inspectArtifact parse structural metadata without a key. This is useful for routing, size display, and format introspection—but it is not proof.
Never authorize from inspected fields
Preset, sizes, chunk counts, and every other keyless field are attacker-controlled until open or unfuse succeeds with the expected key.
Presets
compact — lowest shell overhead.
balanced — general-purpose default.
concealed — heavier shape variation.
Presets do not upgrade the entropy of weak key material. Measure size and performance on your corpus before moving away from balanced.
Version stability
Package version 1.0 and wire-format version 3 are deliberately independent. VOF3 is the frozen authenticated byte format used by the first stable package release. Legacy readers exist for explicit migration; current writers produce VOF3.
Protocol guide
Recovery Deck.
One CSPRNG-shuffled standard deck becomes one deterministic Recovery Key. Persist only the opaque wrapper around your stable root.
The recovery flow
Validate exactly 52 canonical cards, each exactly once.
Rank the permutation into exactly 29 big-endian bytes.
Derive 32 bytes with domain-separated HKDF-SHA256.
Use that key to unwrap the stable 32-byte root.
Clear deck and derived-key copies as soon as the flow ends.
Same deck, same key—every time
The protocol constants are permanent. A future incompatible design must use a separate scheme, not silently reinterpret an existing deck.
What to persist
Material
Persist?
Reason
Ordered deck
No
It is the recovery secret.
29-byte permutation rank
No
It is an equivalent secret representation.
32-byte Recovery Key
No
It directly unwraps the root.
80-byte root wrapper
Yes
It is opaque, authenticated, and intended for storage.
Node.js setup and rotation
recovery.mjs
import {
createRecoveryDeck,
deriveRecoveryKey,
rotateRecoveryDeck,
unwrapRootWithRecoveryKey,
} from "@voideddev/enc-server";
const setup = createRecoveryDeck(stableRoot);
await displayForPhysicalBackup(setup.deck);
await saveOpaqueWrapper(setup.rootWrapper);
// Later: reconstruct the same root.
const recoveryKey = deriveRecoveryKey(enteredDeck);
const root = unwrapRootWithRecoveryKey(savedWrapper, recoveryKey);
// Secure rotation creates a wholly new random deck.
const next = rotateRecoveryDeck(savedWrapper, enteredDeck);
Secure rotation means a fresh random permutation
Manually changing a known deck creates a small, guessable neighborhood. Rotation must generate a completely new CSPRNG deck and replace the old wrapper.
Browser UI
The optional framework-free component opens as a modal with show() or mounts inline with mount(container). It supports card movement and a fresh secure shuffle; it does not impose a manual 52-card construction flow.
Use classNames, labels, renderCardContent, stable data attributes, or a fully application-owned stylesheet. Voided owns behavior; your product owns the experience.
Threats that matter
Brute force is not the practical concern. Screenshots, recording, photographs, clipboard exposure, malware, telemetry, crash reports, browser persistence, accidental sync, weak RNG, and memory copies are.
An attacker holding both an old deck and an offline copy of its old wrapper can still recover that old root. Rotation invalidates the active wrapper; it cannot revoke every copied historical wrapper in the world.
Operational guide
Security.
Voided narrows the cryptographic contract. Your application still owns authentication, authorization, trusted input boundaries, secret custody, and the runtime around it.
Treat keyless inspection as attacker-controlled metadata.
Use protect/open for normal application artifacts.
Zeroize mutable secret buffers after use.
Keep one browser lifecycle writer per key ID.
Keep Recovery Deck material out of logs, storage, analytics, and crash reports.
Run package integrity and current-platform smoke checks in release automation.
Do not do this
Do not authorize based on inspectArtifact output.
Do not reuse an AES-GCM nonce with the same key.
Do not assume a 256-bit KDF output adds entropy to weak input.
Do not enable compression across mixed attacker-controlled and secret values.
Do not interpret grouped fingerprints as an identity-binding safety-number protocol.
Do not treat browser IndexedDB as account recovery.
Failure behavior
Wrong keys, malformed structure, non-canonical inputs, oversized work, tampered tags, invalid algorithms, and unavailable required backends throw. Authenticated decryption does not stream plaintext before the tag verifies.
Errors are part of the API
Catch them at your trust boundary and return a generic failure to untrusted callers. Keep detailed internal diagnostics free of key material and plaintext.
Report a vulnerability
Use a private GitHub Security Advisory for suspected vulnerabilities. Include the affected package and version, platform, minimal reproduction, security impact, and whether any secret material was exposed. Do not post exploitable details in a public issue.
Select the actual failing boundary, run the narrow checks, and share a report containing evidence but no secret material.
Run focused checks
Choose the failing runtime and boundary. This produces commands, not a fake issue report. You decide what evidence is relevant after you see the output.
Compatibility
Safari / WebKitSupported
Current releases; verified browser WASM path.
ChromiumSupported
Current releases; verified browser WASM path.
FirefoxBest effort
Not a 1.0 release gate.
Node.js18+
CJS and ESM native package entry points.
macOS / LinuxVerified
macOS arm64 and Linux x64 GNU release paths.
WindowsRC
x64 MSVC provenance and hashes verified; real Windows execution pending.
Safe support boundary
Never attach secret material
Do not include plaintext, raw keys, Recovery Deck order, Recovery Key, stable root, unredacted environments, or crash dumps that may contain them.
Public integration failures belong in a minimal issue. Suspected vulnerabilities belong in a private security advisory.