Skip to content

Commit

Permalink
fix: added additional check for status list transformation
Browse files Browse the repository at this point in the history
Signed-off-by: Berend Sliedrecht <sliedrecht@berend.io>
  • Loading branch information
berendsliedrecht committed Jan 17, 2024
1 parent becd233 commit f0969be
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/anoncreds-rs/tests/anoncreds-flow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ async function anonCredsFlowTest(options: { issuerId: string; revocable: boolean
options: {},
})

if (!revocationStatusListState.revocationStatusList || !revocationStatusListState.timestamp) {
if (!revocationStatusListState.revocationStatusList) {
throw new Error('Failed to create revocation status list')
}
}
Expand Down
164 changes: 164 additions & 0 deletions packages/indy-vdr/src/anoncreds/utils/__tests__/transform.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import type { RevocationRegistryDelta } from '../transform'
import type { AnonCredsRevocationRegistryDefinition } from '@aries-framework/anoncreds'

import { indyVdrCreateLatestRevocationDelta, anonCredsRevocationStatusListFromIndyVdr } from '../transform'

const createRevocationRegistryDefinition = (maxCreds: number): AnonCredsRevocationRegistryDefinition => ({
value: {
tailsHash: 'hash',
maxCredNum: maxCreds,
publicKeys: {
accumKey: {
z: 'key',
},
},
tailsLocation: 'nowhere',
},
revocDefType: 'CL_ACCUM',
tag: 'REV_TAG',
issuerId: 'does:not:matter',
credDefId: 'does:not:matter',
})

describe('transform', () => {
const accum = 'does not matter'
const revocationRegistryDefinitionId = 'does:not:matter'

describe('indy vdr delta to anoncreds revocation status list', () => {
test('issued and revoked are filled', () => {
const delta: RevocationRegistryDelta = {
accum,
issued: [0, 1, 2, 3, 4],
revoked: [5, 6, 7, 8, 9],
txnTime: 1,
}

const revocationRegistryDefinition = createRevocationRegistryDefinition(10)

const statusList = anonCredsRevocationStatusListFromIndyVdr(
revocationRegistryDefinitionId,
revocationRegistryDefinition,
delta,
true
)

expect(statusList.revocationList).toStrictEqual([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])
})

test('issued and revoked are empty (issuance by default)', () => {
const delta: RevocationRegistryDelta = {
accum,
issued: [],
revoked: [],
txnTime: 1,
}

const revocationRegistryDefinition = createRevocationRegistryDefinition(10)

const statusList = anonCredsRevocationStatusListFromIndyVdr(
revocationRegistryDefinitionId,
revocationRegistryDefinition,
delta,
true
)

expect(statusList.revocationList).toStrictEqual([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
})

test('issued and revoked are empty (issuance on demand)', () => {
const delta: RevocationRegistryDelta = {
accum,
issued: [],
revoked: [],
txnTime: 1,
}

const revocationRegistryDefinition = createRevocationRegistryDefinition(10)

const statusList = anonCredsRevocationStatusListFromIndyVdr(
revocationRegistryDefinitionId,
revocationRegistryDefinition,
delta,
false
)

expect(statusList.revocationList).toStrictEqual([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
})

test('issued index is too high', () => {
const delta: RevocationRegistryDelta = {
accum,
issued: [200],
revoked: [5, 6, 7, 8, 9],
txnTime: 1,
}

const revocationRegistryDefinition = createRevocationRegistryDefinition(10)

expect(() =>
anonCredsRevocationStatusListFromIndyVdr(
revocationRegistryDefinitionId,
revocationRegistryDefinition,
delta,
true
)
).toThrowError()
})
})

describe('create latest indy vdr delta from status list and previous delta', () => {
test('delta and status list are equal', () => {
const delta: RevocationRegistryDelta = {
accum,
issued: [0, 1, 2, 3, 4],
revoked: [5, 6, 7, 8, 9],
txnTime: 1,
}

const revocationStatusList = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]

const { revoked, issued } = indyVdrCreateLatestRevocationDelta(accum, revocationStatusList, delta)

expect(revoked).toStrictEqual([])
expect(issued).toStrictEqual([])
})

test('no previous delta', () => {
const revocationStatusList = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]

const { revoked, issued } = indyVdrCreateLatestRevocationDelta(accum, revocationStatusList)

expect(issued).toStrictEqual([0, 1, 2, 3, 4])
expect(revoked).toStrictEqual([5, 6, 7, 8, 9])
})

test('status list and previous delta are out of sync', () => {
const delta: RevocationRegistryDelta = {
accum,
issued: [0],
revoked: [5],
txnTime: 1,
}

const revocationStatusList = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]

const { revoked, issued } = indyVdrCreateLatestRevocationDelta(accum, revocationStatusList, delta)

expect(issued).toStrictEqual([1, 2, 3, 4])
expect(revoked).toStrictEqual([6, 7, 8, 9])
})

test('previous delta index exceeds length of revocation status list', () => {
const delta: RevocationRegistryDelta = {
accum,
issued: [200],
revoked: [5],
txnTime: 1,
}

const revocationStatusList = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]

expect(() => indyVdrCreateLatestRevocationDelta(accum, revocationStatusList, delta)).toThrowError()
})
})
})
38 changes: 38 additions & 0 deletions packages/indy-vdr/src/anoncreds/utils/transform.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { AnonCredsRevocationStatusList, AnonCredsRevocationRegistryDefinition } from '@aries-framework/anoncreds'

