Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Conformance & Data Model Suites (1) #94

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b182b0a
Add initial statements and links for conformance.
aljones15 Nov 4, 2024
c64dc7f
Further abstract conformance.
aljones15 Nov 5, 2024
9455f73
Start work on conformance setup function.
aljones15 Nov 5, 2024
76c823d
Reuse DI generators for conformance setup.
aljones15 Nov 5, 2024
9523612
Add _getSuites & initial generator params.
aljones15 Nov 5, 2024
f2f75d1
Add conformance spec file.
aljones15 Nov 5, 2024
6c5e4e3
Set issuer on VC.
aljones15 Nov 6, 2024
f7252f1
Conformance suite returns mocha Suite.
aljones15 Nov 7, 2024
0ebad02
Add initial data model suite intended for issuers.
aljones15 Nov 6, 2024
40b5bd5
Add assertBefore & endpoint check.
aljones15 Nov 6, 2024
a277997
Fill in first VM test & get proofs.
aljones15 Nov 6, 2024
d990225
Add further assertions on proofs to data model suite.
aljones15 Nov 6, 2024
a308742
Add initial data-model test.
aljones15 Nov 7, 2024
c89ef2a
Remove proofValue test from data model & update links.
aljones15 Nov 7, 2024
f4f6507
Comment out jcs & correct naming in before statement.
aljones15 Nov 7, 2024
93173ef
Use didResolver to assert on publicKeyMultibase.
aljones15 Nov 7, 2024
4100168
Update tests/suites/data-model.js add period to end of sentence.
aljones15 Nov 11, 2024
5cef3a4
Update tests/suites/data-model.js add period to bs58 reason.
aljones15 Nov 11, 2024
8eb7748
Update tests/suites/data-model.js add missing period to end of bs58 r…
aljones15 Nov 11, 2024
dc39f44
Update tests/suites/data-model.js Remove trailing A from end of sente…
aljones15 Nov 11, 2024
0da7625
Handle implemented & multi-key-types.
aljones15 Nov 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions tests/70-conformance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*!
* Copyright 2024 Digital Bazaar, Inc.
* SPDX-License-Identifier: BSD-3-Clause
*/
import {conformanceSuite} from './suites/conformance.js';
import {endpoints} from 'vc-test-suite-implementations';
import {getSuiteConfig} from './test-config.js';

const cryptosuites = [
'ecdsa-rdfc-2019',
'ecdsa-sd-2023'
];

for(const suiteName of cryptosuites) {
const {tags, credentials, vectors} = getSuiteConfig(suiteName);
const {match: verifiers} = endpoints.filterByTag({
tags: [...tags],
property: 'verifiers'
});
for(const vcVersion of vectors.vcTypes) {
const {
document,
mandatoryPointers,
selectivePointers
} = credentials.create[vcVersion];
conformanceSuite({
verifiers,
suiteName,
keyTypes: vectors.keyTypes,
vcVersion,
credential: document,
mandatoryPointers,
selectivePointers
});
}
}
37 changes: 37 additions & 0 deletions tests/80-data-model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*!
* 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-sd-2023'
//FIXME implement jcs '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];
dataModelSuite({
issuers,
suiteName,
keyTypes: vectors.keyTypes,
vcVersion,
credential: document,
mandatoryPointers,
selectivePointers
});
}
}
157 changes: 157 additions & 0 deletions tests/suites/conformance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*!
* Copyright 2024 Digital Bazaar, Inc.
* SPDX-License-Identifier: BSD-3-Clause
*/
import {
assertions,
generators,
issueCloned
} from 'data-integrity-test-suite-assertion';
import {DataIntegrityProof} from '@digitalbazaar/data-integrity';
import {getMultiKey} from '../vc-generator/key-gen.js';
import {getSuite} from '../vc-generator/cryptosuites.js';

export function conformanceSuite({
verifiers,
suiteName,
keyTypes,
vcVersion,
credential,
mandatoryPointers,
selectivePointers,
setup = _setup
}) {
return describe(`${suiteName} - Conformance - VC ${vcVersion}`, function() {
this.matrix = true;
this.report = true;
this.implemented = [];
this.rowLabel = 'Test Name';
this.columnLabel = 'Implementation';
const credentials = new Map(keyTypes.map(kt => [kt, null]));
before(async function() {
for(const keyType of keyTypes) {
credentials.set(keyType, await setup({
credential,
mandatoryPointers,
selectivePointers,
suiteName,
keyType
}));
}
});
for(const [name, {endpoints}] of verifiers) {
const [verifier] = endpoints;
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}`
});
}
});
});
}
}
});
}
async function _setup({
credential,
suiteName,
keyType,
mandatoryPointers,
selectivePointers
}) {
const {
invalidProofType,
invalidVm,
invalidCryptosuite
} = generators?.mandatory;
const credentials = new Map();
const keyPair = await getMultiKey({keyType});
const signer = keyPair.signer();
const _credential = structuredClone(credential);
_credential.issuer = keyPair.controller;
// not bs58 encoded verificationMethod via invalidVm
// type is not DataIntegrityProof invalidType
// invalid cryptosuite name invalidCryptosuite
credentials.set('invalid cryptosuite', await issueCloned(invalidCryptosuite({
credential: structuredClone(_credential),
..._getSuites({
signer,
suiteName,
selectivePointers,
mandatoryPointers
})
})));
credentials.set('invalid VerificationMethod', await issueCloned(invalidVm({
credential: structuredClone(_credential),
..._getSuites({
signer,
suiteName,
selectivePointers,
mandatoryPointers
})
})));
credentials.set('invalid Proof Type', await issueCloned(invalidProofType({
credential: structuredClone(_credential),
..._getSuites({
signer,
suiteName,
selectivePointers,
mandatoryPointers
})
})));
return credentials;
}

function _getSuites({
signer,
suiteName,
mandatoryPointers,
selectivePointers
}) {
const suites = {
suite: new DataIntegrityProof({
signer,
cryptosuite: getSuite({
suite: suiteName,
mandatoryPointers
})
})
};
if(selectivePointers) {
suites.selectiveSuite = new DataIntegrityProof({
signer,
cryptosuite: getSuite({
suite: suiteName,
selectivePointers
})
});
}
return suites;
}
130 changes: 130 additions & 0 deletions tests/suites/data-model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*!
* 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 {didResolver} from '../didResolver.js';
import {expect} from 'chai';

export function dataModelSuite({
issuers,
suiteName,
keyTypes,
vcVersion,
credential,
mandatoryPointers
}) {
return describe(`${suiteName} - Data Model - VC ${vcVersion}`, function() {
this.matrix = true;
this.report = true;
this.implemented = [];
this.rowLabel = 'Test Name';
this.columnLabel = 'Implementation';
for(const [name, {endpoints}] of issuers) {
for(const keyType of keyTypes) {
for(const issuer of endpoints) {
// does the endpoint support this test?
if(!endpointCheck({endpoint: issuer, keyType, vcVersion})) {
continue;
}
// 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(
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']);
}
});
});
}
}
}
});
}