脚本格式

P2PKH的锁定脚本为:

OP_DUP OP_HASH160 PUSHDATA(<Cafe Public Key Hash>) OP_EQUALVERIFY OP_CHECKSIG

P2PKH的解锁脚本为:

PUSHDATA(<Cafe Signature>) <Cafe Public Key>

脚本参数解释

脚本中的常量值

OP_DUP=0x76
OP_HASH160=0xA9
OP_EQUALVERIFY=0x88
OP_CHECKSIG=0xAC

PUSHDATA

PUSHDATA封装格式为:

如果0 < data.length < 76(0x4C),则结果为:1个字节data.length + data数据
如果76(0x4C) <= data.length < 2^8,则结果为:0x4C + 1个字节data.length + data数据
如果2^8 <= data.length < 2^16,则结果为:0x4D + 2个字节data.length + data数据
如果2^16 <= data.length < 2^32,则结果为:0x4E + 4个字节data.length + data数据

Signature的格式

Signature的格式为DER(r,s) + SIGHASH

DER的封装格式

DER是ASN1数据格式中的一种,DER的封装规则还没有搞太明白,但是数据结构可解,开头是固定值0x30,后面0x45为后续数据长度,0x0220或者0x022100后面就是签名值r和s。

DER的java代码实现:

private static byte[] toDER(BigInteger r, BigInteger s) {
ByteArrayOutputStream bos = new ByteArrayOutputStream(72);
DERSequenceGenerator seq = null;
byte[] res = new byte[0];
try {
seq = new DERSequenceGenerator(bos);
seq.addObject(new ASN1Integer(r));
seq.addObject(new ASN1Integer(s));
seq.close();
res = bos.toByteArray();
return res;
} catch (IOException e) { }
return null;
}

SIGHASH

SIGHASH是签名哈希类型。

比特币签名具有指示交易数据的哪一部分包含在使用 SIGHASH 标志的私钥签名的哈希中的方式。SIGHASH 标志是附加到签名的单个字节。 每个签名都有一个SIGHASH标志,该标志在不同输入之间也可以不同。 具有三个签名输入的交易可以具有不同SIGHASH标志的三个签名,每个签名签署(承诺)交易的不同部分。

记住,每个输入可能在其解锁脚本中包含一个签名。 因此,包含多个输入的交易可以拥有具有不同SIGHASH标志的签名,这些标志在每个输入中承诺交易的不同部分。 还要注意,比特币交易可能包含来自不同“所有者”的输入,他们在部分构建(和无效)的交易中可能仅签署一个输入,继而与他人协作收集所有必要的签名后再使交易生效。 许多SIGHSASH标志类型,只有在你考虑到由许多参与者在比特币网络之外共同协作去更新仅部分签署了的交易,才具有意义。

有三个SIGHASH标志:ALL,NONE和SINGLE,如下表所示。

另外还有一个修饰符标志SIGHASH_ANYONECANPAY,它可以与前面的每个标志组合。 当设置ANYONECANPAY时,只有一个输入被签名,其余的(及其序列号)打开以进行修改。 ANYONECANPAY的值为0x80,并通过按位OR运算,得到如下所示的组合标志:

SIGHASH标志在签名和验证期间应用的方式是建立交易的副本和删节其中的某些字段(设置长度为零并清空),继而生成的交易被序列化,SIGHASH标志被添加到序列化交易的结尾,并将结果哈希化 ,得到的哈希值本身即是被签名的“消息”。 基于SIGHASH标志的使用,交易的不同部分被删节。 所得到的哈希值取决于交易中数据的不同子集。 在哈希化前,SIGHASH作为最后一步被包含在内,签名也会对SIGHASH类型进行签署,因此不能更改(例如,被矿工)。

Public Key

Public Key有两种表示方式,分别是非压缩格式和压缩格式,这两种方式算出来的比特币地址不同,所以不能混用。

压缩格式就是数据中只有公钥的X,没有Y。压缩公钥以0x21开头,0x02或0x03代表Y值在X轴的上方还是下方,后面是X点的数据(32 bytes)。示例:

