Git-mark Profile (v0.1)
Git commits anchored to Bitcoin via Blocktrails output-key commitments.
Abstract
Git-mark binds Bitcoin UTXOs to Git commits using elliptic curve tweaking. Each commit hash becomes a scalar tweak that derives a new pubkey, creating a cryptographic chain linking repository history to Bitcoin.
1. Introduction
Git-mark creates a two-way binding between Git and Bitcoin:
- Git → Bitcoin: Commit hash tweaks the pubkey, recorded on-chain
- Bitcoin → Git: TXO URI in repository points to the UTXO
Unlike Monochrome profiles which use JCS-serialized state as the tweak source, git-mark uses Git commit hashes directly.
2. Cryptographic Model
2.1 Chained Key Derivation
Git-mark follows the Blocktrails chained derivation model:
2.2 Scalar Function
For git-mark, the scalar is the git commit hash interpreted as a big-endian integer:
scalar(commit) := int(commit_hash, big-endian) mod n
Where commit_hash is the 20-byte (40 hex character) git commit hash, and n is the secp256k1 curve order.
Since git uses SHA-1, the commit hash is already a cryptographic hash. No additional hashing is needed.
If scalar(commit) = 0, the commit MUST be rejected (probability ~2-160).
2.3 Private Key Derivation
The spending key for any state:
d_n = d₀ + scalar(commit₁) + scalar(commit₂) + ... + scalar(commitₙ) (mod n)
3. TXO URI Format
Git-mark uses TXO URIs to record the on-chain state:
txo:<network>:<txid>:<vout>?amount=<sats>&pubkey=<hex>[&commit=<git_hash>]
| Field | Type | Description |
|---|---|---|
| network | string | Bitcoin network (mainnet, tbtc4, signet) |
| txid | hex64 | Transaction ID (64 hex characters) |
| vout | integer | Output index |
| amount | integer | Value in satoshis |
| pubkey | hex64 | X-only pubkey (64 hex characters) |
| commit | hex40 | Git commit hash (absent for genesis) |
3.1 Genesis TXO
The genesis TXO has no commit parameter. Its pubkey is the base pubkey P₀:
txo:tbtc4:34cea31b...e854be0e:0?amount=1000000&pubkey=3e458cc6...a5c8cf
3.2 Subsequent TXOs
Each subsequent TXO includes the commit that tweaked to this pubkey:
txo:tbtc4:45fbcbd7...81a9f7d:0?amount=999000&pubkey=b5bc388c...5266c&commit=cf97baba...83d17d
4. State Transitions
4.1 Transition Flow
4.2 Making a Transition
- Create git commit with state changes
- Compute new pubkey:
P_new = P_current + scalar(commit) × G - Spend current UTXO to new pubkey
- Append new TXO URI to
txo.json - Push to git remote
5. Directory Structure
Git-mark state is stored in the repository:
.well-known/
└── txo/
└── txo.json # Array of TXO URIs
5.1 txo.json Format
Simple JSON array of TXO URI strings:
[
"txo:tbtc4:<txid>:0?amount=1000000&pubkey=<genesis_pubkey>",
"txo:tbtc4:<txid>:0?amount=999000&pubkey=<pubkey>&commit=<hash>",
"txo:tbtc4:<txid>:0?amount=998000&pubkey=<pubkey>&commit=<hash>"
]
6. Verification
6.1 Chain Validity
A git-mark chain is valid if:
- Genesis: First TXO has no commit, pubkey is valid point
- Continuity: Each subsequent
pubkey = prev_pubkey + scalar(commit) × G - On-chain: Each UTXO exists (or existed) on Bitcoin
- Git validity: Commit hashes correspond to actual git commits
6.2 Verification Algorithm
function verify(txoUris):
txos = parse(txoUris)
// Genesis check
if txos[0].commit != null:
return { valid: false, error: "genesis has commit" }
// Try both Y parities (x-only loses parity)
for prefix in [0x02, 0x03]:
basePubkey = prefix || txos[0].pubkey
commits = []
valid = true
for i = 1 to txos.length - 1:
commits.push(txos[i].commit)
expected = deriveChainedPubkey(basePubkey, commits)
if xonly(expected) != txos[i].pubkey:
valid = false
break
if valid:
return { valid: true }
return { valid: false, error: "pubkey mismatch" }
6.3 Commit Selection and Ordering
Commits anchored to the TXO chain need not be consecutive in git history. Any commit may be selected for marking. However:
- Marked commits SHOULD be in ancestral order (each marked commit is a descendant of the previous)
- The TXO chain records the order commits were marked
- Verifiers SHOULD confirm referenced commits exist in the repository
- Verifiers MAY check that commits form a valid ancestral chain in git
The EC_ADD verification ensures pubkey chain integrity. Git ancestry verification is an additional check that confirms the logical ordering of state transitions.
7. Comparison with Monochrome
| Aspect | Git-mark | Monochrome |
|---|---|---|
| Tweak source | Git commit hash | sha256(JCS(state)) |
| State storage | Git tree objects | JSON state array |
| State format | Any git content | Structured JSON with ops |
| Linking | TXO URI in txo.json | State contains prev hash |
| Use case | Repository anchoring | Application state machines |
Git-mark leverages Git's existing content-addressed storage and commit graph. Monochrome defines its own state schema with explicit operations.
8. Security Considerations
8.1 Inherited from Blocktrails
- Hash preimage resistance → commit binding
- Discrete log hardness → pubkey security
- Bitcoin consensus → spend ordering
8.2 Git-mark Specific
| Threat | Mitigation |
|---|---|
| Commit rewriting | Git's content-addressing; verifiers check commit exists |
| History divergence | TXO chain anchors specific commit sequence |
| UTXO availability | Bitcoin full node or SPV verification |
| txo.json tampering | Verify pubkey derivation matches recorded commits |
8.3 Trust Model
- Bitcoin: UTXO existence and spend ordering
- Git: Commit immutability (content-addressed)
- Client: Must verify EC_ADD chain and commit existence
9. Implementation
Reference implementation: blocktrails/git-mark
npm install git-seal
git mark init
git mark genesis --txid <txid> --vout 0 --amount 1000000
git commit -m "state change"
git mark advance --txid <txid> --vout 0 --amount 999000
git mark verify
10. References
- Blocktrails Core Specification
- Blocktrails Profiles
- Legacy gitmark
- BIP-340: Schnorr Signatures
- BIP-341: Taproot