diff --git a/tests/setup.js b/tests/setup.js index 9199715..912119c 100644 --- a/tests/setup.js +++ b/tests/setup.js @@ -4,8 +4,10 @@ */ import { deriveCredentials, + getMultikeys, issueCredentials } from './vc-generator/index.js'; +import {generators} from 'data-integrity-test-suite-assertion'; export async function verifySetup({credentials, keyTypes, suite}) { const testVectors = { @@ -25,22 +27,31 @@ export async function verifySetup({credentials, keyTypes, suite}) { lessThanFull: new Map(), //disclosedCredentialsWithoutFirstArrayElement missingElements: new Map() + }, + invalid: { + // invalid "proof.type" and "proof.cryptosuite" + proofTypeAndCryptosuite: new Map(), + // invalid "proof.cryptosuite" + cryptosuite: new Map() } } }; const {subjectNestedObjects, subjectHasArrays} = credentials.verify; + const keys = await getMultikeys({keyTypes}); + // takes an object with keys versions values vector and + // transforms the vectors + const transformVectors = (obj, func = id => id) => Object.entries(obj).map( + input => { + const [vcVersion, vector] = input; + return [vcVersion, func(structuredClone(vector))]; + }); + // create initial signed VCs testVectors.signed = await issueCredentials({ credentials: Object.entries(subjectNestedObjects), suite, keyTypes }); - // takes an object with keys versions values vector and - // transforms the vectors - const transformVectors = (obj, func) => Object.entries(obj).map(input => { - const [vcVersion, vector] = input; - return [vcVersion, func(structuredClone(vector))]; - }); const disclosedBaseVectors = transformVectors( subjectNestedObjects, vector => { @@ -50,8 +61,8 @@ export async function verifySetup({credentials, keyTypes, suite}) { // use initial VCs for a basic selective disclosure test testVectors.disclosed.base = await deriveCredentials({ vectors: disclosedBaseVectors, - suite, - keyTypes + suiteName: suite, + keys }); const disclosedNestedVectors = transformVectors( subjectNestedObjects, @@ -63,8 +74,8 @@ export async function verifySetup({credentials, keyTypes, suite}) { // create initial nestedDisclosedCredential from signedVc testVectors.disclosed.nested = await deriveCredentials({ vectors: disclosedNestedVectors, - suite, - keyTypes + suiteName: suite, + keys }); const disclosedNoIdVectors = transformVectors( subjectNestedObjects, @@ -78,14 +89,14 @@ export async function verifySetup({credentials, keyTypes, suite}) { ); testVectors.disclosed.noIds = await deriveCredentials({ vectors: disclosedNoIdVectors, - keyTypes, - suite + keys, + suiteName: suite }); // select full arrays testVectors.disclosed.array.full = await deriveCredentials({ - vectors: Object.entries(structuredClone(subjectHasArrays)), - suite, - keyTypes + vectors: transformVectors(subjectHasArrays), + suiteName: suite, + keys }); const lessThanFullVectors = transformVectors( subjectHasArrays, @@ -97,8 +108,8 @@ export async function verifySetup({credentials, keyTypes, suite}) { ); testVectors.disclosed.array.lessThanFull = await deriveCredentials({ vectors: lessThanFullVectors, - suite, - keyTypes + suiteName: suite, + keys }); const removeFirst7Vectors = transformVectors( subjectHasArrays, @@ -110,8 +121,23 @@ export async function verifySetup({credentials, keyTypes, suite}) { ); testVectors.disclosed.array.missingElements = await deriveCredentials({ vectors: removeFirst7Vectors, - suite, - keyTypes + suiteName: suite, + keys + }); + const {mandatory} = generators; + const {invalidCryptosuite, invalidProofType} = mandatory; + testVectors.disclosed.invalid.proofTypeAndCryptosuite = + await deriveCredentials({ + keys, + vectors: transformVectors(subjectNestedObjects), + suiteName: suite, + generators: [invalidProofType, invalidCryptosuite] + }); + testVectors.disclosed.invalid.cryptosuite = await deriveCredentials({ + keys, + vectors: transformVectors(subjectNestedObjects), + suiteName: suite, + generators: [invalidCryptosuite] }); return testVectors; } diff --git a/tests/suites/verify.js b/tests/suites/verify.js index 6044f40..98ac537 100644 --- a/tests/suites/verify.js +++ b/tests/suites/verify.js @@ -48,72 +48,69 @@ export function verifySuite({ }; }); const {disclosed, signed} = credentials; - const getTestVector = map => map?.get(keyType)?.get(vcVersion); + const cloneTestVector = map => structuredClone( + map?.get(keyType)?.get(vcVersion)); it('MUST verify a valid VC with a bbs-2023 proof.', async function() { - const credential = getTestVector(disclosed?.base); + const credential = cloneTestVector(disclosed?.base); await verificationSuccess({credential, verifier}); }); it('MUST verify a valid VC with nested disclosed properties.', async function() { - const credential = getTestVector(disclosed?.nested); + const credential = cloneTestVector(disclosed?.nested); await verificationSuccess({credential, verifier}); }); it('MUST verify a valid VC with disclosed properties and bnodes.', async function() { - const credential = getTestVector(disclosed?.noIds); + const credential = cloneTestVector(disclosed?.noIds); await verificationSuccess({credential, verifier}); }); it('MUST verify with full array revealed properties', async function() { - const credential = getTestVector(disclosed?.array?.full); + const credential = cloneTestVector(disclosed?.array?.full); await verificationSuccess({credential, verifier}); }); it('MUST verify with fewer array revealed properties', async function() { - const credential = getTestVector(disclosed?.array?.lessThanFull); + const credential = cloneTestVector(disclosed?.array?.lessThanFull); await verificationSuccess({credential, verifier}); }); it('MUST verify w/o first element revealed properties', async function() { - const credential = getTestVector(disclosed?.array?.missingElements); + const credential = cloneTestVector( + disclosed?.array?.missingElements); await verificationSuccess({credential, verifier}); }); it('If the "proofValue" string does not start with "u", an ' + 'error MUST be raised.', async function() { - const credential = getTestVector(disclosed?.base); - const signedCredentialCopy = structuredClone(credential); + const credential = cloneTestVector(disclosed?.base); // intentionally modify proofValue to not start with 'u' - signedCredentialCopy.proof.proofValue = 'a'; - await verificationFail({ - credential: signedCredentialCopy, verifier - }); + credential.proof.proofValue = 'a'; + await verificationFail({credential, verifier}); }); it('If the "cryptosuite" field is not the string "bbs-2023", ' + 'an error MUST be raised.', async function() { - const credential = getTestVector(disclosed?.base); - const signedCredentialCopy = structuredClone(credential); - signedCredentialCopy.proof.cryptosuite = 'invalid-cryptosuite'; - await verificationFail({ - credential: signedCredentialCopy, verifier - }); + const credential = cloneTestVector(disclosed?.invalid?.cryptosuite); + await verificationFail({credential, verifier}); + }); + it('If proofConfig.type is not set to DataIntegrityProof and/or ' + + 'proofConfig.cryptosuite is not set to bbs-2023, an ' + + 'INVALID_PROOF_CONFIGURATION error MUST be raised.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-bbs/#base-proof-transformation-bbs-2023:~:text=If%20proofConfig.type%20is%20not%20set%20to%20DataIntegrityProof%20and/or%20proofConfig.cryptosuite%20is%20not%20set%20to%20bbs%2D2023%2C%20an%20INVALID_PROOF_CONFIGURATION%20error%20MUST%20be%20raised.'; + const credential = cloneTestVector( + disclosed?.invalid?.proofTypeAndCryptosuite); + await verificationFail({credential, verifier}); }); it('MUST fail to verify a base proof.', async function() { - const credential = getTestVector(signed); - const signedCredentialCopy = structuredClone(credential); - await verificationFail({ - credential: signedCredentialCopy, verifier - }); + const credential = cloneTestVector(signed); + await verificationFail({credential, verifier}); }); it('MUST fail to verify a modified disclosed credential.', async function() { - const credential = getTestVector(disclosed?.base); - const signedCredentialCopy = structuredClone(credential); + const credential = cloneTestVector(disclosed?.base); // intentionally modify `credentialSubject` ID - signedCredentialCopy.credentialSubject.id = 'urn:invalid'; - await verificationFail({ - credential: signedCredentialCopy, verifier - }); + credential.credentialSubject.id = 'urn:invalid'; + await verificationFail({credential, verifier}); }); }); } diff --git a/tests/vc-generator/index.js b/tests/vc-generator/index.js index 38ec93e..228ccc0 100644 --- a/tests/vc-generator/index.js +++ b/tests/vc-generator/index.js @@ -6,6 +6,7 @@ import * as vc from '@digitalbazaar/vc'; import {documentLoader as defaultLoader} from './documentLoader.js'; import {getMultikeys} from './key-gen.js'; import {getSuite} from './cryptosuites.js'; +import {issueCloned} from 'data-integrity-test-suite-assertion'; /** * Issues test data locally and then returns a Map @@ -64,52 +65,6 @@ export async function issueCredential({ }); } -/** - * Derives test data locally and then returns a Map - * with the test data. - * - * @param {object} options - Options to use. - * @param {Map} options.vectors - Version & VC creation options. - * @param {Function} [options.documentLoader = defaultLoader] - A - * documentLoader(url). - * @param {string} options.suite - A cryptosuite id. - * @param {Array} options.keyTypes - A list of key types. - * - * @returns {Promise>} Returns a Map . - */ -export async function deriveCredentials({ - vectors, - documentLoader = defaultLoader, - suite, - keyTypes = ['P-381'] -}) { - const results = new Map(); - const keys = await getMultikeys({keyTypes}); - for(const [keyType, {signer, issuer}] of keys) { - const versionedVcs = new Map(); - for(const [vcVersion, vector] of vectors) { - const {credential, mandatoryPointers, selectivePointers} = vector; - const verifiableCredential = await issueCredential({ - credential, - issuer, - signer, - suite, - mandatoryPointers - }); - const derivedVc = await deriveCredential({ - verifiableCredential, - documentLoader, - suite, - signer, - selectivePointers - }); - versionedVcs.set(vcVersion, derivedVc); - } - results.set(keyType, versionedVcs); - } - return results; -} - export async function deriveCredential({ documentLoader = defaultLoader, verifiableCredential, @@ -135,3 +90,35 @@ export async function verifyCredential({ suite: getSuite({suite, verify: true}) }); } + +export async function deriveCredentials({ + keys, + vectors, + map = new Map(), + suiteName, + generators = [] +}) { + for(const [keyType, {signer, issuer}] of keys) { + map.set(keyType, new Map()); + for(const [vcVersion, vector] of vectors) { + const {credential, mandatoryPointers, selectivePointers} = vector; + const _credential = structuredClone(credential); + _credential.issuer = issuer; + // the first params passed to the first generator + const initParams = { + suite: getSuite({suite: suiteName, signer, mandatoryPointers}), + selectiveSuite: getSuite({suite: suiteName, signer, selectivePointers}), + credential: _credential + }; + // call each generator on itself to produce accumulated invalid suites + // and vectors + const testData = generators.reduce((accumulator, current) => + current(accumulator), initParams); + const vc = await issueCloned(testData); + map.get(keyType).set(vcVersion, vc); + } + } + return map; +} + +export {getSuite, getMultikeys};