Skip to main content
AnonCreds is a privacy-preserving verifiable credential system that supports zero-knowledge proofs, selective disclosure, and advanced cryptography for identity verification.

Overview

AnonCreds provides:
  • Zero-knowledge proofs - Prove attributes without revealing them
  • Selective disclosure - Share only required attributes
  • Predicate proofs - Prove conditions (e.g., age > 18) without revealing exact values
  • Revocation - Support for credential revocation
  • Multi-ledger support - Works with Indy, Cheqd, Hedera, and more

Installation

npm install @credo-ts/anoncreds @hyperledger/anoncreds-nodejs
For specific registries:
# Hyperledger Indy
npm install @credo-ts/indy-vdr @hyperledger/indy-vdr-nodejs

# Cheqd
npm install @credo-ts/cheqd

# Hedera
npm install @credo-ts/hedera

Basic Setup

import { Agent } from '@credo-ts/core'
import { AnonCredsModule } from '@credo-ts/anoncreds'
import { anoncreds } from '@hyperledger/anoncreds-nodejs'
import { IndyVdrAnonCredsRegistry, IndyVdrModule } from '@credo-ts/indy-vdr'
import { indyVdr } from '@hyperledger/indy-vdr-nodejs'
import { agentDependencies } from '@credo-ts/node'

const agent = new Agent({
  config: {},
  dependencies: agentDependencies,
  modules: {
    anoncreds: new AnonCredsModule({
      registries: [new IndyVdrAnonCredsRegistry()],
      anoncreds,
    }),
    indyVdr: new IndyVdrModule({
      indyVdr,
      networks: [
        {
          genesisTransactions: '<genesis-file-content>',
          indyNamespace: 'bcovrin:test',
          isProduction: false,
          connectOnStartup: true,
        },
      ],
    }),
  },
})

await agent.initialize()

Multi-Registry Setup

Credo supports multiple AnonCreds registries simultaneously:
import { AnonCredsModule } from '@credo-ts/anoncreds'
import { IndyVdrAnonCredsRegistry } from '@credo-ts/indy-vdr'
import { CheqdAnonCredsRegistry, CheqdModule } from '@credo-ts/cheqd'
import { HederaAnonCredsRegistry, HederaModule } from '@credo-ts/hedera'

const agent = new Agent({
  config: {},
  dependencies: agentDependencies,
  modules: {
    anoncreds: new AnonCredsModule({
      registries: [
        new IndyVdrAnonCredsRegistry(),
        new CheqdAnonCredsRegistry(),
        new HederaAnonCredsRegistry(),
      ],
      anoncreds,
    }),
    indyVdr: new IndyVdrModule({ /* config */ }),
    cheqd: new CheqdModule({ /* config */ }),
    hedera: new HederaModule({ /* config */ }),
  },
})

Creating Schemas

1
Import or Create a DID
2
You need a DID to act as the issuer:
3
import { TypedArrayEncoder } from '@credo-ts/core'
import { transformPrivateKeyToPrivateJwk } from '@credo-ts/askar'

const { privateJwk } = transformPrivateKeyToPrivateJwk({
  type: { crv: 'Ed25519', kty: 'OKP' },
  privateKey: TypedArrayEncoder.fromString('my-secure-seed-32-characters!!'),
})

const { keyId } = await agent.kms.importKey({ privateJwk })

await agent.dids.import({
  did: 'did:indy:bcovrin:test:AHJzHqBc9tvv3E9Z2dzyPN',
  overwrite: true,
  keys: [{ didDocumentRelativeKeyId: '#verkey', kmsKeyId: keyId }],
})

const issuerId = 'did:indy:bcovrin:test:AHJzHqBc9tvv3E9Z2dzyPN'
4
Register a Schema
5
import type { IndyVdrRegisterSchemaOptions } from '@credo-ts/indy-vdr'

const { schemaState } = await agent.modules.anoncreds.registerSchema<IndyVdrRegisterSchemaOptions>({
  schema: {
    name: 'UniversityDegree',
    version: '1.0.0',
    attrNames: ['name', 'degree', 'graduation_date'],
    issuerId,
  },
  options: {
    endorserMode: 'internal',
    endorserDid: issuerId,
  },
})

if (schemaState.state === 'finished') {
  console.log('Schema ID:', schemaState.schemaId)
} else {
  console.error('Schema registration failed:', schemaState.reason)
}

Creating Credential Definitions

After registering a schema, create a credential definition:
import type { IndyVdrRegisterCredentialDefinitionOptions } from '@credo-ts/indy-vdr'

const { credentialDefinitionState } = 
  await agent.modules.anoncreds.registerCredentialDefinition<IndyVdrRegisterCredentialDefinitionOptions>({
    credentialDefinition: {
      schemaId: schemaState.schemaId,
      issuerId,
      tag: 'latest',
    },
    options: {
      supportRevocation: false,
      endorserMode: 'internal',
      endorserDid: issuerId,
    },
  })

if (credentialDefinitionState.state === 'finished') {
  console.log('Credential Definition ID:', credentialDefinitionState.credentialDefinitionId)
}

Issuing Credentials with DIDComm

import {
  DidCommModule,
  DidCommCredentialV2Protocol,
} from '@credo-ts/didcomm'
import { AnonCredsDidCommCredentialFormatService } from '@credo-ts/anoncreds'

const agent = new Agent({
  config: {},
  dependencies: agentDependencies,
  modules: {
    anoncreds: new AnonCredsModule({
      registries: [new IndyVdrAnonCredsRegistry()],
      anoncreds,
    }),
    didcomm: new DidCommModule({
      credentials: {
        credentialProtocols: [
          new DidCommCredentialV2Protocol({
            credentialFormats: [
              new AnonCredsDidCommCredentialFormatService(),
            ],
          }),
        ],
      },
    }),
  },
})

// Offer credential
await agent.didcomm.credentials.offerCredential({
  connectionId: connectionRecord.id,
  protocolVersion: 'v2',
  credentialFormats: {
    anoncreds: {
      credentialDefinitionId: credentialDefinitionState.credentialDefinitionId,
      attributes: [
        { name: 'name', value: 'Alice Smith' },
        { name: 'degree', value: 'Computer Science' },
        { name: 'graduation_date', value: '2024-05-15' },
      ],
    },
  },
})

Accepting Credentials (Holder)

Before accepting credentials, create a link secret (once per wallet):
await agent.modules.anoncreds.createLinkSecret()

Accept Credential Offer

await agent.didcomm.credentials.acceptOffer({
  credentialExchangeRecordId: credentialRecord.id,
})

Requesting Proofs

Request proof of credentials with various constraints:

Basic Proof Request

await agent.didcomm.proofs.requestProof({
  connectionId: connectionRecord.id,
  protocolVersion: 'v2',
  proofFormats: {
    anoncreds: {
      name: 'degree-verification',
      version: '1.0',
      requested_attributes: {
        name: {
          name: 'name',
          restrictions: [
            { cred_def_id: credentialDefinitionId },
          ],
        },
        degree: {
          name: 'degree',
          restrictions: [
            { cred_def_id: credentialDefinitionId },
          ],
        },
      },
    },
  },
})

Proof with Predicates

Prove conditions without revealing exact values:
await agent.didcomm.proofs.requestProof({
  connectionId: connectionRecord.id,
  protocolVersion: 'v2',
  proofFormats: {
    anoncreds: {
      name: 'age-verification',
      version: '1.0',
      requested_predicates: {
        age_over_18: {
          name: 'age',
          p_type: '>=',
          p_value: 18,
          restrictions: [
            { cred_def_id: credentialDefinitionId },
          ],
        },
      },
    },
  },
})
Available predicate types:
  • >= - Greater than or equal
  • > - Greater than
  • <= - Less than or equal
  • < - Less than

Presenting Proofs (Holder)

Select Credentials for Proof