21 03 0b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478

非压缩格式的数据,开头是0x41,0x04,后面紧跟着X点的数据(32 bytes)和Y点的数据(32 bytes)。示例:

41 04
0bf69616981e5970c992a0762f441abcadfed9fc4630fa5e1b82ab00e81d1690 // X
5d3820e073e1bd4a9dcfed336f4bf25edc634c2e174989767d299748359c2daf // Y

示例

比特币testnet的一笔交易示例:912d470a1178ac09e31c43ee5696138fc51e94c7834864ed5c8eff29e5f54370

通过blockcypher的API接口可以拿到更加详细的JSON数据

这笔交易的JSON返回数据:

{
"block_hash": "000000003b5f089b739219d8f40ec34ca66b051c627cbb8e5d7a3dd031ff47d2",
"block_height": 1298300,
"block_index": 1,
"hash": "912d470a1178ac09e31c43ee5696138fc51e94c7834864ed5c8eff29e5f54370",
"hex": "010000000184f3684abd720033ff7a7654b48936088cd22c8d9e96d3a12e64559562e0fd93000000006b483045022100ea03e8414011fffc00f10a25a771076ee1cb4b0b24a02607c67462009e3d2c1d022070a7a1c74e6bb71c32d78043bccf7bbc353334eb6e517162b2270c85d6bb54d20121030b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478ffffffff0100a92d01000000001976a914d9c637cc30bb0fe9add3a185c1f5d884d12b7b7888ac00000000",
"addresses": [
"mv24N7xJZySdMrLeQHvKTJYWmRyv9DY82Q",
"n1NSP78VQ5iZqVVRMA9ZZ2r77eeGLnwdj8"
],
"total": 19769600,
"fees": 134400,
"size": 192,
"preference": "high",
"relayed_by": "35.205.92.62:18333",
"confirmed": "2018-05-22T03:22:51Z",
"received": "2018-05-22T03:18:51.259Z",
"ver": 1,
"double_spend": false,
"vin_sz": 1,
"vout_sz": 1,
"confirmations": 1,
"confidence": 1,
"inputs": [
{
"prev_hash": "93fde0629555642ea1d3969e8d2cd28c083689b454767aff330072bd4a68f384",
"output_index": 0,
"script": "483045022100ea03e8414011fffc00f10a25a771076ee1cb4b0b24a02607c67462009e3d2c1d022070a7a1c74e6bb71c32d78043bccf7bbc353334eb6e517162b2270c85d6bb54d20121030b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478",
"output_value": 19904000,
"sequence": 4294967295,
"addresses": [
"mv24N7xJZySdMrLeQHvKTJYWmRyv9DY82Q"
],
"script_type": "pay-to-pubkey-hash",
"age": 1298299
}
],
"outputs": [
{
"value": 19769600,
"script": "76a914d9c637cc30bb0fe9add3a185c1f5d884d12b7b7888ac",
"addresses": [
"n1NSP78VQ5iZqVVRMA9ZZ2r77eeGLnwdj8"
],
"script_type": "pay-to-pubkey-hash"
}
]
}

解析交易中的hex原始数据(如何解析比特币中的交易原始数据rawData):

01000000 // version,4字节,倒序
01 // 输入脚本个数
84f3684abd720033ff7a7654b48936088cd22c8d9e96d3a12e64559562e0fd93 // UTXO(Unspent Transaction Output,未花费的交易输出),倒序
00000000 // UTXO的index,从0开始
6b // 解锁脚本长度
48 3045022100ea03e8414011fffc00f10a25a771076ee1cb4b0b24a02607c67462009e3d2c1d022070a7a1c74e6bb71c32d78043bccf7bbc353334eb6e517162b2270c85d6bb54d201 21030b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478 // 解锁脚本
ffffffff // sequence,序列号
01 // 输出脚本个数
00a92d0100000000 // 转账金额,8字节,倒序
19 // 锁定脚本长度
76a914d9c637cc30bb0fe9add3a185c1f5d884d12b7b7888ac // 锁定脚本
00000000 // lock time,时间戳

