From aaf757c4621c49d0ea63bec0f6cced7c56a3bd0e Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 17 Oct 2024 13:09:43 -0400 Subject: [PATCH 1/7] Expand test WRT to cbor array in derived proof to include 7 objects. --- tests/assertions.js | 2 +- tests/suites/create.js | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/assertions.js b/tests/assertions.js index 388027d..ef2ce95 100644 --- a/tests/assertions.js +++ b/tests/assertions.js @@ -111,7 +111,7 @@ export const shouldNotUseCborTags = ({proof}) => { export const baseProofShouldHaveElementCount = ({ proof, - expectedLengths = [5, 6], + expectedLengths = [5, 6, 7], reason = 'Expected baseProof to have expected number of components' }) => { let error; diff --git a/tests/suites/create.js b/tests/suites/create.js index 5971f73..f11b988 100644 --- a/tests/suites/create.js +++ b/tests/suites/create.js @@ -266,19 +266,18 @@ export function createSuite({ } }); it('The transformation options MUST contain an array of mandatory ' + - 'JSON pointers (mandatoryPointers)', function() { + 'JSON pointers (mandatoryPointers).', function() { this.test.link = 'https://w3c.github.io/vc-di-bbs/#:~:text=The%20transformation%20options%20MUST%20contain%20an%20array%20of%20mandatory%20JSON%20pointers%20(mandatoryPointers)'; for(const proof of bbsProofs) { shouldHaveMandatoryPointers({proof}); } }); - it('Initialize components to an array that is the result of ' + - 'CBOR-decoding the bytes that follow the three-byte BBS disclosure ' + - 'proof header. If the result is not an array of five or six elements ' + - '— a byte array, a map of integers to integers, two arrays of ' + - 'integers, and one or two byte arrays; an error MUST be raised and ' + - 'SHOULD convey an error type of PROOF_VERIFICATION_ERROR.', function() { - this.test.link = 'https://w3c.github.io/vc-di-bbs/#:~:text=%22pseudonym_hidden_pid%22.-,Initialize%20components%20to%20an%20array%20that%20is%20the%20result%20of%20CBOR,be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_VERIFICATION_ERROR.,-Replace%20the%20second'; + it('If the result is not an array of five, six, or seven elements ' + + '— a byte array, a map of integers to integers, two arrays of ' + + 'integers, and one or two byte arrays; an error MUST be raised ' + + 'and SHOULD convey an error type of PROOF_VERIFICATION_ERROR.', + function() { + this.test.link = 'https://w3c.github.io/vc-di-bbs/#:~:text=If%20the%20result%20is%20not%20an%20array%20of%20five%2C%20six%2C%20or%20seven%20elements%20%E2%80%94%20a%20byte%20array%2C%20a%20map%20of%20integers%20to%20integers%2C%20two%20arrays%20of%20integers%2C%20and%20one%20or%20two%20byte%20arrays%3B%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_VERIFICATION_ERROR'; for(const proof of bbsProofs) { baseProofShouldHaveElementCount({proof}); } From 62eb3889532fe8aa06ce50b39a0a9f00e5e61c91 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 17 Oct 2024 13:37:23 -0400 Subject: [PATCH 2/7] Move components test to verify suite. --- tests/suites/create.js | 10 ---------- tests/suites/verify.js | 11 +++++++++++ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/suites/create.js b/tests/suites/create.js index f11b988..87ccaed 100644 --- a/tests/suites/create.js +++ b/tests/suites/create.js @@ -272,16 +272,6 @@ export function createSuite({ shouldHaveMandatoryPointers({proof}); } }); - it('If the result is not an array of five, six, or seven elements ' + - '— a byte array, a map of integers to integers, two arrays of ' + - 'integers, and one or two byte arrays; an error MUST be raised ' + - 'and SHOULD convey an error type of PROOF_VERIFICATION_ERROR.', - function() { - this.test.link = 'https://w3c.github.io/vc-di-bbs/#:~:text=If%20the%20result%20is%20not%20an%20array%20of%20five%2C%20six%2C%20or%20seven%20elements%20%E2%80%94%20a%20byte%20array%2C%20a%20map%20of%20integers%20to%20integers%2C%20two%20arrays%20of%20integers%2C%20and%20one%20or%20two%20byte%20arrays%3B%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_VERIFICATION_ERROR'; - for(const proof of bbsProofs) { - baseProofShouldHaveElementCount({proof}); - } - }); it.skip(' If featureOption is set to "anonymous_holder_binding" or ' + '"pseudonym_hidden_pid", the commitment_with_proof input MUST be ' + 'supplied.', async function() { diff --git a/tests/suites/verify.js b/tests/suites/verify.js index 5ced0da..23b89be 100644 --- a/tests/suites/verify.js +++ b/tests/suites/verify.js @@ -144,6 +144,17 @@ export function verifySuite({ const credential = cloneTestVector(disclosed?.invalid?.valuePrefix); await verificationFail({credential, verifier}); }); + it('If the result is not an array of five, six, or seven elements ' + + '— a byte array, a map of integers to integers, two arrays of ' + + 'integers, and one or two byte arrays; 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-di-bbs/#:~:text=If%20the%20result%20is%20not%20an%20array%20of%20five%2C%20six%2C%20or%20seven%20elements%20%E2%80%94%20a%20byte%20array%2C%20a%20map%20of%20integers%20to%20integers%2C%20two%20arrays%20of%20integers%2C%20and%20one%20or%20two%20byte%20arrays%3B%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_VERIFICATION_ERROR'; + await verificationFail({ + credential: cloneTestVector(disclosed?.invalid?.elementCount), + reason: 'Should not verify a disclosed VC w/ less than 4 components' + }); + }); }); } }); From 0878df3d8747d52947fe32bbc1ab0b4b2917f6ae Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 17 Oct 2024 13:37:52 -0400 Subject: [PATCH 3/7] Make encodeProofValue stand alone helper. --- tests/vc-generator/stubMethods.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/vc-generator/stubMethods.js b/tests/vc-generator/stubMethods.js index 5fb1ab6..80665d9 100644 --- a/tests/vc-generator/stubMethods.js +++ b/tests/vc-generator/stubMethods.js @@ -392,6 +392,10 @@ function serializeDisclosureProofValue({ // Uint8Array presentationHeader ]; + return encodeProofValue({payload, typeEncoders}); +} + +export function encodeProofValue({payload, typeEncoders}) { const cbor = concatBuffers([ CBOR_PREFIX_DERIVED, cborg.encode(payload, {useMaps: true, typeEncoders}) ]); From ca57fd4f0bee9ad2404796b7b428816a01b8af66 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 17 Oct 2024 14:13:43 -0400 Subject: [PATCH 4/7] Create invalid disclosed VC w/ 2 components. --- tests/setup.js | 17 ++++++++++ tests/suites/verify.js | 3 +- tests/vc-generator/stubMethods.js | 55 +++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/tests/setup.js b/tests/setup.js index ff0d6aa..b1d149b 100644 --- a/tests/setup.js +++ b/tests/setup.js @@ -14,6 +14,10 @@ import { getMultikeys, issueCredentials } from './vc-generator/index.js'; +import { + encodeProofValue, + parseDisclosureProofValue +} from './vc-generator/stubMethods.js'; import {generators} from 'data-integrity-test-suite-assertion'; import {writeFile} from 'node:fs/promises'; @@ -144,6 +148,19 @@ export async function verifySetup({credentials, keyTypes, suite}) { } } disclosed.invalid.valuePrefix = valuePrefix; + // invalid element count means less than 4 components + const componentCount = disclosed.invalid.componentCount = new Map(); + for(const [keyType, versions] of disclosed?.basic) { + componentCount.set(keyType, new Map()); + for(const [vcVersion, vc] of versions) { + const modifiedVc = structuredClone(vc); + const params = parseDisclosureProofValue({proof: modifiedVc.proof}); + const payload = [params.bbsProof, params.presentationHeader]; + modifiedVc.proof.proofValue = encodeProofValue({payload}); + // perform test data mutation here + componentCount.get(keyType).set(vcVersion, modifiedVc); + } + } return { base, disclosed diff --git a/tests/suites/verify.js b/tests/suites/verify.js index 23b89be..b59262f 100644 --- a/tests/suites/verify.js +++ b/tests/suites/verify.js @@ -151,7 +151,8 @@ export function verifySuite({ async function() { this.test.link = 'https://w3c.github.io/vc-di-bbs/#:~:text=If%20the%20result%20is%20not%20an%20array%20of%20five%2C%20six%2C%20or%20seven%20elements%20%E2%80%94%20a%20byte%20array%2C%20a%20map%20of%20integers%20to%20integers%2C%20two%20arrays%20of%20integers%2C%20and%20one%20or%20two%20byte%20arrays%3B%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_VERIFICATION_ERROR'; await verificationFail({ - credential: cloneTestVector(disclosed?.invalid?.elementCount), + credential: cloneTestVector(disclosed?.invalid?.componentCount), + verifier, reason: 'Should not verify a disclosed VC w/ less than 4 components' }); }); diff --git a/tests/vc-generator/stubMethods.js b/tests/vc-generator/stubMethods.js index 80665d9..6b2c359 100644 --- a/tests/vc-generator/stubMethods.js +++ b/tests/vc-generator/stubMethods.js @@ -439,3 +439,58 @@ async function _findProof({proofId, proofSet, dataIntegrityProof}) { export function stringToUtf8Bytes({str, utfOffset = 0}) { return TEXT_ENCODER.encode(str).map(b => b + utfOffset); } + +export function parseDisclosureProofValue({proof} = {}) { + try { + if(typeof proof?.proofValue !== 'string') { + throw new TypeError('"proof.proofValue" must be a string.'); + } + if(proof.proofValue[0] !== 'u') { + throw new Error('Only base64url multibase encoding is supported.'); + } + + // decode from base64url + const proofValue = base64url.decode(proof.proofValue.slice(1)); + if(!_startsWithBytes(proofValue, CBOR_PREFIX_DERIVED)) { + throw new TypeError('"proof.proofValue" must be a derived proof.'); + } + + const payload = proofValue.subarray(CBOR_PREFIX_DERIVED.length); + const [ + bbsProof, + compressedLabelMap, + mandatoryIndexes, + selectiveIndexes, + presentationHeader + ] = cborg.decode(payload, {useMaps: true, tags: TAGS}); + + const labelMap = _decompressLabelMap(compressedLabelMap); + const params = { + bbsProof, labelMap, mandatoryIndexes, selectiveIndexes, + presentationHeader + }; + return params; + } catch(e) { + const err = new TypeError( + 'The proof does not include a valid "proofValue" property.'); + err.cause = e; + throw err; + } +} + +function _decompressLabelMap(compressedLabelMap) { + const map = new Map(); + for(const [k, v] of compressedLabelMap.entries()) { + map.set(`c14n${k}`, `b${v}`); + } + return map; +} + +function _startsWithBytes(buffer, prefix) { + for(let i = 0; i < prefix.length; ++i) { + if(buffer[i] !== prefix[i]) { + return false; + } + } + return true; +} From 2517791833543002e13187fa61a9a18b45347e5b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 17 Oct 2024 14:19:23 -0400 Subject: [PATCH 5/7] Lint create suite to remove unused assertion. --- tests/suites/create.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/suites/create.js b/tests/suites/create.js index 87ccaed..873e1c9 100644 --- a/tests/suites/create.js +++ b/tests/suites/create.js @@ -4,7 +4,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ import { - baseProofShouldHaveElementCount, checkEncoding, checkHmacKeyLength, shouldBeMultibaseEncoded, From 540d89d9e13baeb20b4b2bfdb90afc4df27f0b31 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 17 Oct 2024 14:24:10 -0400 Subject: [PATCH 6/7] Comment generator for small component count. --- tests/setup.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/setup.js b/tests/setup.js index b1d149b..3728354 100644 --- a/tests/setup.js +++ b/tests/setup.js @@ -150,14 +150,16 @@ export async function verifySetup({credentials, keyTypes, suite}) { disclosed.invalid.valuePrefix = valuePrefix; // invalid element count means less than 4 components const componentCount = disclosed.invalid.componentCount = new Map(); + // use the basic disclosed vc for(const [keyType, versions] of disclosed?.basic) { componentCount.set(keyType, new Map()); for(const [vcVersion, vc] of versions) { const modifiedVc = structuredClone(vc); const params = parseDisclosureProofValue({proof: modifiedVc.proof}); + // create a payload with only 2 components const payload = [params.bbsProof, params.presentationHeader]; + // replace the existing proofValue with the smaller payload modifiedVc.proof.proofValue = encodeProofValue({payload}); - // perform test data mutation here componentCount.get(keyType).set(vcVersion, modifiedVc); } } From 301d1098adfd0f81f12158bc4ab4cb13bd51cf5a Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sun, 20 Oct 2024 14:22:36 +0000 Subject: [PATCH 7/7] Update tests/suites/verify.js improve test title for components. Co-authored-by: Ted Thibodeau Jr --- tests/suites/verify.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/verify.js b/tests/suites/verify.js index b59262f..11385e5 100644 --- a/tests/suites/verify.js +++ b/tests/suites/verify.js @@ -146,7 +146,7 @@ export function verifySuite({ }); it('If the result is not an array of five, six, or seven elements ' + '— a byte array, a map of integers to integers, two arrays of ' + - 'integers, and one or two byte arrays; an error MUST be raised ' + + 'integers, and one or two byte arrays — 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-di-bbs/#:~:text=If%20the%20result%20is%20not%20an%20array%20of%20five%2C%20six%2C%20or%20seven%20elements%20%E2%80%94%20a%20byte%20array%2C%20a%20map%20of%20integers%20to%20integers%2C%20two%20arrays%20of%20integers%2C%20and%20one%20or%20two%20byte%20arrays%3B%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_VERIFICATION_ERROR';