verifyhash 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +883 -0
  3. package/cli/abi/ContributionRegistry.json +881 -0
  4. package/cli/agent.js +2173 -0
  5. package/cli/anchor-artifact.js +853 -0
  6. package/cli/anchor.js +400 -0
  7. package/cli/claim.js +881 -0
  8. package/cli/core/agent-commit.js +448 -0
  9. package/cli/core/agent-session.js +598 -0
  10. package/cli/core/anchor-binding.js +663 -0
  11. package/cli/core/attestation.js +580 -0
  12. package/cli/core/evidence-plans.js +495 -0
  13. package/cli/core/fixtures/evidence-plans/baseline.json +19 -0
  14. package/cli/core/fulfill-intake.js +1082 -0
  15. package/cli/core/go-live-preflight.js +481 -0
  16. package/cli/core/license.js +534 -0
  17. package/cli/core/manifest.js +243 -0
  18. package/cli/core/packetseal.js +591 -0
  19. package/cli/core/registryArtifact.js +49 -0
  20. package/cli/core/revocation.js +539 -0
  21. package/cli/core/rfc3161.js +389 -0
  22. package/cli/core/timestamp.js +482 -0
  23. package/cli/core/trust-asof.js +479 -0
  24. package/cli/dataset.js +2950 -0
  25. package/cli/evidence.js +2227 -0
  26. package/cli/fulfill-webhook-http.js +438 -0
  27. package/cli/git.js +220 -0
  28. package/cli/hash.js +550 -0
  29. package/cli/identity.js +1072 -0
  30. package/cli/journal-cli.js +1110 -0
  31. package/cli/journal-log.js +454 -0
  32. package/cli/journal.js +334 -0
  33. package/cli/lineage.js +447 -0
  34. package/cli/list.js +287 -0
  35. package/cli/parcel.js +1509 -0
  36. package/cli/proof.js +578 -0
  37. package/cli/prove.js +300 -0
  38. package/cli/receipt.js +631 -0
  39. package/cli/registry.js +331 -0
  40. package/cli/reputation.js +344 -0
  41. package/cli/revocation.js +495 -0
  42. package/cli/serve-verify-http.js +298 -0
  43. package/cli/serve-verify.js +333 -0
  44. package/cli/show.js +339 -0
  45. package/cli/verify.js +383 -0
  46. package/cli/vh.js +3927 -0
  47. package/docs/ADOPT.md +183 -0
  48. package/docs/ADOPTION.json +11 -0
  49. package/docs/AGENTTRACE.md +247 -0
  50. package/docs/ANCHORING.md +167 -0
  51. package/docs/AUDIT.md +55 -0
  52. package/docs/CONFORMANCE.md +107 -0
  53. package/docs/DATALEDGER.md +638 -0
  54. package/docs/DECIDE.md +47 -0
  55. package/docs/DECISIONS-PENDING.md +27 -0
  56. package/docs/DEPLOY-PUBLIC-SITE.md +301 -0
  57. package/docs/ENGINE-LEDGER.json +12 -0
  58. package/docs/EVIDENCE.md +519 -0
  59. package/docs/GO-LIVE.md +66 -0
  60. package/docs/IDENTITY.md +123 -0
  61. package/docs/INDEPENDENT-VERIFICATION.md +377 -0
  62. package/docs/INTEGRITY-JOURNAL.md +337 -0
  63. package/docs/KEY-LIFECYCLE.md +179 -0
  64. package/docs/LICENSING.md +46 -0
  65. package/docs/LINEAGE.md +307 -0
  66. package/docs/LOOP-AUDIT-2026-07-03.json +580 -0
  67. package/docs/LOOP-HARDENING-PLAN.md +44 -0
  68. package/docs/MERKLE-LEAVES.md +113 -0
  69. package/docs/METRICS.jsonl +31 -0
  70. package/docs/MORNING.md +204 -0
  71. package/docs/PILOT.md +444 -0
  72. package/docs/PROOFPARCEL.md +227 -0
  73. package/docs/PROOFS.md +262 -0
  74. package/docs/RECEIPTS.md +341 -0
  75. package/docs/REPUTATION.md +158 -0
  76. package/docs/SDK.md +301 -0
  77. package/docs/STRATEGY-ARCHIVE.md +5055 -0
  78. package/docs/SUPERVISOR-RUNBOOK.md +52 -0
  79. package/docs/TRUST-BOUNDARIES.md +335 -0
  80. package/docs/TRUSTLEDGER.md +1976 -0
  81. package/docs/USAGE-BUDGET.json +121 -0
  82. package/docs/VERIFY-SERVICE.md +168 -0
  83. package/index.js +160 -0
  84. package/package.json +41 -0
  85. package/trustledger/build-standalone.js +796 -0
  86. package/trustledger/cli.js +3179 -0
  87. package/trustledger/close.js +391 -0
  88. package/trustledger/corpus.js +159 -0
  89. package/trustledger/dist/BUILD-PROVENANCE.json +99 -0
  90. package/trustledger/dist/trustledger-standalone.html +6197 -0
  91. package/trustledger/dist/trustledger-standalone.html.sha256 +1 -0
  92. package/trustledger/door-core.js +442 -0
  93. package/trustledger/fixtures/bank.csv +7 -0
  94. package/trustledger/fixtures/bank.malformed.csv +3 -0
  95. package/trustledger/fixtures/bank.noalias.csv +5 -0
  96. package/trustledger/fixtures/bank.ofx +34 -0
  97. package/trustledger/fixtures/bank.real.csv +5 -0
  98. package/trustledger/fixtures/corpus/_shared/prior-close.json +22 -0
  99. package/trustledger/fixtures/corpus/bank-book-mismatch--benign-twin/inputs.json +14 -0
  100. package/trustledger/fixtures/corpus/bank-book-mismatch--benign-twin/meta.json +7 -0
  101. package/trustledger/fixtures/corpus/bank-book-mismatch--out-of-trust/inputs.json +14 -0
  102. package/trustledger/fixtures/corpus/bank-book-mismatch--out-of-trust/meta.json +7 -0
  103. package/trustledger/fixtures/corpus/continuity-break--benign-twin/inputs.json +15 -0
  104. package/trustledger/fixtures/corpus/continuity-break--benign-twin/meta.json +7 -0
  105. package/trustledger/fixtures/corpus/continuity-break--out-of-trust/inputs.json +15 -0
  106. package/trustledger/fixtures/corpus/continuity-break--out-of-trust/meta.json +7 -0
  107. package/trustledger/fixtures/corpus/negative-tenant-ledger--benign-twin/inputs.json +13 -0
  108. package/trustledger/fixtures/corpus/negative-tenant-ledger--benign-twin/meta.json +7 -0
  109. package/trustledger/fixtures/corpus/negative-tenant-ledger--out-of-trust/inputs.json +13 -0
  110. package/trustledger/fixtures/corpus/negative-tenant-ledger--out-of-trust/meta.json +7 -0
  111. package/trustledger/fixtures/corpus/owner-overdraw--benign-twin/inputs.json +15 -0
  112. package/trustledger/fixtures/corpus/owner-overdraw--benign-twin/meta.json +7 -0
  113. package/trustledger/fixtures/corpus/owner-overdraw--out-of-trust/inputs.json +15 -0
  114. package/trustledger/fixtures/corpus/owner-overdraw--out-of-trust/meta.json +7 -0
  115. package/trustledger/fixtures/corpus/security-deposit-segregation--benign-twin/inputs.json +16 -0
  116. package/trustledger/fixtures/corpus/security-deposit-segregation--benign-twin/meta.json +7 -0
  117. package/trustledger/fixtures/corpus/security-deposit-segregation--out-of-trust/inputs.json +13 -0
  118. package/trustledger/fixtures/corpus/security-deposit-segregation--out-of-trust/meta.json +7 -0
  119. package/trustledger/fixtures/corpus/subledger-out-of-balance--benign-twin/inputs.json +13 -0
  120. package/trustledger/fixtures/corpus/subledger-out-of-balance--benign-twin/meta.json +7 -0
  121. package/trustledger/fixtures/corpus/subledger-out-of-balance--out-of-trust/inputs.json +13 -0
  122. package/trustledger/fixtures/corpus/subledger-out-of-balance--out-of-trust/meta.json +7 -0
  123. package/trustledger/fixtures/e2e/bank.aliased.csv +4 -0
  124. package/trustledger/fixtures/e2e/bank.csv +4 -0
  125. package/trustledger/fixtures/e2e/bank.nsf.csv +4 -0
  126. package/trustledger/fixtures/e2e/quickbooks.csv +6 -0
  127. package/trustledger/fixtures/e2e/quickbooks.nsf.csv +8 -0
  128. package/trustledger/fixtures/e2e/rentroll.csv +6 -0
  129. package/trustledger/fixtures/e2e/rentroll.nsf.csv +8 -0
  130. package/trustledger/fixtures/e2e/rentroll.short.csv +5 -0
  131. package/trustledger/fixtures/plans/baseline.json +25 -0
  132. package/trustledger/fixtures/plans/price-binding.example.json +27 -0
  133. package/trustledger/fixtures/policy/ambiguous-deposit-example.json +12 -0
  134. package/trustledger/fixtures/policy/baseline.json +19 -0
  135. package/trustledger/fixtures/policy/ca-example.json +12 -0
  136. package/trustledger/fixtures/policy/negative-tenant-ledger-example.json +12 -0
  137. package/trustledger/fixtures/policy/owner-overdraw-example.json +12 -0
  138. package/trustledger/fixtures/quickbooks.csv +7 -0
  139. package/trustledger/fixtures/quickbooks.real.csv +5 -0
  140. package/trustledger/fixtures/rentroll.csv +6 -0
  141. package/trustledger/fixtures/rentroll.real.csv +4 -0
  142. package/trustledger/ingest.js +1163 -0
  143. package/trustledger/lib/policy-bundled-loader.js +44 -0
  144. package/trustledger/lib/sha256-vendored.js +227 -0
  145. package/trustledger/license.js +563 -0
  146. package/trustledger/match.js +551 -0
  147. package/trustledger/plans.js +551 -0
  148. package/trustledger/policy.js +398 -0
  149. package/trustledger/public/index.html +512 -0
  150. package/trustledger/reconcile.js +1486 -0
  151. package/trustledger/report.js +887 -0
  152. package/trustledger/seal.js +854 -0
  153. package/trustledger/server.js +391 -0
  154. package/trustledger/valueproof.js +350 -0
