Skip to content

Commit

Permalink
feat: jsonld-credential support (#718)
Browse files Browse the repository at this point in the history
Signed-off-by: Karim Stekelenburg <[email protected]>
  • Loading branch information
karimStekelenburg authored and TimoGlastra committed Jul 4, 2022
1 parent f36e2b5 commit 76fa3d8
Show file tree
Hide file tree
Showing 101 changed files with 10,508 additions and 242 deletions.
5 changes: 5 additions & 0 deletions DEVREADME.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

This file is intended for developers working on the internals of the framework. If you're just looking how to get started with the framework, see the [docs](./docs)

## Installing dependencies

Right now, as a patch that will later be changed, some platforms will have an "error" when installing the dependencies with yarn. This is because the BBS signatures library that we use is built for Linux x86 and MacOS x86 (and not Windows and MacOS arm). This means that it will show that it could not download the binary.
This is not an error for developers, the library that fails is `node-bbs-signaturs` and is an optional dependency for perfomance improvements. It will fallback to a, slower, wasm build.

## Running tests

Test are executed using jest. Some test require either the **mediator agents** or the **ledger** to be running. When running tests that require a connection to the ledger pool, you need to set the `TEST_AGENT_PUBLIC_DID_SEED` and `GENESIS_TXN_PATH` environment variables.
Expand Down
5 changes: 5 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,14 @@
"prepublishOnly": "yarn run build"
},
"dependencies": {
"@digitalcredentials/jsonld": "^5.2.1",
"@digitalcredentials/jsonld-signatures": "^9.3.1",
"@digitalcredentials/vc": "^1.1.2",
"@mattrglobal/bbs-signatures": "^1.0.0",
"@mattrglobal/bls12381-key-pair": "^1.0.0",
"@multiformats/base-x": "^4.0.1",
"@stablelib/ed25519": "^1.0.2",
"@stablelib/random": "^1.0.1",
"@stablelib/sha256": "^1.0.1",
"@types/indy-sdk": "^1.16.19",
"@types/node-fetch": "^2.5.10",
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/agent/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { QuestionAnswerModule } from '../modules/question-answer/QuestionAnswerM
import { MediatorModule } from '../modules/routing/MediatorModule'
import { RecipientModule } from '../modules/routing/RecipientModule'
import { RoutingService } from '../modules/routing/services/RoutingService'
import { W3cVcModule } from '../modules/vc/module'
import { DependencyManager } from '../plugins'
import { StorageUpdateService, DidCommMessageRepository, StorageVersionRepository } from '../storage'
import { InMemoryMessageRepository } from '../storage/InMemoryMessageRepository'
Expand Down Expand Up @@ -348,7 +349,8 @@ export class Agent {
DidsModule,
WalletModule,
OutOfBandModule,
IndyModule
IndyModule,
W3cVcModule
)
}
}
51 changes: 51 additions & 0 deletions packages/core/src/crypto/LdKeyPair.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { VerificationMethod } from '../modules/dids'

export interface LdKeyPairOptions {
id: string
controller: string
}

