btcvm 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
btcvm-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ryan Scarbery
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
btcvm-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,422 @@
1
+ Metadata-Version: 2.4
2
+ Name: btcvm
3
+ Version: 0.1.0
4
+ Summary: A minimal register machine that executes in lockstep with Bitcoin blocks
5
+ License: MIT
6
+ Keywords: bitcoin,register-machine,vm,blockchain,vdf,cryptography
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Topic :: Security :: Cryptography
13
+ Classifier: Topic :: System :: Emulators
14
+ Requires-Python: >=3.11
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Provides-Extra: dev
18
+ Requires-Dist: pytest>=8.0; extra == "dev"
19
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
20
+ Requires-Dist: ruff>=0.5; extra == "dev"
21
+ Provides-Extra: s3
22
+ Requires-Dist: boto3>=1.34; extra == "s3"
23
+ Dynamic: license-file
24
+
25
+ # btcvm
26
+
27
+ A minimal register machine that executes in lockstep with Bitcoin blocks.
28
+
29
+ Each Bitcoin block triggers a fixed number of VM cycles. After each block, the VM's state is hashed and cryptographically bound to the block hash — producing a verifiable ledger of computation anchored to Bitcoin's clock.
30
+
31
+ ## Why
32
+
33
+ Bitcoin is a clock. Every ~10 minutes a new block is mined, and its hash is unpredictable until the moment it's found. This makes it a natural source of consensus timing for off-chain computation.
34
+
35
+ `btcvm` demonstrates the minimal architecture for a Bitcoin-clocked state machine:
36
+
37
+ ```
38
+ Bitcoin block hash
39
+
40
+ VM executes N cycles
41
+
42
+ commitment = SHA256(block_hash + state_hash)
43
+
44
+ OP_RETURN → committed to Bitcoin (optional)
45
+ ```
46
+
47
+ The resulting ledger is independently verifiable: anyone with the block hashes (publicly available from any Bitcoin node or API) can recompute every commitment and confirm the VM ran exactly as recorded.
48
+
49
+ ## Files
50
+
51
+ | File | Description |
52
+ |------|-------------|
53
+ | `vm.py` | Minimal register machine (8 registers, 7 opcodes) |
54
+ | `clock.py` | Bitcoin block clock via blockstream.info API |
55
+ | `programs.py` | Sample programs (fibonacci, countdown) |
56
+ | `vdf.py` | VDF sub-clock — sequential SHA256 chain with tick/verify (v1.2) |
57
+ | `trace.py` | Step-by-step execution trace with Merkle root commitment (v2) |
58
+ | `fleet.py` | N parallel VMs with fleet Merkle root — one OP_RETURN anchors all (v3) |
59
+ | `broadcast.py` | Optional OP_RETURN broadcast via the `bit` library |
60
+ | `main.py` | Orchestrator — runs clock loop, executes VM(s), writes ledger |
61
+ | `verify.py` | Verifies ledger, VDF chain, trace, and fleet Merkle against Bitcoin |
62
+ | `ott.py` | Bitcoin-anchored media archive — images, video, and git repos; also an interactive shell |
63
+ | `test_vm.py` | Unit tests (VM, VDF, trace, fleet) |
64
+ | `test_ott_completion.py` | Unit tests (ott shell tab completion, path handling) |
65
+ | `Makefile` | Common tasks: install, test, lint, run, ott |
66
+ | `completions/` | Bash and Zsh tab completions for `btcvm` and `ott` |
67
+
68
+ ## VM
69
+
70
+ The VM has 8 registers (`R0`–`R7`) and 7 opcodes:
71
+
72
+ | Opcode | Description |
73
+ |--------|-------------|
74
+ | `LOAD r, val` | Load immediate value into register |
75
+ | `ADD dst, a, b` | `Rdst = Ra + Rb` |
76
+ | `SUB dst, a, b` | `Rdst = Ra - Rb` |
77
+ | `MUL dst, a, b` | `Rdst = Ra * Rb` |
78
+ | `JMP addr` | Unconditional jump |
79
+ | `JZ r, addr` | Jump if register is zero |
80
+ | `HALT` | Stop execution |
81
+
82
+ Programs are tuples loaded into memory. See `programs.py` for examples.
83
+
84
+ ## Usage
85
+
86
+ **Requirements:** Python 3.11+, no runtime dependencies (stdlib only).
87
+
88
+ ```bash
89
+ # Install
90
+ pip install -e . # editable install
91
+ make install # same via Makefile
92
+ make dev # with dev deps (pytest, ruff)
93
+ ```
94
+
95
+ ### btcvm clock
96
+
97
+ ```bash
98
+ # v1 — one entry per Bitcoin block
99
+ python3 main.py fibonacci
100
+
101
+ # v1.2 — VDF sub-clock: 5 ticks per block
102
+ python3 main.py fibonacci --vdf-ticks 5
103
+
104
+ # v2 — trace Merkle root replaces state_hash
105
+ python3 main.py fibonacci --trace
106
+
107
+ # v3 — fleet of 4 parallel VMs, single fleet root per OP_RETURN
108
+ python3 main.py fibonacci --vms 4
109
+
110
+ # Everything combined
111
+ python3 main.py fibonacci --vms 4 --vdf-ticks 3 --trace
112
+
113
+ # Optional: broadcast commitment as OP_RETURN
114
+ pip install bit
115
+ python3 main.py fibonacci --broadcast --wif <your-WIF-key> --network mainnet
116
+ ```
117
+
118
+ **Getting a wallet for broadcast:**
119
+
120
+ ```python
121
+ from bit import PrivateKey
122
+ k = PrivateKey()
123
+ print(k.to_wif(), k.address)
124
+ ```
125
+
126
+ Fund the address with ~5000 sats (covers ~8 commitments at low fee rates).
127
+
128
+ **Verifying a ledger:**
129
+
130
+ ```bash
131
+ python3 verify.py # block hashes + commitments
132
+ python3 verify.py --trace-file trace.jsonl # include trace verification
133
+ python3 verify.py --check-txs # also fetch block tx lists
134
+ ```
135
+
136
+ ### ott — Bitcoin-anchored media archive
137
+
138
+ `ott` stores images and video in a content-addressed Merkle tree and commits
139
+ the root to Bitcoin via the btcvm ledger. Images are hashed whole; video files
140
+ are split into 256 KB chunks with a per-file Merkle tree, enabling byte-range
141
+ inclusion proofs.
142
+
143
+ ```
144
+ image.jpg → SHA256 ──────────────────────────────────┐
145
+ ├─→ global root → Bitcoin
146
+ video.mp4 → [chunk₀, chunk₁, …, chunkₙ] → file root ┘
147
+ ```
148
+
149
+ ```bash
150
+ # Stage files (images or video — detected by extension). Hashed now — that's
151
+ # what identifies the file and catches duplicates — but not yet copied into
152
+ # object storage or written to the manifest.
153
+ python3 ott.py add photo.jpg family.jpg video.mp4
154
+
155
+ # Show what's staged vs. already archived, and the current Merkle root
156
+ python3 ott.py status
157
+
158
+ # Changed your mind about a staged file? Drop it before it's archived.
159
+ # (Only works pre-commit — once a file's archived, rm can't touch it.)
160
+ python3 ott.py rm family.jpg
161
+
162
+ # Archive everything staged, then commit the Merkle root to the btcvm
163
+ # ledger (sync is a plain alias for commit — same thing, either name)
164
+ python3 ott.py commit
165
+
166
+ # List all archived files
167
+ python3 ott.py list
168
+
169
+ # Generate a wallet key, then anchor the commitment on-chain (optional)
170
+ python3 ott.py keygen --network testnet
171
+ python3 ott.py broadcast --wif <WIF_KEY>
172
+
173
+ # Verify a file is in the archive (Merkle inclusion proof)
174
+ python3 ott.py verify photo.jpg
175
+
176
+ # Prove a specific 256 KB chunk of a video is in the archive
177
+ python3 ott.py verify-chunk video.mp4 3
178
+
179
+ # Verify every ledger commit against real Bitcoin, not just internal state
180
+ python3 ott.py verify-chain
181
+ ```
182
+
183
+ **Interactive shell:**
184
+
185
+ ```bash
186
+ python3 ott.py # or: python3 ott.py shell
187
+ ```
188
+
189
+ The shell wraps the same archive with a stateful `cd`-able hierarchy, tab
190
+ completion on every command (archive names, tags, local paths), and a few
191
+ things the flat CLI doesn't have:
192
+
193
+ | Command | Description |
194
+ |---|---|
195
+ | `add [-r] <file>...` | Stage files (git-index style) — hashed now, archived on `commit`/`sync` |
196
+ | `rm <name_or_hash>` | Unstage a pending `add`; refuses once a file's actually committed |
197
+ | `commit` / `sync` | Archive everything staged, then commit the Merkle root to the ledger (same action, either name) |
198
+ | `l [-a] [-t tag] [-b] [dir]` | One-level `ls`-style view of the archive hierarchy (from `orig_path`) |
199
+ | `tree [-a] [-t tag] [-dN] [-b] [dir]` | Recursive tree view; `-d0` for unlimited depth |
200
+ | `cd`, `pwd` | Navigate the *archive* hierarchy (real filesystem nav is `lcd`/`lpwd`) — `cd`'ing to a repo's name instead jumps the real filesystem cwd to that repo's checkout, since repos have no virtual file tree of their own |
201
+ | `list` / `ls [pattern]` | Full flat dump of every path in one table, optionally filtered by regex (bare or `/slash-delimited/`) |
202
+ | `open <name_or_hash>` (alias `o`) | Open an archived file with the OS default handler (prefers the live copy, falls back to the archived one) |
203
+ | `mv <name> <new_path>` | Update an entry's tracked path; moves into an existing dir like real `mv` |
204
+ | `reindex [root]` | One indexed filesystem scan — relocates every stale entry and re-anchors `orig_path` to the archive root |
205
+ | `tag <add\|rm\|list> <pattern> <tagname>` | Bulk-tag entries by regex match against their archive path |
206
+ | `repo <add\|list\|verify\|update\|outdated\|update-all\|tag\|verify-tag\|qr>` | Track a git repo's HEAD and (optionally) a GPG-signed release tag in the archive; `outdated` (alias `o`) checks every tracked repo against its remote, `update-all` (alias `ua`) pulls all of them |
207
+ | `backfill [--workers N]` | Store archive copies for entries on disk but not yet uploaded to the active backend — also the migration path when switching backends (e.g. local → S3). N concurrent (default 8, or `OTT_BACKFILL_WORKERS`); live progress bar on a TTY, one line per file when piped |
208
+ | `verify-objects [--workers N]` | Audit every archived entry against the active backend (existence + size) — for S3 this always queries the bucket directly, bypassing the local cache, so it's the real answer to "did this actually upload" |
209
+ | `bump-fee --wif <WIF> [--fee SAT_PER_VBYTE] [--network testnet\|mainnet]` | CPFP fee bump for a stuck `broadcast` tx — spends the pending change output at a higher fee so miners confirm both together (not RBF). Default 10 sat/vbyte |
210
+ | `verify-chain [-c]` | Verify every ledger commit against real Bitcoin (refetches each block's actual hash) — `-c` also checks the OP_RETURN landed |
211
+ | `keygen [--network]` | Generate a wallet key for `broadcast` (prints WIF + a QR of the address only, never the key) |
212
+ | `broadcast [--wif]` | Broadcast a commitment as a Bitcoin OP_RETURN tx |
213
+ | `qr [hash\|file]` | QR code for a hash, a file's SHA256, or the current Merkle root |
214
+ | `!<cmd>` | Run a real shell command without leaving the shell |
215
+
216
+ Entries missing at their last known path are hidden by default in `l`/`tree`
217
+ (`-a` shows them); `ott reindex` is the real fix.
218
+
219
+ `add` only stages — nothing's copied into object storage or written to the
220
+ manifest until `commit`/`sync`. Names/hashes resolve relative to the current
221
+ archive directory first (`cd`-aware), only falling back to a global search
222
+ if nothing matches locally.
223
+
224
+ **Via Makefile:**
225
+
226
+ ```bash
227
+ make add FILE=photo.jpg
228
+ make verify-file FILE=photo.jpg
229
+ make ott-status
230
+ make ott-list
231
+ make ott-commit
232
+ make ott-clean # remove manifest + ledger
233
+ ```
234
+
235
+ **Environment variables:**
236
+
237
+ | Variable | Default | Description |
238
+ |---|---|---|
239
+ | `OTT_MANIFEST` | `ott_manifest.jsonl` | Manifest path |
240
+ | `OTT_LEDGER` | `ott_ledger.jsonl` | Ledger path |
241
+ | `OTT_CHUNK_BYTES` | `262144` (256 KB) | Video chunk size |
242
+ | `OTT_HOME` | `~/.ott` | Archive root when not using a local `.ott/` dir |
243
+ | `OTT_BACKEND` | `local` | Storage backend — `local` or `s3` (needs `pip install btcvm[s3]`) |
244
+ | `OTT_S3_BUCKET` | — | Required when `OTT_BACKEND=s3` |
245
+ | `OTT_S3_PREFIX` | `''` | Optional key prefix within the bucket |
246
+ | `OTT_S3_CACHE_DIR` | `.ott/cache` | Local cache dir for S3-backed objects |
247
+ | `OTT_BACKFILL_WORKERS` | `8` | Default concurrency for `backfill`/`verify-objects` |
248
+
249
+ **Proof chain for a video chunk:**
250
+
251
+ ```
252
+ chunk N bytes → SHA256 → chunk hash
253
+ ↓ Merkle proof (steps: log₂ chunks)
254
+ file root (= global leaf)
255
+ ↓ Merkle proof (steps: log₂ files)
256
+ global root → committed to Bitcoin
257
+ ```
258
+
259
+ `verify-chunk` outputs all three levels: bytes-on-disk match, per-file proof, global proof.
260
+
261
+ ## Architecture
262
+
263
+ ### VDF sub-clock (v1.2)
264
+
265
+ Between Bitcoin blocks the VM fires once per VDF tick. Each tick is `STEPS_PER_TICK` sequential SHA256 evaluations seeded from the previous tick's output. Because SHA256 can't be parallelised in this chained form, the ticks represent a minimum sequential cost any verifier must replay.
266
+
267
+ ```
268
+ Bitcoin block hash B_h
269
+ tick 0: SHA256ᴺ(B_h) → vdf₀ → VM cycles → commit₀
270
+ tick 1: SHA256ᴺ(vdf₀) → vdf₁ → VM cycles → commit₁
271
+
272
+ Next block B_{h+1} reseeds the chain
273
+ ```
274
+
275
+ ### Trace commitment (v2)
276
+
277
+ Every VM step is recorded as a hash-chained entry:
278
+ `step_hash = SHA256(prev_hash ‖ pc ‖ op ‖ regs_before ‖ regs_after)`.
279
+ A binary Merkle tree over all step hashes produces a single root that
280
+ replaces `state_hash` in the ledger commitment. Any individual step can
281
+ be verified without replaying the full execution. The trace file is
282
+ the witness a ZK prover (RISC Zero, SP1, Cairo) would consume.
283
+
284
+ ### Fleet Merkle root (v3)
285
+
286
+ N VMs run in parallel each tick. A binary Merkle tree over all N
287
+ commitments produces a single `fleet_root` — one OP_RETURN regardless
288
+ of fleet size.
289
+
290
+ ```
291
+ tick N:
292
+ VM₀ → commitment₀ ─┐
293
+ VM₁ → commitment₁ ─┤ Merkle → fleet_root → SHA256(block_hash:fleet_root) → OP_RETURN
294
+ VM₂ → commitment₂ ─┤
295
+ VM₃ → commitment₃ ─┘
296
+ ```
297
+
298
+ ## Ledger formats
299
+
300
+ **v1 entry:**
301
+ ```json
302
+ {
303
+ "block_height": 961224,
304
+ "block_hash": "000000000000...",
305
+ "vdf_tick": 0,
306
+ "vm_ticks": 10,
307
+ "halted": false,
308
+ "registers": [1, 1, 1, 20, 1, 0, 0, 0],
309
+ "state_hash": "a3f9c2b1...",
310
+ "commitment": "88d6f091..."
311
+ }
312
+ ```
313
+
314
+ **v1.2 additions** (VDF active):
315
+ ```json
316
+ {
317
+ "vdf_tick": 2,
318
+ "vdf_input": "prev_tick_output...",
319
+ "vdf_hash": "this_tick_output...",
320
+ "commitment": "SHA256(block_hash:vdf_hash:state_hash)"
321
+ }
322
+ ```
323
+
324
+ **v2 additions** (trace active):
325
+ ```json
326
+ {
327
+ "trace_root": "merkle_root_over_all_steps...",
328
+ "trace_steps": 42,
329
+ "commitment": "SHA256(block_hash:trace_root)"
330
+ }
331
+ ```
332
+
333
+ **v3** (fleet active) replaces per-VM fields with:
334
+ ```json
335
+ {
336
+ "fleet_size": 4,
337
+ "fleet_root": "merkle_root_over_vm_commitments...",
338
+ "commitment": "SHA256(block_hash:fleet_root)",
339
+ "vms": [
340
+ {"vm_id": 0, "program": "fibonacci", "halted": false, "registers": [...], "state_hash": "..."},
341
+ ...
342
+ ]
343
+ }
344
+ ```
345
+
346
+ **ott ledger entry:**
347
+ ```json
348
+ {
349
+ "ts": "2026-08-17T20:37:00Z",
350
+ "block_height": 961301,
351
+ "block_hash": "000000000000...",
352
+ "merkle_root": "b699603c...",
353
+ "commitment": "9dc75674...",
354
+ "image_count": 3
355
+ }
356
+ ```
357
+
358
+ ## Tab completions
359
+
360
+ ```bash
361
+ make completion
362
+ ```
363
+
364
+ Installs Bash and Zsh completions for both `btcvm` and `ott`:
365
+ - `btcvm` — flags and values (`--vdf-ticks`, `--vms`, etc.)
366
+ - `ott add` — any file
367
+ - `ott verify` — filenames from the manifest
368
+ - `ott verify-chunk` — video names, then chunk indices from the manifest
369
+
370
+ For Zsh, add to `~/.zshrc` if not already present:
371
+ ```zsh
372
+ fpath=(~/.zsh/completions $fpath)
373
+ autoload -Uz compinit && compinit
374
+ ```
375
+
376
+ ## Makefile targets
377
+
378
+ ```
379
+ make install pip install -e .
380
+ make dev install with dev deps
381
+ make test run pytest
382
+ make lint ruff check
383
+ make fix ruff --fix
384
+ make run btcvm one block
385
+ make run-vdf btcvm with VDF sub-clock
386
+ make run-trace btcvm with trace Merkle
387
+ make run-fleet btcvm fleet of 4 VMs
388
+ make verify verify ledger.jsonl
389
+ make ott-status show archive status
390
+ make ott-list list archived files
391
+ make ott-commit commit Merkle root
392
+ make ott-clean remove manifest + ledger
393
+ make ott-repo-add update archived repo record to HEAD
394
+ make ott-tag [OTT_NEXT_TAG=v1.x] sign a git tag + record fingerprint in ott
395
+ make ott-push [OTT_NEXT_TAG=v1.x] push commits + tag, then commit ott root
396
+ make ott-snapshot repo-add + commit root (no tag, no push)
397
+ make ott-release [OTT_NEXT_TAG=v1.x] full: tag → push → commit root
398
+ make add FILE=… add file to ott
399
+ make verify-file FILE=… verify inclusion
400
+ make completion install shell completions
401
+ ```
402
+
403
+ ## Roadmap
404
+
405
+ - ✅ **v1** — Bitcoin-clocked register machine, local ledger, optional OP_RETURN
406
+ - ✅ **v1.1** — Ledger verification against block hashes and OP_RETURN
407
+ - ✅ **v1.2** — VDF sub-clock (`--vdf-ticks N`)
408
+ - ✅ **v2** — Trace commitment / Merkle root (`--trace`)
409
+ - ✅ **v3** — Fleet Merkle: N parallel VMs, single OP_RETURN (`--vms N`)
410
+ - ✅ **ott** — Bitcoin-anchored media archive with chunked video and inclusion proofs
411
+
412
+ ## Tests
413
+
414
+ ```bash
415
+ make test
416
+ # or
417
+ python3 -m pytest -v
418
+ ```
419
+
420
+ ## License
421
+
422
+ MIT