这是一笔普通地址转账给普通地址的交易,正好用来解释P2PKH的锁定脚本和解锁脚本。

锁定脚本

例子中,锁定脚本为:

76a914d9c637cc30bb0fe9add3a185c1f5d884d12b7b7888ac // 锁定脚本

对照锁定脚本的格式,可以解析这段脚本如下:

// OP_DUP OP_HASH160 <Cafe Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG

76 // OP_DUP
a9 // OP_HASH160
14 // 公钥的HASH值的长度,PUSHDATA
d9c637cc30bb0fe9add3a185c1f5d884d12b7b78 // 公钥的HASH值
88 // OP_EQUALVERIFY
ac // OP_CHECKSIG

公钥HASH值的计算方法

按常理来说,公钥HASH值计算方法是拿到公钥的byte数据做SHA256,再做RIPEMD160计算,结果为20字节HASH值。

但是这里做的是转账,输入项肯定只有转账地址n1NSP78VQ5iZqVVRMA9ZZ2r77eeGLnwdj8。因为地址就是公钥的HASH值再加入一个头的network type和最后的四个字节checkSum后做base58生成的,所以可以反向操作:

将比特币地址n1NSP78VQ5iZqVVRMA9ZZ2r77eeGLnwdj8进行base58解码,得到:6fd9c637cc30bb0fe9add3a185c1f5d884d12b7b783bcba0fb,其中0x6f代表是测试网络地址。将上面的结果去掉一字节头和尾部4字节校验和,得到:d9c637cc30bb0fe9add3a185c1f5d884d12b7b78,即为公钥HASH值

解锁脚本

例子中,解锁脚本为:

48 3045022100ea03e8414011fffc00f10a25a771076ee1cb4b0b24a02607c67462009e3d2c1d022070a7a1c74e6bb71c32d78043bccf7bbc353334eb6e517162b2270c85d6bb54d201 21030b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478 // 解锁脚本

将解锁脚本按照PUSHDATA的规则解析成两个字段:

Signature=483045022100ea03e8414011fffc00f10a25a771076ee1cb4b0b24a02607c67462009e3d2c1d022070a7a1c74e6bb71c32d78043bccf7bbc353334eb6e517162b2270c85d6bb54d201

Public Key=21030b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478

解析一下Signature:

48 // PUSHDATA

3045022100

ea03e8414011fffc00f10a25a771076ee1cb4b0b24a02607c67462009e3d2c1d // signature r

0220

70a7a1c74e6bb71c32d78043bccf7bbc353334eb6e517162b2270c85d6bb54d2 // signature s

01 // SIGHASH

解析一下Public Key:

// 压缩格式的公钥

21 03 0b461bf0f1253c9dacde9992594042d77798c5f0e7c76a1c587518606fb35478

