Skip to content

Commit

Permalink
Merge pull request #24 from Sphereon-Opensource/develop
Browse files Browse the repository at this point in the history
New release
  • Loading branch information
nklomp authored Mar 19, 2024
2 parents da84e22 + 32d6bd9 commit cde5a2c
Show file tree
Hide file tree
Showing 10 changed files with 3,347 additions and 3,299 deletions.
11 changes: 1 addition & 10 deletions packages/did-provider-key/__tests__/key-did-provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe('@sphereon/did-provider-key', () => {
const identifier: IIdentifier = await agent.didManagerCreate({ options })

expect(identifier).toBeDefined()
expect(identifier.did).toBe('did:key:z7r8oriqybh8QSuroAtjntBoRysmWDxRzCGbJo9GbkG22dd8s6p2jLqbLmWgPYdrkYLdZjTmhFn61UKYBCXL9gxdFLf7Q')
expect(identifier.did).toBe('did:key:zQ3shqZQs23rWENxtomyw4BNz1p23AkbjzwdeYg6DpmhWDDE6')
})

it('should remove identifier', async () => {
Expand Down Expand Up @@ -82,15 +82,6 @@ describe('@sphereon/did-provider-key', () => {
expect(identifier.keys[0].type).toBe(Key.Secp256k1)
})

it('should create identifier with Secp256k1 key', async () => {
const options = { type: Key.Secp256k1 }
const identifier: IIdentifier = await agent.didManagerCreate({ options })

expect(identifier).toBeDefined()
expect(identifier.keys.length).toBe(1)
expect(identifier.keys[0].type).toBe(Key.Secp256k1)
})

it('should create EBSI identifier with Secp256k1 key', async () => {
const options = {
key: {
Expand Down
1 change: 1 addition & 0 deletions packages/did-provider-key/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@transmute/did-key-bls12381": "0.3.0-unstable.10",
"@veramo/core": "4.2.0",
"@veramo/did-manager": "4.2.0",
"did-jwt": "6.11.6",
"debug": "^4.3.4",
"did-resolver": "^4.1.0",
"multibase": "^4.0.6",
Expand Down
33 changes: 22 additions & 11 deletions packages/did-provider-key/src/SphereonKeyDidProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ const debug = Debug('did-provider-key')

type IContext = IAgentContext<IKeyManager>

const keyCodecs = {
RSA: 'rsa-pub',
Ed25519: 'ed25519-pub',
X25519: 'x25519-pub',
Secp256k1: 'secp256k1-pub',
Secp256r1: 'p256-pub',
Bls12381G1: 'bls12_381-g1-pub',
Bls12381G2: 'bls12_381-g2-pub',
} as const

export class SphereonKeyDidProvider extends AbstractIdentifierProvider {
private readonly kms: string

Expand All @@ -43,8 +53,11 @@ export class SphereonKeyDidProvider extends AbstractIdentifierProvider {
},
context: IContext
): Promise<Omit<IIdentifier, 'provider'>> {
const keyType: TKeyType = options?.type ?? 'Secp256k1'
let codecName = options?.codecName && options.codecName === 'EBSI' ? JWK_JCS_PUB_NAME : (options?.codecName as Multicodec.CodecName)
let codecName = (options?.codecName?.toUpperCase() === 'EBSI' ? (JWK_JCS_PUB_NAME as Multicodec.CodecName) : options?.codecName) as
| CodeNameType
| undefined
const keyType: TKeyType = options?.type ?? (codecName === JWK_JCS_PUB_NAME ? 'Secp256r1' : 'Secp256k1')
console.log(`keytype: ${keyType}, codecName: ${codecName}`)
const privateKeyHex = options?.key?.privateKeyHex ?? (await generatePrivateKeyHex(keyType))
const key = await context.agent.keyManagerImport({ type: keyType, privateKeyHex, kms: kms ?? this.kms })
let methodSpecificId: string | undefined
Expand All @@ -59,24 +72,20 @@ export class SphereonKeyDidProvider extends AbstractIdentifierProvider {
Multibase.encode('base58btc', Multicodec.addPrefix(codecName as Multicodec.CodecName, u8a.fromString(key.publicKeyHex, 'hex')))
)
} else {
if (keyType === 'Bls12381G2') {
codecName = 'bls12_381-g2-pub'
} else if (keyType === 'Secp256k1') {
codecName = 'secp256k1-pub'
} else if (keyType === 'Ed25519') {
codecName = 'ed25519-pub'
}
codecName = keyCodecs[keyType]

if (codecName) {
// methodSpecificId = bytesToMultibase({bytes: u8a.fromString(key.publicKeyHex, 'hex'), codecName})
methodSpecificId = u8a
.toString(Multibase.encode('base58btc', Multicodec.addPrefix(codecName as Multicodec.CodecName, u8a.fromString(key.publicKeyHex, 'hex'))))
.toString()
}
}
if (!methodSpecificId) {
throw Error(`Key type ${keyType} is not supported currently for did:key`)
throw Error(`Key type ${keyType}, codec ${codecName} is not supported currently for did:key`)
}
const identifier: Omit<IIdentifier, 'provider'> = {
did: 'did:key:' + methodSpecificId,
did: `did:key:${methodSpecificId}`,
controllerKeyId: key.kid,
keys: [key],
services: [],
Expand Down Expand Up @@ -116,3 +125,5 @@ export class SphereonKeyDidProvider extends AbstractIdentifierProvider {
throw Error('KeyDIDProvider removeService not supported')
}
}

type CodeNameType = Multicodec.CodecName | 'rsa-pub' | 'jwk_jcs-pub'
16 changes: 11 additions & 5 deletions packages/did-utils/src/did-functions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { computeAddress } from '@ethersproject/transactions'
import { UniResolver } from '@sphereon/did-uni-client'
import { ENC_KEY_ALGS, hexKeyFromPEMBasedJwk, JwkKeyUse, toJwk } from '@sphereon/ssi-sdk-ext.key-utils'
import { ENC_KEY_ALGS, hexKeyFromPEMBasedJwk, JwkKeyUse, padLeft, toJwk } from '@sphereon/ssi-sdk-ext.key-utils'
import { base58ToBytes, base64ToBytes, bytesToHex, hexToBytes, multibaseKeyToBytes } from '@sphereon/ssi-sdk.core'
import { convertPublicKeyToX25519 } from '@stablelib/ed25519'
import { DIDDocument, DIDDocumentSection, DIDResolutionResult, IAgentContext, IDIDManager, IIdentifier, IKey, IResolver } from '@veramo/core'
Expand Down Expand Up @@ -102,13 +102,12 @@ export function extractPublicKeyHexWithJwkSupport(pk: _ExtendedVerificationMetho
if (pk.publicKeyJwk.kty === 'EC') {
const secp256 = new elliptic.ec(pk.publicKeyJwk.crv === 'secp256k1' ? 'secp256k1' : 'p256')

// const prefix = pk.publicKeyJwk.crv === 'secp256k1' ? '04' : '03'
const x = u8a.fromString(pk.publicKeyJwk.x!, 'base64url')
const y = u8a.fromString(pk.publicKeyJwk.y!, 'base64url')

const xHex = u8a.toString(x, 'base16')
const yHex = u8a.toString(y, 'base16')
const prefix = '04'
const xHex = padLeft({ data: u8a.toString(x, 'base16'), size: 32, padString: '0' })
const yHex = padLeft({ data: u8a.toString(y, 'base16'), size: 32, padString: '0' })
const prefix = '04' // isEven(yHex) ? '02' : '03'
// Uncompressed Hex format: 04<x><y>
// Compressed Hex format: 02<x> (for even y) or 03<x> (for uneven y)
const hex = `${prefix}${xHex}${yHex}`
Expand All @@ -126,6 +125,10 @@ export function extractPublicKeyHexWithJwkSupport(pk: _ExtendedVerificationMetho
return extractPublicKeyHex(pk, convert)
}

export function isEvenHexString(hex: string) {
const lastChar = hex[hex.length - 1].toLowerCase()
return ['0', '2', '4', '6', '8', 'a', 'c', 'e'].includes(lastChar)
}
interface LegacyVerificationMethod extends VerificationMethod {
publicKeyBase64: string
}
Expand Down Expand Up @@ -319,6 +322,9 @@ export async function getKey(
context: IAgentContext<IResolver & IDIDManager>,
keyId?: string
): Promise<IKey> {
if (!identifier) {
return Promise.reject(new Error(`No identifier provided to getKey method!`))
}
const keys = await mapIdentifierKeysToDocWithJwkSupport(identifier, verificationMethodSection, context)
if (!keys || keys.length === 0) {
throw new Error(`No keys found for verificationMethodSection: ${verificationMethodSection} and did ${identifier.did}`)
Expand Down
4 changes: 2 additions & 2 deletions packages/key-manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
"generate-plugin-schema": "sphereon dev generate-plugin-schema"
},
"dependencies": {
"@mattrglobal/bbs-signatures": "^1.3.0",
"@sphereon/ssi-sdk-ext.kms-local": "workspace:^",
"@veramo/core": "4.2.0",
"@veramo/key-manager": "4.2.0"
},
"devDependencies": {
"@sphereon/ssi-sdk-ext.key-utils": "workspace:*",
"@sphereon/ssi-sdk.dev": "^0.15.1"
"@sphereon/ssi-sdk.dev": "^0.15.1",
"@mattrglobal/bbs-signatures": "^1.3.1"
},
"resolutions": {
"jsonld": "npm:@digitalcredentials/jsonld@^5.2.1",
Expand Down
15 changes: 15 additions & 0 deletions packages/key-utils/src/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,18 @@ const toRSAJwk = (publicKeyHex: string, opts?: { use?: JwkKeyUse; key?: IKey }):
const publicKeyPEM = key?.meta?.publicKeyPEM ?? hexToPEM(publicKeyHex, 'public')
return PEMToJwk(publicKeyPEM, 'public') as JsonWebKey
}

export const padLeft = (args: { data: string; size?: number; padString?: string }): string => {
const { data } = args
const size = args.size ?? 32
const padString = args.padString ?? '0'
if (data.length >= size) {
return data
}

if (padString && padString.length === 0) {
throw Error(`Pad string needs to have at least a length of 1`)
}
const length = padString.length
return padString.repeat((size - data.length) / length) + data
}
2 changes: 1 addition & 1 deletion packages/key-utils/src/types/key-util-types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MinimalImportableKey } from '@veramo/core'

export const JWK_JCS_PUB_NAME = 'jwk_jcs-pub'
export const JWK_JCS_PUB_NAME = 'jwk_jcs-pub' as const
export const JWK_JCS_PUB_PREFIX = 0xeb51

export type TKeyType = 'Ed25519' | 'Secp256k1' | 'Secp256r1' | 'X25519' | 'Bls12381G1' | 'Bls12381G2' | 'RSA'
Expand Down
10 changes: 9 additions & 1 deletion packages/kms-local/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"generate-plugin-schema": "sphereon dev generate-plugin-schema"
},
"dependencies": {
"@mattrglobal/bbs-signatures": "^1.3.0",
"@sphereon/isomorphic-webcrypto": "2.4.0-unstable.4",
"@sphereon/ssi-sdk-ext.did-utils": "workspace:^",
"@sphereon/ssi-sdk-ext.key-utils": "workspace:^",
Expand All @@ -23,10 +22,19 @@
},
"devDependencies": {
"@sphereon/jsencrypt": "3.3.2-unstable.0",
"@mattrglobal/bbs-signatures": "^1.3.1",
"@sphereon/ssi-sdk.dev": "^0.15.1",
"@types/elliptic": "6.4.14",
"@veramo/cli": "4.2.0"
},
"peerDependencies": {
"@mattrglobal/bbs-signatures": "^1.3.1"
},
"peerDependenciesMeta": {
"@mattrglobal/bbs-signatures": {
"optional": true
}
},
"resolutions": {
"**/@digitalcredentials/ed25519-verification-key-2020": "3.2.2"
},
Expand Down
32 changes: 27 additions & 5 deletions packages/kms-local/src/SphereonKeyManagementSystem.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { blsSign, generateBls12381G2KeyPair } from '@mattrglobal/bbs-signatures'
// import { blsSign, generateBls12381G2KeyPair } from '@mattrglobal/bbs-signatures'
import {
generatePrivateKeyHex,
hexToPEM,
Expand Down Expand Up @@ -46,6 +46,7 @@ export class SphereonKeyManagementSystem extends KeyManagementSystem {
debug('imported key', managedKey.type, managedKey.publicKeyHex)
return managedKey

case 'Secp256k1':
case 'Secp256r1':
// @ts-ignore
case 'RSA': {
Expand All @@ -67,7 +68,10 @@ export class SphereonKeyManagementSystem extends KeyManagementSystem {

switch (type) {
case KeyType.Bls12381G2: {
const keyPairBls12381G2 = await generateBls12381G2KeyPair()
// throw Error('BLS support not available because upstream is not really providing Windows and React-Native support; giving too much headache')
// @ts-ignore
const mattr = await import('@mattrglobal/bbs-signatures')
const keyPairBls12381G2 = await mattr.generateBls12381G2KeyPair()
key = await this.importKey({
type,
privateKeyHex: Buffer.from(keyPairBls12381G2.secretKey).toString('hex'),
Expand Down Expand Up @@ -103,6 +107,9 @@ export class SphereonKeyManagementSystem extends KeyManagementSystem {
}

if (privateKey.type === KeyType.Bls12381G2) {
// throw Error('BLS support not available because upstream is not really providing Windows and React-Native support; giving too much headache')
// @ts-ignore
const mattr = await import('@mattrglobal/bbs-signatures')
if (!data || Array.isArray(data)) {
throw new Error('Data must be defined and cannot be an array')
}
Expand All @@ -113,7 +120,7 @@ export class SphereonKeyManagementSystem extends KeyManagementSystem {
},
messages: [data],
}
return Buffer.from(await blsSign(keyPair)).toString('hex')
return Buffer.from(await mattr.blsSign(keyPair)).toString('hex')
} else if (
// @ts-ignore
privateKey.type === 'RSA' &&
Expand Down Expand Up @@ -158,17 +165,32 @@ export class SphereonKeyManagementSystem extends KeyManagementSystem {
},
}
break
case 'Secp256k1': {
const privateBytes = u8a.fromString(args.privateKeyHex.toLowerCase(), 'base16')
const secp256k1 = new elliptic.ec('secp256k1')
const keyPair = secp256k1.keyFromPrivate(privateBytes, 'hex')
const publicKeyHex = keyPair.getPublic(true, 'hex')
key = {
type: args.type,
kid: args.alias ?? publicKeyHex,
publicKeyHex,
meta: {
algorithms: ['ES256'],
},
}
break
}
case 'Secp256r1': {
const privateBytes = u8a.fromString(args.privateKeyHex.toLowerCase(), 'base16')
const secp256r1 = new elliptic.ec('p256')
const keyPair = secp256r1.keyFromPrivate(privateBytes)
const keyPair = secp256r1.keyFromPrivate(privateBytes, 'hex')
const publicKeyHex = keyPair.getPublic(true, 'hex')
key = {
type: args.type,
kid: args.alias ?? publicKeyHex,
publicKeyHex,
meta: {
algorithms: ['ES256'],
algorithms: ['ES256K', 'ES256K-R', 'eth_signTransaction', 'eth_signTypedData', 'eth_signMessage', 'eth_rawSign'],
},
}
break
Expand Down
Loading

0 comments on commit cde5a2c

Please sign in to comment.