该BIP(比特币改进提案)提出了“Merklized Script”的概念,旨在通过使用 Merkle 树编码脚本中的互斥分支,实现更复杂的赎回条件,提高隐私性,并允许包含非共识强制数据。它通过 Merkle 根编码互斥的条件脚本分支,从而减少赎回栈的大小,并实现 O(log n) 的可扩展性。
从 bitcoin/bips fork
vault
搜索此仓库
/
复制路径
BlameMore 文件操作
BlameMore 文件操作
更新 BIP114 并添加与 Merklized Script Version 0 相关的 BIP
2017年9月8日
ce4a698 · 2017年9月8日
打开提交详情
191 行 (131 loc) · 16.9 KB
/
顶部
预览
代码
Blame
191 行 (131 loc) · 16.9 KB
复制原始文件
下载原始文件
大纲
编辑和原始操作
BIP: 114
Layer: Consensus (soft fork)
Title: Merklized Script
Author: Johnson Lau <jl2012@xbt.hk>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0114
Status: Draft
Type: Standards Track
Created: 2016-04-02
License: BSD-3-Clause
CC0-1.0
## 目录<br>永久链接: 目录<br>- 摘要<br>- 动机 <br> - 比特币脚本系统的演变<br> - 见证中的附加脚本<br>- 规范 <br> - Merklized Script <br> - Merklized Script Version 0<br> - MSV0 中的新脚本功能<br> - 可升级性<br>- 原理<br>- 示例 <br> - 脚本 Merkle 根的计算<br> - 不平衡 एमएस<br> - 带超时的 Escrow<br> - 哈希时间锁合约<br> - 大型多重签名结构<br> - 额外数据的承诺<br>- 向后兼容性<br>- 部署<br>- 鸣谢<br>- 参考实现<br>- 参考<br>- 版权 |
此 BIP 定义了一种新的见证程序类型,该类型使用 Merkle 树来编码脚本中互斥的分支。 这使得当前不可能实现的复杂赎回条件成为可能,通过隐藏未执行的脚本来提高隐私性,并允许以非常低或零的额外成本包含非共识强制执行的数据。
比特币使用脚本系统来指定交易输出的赎回条件。 在其原始设计中,赎回条件由资金发送者直接记录在 scriptPubKey 中。 这种模式有几个缺点,特别是对于复杂的脚本:
BIP16(Pay-to-script-hash,“P2SH”)通过在 scriptPubKey 中使用固定长度的 20 字节脚本哈希并将提供脚本的责任转移给赎回者来解决前 3 个问题。 但是,由于脚本中的数据推送大小限制,P2SH 脚本的大小可能不超过 520 字节。 此外,P2SH 仍然要求赎回者发布脚本的所有未执行分支。
BIP141 定义了 2 种支持隔离见证的新脚本类型。 pay-to-witness-script-hash (P2WSH) 在许多方面与 P2SH 相似。 通过在见证中提供脚本,P2WSH 恢复了原始的 10,000 字节脚本限制。 但是,它仍然需要发布未执行的分支。
Merkelized Abstract Syntax Tree (MAST) 的想法是使用 Merkle 树来编码脚本中的操作。 在花费时,用户可能只提供他们正在执行的分支,以及将分支连接到固定大小 Merkle 根的哈希值。 这将赎回栈的大小从 O(n) 减少到 O(log n)(n 作为操作的数量)。 这使得由于脚本大小和操作码限制而当前不可能实现的复杂赎回条件成为可能,通过隐藏未执行的分支来提高隐私性,并允许以非常低或零的额外成本包含非共识强制执行的数据。
此提案是简化且特殊的 MAST 案例。 Merkle 根不是编码单个操作,而是编码互斥的条件脚本分支。 尽管这不是 MAST 的完整实现,但它提供了相同级别的隐私和 O(log n) 可扩展性。
在比特币的原始设计中,允许用户在 scriptSig
中包含功能性脚本(即,不仅仅是数据推送)。 然而,由于密钥持有者没有签署脚本的机制,这种设计没有带来任何功能,而是可延展性的来源 (BIP62)。 当通过 BIP141 引入隔离见证时,也不可能在见证中包含其他脚本。
然而,通过适当的设计,允许在交易输入中添加其他脚本可能会允许现有系统无法实现的功能。 例如,密钥持有者可以委托花费权给其他密钥,无论是否附加其他条件,例如锁定时间。 它也可以与其他提议的功能一起使用,例如检查区块哈希,这在创建输出时可能未知。
本提案定义了一种机制,允许将此类附加脚本作为见证的一部分。 在 BIPYYY 中进一步定义,以确保此类脚本不是第三方可延展的。
在 BIP141 中,版本字节为 1 或更大的见证程序被认为是任何人都可以花费的脚本。 如果见证程序版本字节为 1 并且程序大小为 32 字节,则应用以下新验证规则。 见证程序是 Script Merkle Root
(定义如下)。
要赎回这种输出,见证必须至少包含 3 个项目。
Key Code
是最后一个见证项目。 它必须不小于 33 个字节,但没有上限。 Key Code Hash
是 Key Code
的单个 SHA256 值
Path
是倒数第二个见证项目。 它是 Key Code Hash
的序列化 Merkle 路径。 Path
的大小必须是 32 字节的倍数,并且必须不大于 1024 字节。 每个 32 字节的字都是连接到 Script Merkle Root
的 Merkle 分支中的双 SHA256 Merkle 节点(或者,如果它是另一个 Key Code Hash
的哈希值,则为单个 SHA256)。 树的 Depth
(0 到 32) 是 Path
的大小除以 32。
Position
是倒数第三个见证项目。 它指示 Key Code Hash
在 Merkle 树中的位置,0 表示最左边的位置。 它是带符号的 CScriptNum
整数。 Position
必须按照 BIP62 中的描述进行最小编码,非负数,并且必须不大于树的 Depth
允许的最大项目数。 例如,如果 Depth
为 4,则 Position
的有效范围为 0 到 15 (24-1)。
Script Merkle Root
是由 ComputeMerkleRootFromBranch
函数计算的 Merkle 根,使用 Key Code Hash
、Path
和 Position
。
如果 Script Merkle Root
与见证程序不匹配,则脚本评估失败。
永久链接: Merklized Script Version 0
如果 Key Code
的第一个字节是 0,则将其解释为 Merklized Script Version 0 (MSV0
) 并进一步处理。
Key Code Hash
、Path
和 Position
从见证栈中移除。 剩余的栈必须至少有 1 个项目,否则评估失败。
最后一个见证栈项目是 nScriptWitCode
,它必须是 0 到 5 的最小编码值,否则评估失败。
排除 nScriptWitCode
项目,剩余的栈项目数必须不小于值 nScriptWitCode
,否则评估失败。
如果 nScriptWitCode
不为 0,则 nScriptWitCode
之前的见证项目是 scriptWitCode0
,scriptWitCode0
之前的项目是 scriptWitCode1
,依此类推。 最高索引 scriptWitCode
的大小不得为 0(在这种情况下,应使用较小的nScriptWitCode
值,并省略大小为 0 的 scriptWitCode
)。
未使用的栈项目(如果有)将被视为脚本评估的 Input Stack
。
scriptWitCode
(如果有)会一个接一个地进行评估,从索引最高的那个开始。 scriptKeyCode
是删除了前导 0 版本字节的 Key Code
。 所有 scriptWitCode
之后评估 scriptKeyCode
。
类似于评估旧版 scriptSig
和 scriptPubKey
:
OP_IF
、OP_NOTIF
、OP_ELSE
和 OP_ENDIF
)必须在每个脚本中单独平衡scriptWitCode
和 scriptKeyCode
必须不能失败类似于评估版本 0 见证脚本:
Input Stack
项目的大小必须不大于 520 字节TRUE
项目Opcode
之后,栈和 altstack 项目的总数必须不高于 1000在以下任一条件下,评估也必须失败:
scriptWitCode
和 scriptKeyCode
(不带前导 0 版本字节)的总大小大于 10,000 字节scriptWitCode
和 scriptKeyCode
的非推送操作(nOpCount
)的总数超过 201。 值等于或高于 0x61
的每个 Opcode
,除了 OP_CHECKMULTISIG
和 OP_CHECKMULTISIGVERIFY
之外,都计为 1 个 nOpCount
。 对于 m-of-n OP_CHECKMULTISIG
和 OP_CHECKMULTISIGVERIFY
,它们 被计为 m+1 个 nOpCount
。 [ 1]新的脚本功能在 MSV0
中引入,在不同的 BIP 中描述。
BIPVVV 描述了 pay-to-witness-public-key (P2WPK
),如果花费输出的唯一条件是来自单个公钥的签名,则这是一种使用 MSV0
所有功能的更有效方式。
BIPWWW 描述了重新启用和重新定义禁用的字符串和按位运算,包括 OP_CAT
、OP_LEFT
、OP_RIGHT
、OP_SUBSTR
、OP_INVERT
、OP_AND
、OP_OR
、OP_XOR
、OP_RSHIFT
和 OP_LSHIFT
。
BIPXXX 描述了重新启用和重新定义禁用的数值运算,包括 OP_2MUL
、OP_MUL
、OP_2DIV
、OP_DIV
、OP_MOD
以及重新定义现有的数值运算,包括 OP_CHECKLOCKTIMEVERIFY
、OP_CHECKSEQUENCEVERIFY
、OP_1ADD
、OP_1SUB
、OP_NEGATE
、OP_ABS
、OP_NOT
、OP_0NOTEQUAL
、OP_ADD
、OP_SUB
、OP_BOOLAND
、OP_BOOLOR
、OP_NUMEQUAL
、OP_NUMEQUALVERIFY
、OP_NUMNOTEQUAL
、OP_LESSTHAN
、OP_GREATERTHAN
、OP_LESSTHANOREQUAL
、OP_GREATERTHANOREQUAL
、OP_MIN
、OP_MAX
和 OP_WITHIN
。
BIPYYY 描述了 OP_CHECKSIG
、OP_CHECKSIGVERIFY
、OP_CHECKMULTISIG
和 OP_CHECKMULTISIGVERIFY
的重新定义,以及新 OP_CHECKSIGFROMSTACKVERIFY
的引入。
BIPZZZ 描述了新 OP_PUSHTXDATA
的引入。
如果见证程序版本字节为 1,但程序大小既不是 32 也不是 33 字节,则脚本返回成功而不进行进一步评估。
对于 Merklized Script,如果 Script Merkle Root
匹配,但 Key Code
的第一个字节不是 0,则脚本返回成功而不进行进一步评估。
在这些情况下,SigOpsCost
计为 0。
最小 33 字节大小要求和对 Key Code
使用单 SHA256: 如果双 SHA256 用于哈希 Key Code
和 64 字节的连接 Merkle 哈希,如果任何连接的哈希是有效的 Key Code
,则输出可能会被盗。 另一方面,如果单 SHA256 用于 Key Code
,而双 SHA256 用于连接的 Merkle 哈希,如果任何连接的哈希的单 SHA256 是有效的 Key Code
,则输出可能会被盗。 通过拒绝任何 32 字节的 Key Code
,足以避免后一种情况。 然而,由于压缩公钥大小为 33 字节,因此很明显,任何小于 33 字节的 Key Code
要么无效,要么任何人都可以花费 [ 2]。 因此,拒绝任何小于 33 字节的 Key Code
不会损失任何功能。
在 Key Code
的开头标记 Merklized Script 版本: Merklized Script 版本可以在 scriptPubKey
或 witness
中标记,但 witness
占用的区块空间更少。 此外,在 Key Code
中标记意味着我们可以在一个输出中混合使用不同版本的脚本,如果隐藏了特殊脚本版本的使用,这可以提高隐私性。
scriptWitCode
设计: scriptWitCode
设计允许输出的密钥持有者包含其他脚本。 在 BIPYYY 中对其进行了进一步描述。
(待完成)
在构造 MS 时,如果用户认为某些分支更有可能被执行,他们可能会将它们更靠近 Script Merkle Root
。 当实际执行首选分支时,它将节省一些见证空间。 例如,在支付通道构造中,“合作”脚本比“非合作”脚本更有可能被执行。
以下是 BIP112 中的“带超时的 Escrow”示例:
IF
2 <Alice's pubkey> <Bob's pubkey> <Escrow's pubkey> 3 CHECKMULTISIG
ELSE
"30d" CHECKSEQUENCEVERIFY DROP
<Alice's pubkey> CHECKSIG
ENDIF
使用压缩公钥,此脚本的大小为 150 字节。
使用 MSV0,此脚本可以分解为 2 个互斥的分支:[ 3]
2 <Alice's pubkey> <Bob's pubkey> <Escrow's pubkey> 3 CHECKMULTISIG (105 字节)
"30d" CHECKSEQUENCEVERIFY <Alice's pubkey> CHECKSIG (42 字节)
由于只会发布一个分支,因此区块链分析师更难确定托管的详细信息。
以下是 BIP112 中的“哈希时间锁合约”示例:
HASH160 DUP <R-HASH> EQUAL
IF
"24h" CHECKSEQUENCEVERIFY
2DROP
<Alice's pubkey>
ELSE
<Commit-Revocation-Hash> EQUAL
NOTIF
"Timestamp" CHECKLOCKTIMEVERIFY DROP
ENDIF
<Bob's pubkey>
ENDIF
CHECKSIG
使用 MSV0,它被展平为 3 个互斥的分支:
HASH160 <R-HASH> EQUALVERIFY "24h" CHECKSEQUENCEVERIFY <Alice's pubkey> CHECKSIG
HASH160 <Commit-Revocation-Hash> EQUALVERIFY <Bob's pubkey> CHECKSIG
"Timestamp" CHECKLOCKTIMEVERIFY <Bob's pubkey> CHECKSIG
这大大提高了可读性,并减少了赎回时的见证大小。
当前的 OP_CHECKMULTISIG
最多支持 20 个公钥。 尽管可以通过使用多个 CHECKSIG 将其扩展到 20 个密钥以上,但构造可能非常复杂,并且很快就会用完 10,000 字节和 201 个 nOpCount
限制。
使用 MSV0,大型且复杂的多重签名结构可以展平为许多简单的 OP_CHECKMULTISIG
条件。 例如,3-of-2000 多重签名方案可以表示为 1,331,334,000 个 3-of-3 OP_CHECKMULTISIG
, 形成一个 31 级 MS。 scriptPubKey 仍然保持 34 字节的固定大小,并且赎回见证将非常紧凑,小于 1,500 字节。
目前,在 scriptPubKey 中提交额外数据需要使用 OP_RETURN
,这会占用额外的区块空间。 使用 MS,用户可以将此类数据作为分支提交。 根据可执行分支的数量,包含此类承诺可能不会产生额外的见证空间,或者最多 32 个字节。
一个有用的案例是指定“消息签名密钥”,这些密钥对于花费无效,但允许用户在不接触冷存储“资金密钥”的情况下签署任何消息。
作为软分叉,旧软件将继续运行而无需修改。 但是,未升级的节点会将 Merklized Script 和 P2WPKV0
程序视为任何人都可以花费的脚本。 钱包应始终警惕任何人都可以花费的脚本,并谨慎对待它们。
确切细节待定。
Merklized script 基于 Merklized Abstract Syntax Tree 的思想,该思想起源于 Russell O’Connor、Pieter Wuille 和 Peter Todd。
https://github.com/jl2012/bitcoin/commits/vault
本文档已获得 BSD 3-clause 和 Creative Commons CC0 1.0 Universal 的双重许可。
- 原文链接: github.com/jl2012/bips/b...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!