Zero-knowledge sharing for the data that matters most.

CircleKey is a TypeScript library that end-to-end encrypts the data your users share with each other — and CircleKey Cloud is the backend to run it on. Keys are created on the device and stay there. Our servers hold ciphertext they have no way to open, and cannot see who is in a vault or what changed in it. It is the thinking behind Signal, reframed for the documents, credentials and records a team works on together.

npm install circlekey · MPL-2.0 · source on GitHub

A group vault re-keying after a member is removed Four people are linked to a central vault, each holding their own sealed copy of the vault key. One person is removed: they drift away, their link is severed, and the vault issues a fresh key to everyone who remains. GROUP VAULT
Remove someone and the vault re-keys itself. There is no new key waiting for them — not a permission flag on a server, but arithmetic.

The problem

Real protection is a cryptography problem, not a compliance checkbox.

Some of what your users share with each other is genuinely sensitive — health records, legal matters, financial documents, source material — and for that kind of data, your customers and their regulators expect provable protection, not a policy that promises it.

Delivering it means solving key management for a group, not a single user: who holds the key, what happens the moment somebody joins or is removed, and how a lost device gets recovered without a backdoor. Get any of that wrong and the exposure is yours — a database leak, a rogue administrator or a subpoena reaches straight through to the plaintext.

Building it correctly is months of specialist cryptographic work most product teams can’t staff or justify. CircleKey is that work, already done — so you can offer real end-to-end encryption without your team having to become cryptographers first.

What it is

A group vault your server cannot open.

A group vault is a shared space with its own keys, its own member list, and its own tamper-evident record of who was let in and who was removed. Your app calls a handful of methods. All the cryptography happens in the browser tab.

Keys are born on the device.

Every device generates its own keypair. Private keys never leave it and are never transmitted to any server — ours included. There is no key escrow, no “recovery copy” held on your infrastructure, and nothing for us to hand over.

A membership change re-keys the vault — and every device checks it.

Adding or removing someone produces a brand-new vault key, sealed individually to each remaining member’s devices. Remove someone and they are locked out from that moment on — not because a flag says so, but because they do not have the key. Each change also references the one before it in a signed chain, so every device verifies it independently: a compromised, hostile or subpoenaed server cannot forge a change, rewrite the past, or slip in an extra reader.

And the server can’t read the history either.

That whole chain — who joined, who was removed, who is a manager, what the policy says — is itself encrypted to the vault’s members. The backend stores fixed-size blobs it cannot open, all the same shape, so a join, a removal and a policy change are indistinguishable to it. It routes them without knowing what it is routing.

What your users get

Each of these is a normative requirement of the GroupVault Protocol, not a configuration option somebody can forget to switch on. The chips link to the clause.

Your server can’t read it. Neither can we.

Plaintext, vault keys and private keys never leave the device. What reaches storage is ciphertext plus the bookkeeping needed to route it. §5.1

Nobody can quietly change who’s in the vault.

Membership changes are signed and chained. Tampering, reordering and rollback are all detected independently by every client. §9.1

Phones, laptops, tablets — all covered.

Users link the devices they actually work on, and revoke a lost one on their own, without an administrator and without disturbing anybody else. §9.5

A lost device isn’t lost data.

Recovery is set up before the first vault opens, never bolted on afterwards. The library structurally refuses to proceed without it — there is no “skip for now”. §9.6

New members get the whole history.

Somebody who joins in month nine can read back to day one, the way joining a shared drive works — without anybody re-uploading or re-encrypting a thing. §9.7

The server can’t tell who’s in the vault.

Not just the contents: the membership, the roles, the policy and the type of every change are sealed too. Envelopes carry no addresses and every structure is padded to a fixed size, so counting them reveals nothing either. §5.8

Ten lines to an encrypted vault.

transport is your backend: CircleKey Cloud, or your own server against the documented interface. Everything else runs on the device.

import { GroupVault } from "circlekey";

