> ## Documentation Index
> Fetch the complete documentation index at: https://docs.everabyte.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Wire protocol reference (evb-e2ee-v1)

> The exact bytes Everabyte zero-knowledge clients produce: EVB1 content framing, key hierarchy, envelope formats, wrap schemes and the versioning policy.

This page is the condensed, normative description of protocol `evb-e2ee-v1` — the wire format produced by the Everabyte apps and this SDK. Everything here happens **client-side only**; Everabyte's servers store the resulting bytes verbatim.

## 1. Content format EVB1

```text theme={null}
payload   = magic(4) || fileNonce(12) || block*        # header = 16 bytes
magic     = "EVB1" = 45 56 42 31
block     = ciphertext || tag(16)                      # AES-256-GCM output, ct||tag
```

* **Chunk plaintext size**: 64 KiB (65536), every chunk except the last; the last may be shorter. An **empty file still has exactly one empty chunk** (a lone 16-byte tag) — payload = 32 bytes.
* **fileNonce**: 12 random bytes per file. Bytes `[4..12]` are transported but **unused** by nonce derivation (v1 quirk, kept for wire compatibility).
* **chunkNonce(i)** = `fileNonce[0..4] || BE u64(i)` (12 bytes).
* **AAD(i)** = 8 bytes: `BE u32(i)` then 4 zero bytes. Chunk position is authenticated — reordering or splicing chunks fails the GCM tag.
* Decryption walks blocks sequentially; unknown magic, truncated tags and trailing garbage are hard errors.
* Minimum ciphertext for a plaintext of length *L*: `16 + L + 16*ceil(max(L,1)/65536)`.

## 2. Key hierarchy

```text theme={null}
UMK (User Master Key, 96 B, client-held)
 ├─ private_key_x25519 : 32 B  (X25519)
 ├─ seed_mlkem         : 64 B  (ML-KEM-768 d‖z, FIPS 203)
 ├─ public_key_x25519  : 32 B  = X25519(sk, base)
 └─ public_key_mlkem   : 1184 B
        │
DEK (per file, 32 B, never persisted)
 └─ AES-256-GCM file content
```

The server stores only: the UMK **public** keys, **wrapped** UMK blobs (mnemonic/device), and per-file DEK **envelopes**. Recovery-phrase loss plus loss of every enrolled device means the files are unreadable by anyone, including Everabyte.

## 3. DEK envelope — v2 (current)

HPKE RFC 9180 strict, **mode PSK**:

| Parameter | Value |
| - | - |
| KEM | DHKEM(X25519, HKDF-SHA256) — `kemId 0x0020` |
| KDF | HKDF-SHA256 — `kdfId 0x0001` |
| AEAD | AES-256-GCM — `aeadId 0x0003` |
| PSK | the ML-KEM-768 shared secret (32 B) |
| PSK ID | `"evb-mlkem768-v1"` |
| HPKE `info` and AEAD AAD | the scheme string `evb-e2ee-file-wrap-hpke-psk-v1` |

```json theme={null}
{
  "v": 2,
  "scheme": "evb-e2ee-file-wrap-hpke-psk-v1",
  "kemId": 32,
  "kdfId": 1,
  "aeadId": 3,
  "ephPublicX25519": "<b64(32)>",
  "kemCiphertext": "<b64(1088)>",
  "wrappedDek": "<b64(ct‖tag) = 48 bytes>"
}
```

The seal is one-shot at sequence 0: the AEAD nonce **is** the HPKE `base_nonce`, derived from the key schedule — no nonce is transported. Senders and receivers compute the same DHKEM shared secret with `kem_context = enc ‖ pkRm` on both sides.

## 4. DEK envelope — legacy v1 (read-only)

```json theme={null}
{
  "ephPublicX25519": "<b64(32)>",
  "kemCiphertext": "<b64(1088)>",
  "nonce": "<b64(12)>",
  "wrappedDek": "<b64(48)>"
}
```

Construction: `shared = X25519(skE, pkR)` and `kemShared = ML-KEM.encaps(pkMlkem)`; `wrapKey = HKDF-SHA256(shared ‖ kemShared, info="evb-e2ee-file-wrap-v1")`; `wrappedDek = AES-256-GCM(wrapKey, nonce, DEK)`. Envelopes without a `v` field are v1; every current client unwraps both. **New wraps must use v2.**

## 5. UMK wraps

All blobs are base64; framing is `nonce‖ct‖tag` (device) or `salt‖iv‖ct‖tag` (mnemonic). The plaintext of every UMK wrap is JSON with the four UMK fields (`publicKeyX25519`, `privateKeyX25519`, `publicKeyMlkem`, `seedMlkem`).

| Scheme id | Blob framing | KDF | Status |
| - | - | - | - |
| `evb-e2ee-umk-argon2id-m64-t2-p1-aesgcm` | salt16‖iv12‖ct‖tag | Argon2id v1.3, m=64 MiB, t=2, p=1 (RFC 9106) | current |
| `evb-e2ee-umk-argon2id-m64-t3-p4-aesgcm` | salt16‖iv12‖ct‖tag | Argon2id, RFC 9106 low-memory profile | readable |
| `evb-e2ee-umk-pbkdf2-sha512-100k-aesgcm` | salt16‖iv12‖ct‖tag | PBKDF2-HMAC-SHA512, 100k iterations | legacy, read-only |

Unwraps try the candidates in order and let the AES-GCM tag decide — the parameters that open a blob are by construction those it was sealed with. Phrases are NFKD-normalized, trimmed, lowercased and whitespace-collapsed first.

Device wraps derive the wrap key with `HKDF-SHA256(deviceSecret32, info="evb-e2ee-device-wrap-v1")` and frame as `nonce12‖ct‖tag`. The device secret is 32 random bytes kept exclusively on the device; the server sees only a label.

## 6. Names (metadata encryption)

* **Wire filename** (what the upload multipart carries): `evb-` + hex of `HMAC-SHA256(realName, key = SHA256(privateKeyX25519 ‖ seedMlkem))`. Deterministic — the same real name maps to the same alias, which keeps server-side duplicate detection working without revealing the name.
* **Encrypted display name**: `AES-256-GCM(realName, DEK)` transported as `b64(nonce12 ‖ ct ‖ tag16)` in the envelope attach (`encryptedName` field).

## 7. Sharing wraps

Symmetric wraps under a 32-byte link key (public links) or invitation key share (email invites):

```json theme={null}
{ "wrappedDek": "<b64(48)>", "nonce": "<b64(12)>" }
```

`wrapKey = HKDF-SHA256(key32, info)`, `info = evb-e2ee-link-wrap-v1` or `evb-e2ee-invite-wrap-v1`; AES-256-GCM over the DEK. The key travels only in the URL fragment and is never stored server-side.

## 8. Versioning policy

* Fields are added with defaults; nothing is renamed in place. A format change is a **new scheme id** (or a bumped `v`), shipped together with a dispatch path in every client.
* Interop contract: a client that cannot open a scheme must fail loudly, never reinterpret bytes.
* The frozen vector grid (`evb-e2ee-v1.json`) is the compatibility gate — every binding re-runs it in CI. Byte-exactness against RFC 9180 / NIST / RFC 5869 official vectors is tested separately from the grid.

For the full annotated specification, see `PROTOCOL.md` in the SDK repository — this page is its public summary.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.