Skip to content

Commit

Permalink
@zcloak/message: peer to peer message transport (#20)
Browse files Browse the repository at this point in the history
* add @zcloak/message

* refact IDidKeyring and implement it

* add is functions

* encrypt and decrypt message
  • Loading branch information
zzcwoshizz committed Nov 16, 2022
1 parent b5c44af commit fa2f59a
Show file tree
Hide file tree
Showing 35 changed files with 1,234 additions and 93 deletions.
1 change: 1 addition & 0 deletions jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module.exports = Object.assign({}, config, {
'@zcloak/did-resolver(.*)$': '<rootDir>/packages/did-resolver/src/$1',
'@zcloak/did(.*)$': '<rootDir>/packages/did/src/$1',
'@zcloak/keyring(.*)$': '<rootDir>/packages/keyring/src/$1',
'@zcloak/message(.*)$': '<rootDir>/packages/message/src/$1',
'@zcloak/vc(.*)$': '<rootDir>/packages/vc/src/$1',
'@zcloak/verify(.*)$': '<rootDir>/packages/verify/src/$1',
'@zcloak/wasm(.*)$': '<rootDir>/packages/wasm/src/$1'
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
},
"devDependencies": {
"@types/jest": "^27.4.0",
"@zcloak/dev": "^0.6.2"
"@zcloak/dev": "^0.6.3"
},
"resolutions": {
"typescript": "^4.8.4"
Expand Down
3 changes: 1 addition & 2 deletions packages/ctype/src/publish.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright 2021-2022 zcloak authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { DidUrl } from '@zcloak/did-resolver/types';
import type { BaseCType } from './types';

import { generateMnemonic, initCrypto } from '@zcloak/crypto';
Expand Down Expand Up @@ -39,7 +38,7 @@ describe('publish ctype', (): void => {
};

expect(getCTypeHash(base, publisher.id)).toEqual(
getCTypeHash(base, publisher.getKeyUrl('authentication') as DidUrl)
getCTypeHash(base, publisher.getKeyUrl('authentication'))
);
});

Expand Down
2 changes: 1 addition & 1 deletion packages/ctype/src/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function getCTypeHash(
export function getPublish(base: BaseCType, publisher: Did): CType {
const hash = getCTypeHash(base, publisher.id);

const { id, signature } = publisher.signWithKey('authentication', hash);
const { id, signature } = publisher.signWithKey(hash, 'authentication');

return {
$id: hash,
Expand Down
27 changes: 27 additions & 0 deletions packages/did-resolver/src/MockDidResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2021-2022 zcloak authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { DidDocument, DidUrl } from './types';

import { DidResolver } from './DidResolver';
import { DidNotFoundError } from './errors';

export class MockDidResolver extends DidResolver {
#map: Map<DidUrl, DidDocument> = new Map();

public override resolve(didUrl: string): Promise<DidDocument> {
const { did } = this.parseDid(didUrl);

const document = this.#map.get(did);

if (!document) {
throw new DidNotFoundError();
}

return Promise.resolve(document);
}

public addDocument(document: DidDocument): void {
this.#map.set(document.id, document);
}
}
2 changes: 2 additions & 0 deletions packages/did-resolver/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@

export * from './DidResolver';
export * from './ArweaveDidResolver';

export * from './MockDidResolver';
2 changes: 1 addition & 1 deletion packages/did/src/did/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export abstract class DidChain extends DidDetails {

const proof: DidDocumentProof[] = document.proof ?? [];

const { id, signature } = this.signWithKey('capabilityInvocation', hashDidDocument(document));
const { id, signature } = this.signWithKey(hashDidDocument(document), 'capabilityInvocation');

proof.push({ id, signature: base58Encode(signature), type: 'creation' });

Expand Down
76 changes: 63 additions & 13 deletions packages/did/src/did/details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import type {
VerificationMethodType
} from '@zcloak/did-resolver/types';
import type { KeypairType, KeyringPair } from '@zcloak/keyring/types';
import type { IDidDetails, KeyRelationship } from '../types';
import type { DidKeys, SignedData } from './types';
import type { DidKeys, EncryptedData, IDidDetails, KeyRelationship, SignedData } from '../types';

import { assert } from '@polkadot/util';

import { base58Encode } from '@zcloak/crypto';
import { DidResolver } from '@zcloak/did-resolver';
import { defaultResolver } from '@zcloak/did-resolver/defaults';

import { fromDid } from './helpers';
import { DidKeyring } from './keyring';

export function typeTransform(type: KeypairType): VerificationMethodType {
Expand Down Expand Up @@ -67,37 +69,85 @@ export abstract class DidDetails extends DidKeyring implements IDidDetails {
this.service = service;
}

public getKeyUrl(key: DidKeys): DidUrl | undefined {
return Array.from(this[key] ?? [])[0];
public getKeyUrl(key: DidKeys): DidUrl {
const didUrl = Array.from(this[key] ?? [])[0];

assert(didUrl, `Not find verification method with the key: ${key}`);

return didUrl;
}

public get(id: DidUrl): KeyRelationship {
const method = this.keyRelationship.get(id);

assert(method, `Not find verficationMethod with id ${id}`);
assert(method, `Not find verficationMethod with id: ${id}`);

return method;
}

public signWithKey(key: DidKeys, message: Uint8Array | HexString): SignedData {
public override signWithKey(
message: Uint8Array | HexString,
key: Exclude<DidKeys, 'keyAgreement'>
): SignedData {
const didUrl = this.getKeyUrl(key);

assert(didUrl, `can not find verification method with the key: ${key}`);

return this.signWithId(didUrl, message);
return this.sign(message, didUrl);
}

public signWithId(id: DidUrl, message: Uint8Array | HexString): SignedData {
const { publicKey } = this.get(id);
const signature = this.sign(publicKey, message);
public override sign(message: Uint8Array | HexString, id: DidUrl): SignedData {
const { id: _id, publicKey } = this.get(id);
const pair = this.getPair(publicKey);

const signature = pair.sign(message);

return {
signature,
type: typeTransform(this.getPair(publicKey).type),
id
id: _id
};
}

public override async encrypt(
message: Uint8Array | HexString,
receiverUrlIn: DidUrl,
senderUrl: DidUrl = this.getKeyUrl('keyAgreement'),
resolver: DidResolver = defaultResolver
): Promise<EncryptedData> {
const { id, publicKey } = this.get(senderUrl);
const pair = this.getPair(publicKey);

const receiver = await fromDid(receiverUrlIn, undefined, resolver);

const { id: receiverUrl, publicKey: receiverPublicKey } = receiver.get(receiverUrlIn);

const encrypted = pair.encrypt(message, receiverPublicKey);

return {
senderUrl: id,
receiverUrl,
type: 'X25519KeyAgreementKey2019',
data: encrypted
};
}

public override async decrypt(
encryptedMessageWithNonce: Uint8Array | HexString,
senderUrlIn: DidUrl,
receiverUrl: DidUrl,
resolver: DidResolver = defaultResolver
): Promise<Uint8Array> {
const { publicKey } = this.get(receiverUrl);
const pair = this.getPair(publicKey);

const sender = await fromDid(senderUrlIn, undefined, resolver);

const { publicKey: senderPublicKey } = sender.get(senderUrlIn);

const decrypted = pair.decrypt(encryptedMessageWithNonce, senderPublicKey);

return decrypted;
}

public getDocument(): DidDocument {
assert(this.controller.size > 0, 'Must has one controller');

Expand Down
4 changes: 2 additions & 2 deletions packages/did/src/did/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export function parseDidDocument(document: DidDocument): IDidDetails {
*/
export async function fromDid(
did: DidUrl,
keyring: KeyringInstance = new Keyring(),
keyring?: KeyringInstance,
resolver: DidResolver = defaultResolver
): Promise<Did> {
const document = await resolver.resolve(did);
Expand All @@ -94,7 +94,7 @@ export async function fromDid(
*/
export function fromDidDocument(
document: DidDocument,
keyring: KeyringInstance = new Keyring(),
keyring?: KeyringInstance,
resolver: DidResolver = defaultResolver
): Did {
const details = parseDidDocument(document);
Expand Down
40 changes: 39 additions & 1 deletion packages/did/src/did/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Copyright 2021-2022 zcloak authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { ethereumEncode } from '@zcloak/crypto';
import { stringToU8a } from '@polkadot/util';

import { ethereumEncode, generateMnemonic } from '@zcloak/crypto';
import { MockDidResolver } from '@zcloak/did-resolver';
import { DidDocument } from '@zcloak/did-resolver/types';
import { Keyring } from '@zcloak/keyring';

Expand Down Expand Up @@ -33,7 +36,13 @@ const DOCUMENT: DidDocument = {
service: []
};

const resolver = new MockDidResolver();

describe('Did', (): void => {
beforeAll(() => {
resolver.addDocument(DOCUMENT);
});

describe('create', (): void => {
let keyring: Keyring;

Expand All @@ -59,6 +68,8 @@ describe('Did', (): void => {
'health correct setup usage father decorate curious copper sorry recycle skin equal';
const did = createEcdsaFromMnemonic(mnemonic, keyring);

resolver.addDocument(did.getDocument());

expect(did.get([...(did.authentication ?? [])][0]).publicKey).toEqual(key0);
expect(did.get([...(did.keyAgreement ?? [])][0]).publicKey).toEqual(key1);
expect([...did.controller][0]).toEqual(`did:zk:${ethereumEncode(controllerKey)}`);
Expand All @@ -84,4 +95,31 @@ describe('Did', (): void => {
expect(document.service).toEqual(DOCUMENT.service);
});
});

describe('encrypt and decrypt', (): void => {
it('encrypt and decrypt', async (): Promise<void> => {
const sender = createEcdsaFromMnemonic(generateMnemonic(12));
const receiver = createEcdsaFromMnemonic(generateMnemonic(12));

resolver.addDocument(sender.getDocument());
resolver.addDocument(receiver.getDocument());

const message = stringToU8a('abcd');

const {
data: encrypted,
receiverUrl,
senderUrl
} = await sender.encrypt(
message,
receiver.getKeyUrl('keyAgreement'),
sender.getKeyUrl('keyAgreement'),
resolver
);

const decrypted = await receiver.decrypt(encrypted, senderUrl, receiverUrl, resolver);

expect(decrypted).toEqual(message);
});
});
});
40 changes: 18 additions & 22 deletions packages/did/src/did/keyring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// SPDX-License-Identifier: Apache-2.0

import type { HexString } from '@zcloak/crypto/types';
import type { DidResolver } from '@zcloak/did-resolver';
import type { DidUrl } from '@zcloak/did-resolver/types';
import type { KeyringInstance } from '@zcloak/keyring/types';
import type { IDidKeyring } from '../types';
import type { DidKeys, EncryptedData, IDidKeyring, SignedData } from '../types';

import { assert } from '@polkadot/util';

Expand All @@ -20,30 +22,24 @@ export abstract class DidKeyring implements IDidKeyring {
return this.#keyring.getPair(publicKey);
}

public sign(publicKey: Uint8Array, message: Uint8Array | HexString): Uint8Array {
const pair = this.getPair(publicKey);
public abstract signWithKey(
message: Uint8Array | HexString,
key: Exclude<DidKeys, 'keyAgreement'>
): SignedData;

return pair.sign(message);
}
public abstract sign(message: Uint8Array | HexString, id: DidUrl): SignedData;

public encrypt(
publicKey: Uint8Array,
public abstract encrypt(
message: Uint8Array | HexString,
recipientPublicKey: Uint8Array | HexString,
nonce?: Uint8Array | HexString | undefined
): Uint8Array {
const pair = this.getPair(publicKey);

return pair.encrypt(message, recipientPublicKey, nonce);
}
receiverUrl: DidUrl,
senderUrl?: DidUrl,
resolver?: DidResolver
): Promise<EncryptedData>;

public decrypt(
publicKey: Uint8Array,
public abstract decrypt(
encryptedMessageWithNonce: Uint8Array | HexString,
senderPublicKey: Uint8Array | HexString
): Uint8Array {
const pair = this.getPair(publicKey);

return pair.decrypt(encryptedMessageWithNonce, senderPublicKey);
}
senderUrl: DidUrl,
receiverUrl: DidUrl,
resolver?: DidResolver
): Promise<Uint8Array>;
}
16 changes: 0 additions & 16 deletions packages/did/src/did/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
// Copyright 2021-2022 zcloak authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { DidUrl, VerificationMethodType } from '@zcloak/did-resolver/types';

// @internal generate keys
export type KeyGen = {
// the identifier publicKey
identifier: Uint8Array;
Expand All @@ -13,16 +10,3 @@ export type KeyGen = {
*/
keys: [Uint8Array, Uint8Array];
};

export type SignedData = {
id: DidUrl;
type: VerificationMethodType;
signature: Uint8Array;
};

export type DidKeys =
| 'authentication'
| 'assertionMethod'
| 'keyAgreement'
| 'capabilityInvocation'
| 'capabilityDelegation';
Loading

0 comments on commit fa2f59a

Please sign in to comment.