主页 > imtoken钱包国际版下载 > 比特币交易中的签名和验证

比特币交易中的签名和验证

imtoken钱包国际版下载 2023-04-26 07:40:44

比特币交易中的签名和验证

最近一直在学习一些比特币相关的原理和实现机制,在学习的过程中难免会出现一些问题。看了一些大神的文章,大部分问题都能得到满意的回答,感觉思路清晰了。但是,也有一些问题我一遍又一遍地想不通。看了很多文章,我还是有一种模糊的感觉,就像陷入了迷雾。比如比特币交易中的签名和验证,这个签名和哪个交易有关?签名的内容是什么?验证如何验证?验证证明了什么?以上问题花了我很长时间收集数据,比较和思考。至此,我想我已经有了比较完整的认识和了解。

怀疑的来源

相信大家都看过上图。这张图片来自中本聪的比特币白皮书,用来介绍比特币交易。在这张图片的顶部,中本聪写下了以下文字:我们将电子硬币定义为数字签名链。每个所有者通过对先前交易的哈希和下一个所有者的公钥进行数字签名并将它们添加到硬币的末尾来将硬币转移到下一个所有者。收款人可以验证签名以验证所有权链。为了保持原汁原味,我就不翻译了。相信大家的阅读理解能力还是保留下来的。居住。

但问题是,他说的每一个字我都听懂了,但我还是看不懂这张图在说什么。可能比特币交易在中本聪的心目中是这样的,所以我一直怀疑他是不是潜伏在地球的外星人,他的脑回路和地球的脑回路不一样,包括UTXO的概念,真的是和地球相悖的人类正常思维。因此,本文的任务就是尝试将这张图片转换成地球人容易理解的形式。

什么构成交易

如上图,这是一个比特币交易的简化结构(部分参数被忽略,id被简化)。

在介绍交易结构之前,先简单说一下比特币的UTXO概念,方便零基础的读者阅读。在比特币系统中,没有余额的概念,只有UTXO(Unspent Transaction Output),也就是未花费的交易输出。翻译成白话,我花的钱是别人给我的钱,花的时候一定要花。比如我有一个 2 BTC(比特币)的 UTXO,我想给你 1 BTC,我得花掉 2 BTC 的 UTXO,然后生成两个 UTXO,一个 1 BTC 的 UTXO 给你,一个UTXO(小于1 BTC),差价是交易费)给我自己。如果想看余额怎么处理,只需要查看这个地址有多少个UTXO,把里面的BTC加起来就可以得到余额。

好的,现在让我们看看事务的结构。比特币交易主要由两部分组成:输入和输出。

输入是解释我计划花费的 UTXO 来自哪里。

具体参数包括:

txid : 引用的 UTXO 所在的交易 ID

vout : 被引用的UTXO所在的交易输出中的序号(从0开始)

scriptSig : 解锁脚本,包括本次交易的付款人签名()和付款人的公钥(

)。

输出是指示我计划生成多少个 UTXO,给谁,以及每个 UTXO 中有多少个 BTC。

具体参数包括:

value : 比特币数量

n :UTXO序列号(从0开始)

成为比特币的一个节点

scriptPubkey :锁定脚本,包含命令(OP_DUP 等)和接收者的公钥哈希(

)。

现在我们了解了交易的结构,让我们通过一个交易的例子来看看签名和验证是如何工作的。

交易签名

我们看上图,A通过001交易向B转账1BTC,B通过002交易向C转账1BTC。为简单起见,忽略交易手续费的问题。

让我们重点分析事务002。

B打算给C转1BTC,他先找到A转给他的UTXO,即001交易中n=0的UTXO,将相关参数写入002交易的in,然后输入交易数量比特币进出,UTXO 序列号,并锁定脚本。锁脚本中的命令都是固定的,C的公钥哈希(

)可以通过解码C的钱包地址得到。

