Bitcoin May Be Dumb But It Ain't Stupid: Parts 1 and 2

Disclaimer

Below is a proof of concept for an idea that can be taken deeper or down alternative paths. No “firsts” are being claimed here and, quite frankly, the visual side sucks. The goal is to put something concrete on the table that sparks conversation about what “onchain” actually means on Bitcoin, and how far the existing script system can be pushed without protocol changes or offchain dependencies.

The following records a single execution of each proof of concept. The full parameter space contains 10 valid combinations (Part 1) or any number of possibilities (Part 2) and the remaining ones will be executed and inscribed to friends using parent-child (i.e. don’t ask me for one).

1. Background

The phrase “fully onchain” gets used loosely in crypto art. For Bitcoin, most of the time it means the image file or rendering code is stored in a blockchain transaction rather than on a server somewhere. That is a meaningful improvement over IPFS links or centralized hosting but it is not the same thing as the blockchain doing any work. For those interested, I wrote this thread a couple years back detailing why “onchain” is not a simple binary aspect of a work.

This project asks a different question from current standards: can the Bitcoin blockchain be used as a computational substrate for generative art, not just a storage medium? Can the parameters of a generative artwork be derived from actual Bitcoin Script execution, enforced by consensus, and verifiable by anyone with a node?

The answer, it turns out, is yes (with caveats!).

2. The Core Idea

Bitcoin Script is intentionally limited. It is stack-based, non-Turing-complete, has no loops, no persistent state, and no native randomness. This makes Bitcoin Script auditable and safe and, lucky for us, also makes it a strange environment for generative art.

Limited does not mean useless. Bitcoin Script can hash data, perform bitwise operations, do arithmetic, and branch conditionally. More importantly, Taproot (BIP341) introduced taptrees: a Merkle tree of script spending conditions where each leaf is a distinct script path. The collector spends a UTXO by satisfying one leaf, thereby revealing which path they chose.

The insight this project builds on is that the taptree structure itself can encode a generative parameter space. Each leaf represents a specific set of artwork parameters and spending a leaf is the generative act. The transaction graph is the execution trace and the spent leaves are the outputs.

This is not validation in the traditional Bitcoin Script sense. The artist encodes the entire valid parameter space at genesis, after which the collector navigates it and Bitcoin consensus enforces which path was taken. The result is provable from chain state alone, without trusting the artist, any indexer, or any offchain service.

3. The Generative Model: Cyclic Cellular Automata

The visual output is a cyclic cellular automaton running on a 2D grid. Three parameters fully define its behavior: N (number of states), T (neighbor threshold, a cell advances when at least T neighbors are in the next state), and R (neighborhood radius). A fourth parameter, the seed, is derived from the first 4 bytes of a transaction ID as a uint32 giving each piece a unique initial grid tied to the chain.

Ten parameter combinations were identified from the full valid space. These ten form the artwork’s parameter set, spanning two aesthetic families: an R=1 family producing tight geometric and crystalline forms, and an R=2 family producing fluid organic and wave-based patterns.

Like I said in the disclaimer, the visuals here are not particularly interesting and act as a simple medium to an end.

4. Part 1: Script-Path-Encodes-Choice

Part 1 encodes the parameter space in a two-stage taptree structure. The first transaction encodes the family choice and the second encodes the specific combination within that family (N and T).

Transaction 1 taptree — 2 leaves

Leaf A: OP_SHA256 SHA256("BTC_ART_V1:R1") OP_EQUALVERIFY OP_TRUE
Leaf B: OP_SHA256 SHA256("BTC_ART_V1:R2") OP_EQUALVERIFY OP_TRUE

Each leaf script is a hash preimage lock. The preimage is a human-readable ASCII string namespaced with a version prefix. Spending a leaf requires revealing the preimage in the witness. The preimage itself encodes which parameter choice was made and anyone inspecting the transaction graph sees the plaintext string and knows immediately what was chosen.

This is script-path-encodes-choice; the taptree structure is the parameter space. Spending a leaf is the choice and there is no validation logic nor witness manipulation possible. The structure enforces the parameter space at the consensus level.

One important property of OP_TRUE scripts is they are permissionless. Anyone who sees the preimage in the mempool can spend the UTXO, which is one of the points Part 2 tries to address.

5. The Inscription Architecture

The artwork lives in a three-inscription structure on Bitcoin mainnet, all inscribed as Ordinals using the standard commit/reveal protocol.

Inscription ID Role
Renderer f26aafb4897eb18b0e3b87822f4ae1260402b5e9b1635eb6f49b09634b09996di0 Parent, the algorithm
Execution record fb36abfcc51949edbee170f070715c4dea69d7f438be745281e4366708a8e7f8i0 Child, parameter record
Piece 12b6205e1ce9b379f35b53b5cbfb2efcc720ea714a1267aea3a56dbe2986abe8i0 Child, displayable artwork

The renderer is a self-contained HTML/JavaScript file that implements the cyclic CA visualization. It accepts a child inscription ID as a URL parameter, fetches the execution record JSON via Ordinals recursion, and renders from those parameters. This means there are no external network calls or dependencies outside the Bitcoin network.

The execution record is a JSON child inscription containing the complete parameter derivation record. The piece inscription is a minimal HTML redirect that navigates to the renderer with its own inscription ID as the child parameter.

Resolution chain

/content/12b6205e...i0  (piece - navigate here)
  → redirects to /content/f26aafb4...i0  (renderer)
  → ?child=fb36abfc...i0
  → fetches execution record JSON
  → parses N=3, T=3, R=1, seed=4177152512
  → renders cyclic CA

6. Part 1 Transaction Record

TX TXID Role
Genesis / Reveal f8fa4a0020b4dbc3b11cbbd0f5b2ee21af8bf52d6f3d18d0ee295ce4b18afee6 Inscription + TX1 UTXO
TX1 spend e724d0b492624eea779e433ff8ed3dd28f913577baff0b33dcc8dcea87ee4635 R=1 (front-run)
TX2a funding 4870b2538ae5f2b260e22647869f036bfa134c7fa4739153362f9eeef718968f Refund TX2a taptree
TX2a spend f8c60a296cad264d034c1bfcdec4a612537ce0509c71828e76b38e54880b3cf9 N=3, T=3, R=1 (front-run)

Derived parameters: N=3, T=3, R=1, seed=4177152512 (0xf8fa4a00, the first 4 bytes of the genesis TXID).

Canonical piece URL: ordinals.com/content/12b6205e...i0

7. The Front-Running Attacks

Both TX1 and TX2a spends were front-run in the mempool. This was anticipated as a known property of OP_TRUE scripts and is worth documenting in detail because it is as interesting as it is instructive.

OP_TRUE scripts are permissionless by design. The spending condition is satisfied by revealing a preimage. Anyone who sees that preimage in an unconfirmed transaction can construct a competing transaction using the same preimage, pay a higher fee, and have their transaction confirmed first. The original transaction gets replaced.

In both cases, an automated actor extracted the preimage from the witness of the unconfirmed transaction and broadcast a replacement that burned nearly all the UTXO value as miner fees. The replacements were confirmed and the original transactions were dropped.

What the front-runner could not do was corrupt the parameter commitments. The preimages BTC_ART_V1:R1 and BTC_ART_V1:N3_T3_R1 are permanently and correctly committed in the replacement transactions. The artwork’s parameters are intact and the front-runner captured the economic value but not the semantic value.

That distinction, while not ideal, is important. The artwork survived two adversarial interventions in the mempool and resolved correctly. The parameter commitments were inviolable once the preimages hit the chain meaning the architecture is working as designed, even if the execution was messier than intended.

8. Part 2: Witness-Encodes-Choice

Part 1 demonstrated that taptree topology can encode a generative parameter space that uses its structure as a choice and the leaf selection as a generative act. Part 2 takes a different approach in that the collector provides parameter values directly in the witness stack, and the script validates them against the constraints of the generative model itself.

The move from Part 1 to Part 2 is a move from navigation to validation. In Part 1, the parameter space was a map and spending a leaf was choosing a destination. In Part 2, a single Tapscript leaf enforces the rules of the cyclic CA model arithmetically: N must be in range, T must be in range, and critically, T must be less than or equal to N. That last constraint is not a curator’s approved list and, in this case, is the definition of a valid cyclic CA. The script encodes the model’s own rules.

The Script

# Witness stack at entry (top to bottom): N, T, R, sig

OP_DUP  OP_3  OP_7  OP_WITHIN  OP_VERIFY          # N in [3,6]
OP_OVER  OP_GREATERTHANOREQUAL  OP_VERIFY          # T <= N
OP_1  OP_GREATERTHANOREQUAL  OP_VERIFY             # T >= 1
OP_DUP  OP_1  OP_3  OP_WITHIN  OP_VERIFY          # R in [1,2]
OP_2DROP  OP_DROP                                  # clean stack
<collector_pubkey>  OP_CHECKSIG                    # authorize

The T <= N check is a relational validation between two witness-supplied values computed in script. This is Script doing arithmetic work with the parameters, not just looking them up in a list. A Schnorr signature from the collector’s key is required to authorize the spend, making the transaction impossible to front-run; the signature commits to the transaction, so an automated actor observing the mempool cannot reuse or redirect it.

Part 2 Transaction Record

TX TXID Role
Fund taptree 58b45295683a420f2bb4a7fb8b89dd908b907a590d53b09033b9a7e4c3c3e469 10,000 sats to taptree address
Taptree spend 504988c88f56bc6bf167d688d6b24357a48009fa2bdb758571656fc737270fc0 N=6, T=3, R=2, block 939627
Inscribe execution record 315745b9e0000d6c3c7e384dcf75db28dfc4bc16ae9bda647f0b62719d2c5fcf Child of renderer
Inscribe piece 9a12012d36e7073252034f448b3984c88277f71286d2ae040406ae9c935f87ca Piece redirect, child of renderer

Derived parameters: N=6, T=3, R=2, seed=1346996424 (0x504988c8 for first 4 bytes of the taptree spend TXID, not the inscription TXID like Part 1).

Part 2 Inscription Architecture

Inscription ID Role
Renderer f26aafb4897eb18b0e3b87822f4ae1260402b5e9b1635eb6f49b09634b09996di0 Shared with Part 1, unchanged
Execution record 315745b9e0000d6c3c7e384dcf75db28dfc4bc16ae9bda647f0b62719d2c5fcfi0 Child, witness parameter record
Piece 9a12012d36e7073252034f448b3984c88277f71286d2ae040406ae9c935f87cai0 Child, displayable artwork

Part 2 reuses the Part 1 renderer inscription unchanged. The renderer reads N, T, R, and seed from the execution record JSON via Ordinals recursion (the same four fields, the same field names, and the same rendering logic as Part 1). The execution record shape differs only in provenance metadata: no preimage fields, instead witness_N, witness_T, witness_R, and derivation_method set to “witness-encodes-choice”.

Resolution chain

/content/9a12012d...i0  (piece, navigate here)
  → redirects to /content/f26aafb4...i0  (renderer)
  → ?child=315745b9...i0
  → fetches execution record JSON
  → parses N=6, T=3, R=2, seed=1346996424
  → renders cyclic CA

Canonical piece URL: ordinals.com/content/9a12012d...i0

What Part 2 Adds

The front-running attacks on Part 1 were the direct motivation for Part 2’s design. A signature requirement alongside the preimage would have prevented both. But the more important contribution is architectural: Part 2 demonstrates that Script can perform arithmetic validation of collector-provided inputs rather than encoding the parameter space structurally. The parameter space in this instance is a set of constraints the collector’s choices must satisfy.

The two pieces together map a design space. Part 1 uses a taptree structure as a parameter space where spending a leaf is akin to navigation and Part 2 is a script enforcing the rules of the generative model and collectors supplying values that satisfy them. They have the same renderer and same generative model but different execution architectures. Most importantly, they are both permanently verifiable from chain state alone.

9. The Honest Limitation

Bitcoin Script is not doing heavy computation. It is not running the cellular automaton or hashing parameters into complex outputs. What it is doing is enforcing, at the consensus level, which parameter values were chosen and making that choice permanently provable from chain state alone, but the rendering still happens in JavaScript. The claim is about parameter provenance and onchain enforceability, not about Script as a compute environment (yet).

10. Where This Goes

The two approaches demonstrated here (script-path-encodes-choice and witness-encodes-choice) are primitives. What they establish is a way of thinking about Bitcoin Script as a parameter enforcement layer for generative work. Several directions follow naturally:

Generative series with collector agency

The most direct application is a generative series where each edition’s visual output is determined by the collector’s spend, not the artist’s predetermination. The artist defines the parameter space and the generative model while the collector navigates or populates it. No two collectors make the same choice and every choice is permanently attributable and provable. The artwork exists as a possibility space until it is claimed, at which point it becomes fixed by the chain.

Multi-party parameter determination

Nothing in either architecture requires a single collector. A taptree could require sequential spends from multiple parties, each contributing one parameter. The final output is a function of all their choices combined where no single party controls the result. This is collaborative generative art where the collaboration is enforced by consensus rather than trust.

Using script to define a model

Part 2’s T <= N constraint is the beginning of a more interesting idea: what if the script encoded more of the generative model’s rules, not just its parameter bounds? A richer validation layer could enforce relationships between parameters that correspond to meaningful aesthetic or behavioral properties of the output, constraining the collector to choices that remain within a defined visual or behavioral territory. The script becomes a partial specification of the artwork’s character.

Transaction graph acting as execution trace

Both pieces here use a linear transaction graph (genesis > spend > inscribe) but the graph could be more complex. A taptree could encode branching narrative structures where each spend opens new UTXOs with new taptrees, and the full graph of spends constitutes the execution trace of a larger generative process. The artwork is not a single output but the entire trajectory of a record of choices made across time, each visible to anyone on the network.

Beyond cellular automata

The generative model here is cyclic cellular automata but nothing about the architecture is specific to it. Any parameterized generative system whose parameters fit within Bitcoin Script’s arithmetic range could be used: L-systems, reaction-diffusion, strange attractors, noise functions, etc. The constraint is that the parameters must be expressible as small integers that Script can validate. Within that constraint, the model is arbitrary. The chain enforces the parameter space; the renderer does whatever it wants with them.

The deeper question these projects are circling is what it means for Bitcoin to participate in the creation of an artwork versus “just” recording it. Script-path-encodes-choice and witness-encodes-choice are two answers of many to that question.

11. Closing Note

Parent-child is still not a collection standard.

← all writing