Skip to content

erenyegit/qmdb-visualizer

Repository files navigation

QMDB Proof Visualizer

An interactive, browser-based visualization of Commonware's QMDB — the authenticated state database powered by a Merkle Mountain Range. Watch operations append in real time, generate cryptographic inclusion proofs, and tamper with hashes to see the proof break.

Every byte is hashed with real SHA-256 in your browser. No mocks, no backend, no fake hashes.

Built as a learning aid for the Commonware blog post on MMRs. If you've ever wondered how an append-only authenticated log actually grows, or why you can't forge an inclusion proof — this shows you, click by click.


Demo

QMDB Proof Visualizer screenshot

Replace this image with your own screenshot — see the Screenshots section below.


What this is

A single-page React app that implements the canonical MMR algorithm exactly as Commonware describes it:

  1. Append-only: every operation becomes a new leaf at the next position. No existing node is ever modified.
  2. Mountain merging: when the last two peaks have equal height, they merge into a parent. Repeat until heights are strictly decreasing.
  3. Root commitment: the root hash is SHA-256( totalNodes (u64 LE) ‖ peak[0] ‖ peak[1] ‖ … ), peaks ordered largest mountain to smallest.
  4. Inclusion proofs: a proof for any historical leaf is the sibling hashes from leaf to peak, plus all other peak hashes — logarithmic in the log size.

The visualizer lets you do all of this interactively and watch what happens.


Features

  • Live MMR construction — assign or delete keys and watch the tree grow with smooth D3 transitions.
  • Real cryptographycrypto.subtle.digest('SHA-256', …) via Web Crypto API. The leaf hash format is SHA-256( location(u64 LE) ‖ key ‖ value ), the parent hash is SHA-256( left ‖ right ). No shortcuts.
  • Auto-seed mode — toggle on to append a random key/value every 1.5s; great for watching mountains form.
  • History scrubber — every operation snapshots the full state (deep-cloned). Drag the slider to replay the MMR at any point in time.
  • One-click proof generation — click any operation in the log and the inclusion proof lights up:
    • leaf-to-peak path in yellow
    • sibling hashes in orange
    • other peaks in blue
  • Tamper Mode — every hash in the proof becomes editable hex. Change one character; the recomputed root instantly diverges from the MMR root and the proof flips to INVALID. The cryptographic guarantee, made tangible.
  • Educational tooltips on every key concept (MMR, root hash, proof path, tamper mode).
  • 100% client-side — no backend, no API calls, works offline once loaded.

Tech stack

Layer Choice
UI React 18 + TypeScript
Build Vite 5
Styling Tailwind CSS (via PostCSS)
Tree rendering D3.js v7 (React-controlled SVG, D3 owns node/edge updates)
Hashing Web Crypto API (SubtleCrypto.digest) — no third-party crypto libraries
Bundle ~205 KB JS / ~14 KB CSS (~67 KB gzipped total)

Quick start

git clone https://github.com/<your-username>/qmdb-visualizer.git
cd qmdb-visualizer
npm install
npm run dev

Open http://localhost:5173 and start clicking.

Production build

npm run build       # outputs to dist/
npm run preview     # serve dist/ locally to verify

The output is a static bundle — drop dist/ on Vercel, Netlify, GitHub Pages, Cloudflare Pages, or any static host.


How it works

The append algorithm

Given an existing MMR with nodes, peaks, and totalNodes, appending an operation (key, value) works like this:

const location   = operationLog.length;
const leafPos    = nodes.length;
const leafHash   = SHA-256( u64_le(location) || key || value );

nodes.push({ position: leafPos, hash: leafHash, height: 0 });
peaks.push(leafPos);

while (peaks.length >= 2) {
  const right = nodes[peaks[peaks.length - 1]];
  const left  = nodes[peaks[peaks.length - 2]];
  if (left.height !== right.height) break;

  const parentHash = SHA-256( left.hash || right.hash );
  const parentPos  = nodes.length;
  nodes.push({ position: parentPos, hash: parentHash, height: left.height + 1, leftChild: left.position, rightChild: right.position });
  peaks.pop(); peaks.pop();
  peaks.push(parentPos);
}

const root = SHA-256( u64_le(totalNodes) || peaks.map(p => nodes[p].hash).join() );

Each leaf gets a globally unique position (assigned in insertion order, including internal nodes). Peaks are stored in largest-first order, which is also the order they get bagged into the root.

Generating a proof

For any leaf at position P:

  1. Walk up via parent pointers; at each step record the sibling's hash.
  2. Identify which peak the leaf belongs to.
  3. Return: siblings[] (with direction flags), otherPeaks[] (in canonical order), and peakIndex (where the leaf's peak sits among all peaks).

Verifying a proof

  1. Reconstruct the leaf's peak by hashing leaf with each sibling at each level (respecting the left/right direction).
  2. Insert the reconstructed peak into the peakIndex slot, fill the rest from otherPeaks.
  3. Bag with totalNodes and compare against the expected root.

This is exactly what Tamper Mode re-runs on every keystroke.

See src/mmr/MMR.ts and src/mmr/proof.ts for the actual implementation — it's about 200 LOC total.


Project structure

qmdb-visualizer/
├── index.html
├── package.json
├── vite.config.ts
├── tailwind.config.js
└── src/
    ├── main.tsx
    ├── App.tsx                     # state orchestration, snapshot history, auto-seed
    ├── mmr/
    │   ├── types.ts                # MMRNode, MMRState, InclusionProof
    │   ├── MMR.ts                  # hashing, append, snapshot cloning
    │   └── proof.ts                # generation + verification
    ├── components/
    │   ├── Controls.tsx            # input row + history slider
    │   ├── LogPanel.tsx            # operation log (left)
    │   ├── MMRTree.tsx             # D3 SVG tree (center)
    │   └── ProofPanel.tsx          # proof inspector + tamper mode (right)
    └── styles/
        └── globals.css

Screenshots

Place your own screenshots in docs/ and reference them here. Suggested shots:

  • docs/screenshot-tree.png — a 7–10 op MMR with multiple mountains visible
  • docs/screenshot-proof.png — a proof selected, yellow/orange/blue highlight visible
  • docs/screenshot-tamper.png — Tamper Mode on, INVALID badge red
![Tree](docs/screenshot-tree.png)
![Proof](docs/screenshot-proof.png)
![Tamper](docs/screenshot-tamper.png)

Credits & inspiration

This project is independent and not affiliated with Commonware. It's a community-built educational tool.


Contributing

Issues and PRs welcome. Some ideas:

  • Performance proofs / batch proofs
  • Range proofs over a contiguous slice of leaves
  • A "verifier-only" mode that takes a JSON proof and a root and verifies offline
  • Export / import operation logs as JSON
  • Streaming append from a remote source

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors