diff --git a/test/EcdsaMultikey.spec.js b/test/EcdsaMultikey.spec.js index ec12ef0..f96ae42 100644 --- a/test/EcdsaMultikey.spec.js +++ b/test/EcdsaMultikey.spec.js @@ -4,15 +4,18 @@ import * as base58 from 'base58-universal'; import * as EcdsaMultikey from '../lib/index.js'; import chai from 'chai'; -import {CryptoKey, webcrypto} from '../lib/crypto.js'; +import {webcrypto} from '../lib/crypto.js'; import {getNamedCurveFromPublicMultikey} from '../lib/helpers.js'; import {exportKeyPair} from '../lib/serialize.js'; import { mockKey, mockKeyEcdsaSecp256, mockKeyEcdsaSecp384, - mockKeyEcdsaSecp521 + mockKeyEcdsaSecp521, + keyTypes } from './mock-data.js'; +import {testAlgorithm, testGenerate} from './assertions.js'; + const should = chai.should(); const {expect} = chai; @@ -27,18 +30,11 @@ describe('EcdsaMultikey', () => { }); describe('algorithm', () => { - it('signer() instance should export proper algorithm', async () => { - const keyPair = await EcdsaMultikey.from(mockKey); - const signer = keyPair.signer(); - signer.algorithm.should.equal('P-256'); - }); - - it('verifier() instance should export proper algorithm', async () => { - const keyPair = await EcdsaMultikey.from(mockKey); - const verifier = keyPair.verifier(); - verifier.algorithm.should.equal('P-256'); - }); - + for(const [keyType, {serializedKeyPair}] of keyTypes) { + describe(keyType, function() { + testAlgorithm({keyType, serializedKeyPair}); + }); + } it('deriveSecret() should not be supported by default', async () => { const keyPair = await EcdsaMultikey.generate({curve: 'P-256'}); @@ -65,33 +61,12 @@ describe('EcdsaMultikey', () => { }); }); - describe('generate', () => { - it('should generate a key pair', async () => { - let keyPair; - let error; - try { - keyPair = await EcdsaMultikey.generate({curve: 'P-256'}); - } catch(e) { - error = e; - } - should.not.exist(error); - - expect(keyPair).to.have.property('publicKeyMultibase'); - expect(keyPair).to.have.property('secretKeyMultibase'); - expect(keyPair).to.have.property('publicKey'); - expect(keyPair?.publicKey instanceof CryptoKey).to.be.true; - expect(keyPair).to.have.property('secretKey'); - expect(keyPair?.secretKey instanceof CryptoKey).to.be.true; - expect(keyPair).to.have.property('export'); - expect(keyPair).to.have.property('signer'); - expect(keyPair).to.have.property('verifier'); - const secretKeyBytes = base58 - .decode(keyPair.secretKeyMultibase.slice(1)); - const publicKeyBytes = base58 - .decode(keyPair.publicKeyMultibase.slice(1)); - secretKeyBytes.length.should.equal(34); - publicKeyBytes.length.should.equal(35); - }); + describe('generate', function() { + for(const [keyType, {props}] of keyTypes) { + describe(keyType, function() { + testGenerate({curve: keyType, ...props}); + }); + } }); describe('export', () => { diff --git a/test/assertions.js b/test/assertions.js new file mode 100644 index 0000000..7744220 --- /dev/null +++ b/test/assertions.js @@ -0,0 +1,100 @@ +/*! + * Copyright (c) 2023-2024 Digital Bazaar, Inc. + */ +import * as base58 from 'base58-universal'; +import chai from 'chai'; +import * as EcdsaMultikey from '../lib/index.js'; +import {stringToUint8Array} from './text-encoder.js'; +import {CryptoKey} from '../lib/crypto.js'; + +chai.should(); +const {expect} = chai; + +export function testSignVerify({id, serializedKeyPair}) { + let signer; + let verifier; + before(async function() { + const keyPair = await EcdsaMultikey.from({ + id, + ...serializedKeyPair + }); + signer = keyPair.signer(); + verifier = keyPair.verifier(); + }); + it('should have correct id', function() { + signer.should.have.property('id', id); + verifier.should.have.property('id', id); + }); + it('should sign & verify', async function() { + const data = stringToUint8Array('test 1234'); + const signature = await signer.sign({data}); + const result = await verifier.verify({data, signature}); + result.should.be.true; + }); + + it('has proper signature format', async function() { + const data = stringToUint8Array('test 1234'); + const signature = await signer.sign({data}); + expect(signature).to.be.instanceof(Uint8Array); + }); + + it('fails if signing data is changed', async function() { + const data = stringToUint8Array('test 1234'); + const signature = await signer.sign({data}); + const changedData = stringToUint8Array('test 4321'); + const result = await verifier.verify({data: changedData, signature}); + result.should.be.false; + }); +} + +export function testAlgorithm({serializedKeyPair, keyType}) { + it('signer() instance should export proper algorithm', async () => { + const keyPair = await EcdsaMultikey.from(serializedKeyPair); + const signer = keyPair.signer(); + signer.algorithm.should.equal(keyType); + }); + it('verifier() instance should export proper algorithm', async () => { + const keyPair = await EcdsaMultikey.from(serializedKeyPair); + const verifier = keyPair.verifier(); + verifier.algorithm.should.equal(keyType); + }); +} + +export function testGenerate({ + curve, + decoder = base58, + secretKeyByteLength = 34, + publicKeyByteLength = 35 +}) { + it('should generate a key pair', async function() { + let keyPair; + let err; + try { + keyPair = await EcdsaMultikey.generate({curve}); + } catch(e) { + err = e; + } + expect(err).to.not.exist; + + expect(keyPair).to.have.property('publicKeyMultibase'); + expect(keyPair).to.have.property('secretKeyMultibase'); + expect(keyPair).to.have.property('publicKey'); + expect(keyPair?.publicKey instanceof CryptoKey).to.be.true; + expect(keyPair).to.have.property('secretKey'); + expect(keyPair?.secretKey instanceof CryptoKey).to.be.true; + expect(keyPair).to.have.property('export'); + expect(keyPair).to.have.property('signer'); + expect(keyPair).to.have.property('verifier'); + const secretKeyBytes = decoder + .decode(keyPair.secretKeyMultibase.slice(1)); + const publicKeyBytes = decoder + .decode(keyPair.publicKeyMultibase.slice(1)); + secretKeyBytes.length.should.equal( + secretKeyByteLength, + `Expected secretKey byte length to be ${secretKeyByteLength}.`); + publicKeyBytes.length.should.equal( + publicKeyByteLength, + `Expected publicKey byte length to be ${publicKeyByteLength}.`); + }); +} + diff --git a/test/mock-data.js b/test/mock-data.js index b151f93..f2e12f3 100644 --- a/test/mock-data.js +++ b/test/mock-data.js @@ -33,8 +33,31 @@ export const mockKeyEcdsaSecp521 = { 'K6vuzCXSp1hwwvgGGEnQS82ZeKaPcFDrvhWhaq4767Am' }; +const getKeyId = ({controller, publicKeyMultibase}) => + `${controller}#${publicKeyMultibase}`; + export const keyTypes = new Map([ - ['P-256', mockKeyEcdsaSecp256], - ['P-384', mockKeyEcdsaSecp384], - ['P-521', mockKeyEcdsaSecp521] + ['P-256', { + id: getKeyId(mockKeyEcdsaSecp256), + serializedKeyPair: mockKeyEcdsaSecp256, + props: { + + } + }], + ['P-384', { + id: getKeyId(mockKeyEcdsaSecp384), + serializedKeyPair: mockKeyEcdsaSecp384, + props: { + secretKeyByteLength: 50, + publicKeyByteLength: 51 + } + }], + ['P-521', { + id: getKeyId(mockKeyEcdsaSecp521), + serializedKeyPair: mockKeyEcdsaSecp521, + props: { + secretKeyByteLength: 68, + publicKeyByteLength: 69 + } + }] ]); diff --git a/test/multikey.spec.js b/test/multikey.spec.js new file mode 100644 index 0000000..c399a8d --- /dev/null +++ b/test/multikey.spec.js @@ -0,0 +1,14 @@ +/*! + * Copyright (c) 2024 Digital Bazaar, Inc. + */ +/* +import {multikeys} from './mock-data.js'; + +describe('multikey', function() { + for(const [keyType, options] of multikeys) { + describe(keyType, function() { + + }); + } +}) +*/ diff --git a/test/sign-verify.spec.js b/test/sign-verify.spec.js index 10a54a5..6a6112a 100644 --- a/test/sign-verify.spec.js +++ b/test/sign-verify.spec.js @@ -1,60 +1,13 @@ /*! * Copyright (c) 2023-2024 Digital Bazaar, Inc. */ -import chai from 'chai'; -import * as EcdsaMultikey from '../lib/index.js'; import {keyTypes} from './mock-data.js'; -import {stringToUint8Array} from './text-encoder.js'; - -chai.should(); -const {expect} = chai; +import {testSignVerify} from './assertions.js'; describe('sign and verify', function() { - for(const [keyType, exportedKey] of keyTypes) { + for(const [keyType, {serializedKeyPair, id}] of keyTypes) { describe(keyType, function() { - const id = `${exportedKey.controller}#${exportedKey.publicKeyMultibase}`; - _testKeyType({id, exportedKey, keyType}); + testSignVerify({id, serializedKeyPair, keyType}); }); } }); - -function _testKeyType({id, exportedKey, keyType}) { - let signer; - let verifier; - before(async function() { - const keyPair = await EcdsaMultikey.from({ - id, - ...exportedKey - }); - signer = keyPair.signer(); - verifier = keyPair.verifier(); - }); - it('should have correct id', function() { - signer.should.have.property('id', id); - verifier.should.have.property('id', id); - }); - it(`should have algorithm ${keyType}`, function() { - signer.should.have.property('algorithm', keyType); - verifier.should.have.property('algorithm', keyType); - }); - it('should sign & verify', async function() { - const data = stringToUint8Array('test 1234'); - const signature = await signer.sign({data}); - const result = await verifier.verify({data, signature}); - result.should.be.true; - }); - - it('has proper signature format', async function() { - const data = stringToUint8Array('test 1234'); - const signature = await signer.sign({data}); - expect(signature).to.be.instanceof(Uint8Array); - }); - - it('fails if signing data is changed', async function() { - const data = stringToUint8Array('test 1234'); - const signature = await signer.sign({data}); - const changedData = stringToUint8Array('test 4321'); - const result = await verifier.verify({data: changedData, signature}); - result.should.be.false; - }); -}