btcd源码解析 —— 签名机制(1) —— 基础知识

1. 写在前面

在前面的比特币源码分析中,我们有意忽略了签名机制部分的介绍。
但比特币的签名机制远非我们想象的那么简单,正如这篇博客Bitcoin contracts所言:

Bitcoin achieves high flexibility due to three features:

  1. scripts — unlocking funds in transactions is done using a simple scripting language,
  2. signature hash flags — indicate which parts of the transaction are signed,
  3. sequence numbers and lock time — mark transactions as not valid until specified time.

换句话说,正是因为不同签名格式(signature hash flags)的存在,才使得比特币的编程功能更加灵活多变。
接下来的三篇博客即从原理和源码两个角度来分析比特币的签名机制。
本篇博客先介绍基础知识,第二篇博客介绍签名流程的基本原理,第三篇博客btcd源码层面讲解签名流程。

源码分析所针对的btcd版本为: ed77733ec07dfc8a513741138419b8d9d3de9d2d

2. 签名流程简述

2.1. 签名的数目

我们知道一笔交易可能包含若干笔input和若干笔output。针对其中的每一笔input,都需要构造一个签名。也就是说,签名是逐input构建的。有多少个input,就要构建多少个签名。
P2PKH类型的锁定脚本为例,其格式为

DUP HASH160 <public key hash> EQUALVERIFY CHECKSIG

为花费该交易,需要在input中构建如下格式的解锁脚本:

<sig> <public key>

其中即为签名。

2.2. 签名的对象

构建签名的过程一般包含两个阶段:1)构建用于签名的消息(message);2)使用私钥对该消息进行签名。
后者不是我们这里关注的问题,我们主要关注这个message是由哪些内容组成的。
回顾第1章节,其中提到的"signature hash flags"即是用来指定交易的哪些部分用来组成message.

3. 签名类型介绍

3.1. 基本类型

“签名类型”,更准确地称为Signature Hash Types,主要包括4种基本类型:SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE, SIGHASH_ANYONECANPAY. 4种类型的简述如下表所示:

基本类型简单描述用途
SIGHASH_ALLmessage中包含所有的output默认类型,使用最为广泛
SIGHASH_NONEmessage中不包含任何output允许任何人通过构建output来花费这笔钱
SIGHASH_SINGLEmessage中包含特定 (对应input的) output保证自己的output不被篡改,但允许其他人的output被改动
SIGHASH_ANYONECANPAYmessage中包含当前input允许任何人构建input,也即允许任何人往交易里面输入金额

容易发现,前三者 (SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE)主要是用来对output进行限制,而SIGHASH_ANYONECANPAY是对input进行限制。在任何一次签名中,需要指定前三者中的一项,(可选择地)搭配使用SIGHASH_ANYONECANPAY进行修饰。

3.2. 组合类型

因此,组合后的签名类型可能出现下面两大类(无修饰类和有修饰类)6种情况:

分类组合类型简单描述用途
无修饰类SIGHASH_ALLmessage中包含所有的inputoutput默认类型,使用最为广泛
无修饰类SIGHASH_NONEmessage中包含所有的input,不包含任何output允许任何人通过构建output来花费这笔钱
无修饰类SIGHASH_SINGLEmessage中包含所有input和特定 (对应input的) output保证自己的output不被篡改,但允许其他人的output被改动
有修饰类SIGHASH_ALL | SIGHASH_ANYONECANPAYmessage中包含所有output和当前input常被用来做资金“众筹”
有修饰类SIGHASH_NONE | SIGHASH_ANYONECANPAYmessage中只包含当前input,不包含任何output允许任何人输入金额,也允许任何人花费金额
有修饰类SIGHASH_SINGLE | SIGHASH_ANYONECANPAYmessage中只包含当前input,和对应的output允许任何人输入金额,也保证对应的output不被篡改

容易看出,无修饰类的message是包含了所有input;而有修饰类的message只包含了当前input.
更详细的内容,可以参考比特币开发指南.

