Skip to content

Commit

Permalink
Improve API surface to keep the same abstraction level
Browse files Browse the repository at this point in the history
  • Loading branch information
ntn-x2 committed Oct 3, 2023
1 parent 812a360 commit 54c8022
Show file tree
Hide file tree
Showing 11 changed files with 771 additions and 159 deletions.
280 changes: 227 additions & 53 deletions packages/did/src/Did2.chain.ts

Large diffs are not rendered by default.

64 changes: 42 additions & 22 deletions packages/did/src/Did2.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import { decode as multibaseDecode, encode as multibaseEncode } from 'multibase'
import { blake2AsU8a, encodeAddress } from '@polkadot/util-crypto'
import { DataUtils, SDKErrors, ss58Format } from '@kiltprotocol/utils'

import type { DidDocumentV2, KiltAddress } from '@kiltprotocol/types'
import type {
DidDocumentV2,
KeyringPair,
KiltAddress,
} from '@kiltprotocol/types'

import type { DidKeyType } from './DidDetailsv2/DidDetailsV2.js'

Expand Down Expand Up @@ -121,18 +125,13 @@ const multicodecReversePrefixes: Record<DidKeyType, number> = {
/**
* Decode a multibase, multicodec representation of a verification method into its fundamental components: the public key and the key type.
*
* @param verificationMethod The verification method.
* @param publicKeyMultibase The verification method's public key multibase.
* @returns The decoded public key and [DidKeyType].
*/
export function decodeMultikeyVerificationMethod(
verificationMethod: Pick<
DidDocumentV2.VerificationMethod,
'publicKeyMultibase'
>
export function multibaseKeyToDidKey(
publicKeyMultibase: DidDocumentV2.VerificationMethod['publicKeyMultibase']
): DecodedVerificationMethod {
const decodedMulticodecPublicKey = multibaseDecode(
verificationMethod.publicKeyMultibase
)
const decodedMulticodecPublicKey = multibaseDecode(publicKeyMultibase)
const [keyTypeFlag, publicKey] = [
decodedMulticodecPublicKey.subarray(0, 1)[0],
decodedMulticodecPublicKey.subarray(1),
Expand All @@ -148,7 +147,32 @@ export function decodeMultikeyVerificationMethod(
throw new Error('Invalid encoding of the verification method.')
}

export function encodeVerificationMethodToMultiKey(
export function keypairToMultibaseKey({
type,
publicKey,
}: Pick<
KeyringPair,
'publicKey' | 'type'
>): DidDocumentV2.VerificationMethod['publicKeyMultibase'] {
const multiCodecPublicKeyPrefix = multicodecReversePrefixes[type]
if (multiCodecPublicKeyPrefix === undefined) {
// TODO: Proper error
throw new Error(`Invalid key type provided: ${type}.`)
}
const expectedPublicKeySize = multicodecPrefixes[multiCodecPublicKeyPrefix][1]
if (publicKey.length !== expectedPublicKeySize) {
// TODO: Proper error
throw new Error(
`Provided public key does not match the expected length: ${expectedPublicKeySize}.`
)
}
const multiCodecPublicKey = [multiCodecPublicKeyPrefix, ...publicKey]
return Buffer.from(
multibaseEncode('base58btc', Buffer.from(multiCodecPublicKey))
).toString() as `z${string}`
}

export function didKeyToVerificationMethod(
controller: DidDocumentV2.VerificationMethod['controller'],
id: DidDocumentV2.VerificationMethod['id'],
{ keyType, publicKey }: DecodedVerificationMethod
Expand Down Expand Up @@ -207,7 +231,7 @@ export function validateUri(
const { address, fragment } = parse(input as DidDocumentV2.DidUri)

if (
fragment &&
fragment !== undefined &&
(expectType === 'Did' ||
// for backwards compatibility with previous implementations, `false` maps to `Did` while `true` maps to `undefined`.
(typeof expectType === 'boolean' && expectType === false))
Expand All @@ -217,7 +241,7 @@ export function validateUri(
)
}

if (!fragment && expectType === 'ResourceUri') {
if (fragment === undefined && expectType === 'ResourceUri') {
throw new SDKErrors.DidError(
'Expected a Kilt DidResourceUri (containing a #fragment) but got a DidUri'
)
Expand All @@ -227,14 +251,10 @@ export function validateUri(
}

// TODO: Fix JSDoc
export function getAddressByVerificationMethod(
verificationMethod: Pick<
DidDocumentV2.VerificationMethod,
'publicKeyMultibase'
>
): KiltAddress {
const { keyType: type, publicKey } =
decodeMultikeyVerificationMethod(verificationMethod)
export function getAddressFromVerificationMethod({
publicKeyMultibase,
}: Pick<DidDocumentV2.VerificationMethod, 'publicKeyMultibase'>): KiltAddress {
const { keyType: type, publicKey } = multibaseKeyToDidKey(publicKeyMultibase)
if (type === 'ed25519' || type === 'sr25519') {
return encodeAddress(publicKey, ss58Format)
}
Expand Down Expand Up @@ -275,6 +295,6 @@ export function getFullDidUriFromVerificationMethod(
'publicKeyMultibase'
>
): DidDocumentV2.DidUri {
const address = getAddressByVerificationMethod(verificationMethod)
const address = getAddressFromVerificationMethod(verificationMethod)
return getFullDidUri(address)
}
3 changes: 2 additions & 1 deletion packages/did/src/DidDetails/LightDidDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { SDKErrors, ss58Format, cbor } from '@kiltprotocol/utils'

import { getAddressByKey, parse } from '../Did.utils.js'
import { resourceIdToChain, validateService } from '../Did.chain.js'
import { NewService } from '../DidDetailsv2/DidDetailsV2.js'

const authenticationKeyId = '#authentication'
const encryptionKeyId = '#encryption'
Expand Down Expand Up @@ -65,7 +66,7 @@ export type CreateDocumentInput = {
* The set of service endpoints associated with this DID. Each service endpoint ID must be unique.
* The service ID must not contain the DID prefix when used to create a new DID.
*/
service?: DidServiceEndpoint[]
service?: NewService[]
}

function validateCreateDocumentInput({
Expand Down
44 changes: 24 additions & 20 deletions packages/did/src/DidDetailsv2/DidDetailsV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,47 @@
* found in the LICENSE file in the root directory of this source tree.
*/

import type { DidDocumentV2, KeyRelationship } from '@kiltprotocol/types'
import type { DidDocumentV2 } from '@kiltprotocol/types'

/**
* Possible types for a DID verification key.
*/
const verificationKeyTypesC = ['sr25519', 'ed25519', 'ecdsa'] as const
export const verificationKeyTypes = verificationKeyTypesC as unknown as string[]
export type VerificationKeyType = typeof verificationKeyTypesC[number]
export type DidVerificationKeyType = typeof verificationKeyTypesC[number]
// `as unknown as string[]` is a workaround for https://github.com/microsoft/TypeScript/issues/26255

/**
* Currently, a light DID does not support the use of an ECDSA key as its authentication key.
*/
export type LightDidSupportedVerificationKeyType = Extract<
VerificationKeyType,
'ed25519' | 'sr25519'
>

/**
* Subset of key relationships which pertain to key agreement/encryption keys.
*/
export type EncryptionKeyRelationship = Extract<KeyRelationship, 'keyAgreement'>

/**
* Possible types for a DID encryption key.
*/
const encryptionKeyTypesC = ['x25519'] as const
export const encryptionKeyTypes = encryptionKeyTypesC as unknown as string[]
export type EncryptionKeyType = typeof encryptionKeyTypesC[number]
export type DidEncryptionKeyType = typeof encryptionKeyTypesC[number]

export type DidKeyType = VerificationKeyType | EncryptionKeyType
export type DidKeyType = DidVerificationKeyType | DidEncryptionKeyType

export type NewVerificationMethod = Omit<
DidDocumentV2.VerificationMethod,
'controller'
> & {
id: DidDocumentV2.UriFragment
>
export type NewService = DidDocumentV2.Service

/**
* Type of a new key material to add under a DID.
*/
export type BaseNewDidKey = {
publicKey: Uint8Array
type: string
}

/**
* Type of a new verification key to add under a DID.
*/
export type NewDidVerificationKey = BaseNewDidKey & {
type: DidVerificationKeyType
}

export type NewServiceEndpoint = DidDocumentV2.Service
/**
* Type of a new encryption key to add under a DID.
*/
export type NewDidEncryptionKey = BaseNewDidKey & { type: DidEncryptionKeyType }
2 changes: 1 addition & 1 deletion packages/did/src/DidDetailsv2/FullDidDetailsV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ function groupExtrinsicsByKeyRelationship(
const [first, ...rest] = extrinsics.map((extrinsic) => {
const verificationMethodRelationship =
getVerificationMethodRelationshipForTx(extrinsic)
if (!verificationMethodRelationship) {
if (verificationMethodRelationship === undefined) {
throw new SDKErrors.DidBatchError(
'Can only batch extrinsics that require a DID signature'
)
Expand Down
Loading

0 comments on commit 54c8022

Please sign in to comment.