{"id":51442831,"url":"https://github.com/prof-faustus/mfspv","last_synced_at":"2026-07-05T13:01:45.243Z","repository":{"id":364898614,"uuid":"1269652317","full_name":"prof-faustus/mfspv","owner":"prof-faustus","description":"Merkle-Forest SPV (MF-SPV): sender-held inclusion proofs for BSV/Teranode at 10^6-10^11 tx/s — reference implementation, security audit, and publication-grade evaluation. Open BSV License v4.","archived":false,"fork":false,"pushed_at":"2026-06-15T03:06:15.000Z","size":252,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-15T03:10:42.516Z","etag":null,"topics":["blockchain","bsv","golang","light-client","merkle-proof","payment-verification","spv","teranode"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/prof-faustus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-15T01:07:23.000Z","updated_at":"2026-06-15T03:06:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/prof-faustus/mfspv","commit_stats":null,"previous_names":["prof-faustus/mfspv"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/prof-faustus/mfspv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prof-faustus%2Fmfspv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prof-faustus%2Fmfspv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prof-faustus%2Fmfspv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prof-faustus%2Fmfspv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/prof-faustus","download_url":"https://codeload.github.com/prof-faustus/mfspv/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prof-faustus%2Fmfspv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35154748,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-05T02:00:06.290Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","bsv","golang","light-client","merkle-proof","payment-verification","spv","teranode"],"created_at":"2026-07-05T13:01:43.233Z","updated_at":"2026-07-05T13:01:45.208Z","avatar_url":"https://github.com/prof-faustus.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MF-SPV — Merkle-Forest SPV (BSV / Teranode)\n\nA complete, dependency-free Go implementation of the Merkle-Forest SPV design in\nthis folder (`01_ARCHITECTURE.md`, `02_MODULE_SPECS.md`, `03_SCALING_MODEL.md`,\n`04_TEST_PLAN.md`, `PAPER.md`).\n\n**BSV only.** No BTC parameter, code path, or assumption appears anywhere. The\nmodule has **zero external dependencies** — it builds and tests entirely offline,\nincluding the secp256k1 signer.\n\n## What this is\n\nA five-level Merkle commitment hierarchy that reuses Teranode's existing subtree\nstructure, ships inclusion proofs sender-pushed with the payment, and freezes the\nhistorical proof at block-sealing:\n\n```\n L0  field            -\u003e  MTxID = TXID          (Merkle tree over tx FIELDS; US 2022/0216997)\n L1  TXID             -\u003e  subtree root          (Teranode subtree, \u003c= 2^20 TXIDs)\n L2  subtree root     -\u003e  block Merkle root     (built over subtree roots)\n L3  block root       -\u003e  80-byte header        (PoW-sealed)  -- core ends here, no consensus change\n L4  header           -\u003e  off-header accumulator (MMR root in the generation tx)  -- OPTIONAL\n```\n\nDouble-spend is kept **orthogonal** to the proof: a valid inclusion proof is a\nfail-fast against spam/error, never double-spend protection. Acceptance at the\npoint of sale combines inclusion (local) with a live UTXO query, a PoW-attested\nalert layer, and a merchant risk parameter τ.\n\n## Layout (build order)\n\n| Package            | Design ref                | Role |\n|--------------------|---------------------------|------|\n| `commitment`       | §commitment / T1          | SHA-256d Merkle core; L0–L2 build \u0026 verify; depth law |\n| `crypto`           | (spend authorisation)     | self-contained secp256k1 ECDSA, RFC 6979, low-S |\n| `accumulator`      | §accumulator / T2         | L4 MMR over headers; `VerifyAnchor`; absent-period honesty |\n| `teranode`         | §teranode_adapter / T6    | read-only `ProofSource`/`HeaderChain`/`UTXOClient` + in-memory `MockNode` |\n| `bundle`           | §bundle / T3              | the sender-held proof object; `Build/Serialize/Verify/Reanchor` |\n| `payment`          | §3.2                      | `Tx3`, sighash, the Alice→Bob push message |\n| `walletalice`      | §wallet_alice / T4        | offline customer wallet (`Sign/FillTemplate/Export`) |\n| `walletbob`        | §wallet_bob / T4,T5       | point-of-sale till (`AcceptPayment/Broadcast`, `RiskPolicy`) |\n| `dsalert`          | §dsalert / T5             | evidence-gated, PoW-attested double-spend alert layer |\n| `bench`            | §bench / T7               | scaling simulator reproducing the derived table |\n| `cmd/mfspv`        | —                         | demonstration runner |\n| `adversarial`      | 04_TEST_PLAN A1–A5        | consolidated red-team rejections |\n\n## Run\n\n```sh\ngo test ./...               # 75 tests: T1–T7, A1–A5, RT-1..7, KAT, differential, property, Monte-Carlo, value\ngo test -shuffle=on ./...   # order-independent (06_EVALUATION_DESIGN §3.4)\ngo run ./cmd/mfspv          # scaling table + capacity + one full push payment\ngo run ./cmd/mfspv -eval    # emit environment.json + claims.csv, tagged M/D/S (06 §8 reproduce)\ngo run ./cmd/mutate         # offline mutation-testing gate: kills 17/17 security-critical mutants (06 §4.4/§10)\ngo run ./cmd/mfspv -fabric  # 07 verification-fabric throughput benchmark (bar A\u003e=1.5)\n```\n\n**Verification throughput (07_VERIFICATION_FABRIC.md) — COMPLETE real pipeline.**\n`go run ./scalebench` measures the whole SPV inclusion path end to end: **decode a\nreal proof from its wire bytes, then verify** it, with a zero-allocation streaming\nverifier and shared-node amortisation (Lever B). Measured on a 64-core Xeon: **6.71×10⁷\nverifications/second (A = 6.71), and the rate is independent of depth** — 10⁶ through\n**10¹¹ tx/s all measure A ≈ 6.71**, 4.5× the 1.5×10⁷ minimum (larger batches reach A ≈ 13).\nHashing is not the bottleneck; the per-proof cost is decoding a proof that grows only\nlogarithmically (960→1472 B over 10⁶→10¹¹), so throughput does not fall as tx/s rises.\nStateless and shares-nothing → aggregate scales ~linearly with cores/nodes. No consensus\nchange. **Depth-independence holds at 10× the target** (depth 460: A ≈ 3.5). Per 07 §5, the\ninclusion leaf is the **consensus TXID** (`VerifyToBlockRoot` with `leaf=txid, l0=nil`); the\nMTxID field tree is an optional secondary commitment.\n\n**Full SPV protocol is tested**, both acquisition modes:\n- **Push** (`walletbob.TestE2E_SPV_PushToNodes`): Alice→Bob signed Tx + inclusion path → Bob verifies\n  locally (path **and** signature, unspent, value) → Alice and Bob **push the Tx to 2–3 nodes** →\n  nodes re-validate; tampered Tx rejected.\n- **Pull / proof acquisition** (`fabric.Fetch`, `fabric.TestFetchInclusion_SPVPull`): Bob has a new\n  TXID and **asks a node for the Merkle path + the block header** (`ProofSource`), assembles the\n  inclusion proof, and verifies it against his most-work header chain. Unknown tx errors; tampered\n  path or off-chain header is rejected. This is the classic \"get the Merkle proof from a node\" step.\n\n**Honest ceiling:** a complete payment is path-verify **plus one ECDSA signature verify**. The\n**signature** — not hashing, not the path — is the real per-payment ceiling. The in-repo secp256k1\nverifier is a correct reference (unoptimised); production uses the node's audited libsecp256k1 +\nbatch verification + scale-out. Complete signed SPV is bounded by signature verification (a standard,\nscalable cost), with the MF-SPV inclusion path removed from the critical path.\n\n**Mutation testing (06 §4.4 acceptance gate).** `go run ./cmd/mutate` is a\nzero-dependency, offline gate that flips each security-critical comparison/boolean\n(`Fold`, `Verify*`, `VerifyAnchor`, `VerifyBlockInChain`, low-S/`onCurve`, the RT-1\ncarrier gate, the alert evidence gate, `Decide`, value-conservation), runs the\nsuite, and asserts every mutant is **killed** — currently 17/17, score 1.000. The\nexternal `gremlins` path (`.gremlins.yaml`, needs network to install) is also\nprovided.\n\nThe evaluation follows `06_EVALUATION_DESIGN.md` (publication-grade, ACM-artifact\nstandard): known-answer tests against published vectors (double-SHA256, the secp256k1\n2G constant, the RFC 6979 nonce), a differential Merkle oracle over odd cardinalities,\nproperty tests at 10⁵ cases, Monte-Carlo inclusion-forgery (10⁶ trials, 0 accepted,\nClopper–Pearson `p_upper ≤ 4.6×10⁻⁶`), and a scaling-law regression that statistically\nrejects linear-in-T (R²(log)=0.999 vs R²(T)=0.40). `claims.csv` maps every claim ID to\nits falsifying test.\n\nDemonstration output (abridged):\n\n```\nr      T=r*600        depth proofB  subtrees    L1 L2  push pull\n1e+06  600000000      30    960     573         20 10  0    960\n1e+10  6000000000000  43    1376    5722046     20 23  0    1376\n1e+11  60000000000000 46    1472    57220459    20 26  0    1472   \u003c- 100 billion tx/s\nHeader dataset: 4204800 bytes/year (~4.2 MB/yr), constant in r.\n\n== Running at 100 billion tx/s (1e11) — capacity ==\nThis machine: 3.46 M SHA-256d/s/core (software path).\nr=1e+11  seal: 2.00e+11 hashes/s, ~57829 cores @sw / ~2000 cores @SHA-NI | edge proof: 1472 B\nEdge @1e11 (depth 46, 1472 B): 81920 verifies/s/core, 450560 verifies/s on 8 cores (stateless, linear).\nBob decision: accepted=true ...\nAfter double-spend: accepted=false reason=\"double-spend:utxo-spent\" (inclusion still true)\n```\n\n### Scaling to 100 billion tx/s (10¹¹) and beyond\n\nAt 10¹¹ tx/s the inclusion proof is **depth 46 / 1472 bytes** — just **3 hashes\n(96 B) more than 10¹⁰**, and `46 ≪ 255` (the one-byte depth ceiling). 10¹² is\nheadroom at depth 50 / 1600 B. The verifier's cost is logarithmic and **decoupled\nfrom throughput** by construction, so there is no SPV-side ceiling.\n\n\"Running at that level\" means two measurable things, both delivered:\n\n- **Edge (verification fabric):** per-payment verification is ~13.7 µs (depth-46\n  fold) and **stateless / embarrassingly parallel** — aggregate capacity scales\n  linearly with cores (`bench.VerifyThroughput`, `ProfileEdge`). 100 billion tx/s\n  does not raise per-payment cost.\n- **Sealing (Teranode's sharded job):** building the Merkle forest for 10¹¹ tx/s\n  needs **~2×10¹¹ SHA-256d/s network-wide ≈ ~2,000 SHA-NI cores** across\n  ~95,367 subtrees/s — derived, not asserted, by `bench.PlanCapacity` from a measured\n  hash rate. This is exactly Teranode's horizontal-scale model; `r` is bounded by\n  Teranode validation/propagation, not by SPV (Result 4.4).\n\n## How the falsifiable claims are enforced in code\n\n- **R1 (proof +416 B over 1e6→1e10):** `bench.TestR1_ProofGrowth`.\n- **R2 (header dataset constant 4.2 MB/yr):** `bench.TestT7_3_HeaderConstant` / `I-BE3`.\n- **R3 (verify ∝ depth, not T):** `bench.TestT7_4_LogarithmicVerify` measures real fold time.\n- **R4 (push proof bytes = 0):** `bench.TestT7_5_PushVsPull`.\n- **Depth law `depth == ceil(log2 T)`:** integer `commitment.CeilLog2`, asserted in `T1.3`/`T7`.\n- **Frozen core (anti-Utreexo):** `bundle.TestT3_3_FrozenCore` asserts byte-equality across `Reanchor`.\n- **Inclusion ≠ double-spend:** `bundle.TestT3_5` and `walletbob.TestT4_4` — a spent output's proof\n  still verifies but is not accepted.\n- **Absent-period honesty (I-A3):** `accumulator.TestT2_3_GapHonesty` — a height in a gap returns\n  `inGap == true`, never a false \"in chain\".\n- **No keys at till (I-BB2):** `walletbob.StorePrivateKey` always errors; `TestT4_3`.\n\n## Security posture\n\nInclusion soundness reduces to SHA-256d collision/preimage resistance: every\n`Verify` recomputes the path bottom-up and compares to the header's committed root;\nno input but the true sibling set folds to the root. Every adversarial test\n(`adversarial/`) asserts a **rejection** — forged paths, off-chain headers,\nevidence-free alert floods, and orphaned anchors are all refused. The L4 branch is\ngated: `VerifyBlockInChain` is trusted only when `VerifyAnchor` confirms the\naccumulator root is committed in a PoW-sealed generation transaction (I-A2).\n\n### Two honest implementation notes (stated, not hidden)\n\n1. **`03_SCALING_MODEL.md` / `PAPER.md` subtree count for 1e10 was off by one.**\n   The tables printed `5,722,045` (the floor); the *derived* `ceil(6e12 / 2^20)`\n   is `5,722,046` (remainder 942,080 ≠ 0). Per the design's own rule (\"every\n   number is derived; deviations are bugs\"), the code emits the correct value and\n   the two docs were corrected to match. Every other table cell was already exact.\n\n2. **The secp256k1 signer uses `math/big` and is therefore not constant-time.**\n   It is correct (deterministic RFC 6979 nonces, low-S, on-curve checks, round-trip\n   tested) and dependency-free, but side-channel hardening is a production task.\n   The MF-SPV inclusion-soundness claims rest on the Merkle layer, not on the\n   signer; the signer provides the spend authorisation the push protocol needs. For\n   deployment inside Teranode, swap `crypto` for the node's audited secp256k1.\n\nThe `teranode` package ships an in-memory `MockNode` that builds *real* subtree and\nblock Merkle trees and a *real* header accumulator, so the bundle and wallet layers\nare exercised against genuine cryptographic structures. Wiring `ProofSource` /\n`HeaderChain` / `UTXOClient` to a pinned Teranode revision (01_ARCHITECTURE §7\ndependency #2) is the remaining integration step; the interfaces are read-only by\nconstruction (I-TA1).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprof-faustus%2Fmfspv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprof-faustus%2Fmfspv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprof-faustus%2Fmfspv/lists"}