Skip to content

fix(webvh): enforce the did:webvh future-skew bound on versionTime (#131) - #148

Merged
moisesja merged 5 commits into
mainfrom
fix/issue-131-versiontime-future-skew
Oct 28, 2026
Merged

moisesja merged 5 commits into
mainfrom
fix/issue-131-versiontime-future-skew

Conversation

@moisesja

Copy link
Copy Markdown
Owner

Fixes #131

Problem

did:webvh v1.0, Read step 4: "The versionTime of every entry MUST NOT be more than a small, implementation-defined tolerance in the future relative to the resolver's current time. Resolvers SHOULD use a tolerance of no more than 5 minutes. Entries that exceed this tolerance MUST cause resolution to fail."

NetDid only checked that entries were in increasing order, so a log dated days or years in the future resolved even though conforming resolvers must reject it.

Change

  • LogChainValidator: every validated entry, genesis included, must satisfy versionTime - now <= 5 min. The check sits next to the per-entry SCID check and runs before hash and proof work.
    • Exactly 5 minutes is accepted.
    • Subtracting the two times can't overflow, even for a year-9999 entry.
    • Failures throw LogChainValidationException.
  • DidWebVhMethod: the time comes from the existing Clock seam and is read once per operation. A resolution uses the same reading for the pass up to the requested version and for the pass that checks later entries for a deactivation. Update and Deactivate validate the supplied log against the same rule.
  • Tolerance: fixed at 5 minutes and not configurable. Raising it would exceed the spec's SHOULD. Lowering it would only reject logs that other conforming resolvers accept, because NetDid never writes a future versionTime.

Behavior

  • Latest resolution: returns invalidDidLog if any entry is more than 5 min ahead of the resolver clock.
  • Historical versionId/versionTime resolution: returns an earlier valid entry even when later entries are future-dated, as spec Read step 11.2 requires. A deactivation found only in those future-dated entries is not reported.
  • Update/Deactivate:
  • Operational: writer and resolver clocks must stay synchronized. A resolver whose clock is more than 5 min slow rejects freshly updated DIDs. A writer whose clock is fast publishes entries that correctly clocked resolvers reject.

Evidence

  • Tests: 22 new Issue131_* tests. Fail-first: 12 failed on assertions against the pre-fix code; the other 10 are accept-side and control cases. All 9 code mutations I tried were caught (boundary operator, 4/6-min tolerance, removing either check, tail pass on the system clock or reading the clock twice, Update/Deactivate on the system clock).
  • net-did-verify:
    • Release build: 0 warnings, 0 errors.
    • WebVh tests: 523 → 545. All other projects unchanged and green, W3C conformance 233/233.
    • All 5 samples exit 0.
  • DIF compliance-vector replay: one line differs from the report on main. negative-versiontime-future is now rejected by this rule; before, it was rejected only because the vector's entries are also out of order. Counts are unchanged.
  • Adversarial review: two independent agents, one on correctness/spec and one on trust boundary/operations. No Critical, High or Medium findings. Three Low documentation findings were fixed. The deliberate keep (the internal system-clock validator overload) is recorded in tasks/todo20261027-issue131.md.

No NetDidVersion bump; CHANGELOG updated under [Unreleased].

🤖 Generated with Claude Code

moisesja and others added 5 commits October 27, 2026 23:16
…kew bound (#131)

did:webvh v1.0 Read step 4: an entry whose versionTime is more than the tolerance
(SHOULD <= 5 minutes) ahead of the resolver's current time MUST fail resolution.
22 cases; 12 fail on assertions against the pre-fix resolver, which never compares
versionTime to a clock. The 10 passing cases are accept-side boundaries and controls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bound (#131)

did:webvh v1.0 Read step 4 requires every entry's versionTime to be no more than a
small tolerance (SHOULD <= 5 minutes) ahead of the resolver's current time, and
entries beyond it MUST fail resolution. NetDid only enforced adjacent monotonicity,
so arbitrarily future-dated logs resolved.

LogChainValidator now checks every validated entry (genesis included) against an
explicit "now" at the same choke point as the per-entry SCID check, before hash and
proof work. DidWebVhMethod observes its Clock once per operation: Resolve shares one
observation between the requested-prefix pass and the deactivation-tail pass;
Update and Deactivate validate the supplied log against it. Failures map to
invalidDidLog (resolution) or LogChainValidationException (Update/Deactivate).
Historical resolution of a valid prefix still succeeds below a future-dated tail
(spec Read steps 10-11.2), without asserting a deactivation it cannot verify.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PRD timestamp rules and Resolve step 5, README did:webvh section, CHANGELOG
[Unreleased] Fixed entry, and the regenerated DIF vector divergence report
(negative-versiontime-future now rejected by the skew rule itself).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Correct the Update/Deactivate exception-split wording (a head up to ~1 s ahead
  succeeds after the whole-second wait; exactly 5 min ahead still gets ArgumentException).
- Document that writer clocks must be synchronized too, and how to recover a log
  published by a fast writer clock.
- Make the PRD caching statement precise (historical successes are cached with
  ordinary TTL staleness).
- Plan file review record and lessons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@moisesja moisesja self-assigned this Oct 28, 2026
@moisesja moisesja added this to net-did Oct 28, 2026
@moisesja moisesja added this to the 3.2.0 milestone Oct 28, 2026
@github-project-automation github-project-automation Bot moved this to Backlog in net-did Oct 28, 2026
@moisesja moisesja moved this from Backlog to In review in net-did Oct 28, 2026

@moisesja moisesja left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to merge at a072ba7. No actionable correctness, security, or scalability defect found after reviewing the full diff and an independent adversarial pass. Genesis and later entries enforce the inclusive five-minute bound; historical prefix/tail validation shares one clock observation and cannot assert a future-invalid deactivation. The exception change is documented. Commit messages are clear, and the large line count is mostly tests/docs; production changes stay within two files.

Independently verified: Release build with 0 warnings/errors; 1,845 tests passed, including WebVh 545/545 and W3C 233/233; 7 opt-in EVM tests skipped; all five samples passed. The unchanged did:key sample needed an unsandboxed rerun because Apple cryptography failed inside the sandbox. CI is also green.

@moisesja
moisesja merged commit 5c197d4 into main Oct 28, 2026
1 check passed
@moisesja
moisesja deleted the fix/issue-131-versiontime-future-skew branch October 28, 2026 12:27
@github-project-automation github-project-automation Bot moved this from In review to Done in net-did Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

did:webvh: resolver does not enforce the spec's future-skew bound on versionTime (MUST fail beyond tolerance)

1 participant