SDK Reference

generateProof()

Run the Althea Groth16 circuit inside the user's browser. The circuit validates the credential, the age, and the ID type - then outputs a zero-knowledge proof and a nullifier. The credential is wiped from memory before this function returns.

Signature

generateProof(credential: SignedCredential): Promise<ZKProof>

What this function does

  1. Validates the credential object shape.
  2. Loads afrzk.wasm from the SDK bundle (≈ 240 KB, cached after first load).
  3. Runs snarkjs.groth16.fullProve() with the credential as private input.
  4. The circuit validates: signature, age ≥ 18, and idType is 1 or 2.
  5. Verifies the proof locally with snarkjs.groth16.verify() before returning. A circuit bug or tampered WASM is caught here.
  6. Wipes the credential from memory - sets every field to zero - so the original NIN hash cannot be recovered.
  7. Returns the proof and public signals.

Proof generation is expensive

Groth16 proof generation takes 3–8 seconds depending on device. Show a clear loading state. Do not call generateProof() more than once per verification flow - fail loudly if a user tries to retry without restarting from verifyIdentity().

Returns

A ZKProof object containing a Groth16 proof and the public signals the verifier checks.

ZKProof
type ZKProof = {
  proof: {
    pi_a: [string, string, string]
    pi_b: [[string, string], [string, string], [string, string]]
    pi_c: [string, string, string]
    protocol: 'groth16'
    curve: 'bn128'
  }
  publicSignals: [string, string]
  // [0] = valid (1 if all circuit checks passed, 0 otherwise)
  // [1] = nullifier (one-way hash, deduplication key)
}

Public signals

IndexValueDescription
0'1' | '0'valid — '1' means all three in-circuit checks passed
1stringnullifier — a Poseidon hash of the idHash; unique per identity, unlinkable to the underlying ID

Example

generate-proof-example.ts
import { verifyIdentity, generateProof } from 'afrzk-sdk'

const credential = await verifyIdentity({
  idType: 'NIN',
  idNumber: nin,
  dob,
})

const proof = await generateProof(credential)
// credential fields have been zeroed and the object reference is no longer
// safe to use - it is a wiped husk by design.

if (proof.publicSignals[0] !== '1') {
  throw new Error('Circuit rejected the credential')
}

console.log('Nullifier:', proof.publicSignals[1])

Errors

MessageCause
Invalid credential shapecredential is missing fields or has wrong types
Circuit constraints failedAge < 18, signature invalid, or idType is not 1 or 2
WASM failed to loadNetwork/blob fetch error or CSP blocking wasm-unsafe-eval
Local verification failedGenerated proof does not verify — indicates a corrupt circuit; do NOT submit

Performance benchmarks

Device classApproximate proof time
Desktop (M1+ / Ryzen 5+)1.8s – 2.4s
Modern laptop (Intel 11th gen)3.0s – 4.0s
Mid-tier Android (2022)4.5s – 6.5s
Older Android (2018)7.5s – 11s

See also