Bitcoin Script
Qué es Bitcoin Script
Bitcoin Script es el lenguaje de programación que utiliza Bitcoin para especificar las condiciones que deben cumplirse para gastar un UTXO. A diferencia de los lenguajes de propósito general, Script está diseñado con un objetivo muy concreto: validar transferencias de valor de forma segura, determinista y verificable por cualquier nodo de la red.
Script fue introducido por Satoshi Nakamoto en el código original. Es un lenguaje basado en pila (stack-based), similar en espíritu a Forth, donde las instrucciones (opcodes) operan sobre valores que se apilan y desapilan durante la ejecución. No tiene variables, ni bucles, ni acceso a estado externo.
Por qué no es Turing-completo (y por qué esto es una característica)
Script no permite bucles ni recursión. Esta limitación es intencional y profundamente importante:
- Predecibilidad del costo de validación: cualquier nodo puede determinar antes de ejecutar un script cuántos recursos consumirá, evitando ataques de denegación de servicio.
- Determinismo: el resultado de ejecutar un script es idéntico en todos los nodos del mundo.
- Auditabilidad: un lenguaje simple es más fácil de razonar, revisar y formalizar. Cuantas menos primitivas, menor la superficie de ataque.
En palabras de la comunidad: "Script hace pocas cosas, pero las hace bien y para siempre".
scriptSig y scriptPubKey
Cada gasto de un UTXO involucra dos scripts:
- scriptPubKey (locking script): está en el UTXO que se quiere gastar. Define las condiciones para desbloquearlo.
- scriptSig (unlocking script): lo proporciona quien intenta gastar el UTXO. Contiene firmas, claves públicas o cualquier dato necesario para satisfacer el scriptPubKey.
Se ejecutan secuencialmente: primero el scriptSig deja datos en la pila, luego el scriptPubKey los consume y valida.
Tipos de scripts estándar
| Tipo | Descripción | Dirección |
|---|---|---|
| P2PK | Pay-to-PubKey. Formato original; hoy obsoleto. | (sin estándar) |
| P2PKH | Pay-to-PubKey-Hash. Formato dominante durante años. | 1... |
| P2SH | Pay-to-Script-Hash (BIP-16). Permite multisig y contratos arbitrarios. | 3... |
| P2WPKH | SegWit v0 nativo: versión compacta de P2PKH. | bc1q... (20B) |
| P2WSH | SegWit v0 nativo: versión compacta de P2SH. | bc1q... (32B) |
| P2TR | Taproot (BIP-341). Schnorr + MAST. Máxima eficiencia y privacidad. | bc1p... |
Opcodes clave
OP_DUP: duplica el elemento en la cima de la pila.OP_HASH160: aplica SHA-256 seguido de RIPEMD-160.OP_EQUALVERIFY: compara los dos elementos superiores; si difieren, aborta.OP_CHECKSIG: verifica una firma contra una clave pública y la transacción actual.OP_CHECKMULTISIG: verifica N firmas contra M claves (multisig clásico).OP_CHECKLOCKTIMEVERIFY(CLTV, BIP-65): timelock absoluto.OP_CHECKSEQUENCEVERIFY(CSV, BIP-112): timelock relativo.OP_RETURN: marca un output como inservible y permite adjuntar hasta 80 bytes de datos arbitrarios.
Ejemplo: ejecución paso a paso de un P2PKH
scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
scriptSig aportado por quien gasta: <sig> <pubKey>
- Empujar
<sig>→ pila:[sig] - Empujar
<pubKey>→ pila:[sig, pubKey] OP_DUP→ pila:[sig, pubKey, pubKey]OP_HASH160→ pila:[sig, pubKey, HASH160(pubKey)]- Empujar
<pubKeyHash>→ pila:[sig, pubKey, HASH160(pubKey), pubKeyHash] OP_EQUALVERIFY: compara los dos superiores. Si no coinciden, aborta → pila:[sig, pubKey]OP_CHECKSIG: verifica que sig es firma válida de pubKey sobre la transacción → pila:[true]
Al quedar true, el script es válido y el UTXO puede gastarse.
Tapscript (BIP-342)
Con Taproot llegó Tapscript: una versión actualizada del lenguaje que incorpora firmas Schnorr, reemplaza OP_CHECKMULTISIG por OP_CHECKSIGADD (más flexible y barato), elimina límites obsoletos, y reserva espacio para futuros opcodes mediante OP_SUCCESS, facilitando soft-forks posteriores.
Por qué el conservadurismo en Script es una decisión de seguridad
Bitcoin ha añadido muy pocos opcodes en su historia y ha desactivado varios que existían originalmente (OP_CAT, OP_MUL, OP_SUBSTR) tras descubrirse vectores de ataque. Cada opcode que se añade es un compromiso permanente: los errores no pueden revertirse sin un hard fork. Por eso cualquier propuesta atraviesa años de revisión antes de activarse en mainnet.
Errores habituales
- Creer que Bitcoin Script debería ser Turing-completo: su limitación es una decisión de diseño deliberada, no una carencia.
- Confundir scriptSig con una firma: el scriptSig puede contener firmas, claves, preimágenes o cualquier dato necesario.
- Pensar que Taproot reemplaza a Script: Tapscript coexiste con Script y se activa solo cuando se gasta por la rama de script.
- Asumir que P2SH revela el script al recibir fondos: el redeemScript solo se revela al gastar, no al recibir.
- Usar OP_RETURN creyendo que los datos quedan fuera de la blockchain: están en cadena, pero el output es inservible como UTXO.
Conceptos relacionados
Fuentes primarias
- Bitcoin Wiki: Script (en.bitcoin.it/wiki/Script)
- Andreas Antonopoulos, Mastering Bitcoin (2ª ed.), Capítulo 6
- BIP-16 (P2SH), BIP-141 (SegWit), BIP-341 (Taproot), BIP-342 (Tapscript)
- Jimmy Song, Programming Bitcoin, Capítulos 6 y 8