const requestedCredentials = await agent.didcomm.proofs.selectCredentialsForRequest({
  proofExchangeRecordId: proofRecord.id,
})

Accept Proof Request

await agent.didcomm.proofs.acceptRequest({
  proofExchangeRecordId: proofRecord.id,
  proofFormats: requestedCredentials.proofFormats,
})

Revocation Support

Enable credential revocation:

Create Revocation Registry

const { credentialDefinitionState } = 
  await agent.modules.anoncreds.registerCredentialDefinition({
    credentialDefinition: {
      schemaId: schemaState.schemaId,
      issuerId,
      tag: 'revocable',
    },
    options: {
      supportRevocation: true, // Enable revocation
      endorserMode: 'internal',
      endorserDid: issuerId,
    },
  })

Revoke a Credential

await agent.modules.anoncreds.revokeCredential({
  credentialRevocationId: '1',
  credentialDefinitionId,
})

Registry-Specific Configuration

import { IndyVdrModule, IndyVdrAnonCredsRegistry } from '@credo-ts/indy-vdr'
import { indyVdr } from '@hyperledger/indy-vdr-nodejs'

const agent = new Agent({
  config: {},
  dependencies: agentDependencies,
  modules: {
    anoncreds: new AnonCredsModule({
      registries: [new IndyVdrAnonCredsRegistry()],
      anoncreds,
    }),
    indyVdr: new IndyVdrModule({
      indyVdr,
      networks: [
        {
          genesisTransactions: bcovrinGenesisFile,
          indyNamespace: 'bcovrin:test',
          isProduction: false,
          connectOnStartup: true,
        },
      ],
    }),
  },
})

Complete Example

Here’s a complete issuer setup from the Credo demo:
import { Agent } from '@credo-ts/core'
import { AnonCredsModule } from '@credo-ts/anoncreds'
import {
  DidCommModule,
  DidCommCredentialV2Protocol,
  DidCommProofV2Protocol,
  DidCommAutoAcceptCredential,
  DidCommAutoAcceptProof,
} from '@credo-ts/didcomm'
import {
  AnonCredsDidCommCredentialFormatService,
  AnonCredsDidCommProofFormatService,
} from '@credo-ts/anoncreds'
import { IndyVdrModule, IndyVdrAnonCredsRegistry } from '@credo-ts/indy-vdr'
import { agentDependencies } from '@credo-ts/node'
import { anoncreds } from '@hyperledger/anoncreds-nodejs'
import { indyVdr } from '@hyperledger/indy-vdr-nodejs'

const agent = new Agent({
  config: {},
  dependencies: agentDependencies,
  modules: {
    anoncreds: new AnonCredsModule({
      registries: [new IndyVdrAnonCredsRegistry()],
      anoncreds,
    }),
    indyVdr: new IndyVdrModule({
      indyVdr,
      networks: [
        {
          genesisTransactions: bcovrinGenesis,
          indyNamespace: 'bcovrin:test',
          isProduction: false,
          connectOnStartup: true,
        },
      ],
    }),
    didcomm: new DidCommModule({
      endpoints: ['http://localhost:3000'],
      credentials: {
        autoAcceptCredentials: DidCommAutoAcceptCredential.ContentApproved,
        credentialProtocols: [
          new DidCommCredentialV2Protocol({
            credentialFormats: [
              new AnonCredsDidCommCredentialFormatService(),
            ],
          }),
        ],
      },
      proofs: {
        autoAcceptProofs: DidCommAutoAcceptProof.ContentApproved,
        proofProtocols: [
          new DidCommProofV2Protocol({
            proofFormats: [
              new AnonCredsDidCommProofFormatService(),
            ],
          }),
        ],
      },
    }),
  },
})

await agent.initialize()

Next Steps

DIDComm

Integrate AnonCreds with DIDComm messaging

Multi-Tenancy

Use AnonCreds in multi-tenant deployments

OpenID4VC

Alternative credential format with OpenID4VC

API Reference

Full AnonCreds API documentation

Build docs developers (and LLMs) love