import { compressPublicKey, sign } from '@pdsjs/core/crypto'; import { publicKeyToDidKey } from '@pdsjs/core/plc'; import { describe, expect, it } from 'vitest'; import { createVerifier, parseDidKey } from '../src/verifier.js'; import { vectors } from './helpers/vectors.js'; async function p256() { const keys = await crypto.subtle.generateKey( { name: 'ECDSA', namedCurve: 'P-256' }, true, ['sign', 'verify'], ); const raw = new Uint8Array( await crypto.subtle.exportKey('raw', keys.publicKey), ); return { didKey: publicKeyToDidKey(compressPublicKey(raw), 'p256'), /** @param {Uint8Array} data */ sign: (data) => sign(keys.privateKey, data), }; } describe('parseDidKey', () => { it('recognises the P-256 multicodec', () => { const parsed = parseDidKey(vectors.kem.authorDidKey); expect(parsed.curve).toBe('p256'); expect(parsed.publicKey.length).toBe(33); }); it('rejects a non-did:key string', () => { expect(() => parseDidKey('did:plc:aaaa')).toThrow(/did:key/); }); }); describe('createVerifier', () => { it('verifies a P-256 signature', async () => { const key = await p256(); const data = new Uint8Array([1, 2, 3]); expect( await createVerifier().verify(key.didKey, data, await key.sign(data)), ).toBe(true); }); it('rejects a tampered signature or data', async () => { const key = await p256(); const data = new Uint8Array([1, 2, 3]); const sig = await key.sign(data); const badSig = sig.slice(); badSig[0] ^= 0xff; expect(await createVerifier().verify(key.didKey, data, badSig)).toBe(false); expect( await createVerifier().verify(key.didKey, new Uint8Array([1, 2, 4]), sig), ).toBe(false); }); it('rejects secp256k1 when no verifier is injected', async () => { const verifier = createVerifier(); // did:key with the secp256k1 multicodec, the well-known example from the // did:key spec (https://w3c-ccg.github.io/did-method-key/#secp256k1). await expect( verifier.verify( 'zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme', new Uint8Array(1), new Uint8Array(64), ), ).rejects.toThrow(/secp256k1/); }); it('delegates secp256k1 to an injected verifier', async () => { /** @type {any} */ let called = null; const verifier = createVerifier({ secp256k1: async (publicKey, data, sig) => { called = { publicKey, data, sig }; return true; }, }); const didKey = 'did:key:zQ3shokFTS3brHcDQrn82RUDfCZESWL1ZdCEJwekUDPQiYBme'; const data = new Uint8Array([1, 2, 3]); const sig = new Uint8Array(64); expect(await verifier.verify(didKey, data, sig)).toBe(true); expect(called.data).toEqual(data); expect(called.publicKey.length).toBe(33); }); });