Skip to main content

Zero-Knowledge Proofs Integration

This document explains how Oneliac uses zero-knowledge proofs (ZK-SNARKs) to verify patient eligibility and prescription validity without exposing sensitive medical information.

What are Zero-Knowledge Proofs?

A zero-knowledge proof is a cryptographic method that allows one party (prover) to convince another party (verifier) that a statement is true without revealing the underlying data.

Key Properties

  • Completeness: Valid statements can always be proven
  • Soundness: Invalid statements cannot be proven
  • Zero-Knowledge: Proof reveals nothing beyond the statement's validity

ZK-SNARK Architecture in Oneliac

Oneliac uses Groth16, a specific ZK-SNARK scheme that:

  • Generates proofs ~200 bytes (compressed)
  • Performs fast proof verification (O(n) in circuit size)
  • Is production-ready and audited

Proof Generation Pipeline

Step 1: Circuit Definition (Circom)

Define logical constraints for:
- Patient eligibility rules
- Age requirements
- Insurance coverage rules

Step 2: Private Inputs

patient_id (encrypted)
medical_history_hash (SHA256)

Step 3: Public Inputs

procedure_code (PROC001, PROC002)
insurance_provider_id (INS123)
required_age (18)

Step 4: Circuit Compilation

Convert circuit to rank-1 constraint system (R1CS)

Step 5: Witness Generation

Compute satisfying assignments for constraints

Step 6: Proof Generation (Groth16)

Generate cryptographic proof
Output: 256-byte proof

Step 7: Blockchain Submission

Submit proof + public inputs to Solana

Step 8: On-Chain Verification

Smart contract verifies proof
Returns: eligible (true/false)

Eligibility Verification Circuit

Logical Rules

The eligibility circuit verifies:

  1. Patient Identity: hash(patient_id + nonce) == committed_hash
  2. Age Requirement: age >= 18
  3. Medical History: hash(medical_history) == provided_hash
  4. Coverage Rule: procedure_code in coverage_database

Circuit Pseudocode (Circom)

template EligibilityChecker() {
// Private inputs - kept secret
signal private input patientID;
signal private input medicalHistoryHash;

// Public inputs - revealed
signal input procedureCode;
signal input insuranceProviderID;
signal input requiredAge;

// Outputs
signal output eligibility;

// Constraints
component hashCheck = PoseidonHash(2);
hashCheck.inputs[0] <== patientID;
hashCheck.inputs[1] <== medicalHistoryHash;
// hashCheck.out == stored_commitment

// Age verification (assume age is derived from medicalHistoryHash)
// requiredAge <= derivedAge

// Coverage verification
// procedureCode must be in authorized list

eligibility <== 1; // Valid if all constraints satisfied
}

Prescription Validation Circuit

Similar to eligibility, but adds:

  • Drug interaction checking
  • Pharmacy verification constraints
  • Dosage validation rules

Circuit Constraint Example

// Ensure drug is not contraindicated
signal hasContraindication <== drugContraindicationCheck(
drugCode,
medicalHistoryHash
);
signal validPrescription <== 1 - hasContraindication;

Implementation in Oneliac

ZKProofGenerator Class

class ZKProofGenerator:
def __init__(self, circuit_path: str):
self.circuit_path = circuit_path # Path to compiled circuit

async def generate_proof(
self,
private_inputs: Dict,
public_inputs: Dict
) -> bytes:
"""
Generate a Groth16 ZK proof.

Args:
private_inputs: {
"patientID": "patient_123",
"medicalHistoryHash": "abc123..."
}
public_inputs: {
"procedureCode": "PROC001",
"insuranceProviderID": "INS123"
}

Returns:
256-byte Groth16 proof
"""
# Witness generation
witness = await self._generate_witness(
private_inputs,
public_inputs
)

# Proof generation
proof = self._groth16_prove(witness)

return proof

async def verify_proof(
self,
proof: bytes,
public_inputs: Dict
) -> bool:
"""
Verify a Groth16 proof.

Args:
proof: 256-byte proof from generate_proof
public_inputs: Public inputs used in proof

Returns:
True if proof is valid, False otherwise
"""
vkey = self._load_verification_key()
return vkey.verify(proof, public_inputs)

Proof Submission to Blockchain

async def _submit_to_blockchain(
self,
proof: bytes,
public_inputs: Dict,
ipfs_hash: str
) -> bool:
"""Submit ZK proof to Solana smart contract."""
payload = {
"proof": proof.hex(),
"public_inputs": json.dumps(public_inputs),
"ipfs_hash": ipfs_hash # Link to patient data
}

# Call smart contract via RPC
async with aiohttp.ClientSession() as session:
response = await session.post(
f"{self.solana_endpoint}/verify",
json=payload
)

return response.status == 200

Proof Lifecycle

Client Generates Request

Patient Data: encrypted
Procedure Code: PROC001


Oneliac API Receives Request

Extract Private Inputs
- patient_id
- medical_history_hash

Extract Public Inputs
- procedure_code
- insurance_provider_id


Generate ZK Proof
(256-byte Groth16 proof)


Submit to Blockchain
- Proof
- Public inputs
- IPFS hash reference


Smart Contract Verifies
- Proof verification
- Record transaction
- Emit event


Return Result to Client
- Eligibility status
- Coverage percentage
- zk_proof_verified: true

Security Analysis

Threat Model

ThreatMitigationProof
Medical data exposureEncrypted storage + ZK proofProof never reveals plaintext data
Patient ID linkageHash with nonceDifferent nonces → different proofs
Proof forgeryGroth16 cryptographic securityComputationally infeasible to forge
Proof replayOn-chain timestamp + nonceEach proof is unique
Collusion attackTrusted setup ceremonyOnly possible with trusted setup compromise

Assumptions

  1. Trusted Setup: Groth16 requires a trusted setup. Oneliac uses audited ceremony results.
  2. Cryptographic Hardness: Assumes discrete log problem is hard
  3. Correct Circuit: Circuit must accurately encode business logic
  4. Private Key Security: Encryption keys must be kept secret

Performance Characteristics

OperationTimeSizeNotes
Proof Generation100-500msN/ACPU-bound, pre-computed possible
Proof SizeN/A256 bytesIndependent of circuit size (Groth16)
Proof Verification10-50msN/AFast, suitable for on-chain
Circuit Compilation~10sN/AOne-time, offline

Best Practices

For Developers

  1. Verify Circuit Logic: Test all edge cases in circuit constraints
  2. Randomize Proofs: Use unique nonces to prevent replay attacks
  3. Store Commitments: Hash sensitive data before ZK proof generation
  4. Audit Circuits: Have security experts review constraint definitions

For Healthcare Providers

  1. Encrypt Data: Always encrypt patient data before transmission
  2. Verify Proofs: Check zk_proof_verified field in responses
  3. Audit Trail: Review blockchain transaction history
  4. Key Management: Securely store encryption keys

Limitations

  1. Large Inputs: Complex circuits require more constraints (slower generation)
  2. Privacy Trade-off: Public inputs are visible on blockchain
  3. Proof Size: Unlike STARKs, Groth16 proofs don't scale to millions of constraints
  4. Trusted Setup: Requires initial trusted ceremony

Next Steps