From 651c6c9dfa96c8b7d30dddf554b8eb3bc01d2d6f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 28 Aug 2024 17:08:05 -0400 Subject: [PATCH 01/13] Account for multiple suites for multiple proofs. --- vc-generator/issuer.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/vc-generator/issuer.js b/vc-generator/issuer.js index eb0dd16..7bd6f72 100644 --- a/vc-generator/issuer.js +++ b/vc-generator/issuer.js @@ -13,6 +13,7 @@ const {CredentialIssuancePurpose} = vc; * * @param {object} options - Options to use. * @param {object} options.suite - A DataIntegrityProof. + * @param {Array} options.suites - DataIntegrityProof(s). * @param {object} [options.selectiveSuite] - A D.I. Proof for a selective * suite. * @param {object} options.credential - A credential to be signed. @@ -23,15 +24,18 @@ const {CredentialIssuancePurpose} = vc; * @returns {Promise} - An issued VC. */ export async function issueCloned({ - suite, selectiveSuite, credential, loader = defaultLoader, + suite, suites, selectiveSuite, credential, loader = defaultLoader, purpose = new CredentialIssuancePurpose(), }) { - const verifiableCredential = await vc.issue({ - credential: structuredClone(credential), - suite, - documentLoader: loader, - purpose - }); + let verifiableCredential = structuredClone(credential); + for(const _suite of (suites ? suites : [suite])) { + verifiableCredential = await vc.issue({ + credential: verifiableCredential, + suite: _suite, + documentLoader: loader, + purpose + }); + } if(!selectiveSuite) { return verifiableCredential; } From f11d439fac0b9fdeb333134aee4a331fc85787e2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 28 Aug 2024 17:22:28 -0400 Subject: [PATCH 02/13] Add suites to setup and param to generator. --- vc-generator/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vc-generator/index.js b/vc-generator/index.js index 5091627..895ca06 100644 --- a/vc-generator/index.js +++ b/vc-generator/index.js @@ -62,7 +62,7 @@ export async function generateTestData({ // if a generator has a specific setup use it // otherwise getSuites is fine const setup = setups[id] || getSuites; - const {suite, selectiveSuite} = setup({ + const {suite, suites, selectiveSuite} = setup({ cryptosuite, signer, mandatoryPointers, @@ -70,7 +70,7 @@ export async function generateTestData({ verify }); const issuedCredential = await issueCloned(generator({ - suite, selectiveSuite, + suite, suites, selectiveSuite, credential, loader: documentLoader })); const cleanup = cleanups[id]; From 542cd79794bd86f24827f004a881a639a0c622ab Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 30 Aug 2024 14:20:14 +0000 Subject: [PATCH 03/13] Add initial gens and setups for proofSets & chains. --- vc-generator/generators.js | 50 +++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/vc-generator/generators.js b/vc-generator/generators.js index 46ca8c2..3f6d02c 100644 --- a/vc-generator/generators.js +++ b/vc-generator/generators.js @@ -9,6 +9,9 @@ import jsigs from 'jsonld-signatures'; const {AuthenticationProofPurpose} = jsigs.purposes; const {CredentialIssuancePurpose} = vc; +// default gen just passes params to issueCloned +const defaultGen = params => params; + // generator categories export const generators = { // creates test vectors for `proof.created` & `proof.expires` @@ -36,7 +39,12 @@ export const generators = { invalidProofType, invalidBaseUrl, invalidVm, - undefinedTerm + undefinedTerm, + previousProofString: defaultGen, + previousProofArray: defaultGen, + missingPreviousProofString: defaultGen, + missingPreviousProofArray: defaultGen, + proofSet: defaultGen }, // creates a set of shared test vector generators // not necessarily used in DI Assertion itself, but used @@ -57,6 +65,46 @@ export const setups = { }); } return getSuites({...args}); + }, + previousProofString({ + cryptosuite, + signer, + mandatorypointers, + selectivepointers, + }) { + + }, + previousProofArray({ + cryptosuite, + signer, + mandatorypointers, + selectivepointers, + }) { + + }, + missingPreviousProofString({ + cryptosuite, + signer, + mandatorypointers, + selectivepointers, + }) { + + }, + missingPreviousProofArray({ + cryptosuite, + signer, + mandatorypointers, + selectivepointers, + }) { + + }, + proofSet({ + cryptosuite, + signer, + mandatorypointers, + selectivepointers, + }) { + } }; From e9ef4e6a4854651c478114cb96fb8f46d7f11277 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 30 Aug 2024 17:33:40 +0000 Subject: [PATCH 04/13] Fill in proofSet & proofChain before statements. --- vc-generator/generators.js | 91 ++++++++++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/vc-generator/generators.js b/vc-generator/generators.js index 3f6d02c..0c2ee3e 100644 --- a/vc-generator/generators.js +++ b/vc-generator/generators.js @@ -69,42 +69,105 @@ export const setups = { previousProofString({ cryptosuite, signer, - mandatorypointers, - selectivepointers, + mandatoryPointers, + selectivePointers, + proofId = 'urn:uuid:test:first:proof' }) { - + const {suite: firstSuite} = getSuites({ + cryptosuite, signer, + mandatoryPointers, selectivePointers + }); + firstSuite.proof = {id: proofId}; + const {suite: secondSuite} = getSuites({ + cryptosuite, signer, + mandatoryPointers, selectivePointers + }); + secondSuite.proof = {previousProof: proofId}; + return { + suites: [firstSuite, secondSuite] + }; }, previousProofArray({ cryptosuite, signer, - mandatorypointers, - selectivepointers, + mandatoryPointers, + selectivePointers, + proofId = 'urn:uuid:test:first:proof' }) { + const {suite: firstSuite} = getSuites({ + cryptosuite, signer, + mandatoryPointers, selectivePointers + }); + firstSuite.proof = {id: proofId}; + const {suite: secondSuite} = getSuites({ + cryptosuite, signer, + mandatoryPointers, selectivePointers + }); + secondSuite.proof = {previousProof: [proofId]}; + return { + suites: [firstSuite, secondSuite] + }; }, missingPreviousProofString({ cryptosuite, signer, - mandatorypointers, - selectivepointers, + mandatoryPointers, + selectivePointers, + proofId = 'urn:uuid:test:first:proof' }) { - + const {suite: firstSuite} = getSuites({ + cryptosuite, signer, + mandatoryPointers, selectivePointers + }); + firstSuite.proof = {id: proofId}; + const {suite: secondSuite} = getSuites({ + cryptosuite, signer, + mandatoryPointers, selectivePointers + }); + secondSuite.proof = {previousProof: 'urn:uuid:test:missing:proof'}; + return { + suites: [firstSuite, secondSuite] + }; }, missingPreviousProofArray({ cryptosuite, signer, - mandatorypointers, - selectivepointers, + mandatoryPointers, + selectivePointers, + proofId = 'urn:uuid:test:first:proof' }) { - + const {suite: firstSuite} = getSuites({ + cryptosuite, signer, + mandatoryPointers, selectivePointers + }); + firstSuite.proof = {id: proofId}; + const {suite: secondSuite} = getSuites({ + cryptosuite, signer, + mandatoryPointers, selectivePointers + }); + secondSuite.proof = {previousProof: ['urn:uuid:test:missing:proof']}; + return { + suites: [firstSuite, secondSuite] + }; }, proofSet({ cryptosuite, signer, - mandatorypointers, - selectivepointers, + mandatoryPointers, + selectivePointers, }) { - + const {suite: firstSuite} = getSuites({ + cryptosuite, signer, + mandatoryPointers, selectivePointers + }); + const {suite: secondSuite} = getSuites({ + cryptosuite, signer, + mandatoryPointers, selectivePointers + }); + return { + suites: [firstSuite, secondSuite] + }; } }; From 96fd9917d45e37a13e461902d01fd685bb2a6829 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 30 Aug 2024 17:50:15 +0000 Subject: [PATCH 05/13] Add normative statements WRT to proof chains to verify suite. --- suites/verify.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/suites/verify.js b/suites/verify.js index bb6709f..7c66e80 100644 --- a/suites/verify.js +++ b/suites/verify.js @@ -29,6 +29,28 @@ export function runDataIntegrityProofVerifyTests({ before(async function() { proofValueTests = shouldBeProofValue({credentials, verifier}); }); + it('An OPTIONAL string value (proof.previousProof) or unordered list of ' + + 'string values. Each value identifies another data integrity proof that ' + + 'MUST verify before the current proof is processed.', async function() { + this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=An%20OPTIONAL%20string%20value%20or%20unordered%20list%20of%20string%20values.%20Each%20value%20identifies%20another%20data%20integrity%20proof%20that%20MUST%20verify%20before%20the%20current%20proof%20is%20processed'; + + }); + it('If an unordered list (proof.previousProof), all referenced proofs in ' + + 'the array MUST verify.', async function() { + this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20an%20unordered%20list%2C%20all%20referenced%20proofs%20in%20the%20array%20MUST%20verify'; + + }); + it('If a proof with id equal to previousProof does not exist in ' + + 'allProofs, an error MUST be raised and SHOULD convey an error type ' + + 'of PROOF_GENERATION_ERROR.', async function() { + this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20a%20proof%20with%20id%20equal%20to%20previousProof%20does%20not%20exist%20in%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; + }); + it('If any element of previousProof list has an id attribute that does ' + + 'not match the id attribute of any element of allProofs, an error MUST ' + + 'be raised and SHOULD convey an error type of PROOF_GENERATION_ERROR.', + async function() { + this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20any%20element%20of%20previousProof%20list%20has%20an%20id%20attribute%20that%20does%20not%20match%20the%20id%20attribute%20of%20any%20element%20of%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; + }); it('When deserializing to RDF, implementations MUST ensure that the ' + 'base URL is set to null.', async function() { this.test.link = 'https://w3c.github.io/vc-data-integrity/#securing-data-losslessly:~:text=When%20deserializing%20to%20RDF%2C%20implementations%20MUST%20ensure%20that%20the%20base%20URL%20is%20set%20to%20null.'; From 62d82ffbb014d94a89a032a293be4e92174a171a Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 30 Aug 2024 18:06:00 +0000 Subject: [PATCH 06/13] Use test vectors for first previousProof test. --- suites/verify.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/suites/verify.js b/suites/verify.js index 7c66e80..4e854da 100644 --- a/suites/verify.js +++ b/suites/verify.js @@ -33,7 +33,16 @@ export function runDataIntegrityProofVerifyTests({ 'string values. Each value identifies another data integrity proof that ' + 'MUST verify before the current proof is processed.', async function() { this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=An%20OPTIONAL%20string%20value%20or%20unordered%20list%20of%20string%20values.%20Each%20value%20identifies%20another%20data%20integrity%20proof%20that%20MUST%20verify%20before%20the%20current%20proof%20is%20processed'; - + await verificationSuccess({ + credential: credentials.clone('previousProofString'), + verifier, + reason: 'Should verify VC with a string "proof.previousProof"' + }); + await verificationSuccess({ + credential: credentials.clone('previousProofArray'), + verifier, + reason: 'Should verify VC with an Array "proof.previousProof"' + }); }); it('If an unordered list (proof.previousProof), all referenced proofs in ' + 'the array MUST verify.', async function() { From 70386198be4b0ab59961bcb00fa1170065e84bf2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 30 Aug 2024 18:10:31 +0000 Subject: [PATCH 07/13] Add test fixtures for previousProof Array & string missing. --- suites/verify.js | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/suites/verify.js b/suites/verify.js index 4e854da..ad289c8 100644 --- a/suites/verify.js +++ b/suites/verify.js @@ -36,29 +36,43 @@ export function runDataIntegrityProofVerifyTests({ await verificationSuccess({ credential: credentials.clone('previousProofString'), verifier, - reason: 'Should verify VC with a string "proof.previousProof"' + reason: 'Should verify VC with a string "proof.previousProof".' }); await verificationSuccess({ credential: credentials.clone('previousProofArray'), verifier, - reason: 'Should verify VC with an Array "proof.previousProof"' + reason: 'Should verify VC with an Array "proof.previousProof".' }); }); - it('If an unordered list (proof.previousProof), all referenced proofs in ' + + it('If an unordered list (proof), all referenced proofs in ' + 'the array MUST verify.', async function() { this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20an%20unordered%20list%2C%20all%20referenced%20proofs%20in%20the%20array%20MUST%20verify'; - + await verificationSuccess({ + credential: credentials.clone('proofSet'), + verifier, + reason: 'Should verify VC with multiple proofs.' + }); }); it('If a proof with id equal to previousProof does not exist in ' + 'allProofs, an error MUST be raised and SHOULD convey an error type ' + 'of PROOF_GENERATION_ERROR.', async function() { this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20a%20proof%20with%20id%20equal%20to%20previousProof%20does%20not%20exist%20in%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; + await verificationFail({ + credential: credentials.clone('missingPreviousProofString'), + verifier, + reason: 'Should not verify VC with invalid "proof.previousProof".' + }); }); it('If any element of previousProof list has an id attribute that does ' + 'not match the id attribute of any element of allProofs, an error MUST ' + 'be raised and SHOULD convey an error type of PROOF_GENERATION_ERROR.', async function() { this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20any%20element%20of%20previousProof%20list%20has%20an%20id%20attribute%20that%20does%20not%20match%20the%20id%20attribute%20of%20any%20element%20of%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; + await verificationFail({ + credential: credentials.clone('missingPreviousProofArray'), + verifier, + reason: 'Should not verify VC with invalid "proof.previousProof".' + }); }); it('When deserializing to RDF, implementations MUST ensure that the ' + 'base URL is set to null.', async function() { From da5d08cc037044a9cd79a59d577e8dcd769a59cd Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 24 Sep 2024 19:26:00 -0400 Subject: [PATCH 08/13] Move proofChain tests into optional tests. --- suites/create.js | 35 +++++++++--------- suites/verify.js | 94 +++++++++++++++++++++++++----------------------- 2 files changed, 67 insertions(+), 62 deletions(-) diff --git a/suites/create.js b/suites/create.js index 08c187e..46c865d 100644 --- a/suites/create.js +++ b/suites/create.js @@ -216,23 +216,6 @@ export function runDataIntegrityProofFormatTests({ shouldHaveProofValue({proof, expectedPrefix, encodingName}); } }); - it('If "proof.previousProof" property exists, it MUST be a string value ' + - 'or unordered list of string values.', - function() { - for(const proof of proofs) { - if(proof.previousProof) { - proof.previousProof.should.be. - oneOf(['string', 'object'], 'Expected ' + - '"proof.previousProof" to be a string or an array.'); - if(typeof proof.previousProof === 'object') { - for(const previousProof in proof.previousProof) { - previousProof.should.be.a('string', 'Expected ' + - '"previousProof" items to be a string.'); - } - } - } - } - }); it('Cryptographic suite designers MUST use mandatory proof value ' + 'properties defined in Section 2.1 Proofs, and MAY define other ' + 'properties specific to their cryptographic suite.', async function() { @@ -420,6 +403,24 @@ export function runDataIntegrityProofFormatTests({ } }); } + if(optionalTests.proofChain) { + it('If "proof.previousProof" property exists, it MUST be a string ' + + 'value or unordered list of string values.', function() { + for(const proof of proofs) { + if(proof.previousProof) { + proof.previousProof.should.be. + oneOf(['string', 'object'], 'Expected ' + + '"proof.previousProof" to be a string or an array.'); + if(typeof proof.previousProof === 'object') { + for(const previousProof in proof.previousProof) { + previousProof.should.be.a('string', 'Expected ' + + '"previousProof" items to be a string.'); + } + } + } + } + }); + } }); } diff --git a/suites/verify.js b/suites/verify.js index ad289c8..2c03d6e 100644 --- a/suites/verify.js +++ b/suites/verify.js @@ -29,51 +29,6 @@ export function runDataIntegrityProofVerifyTests({ before(async function() { proofValueTests = shouldBeProofValue({credentials, verifier}); }); - it('An OPTIONAL string value (proof.previousProof) or unordered list of ' + - 'string values. Each value identifies another data integrity proof that ' + - 'MUST verify before the current proof is processed.', async function() { - this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=An%20OPTIONAL%20string%20value%20or%20unordered%20list%20of%20string%20values.%20Each%20value%20identifies%20another%20data%20integrity%20proof%20that%20MUST%20verify%20before%20the%20current%20proof%20is%20processed'; - await verificationSuccess({ - credential: credentials.clone('previousProofString'), - verifier, - reason: 'Should verify VC with a string "proof.previousProof".' - }); - await verificationSuccess({ - credential: credentials.clone('previousProofArray'), - verifier, - reason: 'Should verify VC with an Array "proof.previousProof".' - }); - }); - it('If an unordered list (proof), all referenced proofs in ' + - 'the array MUST verify.', async function() { - this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20an%20unordered%20list%2C%20all%20referenced%20proofs%20in%20the%20array%20MUST%20verify'; - await verificationSuccess({ - credential: credentials.clone('proofSet'), - verifier, - reason: 'Should verify VC with multiple proofs.' - }); - }); - it('If a proof with id equal to previousProof does not exist in ' + - 'allProofs, an error MUST be raised and SHOULD convey an error type ' + - 'of PROOF_GENERATION_ERROR.', async function() { - this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20a%20proof%20with%20id%20equal%20to%20previousProof%20does%20not%20exist%20in%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; - await verificationFail({ - credential: credentials.clone('missingPreviousProofString'), - verifier, - reason: 'Should not verify VC with invalid "proof.previousProof".' - }); - }); - it('If any element of previousProof list has an id attribute that does ' + - 'not match the id attribute of any element of allProofs, an error MUST ' + - 'be raised and SHOULD convey an error type of PROOF_GENERATION_ERROR.', - async function() { - this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20any%20element%20of%20previousProof%20list%20has%20an%20id%20attribute%20that%20does%20not%20match%20the%20id%20attribute%20of%20any%20element%20of%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; - await verificationFail({ - credential: credentials.clone('missingPreviousProofArray'), - verifier, - reason: 'Should not verify VC with invalid "proof.previousProof".' - }); - }); it('When deserializing to RDF, implementations MUST ensure that the ' + 'base URL is set to null.', async function() { this.test.link = 'https://w3c.github.io/vc-data-integrity/#securing-data-losslessly:~:text=When%20deserializing%20to%20RDF%2C%20implementations%20MUST%20ensure%20that%20the%20base%20URL%20is%20set%20to%20null.'; @@ -272,6 +227,55 @@ export function runDataIntegrityProofVerifyTests({ }); }); } + if(optionalTests.proofChain) { + it('An OPTIONAL string value (proof.previousProof) or unordered list ' + + 'of string values. Each value identifies another data integrity proof ' + + 'that MUST verify before the current proof is processed.', + async function() { + this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=An%20OPTIONAL%20string%20value%20or%20unordered%20list%20of%20string%20values.%20Each%20value%20identifies%20another%20data%20integrity%20proof%20that%20MUST%20verify%20before%20the%20current%20proof%20is%20processed'; + await verificationSuccess({ + credential: credentials.clone('previousProofString'), + verifier, + reason: 'Should verify VC with a string "proof.previousProof".' + }); + await verificationSuccess({ + credential: credentials.clone('previousProofArray'), + verifier, + reason: 'Should verify VC with an Array "proof.previousProof".' + }); + }); + it('If an unordered list (proof), all referenced proofs in ' + + 'the array MUST verify.', async function() { + this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20an%20unordered%20list%2C%20all%20referenced%20proofs%20in%20the%20array%20MUST%20verify'; + await verificationSuccess({ + credential: credentials.clone('proofSet'), + verifier, + reason: 'Should verify VC with multiple proofs.' + }); + }); + it('If a proof with id equal to previousProof does not exist in ' + + 'allProofs, an error MUST be raised and SHOULD convey an error type ' + + 'of PROOF_GENERATION_ERROR.', async function() { + this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20a%20proof%20with%20id%20equal%20to%20previousProof%20does%20not%20exist%20in%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; + await verificationFail({ + credential: credentials.clone('missingPreviousProofString'), + verifier, + reason: 'Should not verify VC with invalid "proof.previousProof".' + }); + }); + it('If any element of previousProof list has an id attribute that does ' + + 'not match the id attribute of any element of allProofs, an error MUST ' + + 'be raised and SHOULD convey an error type of PROOF_GENERATION_ERROR.', + async function() { + this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20any%20element%20of%20previousProof%20list%20has%20an%20id%20attribute%20that%20does%20not%20match%20the%20id%20attribute%20of%20any%20element%20of%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; + await verificationFail({ + credential: credentials.clone('missingPreviousProofArray'), + verifier, + reason: 'Should not verify VC with invalid "proof.previousProof".' + }); + }); + + } }); } From 9b830c7ddfd1d7e473c4991bf5585d10e2fe97e4 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 24 Sep 2024 19:35:15 -0400 Subject: [PATCH 09/13] Shorten issuer previousProof test. --- suites/create.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/suites/create.js b/suites/create.js index 46c865d..eff83b4 100644 --- a/suites/create.js +++ b/suites/create.js @@ -408,15 +408,10 @@ export function runDataIntegrityProofFormatTests({ 'value or unordered list of string values.', function() { for(const proof of proofs) { if(proof.previousProof) { - proof.previousProof.should.be. - oneOf(['string', 'object'], 'Expected ' + - '"proof.previousProof" to be a string or an array.'); - if(typeof proof.previousProof === 'object') { - for(const previousProof in proof.previousProof) { - previousProof.should.be.a('string', 'Expected ' + - '"previousProof" items to be a string.'); - } - } + isStringOrArrayOfStrings(proof.previousProof).should.equal( + true, + '"proof.previousProof" should be a string or an Array of strings.' + ); } } }); From aa95825eb3678ce8c8149f1f67bd1aaa4cf66e6e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 25 Sep 2024 13:32:13 +0000 Subject: [PATCH 10/13] Functions default to proofChain tests false, but test project enables tests for ecdsa and eddsa rdfc suites. --- index.js | 6 ++++-- tests/fixtures/cryptosuites.js | 9 ++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index b5184fb..23ea663 100644 --- a/index.js +++ b/index.js @@ -39,7 +39,8 @@ export function checkDataIntegrityProofFormat({ optionalTests = { dates: false, contextInjection: false, - domain: false + domain: false, + proofChain: false } } = {}) { return describe(testDescription, function() { @@ -106,7 +107,8 @@ export function checkDataIntegrityProofVerifyErrors({ testDataOptions, optionalTests = { dates: false, - authentication: false + authentication: false, + proofChain: false } } = {}) { return describe(testDescription, async function() { diff --git a/tests/fixtures/cryptosuites.js b/tests/fixtures/cryptosuites.js index 40d88f0..bac4cdb 100644 --- a/tests/fixtures/cryptosuites.js +++ b/tests/fixtures/cryptosuites.js @@ -53,7 +53,8 @@ export const cryptosuites = [{ keyType: 'P-256', optionalTests: { dates: true, - authentication: true + authentication: true, + proofChain: true }, cryptosuite: ecdsaRdfc2019Cryptosuite, multikey: EcdsaMultikey, @@ -65,7 +66,8 @@ export const cryptosuites = [{ keyType: 'P-384', optionalTests: { dates: true, - authentication: true + authentication: true, + proofChain: true }, cryptosuite: ecdsaRdfc2019Cryptosuite, multikey: EcdsaMultikey, @@ -85,7 +87,8 @@ export const cryptosuites = [{ suiteName: 'eddsa-rdfc-2022', optionalTests: { dates: true, - authentication: true + authentication: true, + proofChain: true }, cryptosuite: eddsaRdfc2022CryptoSuite, multikey: Ed25519Multikey, From df355a8c6d3cafc9c65897f1d0d3b8de74ede344 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 26 Sep 2024 14:14:42 -0400 Subject: [PATCH 11/13] Add test for previousProof fail. --- suites/verify.js | 11 +++++++++++ vc-generator/generators.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/suites/verify.js b/suites/verify.js index 2c03d6e..12fba2c 100644 --- a/suites/verify.js +++ b/suites/verify.js @@ -274,7 +274,18 @@ export function runDataIntegrityProofVerifyTests({ reason: 'Should not verify VC with invalid "proof.previousProof".' }); }); + it('Each value identifies another data integrity proof, all of which ' + + 'MUST also verify for the current proof to be considered verified', + async function() { + this.test.link = 'https://w3c.github.io/vc-data-integrity/#:~:text=Each%20value%20identifies%20another%20data%20integrity%20proof%2C%20all%20of%20which%20MUST%20also%20verify%20for%20the%20current%20proof%20to%20be%20considered%20verified'; + await verificationFail({ + credential: credentials.clone('previousProofFail'), + verifier, + reason: 'Should not verify VC with a "previousProof" that does ' + + 'not verify.' + }); + }); } }); } diff --git a/vc-generator/generators.js b/vc-generator/generators.js index 0c2ee3e..9698a34 100644 --- a/vc-generator/generators.js +++ b/vc-generator/generators.js @@ -41,6 +41,7 @@ export const generators = { invalidVm, undefinedTerm, previousProofString: defaultGen, + previousProofFail: defaultGen, previousProofArray: defaultGen, missingPreviousProofString: defaultGen, missingPreviousProofArray: defaultGen, @@ -87,6 +88,28 @@ export const setups = { suites: [firstSuite, secondSuite] }; }, + previousProofFail({ + cryptosuite, + signer, + mandatoryPointers, + selectivePointers, + proofId = 'urn:uuid:test:first:proof' + + }) { + const {suite: firstSuite} = getSuites({ + cryptosuite, signer, + mandatoryPointers, selectivePointers + }); + firstSuite.proof = {id: proofId}; + const {suite: secondSuite} = getSuites({ + cryptosuite, signer, + mandatoryPointers, selectivePointers + }); + secondSuite.proof = {previousProof: proofId}; + return { + suites: [firstSuite, secondSuite] + }; + }, previousProofArray({ cryptosuite, signer, @@ -181,6 +204,11 @@ export const cleanups = { return !('@base' in c); }); return issuedCredential; + }, + previousProofFail({issuedCredential}) { + // make the first proof fail verification + issuedCredential.proof[0].proofValue = 'invalidProofValue'; + return issuedCredential; } }; /** From 355d4b3e166e50701c7e4bc2335c3c1947237bfc Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 27 Sep 2024 14:51:58 +0000 Subject: [PATCH 12/13] Ensure statement being tested for proofChain is verification related. --- suites/verify.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/suites/verify.js b/suites/verify.js index 12fba2c..62378ef 100644 --- a/suites/verify.js +++ b/suites/verify.js @@ -255,19 +255,19 @@ export function runDataIntegrityProofVerifyTests({ }); it('If a proof with id equal to previousProof does not exist in ' + 'allProofs, an error MUST be raised and SHOULD convey an error type ' + - 'of PROOF_GENERATION_ERROR.', async function() { - this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20a%20proof%20with%20id%20equal%20to%20previousProof%20does%20not%20exist%20in%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; + 'of PROOF_VERIFICATION_ERROR.', async function() { + this.test.link = 'https://w3c.github.io/vc-data-integrity/#:~:text=If%20a%20proof%20with%20id%20equal%20to%20previousProof%20does%20not%20exist%20in%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_VERIFICATION_ERROR'; await verificationFail({ credential: credentials.clone('missingPreviousProofString'), verifier, reason: 'Should not verify VC with invalid "proof.previousProof".' }); }); - it('If any element of previousProof list has an id attribute that does ' + - 'not match the id attribute of any element of allProofs, an error MUST ' + - 'be raised and SHOULD convey an error type of PROOF_GENERATION_ERROR.', - async function() { - this.test.link = 'https://w3c.github.io/vc-data-integrity/#proofs:~:text=If%20any%20element%20of%20previousProof%20list%20has%20an%20id%20attribute%20that%20does%20not%20match%20the%20id%20attribute%20of%20any%20element%20of%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; + it('If any element of previousProof list has an id attribute that ' + + 'does not match the id attribute of any element of allProofs, an ' + + 'error MUST be raised and SHOULD convey an error type of ' + + 'PROOF_VERIFICATION_ERROR.', async function() { + this.test.link = 'https://w3c.github.io/vc-data-integrity/#:~:text=If%20any%20element%20of%20previousProof%20list%20has%20an%20id%20attribute%20that%20does%20not%20match%20the%20id%20attribute%20of%20any%20element%20of%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_VERIFICATION_ERROR.'; await verificationFail({ credential: credentials.clone('missingPreviousProofArray'), verifier, From c6c5810f0f394fc87d5d13ed88e89b6b3dd6f815 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 27 Sep 2024 15:35:37 +0000 Subject: [PATCH 13/13] Use ?. for cases where proof or optionalTests are undefined. --- suites/create.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/suites/create.js b/suites/create.js index eff83b4..505d227 100644 --- a/suites/create.js +++ b/suites/create.js @@ -403,11 +403,11 @@ export function runDataIntegrityProofFormatTests({ } }); } - if(optionalTests.proofChain) { + if(optionalTests?.proofChain) { it('If "proof.previousProof" property exists, it MUST be a string ' + 'value or unordered list of string values.', function() { for(const proof of proofs) { - if(proof.previousProof) { + if(proof?.previousProof) { isStringOrArrayOfStrings(proof.previousProof).should.equal( true, '"proof.previousProof" should be a string or an Array of strings.'