An in-browser implementation of the MTA-QR protocol, served live at mta-qr.peculiarventures.com.
index.html is a single self-contained file generated by build.py from
index.template.html. It inlines three JavaScript bundles — nayuki QR encoder,
noble post-quantum, and the MTA-QR SDK — via placeholder injection. Do not edit
index.html directly; edit the template and run the build.
# Rebuild index.html from source
cd browser-demo && python3 build.py
# View locally (no server required — file:// works)
open browser-demo/index.html
# or
python3 -m http.server 8000 # then visit http://localhost:8000/browser-demo/- Mode 1 (Cached Checkpoint) and Mode 2 (Online Reference) issuance and verification
- Ed25519 and ML-DSA-44 (FIPS 204) issuer signing algorithms
- Tiled Merkle tree (BATCH_SIZE=16, OUTER_MAX_BATCHES=16)
- Auto-rotating credentials (Ticket, Membership) with configurable interval
- Tamper panel to exercise all verification failure paths
- Offline simulation — cache hits work without network, cache misses show the fetch that would happen in a real deployment
Chrome 113+, Firefox 130+, Safari 17+ (requires Ed25519 Web Crypto support)
- nayuki-qr-code-generator 1.8.0 (
deps/nayuki_qr.js, MIT) — QR rendering - @noble/post-quantum 0.5.4 (
deps/noble_pq.iife.js, MIT) — ML-DSA-44 - mta_qr_sdk.iife.js (
deps/mta_qr_sdk.iife.js) — compiled fromts/sdk/src/browser-bundle.tsby esbuild; rebuilt by CI on every push. The committed copy is a convenience snapshot. - Web Crypto API — Ed25519 signing and verification, SHA-256
ts/sdk/src/browser-bundle.ts
│
└── esbuild ──► deps/mta_qr_sdk.iife.js (6.5 KB minified)
index.template.html ──┐
deps/nayuki_qr.js ──┤
deps/noble_pq.iife.js──┤── build.py ──► index.html (~150 KB)
deps/mta_qr_sdk.iife.js┘
build.py replaces /* {{MTA_QR_SDK}} */ and equivalent placeholders in
the template with the contents of each dependency file.
The demo uses the tiled payload format with two proof bytes:
version(1) | flags(1) | originId(8) | treeSize(8) | entryIndex(8)
proofCount(1) | innerProofCount(1) | proof[proofCount×32]
tbsLen(2) | tbs
innerProofCount splits the proof array into inner (batch-level) and outer
(parent tree) segments. Mode 2 payloads set proofCount=0.
This demo is built on ts/sdk/, the standalone TypeScript SDK. The same
Issuer and Verifier classes used here are tested in the 96-cell cross-language
interop matrix against Go, Rust, and Java. Payloads produced by the browser
demo verify correctly in any of the four SDK verifiers, and vice versa.
The demo uses bound mode (no origin string embedded in the payload) as a deliberate simplification — the trust configuration is held in-page rather than distributed separately. The SDK issuers default to self-describing mode (origin embedded), which is the correct choice for real deployments where verifiers load trust configs independently.