Skip to content
Back to Blog
Developers

BitVMX Made EasyBeginner's GuideWith Hands On Examples

Read Time: 12 mins
BitVMX made easy: beginner’s guide with hands-on examples (Part 1)

By Ramon Amela, Research Engineer

BitVMX is a groundbreaking technology that enables Bitcoin to validate arbitrary programs without requiring changes to the Bitcoin protocol. Understanding BitVMX can be challenging for newcomers. This guide aims to break down the core concepts with practical examples.

Current state of Bitcoin

Bitcoin’s transaction model is based on UTXOs (Unspent Transaction Outputs). Think of UTXOs as individual “coins” that can only be spent once. Each UTXO represents a specific amount of bitcoin locked to specific spending conditions. When you spend bitcoin, you’re actually consuming one or more UTXOs. New UTXOs are created as outputs of transactions. When a UTXO is created, it is locked with a script that specifies the conditions under which it can be spent. In this case, the script is a set of operations executed on an input that must end up with a boolean value. For example, we could build a program that checks that the input is smaller than 10. All inputs smaller than 10 would be valid, while all inputs greater than or equal to 10 would be invalid. The most common condition is that the spender must provide a valid digital signature, which can only be generated with the private key corresponding to the public key (or address) that the UTXO is locked to. For example, if Alice has a UTXO locked to her address, she can spend it by creating a transaction that includes a signature generated with her private key. This signature proves that she is the rightful owner of the UTXO and has the authority to spend it. Without the private key, it is practically impossible to generate a valid signature, and thus the UTXO remains unspendable by anyone else. Your wallet balance is the sum of all UTXOs you can spend.

For example:

  • Alice has a UTXO worth 1 BTC
  • She sends 0.7 BTC to Bob
  • The transaction creates two new UTXOs:
    • 0.7 BTC locked to Bob’s address
    • 0.3 BTC returned to Alice as change

This UTXO model helps prevent double-spending and makes transaction validation simpler. To better understand it, let’s compare it to writing checks in real life:

Each UTXO is like a check. When you write a check, you specify the amount. In order to spend it, you write the recipient’s address on the check. Only the person who has the private key corresponding to the address on the check can write this address on the check. The publication of a transaction is the equivalent of writing a check. In order to spend it, we destroy it and we write several new checks the sum of which is equal to the amount of the original check. If you need to pay someone a specific amount, you might write multiple checks or receive change if the check amount exceeds the payment.

For example:

  • Alice has a check worth $100.
  • She writes a check for $70 to Bob.
  • Bob cashes the check, and the bank creates two new checks:
    • A $70 check for Bob
    • A $30 check returned to Alice as change

Bitcoin script

Bitcoin Script is a simple, stack-based programming language used to define the conditions under which a UTXO can be spent. It is purposefully designed to be non-Turing complete, meaning that it does not support loops or more complex constructs that could lead to undecidability. In addition, its length is limited to a single Bitcoin block. For non computer scientists, this means that the script is limited both to extremely simple operations and relatively short scripts. This design choice ensures that script execution is predictable and terminates quickly, but it also means that more sophisticated computations must be handled off-chain or through other mechanisms. For instance, Bitcoin Script allows for basic arithmetic operations such as addition and subtraction. However, it lacks support for multiplication and division because of their inherent complexity and associated security risks. This limitation highlights the simplicity and constrained nature of the Bitcoin Script language.

Protocol Improvements

Bitcoin has evolved to address some of these limitations through protocol upgrades. Two significant improvements are particularly relevant:

  1. Segregated Witness (SegWit) – Activated in 2017
    • Separates transaction signatures (“witnesses”) from transaction data
    • Signature data no longer affects transaction ID calculation
    • Improves transaction malleability protection
    • Increases block capacity without changing the block size limit
  2. Taproot – Activated in 2021
    • Enables multiple spending conditions to be encoded in a single address
    • Improves privacy by making complex smart contracts look like regular transactions
    • Reduces transaction fees for complex scripts
    • Enhances Bitcoin’s smart contract capabilities while maintaining simplicity

These upgrades have expanded Bitcoin’s programmability while preserving its security model and decentralized nature.

Continuing with the check analogy, we can think of an address as containing a script that authorizes the release of funds. To access these funds, the script requires a password. Typically, this password is a digital signature, which is a message created using the private key associated with the address. However, other types of passwords can also be used, such as preimages of hash functions.

A hash can be thought of as a digital fingerprint – a fixed-length string of characters that uniquely represents data of any size. Just like how a fingerprint uniquely identifies a person, a hash uniquely identifies digital content. For example, we could take an entire book and generate a 32-character hash that serves as its unique identifier. If two books generate identical hashes, we can be virtually certain that their contents are identical, without needing to compare the books page by page. This property makes hashes extremely useful for verifying data integrity and equality.

One-time signatures

One-time signatures are cryptographic schemes where each signing key can be used exactly once. Lamport signatures represent the most basic form of one-time signatures, using pairs of random numbers as private keys and their corresponding hash values as public keys. Winternitz signatures build upon this concept, achieving better efficiency than Lamport signatures.

In Bitcoin’s context, these signatures work differently from traditional public/private key pairs. Rather than storing the public key in the Bitcoin address, we store a hash of it. The actual signing key (preimage) is kept off-chain, and revealing this preimage serves as proof of ownership when spending.

One-time signatures enable powerful cryptographic commitments across multiple transactions when used along connectors. 

Connectors

SegWit separates the transaction’s authorization data (known as the “witness”) from the transaction ID calculation. This separation allows us to create valid transactions without immediate signatures, as the witness data isn’t part of the transaction ID. The required signatures can be added later, just before broadcasting the transaction to the Bitcoin network.

As mentioned earlier, transactions work by consuming existing UTXOs and creating new ones. SegWit introduces an interesting capability: we can construct chains of transactions where each transaction depends on the previous one. In this way, only someone with specific witness data can broadcast a transaction and transactions must be broadcast in a specific order (e.g., in a chain of 3 transactions, transaction 2 requires transaction 1 to be broadcast first, and transaction 3 requires transaction 2).

Bitcoin Script is stateless, meaning there is no shared database or direct way for scripts to exchange information. However, this limitation can be circumvented using one-time signatures. By embedding the same private key in multiple transactions, the first broadcasted transaction reveals the corresponding public key, linking it to a specific value. Subsequent transactions must use the same public key, ensuring that the value remains consistent. This mechanism effectively creates a cryptographic commitment, guaranteeing that the value does not change across transactions.

Taproot further enhances these capabilities by allowing multiple spending conditions to be encoded within a single address. This means that the party broadcasting the transaction can choose which spending condition to fulfill, providing flexibility while maintaining security.

Current limitations

Bitcoin’s design prioritizes security and decentralization over programmability. While recent improvements like SegWit and Taproot have enhanced its capabilities, Bitcoin remains more constrained in its computational expressiveness compared to platforms like Ethereum.

This limitation has historically led to a perception of Bitcoin primarily as a store of value, with more complex operations being delegated to other blockchains. To bridge this functionality gap, various solutions have emerged over the years. Layer-2 solutions and sidechains provide EVM compatibility and enable smart contract functionality while leveraging Bitcoin’s security, though they typically require certain trust assumptions in their bridge mechanisms. More precisely, Rootstock is a sidechain that allows for smart contracts and EVM compatibility while having the best bridge currently available.

The introduction of BitVM represents a significant breakthrough in this landscape. This innovation introduces a novel approach to verification that enables arbitrary computation verification without requiring changes to the Bitcoin protocol. BitVM maintains Bitcoin’s robust security model while substantially expanding its capabilities, particularly in the realm of cross-chain interactions and complex applications.

BitVM has sparked significant interest in the developer community, leading to various projects that aim to enhance Bitcoin’s verification capabilities. While initially focused on cross-chain bridges, BitVM’s potential applications extend to many other use cases, marking a significant advancement in Bitcoin’s evolutionary journey. This development suggests that Bitcoin’s role might expand beyond its traditional perception as purely a store of value, opening new possibilities for trustless and sophisticated applications built on top of Bitcoin’s secure foundation.

BitVMX

BitVMX represents a significant advancement in Bitcoin’s computational capabilities, building upon the foundational work of the BitVM team while introducing additional innovations. At its core, BitVMX enables the efficient verification of arbitrary RISC-V programs directly on the Bitcoin network.

To understand BitVMX, we must first explore the fundamental concepts of arbitrary computation verification. These principles form the basis of how BitVMX achieves its remarkable functionality while maintaining Bitcoin’s security guarantees. In the following sections, we’ll examine these core concepts and demonstrate how BitVMX leverages them to create a powerful verification system.

Arbitrary computation verification

An arbitrary computation is fundamentally a sequence of simple instructions that transform input data step by step. While each individual instruction performs a basic operation, the true power lies in combining thousands or millions of these elementary steps to accomplish sophisticated tasks. This principle forms the foundation of computer science and modern computing systems.

When it comes to Bitcoin, verifying arbitrary computations face significant challenges, primarily related to scale. Verifying seemingly straightforward operations, such as confirming whether a transaction is included in the Bitcoin blockchain, requires extensive computational programs. The problem becomes even more pronounced when considering the input data required for these verifications.

In fact, the size limitations on input data have emerged as the first critical bottleneck, more so than the computational complexity itself. This constraint has led many blockchain projects to adopt zero knowledge proof systems (like those used by risczero.com). These cryptographic techniques offer a solution to the scaling challenge, though their detailed mechanics fall outside this article’s scope.

After solving the input data challenge, we must address the computation itself. While individual computational steps are simple, the main challenge lies in managing the length of the entire program. BitVMX addresses this by breaking down the computation into its smallest units: individual instructions.

BitVMX provides a framework for verifying computations on the Bitcoin blockchain through what’s known as optimistic verification. When someone wants to prove they performed a computation correctly, they post their claim along with cryptographic hashes that represent key steps or states of that computation. These hashes act like digital fingerprints of the computation process.

The system is called “optimistic” because it assumes that the posted computation is correct unless someone challenges it. If anyone doubts the validity of the computation, they can examine the hashes and verify each step. The hashes make it impossible to fake or alter the computation results without detection, since even a tiny change would produce completely different hash values.

Think of it like showing your work in a math problem, but instead of writing out every step, you provide cryptographic proof that you followed the correct process. Anyone can check these proofs to confirm that you reached the right answer, without having to redo the entire computation themselves.

In this case, BitVMX proposes the following verification process:

  1. The program executes one instruction and produces a result
  2. This result is hashed to create a unique identifier (a chain of characters)
  3. The next instruction is executed, and its result is also hashed
  4. Then, a hash is computed by using the two previous hashes
  5. The third instruction is executed, and its result is hashed
  6. The hash is computed by using the two previous hashes
  7. The fourth instruction is executed, and its result is hashed
  8. The hash is computed by using the two previous hashes

At each step, we compute a hash by combining the result of the current instruction with the previous hash. This process ensures that if two parties have the same hash at any given step, they must have executed the same instruction and had the same previous hash. Consequently, the result of the current instruction and the previous hash are identical. Since the previous hash is also derived from the preceding instruction and its prior hash, we can infer that all previous instructions and their corresponding hashes are identical as well. Therefore, having the same hash at any step guarantees that all prior instructions and hashes in the sequence are the same, ensuring the integrity and consistency of the entire computation process.

Since hashes uniquely identify the results of each instruction, two parties executing the same instructions in the same order will produce identical cumulative hashes. By comparing these hashes, we can verify that both parties obtained the same results throughout the computation sequence.

First wrong step search

When verifying computations in BitVMX, the process begins by publishing a hash representing the final computational state to the blockchain, along with the input that generated it. This enables any observer to independently execute the same program with the provided input and verify whether their resulting hash matches the published one. Initially, only this final hash is made public, which allows verification of the end result but provides no insight into the intermediate steps.

In the verification process, we distinguish between two key participants: the prover and the verifier. The prover is the party who initially published both the input and the final hash, asserting their correct execution of the program. The verifier, on the other hand, takes on the responsibility of validating the accuracy of this execution. This clear distinction of roles establishes the framework for the verification protocol that follows.

When disagreements arise about the computation’s validity, it becomes crucial to identify the exact point where the discrepancy occurred. The protocol’s first procedure, therefore, focuses on locating the earliest step where two parties’ computations diverge. This precise identification of the first point of disagreement enables efficient resolution of computational disputes.

The execution of a program can involve billions of instructions, making it crucial to efficiently identify the first wrong step when verifications diverge. As established earlier, matching hashes at any point guarantee the equality of all preceding instructions. When a disagreement occurs with the final hash, we can employ an efficient binary search strategy. The prover initially shares strategic intermediate hashes that divide the total execution into intervals. This allows the verifier to identify the specific interval where the computation first diverged – marked by a correct hash at its lower bound but an incorrect hash at its upper bound. Once this interval is identified, the verifier selects it for further examination. The prover then provides additional intermediate hashes within this selected interval, effectively subdividing it. This recursive process continues, progressively narrowing down the search space until the exact point of divergence is located. This systematic approach transforms what could be an exhaustive search through billions of steps into a logarithmic-time operation.

Once the first point of divergence is identified, we have two consecutive steps: one where the hashes match between prover and verifier, and one where they differ. This transition point is crucial, as it pinpoints exactly where the computation began to diverge. To understand why this divergence occurred, we need to examine what constitutes an instruction in our system.

An instruction in BitVMX consists of several key components:

  • Inputs
    • read 1
      • address: address from where this value is read
      • value: value of the read
      • lastStep: last step in which this value was written
    • read 2
      • address: address from where this value is read
      • value: value of the read
      • lastStep: last step in which this value was written
    • read PC
      • address: address from where this value is read
      • opcode: opcode of the instruction
  • Outputs
    • write
      • address: address where this value is written
      • value: value of the write
    • write PC
      • address: address where the next opcode is stored

To better understand these instruction components, let’s break down how a computer processor works:

A computer processor is like a chef in a kitchen (memory). The chef (processor) follows a recipe (program) step by step, reading ingredients (input values) from different shelves (memory addresses) and creating new dishes (output values) that get stored back on specific shelves. Each instruction is one step in this recipe.

When executing an instruction:

  1. The processor reads values from specific memory addresses (the reads)
  2. Performs an operation based on the instruction (the opcode)
  3. Stores the result in another memory address (the write)

For example, if we want to add two numbers:

  • read 1 might get the value 5 from memory address 100
  • read 2 might get the value 3 from memory address 101
  • The opcode would be “add”
  • write would store the result (8) in memory address 102

Each instruction builds upon previous ones, as values written by earlier instructions can be read by later ones. This creates a chain of operations that transforms the initial memory state into the final computed result.

From the principles discussed above, the state of memory at any point can be determined by knowing two key elements: the initial memory state and the sequence of all write operations performed. When two parties have identical write operations up to a specific instruction, they must necessarily share the same memory state at that point. This fundamental property explains why the hash chain only needs to incorporate write operations. Understanding this concept, combined with our knowledge of virtual CPU behavior, enables us to design an effective procedure for identifying which party is acting incorrectly during a verification dispute.

Once the first incorrect step is identified, the prover must disclose the entire instruction, including both read and write values. The verifier can then examine all the values and challenge any of them. It is essential to develop a mechanism that enables the verifier to contest any value, including read values, and resolve the dispute definitively on-chain.

Value challenges

When examining the instruction data shared by the prover, the verifier has several options to challenge the computation’s validity. Each type of challenge focuses on a specific aspect of the instruction.

Hash challenge

A special case arises when all instruction components are correct, but the shared hash is wrong. This type of challenge focuses on verifying the hash computation itself. The verifier can compute the correct hash from the instruction data and demonstrate that it differs from the previously shared hash. To enable on-chain verification of such challenges, the Bitcoin script must be able to compute hashes directly. This requirement explains why the implementation of cryptographic hash functions like Blake3 and SHA-256 in Bitcoin script has been crucial for the BitVMX ecosystem.

Read/write address challenge

Each instruction’s opcode contains encoded information about both read and write addresses. This encoding serves as a blueprint for where the instruction should read from and write to in memory. Since these addresses are determined by the opcode itself, we can verify their correctness by examining the opcode. If any read or write address doesn’t match what the opcode specifies, we can challenge the instruction. If the opcode itself appears incorrect, that would require a separate opcode challenge rather than an address challenge.

lastStep challenge

When challenging an incorrect lastStep value, we need to consider two possible scenarios:

  1. If the provided lastStep is too high (later than the actual last write), we can examine the claimed lastStep instruction and show that this instruction either writes to a different address or doesn’t write at all. This proves the prover’s claim is false.
  2. If the provided lastStep is too low (earlier than the actual last write), we can find a more recent instruction that writes to this address. This proves the value should have come from this later instruction instead. Therefore, the prover’s lastStep was incorrect.

In both cases, we can definitively prove on-chain that the lastStep value was wrong, allowing the challenge to be verified by the Bitcoin script.

Read value challenge

When challenging a read value, we need to verify that the value matches what should have been in memory at that point. There are two possible cases:

  1. Initial memory values (lastStep = -1): The value being read was part of the program’s initial memory state. In this case, the correct initial values are stored in a Merkle tree within the challenge script. We can verify the claimed value against this Merkle tree, and if they don’t match, the challenge proves the prover provided an incorrect value.
  2. Previously written values (lastStep ≥ 0): The value should match what was written in the instruction referenced by lastStep. We can simply compare the claimed read value with the write value from that previous instruction. Any mismatch proves the prover provided an incorrect value.

Note that we can assume the read address and lastStep is correct at this point – if it weren’t, we would have used a previous challenge instead.

Second search process

For both lastStep and read value challenges, we often need to search through previous instructions to prove our case. This search process follows similar principles to our initial “first wrong step” search, but with a specific focus on finding relevant write operations.

The hash chain we established earlier becomes crucial here. When searching through previous instructions, the prover must share the relevant instruction data. Since each hash incorporates all previous operations, the prover can’t manipulate or hide historical data without detection.

The verification process begins when the verifier identifies a specific previous instruction they want to examine. The prover must then reveal that instruction’s complete data. If the prover attempts to share incorrect data, we can prove this deception through hash verification. By computing the correct hash using the real values and comparing it with the previously agreed-upon hash for that step, we can demonstrate the mismatch on-chain.

This mechanism ensures that any attempt to falsify historical instruction data will be detected through hash verification, making the challenge process robust and reliable.

Write value and write PC challenge

The correctness of write values (both data writes and program counter updates) can be verified by executing the instruction directly on-chain. This verification assumes that all read values and the opcode itself have already been validated through previous challenges.

To enable this verification, BitVMX implements each RISC-V opcode as a separate Bitcoin script. When a write value is challenged, the corresponding opcode’s script takes the read values as inputs, performs the computation, and verifies that the results match the prover’s claimed write values. This on-chain execution provides a definitive way to verify that the instruction’s outputs are correct, completing our suite of challenge mechanisms.

Read PC address and opcode challenge

The Program Counter (PC) serves as a pointer to the next instruction that should be executed. Each instruction’s write PC value naturally becomes the read PC value for the subsequent instruction. This creates a direct link between consecutive instructions in the execution chain.

Verifying the correctness of a read PC value becomes straightforward due to the hash chain mechanism we established earlier. When a verifier challenges a read PC value, they can require the prover to reveal both the previous instruction’s complete data and the two preceding hashes. Since both parties have already agreed on these hashes, the prover cannot manipulate this historical data. By examining the write PC value from the previous instruction, we can directly verify whether it matches the challenged read PC value in the current instruction. This creates an unbreakable chain of verification that ensures the program’s control flow remains intact and accurate.

Conclusion

BitVMX represents a significant advancement in Bitcoin’s computational capabilities, enabling the verification of arbitrary RISC-V programs directly on the Bitcoin blockchain. Through its innovative approach to optimistic verification and challenge-response mechanisms, BitVMX maintains Bitcoin’s security guarantees while substantially expanding its functionality.

Key takeaways from this guide include:

  1. BitVMX breaks down complex computations into individual instructions that can be verified independently
  2. The system uses hash chains to create cryptographic commitments of computation states
  3. A search process efficiently identifies the first point of divergence in disputed computations
  4. Multiple challenge mechanisms ensure the correctness of every aspect of instruction execution
  5. All verifications can be performed directly on-chain using Bitcoin script

This technology opens new possibilities for Bitcoin applications, from cross-chain bridges to complex smart contracts, all without requiring changes to the Bitcoin protocol. As the ecosystem continues to evolve, BitVMX demonstrates that Bitcoin’s perceived limitations can be overcome through innovative solutions that preserve its fundamental security model.

In Part 2 of this guide, we’ll explore practical examples of implementing BitVMX applications and dive deeper into specific use cases.

Recommended articles

From Hackathon Hustle to Big Ideas: Blinkz

From Hackathon Hustle to Big Ideas: Blinkz

By Carol E. –  Program Manager Developers across the world are pushing the boundaries of what’s possible on Bitcoin, and Rootstock is at the heart of that transformation. By providing an EVM-compatible environment secured by Bitcoin’s proof-of-work, Rootstock is taking its rightful place as the hub for innovation on Bitcoin. This is the first article […]

Developers
AnonMarket: Revolutionizing Privacy in Predictive Markets with Rootstock’s Infrastructure

AnonMarket: Revolutionizing Privacy in Predictive Markets with Rootstock’s Infrastructure

This article is part of the series “Real stories, Real builders” where we’ll share stories from developers who have built on Rootstock—what they created, why they chose it, how their projects are growing, and their advice for developers. Developers around the world are pushing the boundaries of what’s possible on Bitcoin, and Rootstock is taking […]

Developers
POWpeg Compostition Change: Enhancing Network Security

POWpeg Compostition Change: Enhancing Network Security

Summary: The Rootstock network will undergo a POWpeg change on block 7226594. Based on its current state, this is expected to occur on February 9th, 2025. Since the Bitcoin deposit address will change, it is strongly recommended that users verify the address before initiating any conversions from BTC to RBTC on the network. No further […]

Ecosystem