import { AriesFrameworkError } from '@aries-framework/core'

export type RevocationRegistryDelta = {
accum: string
issued: number[]
Expand All @@ -18,6 +20,18 @@ export function anonCredsRevocationStatusListFromIndyVdr(
delta: RevocationRegistryDelta,
isIssuanceByDefault: boolean
): AnonCredsRevocationStatusList {
// Check whether the highest delta index is supported in the `maxCredNum` field of the
// revocation registry definition. This will likely also be checked on other levels as well
// by the ledger or the indy-vdr library itself
if (Math.max(...delta.issued, ...delta.revoked) >= revocationRegistryDefinition.value.maxCredNum) {
throw new AriesFrameworkError(
`Highest delta index '${Math.max(
...delta.issued,
...delta.revoked
)}' is too large for the Revocation registry maxCredNum '${revocationRegistryDefinition.value.maxCredNum}' `
)
}

// 0 means unrevoked, 1 means revoked
const defaultState = isIssuanceByDefault ? RevocationState.Active : RevocationState.Revoked

Expand Down Expand Up @@ -66,22 +80,46 @@ export function indyVdrCreateLatestRevocationDelta(
revocationStatusList: Array<number>,
previousDelta?: RevocationRegistryDelta
) {
if (previousDelta && Math.max(...previousDelta.issued, ...previousDelta.revoked) > revocationStatusList.length - 1) {
throw new AriesFrameworkError(
`Indy Vdr delta contains an index '${Math.max(
...previousDelta.revoked,
...previousDelta.issued
)}' that exceeds the length of the revocation status list '${revocationStatusList.length}'`
)
}

const issued: Array<number> = []
const revoked: Array<number> = []

if (previousDelta) {
for (const issuedIdx of previousDelta.issued) {
// Check whether the revocationStatusList has a different state compared to the delta
if (revocationStatusList[issuedIdx] !== RevocationState.Active) {
issued.push(issuedIdx)
}
}

for (const revokedIdx of previousDelta.revoked) {
// Check whether the revocationStatusList has a different state compared to the delta
if (revocationStatusList[revokedIdx] !== RevocationState.Revoked) {
revoked.push(revokedIdx)
}
}

revocationStatusList.forEach((revocationStatus, idx) => {
// Check whether the revocationStatusList entry is not included in the previous delta issued indices
if (revocationStatus === RevocationState.Active && !previousDelta.issued.includes(idx)) {
issued.push(idx)
}

// Check whether the revocationStatusList entry is not included in the previous delta revoked indices
if (revocationStatus === RevocationState.Revoked && !previousDelta.revoked.includes(idx)) {
revoked.push(idx)
}
})
} else {
// No delta is provided, initial state, so the entire revocation status list is converted to two list of indices
revocationStatusList.forEach((revocationStatus, idx) => {
if (revocationStatus === RevocationState.Active) issued.push(idx)
if (revocationStatus === RevocationState.Revoked) revoked.push(idx)
Expand Down

0 comments on commit f0969be

Please sign in to comment.