Plug Kanon into a Credo agent in five minutes.
The plugin registers the Kanon AnonCreds VDR, wraps the verifier service for on-chain status checks, and subscribes to issuance events. You write zero AnonCreds plumbing.
Add the plugin to your backend.
@credo-ts/kanon is a first-party Credo 0.6+ module. The package works with any EVM RPC — Besu, Ethereum mainnet, L2s, private rollups. You need ethers v6.
"@credo-ts/anoncreds": "0.6.1","@credo-ts/core": "0.6.1","@credo-ts/kanon": "^0.1.0","ethers": "^6.13.0",
Register KanonModule with your AnonCredsModule.
Pass the kanonv2 contract address for AnonCredsStatusRegistry. The plugin replaces the default AnonCredsVerifierService with one that ANDs the on-chain status check.
import { Agent } from '@credo-ts/core'import { AnonCredsModule } from '@credo-ts/anoncreds'import { KanonModule, KanonAnonCredsRegistry } from '@credo-ts/kanon'const agent = new Agent({modules: {anoncreds: new AnonCredsModule({registries: [new KanonAnonCredsRegistry()],}),kanon: new KanonModule({networks: [{ network: 'besu', rpcUrl, privateKey }],anonCredsStatusRegistryAddress: '0x…',}),},})
Write your attrNames. The plugin handles the rest.
Pass your normal AnonCreds schema to buildKanonSchema. The plugin transparently adds the bookkeeping attribute needed for on-chain status lookup — you never type it.
import { buildKanonSchema } from '@credo-ts/kanon'await agent.modules.anoncreds.registerSchema({schema: buildKanonSchema({name: 'DriverLicense',version: '1.0',attrNames: ['fullName', 'dateOfBirth', 'licenseNumber'],issuerId: did,}),})
Pass your attributes. The plugin adds the credId.
buildKanonCredentialAttributes prepends a fresh UUID for the bookkeeping field. The event listener writes issueCredential(credDefId, credIdHash) when the credential reaches state 'done' — you don't touch the chain.
import { buildKanonCredentialAttributes } from '@credo-ts/kanon'const { attributes } = buildKanonCredentialAttributes([{ name: 'fullName', value: 'Jane Doe' },{ name: 'dateOfBirth', value: '1990-04-12' },{ name: 'licenseNumber', value: 'NY-441-AAA' },])await agent.modules.anoncreds.acceptCredentialOffer({credentialRecordId,credentialFormats: { anoncreds: { attributes } },})
Wrap your proof request. Get on-chain status for free.
buildKanonProofRequest adds the bookkeeping attribute to your proof request for each Kanon credDef. The wrapped AnonCredsVerifierService then runs anoncreds-rs and the on-chain isRevoked lookup — both must pass for isValid to be true.
import { buildKanonProofRequest } from '@credo-ts/kanon'const proofRequest = buildKanonProofRequest({name: 'age check',version: '1.0',requested_attributes: {fullName: { name: 'fullName', restrictions: [{ cred_def_id }] },},kanonCredDefIds: [cred_def_id],})// verifyProof returns true only if both the AnonCreds CL proof// and the on-chain status lookup pass.
One transaction. No tails file.
Call revokeCredentialOnChain on the registry. The issuer's signer must be a member of the credDef's issuing org. The next verifier check returns 'revoked' on the very next call.
import { KanonAnonCredsRegistry } from '@credo-ts/kanon'const registry = agent.dependencyManager.resolve(KanonAnonCredsRegistry)await registry.revokeCredentialOnChain(agentContext,credDefId,credId,)
kanonCredIdHash — internal.
Internal hash used as the on-chain registry key. The helpers above call it for you; you'll only need this if you're building tooling that talks to the contract directly.
import { kanonCredIdHash } from '@credo-ts/kanon'// keccak256 of the utf-8 encodingkanonCredIdHash('a3f4-…-9d2b')// '0x4a…b2'
Need the optional ZK mode?
Mode B replaces the AnonCreds presentation with a Groth16 SNARK for unlinkable verification. See the architecture page for the circuit and verifier registry.