Skip to content

Every proof in a proof set must verify - #76

Merged
ottonomy merged 3 commits into
fix/expiry-and-status-no-haltfrom
fix/proof-set-all-proofs
Oct 21, 2026
Merged

ottonomy merged 3 commits into
fix/expiry-and-status-no-haltfrom
fix/proof-set-all-proofs

Conversation

@ottonomy

Copy link
Copy Markdown
Contributor

Stacked on #75 — review and merge that first.

Closes #67.

A credential, presentation or status list credential carrying a proof set passed proof.signature (and verified: 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

  • Each proof is verified on its own. dispatchProofSetVerification hands the CryptoService a shallow copy carrying one proof at a time and combines the verdicts. proof.signature and verifyStatusList both use it; proof.signature goes 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.
  • Any failing proof fails the set (VC Data Integrity §4.5), and the problem names it: Proof 2 of 2 (DataIntegrityProof, eddsa-rdfc-2022): …. A status list with one broken proof is STATUS_LIST_SIGNATURE_ERROR; an expired credential with one broken proof reports the broken proof.
  • New PROOF_UNSUPPORTED problem type and non-fatal proof.unsupported-proofs check. 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.signature fails with PROOF_UNSUPPORTED in place of INVALID_SIGNATURE. Every credential and presentation result now has one more row.
  • A challenged presentation whose only proof is assertionMethod now fails as PROOF_UNSUPPORTED ("This proof's purpose (assertionMethod) is not the one being checked (authentication).") instead of INVALID_SIGNATURE. Still fatal.
  • status-list-cryptosuite-parity.spec.ts signed its list templates in place; vc's issue adds 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.
  • README, docs/api/verification-results.md, docs/architecture.md, CryptoResult TSDoc and CHANGELOG updated.

Validation

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

ottonomy and others added 3 commits October 20, 2026 17:01
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>
@ottonomy
ottonomy added this pull request to stack #77 October 20, 2026 22:36
@ottonomy
ottonomy merged commit e86bb79 into main Oct 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A credential with one valid and one invalid proof reports verified: true

1 participant