Repository navigation
Every proof in a proof set must verify - #76
Merged
ottonomy merged 3 commits intoOct 21, 2026
Merged
Conversation
jsonld-signatures reports a proof set verified when any one of its proofs verifies, and silently skips proofs that no registered suite or expected purpose matches. This adds the pieces to check each proof on its own; nothing calls them yet. - New `PROOF_UNSUPPORTED` problem type. - The Data Integrity crypto service reports jsonld-signatures' "no proof matched" failure as `PROOF_UNSUPPORTED` rather than `INVALID_SIGNATURE`, and says whether the proof's cryptosuite is not supported or its purpose is not the one being checked. The error is matched strictly: a `VerificationError` wrapping exactly one `NotFoundError` with the library's full message. A presentation checked with a challenge whose only proof is `assertionMethod` now fails this way, still fatally. - `dispatchProofSetVerification` dispatches each proof of a set as its own shallow copy through the existing `CryptoService` port and combines the verdicts: any failing proof fails the set, naming the proof; a date-only rejection is reported as before; unsupported proofs beside a checked one are left for the caller to report. Documents with zero or one proof are dispatched as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A credential, presentation or status list credential carrying a proof set passed `proof.signature` when only one of its proofs verified, because jsonld-signatures reports a set verified when any proof does. Breaking either proof of a two-proof credential still read as "Signature verified successfully." - `proof.signature` verifies each proof on its own through `dispatchProofSetVerification`, via a per-verification memo so a later check can read each proof's verdict without verifying again. A failing proof fails the check, and its problem names the proof: "Proof 2 of 2 (DataIntegrityProof, eddsa-rdfc-2022): ...". - An expired credential with one broken proof now reports the broken proof rather than reading as authentic and merely expired. - `verifyStatusList` does the same for status list credentials, so a list with one broken proof is a bad list signature. - The status-list parity test signed its list templates in place; vc's `issue` adds the proof to the object it is given, so lists spread from them carried a stale second proof. It now signs copies. Offline tests with real signatures cover v1 and v2 credentials, expired credentials, status lists and presentations. Closes #67 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A proof set often carries proofs for different audiences, and not
every verifier supports every cryptosuite. A proof that no registered
suite supports, or that was made for a different proof purpose, now no
longer vanishes silently beside a proof that verified.
- New non-fatal `proof.unsupported-proofs` check, between
`proof.signature` and `proof.validity-period`. It reads the proof
verification `proof.signature` already ran and fails with one
`PROOF_UNSUPPORTED` problem per unchecked proof, so the credential
stays verified and the proof suite shows a warning. It succeeds
("Every proof was checked.") otherwise, is skipped for an unsigned
presentation, and is not run when the signature check failed. Every
credential and presentation result has this one more row.
- An unsupported cryptosuite is worded without repeating the proof's
label, since the proof-set prefix already names it.
- README, verification-results and architecture docs, the
`CryptoResult` TSDoc and the CHANGELOG describe proof sets, the new
check and `PROOF_UNSUPPORTED`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #75 — review and merge that first.
Closes #67.
A credential, presentation or status list credential carrying a proof set passed
proof.signature(andverified: true) when only one of its proofs verified: jsonld-signatures accepts a set when any proof verifies, and silently skips proofs no registered suite or purpose matches. On top of #75 this also let an expired credential with one broken proof read as "authentic, merely expired".What changed
dispatchProofSetVerificationhands theCryptoServicea shallow copy carrying one proof at a time and combines the verdicts.proof.signatureandverifyStatusListboth use it;proof.signaturegoes through a per-verification memo so later checks reuse the result. Documents with zero or one proof are dispatched as before. No public type changed.Proof 2 of 2 (DataIntegrityProof, eddsa-rdfc-2022): …. A status list with one broken proof isSTATUS_LIST_SIGNATURE_ERROR; an expired credential with one broken proof reports the broken proof.PROOF_UNSUPPORTEDproblem type and non-fatalproof.unsupported-proofscheck. A proof in a cryptosuite this verifier does not support, or made for another proof purpose, beside a proof that verified is a warning rather than a failure — proof sets exist so different verifiers can each check the proof they support. When no proof could be checked at all,proof.signaturefails withPROOF_UNSUPPORTEDin place ofINVALID_SIGNATURE. Every credential and presentation result now has one more row.assertionMethodnow fails asPROOF_UNSUPPORTED("This proof's purpose (assertionMethod) is not the one being checked (authentication).") instead ofINVALID_SIGNATURE. Still fatal.status-list-cryptosuite-parity.spec.tssigned its list templates in place; vc'sissueadds the proof to the object it is given, so three lists were unknowingly two-proof sets with a stale broken proof. It now signs copies; expectations unchanged.docs/api/verification-results.md,docs/architecture.md,CryptoResultTSDoc and CHANGELOG updated.Validation
pnpm run build— okpnpm run test(lint + vitest) — 994 passedpnpm exec tsc -p tsconfig.dev.json— the same 6 pre-existing errors as Expiry and revocation no longer halt verification #75's head, none newtest/proof-sets.spec.ts) cover A credential with one valid and one invalid proof reports verified: true #67's table for v1 and v2, expired credentials, status lists and presentations; with the fix reverted inproof.signature, 8 of them fail.pnpm run test:browser(Playwright) was not run.Deferred
Structured per-proof results on the check result; a warning row for unsupported proofs on status list credentials; proof chains (
previousProof).🤖 Generated with Claude Code