比特币中P2PKH(pay-to-public-key-hash)的锁定脚本和解锁脚本的更多相关文章

  1. 比特币中P2SH(pay-to-script-hash)多重签名的锁定脚本和解锁脚本

    P2SH(pay-to-script-hash)多重签名的脚本 P2SH是多重签名的一种应用形式.在P2SH的交易中,多了一个Redeem Script的概念,称为赎回脚本.当向P2SH脚本的地址转账 ...

  2. 在iOS中使用OpenSSL的Public Key 进行加密

    这几天一直潜心于iOS开发,刚好把遇到的问题都记录一下.这次遇到的问题就是如果根据得到的Public Key在iOS 客户端对用户名和密码进行加密. Public Key如下: -----BEGIN ...

  3. 深入比特币原理(四)——锁定脚本(locking script)与解锁脚本(unlocking script)

    通常比特币都是以虚拟货币的概念出现在大众眼前,实际上比特币是第一个真正的区块链"平台",利用它去中心化.不可篡改.可追溯等特点不光可以实现多种交易模式(如点对点交易.多重签名交易等 ...

  4. 【原创】浅析密码学在互联网支付中的应用|RSA,Hash,AES,DES,3DES,SHA1,SHA256,MD5,SSL,Private Key,Public Key

    一)概述 什么是互联网支付? 当支付遇到互联网,一场革命自然不可避免.成为现实的是传统的现金支付已经“退居二线”,各种在线支付方式成为人们日常消费的主要支付方式.银行推出的网银以及第三方支付公司推出的 ...

  5. 从 ssh private key 中重新生成 public key

    Use the -y option to ssh-keygen: ssh-keygen -f ~/.ssh/id_rsa -y > ~/.ssh/id_rsa.pub From the 'man ...

  6. Map集合中get不存在的key值

    返回的值是null 测试代码 import java.util.HashMap; import java.util.Map; public class Test { public static voi ...

  7. HashMap中使用自定义类作为Key时,为何要重写HashCode和Equals方法

    之前一直不是很理解为什么要重写HashCode和Equals方法,才只能作为键值存储在HashMap中.通过下文,可以一探究竟. 首先,如果我们直接用以下的Person类作为键,存入HashMap中, ...

  8. 公钥(Public Key)与私钥(Private Key)

    公钥(Public Key)与私钥(Private Key)是通过一种算法得到的一个密钥对(即一个公钥和一个私钥),公钥是密钥对中公开的部分,私钥则是非公开的部分.公钥通常用于加密会话密钥.验证数字签 ...

  9. .NET导入openssl生成的公钥之BEGIN RSA PUBLIC KEY

    .NET导入openssl生成的公钥之BEGIN RSA PUBLIC KEY 我得到了一个公钥,形式如下 -----BEGIN RSA PUBLIC KEY----- MIGJAoGBAMroxz3 ...

随机推荐

  1. Dropout和学习率衰减

         Dropout 在机器学习的模型中,如果模型的参数太多,而训练样本又太少,训练出来的模型很容易产生过拟合的现象.在训练神经网络的时候经常会遇到过拟合的问题,过拟合具体表现在:模型在训练数据上 ...

  2. go语言web开发框架_Iris框架讲解(六):Session的使用和控制

    在实际的项目开发中,我们会经常有业务场景使用到Session功能.在iris框架中,也为我们提供了方便使用,功能齐全的Session模块.Session模块的源码目录为kataras/iris/ses ...

  3. 小程序启用slot -- 传入 wxml标签

    options:{ multipleSlots:true } 直接看:https://www.jianshu.com/p/b22c9e075931

  4. springboot 简单自定义starter - beetl

    使用idea新建springboot项目beetl-spring-boot-starter 首先添加pom依赖 packaging要设置为jar不能设置为pom<packaging>jar ...

  5. 安装php过程中的错误和解决方式 configure: error: jpeglib.h not found

    centos6.5 32位系统: checking for the location of libpng... yeschecking for the location of libXpm... no ...

  6. iOS客户端与网页交互文档

    很少和客户端打交道,这次由于做会活动,要和客户端配合做个分享的功能 这里总结下基本的流程,就是前端在H5 里调用客户端的方法即可 第一部分 客户端提供需求文档 网页请求设置 客户端发起请求时在HTTP ...

  7. Luogu P5103 「JOI 2016 Final」断层 树状数组or线段树+脑子

    太神仙了这题... 原来的地面上升,可以倒着操作(时光倒流),转化为地面沉降,最后的答案就是每个点的深度. 下面的1,2操作均定义为向下沉降(与原题意的变换相反): 首先这个题目只会操作前缀和后缀,并 ...

  8. 1105 Spiral Matrix(25 分)

    This time your job is to fill a sequence of N positive integers into a spiral matrix in non-increasi ...

  9. java实现的各种hash加密

    public class jiami { public static void main(String args[]){ String signString="Thank you!" ...

  10. string的各种函数(系统学习)

    1.按照面向对象的要求,可以把字符串看作一个对象,设计一个串类加以描述.但是,在一般的情况下不必建立自己的串类,c++标准 在库<string>中给出了类string,提供了丰富的串操作, ...