Skip to content
ciphernomPublic

About

experimental confidential-transaction chain: hidden amounts, stealth payments, view keys to share your balance for audits or compliance, and post-quantum coin recovery

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Latest commit

 

History

124 Commits

Folders and files

Repository files navigation

midwimble

A privacy chain built from midstate's networking and consensus plus pluribit's MimbleWimble transactions, with receiver-only spend authority. It is merge-mineable with midstate, and anchored to midstate for post-quantum disaster recovery.

Status: devnet-quality research code. Not audited. Do not use for real value.

About 23k lines of Rust. See docs/ANCHORING.md for the anchoring and recovery design.

What came from where

Area Source Notes
core/finality.rs, core/extension.rs, core/wots_simd.rs midstate verbatim
core/mmr.rs, core/simd_mining.rs midstate plus marked additions (MMR prefix truncation, multi-seed SIMD verification)
core/wots.rs, core/mss.rs midstate key-reuse punishment section dropped; MSS checkpoint file keyed by seed (see Upstream bug)
core/gpu_mining.rs midstate wgpu 30 fix and opt-in software adapters (for testing only)
network/amino.rs midstate verbatim except the rendezvous label
network/*, core/state.rs, core/types.rs, core/filter.rs midstate MW payloads, /midwimble/* protocol ids, no activation heights
sync.rs, node.rs, mempool.rs, storage.rs, miner.rs, pool.rs midstate (design) re-implemented around the MW core
core/mw/* pluribit hardened, with the ownership fix
core/auxpow.rs, merge_mine.rs new merged mining with unmodified midstate nodes
core/anchor.rs, core/recovery.rs, anchor.rs new anchoring and dormant post-quantum recovery
core/snapshot.rs, finality.rs new anchored pruning: finalized checkpoints, snapshots, checkpoint sync
wallet/, rpc.rs, bin/main.rs new pluribit-style wallet, midstate-style RPC

Design summary

Consensus (midstate)

  • Proof of work: sequential BLAKE3 (H^N(H(header ‖ nonce)), N = 1,000,000) below WALK_ACTIVATION_HEIGHT (86,400), then Midstate Walk (core/walk.rs, shared with midstate), a CPU-friendly walk over a 256 KiB scratchpad, natively and merged. Relayed and anchored midstate headers follow midstate's own switch at its height 420,000 (MIDSTATE_WALK_ACTIVATION_HEIGHT, which must match midstate's).
  • Difficulty and time: ASERT with a 4-hour half-life and a 60-second target. Timestamps must beat the median of the last 11 blocks and may be at most 15 minutes ahead.
  • Fork choice: cumulative work, less what two caps withhold, tie-broken by the lower midstate. Each bond's blocks count in full up to its share of the day (four blocks once 360 bonds are eligible), and no block counts for more than a quarter above the lowest of the week before it (docs/BONDED_POW.md). Each header claims its chain's weight under its proof of work, so sync compares chains by it too. A block must be signed whenever a registered bond could sign it; while none can (before the first registration), an unsigned block counts for 1/1,024 of its work.
  • State root: covers the UTXO set, the kernel set, the chain MMR, the running excess sum, the total offset, the supply, the bond set and the midstate relay.

Emission (core/types.rs, docs/LAUNCH.md)

  • Supply: at most 1,000,000.00000000 coins (8 decimals). The schedule reaches that exactly at about block 49.7 million (~95 years), but it is a ceiling rather than a promise: a block whose signer is over its per-bond cap mints less than the schedule allows and the difference is burned, so the chain's supply parts from the curve and its final total settles below the cap (see Over-cap taper).
  • Slow start: the reward ramps linearly over the first 30 days, so the blocks mined while the network is small and least known are worth little.
  • Halvings: 0.23932616 per block in era 0, halving every 2,100,000 blocks, the same wall-clock era as Bitcoin's. ASERT's genesis anchoring keeps the halving dates predictable to within a day or two.
  • Over-cap taper: from the mainnet switch, a bond that has signed n of the last 1,440 blocks against a cap of cap mints only reward x cap / n of a block's subsidy, rounded down; fees are always paid in full. What the taper withholds is never minted by anyone -- it is a burn, not a redistribution -- so earning the whole reward means spreading hashrate over enough bonds, and the capital locked grows with the hashrate it covers. It is the same n > cap test that already drops an over-cap block's fork-choice weight to 1/1024 of its work, so pay and weight agree.
  • Checkable anywhere: the schedule is defined by its running total, so any node can check that a supply claimed at any height is one the schedule could have produced -- never above it, and below it by whatever has been burned; checkpoint-synced nodes check the snapshot they start from. The Pedersen audit ties the figure to the coins that actually exist.
  • After the cap: a block pays only its fees, and a block with none carries no coinbase.

Transactions (pluribit, hardened)

  • Commitments: Pedersen commitments on Ristretto255 with aggregated Bulletproofs, padded to a power of two and bound to their outputs' metadata.

  • Stealth outputs: each carries a one-time owner key Ko = H(t)·G + B, so only the recipient can spend.

  • Balance rules:

    Pedersen:  Σ C_out − Σ C_in + fee·G = Σ E + o·H
    Owner:     Σ Ko_in              = Σ E' + x·G
    Coinbase:  Σ C_cb − (subsidy + fees)·G = E_cb
    
  • Further rules:

    • Kernel ids are unique across the chain (replay protection).
    • Coinbase outputs mature after 100 blocks.
    • Blocks list everything in canonical order.
    • A supply audit is available on any node.

Merged mining with midstate (core/auxpow.rs)

  • Commitment: a miner puts H(NETWORK_MAGIC, midwimble mining hash) in the salt of the last output of a midstate coinbase. Midstate's own /block_template computes the state root, so midstate needs no change.
  • Acceptance: a midwimble block whose work is in such a midstate block is valid when the midstate block meets midwimble's target.
  • Proof size: usually about 220 bytes. Proofs are checked during header sync in the same SIMD batches as native blocks.
  • Safety check: the miner refuses to hash unless its reconstruction of midstate's fold reproduces the midstate node's mining hash exactly.

Pool (pool.rs, after midstate's provably fair design)

  • Payouts (PPLNS): every block pays the newest shares worth two blocks, directly in its coinbase. Miners entitled to at least 1/31 of the block are paid exactly; smaller ones share the remaining outputs by systematic sampling, so everyone's expected payout is exactly their share and splitting work across addresses gains nothing. Nothing is deducted, so there is nothing to settle or restore after a reorganisation.
  • Commitment: every job commits the window it pays and the window it freezes for the next tip (in the coinbase extra field). The sampling is seeded by the block the job builds on, and a job on a new tip must pay the window miners saw frozen on the previous one, so the pool cannot steer it, short of holding a new tip back until it has seen the next block. A miner run with --node <own node's RPC> refuses jobs for a height its own node passed more than 15 s earlier, which is how such a delay shows.
  • Ownership: each miner hashes its own copy of the job, whose extra binds the commitment to the miner's address and which the node re-signs under the pool's bond (/mining/bind). Work found on one miner's copy is worthless to anyone else, so shares cannot be stolen, even by a man in the middle. A block with nothing to pay (no reward and no fees, after issuance ends) has no coinbase to bind, so work on it is credited to nobody.
  • Miner audit: before hashing, a miner checks the template hash, the coinbase total for the claimed height, that the job is bound to its own address and to the published windows, that every share the pool accepted from it is counted, and, with its wallet's view key, that the coinbase pays it exactly what the rule gives it, in outputs it can claim.
  • Privacy: the window names owners by a hash of their address, and the pool publishes nothing that links a coinbase output to anyone. The view key stays with the miner; it sees payments but cannot spend them.
  • Spot checks: every window commits to each share, ordered by its proof of work's output. Each miner picks random points of each window it is paid from (four by default, --spot-checks), weighted by weight, and has the pool prove the share covering each and the job it was mined on, then recomputes that share's proof of work on its owner's own copy of the job. Weight nobody mined, or real work counted twice, fails a check that lands on it.
  • TLS: pool --stratum-tls 0.0.0.0:3334 --tls-cert cert.pem --tls-key key.pem adds a TLS listener and prints the certificate's SHA-256; miners connect to stratum+tls://host:3334, pinning a self-signed certificate with --tls-pin <sha256> or relying on a web root authority otherwise.
  • Verification: each connection's difficulty aims at one share per 15 s, with shares weighted by difficulty. Shares queue rather than being dropped; connections that have proven work are verified first, in SIMD batches; an invalid share bans its sender's address; connections and message sizes are capped.

Anchoring and post-quantum recovery (docs/ANCHORING.md)

Anchoring. A checkpoint (height, header, state root, work, previous checkpoint) is anchored in midstate without changing midstate, in one of two ways:

  • as an ordinary Commit transaction, with midstate's commit proof of work;
  • for free, through a merged-mined parent block.

Evidence (the fold proof plus confirmations) is verified SPV-style and stored on the midwimble side.

Recovery commitments. Every output carries

rc = H(R, value, blinding, salt)
  • R is the recipient's midstate-style MSS key, which is part of the v1 address.
  • salt comes from the stealth shared secret.
  • Because rc fixes the commitment's opening while the commitment is still binding, a later recovery can pin the value even after a discrete-log break.

Recovery epoch (dormant). A future hard fork activates it at an anchored checkpoint.

  • Claims: accepted only with an SMT proof of the UTXO leaf, the frozen opening, and an MSS signature.
  • Limits: each MSS leaf is used once, each output is claimed once, and the total is capped at the checkpoint's supply.
  • No elliptic curves: elliptic-curve keys are never consulted.

Anchored pruning (docs/PRUNING.md)

MimbleWimble cut-through cannot coexist with one-sided ownership: removing a spent output would remove the owner key and signature the rules depend on. Midstate anchors serve as the horizon instead.

  • Finalized checkpoints. A checkpoint counts once its Midstate evidence is deep enough, it describes this node's chain, the tip is far enough past it, and no conflicting anchored checkpoint is known.
  • Floor. No reorg below it, whatever the competing chain's work.
  • Pruning. Block bodies below the floor can be deleted. Headers, kernels (with signatures), UTXO records and range proofs stay.
  • Grouped proofs keep aggregation. A spent output shrinks to its commitment and metadata hash, which is all its group's Bulletproof needs. A group is deleted once all its outputs are spent.
  • UTXO records commit to their whole output, so a snapshot cannot alter scanning data.
  • Wallets restoring from a pruned node scan the unspent-output set (GET /utxos) instead of block bodies.

Networking (midstate)

  • Transports: TCP and QUIC (WebRTC-direct for browser wallets behind a feature), with Noise and Yamux.
  • Discovery and reachability: Kademlia on a private protocol id, identify, relay, DCUtR hole punching, AutoNAT, peer exchange, and the IPFS-DHT rendezvous.
  • Limits: connection caps per /24 subnet and on inbound peers.
  • Address book: an address is saved only once this node has dialled it and the peer there has identified itself as a midwimble node. Midstate's nodes share our transports and often our machines; one is dropped as soon as it identifies, forgotten, and not dialled or let in for a day. Addresses heard in peer exchange are tried and dropped at their first failure; saved ones survive a few; the operator's --peers are redialled whenever they are not connected.
  • Bans end: an hour at first, twice as long for each further ban of the same peer, up to a day. /state lists the peers banned now, and why.
  • Light clients: a light-client protocol with a reputation-based rate limiter. Wallets read each block's scan data (src/core/scan.rs: its outputs' ephemeral keys and view tags and its inputs' prefixes, about 100 bytes) rather than the block, fetch the few blocks that concern them from any node, checked against it, and learn from a node the WebRTC addresses of the nodes connected to it.
  • Dandelion++: expired stem transactions are aggregated before fluffing.
  • Sync:
    • headers first, with SIMD proof-of-work checks, comparing chains by the weight fork choice uses;
    • while a session is only fetching and checking a peer's headers, the node keeps taking blocks and mining; it stops only to download a chain whose verified headers outweigh its own;
    • a claimed heavier chain has to be backed: a peer whose headers fall short of its claim, or that goes quiet before they reach it, is struck and barred for a while (longer each time) and banned at the third strike, and one that answers a sync request with anything else is banned at once. A peer that goes quiet after its headers have backed its claim is only paused: a slow seed is not a liar. Peers this node dialed are preferred to peers that dialed it;
    • blocks downloaded from several peers at once, with resume from verified headers after a restart;
    • reorgs committed atomically;
    • fork states rebuilt from on-disk undo records.
  • Storage: incremental redb tables, with group and kernel bookkeeping for pruning. The state is checked against the tip header on load.
  • Sync modes: full verification from genesis (default), or checkpoint verification from a trusted checkpoint id (--checkpoint), which verifies a snapshot and its Midstate anchor before validating everything after it in full.

Build and test

cargo build --release                                  # node, wallet, pool, merged miner, anchoring
cargo build --release --features gpu                   # + midstate's wgpu miner
cargo test --features fast-mining                      # 190 unit, 16 integration, 11 doc tests
cargo test --lib                                       # production constants (165 tests)
cargo test --no-default-features --features fast-mining --lib   # core only (159 tests)

fast-mining makes proof of work trivial, moves genesis to 2023, sets coinbase maturity to 3 and skips the slow start. Never ship a binary built with it. midwimble params prints a build's launch parameters, emission calendar and genesis block id; a build whose launch parameters are still placeholders says so there and at node startup. Release builds have not been compiled in this environment.

The integration tests run real nodes on localhost:

Test What it shows
network (15; 16 with webrtc) gossip sync and a Dandelion++ payment; shallow and deep reorgs; late-joiner sync with restart; resumed sync; multi-peer download; forged-block and lying peers banned; bans that end and grow; a slow seed waited for, not banned; midstate-style foreign peers kept out; --peers redialled until they are back
merge_mining (1) one search mines both chains against a midstate stand-in built from midstate's own types; merged-mining anchors recorded and verified; a second node syncs the merged-mined chain
pool (1) two auditing miners paid in coinbases; fee to the operator; supply audit holds
quantum_recovery (3) an attacker holding every elliptic-curve secret cannot claim anchored coins while owners can; a genuinely broken commitment binding still cannot inflate a claim; anchoring round trip with chained checkpoints and tamper detection
pruning (3) an anchored checkpoint finalizes, bodies are pruned and a new node bootstraps from the snapshot to the same state root; a heavier chain cannot reorganise below the floor; a wallet restores from a pruned node

GPU. midwimble gpu-info runs midstate's shader self-test. It was verified here on Mesa llvmpipe (software Vulkan), including chains split across many dispatches, via MIDWIMBLE_GPU_ALLOW_SOFTWARE=1. It has not been tested on real GPU hardware.

Usage

export MIDWIMBLE_PASSWORD=...
midwimble wallet --wallet w.mww create            # prints a v1 address + 24 words (recovery key: ~seconds to a minute)
midwimble wallet --wallet w.mww phrase            # prints the 24 words again
midwimble node --data-dir ./node --mine-to <address> [--backend gpu] [--prune]
midwimble node --data-dir ./node --checkpoint <checkpoint id>   # checkpoint verification
midwimble wallet --wallet w.mww balance           # incoming: payments to it still waiting for a block
midwimble wallet --wallet w.mww sync              # what changed: payments received and confirmed, reorgs
midwimble wallet --wallet w.mww send --to <address> --amount 0.25   # amounts in coins
midwimble wallet --wallet w.mww cancel --tx <hash>                  # release a payment that will never confirm
midwimble wallet --wallet w.mww rescan [--from <height>]            # scan again; starts over on a relaunched network
midwimble bond new --file bond.json              # mining requires a bond: docs/BONDED_POW.md
midwimble node --mining-bond bond.json --mine-to <address>
python3 scripts/rehearse.py --midstate-rpc 127.0.0.1:8545   # full rehearsal: docs/REHEARSAL.md
python3 scripts/join_testnet.py [--mine]                    # join the network (mainnet from 31 Oct): docs/TESTNET.md

# merged mining against a midstate node
midwimble merge-mine --midstate-rpc 127.0.0.1:8545 --midstate-address <hex> \
    --midwimble-address <address> --anchor-store anchors.jsonl

# pool and pool miners
midwimble pool --address <operator address> --stratum 0.0.0.0:3333 --api 0.0.0.0:8081
MIDWIMBLE_VIEW_KEY="$(midwimble wallet view-key)" \
    midwimble pool-mine --pool stratum+tcp://host:3333   # the view key never leaves the miner
midwimble pool-mine --pool stratum+tls://host:3334 --tls-pin <sha256> --node 127.0.0.1:9434

# anchoring checkpoints in midstate
midwimble anchor --midstate-rpc 127.0.0.1:8545 --depth 6
midwimble anchor-verify --depth 6

Browser wallet. web-wallet/ is the wallet compiled to WebAssembly, with a page in the explorer's style: create, restore or open a .mww file, send, receive, history. It reaches nodes built with --features webrtc through the light protocol, three at a time, follows the chain by its scan data, and shares the CLI's phrases, addresses and wallet file format. See web-wallet/README.md and docs/TESTNET.md.

RPC. The node serves these endpoints on loopback, with no authentication:

  • GET /state
  • GET /blocks/{start}/{count}
  • GET /headers/{start}/{count}
  • GET /utxo/{commitment}
  • GET /mempool
  • POST /mempool/txs (those transactions, for wallets to see payments before a block confirms them)
  • POST /tx
  • POST /mining
  • POST /mining/template (weighted payouts, extra, receipts)
  • POST /mining/bind (copies of a template with their own extra, re-signed, one per pool miner)
  • POST /mining/submit
  • POST /peers
  • GET /utxos (unspent outputs, for wallets on pruned nodes)
  • GET /anchors, POST /anchors
  • GET /finality

It also serves the block explorer (/, /explorer/...) for the machine it runs on. The RPC answers only requests addressed to an IP address, localhost, or a name given with --rpc-allow-host (a proxy's or container network's name for the node), so a web page cannot reach it by pointing a domain of its own at 127.0.0.1. To publish the explorer, serve it on a listener of its own, which has nothing on it that changes the node: --explorer 0.0.0.0:9435. Never publish the RPC port: anyone who can reach it can redirect the node's mining rewards.

Upstream bug found in midstate

mss::keygen resumes from mss_h{height}.checkpoint whatever seed wrote it. If a generation is interrupted and a different seed later generates a key of the same height in that directory, the new key loads the old leaves. Its tree then no longer matches its seed, and signatures from those leaves fail to verify. The vendored copy keys the file by a seed fingerprint.

Before any real launch

  • Emission schedule, supply cap and decimals (core/types.rs).
  • Run scripts/set_launch_params.py on launch day: network magic, a Bitcoin anchor mined after the code freeze, the genesis time, and a genesis target calibrated from midstate's live target (docs/LAUNCH.md). Done for the testnet (16 October 2026), which becomes mainnet in place when its early phase ends on 31 October 2026 (docs/TESTNET.md).
  • Get a cryptographic review of:
    • the ownership scheme (owner sum, kernel AND-proof, transcript binding);
    • the merged-mining proof;
    • the recovery commitments.
  • Anchor evidence: 1,000 midstate confirmations, each header worth at least 2^19 attempts (finality.rs). Forging costs about an hour of midstate's whole network, with room for its difficulty to fall eightfold.
  • Finality depth: 100 midwimble blocks, fixed. It is a reorg floor, so it must be identical everywhere; core/finality.rs's estimator advises wallets instead.
  • Anchoring cadence: about every 10,000 blocks (a week). Archival nodes assumed; pruning stays off (docs/ANCHORING.md).
  • EXTENSION_ITERATIONS stays 1,000,000: midstate compatibility, and so merged mining.
  • Midstate Walk: confirm WALK_ACTIVATION_HEIGHT (expected a few hours before midstate's switch, so this chain stops taking GPU-friendly work first), WALK_TARGET_SHIFT, and that MIDSTATE_WALK_ACTIVATION_HEIGHT and MIDSTATE_WALK_TARGET_SHIFT equal midstate's release. Merged mining pauses between the two switches; the merge miner and pools mine midstate alone meanwhile.
  • Consensus encodings pinned: block hashes cover bincode 1 encodings, so bincode is pinned to =1.3.3, and core/golden.rs and the protocol tests hold vectors for every hashed encoding and the wire format. Build releases with --locked.
  • Rehearse against a real midstate node: bonded mining and merged mining (scripts/rehearse.py, docs/REHEARSAL.md).
  • Run the public testnet (docs/TESTNET.md): publish scripts/testnet.json, run a seed, and get a midstate pool merge-mining it.
  • Before 31 October 2026: every node on a build with the early phase, mainnet bonds registered ahead of the switch, and a checkpoint anchored after it (docs/TESTNET.md, "The switch").

Known limitations

  • Not post-quantum in normal operation. Anchoring plus recovery commitments make a recovery possible after a curve break, but the recovery epoch is a future hard fork and is not wired into the node.
  • Recovery commitments are written by senders. Wallets flag bad ones (unrecoverable_coins); consensus cannot check them without heavy zero-knowledge proofs.
  • Anchor verification is SPV-level. Cross-check with a trusted midstate node where that matters. Everything midstate-facing has been tested against a stand-in built from midstate's source, not a live midstate node.
  • Pruned nodes cannot serve history. A network needs archive nodes for new full-verification peers; checkpoint-synced nodes also cannot serve headers below their snapshot.
  • Conflicting anchors stop finalization rather than resolving by "earliest anchored wins".
  • Full verification does not use snapshots yet; it downloads every block.
  • Wallets restored from a pruned node lose outgoing history (they see only unspent outputs).
  • Staged reorgs are held in memory (at most 1,000 blocks), and startup scans the UTXO set once.
  • Linked outputs: outputs in one range-proof group are visibly linked (the cost of keeping aggregation; one proof per output would remove it).
  • Pool: a coinbase pays at most 31 miners, so miners with less than 1/31 of a block are paid by sampling: exactly their share on average, but in fewer, larger payouts. The WebRTC browser pool from midstate is not ported.
  • Wallet: the CLI records its payments (and keeps the browser wallet's) but has no history command (the browser wallet shows them), and the password prompt echoes (use MIDWIMBLE_PASSWORD).

Licence

GPL-3.0-or-later (see LICENSE), matching midstate and pluribit.

About

experimental confidential-transaction chain: hidden amounts, stealth payments, view keys to share your balance for audits or compliance, and post-quantum coin recovery

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages