Skip to content
cura

One idea: prove the answer, keep the record.

Three parts: your vault, a proof and a consent contract.

The three parts

On your device
The vault
The proof
proof · 256 bytes
On-chain
The consent contract
eligible · nullifier
At the lab
A count of eligible participants, then only the consented fields
consented fields, encrypted to the lab’s key

The vault

Encrypted on your device with a key from your wallet. Cura can host it, not read it.

The proof

Criteria are public inputs, your values private. Output: one bit and a nullifier.

The consent contract

Records who reads which fields until when, pays rewards and enforces revocation.

One study, one record, one bit

What the circuit sees. The middle column never leaves the device.

Criterion (public input)Circuit
Age between 40 and 7052satisfied
Diagnosis: type 2 diabetesYes, since 2019satisfied
HbA1c between 6.5 and 9.0 %7.1 %satisfied
Systolic blood pressure ≥ 130138 mmHgsatisfied

Public outputs

eligible = 1

nullifier = hash(vault key, study id)

A failed criterion produces no proof, and nothing is sent.

The life of a consent

  1. Granted

    Signed with the proof. The lab gets a key to the named fields.

  2. Active

    Rewards accrue from the study’s escrow. Every read is logged.

  3. Narrowed

    Untick a field; the lab’s key drops it next block.

  4. Revoked or expired

    Access and rewards end. Computed aggregates stay.

What keeps the exchange honest

Nullifiers

Stop a second enrolment without knowing who you are. Two studies can’t link you.

Minimum cohort size

Counts are rounded to 10 and hidden below the council’s threshold.

Audit trail

Every proof, consent, read and payment is logged with its block.

The council

Contributors vote on the rules anonymously: one member, one vote.

Built around the principles, not claiming the certificate

Minimisation
Eligibility is one bit; fields are shared only when named.
Specific consent
One slip per study, listing fields and an end date.
Withdrawal
Revocation is one signature and takes effect on-chain.
Accountability
An append-only audit trail anyone involved can read.

This demo is not certified under HIPAA, GDPR or Law 25, and is not legal advice.

The contract surface, and where the demo fakes it

The simulated layer in src/lib/demo mirrors the calls a real deployment makes.

Show the contract interface
interface ICuraConsent {
  /// Verify an eligibility proof and record a consent slip.
  function enrol(
    bytes32 studyId,
    bytes calldata proof,     // 256 bytes, Groth16
    bytes32 nullifier,        // hash(vaultKey, studyId)
    uint16  fieldMask,        // fields the slip covers
    uint64  expiresAt
  ) external returns (bytes32 consentId);

  function narrow(bytes32 consentId, uint16 fieldMask) external;
  function revoke(bytes32 consentId) external;
  function claim(bytes32[] calldata consentIds) external;

  event Enrolled(bytes32 indexed studyId, bytes32 consentId, bytes32 nullifier);
  event Revoked(bytes32 indexed consentId, uint64 atBlock);
}

Demo module → real counterpart

  • prover.ts

    Circuit compiled to WASM, proving in a Web Worker

  • chain.ts

    wagmi writeContract + waitForTransactionReceipt

  • store.ts

    Contract events indexed by a subgraph

  • population.ts

    Aggregated, noise-added cohort counts

Now watch it happen.

Try the demo