这样002交易相关的数据就已经准备好了,还需要最后的签名。这个签名类似于写支票时的签名,证明我同意给你钱。但具体的实现比签一个字要复杂得多。原因是互联网上的一切都可以复制。如何证明你拥有这笔钱,如何证明交易是你创建的并且没有被修改过,有严谨的数学理论和算法保证。

我们先来看看签名的过程:

签名输入:

1. 要签名的交易数据(输入和输出),即。

2. 引用的UTXO相关信息(交易ID、序列号、锁脚本)

3. B 的私钥,即

.

4. 签名类型

签名输出:

1. scriptSig ,解锁脚本,包含签名 ( ) 和 B 的公钥 (

成为比特币的一个节点

)。

至此,一个完整的交易创建成功,可以发送到其他节点进行验证。

这里还要多说一点,细心的读者可能会发现,输入2的信息其实包含在输入1中,或者可以根据输入1找到,为什么要单独列出呢?目前我还没有找到明确的、令人信服的解释,也不知道还有没有其他深意。期待各位大神指点。

签名验证

交易发送到其他节点后,其他节点会对其进行验证,只有经过验证的交易才会继续传播。交易验证的项目很多,这里只谈签名验证。

签名验证的目的有两个:

1. 证明交易所引用的UTXO确实属于付款人。

具体到这个交易,就是证明交易001中序号为0的UTXO确实是发给B的。

2. 证明交易的所有数据确实是付款人提供的,没有被修改过。

具体到这个事务,就是证明B确实创建了事务002,并且事务中的数据没有被修改过。

让我们看看验证是如何进行的。其实很简单。就是使用unlock脚本来解锁UTXO对应的lock script。上图对应橙色线连接的两个脚本:

OP_DUP OP_HASH160

OP_EQUALVERIFY OP_CHECKSIG

比特币脚本的执行基于栈模型,遵循从左到右、后进先出的原则。关于栈的介绍,文末的参考文章中有比较清晰的图解,不清楚的读者可以参考。在本文中,为了方便解释每个步骤的含义,都用文字来描述。步骤如下:

1. 推送

2.

压入堆栈

3. OP_DUP 复制栈顶

, 将副本放在堆栈顶部。

成为比特币的一个节点

4. OP_HASH160 对在栈顶

HASH160 的副本,

进入

.

5.

压入堆栈

6. OP_EQUALVERIFY 比较栈顶两个元素是否相同,如果相同则移除两个元素继续执行。如果不同,将中断执行并返回失败。

7.OP_CHECKSIG 检查签名(注意堆栈中的现有元素是

),并根据结果返回成功或失败。

我们来分析一下每一步的意义。步骤1到6的意义其实很明显。使用 B 提供的公钥(

) 双重散列 (HASH160),然后使用锁定脚本中的公钥进行散列 (

) 进行比较,同样会返回成功。我们知道公钥哈希 (

)是A在创建交易时根据B的地址生成的,是B的公钥通过双哈希运算得到的,所以只要在这一步提供了B的公钥,就一定验证成功。因此,步骤 1 到 6 相当于 A 向 B 的邮箱发送 1 BTC成为比特币的一个节点,B 用钥匙打开邮箱,证明 B 确实拥有 1 BTC。也就是证明上面提到的验证目的1:证明交易001的序号为0的UTXO确实发送给了B。

比较麻烦的是第7步。这里的很多文章只是泛泛而谈,或简要提及。当我得知这一点时,就像陷入迷雾中,茫然地环顾四周。现在回想起来,有些文章中的说法是非常不准确的。这一步中简单的 CHECKSIG 操作实际上包含了复杂的密码学和数学原理。不是所有权问题,而是证明 B 确实创建了交易 002,并且交易中的数据没有被修改过,也就是上面提到的验证目的 2。

那么,CHECKSIG的验证是如何实现的呢?这里使用椭圆曲线数字签名算法(ECDSA:The Elliptic Curve Digital Signature Algorithm),一种使用椭圆曲线进行数字签名和验证的算法。下面将简要介绍如何使用该算法对比特币交易进行签名和验证。涉及的数学知识就不深入介绍了。感兴趣的读者可以参考文末的文章链接进行深入了解。

