Skip to content

Commit

Permalink
Add an algorithm test file and helper functions for ecdsa-jcs-2019
Browse files Browse the repository at this point in the history
Signed-off-by: PatStLouis <[email protected]>
  • Loading branch information
PatStLouis committed Nov 17, 2024
1 parent 492f6e5 commit 13d0011
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 0 deletions.
194 changes: 194 additions & 0 deletions tests/90-algorithms-jcs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*!
* Copyright 2024 Digital Bazaar, Inc.
* SPDX-License-Identifier: BSD-3-Clause
*/
import {
config,
createInitialVc,
createValidCredential,
getProofs,
isValidDatetime,
isValidUtf8,
setupReportableTestSuite,
setupRow
} from '../helpers.js';
import chai from 'chai';
import {endpoints} from 'vc-test-suite-implementations';

const should = chai.should();

const cryptosuite = 'ecdsa-jcs-2019';
const {tags} = config.suites[
cryptosuite
];
const {match: issuers} = endpoints.filterByTag({
tags: [...tags],
property: 'issuers'
});

describe('ecdsa-jcs-2019 - Algorithms - Transformation', function() {
setupReportableTestSuite(this);
this.implemented = [...issuers.keys()];
let validCredential;
before(async function() {
validCredential = await createValidCredential();
});
for(const [columnId, {endpoints}] of issuers) {
describe(columnId, function() {
const [issuer] = endpoints;
let issuedVc;
let proofs;
let jcs2019Proofs = [];
before(async function() {
issuedVc = await createInitialVc({issuer, vc: validCredential});
proofs = getProofs(issuedVc);
if(proofs?.length) {
jcs2019Proofs = proofs.filter(
proof => proof?.cryptosuite === cryptosuite);
}
});
beforeEach(setupRow);
const assertBefore = () => {
should.exist(issuedVc, 'Expected issuer to have issued a ' +
'credential.');
should.exist(proofs, 'Expected credential to have a proof.');
jcs2019Proofs.length.should.be.gte(1, 'Expected at least one ' +
'ecdsa-jcs-2019 cryptosuite.');
};
it('The proof options MUST contain a type identifier for the ' +
'cryptographic suite (type) and MAY contain a cryptosuite ' +
'identifier (cryptosuite).',
async function() {
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019';
assertBefore();
for(const proof of jcs2019Proofs) {
should.exist(proof.type,
'Expected a type identifier on the proof.');
}
});
it('The transformation options MUST contain a type identifier ' +
'for the cryptographic suite (type) and a cryptosuite identifier ' +
'(cryptosuite).',
async function() {
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019';
assertBefore();
for(const proof of jcs2019Proofs) {
should.exist(proof.type, 'Expected a type identifier on ' +
'the proof.');
should.exist(proof.cryptosuite,
'Expected a cryptosuite identifier on the proof.');
}
});
it('Whenever this algorithm encodes strings, ' +
'it MUST use UTF-8 encoding.',
async function() {
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019';
assertBefore();
for(const proof of jcs2019Proofs) {
should.exist(proof?.proofValue,
'Expected proofValue to exist.');
isValidUtf8(proof.proofValue).should.equal(
true,
'Expected proofValue value to be a valid UTF-8 encoded string.'
);
}
});
it('If options.type is not set to the string DataIntegrityProof or ' +
'options.cryptosuite is not set to the string ecdsa-jcs-2019, ' +
'an error MUST be raised and SHOULD convey an error type ' +
'of PROOF_TRANSFORMATION_ERROR.',
async function() {
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019';
assertBefore();
for(const proof of jcs2019Proofs) {
should.exist(proof.type,
'Expected a type identifier on the proof.');
should.exist(proof.cryptosuite,
'Expected a cryptosuite identifier on the proof.');
proof.type.should.equal('DataIntegrityProof',
'Expected DataIntegrityProof type.');
proof.cryptosuite.should.equal('ecdsa-jcs-2019',
'Expected ecdsa-jcs-2019 cryptosuite.');
}
});
});
}
});

describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() {
setupReportableTestSuite(this);
this.implemented = [...issuers.keys()];
let validCredential;
before(async function() {
validCredential = await createValidCredential();
});
for(const [columnId, {endpoints}] of issuers) {
describe(columnId, function() {
const [issuer] = endpoints;
let issuedVc;
let proofs;
let jcs2019Proofs = [];
before(async function() {
issuedVc = await createInitialVc({issuer, vc: validCredential});
proofs = getProofs(issuedVc);
if(proofs?.length) {
jcs2019Proofs = proofs.filter(
proof => proof?.cryptosuite === cryptosuite);
}
});
beforeEach(setupRow);
const assertBefore = () => {
should.exist(issuedVc, 'Expected issuer to have issued a ' +
'credential.');
should.exist(proofs, 'Expected credential to have a proof.');
jcs2019Proofs.length.should.be.gte(1, 'Expected at least one ' +
'ecdsa-jcs-2019 cryptosuite.');
};
it('The proof options MUST contain a type identifier for the ' +
'cryptographic suite (type) and MUST contain a cryptosuite ' +
'identifier (cryptosuite).',
async function() {
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019';
assertBefore();
for(const proof of jcs2019Proofs) {
should.exist(proof.type,
'Expected a type identifier on the proof.');
should.exist(proof.cryptosuite,
'Expected a cryptosuite identifier on the proof.');
}
});
it('If proofConfig.type is not set to DataIntegrityProof ' +
'and/or proofConfig.cryptosuite is not set to ecdsa-jcs-2019, ' +
'an error MUST be raised and SHOULD convey an error type ' +
'of PROOF_GENERATION_ERROR.',
async function() {
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019';
assertBefore();
for(const proof of jcs2019Proofs) {
should.exist(proof.type,
'Expected a type identifier on the proof.');
should.exist(proof.cryptosuite,
'Expected a cryptosuite identifier on the proof.');
proof.type.should.equal('DataIntegrityProof',
'Expected DataIntegrityProof type.');
proof.cryptosuite.should.equal('ecdsa-jcs-2019',
'Expected ecdsa-jcs-2019 cryptosuite.');
}
});
it('If proofConfig.created is set and if the value is not a ' +
'valid [XMLSCHEMA11-2] datetime, an error MUST be raised and ' +
'SHOULD convey an error type of PROOF_GENERATION_ERROR.',
async function() {
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019';
for(const proof of jcs2019Proofs) {
if(proof?.created) {
isValidDatetime(proof.created).should.equal(
true,
'Expected created value to be a valid datetime string.'
);
}
}
});
});
}
});
54 changes: 54 additions & 0 deletions tests/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import * as bs58 from 'base58-universal';
import * as bs64 from 'base64url-universal';
import {createRequire} from 'node:module';
import {isUtf8} from 'node:buffer';
import {klona} from 'klona';
import {v4 as uuidv4} from 'uuid';

Expand Down Expand Up @@ -216,3 +217,56 @@ export function setupReportableTestSuite(runnerContext, name) {

runnerContext.implemented = [];
}

export function isValidUtf8(string) {
const textEncoder = new TextEncoder();
const uint8Array = textEncoder.encode(string);
if(!isUtf8(uint8Array)) {
return false;
} else {
return true;
}
}

export function isValidDatetime(dateString) {
return !isNaN(Date.parse(dateString));
}

export function getProofs(issuedVc) {
// if the implementation failed to issue a VC or to sign the VC,
// return an empty array
if(!issuedVc?.proof) {
return [];
}
const proofs = Array.isArray(issuedVc?.proof) ?
issuedVc.proof : [issuedVc?.proof];
return proofs;
}

export function createValidCredential(version = 2) {
let credential = {
type: ['VerifiableCredential'],
id: `urn:uuid:${uuidv4()}`,
credentialSubject: {id: 'did:example:alice'}
};
if(version === 1) {
// add v1.1 context and issuanceDate
credential = Object.assign({}, {
'@context': [
'https://www.w3.org/2018/credentials/v1',
'https://w3id.org/security/data-integrity/v2'
],
issuanceDate: ISOTimeStamp()
}, credential);
} else if(version === 2) {
// add v2 context
credential = Object.assign({}, {
'@context': [
'https://www.w3.org/ns/credentials/v2'
]
}, credential);
} else {
return null;
}
return credential;
}

0 comments on commit 13d0011

Please sign in to comment.