git mark
Anchor git commits to Bitcoin via blocktrails key chaining.
Install
npm install -g gitmark
This gives you git mark as a native git subcommand.
Quick Start
# Initialize in a git repo (tbtc4 = Bitcoin testnet4)
git mark init --chain tbtc4 --voucher txo:tbtc4:txid:vout?amount=X&key=Y
# Or read vouchers from a file (uses last line, removes on success)
git mark init --voucher ~/faucet/vouchers.txt
# Make commits, then mark them
git commit -m "my change"
git mark
# Verify the trail against Bitcoin
git mark verify
# Show trail state
git mark info
Chains
Pick one with --chain at git mark init. It's recorded in blocktrails.json and used for every later mark.
| Chain | Network | Addresses | Explorer API |
|---|---|---|---|
tbtc4 (default) |
Bitcoin testnet4 | tb1p… |
mempool.space/testnet4 |
tbtc3 |
Bitcoin testnet3 | tb1p… |
mempool.space/testnet |
signet |
Bitcoin signet | tb1p… |
mempool.space/signet |
btc |
Bitcoin | bc1p… |
mempool.space |
xbt |
BLAKE2b fork of Bitcoin, from block 961,640 | bc1p… |
mempool.kilombino.com |
txbt4 |
BLAKE2b fork of testnet4, from block 150,308 | tb1p… |
mempool.guide/testnet4 |
On xbt and txbt4, marks are signed with SIGHASH_UNIFIED (spec): a 65-byte signature ending 0x21 that Knots accepts on the BLAKE2b chains and SHA256d nodes reject. Coins from before the fork exist on both chains, so without this a mark could be replayed onto the original chain. lib/unified-sighash.js implements it and passes Knots's 166 test vectors (test/unified_sighash.json).
How It Works
Each git mark creates a real Bitcoin transaction. The address is derived from your key + the commit hash using BIP-341 taproot key chaining:
baseKey + tweak(commit₁) → Address₁ → TXO₁
baseKey + tweak(commit₁, commit₂) → Address₂ → TXO₂
The chain of addresses on Bitcoin mirrors the chain of commits in git. Anyone can verify by re-deriving the addresses from the public key + commit hashes.
Commands
| Command | Description |
|---|---|
git mark init |
Initialize trail. Options: --chain, --voucher, --force |
git mark |
Anchor HEAD commit to Bitcoin |
git mark info |
Show trail state, balance, addresses |
git mark verify |
Verify all marks against Bitcoin |
git mark update |
Update blocktrails.json from git notes |
git mark --version |
Show version |
Trail File
blocktrails.json in your repo root — committed, visible, verifiable:
{
"version": "0.0.3",
"profile": "gitmark",
"pubkeyBase": "02abc...",
"chain": "tbtc4",
"states": ["a1b2c3", "e5f6a7"],
"txo": [
"txo:tbtc4:abc:0?commit=a1b2c3",
"txo:tbtc4:def:0?commit=e5f6a7"
]
}
- pubkeyBase — compressed pubkey (02/03 prefix), base for BIP-341 key chaining
- states — commit hashes (input to key derivation)
- txo — Bitcoin anchors (TXO URIs, self-contained and verifiable)
Private spending state stored in gitmark.txo git config (never committed).
Configuration
# Private key (auto-generated by init)
git config --local nostr.privkey <64-char-hex>
# Current UTXO (updated on each mark)
git config --local gitmark.txo txo:tbtc4:txid:vout?amount=X&commit=Y
# Dirty flag — set to false to keep working tree clean after marking
git config --local gitmark.dirty false
When gitmark.dirty=false, git mark only writes git notes + git config. Run git mark update to sync blocktrails.json when ready.
Same secp256k1 key used for Nostr, Bitcoin, and Solid pod authentication.
Dependencies
Two: @noble/curves and @noble/hashes. No bitcoinjs-lib, no external transaction builders.
Related
- blocktrails.org — state anchoring on Bitcoin
- git-mark.com — project homepage
- BIP-341 — Taproot key tweaking
License
AGPL-3.0 Melvin Carvalho