ECDSA

首先我们看一下椭圆曲线的形状,如上图红线所示。我们可以在这条曲线上定义一个点的加法:连接两点的直线与椭圆曲线的交点关于 X 轴对称,即两点之和。图中A+B=C。

当A+A时,我们取点A的切线与曲线相对于X轴的交点的对称点。使用 A+A,我们可以轻松定义乘法。通过乘法,我们选择一个基点G,可以很容易地计算出K=kG。但是,给定 K 和 G,很难计算出 k(目前还没有有效的算法)。这就是椭圆曲线离散对数问题。ECC椭圆曲线密码学的安全性是基于椭圆曲线离散对数问题的难度。基于此,在 ECC 中,我们将 k 定义为私钥,将 K 定义为公钥。

成为比特币的一个节点

那么,我们看一下基于有限域Fp的椭圆曲线域E(Fp):

y^2 ≡ x^3 + ax + b (mod p)

当:a, b ∈ Fp 并且满足 4a^3+27b^2 ≠ 0 (mod p)。,当x,y ∈ Fp时,这条曲线上的点集合P=(x,y)构成了一个基于有限域Fp的椭圆曲线域E(Fp)。

一个椭圆曲线域的完整描述实际上需要6个参数:

p: 限定有限域边界的素数

a、b:椭圆曲线的参数

G:基点

n:G的阶数,nG=O∞

h:辅因子,控制点的密度。

椭圆曲线域可以简单理解为只取椭圆曲线上的那些整数点成为比特币的一个节点,但是由于多了一次模运算,显示的形状和之前的平滑曲线不同(如下图),而是之前定义的加法乘法规则不变。

好了,有了这些概念,我们现在来看看签名和验证的过程:

签名者的密钥对:(d, Q);(d是私钥,Q是公钥)

需签署的资料:M;

签名:签名(M)=(r,s)

签约流程:

1、根据ECC算法随机生成一个密钥对(k, R),R=(xR, yR)

2、令 r = xR mod n,如果 r = 0,则返回步骤 1

3、计算 H = Hash(M)

成为比特币的一个节点

4、根据数据类型转换规则,将H转换为大端整数e

5、s = k^-1 (e + rd) mod n,如果s = 0,则返回步骤1

6、输出 S =(r,s) 是签名。

验证过程:

1、 计算 H = Hash(M)

2、根据数据类型转换规则,将H转换为大端整数e

3、计算 u1 = es^-1 mod n, u2 = rs^-1 mod n

4、计算R = (xR, yR) = u1G + u2Q,如果R = 0,验证签名无效

5、令 v = xR mod n

6、如果v == r,则签名有效;如果 v ≠ r,则签名无效。

数学上可以证明,如果v == r,就可以证明消息M确实是由持有密钥对(d,Q)的签名者签名的,并且没有被修改过。

上述过程中的Q、S、R都是椭圆曲线域中的点。

让我们将上面示例中的输入参数与比特币交易 002 中的参数进行比较:

如上图所示,可以看出这两个过程中的参数是一一对应的。我们按照例子操作交易002中的相关参数,不难理解签名和验证的具体过程。由于数学原理的保证,如果签名验证成功,则可以证明B确实创建了交易002,并且交易中的数据没有被修改,也就是上面提到的验证目的2。

好了,以上就是作者目前对比特币交易中签名和验证的理解和思考。水平有限,难免有谬误和疏漏。欢迎批评指正!

ECDSA部分的两个动画引用自参考文章,感谢原作者Nick Sullivan,以及参考文章的所有作者!

参考文章

[1] 深入比特币原理(四)——加锁脚本(locking script)和解锁脚本(unlocking script)

[2] 比特币交易的数据结构和签名类型

[3] 椭圆曲线密码学简介

[4]比特币系统采用的公钥密码方案和ECDSA签名算法介绍-第1部分:原理