Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.lucid.foundation/llms.txt

Use this file to discover all available pages before exploring further.

The lucid_zkml_verifier program verifies Groth16 zero-knowledge proofs for ML model inference on Solana. It links verified proofs to inference receipts and uses a bloom filter to prevent duplicate verification. Program ID (devnet): 69cJRFGWijD1FdapQ2vz7VP6x2jcXRQyBws9VzzPpqAN

Instructions

InstructionDescription
register_modelRegister a model circuit with its Groth16 verifying key
verify_proofVerify a single proof against a registered model
verify_batchBatch verify up to 10 proofs
check_proofCheck if a proof was previously verified (bloom lookup)
init_bloomInitialize the bloom filter PDA

Account Structures

ModelCircuit

PDA seeds: ["model", model_hash] Stores the Groth16 verifying key components for a registered model.
FieldTypeDescription
model_hash[u8; 32]SHA-256 hash of the model
vk_alpha_g1[u8; 64]G1 point of verifying key
vk_beta_g2[u8; 128]G2 point of verifying key
vk_gamma_g2[u8; 128]G2 point
vk_delta_g2[u8; 128]G2 point
vk_icVec<[u8; 64]>IC points (length = nr_pubinputs + 1)
nr_pubinputsu8Number of public inputs (1-8)
ownerPubkeyModel registrant
registered_ati64Registration timestamp

VerifiedProof

Optional on-chain record for high-value proofs.
FieldTypeDescription
proof_hash[u8; 32]SHA-256 of proof components
model_hash[u8; 32]Associated model
receipt_hash[u8; 32]Linked inference receipt
verified_ati64Verification timestamp
verifierPubkeyVerifier’s public key

ProofBloomFilter

PDA seeds: ["bloom", authority] 16KB bloom filter with 7 hash functions for approximately 0.1% false positive rate at 10,000 proofs.
FieldTypeDescription
filter[u8; 2048]Bloom filter bits
proof_countu64Total proofs verified
last_updatedi64Last update timestamp
authorityPubkeyOnly this signer can submit proofs

Verification Flow

  1. Caller submits proof components (proof_a, proof_b, proof_c) and public inputs
  2. Program computes a deterministic proof hash from all components
  3. Bloom filter is checked for duplicates
  4. Proof components are validated (non-zero check)
  5. Bloom filter is updated with the new proof hash
  6. ProofVerified event is emitted with the linked receipt hash
await program.methods
  .verifyProof(
    proofA,         // [u8; 64]
    proofB,         // [u8; 128]
    proofC,         // [u8; 64]
    publicInputs,   // Vec<[u8; 32]>
    receiptHash     // [u8; 32]
  )
  .accounts({
    model: modelPda,
    bloom: bloomPda,
    verifier: wallet.publicKey,
  })
  .rpc();

Batch Verification

Verify up to 10 proofs in a single transaction for gas efficiency:
await program.methods
  .verifyBatch(proofs) // Vec<ProofData>, max 10
  .accounts({
    bloom: bloomPda,
    verifier: wallet.publicKey,
  })
  .rpc();

Bloom Filter Details

  • Size: 2048 bytes (16,384 bits)
  • Hash functions: 7 (double hashing: h(i) = (h1 + i * h2) mod bit_count)
  • False positive rate: ~0.1% at 10,000 proofs
  • Purpose: Prevents the same proof from being verified twice on-chain

Events

EventDescription
ModelRegisteredNew model circuit registered
ProofVerifiedSingle proof verified (includes proof_hash, model_hash, receipt_hash)
BatchVerifiedBatch of proofs verified
ProofCheckedBloom filter lookup result

Current Status

The Groth16 pairing check is currently a stub — proof components are validated for non-zero values and authority is checked, but the full e(-A, B) * e(alpha, beta) * e(vk_x, gamma) * e(C, delta) == 1 pairing equation is not yet computed on-chain. Full verification requires Solana’s alt_bn128 syscalls (available since v1.16). Only the bloom authority can submit proofs, preventing unauthorized verification while the pairing check is being finalized.