虽然数字签名能够满足普通的交易需求,但没有太多扩展性。比特币中创建了一种脚本语言,来满足交易中的一些多样性的需求,如:
- 制造一枚的在指定时间才能使用比特币
- 制造一枚任何人可以花费的比特币
- 作废一枚比特币
比特币脚本
比特币脚本是一种基于栈(Stack)的、从左到右运行的、非图灵的脚本语言,用于校验交易。
栈是一种数据结构,只有两种基本操作:push 和 pop:
- push:将数据放入栈的顶端。
- pop:将栈的顶端的数据推出。
脚本会从左到右执行,每次操作都会修改全局的栈。如果执行完成后,没有错误且栈顶的值为真,那么就交易校验通过,否则交易校验不通过。一个最简单的例子是:
OP_0 OP_1 OP_ADD
栈 | 脚本 | 描述 |
---|---|---|
空 | OP_0 OP_1 OP_ADD | script 的含义是 0 + 1 |
0 | OP_1 OP_ADD | 将 0 push 到 stack 中 |
0 1 | OP_ADD | 将 1 push 到 stack 中 |
1 | 空 | pop 两个 stack 的值,并进行相加,然后结果 push 到 stack 中 |
该 script 运行的结果是 1,因此通过了验证通过。
锁定脚本与解锁脚本
用于验证交易是否通过的脚本由两部分组成:
- 解锁脚本:本次交易的 input 中的 scriptSig
- 锁定脚本:上次交易的 output 中的 scriptPubKey
在比特币交易的最初的设计中,使用的是 pay-to-pubkey。那时候,并没有引入地址 address 的概念。验证交易是否合法,就是验证由 scriptSig 脚本和
scriptPubKey 组成的脚本执行结果是否为 1。
scriptSig: <sig>
scriptPubKey: <pubKey> OP_CHECKSIG
栈 | 脚本 | 描述 |
---|---|---|
空 | <sig> <pubKey> OP_CHECKSIG | 将 scriptSig 和 scriptPubKey 结合成脚本 |
<sig> <pubKey> | OP_CHECKSIG | 将 <sig> <pubKey> push 到 stack 中 |
1 | OP_CHECKSIG | pop stack 顶端的连个参数,并使用数字签名验证函数验证,并将结果 push 到 stack 中。 |
这种 pay-to-pubkey 脚本,在上一笔交易中就将电子货币所有者的公钥暴露出来了,这降低了数字签名的安全性。比如,可以利用提早暴露公钥,暴力来破解私钥。
checkSig(pubKey, tryToKnowPrivateKey)
P2PKH(Pay-to-Public-Key-Hash)
为了解决提前暴露公钥带来的安全性隐患,BitCoin Core 团队引入了地址 Address 的概念。比特币网络处理的大多数交易都是 P2PKH 这种模式。
scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
scriptSig: <sig> <pubKey>
栈 | 脚本 | 描述 |
---|---|---|
空 | <sig> <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG | 将 scriptSig 和 scriptPubKey 结合成脚本 |
<sig> <pubKey> | OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG | 将 <sig> <pubKey> push 入栈 |
<sig> <pubKey> <pubKey> | OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG | 复制一份栈顶的值 |
<sig> <pubKey> <pubHashA> | <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG | 对栈顶的值进行一次 hash160 运算 |
<sig> <pubKey> <pubHashA> <pubKeyHash> | OP_EQUALVERIFY OP_CHECKSIG | 将 <pubKeyHash> push 入栈 |
<sig> <pubKey> | OP_CHECKSIG | 判断栈顶的两个值是否相等 |
true | 空 | 使用数字签名验证函数验证栈顶的两个值 |
脚本带来的多样性
由于脚本的存在,所以比特币交易的多样性就变得更多了,比如
- 制造一枚的在指定时间才能使用比特币
scriptPubKey: <expiry time> OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
scriptSig: <sig> <pubKey>
- 制造一枚任何人可以花费的比特币
scriptPubKey: (empty)
scriptSig: OP_TRUE
- 作废一枚比特币
scriptPubKey: OP_RETURN {zero or more ops}
总结
- 比特币脚本用于校验交易
- 比特币脚本包括:scriptSig 和 scriptPubKey
- 比特币脚本常用的是 P2PKH 模式
JavaScript implementation of Script, Bitcoin's scripting language.