// Opens (or restores) this user's identity on this device.
const vault = await GroupVault.open({ transport, userId: "alice" });

// Recovery is mandatory before any vault can be used. Show this
// credential to the user once — no server ever sees it.
const recoveryCredential = await vault.enrollBackup();

// Create a vault. The creator becomes its first manager. The id is
// generated here, not chosen — it is plaintext to the backend, so you
// keep your own label ("case 4417") against it locally.
const { group_id } = await vault.createGroup({ min_managers: 2 });

// Add a colleague, then write something only the two of you can read.
await vault.addMember(group_id, { userId: "bob", devicePubkey });
await vault.putJsonRecord(group_id, "note-1", { body: "…" });

// Bob leaves the matter. The vault re-keys; he keeps nothing new.
await vault.removeMember(group_id, "bob");

Who it’s for

Built for the teams who actually need this.

CircleKey is designed for the ten or twenty people who genuinely need access to something sensitive — and it is deliberately efficient at that size, because every membership change re-keys the vault for everybody in it. It is not built for broadcasting a secret to a hundred people. That isn’t a secret.

Health & clinical

A care team around one patient. Records that must not be readable by the vendor hosting them.

Legal

A matter, its documents, and the handful of people on it. Add counsel, remove them at close.

Finance & boards

Deal rooms, board packs, cap tables. Membership that changes and has to be provably auditable.

Journalism

Source material shared by a desk, where “our provider was compelled to hand it over” is not survivable.

HR & investigations

Casework a small panel can see and the rest of the company — and the IT department — cannot.

Security operations

Incident channels, credentials, response notes. Especially when the incident is your own infrastructure.

Straight answers

What our servers can and cannot see.

“The server knows nothing” is a claim we could not defend, so we don’t make it. Here is the split, field by field. The left column is short because the protocol keeps it short: the membership list, the governance history and the shape of every change are sealed before they reach any server, ours or yours.

◐ Visible to us, in plaintext

  • The vault’s identifier and its version counter
  • The vault’s size class — an upper bound like “up to 15 members”, never the membership
  • That a change happened, and when — never what kind of change
  • Record identifiers, which are derived and meaningless to us, and how many there are
  • Each record’s size bucket — roughly how much data, not how much
  • The salt and parameters on a recovery backup, stored under a blinded handle
  • Request metadata any host sees: IP address, user agent, timing

● Never received by us at all

  • Any plaintext your users write, of any kind
  • Who is in the vault — no user identifiers, device keys or manager flags
  • What any change did — a join, a removal and a policy edit are identical to us
  • Whether anyone was removed at all
  • The vault’s governance policy, or which device signed anything
  • Any vault key, per-record key, device private key or recovery credential
  • Anything that would let us decrypt, forge or join
Read plainly: a breach of our infrastructure reveals that a vault exists, how often it changes and roughly how much it holds — not who is in it, not what happened to it, and not one byte of the data. An attacker who owns our servers outright still cannot add themselves, because they hold no manager’s signing key and every client checks.

Identifiers are handled for you. Vault ids are generated on the device — random, meaningless, and not something your application gets to choose, so a vault cannot be called acme-acquisition-2026 where we can read it. Record names are hashed into opaque identifiers before they leave the device, so a filename never reaches us either. You keep your own labels locally and we never see them. The complete picture →

CircleKey Cloud

You write the app. We’ll hold the ciphertext.

The library is front-end only. Something still has to store the encrypted records and keep each vault’s history in order — a small service, but a real one to operate. So we operate it. From $29 a month, priced per vault, with a 14-day free trial.

And if you would rather run it yourself, the interface is documented, and there is an executable acceptance test you can point at your own implementation. Both doors are open on purpose — a backend you can leave is the only kind worth trusting.

Ship encryption you don’t have to apologise for.

The library is source-available and MPL-2.0 licensed, so your security team can read every line before you commit to it. The protocol underneath it is public. Nothing here depends on trusting us.