tinylayer

[==]

[========]

smallest BIP448 statechain we can explain

GitHub repository

Tinylayer is a Mutinynet-only Layer 2 for transferring ownership of one Bitcoin UTXO off chain. A rollback-protected Enclavia workload chooses one successor; BIP448 lets the accepted latest state replace any stale state on chain without another signature.

Bitcoin / Mutinynet
    funding UTXO
         │
         │ N private ownership transfers
         ▼
client ↔ Enclavia
         │
         │ unilateral close
         ▼
latest BIP448 update → 12-block contest → owner settlement

The complete wire and transaction rules are in the protocol specification.

Why this is a Layer 2

Alice can transfer to Bob, Bob to Carol, and so on without broadcasting a transaction. Mutinynet normally sees only funding and the final exit sequence. Every receiver gets an encrypted history and a fully signed latest update.

After Carol accepts, Enclavia can disappear. If Alice publishes an old state, Carol changes only her update’s prevout, keeps both signature bytes unchanged, and spends Alice’s state before its delayed settlement matures.

That is the eltoo/LN-Symmetry latest-state mechanism applied to a statechain. Enclavia remains necessary for a different problem: refusing two sibling successors from the same owner.

The deliberately small design

Protocol 2 uses:

This makes every exit a recognizable Taproot script-path close. Funding and all cooperative ownership transfers remain hidden until then.

Read the complete signer

The rollback-protected signing state machine is about 254 lines. Its Bitcoin-opaque HTTP workload brings the complete production enclave Rust to 300 lines.

The website renders the exact compiled source rather than maintaining a second handwritten copy:

Components

Crate Responsibility Guide
enclave Global BIP340 template signer, capability CAS, exact retry Enclave guide
client BIP446 hash, Taproot trees, updates, rebinding, settlement, attested transport Client guide
wallet-core Encrypted state and encrypted transfer package Wallet core guide
wallet Mutinynet-only CLI, explorer checks, P2A packages, state monitoring Wallet guide

Mutinynet prerequisites

Mutinynet’s custom Bitcoin Inquisition build includes the BIP448 opcodes. The TEMPLATEHASH activation signal was mined in Mutinynet block 3,108,700. Before using funds, the deployment node must report both templatehash and checksigfromstack active through getdeploymentinfo.

The reference wallet defaults to https://mutinynet.com/api for chain reads and package submission. The Enclavia workload never parses a transaction or contacts a Bitcoin service. Public activation admission and rate limiting must be enforced outside the enclave.

Build and test

cargo build --locked --workspace --all-features
cargo test --locked --workspace --all-features

The tests pin the official BIP446 vector, prove prevout rebinding, reject transaction mutations and sibling transitions, exercise idempotent opaque activation, and run a complete CLI Alice-to-Bob transfer against local servers.

CLI walkthrough

Set a password non-interactively for the examples:

export ENCLAVIA_WALLET_PASSWORD='replace this'

Initialize Alice:

tinylayer-wallet --data-dir alice init \
  --enclave-url wss://<deployment>.enclavia.io \
  --pcr0 <96-hex> --pcr1 <96-hex> --pcr2 <96-hex>

Prepare a 100,000-sat coin without allocating enclave state:

tinylayer-wallet --data-dir alice coin new --amount-sat 100000

Send exactly that amount from the Mutinynet faucet to the returned address. After confirmation, bind the output:

tinylayer-wallet --data-dir alice coin bind --outpoint <txid>:<vout>

The coin is still absent from Enclavia. Its committed bootstrap update is enough for Alice to exit.

Bob creates a request:

tinylayer-wallet --data-dir bob init \
  --enclave-url wss://<deployment>.enclavia.io \
  --pcr0 <96-hex> --pcr1 <96-hex> --pcr2 <96-hex>

tinylayer-wallet --data-dir bob transfer request --output bob-request.json

Alice performs the first lazy activation and transfer:

tinylayer-wallet --data-dir alice transfer send \
  --request bob-request.json \
  --output bob-package.json

Bob verifies and accepts:

tinylayer-wallet --data-dir bob transfer receive \
  --request bob-request.json \
  --package bob-package.json

Before exit, fund Bob’s fee address shown by:

tinylayer-wallet --data-dir bob fee-address

Then publish the latest update:

tinylayer-wallet --data-dir bob exit --destination <mutinynet-address>

Run the same command after the update has 12 confirmations to broadcast the settlement.

See the wallet guide for stale-state defense, local debug mode, and the complete command lifecycle.

What this proves

The public demonstration is complete when it links Mutinynet transactions for:

fund coin
Alice → Bob → Carol off chain
stop Enclavia
publish Alice's stale bootstrap state
rebind Carol's already-signed update to Alice's output
confirm Carol's update without new signatures
wait 12 blocks
settle to Carol

Live Mutinynet proof

Bootstrap-state replacement

Step Transaction
Funding d2a5b0f8…d5f2b
Alice stale U1 cbb573fe…c2bbf
U1 P2A child 94984ba1…2c25a
Carol rebound U3 dd9565bd…8ebe1
U3 P2A child 3c116cdc…7a76c
Carol settlement de85499e…98c9f

Alice transferred state 2 to Bob and Bob transferred state 3 to Carol entirely off chain. The signer was stopped before Alice’s state confirmed. Carol’s already-signed U3 then spent U1:0; no new client or Enclavia signature was created. After 12 confirmations, Carol’s CSV settlement confirmed at Mutinynet height 3,366,659.

Fully signed state replacement

A second coin demonstrated the stronger U2 → U3 case:

Step Transaction
Funding 0ad7d83b…cc634
Bob stale signed U2 c9e12daa…1cfff
U2 P2A child f09b5ddd…7e985
Carol rebound U3 be7a747c…9b9ac
U3 P2A child 68dbdcce…95f42
Carol settlement b75bc489…b1e63

The signer was stopped before Bob published his fully client-and-Enclavia-signed state 2. U2 revealed the funding live-update leaf. Carol then spent U2:0 with her already-signed state 3, revealing state 2’s L2+1 CLTV update leaf. No signature was created after the signer stopped. Carol’s settlement confirmed at Mutinynet height 3,366,720.

This is an experiment, not a production wallet or a mainnet protocol.

Security reports follow SECURITY.md. Contributions follow CONTRIBUTING.md. The project is MIT licensed.