package/docs/AUDIT.md ADDED
@@ -0,0 +1,55 @@
1
+ # Security audit — ContributionRegistry (run wmkm6kzoj, 2026-06-23)
2
+
3
+ 8-lens adversarial audit + 3-judge verification panel. **21 raw → 10 confirmed, 13 dismissed.**
4
+ Full machine output: `tasks/wmkm6kzoj.output`.
5
+
6
+ ## Staged Epic-0 fix-tasks (fold into BACKLOG.md when no driver run is active)
7
+
8
+ Append these under `## EPIC-0` in BACKLOG.md, then relaunch the driver.
9
+
10
+ - **T-0.1** `TODO` Domain-separate Merkle leaves from internal nodes (verifyLeaf + CLI). deps: none. files: contracts/ContributionRegistry.sol, cli/hash.js, test/
11
+ - Acceptance: leaves are domain-separated so a crafted internal node can NOT be verified as a leaf
12
+ (double-hash leaves per OZ StandardMerkleTree, or tag the hash); `cli/hash.js` and the JS Merkle
13
+ helper in tests use the identical convention; a test constructs a second-preimage forgery attempt and
14
+ asserts `verifyLeaf` rejects it; full suite green. *(Covers F15, F11, F13. → Builder, `contract` persona.)*
15
+
16
+ - **T-0.2** `TODO` Bind file paths into repo Merkle leaves. deps: T-0.1. files: cli/hash.js, test/
17
+ - Acceptance: directory leaf = `keccak256(domainPrefix ‖ relPath ‖ 0x00 ‖ keccak256(content))`; the root
18
+ commits to names+content so renaming/moving a file changes the root; docs state exactly what the root
19
+ commits to; a test proves a rename is detected; suite green. *(Covers C2. → Builder, `cli` persona.)*
20
+
21
+ - **T-0.3** `TODO needs-decision` Resolve attribution front-running (this IS decision D-1). deps: none. files: contracts/, cli/, test/
22
+ - Engineering fork for the Decider. Options: (a) **commit–reveal** — `commit(keccak256(contentHash, msg.sender, salt))`
23
+ then `reveal(contentHash, salt)` after N blocks (audit's recommendation; defeats both theft and griefing);
24
+ (b) **per-author namespacing** — key records by `keccak256(addr, contentHash)`; (c) **accept + document** —
25
+ redefine `contributor` as "first anchorer", drop authorship claims from spec/NatSpec.
26
+ - Acceptance (after the Decider chooses): chosen scheme implemented; a test proves a front-runner who copies
27
+ the mempool value canNOT become the recorded author (or, for option c, NatSpec/README/spec updated to drop
28
+ authorship claims + a test asserting only the weaker "existed by block N" guarantee); suite green.
29
+ *(Covers F4, F14, F2, F5. → Decider, then Builder.)*
30
+
31
+ - **T-0.4** `TODO` Document trust boundaries: uri + timestamp. deps: none. files: contracts/ (NatSpec), README/docs
32
+ - Acceptance: NatSpec + docs state plainly that `uri` is an untrusted hint (consumers must re-derive and
33
+ re-hash content) and that `timestamp`/`blockNumber` prove on-chain ordering and an upper bound on existence
34
+ time, NOT authorship time and not validator-proof. *(Covers F17, C3. → Builder, docs.)*
35
+
36
+ ## Confirmed findings (record)
37
+
38
+ | ID | Sev | Panel | Title |
39
+ |----|-----|-------|-------|
40
+ | F4 | High | 3/3 | anchor() front-runnable — permanent mis-attribution |
41
+ | F14 | High | 3/3 | attribution = first broadcaster, not author |
42
+ | F15 | High | 3/3 | verifyLeaf accepts internal nodes as leaves (second-preimage) |
43
+ | F2 | Med | 3/3 | no msg.sender↔content binding → authorship squatting |
44
+ | F5 | Med | 3/3 | griefing pre-emption with poisoned uri |
45
+ | F11 | Med | 2/3 | verifyLeaf no leaf/node domain separation |
46
+ | F17 | Med | 3/3 | uri unauthenticated, unbound, fixed by first anchorer |
47
+ | C2 | Med | 3/3 | Merkle root doesn't commit to file names/paths |
48
+ | C3 | Low | 2/3 | timestamp/blockNumber validator-influenced, not trustworthy time |
49
+ | F13 | Info | 2/3 | sorted-pair odd-node promotion enables ambiguous tree shapes |
50
+
51
+ ## Dismissed (13 — panel refuted as non-issues / accepted risk)
52
+
53
+ No reentrancy surface · ownerless-immutable remediation gap · verifyLeaf no MEV (pure) · unbounded proof loop
54
+ (self-paid) · unbounded uri (self-paid) · uint64 truncation · `unchecked total+1` sound · empty-proof leaf==root
55
+ (×2) · Anchored event omits blockNumber (×2) · evmVersion not pinned · incomplete NatSpec.
@@ -0,0 +1,107 @@
1
+ # The adversarial conformance corpus — what "REJECT" actually proves
2
+
3
+ > **Audience: a buyer's security/procurement reviewer asking "how do I know your verifier won't say
4
+ > ACCEPT on something it shouldn't?"** This page answers that mechanically, with a runnable gate and a
5
+ > precise statement of what it proves — and what it does **not**. It trusts nothing but `node` and the
6
+ > bytes committed in this repo.
7
+
8
+ The 60-second [`../challenge/`](../challenge/) kit proves a verifier catches **one** byte-edit on **one**
9
+ packet. The conformance corpus raises that to the real question: *does the verifier catch the OTHER ways
10
+ an artifact gets poisoned, across the kinds of packets a business actually seals?* It commits one CLEAN
11
+ business packet per vertical plus exactly one POISONED packet per tamper class, and drives every shipped
12
+ evidence-seal verifier of the UNSIGNED content-integrity seal against every poisoned artifact in one
13
+ read-only command.
14
+
15
+ ## Run it
16
+
17
+ ```sh
18
+ node challenge/corpus/run-corpus.js # human report; exit 0 = PASS, 1 = FAIL
19
+ node challenge/corpus/run-corpus.js --json # stable, machine-readable result on stdout
20
+ ```
21
+
22
+ [`challenge/corpus/run-corpus.js`](../challenge/corpus/run-corpus.js) is the **self-auditing conformance
23
+ runner**: it drives every shipped verifier of the unsigned content-integrity seal — the producer's own
24
+ `vh evidence verify` **and** the two INDEPENDENT offline verifiers a counterparty actually runs (the
25
+ single-file standalone bundle
26
+ [`../verifier/dist/verify-vh-standalone.js`](../verifier/dist/verify-vh-standalone.js) and the split-tree
27
+ [`../verifier/verify-vh.js`](../verifier/verify-vh.js)) — against EVERY poisoned artifact in the corpus,
28
+ and asserts the one load-bearing safety invariant the whole product rests on:
29
+
30
+ > **NO verifier EVER returns ACCEPT (exit 0) on a poisoned input.**
31
+
32
+ It is a permanent **regression floor**: if any future refactor ever opens a false-ACCEPT hole in ANY
33
+ verifier, this runner goes RED. The gate is proven to have teeth — its companion test injects a synthetic
34
+ verifier that wrongly ACCEPTS a poisoned input and proves the runner then exits 1, naming the offending
35
+ class + verifier (a gate that cannot fail proves nothing).
36
+
37
+ ## The honest boundary — what a green run proves, and what it does NOT
38
+
39
+ Be precise about what an all-REJECT run buys you:
40
+
41
+ - **It proves the verifier REJECTs every ENUMERATED tamper class** in the corpus (each clean packet plus
42
+ exactly one documented mutation), **by re-deriving the keccak-256 Merkle root from the bytes you hold**
43
+ — never trusting the seal's own stored hashes. That is mechanical, runnable in seconds, and trusts
44
+ nothing but `node` and the committed bytes.
45
+ - **It does NOT prove the absence of unknown tamper classes.** The corpus is a finite, enumerated
46
+ taxonomy; passing it means the verifier rejects *these* poisonings, not *every conceivable* one. A
47
+ green run is evidence of conformance to the published classes, never a proof that no other attack
48
+ exists.
49
+ - **A REJECT is tamper-evidence, NOT a trusted timestamp.** The verifier re-derives "these are exactly
50
+ those bytes"; it asserts nothing about *when*. A trustworthy "sealed at T" still requires **P-3** (the
51
+ human-owned trust-root — a self-managed signing key, an RFC-3161 timestamp authority, or an on-chain
52
+ anchor; see [`INDEPENDENT-VERIFICATION.md`](INDEPENDENT-VERIFICATION.md) §3 and **P-3** in
53
+ [`../STRATEGY.md`](../STRATEGY.md)). The corpus is the **FREE, UNSIGNED** path, so there is no signer to
54
+ pin here either; a green verdict is not a legal or accounting opinion.
55
+ - **It covers the UNSIGNED content-integrity surface ONLY — it does NOT red-team the signer-pin
56
+ (`--vendor`) path.** Every fixture in the corpus is unsigned, and the taxonomy contains **no
57
+ signature-corruption / signer-substitution / attestation-edit class**. So this corpus exercises only the
58
+ three verifiers of the unsigned content-integrity seal (the standalone bundle, the split-tree
59
+ `verify-vh.js`, and the producer's `vh evidence verify`); it does **not** exercise the signed-verifier
60
+ surface — the standalone verifier's `--vendor` signer-pin, `vh evidence verify-signed`, or the
61
+ attestation verifiers (`vh dataset/parcel verify-attest`, `vh revocation/identity verify`). Signer-pin
62
+ is the page's named **PAID** upgrade; a green corpus run is **not** evidence that the signer-pin path was
63
+ adversarially tested.
64
+
65
+ This is the same trust boundary every verifyhash seal carries — stated once, so the conformance story
66
+ never over-promises.
67
+
68
+ ## The enumerated tamper classes
69
+
70
+ The taxonomy is published in [`../challenge/corpus/manifest.json`](../challenge/corpus/manifest.json) and
71
+ regenerated deterministically by [`../challenge/corpus/generate.js`](../challenge/corpus/generate.js).
72
+ Each class is one clean business packet plus exactly one documented mutation the verifier must REJECT.
73
+ `expectedExit` is the standalone verifier's own contract: **3** = REJECTED (tamper: CHANGED / MISSING /
74
+ forged root), **2** = usage (unrecognized seal kind).
75
+
76
+ | class id | vertical | mutation | expected exit |
77
+ |----------|----------|----------|---------------|
78
+ | `finance-amount-edited` | finance | Flip one digit in a ledger credit amount. | 3 |
79
+ | `finance-tie-out-dropped` | finance | Delete the bank tie-out file the seal still references. | 3 |
80
+ | `ai-data-sample-swapped` | ai-data | Relabel one training sample in `samples.jsonl`. | 3 |
81
+ | `ai-data-license-stripped` | ai-data | Truncate `LICENSE.txt` to empty (strip the provenance license). | 3 |
82
+ | `ai-data-file-renamed` | ai-data | Rename a sealed file so the sealed path is now MISSING. | 3 |
83
+ | `software-sbom-injected` | software | Inject an undeclared dependency line into `sbom.json`. | 3 |
84
+ | `software-checksum-edited` | software | Alter one published artifact checksum digit in `checksums.txt`. | 3 |
85
+ | `legal-clause-altered` | legal | Alter the fee amount in `agreement.txt`. | 3 |
86
+ | `legal-signature-page-dropped` | legal | Delete the executed signature page the seal references. | 3 |
87
+ | `seal-root-forged` | finance | Forge the seal's Merkle root (packet bytes untouched); the verifier RE-DERIVES the root and rejects. | 3 |
88
+ | `seal-kind-corrupted` | software | Corrupt the seal's `kind` to an unrecognized value (usage error). | 2 |
89
+
90
+ Adding a new tamper class to the manifest WITHOUT also documenting it here FAILS the build: the docs-rot
91
+ guard [`../test/challenge.corpus.docs.test.js`](../test/challenge.corpus.docs.test.js) cross-checks this
92
+ list against `manifest.json` (every manifest class id appears here, and no id here is stale), so the
93
+ buyer-facing trust story can never silently drift from the taxonomy it claims to cover.
94
+
95
+ ## Where this fits
96
+
97
+ - The corpus is reachable from the cold-prospect kit: [`../challenge/README.md`](../challenge/README.md)
98
+ links this conformance step after the one-byte tamper walkthrough.
99
+ - The deeper specification of the verifiers it drives — the exact bytes verified, the no-network posture,
100
+ and how their independence is proven mechanically — is in
101
+ [`INDEPENDENT-VERIFICATION.md`](INDEPENDENT-VERIFICATION.md).
102
+ - The buyer pilot runbook [`PILOT.md`](PILOT.md) points at this corpus as the procurement-grade
103
+ conformance check a security reviewer runs before relying on the verifier.
104
+
105
+
106
+ ---
107
+ <sub>© 2026 verifyhash.com · Licensed under Apache-2.0 (SPDX-License-Identifier: Apache-2.0) — see the [LICENSE](https://verifyhash.com/LICENSE) and [NOTICE](https://verifyhash.com/NOTICE) served with this file.</sub>