Skip to content

Commit

Permalink
feat(anoncreds): use legacy prover did (#1374)
Browse files Browse the repository at this point in the history
Signed-off-by: Ariel Gentile <[email protected]>
  • Loading branch information
genaris authored Mar 17, 2023
1 parent 0351eec commit c17013c
Show file tree
Hide file tree
Showing 12 changed files with 103 additions and 43 deletions.
4 changes: 2 additions & 2 deletions packages/anoncreds-rs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@
"dependencies": {
"@aries-framework/core": "0.3.3",
"@aries-framework/anoncreds": "0.3.3",
"@hyperledger/anoncreds-shared": "^0.1.0-dev.9",
"@hyperledger/anoncreds-shared": "^0.1.0-dev.10",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"rxjs": "^7.2.0",
"tsyringe": "^4.7.0"
},
"devDependencies": {
"@hyperledger/anoncreds-nodejs": "^0.1.0-dev.9",
"@hyperledger/anoncreds-nodejs": "^0.1.0-dev.10",
"rimraf": "^4.0.7",
"typescript": "~4.9.4"
}
Expand Down
14 changes: 11 additions & 3 deletions packages/anoncreds-rs/src/services/AnonCredsRsHolderService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ import {
AnonCredsCredentialRecord,
AnonCredsLinkSecretRepository,
AnonCredsCredentialRepository,
legacyIndyCredentialDefinitionIdRegex,
} from '@aries-framework/anoncreds'
import { utils, injectable } from '@aries-framework/core'
import { TypedArrayEncoder, AriesFrameworkError, utils, injectable } from '@aries-framework/core'
import {
anoncreds,
Credential,
Expand Down Expand Up @@ -193,7 +194,7 @@ export class AnonCredsRsHolderService implements AnonCredsHolderService {
agentContext: AgentContext,
options: CreateCredentialRequestOptions
): Promise<CreateCredentialRequestReturn> {
const { credentialDefinition, credentialOffer } = options
const { useLegacyProverDid, credentialDefinition, credentialOffer } = options
let createReturnObj:
| { credentialRequest: CredentialRequest; credentialRequestMetadata: CredentialRequestMetadata }
| undefined
Expand All @@ -212,8 +213,15 @@ export class AnonCredsRsHolderService implements AnonCredsHolderService {
)
}

const isLegacyIdentifier = credentialOffer.cred_def_id.match(legacyIndyCredentialDefinitionIdRegex)
if (!isLegacyIdentifier && useLegacyProverDid) {
throw new AriesFrameworkError('Cannot use legacy prover_did with non-legacy identifiers')
}
createReturnObj = CredentialRequest.create({
entropy: anoncreds.generateNonce(), // FIXME: find a better source of entropy
entropy: !useLegacyProverDid || !isLegacyIdentifier ? anoncreds.generateNonce() : undefined,
proverDid: useLegacyProverDid
? TypedArrayEncoder.toBase58(TypedArrayEncoder.fromString(anoncreds.generateNonce().slice(0, 16)))
: undefined,
credentialDefinition: credentialDefinition as unknown as JsonObject,
credentialOffer: credentialOffer as unknown as JsonObject,
masterSecret: { value: { ms: linkSecretRecord.value } },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from '@aries-framework/anoncreds'
import { anoncreds, RevocationRegistryDefinition } from '@hyperledger/anoncreds-nodejs'

import { describeRunInNodeVersion } from '../../../../../tests/runInVersion'
import { AnonCredsCredentialDefinitionRepository } from '../../../../anoncreds/src/repository/AnonCredsCredentialDefinitionRepository'
import { AnonCredsCredentialRepository } from '../../../../anoncreds/src/repository/AnonCredsCredentialRepository'
import { AnonCredsLinkSecretRepository } from '../../../../anoncreds/src/repository/AnonCredsLinkSecretRepository'
Expand Down Expand Up @@ -56,7 +57,8 @@ const agentContext = getAgentContext({
agentConfig,
})

describe('AnonCredsRsHolderService', () => {
// FIXME: Re-include in tests when NodeJS wrapper performance is improved
describeRunInNodeVersion([18], 'AnonCredsRsHolderService', () => {
const getByCredentialIdMock = jest.spyOn(anoncredsCredentialRepositoryMock, 'getByCredentialId')

beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { anoncreds } from '@hyperledger/anoncreds-nodejs'
import { Subject } from 'rxjs'

import { InMemoryStorageService } from '../../../../../tests/InMemoryStorageService'
import { describeRunInNodeVersion } from '../../../../../tests/runInVersion'
import { encodeCredentialValue } from '../../../../anoncreds/src/utils/credential'
import { InMemoryAnonCredsRegistry } from '../../../../anoncreds/tests/InMemoryAnonCredsRegistry'
import { agentDependencies, getAgentConfig, getAgentContext } from '../../../../core/tests/helpers'
Expand All @@ -46,7 +47,8 @@ const agentContext = getAgentContext({
agentConfig,
})

describe('AnonCredsRsServices', () => {
// FIXME: Re-include in tests when NodeJS wrapper performance is improved
describeRunInNodeVersion([18], 'AnonCredsRsServices', () => {
test('issuance flow without revocation', async () => {
const issuerId = 'did:indy:pool:localtest:TL1EaPFCZ8Si5aUrqScBDt'

Expand Down
8 changes: 5 additions & 3 deletions packages/anoncreds-rs/tests/indy-flow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ import {
import { Subject } from 'rxjs'

import { InMemoryStorageService } from '../../../tests/InMemoryStorageService'
import { describeRunInNodeVersion } from '../../../tests/runInVersion'
import { AnonCredsRegistryService } from '../../anoncreds/src/services/registry/AnonCredsRegistryService'
import { InMemoryAnonCredsRegistry } from '../../anoncreds/tests/InMemoryAnonCredsRegistry'
import { agentDependencies, getAgentConfig, getAgentContext } from '../../core/tests/helpers'
import { AnonCredsRsHolderService } from '../src/services/AnonCredsRsHolderService'
import { AnonCredsRsIssuerService } from '../src/services/AnonCredsRsIssuerService'
import { AnonCredsRsVerifierService } from '../src/services/AnonCredsRsVerifierService'

const registry = new InMemoryAnonCredsRegistry()
const registry = new InMemoryAnonCredsRegistry({ useLegacyIdentifiers: true })
const anonCredsModuleConfig = new AnonCredsModuleConfig({
registries: [registry],
})
Expand Down Expand Up @@ -69,9 +70,10 @@ const legacyIndyCredentialFormatService = new LegacyIndyCredentialFormatService(
const legacyIndyProofFormatService = new LegacyIndyProofFormatService()

// This is just so we don't have to register an actually indy did (as we don't have the indy did registrar configured)
const indyDid = 'did:indy:pool:localtest:TL1EaPFCZ8Si5aUrqScBDt'
const indyDid = 'LjgpST2rjsoxYegQDRm7EL'

describe('Legacy indy format services using anoncreds-rs', () => {
// FIXME: Re-include in tests when NodeJS wrapper performance is improved
describeRunInNodeVersion([18], 'Legacy indy format services using anoncreds-rs', () => {
test('issuance and verification flow starting from proposal without negotiation and without revocation', async () => {
const schema = await anonCredsIssuerService.createSchema(agentContext, {
attrNames: ['name', 'age'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { AnonCredsError } from '../error'
import { AnonCredsCredentialProposal } from '../models/AnonCredsCredentialProposal'
import { AnonCredsIssuerServiceSymbol, AnonCredsHolderServiceSymbol } from '../services'
import { AnonCredsRegistryService } from '../services/registry/AnonCredsRegistryService'
import { legacyIndyCredentialDefinitionIdRegex, legacyIndySchemaIdRegex } from '../utils'
import {
convertAttributesToCredentialValues,
assertCredentialValuesMatch,
Expand Down Expand Up @@ -146,10 +147,14 @@ export class LegacyIndyCredentialFormatService implements CredentialFormatServic

if (!credentialDefinitionId) {
throw new AriesFrameworkError(
'No credentialDefinitionId in proposal or provided as input to accept proposal method.'
'No credential definition id in proposal or provided as input to accept proposal method.'
)
}

if (!credentialDefinitionId.match(legacyIndyCredentialDefinitionIdRegex)) {
throw new AriesFrameworkError(`${credentialDefinitionId} is not a valid legacy indy credential definition id`)
}

if (!attributes) {
throw new AriesFrameworkError('No attributes in proposal or provided as input to accept proposal method.')
}
Expand Down Expand Up @@ -205,7 +210,10 @@ export class LegacyIndyCredentialFormatService implements CredentialFormatServic

const credOffer = attachment.getDataAsJson<AnonCredsCredentialOffer>()

if (!credOffer.schema_id || !credOffer.cred_def_id) {
if (
!credOffer.schema_id.match(legacyIndySchemaIdRegex) ||
!credOffer.cred_def_id.match(legacyIndyCredentialDefinitionIdRegex)
) {
throw new ProblemReportError('Invalid credential offer', {
problemCode: CredentialProblemReportReason.IssuanceAbandoned,
})
Expand All @@ -226,6 +234,11 @@ export class LegacyIndyCredentialFormatService implements CredentialFormatServic

const credentialOffer = offerAttachment.getDataAsJson<AnonCredsCredentialOffer>()

if (!credentialOffer.cred_def_id.match(legacyIndyCredentialDefinitionIdRegex)) {
throw new AriesFrameworkError(
`${credentialOffer.cred_def_id} is not a valid legacy indy credential definition id`
)
}
// Get credential definition
const registry = registryService.getRegistryForIdentifier(agentContext, credentialOffer.cred_def_id)
const { credentialDefinition, resolutionMetadata } = await registry.getCredentialDefinition(
Expand All @@ -243,6 +256,7 @@ export class LegacyIndyCredentialFormatService implements CredentialFormatServic
credentialOffer,
credentialDefinition,
linkSecretId: credentialFormats?.indy?.linkSecretId,
useLegacyProverDid: true,
})

if (!credentialRequest.prover_did) {
Expand Down
10 changes: 10 additions & 0 deletions packages/anoncreds/src/formats/LegacyIndyProofFormatService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ import {
checkValidCredentialValueEncoding,
encodeCredentialValue,
assertNoDuplicateGroupsNamesInProofRequest,
legacyIndyCredentialDefinitionIdRegex,
legacyIndySchemaIdRegex,
} from '../utils'

const V2_INDY_PRESENTATION_PROPOSAL = 'hlindy/[email protected]'
Expand Down Expand Up @@ -471,6 +473,10 @@ export class LegacyIndyProofFormatService implements ProofFormatService<LegacyIn
const schemas: { [key: string]: AnonCredsSchema } = {}

for (const schemaId of schemaIds) {
if (!schemaId.match(legacyIndySchemaIdRegex)) {
throw new AriesFrameworkError(`${schemaId} is not a valid legacy indy schema id`)
}

const schemaRegistry = registryService.getRegistryForIdentifier(agentContext, schemaId)
const schemaResult = await schemaRegistry.getSchema(agentContext, schemaId)

Expand Down Expand Up @@ -499,6 +505,10 @@ export class LegacyIndyProofFormatService implements ProofFormatService<LegacyIn
const credentialDefinitions: { [key: string]: AnonCredsCredentialDefinition } = {}

for (const credentialDefinitionId of credentialDefinitionIds) {
if (!credentialDefinitionId.match(legacyIndyCredentialDefinitionIdRegex)) {
throw new AriesFrameworkError(`${credentialDefinitionId} is not a valid legacy indy credential definition id`)
}

const credentialDefinitionRegistry = registryService.getRegistryForIdentifier(
agentContext,
credentialDefinitionId
Expand Down
1 change: 1 addition & 0 deletions packages/anoncreds/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export { AnonCredsModuleConfig, AnonCredsModuleConfigOptions } from './AnonCreds
export { AnonCredsApi } from './AnonCredsApi'
export * from './AnonCredsApiOptions'
export { generateLegacyProverDidLikeString } from './utils/proverDid'
export * from './utils/legacyIndyIdentifiers'
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export interface CreateCredentialRequestOptions {
credentialOffer: AnonCredsCredentialOffer
credentialDefinition: AnonCredsCredentialDefinition
linkSecretId?: string
useLegacyProverDid?: boolean
}

export interface CreateCredentialRequestReturn {
Expand Down
60 changes: 38 additions & 22 deletions packages/anoncreds/tests/InMemoryAnonCredsRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,26 @@ export class InMemoryAnonCredsRegistry implements AnonCredsRegistry {
private credentialDefinitions: Record<string, AnonCredsCredentialDefinition>
private revocationRegistryDefinitions: Record<string, AnonCredsRevocationRegistryDefinition>
private revocationStatusLists: Record<string, Record<string, AnonCredsRevocationStatusList>>
private useLegacyIdentifiers: boolean

public constructor({
existingSchemas = {},
existingCredentialDefinitions = {},
existingRevocationRegistryDefinitions = {},
existingRevocationStatusLists = {},
useLegacyIdentifiers = false,
}: {
existingSchemas?: Record<string, AnonCredsSchema>
existingCredentialDefinitions?: Record<string, AnonCredsCredentialDefinition>
existingRevocationRegistryDefinitions?: Record<string, AnonCredsRevocationRegistryDefinition>
existingRevocationStatusLists?: Record<string, Record<string, AnonCredsRevocationStatusList>>
useLegacyIdentifiers?: boolean
} = {}) {
this.schemas = existingSchemas
this.credentialDefinitions = existingCredentialDefinitions
this.revocationRegistryDefinitions = existingRevocationRegistryDefinitions
this.revocationStatusLists = existingRevocationStatusLists
this.useLegacyIdentifiers = useLegacyIdentifiers
}

public async getSchema(agentContext: AgentContext, schemaId: string): Promise<GetSchemaReturn> {
Expand Down Expand Up @@ -94,21 +98,23 @@ export class InMemoryAnonCredsRegistry implements AnonCredsRegistry {
agentContext: AgentContext,
options: RegisterSchemaOptions
): Promise<RegisterSchemaReturn> {
const { namespaceIdentifier, namespace } = parseIndyDid(options.schema.issuerId)
const didIndySchemaId = getDidIndySchemaId(
namespace,
namespaceIdentifier,
options.schema.name,
options.schema.version
)
const legacySchemaId = getLegacySchemaId(namespaceIdentifier, options.schema.name, options.schema.version)
let legacyIssuerId
let didIndySchemaId = ''
if (this.useLegacyIdentifiers) {
legacyIssuerId = options.schema.issuerId
} else {
const { namespace, namespaceIdentifier } = parseIndyDid(options.schema.issuerId)
legacyIssuerId = namespaceIdentifier
didIndySchemaId = getDidIndySchemaId(namespace, namespaceIdentifier, options.schema.name, options.schema.version)
this.schemas[didIndySchemaId] = options.schema
}

const legacySchemaId = getLegacySchemaId(legacyIssuerId, options.schema.name, options.schema.version)
const indyLedgerSeqNo = getSeqNoFromSchemaId(legacySchemaId)

this.schemas[didIndySchemaId] = options.schema
this.schemas[legacySchemaId] = {
...options.schema,
issuerId: namespaceIdentifier,
issuerId: legacyIssuerId,
}

return {
Expand All @@ -121,7 +127,7 @@ export class InMemoryAnonCredsRegistry implements AnonCredsRegistry {
schemaState: {
state: 'finished',
schema: options.schema,
schemaId: didIndySchemaId,
schemaId: this.useLegacyIdentifiers ? legacySchemaId : didIndySchemaId,
},
}
}
Expand Down Expand Up @@ -163,24 +169,32 @@ export class InMemoryAnonCredsRegistry implements AnonCredsRegistry {
)
const indyLedgerSeqNo = getSeqNoFromSchemaId(legacySchemaId)

const { namespaceIdentifier, namespace } = parseIndyDid(options.credentialDefinition.issuerId)
let legacyIssuerId
let didIndyCredentialDefinitionId = ''
if (this.useLegacyIdentifiers) {
legacyIssuerId = options.credentialDefinition.issuerId
} else {
const { namespace, namespaceIdentifier } = parseIndyDid(options.credentialDefinition.issuerId)
legacyIssuerId = namespaceIdentifier
didIndyCredentialDefinitionId = getDidIndyCredentialDefinitionId(
namespace,
namespaceIdentifier,
indyLedgerSeqNo,
options.credentialDefinition.tag
)

this.credentialDefinitions[didIndyCredentialDefinitionId] = options.credentialDefinition
}

const didIndyCredentialDefinitionId = getDidIndyCredentialDefinitionId(
namespace,
namespaceIdentifier,
indyLedgerSeqNo,
options.credentialDefinition.tag
)
const legacyCredentialDefinitionId = getLegacyCredentialDefinitionId(
namespaceIdentifier,
legacyIssuerId,
indyLedgerSeqNo,
options.credentialDefinition.tag
)

this.credentialDefinitions[didIndyCredentialDefinitionId] = options.credentialDefinition
this.credentialDefinitions[legacyCredentialDefinitionId] = {
...options.credentialDefinition,
issuerId: namespaceIdentifier,
issuerId: legacyIssuerId,
schemaId: legacySchemaId,
}

Expand All @@ -190,7 +204,9 @@ export class InMemoryAnonCredsRegistry implements AnonCredsRegistry {
credentialDefinitionState: {
state: 'finished',
credentialDefinition: options.credentialDefinition,
credentialDefinitionId: didIndyCredentialDefinitionId,
credentialDefinitionId: this.useLegacyIdentifiers
? legacyCredentialDefinitionId
: didIndyCredentialDefinitionId,
},
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ export class IndySdkHolderService implements AnonCredsHolderService {
): Promise<CreateCredentialRequestReturn> {
assertIndySdkWallet(agentContext.wallet)

if (!options.useLegacyProverDid) {
throw new AriesFrameworkError('Indy SDK only supports legacy prover did for credential requests')
}

const linkSecretRepository = agentContext.dependencyManager.resolve(AnonCredsLinkSecretRepository)

// We just generate a prover did like string, as it's not used for anything and we don't need
Expand Down
18 changes: 9 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -864,23 +864,23 @@
resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340"
integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==

"@hyperledger/anoncreds-nodejs@^0.1.0-dev.9":
version "0.1.0-dev.9"
resolved "https://registry.yarnpkg.com/@hyperledger/anoncreds-nodejs/-/anoncreds-nodejs-0.1.0-dev.9.tgz#5f09d5f147ce204abd9b3cea486c23e556cc8fdc"
integrity sha512-Ht5Gt1DfnFiRIY+AlTpe8Hcdryb+jKl79hGQ3kszdct/1JFZ70A81ssfwX0VKYTdCHt5jK5cJzVaOjOVmBKZiw==
"@hyperledger/anoncreds-nodejs@^0.1.0-dev.10":
version "0.1.0-dev.10"
resolved "https://registry.yarnpkg.com/@hyperledger/anoncreds-nodejs/-/anoncreds-nodejs-0.1.0-dev.10.tgz#80c093ecb08a277fb494399b64aad1b900c3103f"
integrity sha512-ju5mJPwuyebAPziuf+eUOwxEws02G2FHEp/qG3GV3kxtlx7THW7HVB7dMSNqhRVKCsbcNnZtWJB1UiPvWqboUg==
dependencies:
"@hyperledger/anoncreds-shared" "0.1.0-dev.9"
"@hyperledger/anoncreds-shared" "0.1.0-dev.10"
"@mapbox/node-pre-gyp" "^1.0.10"
ffi-napi "4.0.3"
node-cache "5.1.2"
ref-array-di "1.2.2"
ref-napi "3.0.3"
ref-struct-di "1.1.1"

"@hyperledger/[email protected].9", "@hyperledger/anoncreds-shared@^0.1.0-dev.9":
version "0.1.0-dev.9"
resolved "https://registry.yarnpkg.com/@hyperledger/anoncreds-shared/-/anoncreds-shared-0.1.0-dev.9.tgz#7f6a033997e2641432a51ff2b609d603b3f9ab50"
integrity sha512-xbWEB9Z9PwkxC2awx74xt1OULMxihbK2v7818Dtrrmun75gNBXF8Jdorn9+t+TEd62QLrJpVUJ1ZCKhXPx81zw==
"@hyperledger/[email protected].10", "@hyperledger/anoncreds-shared@^0.1.0-dev.10":
version "0.1.0-dev.10"
resolved "https://registry.yarnpkg.com/@hyperledger/anoncreds-shared/-/anoncreds-shared-0.1.0-dev.10.tgz#9d67f64e98ff41971644c95b03dabafd741df4df"
integrity sha512-POvcwQrUcPrwoZehQa38pN1dnjyeUlrQ6VlksbBRS8SUHJuyixZsD+d3XoumqaNfl9Z1DCjfuOgEiPlec01gXQ==

"@hyperledger/aries-askar-nodejs@^0.1.0-dev.4":
version "0.1.0-dev.4"
Expand Down

0 comments on commit c17013c

Please sign in to comment.