export abstract class LdKeyPair {
public readonly id: string
public readonly controller: string
public abstract type: string

public constructor(options: LdKeyPairOptions) {
this.id = options.id
this.controller = options.controller
}

public static async generate(): Promise<LdKeyPair> {
throw new Error('Not implemented')
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
public static async from(verificationMethod: VerificationMethod): Promise<LdKeyPair> {
throw new Error('Abstract method from() must be implemented in subclass.')
}

public export(publicKey = false, privateKey = false) {
if (!publicKey && !privateKey) {
throw new Error('Export requires specifying either "publicKey" or "privateKey".')
}
const key = {
id: this.id,
type: this.type,
controller: this.controller,
}

return key
}

public abstract fingerprint(): string

public abstract verifyFingerprint(fingerprint: string): boolean

public abstract signer(): {
sign: (data: { data: Uint8Array | Uint8Array[] }) => Promise<Uint8Array | Array<Uint8Array>>
}

public abstract verifier(): {
verify: (data: { data: Uint8Array | Uint8Array[]; signature: Uint8Array }) => Promise<boolean>
}
}
123 changes: 123 additions & 0 deletions packages/core/src/crypto/WalletKeyPair.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import type { Wallet } from '..'
import type { Key } from './Key'
import type { LdKeyPairOptions } from './LdKeyPair'

import { VerificationMethod } from '../modules/dids'
import { getKeyDidMappingByVerificationMethod } from '../modules/dids/domain/key-type/keyDidMapping'
import { JsonTransformer } from '../utils'
import { MessageValidator } from '../utils/MessageValidator'
import { Buffer } from '../utils/buffer'

import { LdKeyPair } from './LdKeyPair'

interface WalletKeyPairOptions extends LdKeyPairOptions {
wallet: Wallet
key: Key
}

export function createWalletKeyPairClass(wallet: Wallet) {
return class WalletKeyPair extends LdKeyPair {
public wallet: Wallet
public key: Key
public type: string

public constructor(options: WalletKeyPairOptions) {
super(options)
this.wallet = options.wallet
this.key = options.key
this.type = options.key.keyType
}

public static async generate(): Promise<WalletKeyPair> {
throw new Error('Not implemented')
}

public fingerprint(): string {
throw new Error('Method not implemented.')
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
public verifyFingerprint(fingerprint: string): boolean {
throw new Error('Method not implemented.')
}

public static async from(verificationMethod: VerificationMethod): Promise<WalletKeyPair> {
const vMethod = JsonTransformer.fromJSON(verificationMethod, VerificationMethod)
MessageValidator.validateSync(vMethod)
const { getKeyFromVerificationMethod } = getKeyDidMappingByVerificationMethod(vMethod)
const key = getKeyFromVerificationMethod(vMethod)

return new WalletKeyPair({
id: vMethod.id,
controller: vMethod.controller,
wallet: wallet,
key: key,
})
}

/**
* This method returns a wrapped wallet.sign method. The method is being wrapped so we can covert between Uint8Array and Buffer. This is to make it compatible with the external signature libraries.
*/
public signer(): { sign: (data: { data: Uint8Array | Uint8Array[] }) => Promise<Uint8Array> } {
// wrap function for conversion
const wrappedSign = async (data: { data: Uint8Array | Uint8Array[] }): Promise<Uint8Array> => {
let converted: Buffer | Buffer[] = []

// convert uint8array to buffer
if (Array.isArray(data.data)) {
converted = data.data.map((d) => Buffer.from(d))
} else {
converted = Buffer.from(data.data)
}

// sign
const result = await wallet.sign({
data: converted,
key: this.key,
})

// convert result buffer to uint8array
return Uint8Array.from(result)
}

return {
sign: wrappedSign.bind(this),
}
}

/**
* This method returns a wrapped wallet.verify method. The method is being wrapped so we can covert between Uint8Array and Buffer. This is to make it compatible with the external signature libraries.
*/
public verifier(): {
verify: (data: { data: Uint8Array | Uint8Array[]; signature: Uint8Array }) => Promise<boolean>
} {
const wrappedVerify = async (data: {
data: Uint8Array | Uint8Array[]
signature: Uint8Array
}): Promise<boolean> => {
let converted: Buffer | Buffer[] = []

// convert uint8array to buffer
if (Array.isArray(data.data)) {
converted = data.data.map((d) => Buffer.from(d))
} else {
converted = Buffer.from(data.data)
}

// verify
return wallet.verify({
data: converted,
signature: Buffer.from(data.signature),
key: this.key,
})
}
return {
verify: wrappedVerify.bind(this),
}
}

public get publicKeyBuffer(): Uint8Array {
return new Uint8Array(this.key.publicKey)
}
}
}
Loading

0 comments on commit 76fa3d8

Please sign in to comment.