3.3. 源码&字节码分析

3.3.1. 定义

btcd中和签名基本类型相关的定义如下所示:

// script.go
type SigHashType uint32

const (      
    SigHashOld                  SigHashType = 0x0      
    SigHashAll                   SigHashType = 0x1     
    SigHashNone                SigHashType = 0x2      
    SigHashSingle               SigHashType = 0x3      
    SigHashAnyOneCanPay   SigHashType = 0x80      
    
    // sigHashMask defines the number of bits of the hash type which is used      
    // to identify which outputs are signed.      
    sigHashMask = 0x1f
)

其中SigHashOld是弃用的类型了,其和SigHashAll功能完全相同。
可见四种基本类型都只占用一个字节。SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE可与SigHashAnyOneCanPay进行位操作,从而实现组合类型。不同组合类型和字节码如下所示:

分类组合类型字节码
无修饰类SIGHASH_ALL0x01
无修饰类SIGHASH_NONE0x02
无修饰类SIGHASH_SINGLE0x03
有修饰类SIGHASH_ALL | SIGHASH_ANYONECANPAY0x81
有修饰类SIGHASH_NONE | SIGHASH_ANYONECANPAY0x82
有修饰类SIGHASH_SINGLE | SIGHASH_ANYONECANPAY0x83
3.3.2. 举例

我们以比特币主网上的交易737ec67db90553cf2c3fda6e241e7c4d759ee7636d877f7c24017ecbd62b5792为例,介绍一下签名类型字节码在交易中的位置。
从比特币浏览器BTC.com中容易查询到该交易的输入输出和输入脚本分别如下所示:
输入输出
输入脚本
其中每一笔输入的输入脚本都是用来解锁一笔P2PKH输出的,且签名类型都是SIGHASH_ALL | SIGHASH_ANYONECANPAY.
以第一笔input为例,其输入脚本可被解析如下:

字节码含义
47OP_PUSHDATA47
30表示DER序列的开始
44序列的长度(68字节)
02表示接下来是一个整数值
20表示接下来这个整数的长度
207ab184b288275c6466075d724a9f632487b6996489d49c8148cf30f9d5fc1aDER编码中的R
02表示接下来是一个整数值
20表示接下来这个整数的长度
518b62471a25f8da86d0184de5b0496d4c2b272115c84fa58ea32e568b53053dDER编码中的S
81表示签名类型
21OP_PUSHDATA21
032153889b1813175f337f24944ff632a6b9a78b63e09ff8c6a569f5d5d429cf97公钥

关于签名数据的解析,可以结合博客理解比特币的raw transaction (1) P2PKH类型输出和电子书《Mastering Bitcoin (2nd Edition)》Serialization of signatures (DER)部分,深入理解。
重点关注表格中加粗的“81”,其表示当前的签名类型是SIGHASH_ALL | SIGHASH_ANYONECANPAY.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用: 如果要使用docker容器中的btc节点,请取消注释fdocker-compose文件的btcd-testnet部分,并在cmd/multy.config BTCNodeAddress字段中设置其地址。 引用:通过统一的界面获取300多种加密货币的钱包余额。 与:可选的API密钥支持,用TypeScript编写,使用node-fetch而不是弃用的request,较小的图书馆。 根据以上引用内容,btc钱包 node是指在docker容器中的btc节点,可以通过设置docker-compose文件中的btcd-testnet部分,并在cmd/multy.config 的BTCNodeAddress字段中设置节点的地址获取。该节点可以用于获取多种加密货币的钱包余额,并且支持可选的API密钥。这个节点是用TypeScript编写的,并使用了node-fetch库,相对较小。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [Multy-back:Multy的后端-移动Multy区块链钱包](https://download.csdn.net/download/weixin_42134168/14974063)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [balance-crypto:with通过统一的界面获取300多种加密货币的钱包余额](https://download.csdn.net/download/weixin_42169245/15910733)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值