A privacy-preserving statistics service that computes aggregate health data (sums, averages, variance) directly on homomorphically encrypted values. Every operation is logged to a tamper-evident Oracle blockchain table so the process is independently auditable, without the log ever containing the underlying data.
Status: working v1 prototype. The server computes on ciphertext, but in v1 it also performs the initial encryption of incoming values, so it is not yet fully server-blind. See Known limitations and Roadmap.
Most "privacy" systems protect data at rest and in transit, but decrypt it the moment computation happens. This project explores a different guarantee: computation on encrypted data, where the server produces correct aggregate statistics without ever holding a decryption key for the stored values.
It pairs that with a second, complementary guarantee: every submission and computation is logged to an append-only, hash-chained table, so anyone can verify that the reported process happened as claimed, without the log containing sensitive data.
| Property | v1 status |
|---|---|
| Aggregates (sum, sum of squares, average) are computed on ciphertext | Yes |
| The server never holds the secret key; only the client can decrypt results | Yes |
| The server never sees plaintext | No. In v1 the API encrypts incoming values, so plaintext briefly exists in request bodies and server memory |
| Audit log is tamper-evident | Yes (Oracle blockchain table, SHA2-512 hash chain) |
| Audit log contains no sensitive values | Yes (event type and a hash of the ciphertext only) |
- EHL.Crypto: a C# wrapper around Microsoft SEAL implementing CKKS homomorphic encryption: encrypt, add, multiply, multiply-by-constant (used for division), and decrypt.
- EHL.Client: a console app representing the clinic. Generates and holds its own CKKS key pair and is the only component that ever decrypts results.
- EHL.Api: an ASP.NET Core Web API exposing
POST /submit,GET /average, andPOST /register-keys, plus a SignalR hub (/statshub) that pushes live encrypted statistics to connected clients after every submission. Statistics are computed with homomorphic addition and multiplication on serialized ciphertext, and the API holds no secret key. - EHL.Ledger: a thin data-access layer writing audit events to an Oracle 26ai Free blockchain table.
- Oracle blockchain table: an append-only, SHA2-512 hash-chained table logging every submission and computation as an event type plus a hash of the ciphertext involved. No plaintext or ciphertext values are stored in the ledger.
CKKS vs BFV. CKKS supports approximate arithmetic on real numbers (used here for values like cholesterol readings). BFV supports exact arithmetic on integers. This project uses CKKS throughout because health statistics are naturally real-valued.
Noise and modulus-chain levels. Every homomorphic operation adds numerical error. Addition adds very little; ciphertext-by-ciphertext multiplication adds substantially more (about 70x more drift than an addition in testing). CKKS does not expose a BFV-style noise budget; remaining headroom shows up as the number of levels left in the modulus chain. In testing, after 5 submissions the plain sum sat at chain level 2 while the sum of squares, which needed one extra multiplication and rescale, sat at level 1. This project keeps computation depth shallow (a handful of additions plus one constant multiplication) to avoid bootstrapping.
Relinearization. Multiplying two ciphertexts grows their internal size; relinearization (using separate RelinKeys) compresses the result back down. This is a size/performance cost, distinct from noise growth.
Division by a public constant. CKKS has no native division. Averaging multiplies the encrypted sum by the plaintext constant 1/n, where n (the submission count) is public, not sensitive.
Variance via sum of squares. Alongside the running encrypted sum (Σx), the server maintains an encrypted sum of squares (Σx²). The client decrypts both and derives variance = (Σx²/n) − mean² locally, since CKKS cannot compare values on ciphertext.
Blockchain table, precisely. Oracle's blockchain table is a centralized, tamper-evident, insert-only ledger: rows are hash-chained so any modification breaks verification. It is not a decentralized network with consensus among untrusted parties. The guarantee is tamper-evidence within a trusted database.
Prerequisites: .NET 8 SDK, Oracle 26ai Free (or any Oracle instance with blockchain table support), and a JDK if using SQL Developer/SQLcl for manual queries.
- Create the Oracle schema and table:
CREATE USER ehl_user IDENTIFIED BY "YourStrongPassword";
GRANT CONNECT, RESOURCE, DBA TO ehl_user;
ALTER USER ehl_user QUOTA UNLIMITED ON USERS;Connect as ehl_user, then:
CREATE BLOCKCHAIN TABLE ehl_audit_log (
event_id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
event_type VARCHAR2(30) NOT NULL,
ciphertext_hash VARCHAR2(64) NOT NULL,
event_timestamp TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
)
NO DROP UNTIL 0 DAYS IDLE
NO DELETE LOCKED
HASHING USING SHA2_512 VERSION V1;- Configure the connection string in
EHL.Api/appsettings.json(development only; see limitations):
{
"ConnectionStrings": {
"OracleLedger": "User Id=ehl_user;Password=YOUR_PASSWORD_HERE;Data Source=localhost:1521/freepdb1;"
}
}- Restore and run:
dotnet build
dotnet run --project EHL.ApiOpen the Swagger UI at the URL shown in the console output.
POST /api/HealthStats/submit
{ "ciphertextBase64": "<base64-encoded ciphertext>" }Stores the ciphertext and logs a SUBMIT event to the ledger.
{ "message": "Submitted", "totalCount": 1 }GET /api/HealthStats/average
Computes the homomorphic average of all submitted values on ciphertext and logs a COMPUTE_AVERAGE event to the ledger.
{ "encryptedAverageBase64": "<base64-encoded ciphertext>", "basedOnCount": 4 }The result is returned encrypted. Only a client holding the matching secret key (generated in EHL.Client) can decrypt it.
Clients register their non-secret relinearization keys once via POST /api/HealthStats/register-keys, then connect to the /statshub SignalR hub. After each submission the server pushes a StatsUpdated event containing the encrypted sum, encrypted sum of squares, and current count. Only the connected client, holding the matching secret key, can decrypt these values and derive live mean, standard deviation, and modulus-chain-level diagnostics.
DECLARE
verified_rows NUMBER;
BEGIN
DBMS_BLOCKCHAIN_TABLE.VERIFY_ROWS(
schema_name => 'EHL_USER',
table_name => 'EHL_AUDIT_LOG',
number_of_rows_verified => verified_rows
);
DBMS_OUTPUT.PUT_LINE('Verified rows: ' || verified_rows);
END;
/No error and a row count matching your total events confirms the chain is intact.
- Server-side initial encryption (v1). The API encrypts values it receives, so plaintext briefly exists in request bodies and server memory. The server therefore is not yet fully server-blind.
- In-memory ciphertext storage. Submitted ciphertexts are not persisted; restarting the API loses them. The audit log persists independently in Oracle.
- Single-tenant. No authentication or per-clinic isolation yet; all submissions are pooled into one running average.
- Development connection string. The Oracle password is stored in plaintext in
appsettings.json. Beyond local development, move it to environment variables, user secrets, or a secrets manager. - Recomputation on every submission. The server recalculates the full running sum and sum of squares on every submit. Fine at small scale; at high volume it would need batching.
- Centralized ledger. Tamper-evidence, not decentralization (see Key concepts).
- Client-side encryption before submission, so plaintext never reaches the server.
- Persist ciphertexts and add per-clinic authentication and isolation.
- Batch aggregation instead of recomputing on every submit.
- Secrets management for database credentials.
Homomorphic encryption (CKKS via Microsoft SEAL) and Oracle blockchain tables solve two different, complementary problems: computing on data without decrypting it, and proving what happened without exposing what it was. Together they sketch a pattern for domains such as healthcare, finance, and compliance, where both confidentiality and auditability matter.