Skip to content

Commit

Permalink
feat(data-store): use IPFS CID instead of hex blake2 hashes for crede…
Browse files Browse the repository at this point in the history
…ntial IDs (#1239)

BREAKING CHANGE: going forward credentials and presentations will have a new ID format in the database. If you are relying on the IDs assigned internally by `@veramo/data-store` to work with your credentials, you will have to recompute them using the `@veramo/utils#computeEntryHash` method.
  • Loading branch information
simonas-notcat committed Sep 21, 2023
1 parent 3e5b728 commit acc47e6
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 21 deletions.
15 changes: 7 additions & 8 deletions packages/credential-w3c/src/__tests__/message-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { DIDResolutionResult, IAgentContext, ICredentialPlugin, IResolver } from
import { Message } from '../../../message-handler/src'
import { IContext, MessageTypes, W3cMessageHandler } from '../message-handler.js'
import { jest } from '@jest/globals'
import { blake2b } from '@noble/hashes/blake2b'
import { bytesToHex } from '../../../utils/src'
import { computeEntryHash } from '../../../utils/src'

describe('@veramo/credential-w3c', () => {
const handler = new W3cMessageHandler()
Expand Down Expand Up @@ -120,7 +119,7 @@ describe('@veramo/credential-w3c', () => {
message.addMetaData({ type: 'JWT', value: 'ES256K-R' })
const handled = await handler.handle(message, context)
expect(handled.isValid()).toEqual(true)
expect(handled.id).toEqual(bytesToHex(blake2b(vcJwtSecp256k1)))
expect(handled.id).toEqual(computeEntryHash(vcJwtSecp256k1))
expect(handled.raw).toEqual(vcJwtSecp256k1)
expect(handled.type).toEqual(MessageTypes.vc)
expect(handled.from).toEqual(vcPayloadSecp256k1.iss)
Expand All @@ -137,7 +136,7 @@ describe('@veramo/credential-w3c', () => {

const handled = await handler.handle(message, context)
expect(handled.isValid()).toEqual(true)
expect(handled.id).toEqual(bytesToHex(blake2b(vpJwtSecp256k1)))
expect(handled.id).toEqual(computeEntryHash(vpJwtSecp256k1))
expect(handled.raw).toEqual(vpJwtSecp256k1)
expect(handled.type).toEqual(MessageTypes.vp)
expect(handled.from).toEqual(vpPayloadSecp256k1.iss)
Expand Down Expand Up @@ -187,7 +186,7 @@ describe('@veramo/credential-w3c', () => {
message.addMetaData({ type: 'JWT', value: 'Ed25519' })
const handled = await handler.handle(message, context)
expect(handled.isValid()).toEqual(true)
expect(handled.id).toEqual(bytesToHex(blake2b(vcJwtEd25519)))
expect(handled.id).toEqual(computeEntryHash(vcJwtEd25519))
expect(handled.raw).toEqual(vcJwtEd25519)
expect(handled.type).toEqual(MessageTypes.vc)
expect(handled.from).toEqual(vcPayloadEd25519.iss)
Expand All @@ -203,7 +202,7 @@ describe('@veramo/credential-w3c', () => {

const handled = await handler.handle(message, context)
expect(handled.isValid()).toEqual(true)
expect(handled.id).toEqual(bytesToHex(blake2b(vpJwtEd25519)))
expect(handled.id).toEqual(computeEntryHash(vpJwtEd25519))
expect(handled.raw).toEqual(vpJwtEd25519)
expect(handled.type).toEqual(MessageTypes.vp)
expect(handled.from).toEqual(vpPayloadEd25519.iss)
Expand Down Expand Up @@ -235,7 +234,7 @@ describe('@veramo/credential-w3c', () => {

const handled = await handler.handle(message, context)
expect(handled.isValid()).toEqual(true)
expect(handled.id).toEqual(bytesToHex(blake2b(vpMultiAudJwt)))
expect(handled.id).toEqual(computeEntryHash(vpMultiAudJwt))
expect(handled.raw).toEqual(vpMultiAudJwt)
expect(handled.type).toEqual(MessageTypes.vp)
expect(handled.from).toEqual(vpMultiAudPayload.iss)
Expand Down Expand Up @@ -274,7 +273,7 @@ describe('@veramo/credential-w3c', () => {
const handled = await handler.handle(message, context)

expect(handled.isValid()).toEqual(true)
expect(handled.id).toEqual(bytesToHex(blake2b(token)))
expect(handled.id).toEqual(computeEntryHash(token))
expect(handled.raw).toEqual(token)
expect(handled.type).toEqual(MessageTypes.vc)
expect(handled.from).toEqual('did:ethr:0x54d59e3ffd76917f62db702ac354b17f3842955e')
Expand Down
5 changes: 2 additions & 3 deletions packages/data-store/src/__tests__/entities.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { createPresentationEntity } from '../entities/presentation.js'
import { Claim, Entities, Identifier, Message } from '../index.js'
import { DataSource, In } from 'typeorm'
import * as fs from 'fs'
import { bytesToHex } from '../../../utils/src'
import { blake2b } from '@noble/hashes/blake2b'
import { computeEntryHash } from '../../../utils/src'

describe('DB entities test', () => {
let connection: DataSource
Expand Down Expand Up @@ -167,7 +166,7 @@ describe('DB entities test', () => {
})

it('Message can have externally set id', async () => {
const customId = bytesToHex(blake2b('hash123'))
const customId = computeEntryHash('hash123')

const message = new Message()
message.type = 'custom'
Expand Down
3 changes: 2 additions & 1 deletion packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@
"dependencies": {
"@ethersproject/signing-key": "^5.7.0",
"@ethersproject/transactions": "^5.7.0",
"@ipld/dag-pb": "^4.0.5",
"@noble/curves": "^1.1.0",
"@noble/hashes": "^1.3.1",
"@veramo/core-types": "workspace:^",
"credential-status": "^2.0.5",
"cross-fetch": "^4.0.0",
"debug": "^4.3.3",
"did-jwt": "^7.2.5",
"did-jwt-vc": "^3.2.5",
"did-resolver": "^4.1.0",
"ipfs-unixfs": "^11.1.0",
"multiformats": "^12.0.1",
"uint8arrays": "^4.0.6"
},
Expand Down
4 changes: 2 additions & 2 deletions packages/utils/src/__tests__/credential-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ describe('@veramo/utils credential utils', () => {
expect(computeEntryHash(expandedCred)).toEqual(computeEntryHash(serializedCred))
expect(computeEntryHash(jwt)).toEqual(computeEntryHash(serializedCred))
expect(computeEntryHash(serializedCred)).toEqual(
'452f0fb4b876e22867585ee15a6aabb7a6f9ccccf6a2ee664e9f7618737792d64b219fef0792b9d73f3ff756a265083526ecb7313ae4972ef6290b600cacbe88',
'QmYBWeZCoB1zbJwGou1svfgrq9muVQyy7uzokMfdeSEoHH',
)
})

Expand All @@ -208,7 +208,7 @@ describe('@veramo/utils credential utils', () => {
'{"issuer":{"id":"did:key:z6MkvGFkoFarw7pXRBkKqZKwDcc2L3U4AZC1RtBiceicUHqn"},"@context":["https://www.w3.org/2018/credentials/v1","https://veramo.io/contexts/profile/v1"],"type":["VerifiableCredential","Profile"],"issuanceDate":"2021-11-23T15:06:12.820Z","credentialSubject":{"id":"did:key:z6MkvGFkoFarw7pXRBkKqZKwDcc2L3U4AZC1RtBiceicUHqn","name":"Martin, the great"},"proof":{"type":"Ed25519Signature2018","created":"2021-11-23T15:06:12Z","verificationMethod":"did:key:z6MkvGFkoFarw7pXRBkKqZKwDcc2L3U4AZC1RtBiceicUHqn#z6MkvGFkoFarw7pXRBkKqZKwDcc2L3U4AZC1RtBiceicUHqn","proofPurpose":"assertionMethod","jws":"eyJhbGciOiJFZERTQSIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..wKMmMZNdIgL_19HYJgpRL9SeKVzYT85S-ZyVdF3IMiaiL8nhX8i48D82TQtuQlTT960h_TOQ18fQFula6QxADA"}}'
expect(computeEntryHash(expandedCred)).toEqual(computeEntryHash(serializedCred))
expect(computeEntryHash(serializedCred)).toEqual(
'357436ca94682f2872b26c35a64d52c8e12dfbf86561a8f219cb395482f5978758fb577c927874cdb01189853054433a07eca81a4b3a999be12290021eb9bcbb',
'QmYeBhqpqiFUcsTS1qz7tkuVCJq8Z4VrrSJsjJc4Q7k9ig',
)
})

Expand Down
20 changes: 16 additions & 4 deletions packages/utils/src/credential-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import {
} from '@veramo/core-types'
import { decodeJWT } from 'did-jwt'
import { normalizeCredential, normalizePresentation } from 'did-jwt-vc'
import { blake2b } from '@noble/hashes/blake2b'
import { bytesToHex } from './encodings.js'

import { sha256 } from 'multiformats/hashes/sha2'
import { code, encode, prepare } from '@ipld/dag-pb'
import { CID } from 'multiformats/cid'
import { UnixFS } from 'ipfs-unixfs'
/**
* Every Verifiable Credential `@context` property must contain this.
*
Expand Down Expand Up @@ -96,7 +97,18 @@ export function computeEntryHash(
} else {
hashable = JSON.stringify(input)
}
return bytesToHex(blake2b(hashable))

const unixfs = new UnixFS({
type: 'file',
data: new TextEncoder().encode(hashable)
})

const bytes = encode(prepare({ Data: unixfs.marshal() }))
const multihash = sha256.digest(bytes)
//@ts-ignore
const cid = CID.create(0, code, multihash).toString()

return cid
}

/**
Expand Down
111 changes: 108 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit acc47e6

Please sign in to comment.