区块链教程——P2P交易原理
Posted 夏风喃喃
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了区块链教程——P2P交易原理相关的知识,希望对你有一定的参考价值。
区块链教程(2)——P2P交易原理
参考:廖雪峰的官方网站区块链教程
https://www.liaoxuefeng.com/wiki/1207298049439968
2.1 P2P交易原理
比特币的交易是一种无需信任中介参与的P2P(Peer-to-peer)交易。
传统的电子交易,交易双方必须通过银行这样的信任机构作为中介,这样可以保证交易的安全性,因为银行记录了交易双方的账户资金,能保证在一笔交易中,要么保证成功,要么交易无效,不存在一方到账而另一方没有付款的情况。
但是在比特币这种去中心化的P2P网络中,并没有一个类似银行这样的信任机构存在,要想在两个节点之间达成交易,就必须实现一种在零信任的情况下安全交易的机制。
数字签名
在比特币交易中,付款方就是通过数字签名来证明自己拥有某一笔比特币,并且,要把这笔比特币转移给指定的收款方。
使用签名是为了验证某个声明确实是由某个人做出的。例如,在付款合同中签名,可以通过验证笔迹的方式核对身份。而在计算机中,用密码学理论设计的数字签名算法比验证笔迹更加可信。使用数字签名时,每个人都可以自己生成一个秘钥对,这个秘钥对包含一个私钥和一个公钥:私钥被称为Secret Key或者Private Key,私钥必须严格保密,不能泄漏给其他人;公钥被称为Public Key,可以公开给任何人:
当私钥持有人,例如,小明希望对某个消息签名的时候,他可以用自己的私钥对消息进行签名,然后,把消息、签名和自己的公钥发送出去:
其他任何人都可以通过小明的公钥对这个签名进行验证,如果验证通过,可以肯定,该消息是小明发出的。
数字签名算法在电子商务、在线支付这些领域有非常重要的作用:
首先,签名不可伪造,因为私钥只有签名人自己知道,所以其他人无法伪造签名。
其次,消息不可篡改,如果原始消息被人篡改了,那么对签名进行验证将失败。
最后,签名不可抵赖。如果对签名进行验证通过了,那么,该消息肯定是由签名人自己发出的,他不能抵赖自己曾经发过这一条消息。
数字签名算法
常用的数字签名算法有:RSA算法,DSA算法和ECDSA算法。比特币采用的签名算法是椭圆曲线签名算法:ECDSA,使用的椭圆曲线是一个已经定义好的标准曲线secp256k1:
y
2
=
x
3
+
7
y^2=x^3+7
y2=x3+7
这条曲线的图像长这样:
比特币采用的ECDSA签名算法需要一个私钥和公钥组成的秘钥对:私钥本质上就是一个
1
~
2
256
1~2^{256}
1~2256的随机数,公钥是由私钥根据ECDSA算法推算出来的,通过私钥可以很容易推算出公钥,所以不必保存公钥,但是,通过公钥无法反推私钥,只能暴力破解。
比特币的私钥是一个随机的非常大的256位整数。它的上限,确切地说,比
2
256
2^{256}
2256要稍微小一点。而比特币的公钥是根据私钥推算出的两个256位整数。如果用银行卡作比较的话,比特币的公钥相当于银行卡卡号,它是两个256位整数:
比特币的私钥相当于银行卡密码,它是一个256位整数:
18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725
银行卡的卡号由银行指定,银行卡的密码可以由用户随时修改。而比特币“卡”和银行卡的不同点在于:密码(实际上是私钥)由用户先确定下来,然后计算出“卡号”(实际上是公钥),即卡号是由密码通过ECDSA算法推导出来的,不能更换密码,因为更换密码实际上相当于创建了一张新卡片。
由于比特币账本是全网公开的,所以,任何人都可以根据公钥查询余额,但是,不知道持卡人是谁。这就是比特币的匿名特性。
丢失了私钥和忘记银行卡密码不一样,忘记银行卡密码可以拿身份证到银行重新设置一个密码,因为密码是存储在银行的计算机中的,而比特币的P2P网络不存在中央节点,私钥只有持有人自己知道,因此,丢失了私钥,对应的比特币就永远无法花费。 如果私钥被盗,黑客就可以花费对应公钥的比特币,并且这是无法追回的。
比特币私钥的安全性在于如何生成一个安全的256位的随机数。不要试图自己想一个随机数,而是应当使用编程语言提供的安全随机数算法,但绝对不能使用伪随机数。
比特币钱包
比特币钱包实际上就是帮助用户管理私钥的软件。因为比特币的钱包是给普通用户使用的,它有几种分类:
本地钱包:是把私钥保存在本地计算机硬盘上的钱包软件,如Electrum;
手机钱包:和本地钱包类似,但可以直接在手机上运行,如Bitpay;
在线钱包:是把私钥委托给第三方在线服务商保存;
纸钱包:是指把私钥打印出来保存在纸上;
脑钱包:是指把私钥记在自己脑袋里。
和银行账户不同,比特币网络没有账户的概念,任何人都可以从区块链查询到任意公钥对应的比特币余额,但是,并不知道这些公钥是由谁持有的,也就无法根据用户查询比特币余额。
作为用户,可以生成任意数量的私钥-公钥对,公钥是接收别人转账的地址,而私钥是花费比特币的唯一手段,钱包程序可以帮助用户管理私钥-公钥对。
交易
我们再来看记录在区块链上的交易。每个区块都记录了至少一笔交易,一笔交易就是把一定金额的比特币从一个输入转移到一个输出:
例如,小明把两个比特币转移给小红,这笔交易的输入是小明,输出就是小红。实际记录的是双方的公钥地址。
如果小明有50个比特币,他要转给小红两个比特币,那么剩下的48个比特币应该记录在哪?比特币协议规定一个输出必须一次性花完,所以,小明给小红的两个比特币的交易必须表示成:
小明给小红2个比特币,同时小明又给自己48个比特币,这48个比特币就是找零。所以,一个交易中,一个输入可以对应多个输出。
当小红有两笔收入时,一笔2.0,一笔1.5,她想给小白转3.5比特币时,就不能单用一笔输出,她必须把两笔钱合起来再花掉,这种情况就是一个交易对应多个输入和1个输出:
如果存在找零,这笔交易就既包含多个输入也包含多个输出:
在实际的交易中,输入比输出要稍微大一点点,这个差额就是隐含的交易费用,交易费用会算入当前区块的矿工收入中作为矿工奖励的一部分:
计算出的交易费用:
交易费用 = 输入 - 输出 = (2.0 + 1.5) - (2.99 + 0.49) = 3.5 - 3.48 = 0.02
比特币实际的交易记录是由一系列交易构成,每一个交易都包含一个或多个输入,以及一个或多个输出。未花费的输出被称为UTXO(Unspent Transaction Ouptut)。
当我们要简单验证某个交易的时候,例如,对于交易f36abd
,它记录的输入是3f96ab
,索引号是1
(索引号从0
开始,0
表示第一个输出,1
表示第二个输出,以此类推),我们就根据3f96ab
找到前面已发生的交易,再根据索引号找到对应的输出是0.5个比特币,所以,这笔交易的输入总计是0.5个比特币,输出分别是0.4个比特币和0.09个比特币,隐含的交易费用是0.01个比特币:
2.2 私钥
在比特币中,私钥本质上就是一个256位的随机整数。想要记住一个256位的整数是非常困难的,并且,如果记错了其中某些位,这个记错的整数仍然是一个有效的私钥,因此,比特币有一种对私钥进行编码的方式,这种编码方式就是带校验的Base58编码。
对私钥进行Base58编码有两种方式,一种是非压缩的私钥格式,一种是压缩的私钥格式,它们分别对应非压缩的公钥格式和压缩的公钥格式。
非压缩的私钥格式是指在32字节的私钥前添加一个0x80字节前缀,得到33字节的数据,对其计算4字节的校验码,附加到最后,一共得到37字节的数据:
计算校验码非常简单,对其进行两次SHA256,取开头4字节作为校验码。
对这37字节的数据进行Base58编码,得到总是以5
开头的字符串编码,这个字符串就是我们需要非常小心地保存的私钥地址,又称为钱包导入格式:WIF(Wallet Import Format),整个过程如下图所示:
目前,非压缩的格式几乎已经不使用了。
压缩格式的私钥编码方式,与非压缩格式不同的是,压缩的私钥格式会在32字节的私钥前后各添加一个0x80字节前缀和0x01字节后缀,共34字节的数据,对其计算4字节的校验码,附加到最后,一共得到38字节的数据:
对这38字节的数据进行Base58编码,得到总是以K
或L
开头的字符串编码,整个过程如下图所示:
2.3 公钥和地址
比特币的公钥是根据私钥计算出来的。私钥本质上是一个256位整数,记作k
。根据比特币采用的ECDSA算法,可以推导出两个256位整数,记作(x, y)
,这两个256位整数即为非压缩格式的公钥。由于ECC曲线的特点,根据非压缩格式的公钥(x, y)
的x
实际上也可推算出y
,但需要知道y
的奇偶性,因此,可以根据(x, y)
推算出x'
,作为压缩格式的公钥。
压缩格式的公钥实际上只保存x
这一个256位整数,但需要根据y
的奇偶性在x
前面添加02
或03
前缀,y
为偶数时添加02
,否则添加03
,这样,得到一个1+32=33字节的压缩格式的公钥数据,记作x'
。
注意压缩格式的公钥和非压缩格式的公钥是可以互相转换的,但均不可反向推导出私钥。非压缩格式的公钥目前已很少使用,原因是非压缩格式的公钥签名脚本数据会更长。
要特别注意,比特币的地址并不是公钥,而是公钥的哈希,即从公钥能推导出地址,但从地址不能反推公钥,因为哈希函数是单向函数。
以压缩格式的公钥为例,从公钥计算地址的方法是,首先对1+32=33字节的公钥数据进行Hash160(即先计算SHA256,再计算RipeMD160),得到20字节的哈希。然后,添加0x00前缀,得到1+20=21字节数据,再计算4字节校验码,拼在一起,总计得到1+20+4=25字节数据:
对上述25字节数据进行Base58编码,得到总是以1
开头的字符串,该字符串即为比特币地址,整个过程如下:
计算地址的时候,不必知道私钥,可以直接从公钥计算地址。要注意,对非压缩格式的公钥和压缩格式的公钥进行哈希编码得到的地址,都是以1
开头的,因此,从地址本身并无法区分出使用的是压缩格式还是非压缩格式的公钥。以1
开头的字符串地址即为比特币收款地址,可以安全地公开给任何人。仅提供地址并不能让其他人得知公钥。通常来说,公开公钥并没有安全风险。实际上,如果某个地址上有对应的资金,要花费该资金,就需要提供公钥。如果某个地址的资金被花费过至少一次,该地址的公钥实际上就公开了。
私钥、公钥以及地址的推导关系如下:
2.4 签名
签名算法是使用私钥签名,公钥验证的方法,对一个消息的真伪进行确认。如果一个人持有私钥,他就可以使用私钥对任意的消息进行签名,即通过私钥sk
对消息message
进行签名,得到signature
:
signature = sign(message, sk);
签名的目的是为了证明,该消息确实是由持有私钥sk
的人发出的,任何其他人都可以对签名进行验证。验证方法是,由私钥持有人公开对应的公钥pk,其他人用公钥pk
对消息message
和签名signature
进行验证:
isValid = verify(message, signature, pk);
如果验证通过,则可以证明该消息确实是由持有私钥sk的人发出的,并且未经过篡改。数字签名可以防伪造,防篡改,防抵赖。
对消息进行签名,实际上是对消息的哈希进行签名,这样可以使任意长度的消息在签名前先转换为固定长度的哈希数据。对哈希进行签名相当于保证了原始消息的不可伪造性。
比特币对交易数据进行签名和对消息进行签名的原理是一样的,只是格式更加复杂。对交易签名确保了只有持有私钥的人才能够花费对应地址的资金。
以上是关于区块链教程——P2P交易原理的主要内容,如果未能解决你的问题,请参考以下文章