Skip to content

Commit 70d126e

Browse files
committed
add db vectors and improve code handling
Signed-off-by: PatStLouis <[email protected]>
1 parent 02c2492 commit 70d126e

File tree

4 files changed

+260
-11
lines changed

4 files changed

+260
-11
lines changed

tests/90-algorithms-jcs.js

Lines changed: 159 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,23 @@
33
* SPDX-License-Identifier: BSD-3-Clause
44
*/
55
import {
6+
assertAllUtf8,
67
assertDataIntegrityProof,
78
assertSecuredCredential
89
} from './assertions.js';
910
import {
10-
baseCredential,
11+
generateCredential,
1112
getProofs,
13+
isValidDatetime,
1214
secureCredential,
1315
setupReportableTestSuite,
14-
setupRow
16+
setupRow,
17+
verifyFail,
18+
verifySuccess
1519
} from './helpers.js';
1620
import canonicalize from 'json-canon';
1721
import chai from 'chai';
22+
import {ecdsaJcsVectors} from './vectors.js';
1823
import {endpoints} from 'vc-test-suite-implementations';
1924
import {expect} from 'chai';
2025

@@ -34,7 +39,7 @@ const {match: verifiers} = endpoints.filterByTag({
3439
property: 'verifiers'
3540
});
3641

