From f79bb5dc13d27436ce7c8c5ef1eb2c3bd0c07e60 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 6 Nov 2024 15:24:30 -0500 Subject: [PATCH 01/13] Add initial data model suite intended for issuers. --- tests/suites/data-model.js | 67 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tests/suites/data-model.js diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js new file mode 100644 index 00000000..9f6f3ad7 --- /dev/null +++ b/tests/suites/data-model.js @@ -0,0 +1,67 @@ +/*! + * Copyright 2024 Digital Bazaar, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +import { + assertions, +} from 'data-integrity-test-suite-assertion'; + +export function dataModelSuite({ + issuers, + suiteName, + keyType, + vcVersion, + credential, + mandatoryPointers, + selectivePointers, +}) { + describe(`${suiteName} - Data Model - VC ${vcVersion}`, function() { + this.matrix = true; + this.report = true; + this.implemented = [...issuers]; + this.rowLabel = 'Test Name'; + this.columnLabel = 'Implementation'; + for(const [name, {endpoints}] of issuers) { + const [issuer] = endpoints; + describe(`${name}: ${keyType}`, function() { + let securedCredential = null; + let issuerError = null; + before(async function(){ + + }); + beforeEach(function() { + this.currentTest.cell = { + rowId: this.currentTest.title, + columnId: this.currentTest.parent.title + }; + }); + it('The publicKeyMultibase value of the verification method MUST ' + + 'start with the base-58-btc prefix (z), as defined in the ' + + 'Multibase section of Controller Documents 1.0. A ' + + 'Multibase-encoded Ed25519 256-bit public key value follows, as ' + + 'defined in the Multikey section of Controller Documents 1.0.', + async function() { + this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=in%20this%20specification.-,The%20publicKeyMultibase%20value%20of%20the%20verification%20method%20MUST%20start%20with%20the%20base%2D58%2Dbtc%20prefix,-(z)%2C%20as'; + }); + it('Any other encoding MUST NOT be allowed. (verificationMethod)', + async function() { + this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=of%20Controller%20Documents%201.0.-,Any%20other%20encoding%20MUST%20NOT%20be%20allowed.,-Developers%20are%20advised%20to%20not'; + }); + it('The type property MUST be DataIntegrityProof.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=The%20type%20property%20MUST%20be%20DataIntegrityProof.'; + }); + it('The cryptosuite property of the proof MUST be eddsa-rdfc-2022 or ' + + 'eddsa-jcs-2022.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=The%20cryptosuite%20property%20of%20the%20proof%20MUST%20be%20eddsa%2Drdfc%2D2022%20or%20eddsa%2Djcs%2D2022.'; + }); + it('The proofValue property of the proof MUST be a detached EdDSA ' + + 'signature produced according to [RFC8032], encoded using the ' + + 'base-58-btc header and alphabet as described in the Multibase ' + + 'section of Controller Documents 1.0.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=The%20proofValue%20property%20of%20the%20proof%20MUST%20be%20a%20detached%20EdDSA%20signature%20produced%20according%20to%20%5BRFC8032%5D%2C%20encoded%20using%20the%20base%2D58%2Dbtc%20header%20and%20alphabet%20as%20described%20in%20the%20Multibase%20section%20of%20Controller%20Documents%201.0.'; + + }); + }); + } + }); +} From b6bc2939315867dbfa998da82e692089bd4ddfa2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 6 Nov 2024 16:07:03 -0500 Subject: [PATCH 02/13] Add assertBefore & endpoint check. --- tests/suites/data-model.js | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js index 9f6f3ad7..3c278997 100644 --- a/tests/suites/data-model.js +++ b/tests/suites/data-model.js @@ -2,9 +2,11 @@ * Copyright 2024 Digital Bazaar, Inc. * SPDX-License-Identifier: BSD-3-Clause */ +import {createInitialVc, endpointCheck} from '../helpers.js'; import { assertions, } from 'data-integrity-test-suite-assertion'; +import {expect} from 'chai'; export function dataModelSuite({ issuers, @@ -12,8 +14,7 @@ export function dataModelSuite({ keyType, vcVersion, credential, - mandatoryPointers, - selectivePointers, + mandatoryPointers }) { describe(`${suiteName} - Data Model - VC ${vcVersion}`, function() { this.matrix = true; @@ -23,11 +24,19 @@ export function dataModelSuite({ this.columnLabel = 'Implementation'; for(const [name, {endpoints}] of issuers) { const [issuer] = endpoints; + // does the endpoint support this test? + if(!endpointCheck({endpoint: issuer, keyType, vcVersion})) { + continue; + } describe(`${name}: ${keyType}`, function() { let securedCredential = null; - let issuerError = null; - before(async function(){ - + before(async function() { + securedCredential = await createInitialVc({ + issuer, + vcVersion, + vc: credential, + mandatoryPointers + }); }); beforeEach(function() { this.currentTest.cell = { @@ -35,6 +44,12 @@ export function dataModelSuite({ columnId: this.currentTest.parent.title }; }); + function assertBefore() { + expect( + securedCredential, + `Expected issuer ${name}: ${keyType} to issue a VC` + ).to.exist; + } it('The publicKeyMultibase value of the verification method MUST ' + 'start with the base-58-btc prefix (z), as defined in the ' + 'Multibase section of Controller Documents 1.0. A ' + @@ -42,23 +57,28 @@ export function dataModelSuite({ 'defined in the Multikey section of Controller Documents 1.0.', async function() { this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=in%20this%20specification.-,The%20publicKeyMultibase%20value%20of%20the%20verification%20method%20MUST%20start%20with%20the%20base%2D58%2Dbtc%20prefix,-(z)%2C%20as'; + assertBefore(); }); it('Any other encoding MUST NOT be allowed. (verificationMethod)', async function() { this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=of%20Controller%20Documents%201.0.-,Any%20other%20encoding%20MUST%20NOT%20be%20allowed.,-Developers%20are%20advised%20to%20not'; + assertBefore(); }); it('The type property MUST be DataIntegrityProof.', async function() { this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=The%20type%20property%20MUST%20be%20DataIntegrityProof.'; + assertBefore(); }); it('The cryptosuite property of the proof MUST be eddsa-rdfc-2022 or ' + 'eddsa-jcs-2022.', async function() { this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=The%20cryptosuite%20property%20of%20the%20proof%20MUST%20be%20eddsa%2Drdfc%2D2022%20or%20eddsa%2Djcs%2D2022.'; + assertBefore(); }); it('The proofValue property of the proof MUST be a detached EdDSA ' + 'signature produced according to [RFC8032], encoded using the ' + 'base-58-btc header and alphabet as described in the Multibase ' + 'section of Controller Documents 1.0.', async function() { this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=The%20proofValue%20property%20of%20the%20proof%20MUST%20be%20a%20detached%20EdDSA%20signature%20produced%20according%20to%20%5BRFC8032%5D%2C%20encoded%20using%20the%20base%2D58%2Dbtc%20header%20and%20alphabet%20as%20described%20in%20the%20Multibase%20section%20of%20Controller%20Documents%201.0.'; + assertBefore(); }); }); From 42d791fb1a6be338e9343f7642553895f6bb356e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 6 Nov 2024 16:59:56 -0500 Subject: [PATCH 03/13] Fill in first VM test & get proofs. --- tests/suites/data-model.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js index 3c278997..2b3065ce 100644 --- a/tests/suites/data-model.js +++ b/tests/suites/data-model.js @@ -16,7 +16,7 @@ export function dataModelSuite({ credential, mandatoryPointers }) { - describe(`${suiteName} - Data Model - VC ${vcVersion}`, function() { + return describe(`${suiteName} - Data Model - VC ${vcVersion}`, function() { this.matrix = true; this.report = true; this.implemented = [...issuers]; @@ -30,6 +30,7 @@ export function dataModelSuite({ } describe(`${name}: ${keyType}`, function() { let securedCredential = null; + let proofs = []; before(async function() { securedCredential = await createInitialVc({ issuer, @@ -37,6 +38,12 @@ export function dataModelSuite({ vc: credential, mandatoryPointers }); + if(securedCredential) { + proofs = Array.isArray(securedCredential.proofs) ? + securedCredential?.proofs : [securedCredential?.proofs]; + // only test proofs that match the relevant cryptosuite + proofs.filter(p => p.cryptosuite === suiteName); + } }); beforeEach(function() { this.currentTest.cell = { @@ -49,6 +56,10 @@ export function dataModelSuite({ securedCredential, `Expected issuer ${name}: ${keyType} to issue a VC` ).to.exist; + expect( + securedCredential, + 'Expected VC to be an object' + ).to.be.an('object'); } it('The publicKeyMultibase value of the verification method MUST ' + 'start with the base-58-btc prefix (z), as defined in the ' + @@ -58,6 +69,14 @@ export function dataModelSuite({ async function() { this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=in%20this%20specification.-,The%20publicKeyMultibase%20value%20of%20the%20verification%20method%20MUST%20start%20with%20the%20base%2D58%2Dbtc%20prefix,-(z)%2C%20as'; assertBefore(); + for(const proof of proofs) { + expect(proof.verificationMethod).to.exist; + expect(proof.verificationMethod).to.be.a('string'); + expect( + assertions.shouldBeBs58(proof.verificationMethod), + 'Expected "proof.verificationMethod" to be Base58 encoded' + ).to.be.true; + } }); it('Any other encoding MUST NOT be allowed. (verificationMethod)', async function() { From 36cb201e7d367d10bd907a7de197fd8e96404af5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 6 Nov 2024 17:05:03 -0500 Subject: [PATCH 04/13] Add further assertions on proofs to data model suite. --- tests/suites/data-model.js | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js index 2b3065ce..4c8be234 100644 --- a/tests/suites/data-model.js +++ b/tests/suites/data-model.js @@ -82,15 +82,34 @@ export function dataModelSuite({ async function() { this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=of%20Controller%20Documents%201.0.-,Any%20other%20encoding%20MUST%20NOT%20be%20allowed.,-Developers%20are%20advised%20to%20not'; assertBefore(); + for(const proof of proofs) { + expect(proof.verificationMethod).to.exist; + expect(proof.verificationMethod).to.be.a('string'); + expect( + assertions.shouldBeBs58(proof.verificationMethod), + 'Expected "proof.verificationMethod" to be Base58 encoded' + ).to.be.true; + } }); it('The type property MUST be DataIntegrityProof.', async function() { this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=The%20type%20property%20MUST%20be%20DataIntegrityProof.'; assertBefore(); + for(const proof of proofs) { + expect(proof.type).to.exist; + expect(proof.type).to.be.a('string'); + expect(proof.type).to.equal('DataIntegrityProof'); + } }); it('The cryptosuite property of the proof MUST be eddsa-rdfc-2022 or ' + 'eddsa-jcs-2022.', async function() { this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=The%20cryptosuite%20property%20of%20the%20proof%20MUST%20be%20eddsa%2Drdfc%2D2022%20or%20eddsa%2Djcs%2D2022.'; assertBefore(); + for(const proof of proofs) { + expect(proof.cryptosuite).to.exist; + expect(proof.cryptosuite).to.be.a('string'); + expect(proof.cryptosuite).to.oneOf( + ['eddsa-rdfc-2022', 'eddsa-jcs-2022']); + } }); it('The proofValue property of the proof MUST be a detached EdDSA ' + 'signature produced according to [RFC8032], encoded using the ' + @@ -98,7 +117,14 @@ export function dataModelSuite({ 'section of Controller Documents 1.0.', async function() { this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=The%20proofValue%20property%20of%20the%20proof%20MUST%20be%20a%20detached%20EdDSA%20signature%20produced%20according%20to%20%5BRFC8032%5D%2C%20encoded%20using%20the%20base%2D58%2Dbtc%20header%20and%20alphabet%20as%20described%20in%20the%20Multibase%20section%20of%20Controller%20Documents%201.0.'; assertBefore(); - + for(const proof of proofs) { + expect(proof.proofValue).to.exist; + expect(proof.proofValue).to.be.a('string'); + expect( + assertions.shouldBeBs58(proof.proofValue), + 'Expected "proof.proofValue" to be Base58 encoded' + ).to.be.true; + } }); }); } From 0c32e033a208ed581f82715f51e9b1d79cd8836c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 7 Nov 2024 10:22:51 -0500 Subject: [PATCH 05/13] Add initial data-model test. --- tests/80-data-model.js | 38 ++++++++++++++++++++++++++++++++++++++ tests/suites/data-model.js | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/80-data-model.js diff --git a/tests/80-data-model.js b/tests/80-data-model.js new file mode 100644 index 00000000..d2ed151f --- /dev/null +++ b/tests/80-data-model.js @@ -0,0 +1,38 @@ +/*! + * Copyright 2024 Digital Bazaar, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ +import {dataModelSuite} from './suites/data-model.js'; +import {endpoints} from 'vc-test-suite-implementations'; +import {getSuiteConfig} from './test-config.js'; + +const cryptosuites = [ + 'ecdsa-rdfc-2019', + 'ecdsa-jcs-2019' +]; + +for(const suiteName of cryptosuites) { + const {tags, credentials, vectors} = getSuiteConfig(suiteName); + const {match: issuers} = endpoints.filterByTag({ + tags: [...tags], + property: 'issuers' + }); + for(const vcVersion of vectors.vcTypes) { + const { + document, + mandatoryPointers, + selectivePointers + } = credentials.create[vcVersion]; + for(const keyType of vectors.keyTypes) { + dataModelSuite({ + issuers, + suiteName, + keyType, + vcVersion, + credential: document, + mandatoryPointers, + selectivePointers + }); + } + } +} diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js index 4c8be234..97f1d962 100644 --- a/tests/suites/data-model.js +++ b/tests/suites/data-model.js @@ -107,7 +107,7 @@ export function dataModelSuite({ for(const proof of proofs) { expect(proof.cryptosuite).to.exist; expect(proof.cryptosuite).to.be.a('string'); - expect(proof.cryptosuite).to.oneOf( + expect(proof.cryptosuite).to.be.oneOf( ['eddsa-rdfc-2022', 'eddsa-jcs-2022']); } }); From 280abf85fe0dca409c51f941d206cf34f142e886 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 7 Nov 2024 10:33:25 -0500 Subject: [PATCH 06/13] Remove proofValue test from data model & update links. --- tests/suites/data-model.js | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js index 97f1d962..c7823836 100644 --- a/tests/suites/data-model.js +++ b/tests/suites/data-model.js @@ -63,11 +63,9 @@ export function dataModelSuite({ } it('The publicKeyMultibase value of the verification method MUST ' + 'start with the base-58-btc prefix (z), as defined in the ' + - 'Multibase section of Controller Documents 1.0. A ' + - 'Multibase-encoded Ed25519 256-bit public key value follows, as ' + - 'defined in the Multikey section of Controller Documents 1.0.', + 'Multibase section of Controller Documents 1.0. A ', async function() { - this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=in%20this%20specification.-,The%20publicKeyMultibase%20value%20of%20the%20verification%20method%20MUST%20start%20with%20the%20base%2D58%2Dbtc%20prefix,-(z)%2C%20as'; + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#data-model:~:text=The%20publicKeyMultibase%20value%20of%20the%20verification%20method%20MUST%20start%20with%20the%20base%2D58%2Dbtc%20prefix%20(z)%2C%20as%20defined%20in%20the%20Multibase%20section%20of%20Controller%20Documents%201.0.'; assertBefore(); for(const proof of proofs) { expect(proof.verificationMethod).to.exist; @@ -80,7 +78,7 @@ export function dataModelSuite({ }); it('Any other encoding MUST NOT be allowed. (verificationMethod)', async function() { - this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=of%20Controller%20Documents%201.0.-,Any%20other%20encoding%20MUST%20NOT%20be%20allowed.,-Developers%20are%20advised%20to%20not'; + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#multikey'; assertBefore(); for(const proof of proofs) { expect(proof.verificationMethod).to.exist; @@ -92,7 +90,7 @@ export function dataModelSuite({ } }); it('The type property MUST be DataIntegrityProof.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=The%20type%20property%20MUST%20be%20DataIntegrityProof.'; + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#multikey:~:text=The%20type%20property%20MUST%20be%20DataIntegrityProof.'; assertBefore(); for(const proof of proofs) { expect(proof.type).to.exist; @@ -100,30 +98,15 @@ export function dataModelSuite({ expect(proof.type).to.equal('DataIntegrityProof'); } }); - it('The cryptosuite property of the proof MUST be eddsa-rdfc-2022 or ' + - 'eddsa-jcs-2022.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=The%20cryptosuite%20property%20of%20the%20proof%20MUST%20be%20eddsa%2Drdfc%2D2022%20or%20eddsa%2Djcs%2D2022.'; + it('The cryptosuite property MUST be ecdsa-rdfc-2019, ' + + 'ecdsa-jcs-2019, or ecdsa-sd-2023.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#multikey:~:text=The%20cryptosuite%20property%20MUST%20be%20ecdsa%2Drdfc%2D2019%2C%20ecdsa%2Djcs%2D2019%2C%20or%20ecdsa%2Dsd%2D2023.'; assertBefore(); for(const proof of proofs) { expect(proof.cryptosuite).to.exist; expect(proof.cryptosuite).to.be.a('string'); expect(proof.cryptosuite).to.be.oneOf( - ['eddsa-rdfc-2022', 'eddsa-jcs-2022']); - } - }); - it('The proofValue property of the proof MUST be a detached EdDSA ' + - 'signature produced according to [RFC8032], encoded using the ' + - 'base-58-btc header and alphabet as described in the Multibase ' + - 'section of Controller Documents 1.0.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-eddsa/#data-model:~:text=The%20proofValue%20property%20of%20the%20proof%20MUST%20be%20a%20detached%20EdDSA%20signature%20produced%20according%20to%20%5BRFC8032%5D%2C%20encoded%20using%20the%20base%2D58%2Dbtc%20header%20and%20alphabet%20as%20described%20in%20the%20Multibase%20section%20of%20Controller%20Documents%201.0.'; - assertBefore(); - for(const proof of proofs) { - expect(proof.proofValue).to.exist; - expect(proof.proofValue).to.be.a('string'); - expect( - assertions.shouldBeBs58(proof.proofValue), - 'Expected "proof.proofValue" to be Base58 encoded' - ).to.be.true; + ['ecdsa-rdfc-2019', 'edcsa-jcs-2019', 'ecdsa-sd-2023']); } }); }); From 4edf3a5d5be4bfdc333ce5e49c1e97f32734a22c Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 7 Nov 2024 10:38:03 -0500 Subject: [PATCH 07/13] Comment out jcs & correct naming in before statement. --- tests/80-data-model.js | 3 ++- tests/suites/data-model.js | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/80-data-model.js b/tests/80-data-model.js index d2ed151f..15419520 100644 --- a/tests/80-data-model.js +++ b/tests/80-data-model.js @@ -8,7 +8,8 @@ import {getSuiteConfig} from './test-config.js'; const cryptosuites = [ 'ecdsa-rdfc-2019', - 'ecdsa-jcs-2019' + 'ecdsa-sd-2023' + //FIXME implement jcs 'ecdsa-jcs-2019' ]; for(const suiteName of cryptosuites) { diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js index c7823836..90e5d0c2 100644 --- a/tests/suites/data-model.js +++ b/tests/suites/data-model.js @@ -39,10 +39,10 @@ export function dataModelSuite({ mandatoryPointers }); if(securedCredential) { - proofs = Array.isArray(securedCredential.proofs) ? - securedCredential?.proofs : [securedCredential?.proofs]; + proofs = Array.isArray(securedCredential.proof) ? + securedCredential?.proof : [securedCredential?.proof]; // only test proofs that match the relevant cryptosuite - proofs.filter(p => p.cryptosuite === suiteName); + proofs = proofs.filter(p => p?.cryptosuite === suiteName); } }); beforeEach(function() { From e7d9a88e5b11438dd2e1996209ed39f62c2fa387 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 7 Nov 2024 10:45:41 -0500 Subject: [PATCH 08/13] Use didResolver to assert on publicKeyMultibase. --- tests/suites/data-model.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js index 90e5d0c2..5a8bf7f4 100644 --- a/tests/suites/data-model.js +++ b/tests/suites/data-model.js @@ -6,6 +6,7 @@ import {createInitialVc, endpointCheck} from '../helpers.js'; import { assertions, } from 'data-integrity-test-suite-assertion'; +import {didResolver} from '../didResolver.js'; import {expect} from 'chai'; export function dataModelSuite({ @@ -70,9 +71,12 @@ export function dataModelSuite({ for(const proof of proofs) { expect(proof.verificationMethod).to.exist; expect(proof.verificationMethod).to.be.a('string'); + const didDoc = await didResolver({url: proof.verificationMethod}); + expect(didDoc).to.be.an('object'); + expect(didDoc.publicKeyMultibase).to.be.a('string'); expect( - assertions.shouldBeBs58(proof.verificationMethod), - 'Expected "proof.verificationMethod" to be Base58 encoded' + assertions.shouldBeBs58(didDoc.publicKeyMultibase), + 'Expected "publicKeyMultibase" to be Base58 encoded' ).to.be.true; } }); @@ -83,9 +87,12 @@ export function dataModelSuite({ for(const proof of proofs) { expect(proof.verificationMethod).to.exist; expect(proof.verificationMethod).to.be.a('string'); + const didDoc = await didResolver({url: proof.verificationMethod}); + expect(didDoc).to.be.an('object'); + expect(didDoc.publicKeyMultibase).to.be.a('string'); expect( - assertions.shouldBeBs58(proof.verificationMethod), - 'Expected "proof.verificationMethod" to be Base58 encoded' + assertions.shouldBeBs58(didDoc.publicKeyMultibase), + 'Expected "publicKeyMultibase" to be Base58 encoded' ).to.be.true; } }); From 574811276b2ceb5239a98374084b6721ab2164f2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 11 Nov 2024 16:20:05 +0000 Subject: [PATCH 09/13] Update tests/suites/data-model.js add period to end of sentence. Co-authored-by: Ted Thibodeau Jr --- tests/suites/data-model.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js index 5a8bf7f4..4d338bba 100644 --- a/tests/suites/data-model.js +++ b/tests/suites/data-model.js @@ -55,11 +55,11 @@ export function dataModelSuite({ function assertBefore() { expect( securedCredential, - `Expected issuer ${name}: ${keyType} to issue a VC` + `Expected issuer ${name}: ${keyType} to issue a VC.` ).to.exist; expect( securedCredential, - 'Expected VC to be an object' + 'Expected VC to be an object.' ).to.be.an('object'); } it('The publicKeyMultibase value of the verification method MUST ' + From 24fe1c974b740d79a22c40eaa32b0834a139b783 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 11 Nov 2024 16:21:55 +0000 Subject: [PATCH 10/13] Update tests/suites/data-model.js add period to bs58 reason. Co-authored-by: Ted Thibodeau Jr --- tests/suites/data-model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js index 4d338bba..ba17f16e 100644 --- a/tests/suites/data-model.js +++ b/tests/suites/data-model.js @@ -76,7 +76,7 @@ export function dataModelSuite({ expect(didDoc.publicKeyMultibase).to.be.a('string'); expect( assertions.shouldBeBs58(didDoc.publicKeyMultibase), - 'Expected "publicKeyMultibase" to be Base58 encoded' + 'Expected "publicKeyMultibase" to be Base58 encoded.' ).to.be.true; } }); From 2035e752d69d41a3ad337885d11a129dab6a8ffe Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 11 Nov 2024 16:22:17 +0000 Subject: [PATCH 11/13] Update tests/suites/data-model.js add missing period to end of bs58 reason. Co-authored-by: Ted Thibodeau Jr --- tests/suites/data-model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js index ba17f16e..18a79dc8 100644 --- a/tests/suites/data-model.js +++ b/tests/suites/data-model.js @@ -92,7 +92,7 @@ export function dataModelSuite({ expect(didDoc.publicKeyMultibase).to.be.a('string'); expect( assertions.shouldBeBs58(didDoc.publicKeyMultibase), - 'Expected "publicKeyMultibase" to be Base58 encoded' + 'Expected "publicKeyMultibase" to be Base58 encoded.' ).to.be.true; } }); From df7e5726c08069bda91aab71e0ac19af9b08ce3f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 11 Nov 2024 16:25:34 +0000 Subject: [PATCH 12/13] Update tests/suites/data-model.js Remove trailing A from end of sentence. --- tests/suites/data-model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js index 18a79dc8..f1403020 100644 --- a/tests/suites/data-model.js +++ b/tests/suites/data-model.js @@ -64,7 +64,7 @@ export function dataModelSuite({ } it('The publicKeyMultibase value of the verification method MUST ' + 'start with the base-58-btc prefix (z), as defined in the ' + - 'Multibase section of Controller Documents 1.0. A ', + 'Multibase section of Controller Documents 1.0. ', async function() { this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#data-model:~:text=The%20publicKeyMultibase%20value%20of%20the%20verification%20method%20MUST%20start%20with%20the%20base%2D58%2Dbtc%20prefix%20(z)%2C%20as%20defined%20in%20the%20Multibase%20section%20of%20Controller%20Documents%201.0.'; assertBefore(); From c20af055d55744c6efd6f6f84ea1858ce85c2999 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 11 Nov 2024 17:40:08 +0000 Subject: [PATCH 13/13] Handle implemented & multi-key-types. --- tests/70-conformance.js | 20 ++-- tests/80-data-model.js | 20 ++-- tests/suites/conformance.js | 86 ++++++++-------- tests/suites/data-model.js | 190 +++++++++++++++++++----------------- 4 files changed, 163 insertions(+), 153 deletions(-) diff --git a/tests/70-conformance.js b/tests/70-conformance.js index 5243eb9c..90b33243 100644 --- a/tests/70-conformance.js +++ b/tests/70-conformance.js @@ -23,16 +23,14 @@ for(const suiteName of cryptosuites) { mandatoryPointers, selectivePointers } = credentials.create[vcVersion]; - for(const keyType of vectors.keyTypes) { - conformanceSuite({ - verifiers, - suiteName, - keyType, - vcVersion, - credential: document, - mandatoryPointers, - selectivePointers - }); - } + conformanceSuite({ + verifiers, + suiteName, + keyTypes: vectors.keyTypes, + vcVersion, + credential: document, + mandatoryPointers, + selectivePointers + }); } } diff --git a/tests/80-data-model.js b/tests/80-data-model.js index 15419520..e67f2e05 100644 --- a/tests/80-data-model.js +++ b/tests/80-data-model.js @@ -24,16 +24,14 @@ for(const suiteName of cryptosuites) { mandatoryPointers, selectivePointers } = credentials.create[vcVersion]; - for(const keyType of vectors.keyTypes) { - dataModelSuite({ - issuers, - suiteName, - keyType, - vcVersion, - credential: document, - mandatoryPointers, - selectivePointers - }); - } + dataModelSuite({ + issuers, + suiteName, + keyTypes: vectors.keyTypes, + vcVersion, + credential: document, + mandatoryPointers, + selectivePointers + }); } } diff --git a/tests/suites/conformance.js b/tests/suites/conformance.js index 0b4e6585..8df7bce0 100644 --- a/tests/suites/conformance.js +++ b/tests/suites/conformance.js @@ -14,7 +14,7 @@ import {getSuite} from '../vc-generator/cryptosuites.js'; export function conformanceSuite({ verifiers, suiteName, - keyType, + keyTypes, vcVersion, credential, mandatoryPointers, @@ -24,52 +24,58 @@ export function conformanceSuite({ return describe(`${suiteName} - Conformance - VC ${vcVersion}`, function() { this.matrix = true; this.report = true; - this.implemented = [...verifiers]; + this.implemented = []; this.rowLabel = 'Test Name'; this.columnLabel = 'Implementation'; - let credentials = new Map(); + const credentials = new Map(keyTypes.map(kt => [kt, null])); before(async function() { - credentials = await setup({ - credential, - mandatoryPointers, - selectivePointers, - suiteName, - keyType - }); + for(const keyType of keyTypes) { + credentials.set(keyType, await setup({ + credential, + mandatoryPointers, + selectivePointers, + suiteName, + keyType + })); + } }); for(const [name, {endpoints}] of verifiers) { const [verifier] = endpoints; - describe(`${name}: ${keyType}`, function() { - beforeEach(function() { - this.currentTest.cell = { - rowId: this.currentTest.title, - columnId: this.currentTest.parent.title - }; - }); - it('Specifically, all relevant normative statements in Sections 2. ' + - 'Data Model and 3. Algorithms of this document MUST be enforced.', - async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#:~:text=Specifically%2C%20all%20relevant%20normative%20statements%20in%20Sections%202.%20Data%20Model%20and%203.%20Algorithms%20of%20this%20document%20MUST%20be%20enforced.'; - for(const [key, credential] of credentials) { - await assertions.verificationFail({ - verifier, - credential, - reason: `Should not verify VC with ${key}` - }); - } - }); - it('Conforming processors MUST produce errors when non-conforming ' + - 'documents are consumed.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#:~:text=Conforming%20processors%20MUST%20produce%20errors%20when%20non%2Dconforming%20documents%20are%20consumed.'; - for(const [key, credential] of credentials) { - await assertions.verificationFail({ - verifier, - credential, - reason: `Should not verify VC with ${key}` - }); - } + for(const keyType of keyTypes) { + // add implementer name and keyType to test report + this.implemented.push(`${name}: ${keyType}`); + describe(`${name}: ${keyType}`, function() { + beforeEach(function() { + this.currentTest.cell = { + rowId: this.currentTest.title, + columnId: this.currentTest.parent.title + }; + }); + it('Specifically, all relevant normative statements in Sections 2. ' + + 'Data Model and 3. Algorithms of this document MUST be enforced.', + async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#:~:text=Specifically%2C%20all%20relevant%20normative%20statements%20in%20Sections%202.%20Data%20Model%20and%203.%20Algorithms%20of%20this%20document%20MUST%20be%20enforced.'; + for(const [key, credential] of credentials.get(keyType)) { + await assertions.verificationFail({ + verifier, + credential, + reason: `Should not verify VC with ${key}` + }); + } + }); + it('Conforming processors MUST produce errors when non-conforming ' + + 'documents are consumed.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#:~:text=Conforming%20processors%20MUST%20produce%20errors%20when%20non%2Dconforming%20documents%20are%20consumed.'; + for(const [key, credential] of credentials.get(keyType)) { + await assertions.verificationFail({ + verifier, + credential, + reason: `Should not verify VC with ${key}` + }); + } + }); }); - }); + } } }); } diff --git a/tests/suites/data-model.js b/tests/suites/data-model.js index f1403020..a8f486c1 100644 --- a/tests/suites/data-model.js +++ b/tests/suites/data-model.js @@ -12,7 +12,7 @@ import {expect} from 'chai'; export function dataModelSuite({ issuers, suiteName, - keyType, + keyTypes, vcVersion, credential, mandatoryPointers @@ -20,103 +20,111 @@ export function dataModelSuite({ return describe(`${suiteName} - Data Model - VC ${vcVersion}`, function() { this.matrix = true; this.report = true; - this.implemented = [...issuers]; + this.implemented = []; this.rowLabel = 'Test Name'; this.columnLabel = 'Implementation'; for(const [name, {endpoints}] of issuers) { - const [issuer] = endpoints; - // does the endpoint support this test? - if(!endpointCheck({endpoint: issuer, keyType, vcVersion})) { - continue; - } - describe(`${name}: ${keyType}`, function() { - let securedCredential = null; - let proofs = []; - before(async function() { - securedCredential = await createInitialVc({ - issuer, - vcVersion, - vc: credential, - mandatoryPointers - }); - if(securedCredential) { - proofs = Array.isArray(securedCredential.proof) ? - securedCredential?.proof : [securedCredential?.proof]; - // only test proofs that match the relevant cryptosuite - proofs = proofs.filter(p => p?.cryptosuite === suiteName); + for(const keyType of keyTypes) { + for(const issuer of endpoints) { + // does the endpoint support this test? + if(!endpointCheck({endpoint: issuer, keyType, vcVersion})) { + continue; } - }); - beforeEach(function() { - this.currentTest.cell = { - rowId: this.currentTest.title, - columnId: this.currentTest.parent.title - }; - }); - function assertBefore() { - expect( - securedCredential, - `Expected issuer ${name}: ${keyType} to issue a VC.` - ).to.exist; - expect( - securedCredential, - 'Expected VC to be an object.' - ).to.be.an('object'); - } - it('The publicKeyMultibase value of the verification method MUST ' + - 'start with the base-58-btc prefix (z), as defined in the ' + - 'Multibase section of Controller Documents 1.0. ', - async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#data-model:~:text=The%20publicKeyMultibase%20value%20of%20the%20verification%20method%20MUST%20start%20with%20the%20base%2D58%2Dbtc%20prefix%20(z)%2C%20as%20defined%20in%20the%20Multibase%20section%20of%20Controller%20Documents%201.0.'; - assertBefore(); - for(const proof of proofs) { - expect(proof.verificationMethod).to.exist; - expect(proof.verificationMethod).to.be.a('string'); - const didDoc = await didResolver({url: proof.verificationMethod}); - expect(didDoc).to.be.an('object'); - expect(didDoc.publicKeyMultibase).to.be.a('string'); - expect( - assertions.shouldBeBs58(didDoc.publicKeyMultibase), - 'Expected "publicKeyMultibase" to be Base58 encoded.' - ).to.be.true; - } - }); - it('Any other encoding MUST NOT be allowed. (verificationMethod)', - async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#multikey'; - assertBefore(); - for(const proof of proofs) { - expect(proof.verificationMethod).to.exist; - expect(proof.verificationMethod).to.be.a('string'); - const didDoc = await didResolver({url: proof.verificationMethod}); - expect(didDoc).to.be.an('object'); - expect(didDoc.publicKeyMultibase).to.be.a('string'); + // add implementer name and keyType to test report + this.implemented.push(`${name}: ${keyType}`); + describe(`${name}: ${keyType}`, function() { + let securedCredential = null; + let proofs = []; + before(async function() { + securedCredential = await createInitialVc({ + issuer, + vcVersion, + vc: credential, + mandatoryPointers + }); + if(securedCredential) { + proofs = Array.isArray(securedCredential.proof) ? + securedCredential?.proof : [securedCredential?.proof]; + // only test proofs that match the relevant cryptosuite + proofs = proofs.filter(p => p?.cryptosuite === suiteName); + } + }); + beforeEach(function() { + this.currentTest.cell = { + rowId: this.currentTest.title, + columnId: this.currentTest.parent.title + }; + }); + function assertBefore() { + expect( + securedCredential, + `Expected issuer ${name}: ${keyType} to issue a VC.` + ).to.exist; expect( - assertions.shouldBeBs58(didDoc.publicKeyMultibase), - 'Expected "publicKeyMultibase" to be Base58 encoded.' - ).to.be.true; + securedCredential, + 'Expected VC to be an object.' + ).to.be.an('object'); } + it('The publicKeyMultibase value of the verification method MUST ' + + 'start with the base-58-btc prefix (z), as defined in the ' + + 'Multibase section of Controller Documents 1.0. ', + async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#data-model:~:text=The%20publicKeyMultibase%20value%20of%20the%20verification%20method%20MUST%20start%20with%20the%20base%2D58%2Dbtc%20prefix%20(z)%2C%20as%20defined%20in%20the%20Multibase%20section%20of%20Controller%20Documents%201.0.'; + assertBefore(); + for(const proof of proofs) { + expect(proof.verificationMethod).to.exist; + expect(proof.verificationMethod).to.be.a('string'); + const didDoc = await didResolver({ + url: proof.verificationMethod}); + expect(didDoc).to.be.an('object'); + expect(didDoc.publicKeyMultibase).to.be.a('string'); + expect( + assertions.shouldBeBs58(didDoc.publicKeyMultibase), + 'Expected "publicKeyMultibase" to be Base58 encoded.' + ).to.be.true; + } + }); + it('Any other encoding MUST NOT be allowed. (verificationMethod)', + async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#multikey'; + assertBefore(); + for(const proof of proofs) { + expect(proof.verificationMethod).to.exist; + expect(proof.verificationMethod).to.be.a('string'); + const didDoc = await didResolver({ + url: proof.verificationMethod}); + expect(didDoc).to.be.an('object'); + expect(didDoc.publicKeyMultibase).to.be.a('string'); + expect( + assertions.shouldBeBs58(didDoc.publicKeyMultibase), + 'Expected "publicKeyMultibase" to be Base58 encoded.' + ).to.be.true; + } + }); + it('The type property MUST be DataIntegrityProof.', + async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#multikey:~:text=The%20type%20property%20MUST%20be%20DataIntegrityProof.'; + assertBefore(); + for(const proof of proofs) { + expect(proof.type).to.exist; + expect(proof.type).to.be.a('string'); + expect(proof.type).to.equal('DataIntegrityProof'); + } + }); + it('The cryptosuite property MUST be ecdsa-rdfc-2019, ' + + 'ecdsa-jcs-2019, or ecdsa-sd-2023.', async function() { + this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#multikey:~:text=The%20cryptosuite%20property%20MUST%20be%20ecdsa%2Drdfc%2D2019%2C%20ecdsa%2Djcs%2D2019%2C%20or%20ecdsa%2Dsd%2D2023.'; + assertBefore(); + for(const proof of proofs) { + expect(proof.cryptosuite).to.exist; + expect(proof.cryptosuite).to.be.a('string'); + expect(proof.cryptosuite).to.be.oneOf( + ['ecdsa-rdfc-2019', 'edcsa-jcs-2019', 'ecdsa-sd-2023']); + } + }); }); - it('The type property MUST be DataIntegrityProof.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#multikey:~:text=The%20type%20property%20MUST%20be%20DataIntegrityProof.'; - assertBefore(); - for(const proof of proofs) { - expect(proof.type).to.exist; - expect(proof.type).to.be.a('string'); - expect(proof.type).to.equal('DataIntegrityProof'); - } - }); - it('The cryptosuite property MUST be ecdsa-rdfc-2019, ' + - 'ecdsa-jcs-2019, or ecdsa-sd-2023.', async function() { - this.test.link = 'https://w3c.github.io/vc-di-ecdsa/#multikey:~:text=The%20cryptosuite%20property%20MUST%20be%20ecdsa%2Drdfc%2D2019%2C%20ecdsa%2Djcs%2D2019%2C%20or%20ecdsa%2Dsd%2D2023.'; - assertBefore(); - for(const proof of proofs) { - expect(proof.cryptosuite).to.exist; - expect(proof.cryptosuite).to.be.a('string'); - expect(proof.cryptosuite).to.be.oneOf( - ['ecdsa-rdfc-2019', 'edcsa-jcs-2019', 'ecdsa-sd-2023']); - } - }); - }); + } + } } }); }