Files
yvgude--lean-ctx/docs/contracts/personal-cloud-encryption-v1.md
wehub-resource-sync 26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:30 +08:00

3.1 KiB

personal-cloud-encryption-v1 — Zero-Knowledge Vaults (Knowledge + Gotchas)

Status: active (GL #467) · Engine: core/knowledge_vault.rs · Server: cloud_server/knowledge.rs (knowledge_blobs), cloud_server/gotchas.rs (gotcha_blobs)

Claim

For E2E surfaces, the Personal Cloud backend stores only ciphertext. We cannot read, search, sell or leak knowledge content — provably: the decryption key is derived from the account API key, of which the server only ever stores a SHA-256 hash.

Construction

Property Value
Cipher XChaCha20-Poly1305 (AEAD), 24-byte random nonce per seal
Key derivation HKDF-SHA256(salt=leanctx, ikm=API key, info=knowledge-vault-v1 | gotcha-vault-v1)
Domain separation distinct HKDF info per surface — the index-bundle key (index-bundle-v1), the knowledge-vault key and the gotcha-vault key can never open each other's blobs
Envelope {"v":1,"entries":[{category,key,value},…]}, serialized then sealed; wire format nonce ‖ ciphertext
Consistency whole-account snapshot, last-writer-wins (same model as hosted-personal-index-v1)

The key is identical on every logged-in device (stable API key, not the rotating OAuth token) — that is what makes cross-device pull work. Key rotation = new API key + one re-push from any device that has the local store.

Wire protocol (/api/sync/knowledge, /api/sync/gotchas)

Both routes speak the same dual wire format; each has its own blob table (knowledge_blobs / gotcha_blobs) and purges its own legacy table (knowledge_entries / gotchas).

Request Behaviour
POST Content-Type: application/octet-stream + X-Entry-Count: N store vault blob (≤ 8 MB), then delete the account's plaintext rows — the built-in re-encryption migration
POST Content-Type: application/json legacy plaintext upserts (deprecated; removed two releases after vault clients ship)
GET Accept: application/octet-stream encrypted vault blob; 404 when the account has none yet
GET (anything else) legacy plaintext listing

X-Entry-Count is a client-declared display metadatum (dashboards show counts and sizes); the server cannot verify it — by design.

Clients pull vault-first and fall back to the legacy listing on 404 or when an older server ignores the Accept header (detected via the response Content-Type).

What is deliberately NOT E2E

Surface Why it stays aggregate/plaintext
Commands / CEP / Gain stats numbers only (counts, token totals) — no content; they feed the savings dashboard and the opt-in leaderboard, which require server-side aggregation
Supporter / billing metadata Stripe-owned, never includes code or knowledge
Index bundles already E2E under hosted-personal-index-v1

Server obligations

  • Zero-content logging: sizes, hashes, counts — never payloads.
  • knowledge_blobs carries sha256 over the ciphertext for drift detection.
  • The legacy table stays queryable until the deprecation window closes, but any vault push purges that account's plaintext rows immediately.