Skip to content

About

Privacy-preserving health statistics using homomorphic encryption (CKKS) with a tamper-evident Oracle blockchain audit ledger

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Encrypted Health Ledger

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.

Why this exists

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.

What is guaranteed today (v1)

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)

Architecture

  • 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, and POST /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.

Key concepts

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.

Setup

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.

  1. 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;
  1. 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;"
  }
}
  1. Restore and run:
dotnet build
dotnet run --project EHL.Api

Open the Swagger UI at the URL shown in the console output.

API reference

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.

Real-time layer

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.

Verifying the ledger

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.

Known limitations

  • 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).

Roadmap

  1. Client-side encryption before submission, so plaintext never reaches the server.
  2. Persist ciphertexts and add per-clinic authentication and isolation.
  3. Batch aggregation instead of recomputing on every submit.
  4. Secrets management for database credentials.

What this project demonstrates

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.

About

Privacy-preserving health statistics using homomorphic encryption (CKKS) with a tamper-evident Oracle blockchain audit ledger

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages