目录
简介
钱包在比特币中是做什么的呢?比特币的交易又有什么特点呢?怎么才能伪造比特币的交易呢?今天和大家一起学习一下比特币中的钱包和交易。
比特币密码学的基础
之前我们提到过比特币使用的并不是什么新技术,只是对于老的技术比如:P2P网络,分布式系统,密码学,共识算法的重新而又巧妙的应用。
在钱包和交易生成验证的过程中,都需要使用到密码学的计算。这里我们先介绍一下比特币中会使用到的几种密码学技术。
更多精彩内容且看:
- 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
- Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
- Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
- java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程
单向散列函数(hash算法)
在介绍单向散列函数之前,我们先了解一下什么情况下需要使用到单向散列函数。
如果你需要从国外的网站上下载一个软件,但是因为种种原因,国外的网络太慢了,下载几个G的数据几乎是不可能的。刚好国内有镜像网站,可以从国内下载数据。但是如何保证国内的镜像不是被篡改过后的呢?这个时候就需要单向散列函数了。一般来说网站会提供MD5或者SHA的值作为验证值。
单向散列函数有一个输入和输出。输入称为消息,输出称为散列值。
散列值的长度跟消息的长度无关,不论多少大小的长度的消息,都会计算出固定长度的散列值。
hash算法有下面几个特点:
- 能够根据任意长度的消息计算出固定长度的散列值。
- 计算速度要快。
- 消息不同,散列值也不同。
这就意味着,如果仅仅是一点点的变动都会引起整个散列值的巨大变化。
因为散列值的大小是固定的,所以有可能会出现不同的消息产生相同散列值的情况。这种情况叫做碰撞。
难以发现碰撞的性质被称为抗碰撞性。当给定某条消息的散列值时,必须保证很难找到和该消息具有相同散列值的另一条消息。 - 单向散列函数必须具有单向性。所谓单向性是指无法通过散列值来反推出消息的性质。
比特币使用的散列算法是SHA256,他是安全散列算法SHA(Secure Hash Algorithm)系列算法的一种(另外还有SHA-1、SHA-224、SHA-384 和 SHA-512 等变体),SHA是美国国家安全局 (NSA) 设计,美国国家标准与技术研究院(NIST) 发布的,主要适用于数字签名标准(DigitalSignature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。
RIPEMD(RACE Integrity Primitives Evaluation Message Digest,RACE原始完整性校验消息摘要),是Hans Dobbertin等3人在md4,md5的基础上,于1996年提出来的。
非对称加密算法
非对称加密算法也叫公钥密码算法,通过生成的公私钥来对明文密文进行加密解密。
非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
扩展阅读:同态加密
同态加密是一种加密形式,它允许人们对密文进行特定的代数运算得到仍然是加密的结果,将其解密所得到的结果与对明文进行同样的运算结果一样。换言之,这项技术令人们可以在加密的数据中进行诸如检索、比较等操作,得出正确的结果,而在整个处理过程中无需对数据进行解密。其意义在于,真正从根本上解决将数据及其操作委托给第三方时的保密问题,例如对于各种云计算的应用。
密钥,地址和钱包
比特币的所有权是通过数字密钥、比特币地址和数字签名来确立的。数字密钥实际上并不是存储在网络中,而是由用户生成并存储在一个文件或简单的数据库 中,称为钱包。存储在用户钱包中的数字密钥完全独立于比特币协议,可由用户的钱包软件生成并管理,而无需区块链或网络连接。密钥实现了比特币的许多有趣特性,包括去中心化信任和控制、所有权认证和基于密码学证明的安全模型。
比特币钱包只包含私钥而不是比特币。每一个用户有一个包含多个私钥的钱包。钱包中包含成对的私钥和公钥。用户用这些私钥来签名交易,从而证明它们拥有交易的输出(也就是其中的比特币)。比特币是以交易输出的形式来储存在区块链中(通常记为vout或txout)。
如果钱包只包含私钥,那么钱包地址是什么呢?钱包地址是从公钥的hash值的出来的,如下图所示:
- 首先使用随机数发生器生成一个『私钥』。一般来说这是一个256bits的数,拥有了这串数字就可以对相应『钱包地址』中的比特币进行操作,所以必须被安全地保存起来。
- 『私钥』经过SECP256K1算法处理生成了『公钥』。SECP256K1是一种椭圆曲线算法,通过一个已知『私钥』时可以算得『公钥』,而『公钥』已知时却无法反向计算出『私钥』。这是保障比特币安全的算法基础。
- 同SHA256一样,RIPEMD160也是一种Hash算法,由『公钥』可以计算得到『公钥哈希』,而反过来是行不通的。
- 将一个字节的地址版本号连接到『公钥哈希』头部(对于比特币网络的pubkey地址,这一字节为“0”),然后对其进行两次SHA256运算,将结果的前4字节作为『公钥哈希』的校验值,连接在其尾部。
- 将上一步结果使用BASE58进行编码(比特币定制版本),就得到了『钱包地址』。 比如,1A1zP1eP5QGefi2DMPTfTL5TTmv7DivfNa。
所以私钥,公钥和钱包地址的关系如下图所示:
大家看到钱包地址1A1zP1eP5QGefi2DMPTfTL5TTmv7DivfNa有什么想法呢?
肯定有人在想,这么一大长串字母和数字实在是太不好记忆了。能不能生产一个比较好记的钱包地址呢? 比如MyNameIsHanMeiMei....这样开头的地址呢?
当然可以,这叫做靓号地址,只不过需要大量的算力才行。
比特币中的交易
简单来说,交易就是告知全网:比特币的持有者已授权把比特币转帐给其他人。而新持有者能够再次授权,转移给该比特币所有权链中的其他人。
注意, 在比特币的世界里既没有账户,也没有余额,只有分散到区块链里的UTXO(Unspent Transaction Outputs)。
怎么理解这个UTXO呢?没有账户也没有余额,那么钱包里面的金额是怎么计算出来的呢?
别急,让我们一一道来。
话说,在比特币中,比特币钱包间的转账是通过交易(Transaction)实现的。
我们看一个标准的交易流程。
那么问题来了,世界上第一个比特币是哪里来的呢?
答,是挖矿来的。好了,我们的001交易表示的就是一个挖矿的过程,在这个交易中,输入就是挖矿,输出编号1,BTC数目是50,目的地址是A,表示这50个BTC给A了。
接下来,A想发25个BTC给B,怎么构造这个交易呢?
同样的,我们需要一个输入,这个输入就是001交易的1号输出,我们用001.1来表示。输出分为两个,第一个输出编号1,表示要付25个BTC给B。第二个输出编号2,表示剩下的BTC要还给A。
大家可能会问了,输入是50BTC,两个输出加起来才45个BTC,好像还少了5个BTC?没错,这个5个BTC就是给矿工的挖矿所得。
接下来,A又继续转账给C,同样的道理,把一个一个的交易连接起来。
从上面的例子我们可以看到,实际上钱是存在一个一个的交易记录里面的,那些未被花费的输出,就叫做UTXO(Unspent Transaction Outputs)。
那么怎么保证转账给B的钱,不会被其他的人消费呢?这就涉及到交易的加密过程了。
我们以单个输入和输出为例来详细了解一下交易的构成:
上图中,交易的输入就是txid,也就是之前生成的还有未花费暑输出的交易ID。output index就是交易的输出id。
一个非常重要的ScriptSig是输入交易的验证,表明这个用户拥有这个账户的转账权限。
输出是一个脚本,只有满足脚本运行条件的人才能花费这个output。这也就是ScriptSig需要验证的脚本。
我们看下脚本是怎么做认证的吧。
比特币的标准输出形式有两种。Pay To Public Key Hash (P2PKH) 和 Pay To Script Hash (P2SH)。两者的区别在于,一个是输出到public key的hash,一个是输出到任意的一个脚本输出hash。
为了保证输出只能由特定的人来花费,一般的情况下是直接输出到对方的public key hash。由于只有对方拥有的私钥能够生成这个public key hash,也就是说只有对方才能够对这个输出进行验证。
但每次都需要知道对方的public key hash还是比较麻烦的,更简单的做法就是,发送者直接输出到一个特定的hash值就行了,只要对方能够生成这个hash就可以。
下面的例子是一个P2PKH的脚本形式。
P2PKH的输出是一个脚本,里面一个重要的值就是PK hash。
怎么验证呢?
验证方提供两个值,一个是sig,一个是PubKey。因为比特币的虚拟机是栈结构的,我们先把这两个值入栈。
然后调用OP_DUP对最上层的PubKey进行拷贝,然后调用OP_HASH160算法来计算Pk Hash,然后将发送方保存的Pk Hash入栈。接下来调用OP_EQUALVERIFY对两个PK Hash进行对比。
如果对比成功,最后一步就是验证Sig和PubKey是否匹配。
如果都成功,说明接收方的确是这个PK Hash的拥有者。那么对方就可以尽情使用了。
扩展阅读:图灵非完备性
和冯·诺伊曼同为现代计算机奠基人的阿兰·图灵(AlanTurin)在1950年提出了判定计算机能否像人那般实际“思考”的标准,也就是著名的“图灵检验”。
他设想一台超级计算机和一个人躲藏在幕后回答提问者的问题,而提问者则试图分辨哪个是人哪个是计算机。
图灵争辩说,假如计算机伪装得如此巧妙,以致没有人可以在实际上把它和一个真人分辨开来的话,那么我们就可以声称,这台计算机和人一样具备了思考能力,或者说,意识(他的原词是“智慧”)。
在可计算性理论里,如果一系列操作数据的规则(如指令集、编程语言、细胞自动机)按照一定的顺序可以计算出结果,被称为图灵完备(turing complete)。
比特币脚本语言不是图灵完备的,具有一定的局限性,它没有循环语句和复杂的条件控制语句。