UNPKG

ts-mls

Version:

[![CI](https://github.com/LukaJCB/ts-mls/actions/workflows/ci.yml/badge.svg)](https://github.com/LukaJCB/ts-mls/actions/workflows/ci.yml) [![npm version](https://badge.fury.io/js/ts-mls.svg)](https://badge.fury.io/js/ts-mls) [![Coverage Status](https://co

86 lines 4.97 kB
import { getCiphersuiteFromId, getCiphersuiteImpl } from "../../src/crypto/ciphersuite"; import { hexToBytes } from "@noble/ciphers/utils"; import jsonCommit from "../../test_vectors/passive-client-handling-commit.json"; import jsonRandom from "../../test_vectors/passive-client-random.json"; import jsonWelcome from "../../test_vectors/passive-client-welcome.json"; import { hpkeKeysMatch, signatureKeysMatch } from "../crypto/keyMatch"; import { decodeMlsMessage } from "../../src/message"; import { decodeRatchetTree } from "../../src/ratchetTree"; import { joinGroup, makePskIndex } from "../../src/clientState"; import { processPrivateMessage, processPublicMessage } from "../../src/processMessages"; import { bytesToBase64 } from "../../src/util/byteArray"; for (const [index, x] of jsonCommit.entries()) { test(`passive-client-handling-commit test vectors ${index}`, async () => { const impl = await getCiphersuiteImpl(getCiphersuiteFromId(x.cipher_suite)); await testPassiveClientScenario(x, impl); }); } for (const [index, x] of jsonRandom.entries()) { test(`passive-client-random test vectors ${index}`, async () => { const impl = await getCiphersuiteImpl(getCiphersuiteFromId(x.cipher_suite)); await testPassiveClientScenario(x, impl); }, 40000); } for (const [index, x] of jsonWelcome.entries()) { test(`passive-client-welcome test vectors ${index}`, async () => { const impl = await getCiphersuiteImpl(getCiphersuiteFromId(x.cipher_suite)); await testPassiveClientScenario(x, impl); }); } async function testPassiveClientScenario(data, impl) { const kp = decodeMlsMessage(hexToBytes(data.key_package), 0); if (kp === undefined || kp[0].wireformat !== "mls_key_package") throw new Error("Could not decode KeyPackage"); await verifyKeys(data, kp[0].keyPackage, impl); const welcome = decodeMlsMessage(hexToBytes(data.welcome), 0); if (welcome === undefined || welcome[0].wireformat !== "mls_welcome") throw new Error("Could not decode Welcome"); const pks = { hpkePrivateKey: hexToBytes(data.encryption_priv), initPrivateKey: hexToBytes(data.init_priv), signaturePrivateKey: hexToBytes(data.signature_priv), }; const tree = data.ratchet_tree !== null ? decodeRatchetTree(hexToBytes(data.ratchet_tree), 0)?.[0] : undefined; const psks = data.external_psks.reduce((acc, psk) => ({ ...acc, [bytesToBase64(hexToBytes(psk.psk_id))]: hexToBytes(psk.psk) }), {}); let state = await joinGroup(welcome[0].welcome, kp[0].keyPackage, pks, makePskIndex(undefined, psks), impl, tree); expect(state.keySchedule.epochAuthenticator).toStrictEqual(hexToBytes(data.initial_epoch_authenticator)); for (const epoch of data.epochs) { for (const proposal of epoch.proposals) { const mlsProposal = decodeMlsMessage(hexToBytes(proposal), 0); if (mlsProposal === undefined || (mlsProposal[0].wireformat !== "mls_private_message" && mlsProposal[0].wireformat !== "mls_public_message")) throw new Error("Could not decode proposal message"); if (mlsProposal[0].wireformat === "mls_private_message") { const res = await processPrivateMessage(state, mlsProposal[0].privateMessage, makePskIndex(state, psks), impl); state = res.newState; } else { const res = await processPublicMessage(state, mlsProposal[0].publicMessage, makePskIndex(state, psks), impl); state = res.newState; } } const mlsCommit = decodeMlsMessage(hexToBytes(epoch.commit), 0); if (mlsCommit === undefined || (mlsCommit[0].wireformat !== "mls_private_message" && mlsCommit[0].wireformat !== "mls_public_message")) throw new Error("Could not decode commit message"); if (mlsCommit[0].wireformat === "mls_private_message") { const res = await processPrivateMessage(state, mlsCommit[0].privateMessage, makePskIndex(state, psks), impl); state = res.newState; } else { const res = await processPublicMessage(state, mlsCommit[0].publicMessage, makePskIndex(state, psks), impl); state = res.newState; } expect(state.keySchedule.epochAuthenticator).toStrictEqual(hexToBytes(epoch.epoch_authenticator)); } } async function verifyKeys(data, kp, impl) { const hpke = await hpkeKeysMatch(kp.leafNode.hpkePublicKey, hexToBytes(data.encryption_priv), impl.hpke); expect(hpke).toBe(true); const hpkeInit = await hpkeKeysMatch(kp.initKey, hexToBytes(data.init_priv), impl.hpke); expect(hpkeInit).toBe(true); const sig = await signatureKeysMatch(kp.leafNode.signaturePublicKey, hexToBytes(data.signature_priv), impl.signature); expect(sig).toBe(true); hexToBytes(data.init_priv); } //# sourceMappingURL=passiveClientScenarios.test.js.map