37-
describe('Create Proof (ecdsa-jcs-2019)', function() {
42+
describe('Algorithms - Create Proof (ecdsa-jcs-2019)', function() {
3843
setupReportableTestSuite(this);
3944
this.implemented = [...issuers.keys()];
4045
for(const [columnId, {endpoints}] of issuers) {
@@ -44,7 +49,7 @@ describe('Create Proof (ecdsa-jcs-2019)', function() {
4449
let proof;
4550
before(async function() {
4651
securedCredential = await secureCredential(
47-
{issuer, vc: baseCredential()});
52+
{issuer, vc: generateCredential()});
4853
proof = getProofs(securedCredential)[0];
4954
});
5055
beforeEach(setupRow);
@@ -86,18 +91,162 @@ describe('Algorithms - Verify Proof (ecdsa-jcs-2019)', function() {
8691
setupReportableTestSuite(this);
8792
for(const [columnId, {endpoints}] of verifiers) {
8893
describe(columnId, function() {
89-
const [issuer] = issuers.get(columnId).endpoints;
9094
const [verifier] = endpoints;
95+
beforeEach(setupRow);
96+
it('The following algorithm specifies how to verify a ' +
97+
'data integrity proof given an secured data document. ' +
98+
'Required inputs are an secured data document (map securedDocument). ' +
99+
'This algorithm returns a verification result.',
100+
async function() {
101+
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#verify-proof-ecdsa-rdfc-2019';
102+
for(const curve of verifier.settings.supportedEcdsaKeyTypes) {
103+
const testVector = structuredClone(ecdsaJcsVectors[curve]);
104+
await verifySuccess(verifier, testVector);
105+
106+
// Slice the proof
107+
testVector.proof.proofValue =
108+
testVector.proof.proofValue.slice(0, -1);
109+
await verifyFail(verifier, testVector);
110+
}
111+
});
112+
});
113+
}
114+
});
115+
116+
describe('Algorithms - Transformation', function() {
117+
setupReportableTestSuite(this);
118+
this.implemented = [...issuers.keys()];
119+
for(const [columnId, {endpoints}] of issuers) {
120+
describe(columnId, function() {
121+
const [issuer] = endpoints;
91122
let securedCredential;
123+
let proof;
92124
before(async function() {
93125
securedCredential = await secureCredential(
94-
{issuer, vc: baseCredential()});
126+
{issuer, vc: generateCredential()});
127+
proof = getProofs(securedCredential)[0];
95128
});
96129
beforeEach(setupRow);
97-
it('',
98-
async function() {
99-
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#verify-proof-ecdsa-rdfc-2019';
100-
});
130+
it('The proof options MUST contain a type identifier for the ' +
131+
'cryptographic suite (type) and MAY contain a cryptosuite ' +
132+
'identifier (cryptosuite).',
133+
async function() {
134+
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019';
135+
should.exist(proof.type,
136+
'Expected a type identifier on the proof.');
137+
});
138+
it('The transformation options MUST contain a type identifier ' +
139+
'for the cryptographic suite (type) and a cryptosuite identifier ' +
140+
'(cryptosuite).',
141+
async function() {
142+
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019';
143+
should.exist(proof.type, 'Expected a type identifier on ' +
144+
'the proof.');
145+
should.exist(proof.cryptosuite,
146+
'Expected a cryptosuite identifier on the proof.');
147+
});
148+
it('Whenever this algorithm encodes strings, ' +
149+
'it MUST use UTF-8 encoding.',
150+
async function() {
151+
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019';
152+
assertAllUtf8(proof);
153+
});
154+
it('If options.type is not set to the string DataIntegrityProof or ' +
155+
'options.cryptosuite is not set to the string ecdsa-jcs-2019, ' +
156+
'an error MUST be raised and SHOULD convey an error type ' +
157+
'of PROOF_TRANSFORMATION_ERROR.',
158+
async function() {
159+
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#transformation-ecdsa-jcs-2019';
160+
should.exist(proof.type,
161+
'Expected a type identifier on the proof.');
162+
should.exist(proof.cryptosuite,
163+
'Expected a cryptosuite identifier on the proof.');
164+
proof.type.should.equal('DataIntegrityProof',
165+
'Expected DataIntegrityProof type.');
166+
proof.cryptosuite.should.equal('ecdsa-jcs-2019',
167+
'Expected ecdsa-jcs-2019 cryptosuite.');
168+
});
169+
});
170+
}
171+
});
172+
173+
describe('ecdsa-jcs-2019 - Algorithms - Proof Configuration', function() {
174+
setupReportableTestSuite(this);
175+
this.implemented = [...issuers.keys()];
176+
for(const [columnId, {endpoints}] of issuers) {
177+
describe(columnId, function() {
178+
const [issuer] = endpoints;
179+
let securedCredential;
180+
let proof;
181+
before(async function() {
182+
securedCredential = await secureCredential(
183+
{issuer, vc: generateCredential()});
184+
proof = getProofs(securedCredential)[0];
185+
});
186+
beforeEach(setupRow);
187+
it('The proof options MUST contain a type identifier for the ' +
188+
'cryptographic suite (type) and MUST contain a cryptosuite ' +
189+
'identifier (cryptosuite).',
190+
async function() {
191+
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019';
192+
should.exist(proof.type,
193+
'Expected a type identifier on the proof.');
194+
should.exist(proof.cryptosuite,
195+
'Expected a cryptosuite identifier on the proof.');
196+
});
197+
it('If proofConfig.type is not set to DataIntegrityProof ' +
198+
'and/or proofConfig.cryptosuite is not set to ecdsa-jcs-2019, ' +
199+
'an error MUST be raised and SHOULD convey an error type ' +
200+
'of PROOF_GENERATION_ERROR.',
201+
async function() {
202+
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019';
203+
should.exist(proof.type,
204+
'Expected a type identifier on the proof.');
205+
should.exist(proof.cryptosuite,
206+
'Expected a cryptosuite identifier on the proof.');
207+
proof.type.should.equal('DataIntegrityProof',
208+
'Expected DataIntegrityProof type.');
209+
proof.cryptosuite.should.equal('ecdsa-jcs-2019',
210+
'Expected ecdsa-jcs-2019 cryptosuite.');
211+
});
212+
it('If proofConfig.created is set and if the value is not a ' +
213+
'valid [XMLSCHEMA11-2] datetime, an error MUST be raised and ' +
214+
'SHOULD convey an error type of PROOF_GENERATION_ERROR.',
215+
async function() {
216+
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-configuration-ecdsa-jcs-2019';
217+
if(proof?.created) {
218+
isValidDatetime(proof.created).should.equal(
219+
true,
220+
'Expected created value to be a valid datetime string.'
221+
);
222+
}
223+
});
224+
});
225+
}
226+
});
227+
228+
describe('ecdsa-jcs-2019 - Algorithms - Proof Serialization', function() {
229+
setupReportableTestSuite(this);
230+
this.implemented = [...issuers.keys()];
231+
for(const [columnId, {endpoints}] of issuers) {
232+
describe(columnId, function() {
233+
const [issuer] = endpoints;
234+
let securedCredential;
235+
let proof;
236+
before(async function() {
237+
securedCredential = await secureCredential(
238+
{issuer, vc: generateCredential()});
239+
proof = getProofs(securedCredential)[0];
240+
});
241+
beforeEach(setupRow);
242+
it('The proof options MUST contain a type identifier for the ' +
243+
'cryptographic suite (type) and MAY contain a cryptosuite identifier ' +
244+
'(cryptosuite).',
245+
async function() {
246+
this.test.link = 'https://www.w3.org/TR/vc-di-ecdsa/#proof-serialization-ecdsa-jcs-2019';
247+
should.exist(proof.type,
248+
'Expected a type identifier on the proof.');
249+
});
101250
});
102251
}
103252
});

tests/assertions.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,15 @@ export function assertSecuredCredential(securedCredential) {
196196
'Expected credential to have a single proof.');
197197
}
198198

199+
export function assertAllUtf8(proof) {
200+
for(const [key, value] of Object.entries(proof)) {
201+
isValidUtf8(value).should.equal(
202+
true,
203+
`Expected ${key} value to be a valid UTF-8 encoded string.`
204+
);
205+
}
206+
}
207+
199208
export function assertDataIntegrityProof(proof, cryptosuite) {
200209
if(proof?.id) {
201210
}

tests/helpers.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ export function getProofs(issuedVc) {
250250
return proofs;
251251
}
252252

253-
export function baseCredential(version = 2) {
253+
export function generateCredential(version = 2) {
254254
let credential = {
255255
type: ['VerifiableCredential'],
256256
id: `urn:uuid:${uuidv4()}`,
@@ -272,6 +272,7 @@ export function baseCredential(version = 2) {
272272
'https://www.w3.org/ns/credentials/v2'
273273
]
274274
}, credential);
275+
credential.credentialSubject.name = 'Alice';
275276
} else {
276277
return null;
277278
}
@@ -295,3 +296,20 @@ export function assertSecuredCredential(securedCredential) {
295296
proofs.length.should.equal(1,
296297
'Expected credential to have a single proof.');
297298
}
299+
300+
export async function verifySuccess(verifier, securedCredential) {
301+
const body = {
302+
verifiableCredential: securedCredential
303+
};
304+
const response = await verifier.post({json: body});
305+
should.exist(response.result, 'Expected a result from verifier.');
306+
}
307+
308+
export async function verifyFail(verifier, securedCredential) {
309+
const body = {
310+
verifiableCredential: securedCredential
311+
};
312+
const response = await verifier.post({json: body});
313+
should.exist(response.error, 'Expected an error from verifier.');
314+
}
315+

tests/vectors.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*!
2+
* Copyright (c) 2024 Digital Bazaar, Inc. All rights reserved.
3+
*/
4+
/* Note: This file contains data generated from the vc-di-ecdsa specification
5+
test vectors. */
6+
7+
/* eslint-disable max-len */
8+
/* eslint-disable quote-props */
9+
/* eslint-disable quotes */
10+
export const ecdsaJcsVectors = {
11+
'P-256': {
12+
"@context": [
13+
"https://www.w3.org/ns/credentials/v2",
14+
"https://www.w3.org/ns/credentials/examples/v2"
15+
],
16+
"id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
17+
"type": [
18+
"VerifiableCredential",
19+
"AlumniCredential"
20+
],
21+
"name": "Alumni Credential",
22+
"description": "A minimum viable example of an Alumni Credential.",
23+
"issuer": "https://vc.example/issuers/5678",
24+
"validFrom": "2023-01-01T00:00:00Z",
25+
"credentialSubject": {
26+
"id": "did:example:abcdefgh",
27+
"alumniOf": "The School of Examples"
28+
},
29+
"proof": {
30+
"type": "DataIntegrityProof",
31+
"created": "2023-02-24T23:36:38Z",
32+
"verificationMethod": "did:key:zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP#zDnaepBuvsQ8cpsWrVKw8fbpGpvPeNSjVPTWoq6cRqaYzBKVP",
33+
"cryptosuite": "ecdsa-jcs-2019",
34+
"proofPurpose": "assertionMethod",
35+
"@context": [
36+
"https://www.w3.org/ns/credentials/v2",
37+
"https://www.w3.org/ns/credentials/examples/v2"
38+
],
39+
"proofValue": "z48fSpWLud2PXMmBjRnacU3oE4WMHX4J1hx7qjc2K31x1aoVfLPCcpEincvjUg8ptbDnrYgcytmSj51Uj2Ap3a7WB"
40+
}
41+
},
42+
'P-384': {
43+
"@context": [
44+
"https://www.w3.org/ns/credentials/v2",
45+
"https://www.w3.org/ns/credentials/examples/v2"
46+
],
47+
"id": "urn:uuid:58172aac-d8ba-11ed-83dd-0b3aef56cc33",
48+
"type": [
49+
"VerifiableCredential",
50+
"AlumniCredential"
51+
],
52+
"name": "Alumni Credential",
53+
"description": "A minimum viable example of an Alumni Credential.",
54+
"issuer": "https://vc.example/issuers/5678",
55+
"validFrom": "2023-01-01T00:00:00Z",
56+
"credentialSubject": {
57+
"id": "did:example:abcdefgh",
58+
"alumniOf": "The School of Examples"
59+
},
60+
"proof": {
61+
"type": "DataIntegrityProof",
62+
"created": "2023-02-24T23:36:38Z",
63+
"verificationMethod": "did:key:z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ#z82LkuBieyGShVBhvtE2zoiD6Kma4tJGFtkAhxR5pfkp5QPw4LutoYWhvQCnGjdVn14kujQ",
64+
"cryptosuite": "ecdsa-jcs-2019",
65+
"proofPurpose": "assertionMethod",
66+
"@context": [
67+
"https://www.w3.org/ns/credentials/v2",
68+
"https://www.w3.org/ns/credentials/examples/v2"
69+
],
70+
"proofValue": "zasuhHXVzmepTMgSuyWvCCY3gYbLpANXDYWSuemx7WjopwRr6DDN532dKSMoxqNeQm7BWZxqyurFLSPBDmzaHe57k7JgGRaNtJhjfYjgww19nPWdP7dYqqf1X1LvNEcZJP75"
71+
}
72+
}
73+
};

0 commit comments

Comments
 (0)