The data-in-use gap
Encryption protects data on disk and on the wire. Analytics needs the values themselves, so the server decrypts them first. That open moment is the gap.
Where a record is protected
- At rest: disk encryption.
- In transit: TLS.
- In use: decrypted in server memory to compute.
Removing names and ID numbers is not enough. Postcode, date of birth and sex together re-identify most people when joined with public records.
Locked everywhere except where it matters.
Behind the panel
Insiders, compromised hosts and memory-scraping malware can all read data while it is being computed on. This is the data-in-use gap.
A second problem is the linkage attack: quasi-identifiers such as postcode, date of birth and sex, joined with a public record, single a person out even when direct identifiers are removed. So we do both things: direct identifiers never leave the hospital, and everything the cloud stores for computing stays encrypted.
Add without unlocking
With an additively homomorphic cipher, multiplying two ciphertexts gives the encryption of the sum. The cloud adds locked values and returns a locked total. Only the hospital can open it.
The trick, with small numbers
- Hospital locks
- Enc(12) and Enc(30)
- Cloud multiplies
- Enc(12) × Enc(30)
- Hospital opens
- Dec( … ) = 42
I added it up. I never saw a number.
Behind the panel
Paillier
We use the Paillier cryptosystem: Enc(a) · Enc(b) mod n² decrypts to a + b. A fresh keypair is generated for every analytics campaign and the private key never leaves the hospital's own service. Key length is chosen per campaign, 1024 or 2048 bits.
Why not something heavier
Fully homomorphic encryption can compute more, but our benchmark put CKKS at about 617 GB for 2 million records at 2048 bits, against about 1 GB for Paillier. Sums, counts and averages need nothing more than addition, so we chose the narrowest scheme that does the job. The Cryptographic Design document has the benchmark.
Only totals leave
The hospital drops names, ID numbers, birth dates and postcodes, and encrypts every clinical and billing value. The cloud sees ciphertext and a few coarse labels. It only ever releases group totals.
What the cloud can see
- Public keys and ciphertext.
- Coarse labels: department, ward, month, age band.
- Names, ID numbers, birth dates, postcodes.
- Any measured value: stay, cost, vitals, outcome.
Groups smaller than the minimum size, 10 by default, are withheld so no individual can be singled out.
Departments, yes. People, never.
Behind the panel
Policy at the cloud
The cloud gateway enforces roles and a minimum group size (K_MIN, default 10). A result for a group below that size is refused rather than released.
Honest limit
The coarse labels are visible to the cloud by design, since it needs them to group. They are chosen so a single group has many records.
A receipt for every record
When the cloud stores your ciphertexts it signs a receipt: the root of a Merkle tree over every record it got. Drop, add or change one record and the root changes.
Edit one record, break the root
- Entry 2, as logged
- record 3 · oncology
- Entry 2, edited
- record 3 · oncology (changed)
This demo hashes short text labels. The real leaves are the stored ciphertext records.
Edit a record yourself in the gameChange one thing and every hash up shows it.
Behind the panel
What the hospital does
After upload, the hospital compares the cloud's signed Merkle root with the one it computed itself. Any single record can later be proven still stored as uploaded, from the Receipts page, with a Merkle proof.
Where the code lives
Record layout, leaf and Merkle hashing and the signatures live in one shared module, shared/protocol.js, used by the hospital agent, the cloud and the auditor's browser, so all three agree byte for byte.
Five checks, then decrypt
The hospital does not trust the cloud's answer. A result is accepted only when five independent checks all agree. Only then are the sums decrypted and charted.
Before anything is opened
SignatureThe result is signed by the cloud.
Board copyIt matches what the public log shows.
Input rootIt was computed over the records the hospital sent.
Record countNo record was left out or added.
RecomputeIt agrees with a recomputation from local plaintext.
Trust, but check five times.
Behind the panel
After the checks pass, the hospital decrypts the sums and publishes the decrypted value m together with the randomness r used in the ciphertext. Anyone can then check that gᵐ · rⁿ ≡ C (mod n²) with only public information, so even the hospital cannot misreport a result.
Anyone can audit
Every step goes on a signed, hash-chained public bulletin board. An auditor needs no key and no trust in the hospital or the cloud: the browser replays everything.
The four public checks
- The hash chain and every signature hold.
- Every Merkle root rebuilds from the published ciphertexts.
- Every encrypted sum recomputes.
- Every published plaintext matches its ciphertext.
Run all four from the Bulletin board page. They run in a Web Worker in your browser and use only public data.
Don't take my word. Run it yourself.
Behind the panel
Individual verifiability: the hospital proves its own records were stored as uploaded and used in its query. Universal verifiability: any auditor checks the signed log, rebuilds the input set, recomputes every encrypted sum and verifies every published result using public data only.
Catching a cheating cloud
The cloud can misbehave, but not silently. The app ships with a switch that makes it cheat on purpose, so you can watch the hospital and the auditor catch it.
Two ways to cheat, both caught
| The cloud… | Caught by |
|---|---|
| drops a record from a query | Record count and input root |
| doubles one ciphertext | The recomputation, and the auditor's sum check |
Run an analysis with the switch on and the hospital rejects it. Run the audit and the matching check fails.
I tried. It noticed.
Behind the panel
On the Monitor page an admin can turn on drop, which leaves a record out of each query, or tamper, which doubles one ciphertext. Neither can hide: dropping a record or changing a ciphertext alters a root, a count or an encrypted sum that someone is checking independently.
What we don't claim
This is an academic project. Here is what it does not do.
Not security-audited
It shows the design end to end. It is not cleared for real patient data.
No differential privacy yet
Released totals carry no noise. This is still to build.
One hospital only
Multi-hospital studies with threshold decryption are still to build.
Synthetic data
The 540,000 admissions are generated. No real patient data is used anywhere.