Skip to content

Bound per-call typed-data value visits - #9

Merged
HDauven merged 1 commit into
mainfrom
fix/typed-data-value-work-budget
Sep 14, 2026
Merged

HDauven merged 1 commit into
mainfrom
fix/typed-data-value-work-budget

Conversation

@HDauven

@HDauven HDauven commented Sep 14, 2026

Copy link
Copy Markdown
Member

Summary

Resolves #6; follow-up to merged #8 and the shared-value work report.

Add an inclusive 262,144 typed-value visits per call reference guard. A visit is processing one root, field value or array element—an atomic value, array container or struct, including empty structs. Shared references are charged on every path; structs are not double-counted when emitting their hashes.

  • Share one private counter across domain and primary for hash/debug/BLS verification. Apply the same guard to the optional policy value walks before JSON serialization.
  • Propagate TypedDataError / E_COMPLEXITY as a resource exception, not a failed-signature result. Ordinary signer-floor refusals remain E_POLICY_LIMIT.
  • Keep hashing independent of signer policy and JSON serialization. Shape validation remains shape-only; type-hash caching remains per-call, with no value-hash memoization.
  • Document the counting rule, floor-preserving threshold and remaining limitations in §11.1; record the observable refusal change in Unreleased.

Why this threshold: every visited occurrence in a complete, otherwise-valid JSON payload has its own serialized value-token/opening-delimiter byte. The sole implicit domain-contract visit can use the unvisited top-level opening delimiter. Therefore inputs within the existing 262,144-byte compact-JSON interoperability floor cannot exhaust this visit budget. The argument includes alias-preserving copies with identical expanded JSON values; lossy/custom JavaScript serialization cannot establish that guarantee.

This is a reference resource refusal, not a universal validity ceiling. Some previously accepted above-floor work is now refused; accepted encodings remain unchanged. No exported function signature, dependency, signing string, normalization or fixture change.

Limits and review focus

The counter bounds visits, not per-value bytes, wall-clock time, peak memory, arbitrary getters/proxies, or policy serialization of unused metadata. No hostile-object snapshot framework is introduced. Transport controls and broader resource decisions remain separate. The accepted approach is implementation-local guards, not a universal ceiling; together with merged #8, this PR completes #6's agreed traversal-bounds scope.

Please review the visit accounting (including both roots, array containers and empty structs), per-call reset, JSON-floor argument and resource-error propagation.

Validation

Fresh on exact head a4756af009c8905e08dc3f5ff64681231f0096e5, directly based on c6f3c19:

  • npm run ci: build/coverage and 191 library tests /5 files pass. Its separate, unchanged application-approval example also passes 16 real-BLS/SQLite checks; SQLite is example-test infrastructure, not a hashing dependency.
  • Fresh integrity checks preserve all 41 fixtures and confirm that all 71 packed files equal current source/build and installed bytes.

Retained checks on this same commit/tree:

  • Final affected tests on old main: 7 intended failures /143 passes. Eight isolated mutations detect omitted/doubled charges, root resets, missing policy enforcement and an exclusive boundary.
  • Installed package: seven new budget groups with Node/OpenSSL full-preimage comparisons against the real Noble target, 14 prior field/policy/BLS checks, six prior array/BLS checks, public types and the copied application checks pass.
  • Committed repack is byte-identical. Five locked/offline native Rust BLS outputs match retained vectors—not an independent typed-data encoder.
  • Bounded shared-graph probes preserve under-budget digests and return E_COMPLEXITY above the visit limit for structs and arrays. Existing wide-array/large-string and policy-separation assertions remain intact.

Draft for review. No Wallet/Connect source changes, new browser/extension signing E2E, package publication, registry-backed consumer locks or protocol-freeze claim. Local author validation is not independent approval or remote CI.

Reported-by: ichbindas 54631150+ichbindas@users.noreply.github.com

Count atomic, array and struct visits across both roots, including repeated
paths through shared values. Use the same inclusive 262144-visit guard in
the optional policy walk and refuse with E_COMPLEXITY before further work.
The threshold preserves the complete-JSON interoperability floor without
calling signer policy or changing accepted encodings.

Document the counting proof and limits: this is not a byte-work, wall-clock,
peak-memory or arbitrary-JavaScript safety guarantee. Add boundary, alias,
policy, reset and genuine-BLS regression checks; retain all frozen fixtures.

Refs: #6
Reported-by: ichbindas <54631150+ichbindas@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

No unresolved approval blockers are identified.

Pull request overview

Adds an inclusive per-call 262,144 typed-value visit guard while preserving existing encoding and policy behavior.

Changes:

  • Tracks roots, fields, arrays, structs, atomic values, and shared references.
  • Propagates E_COMPLEXITY through hashing and verification.
  • Adds boundary tests and documents the guard and limitations.
File summaries
File Description
src/typed-data/hash.ts Implements shared per-call visit budgeting.
src/typed-data/hash.test.ts Tests visit accounting and boundaries.
src/bls/sig.test.ts Verifies resource-error propagation.
docs/typed-data-v1.md Documents counting and floor preservation.
CHANGELOG.md Records the new guard.
Review details
  • Files reviewed: 5/5 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@HDauven
HDauven marked this pull request as ready for review September 14, 2026 23:52
@HDauven
HDauven merged commit a379242 into main Sep 14, 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.

Bound the type-graph traversal and fail with a coded error

2 participants