区块链系列教程之比特币的钱包与交易

38次阅读

共计 4419 个字符,预计需要花费 12 分钟才能阅读完成。

[toc]

简介

钱包在比特币中是做什么的呢?比特币的交易又有什么特点呢?怎么才能伪造比特币的交易呢?今天和大家一起学习一下比特币中的钱包和交易。

比特币密码学的基础

之前我们提到过比特币使用的并不是什么新技术,只是对于老的技术比如:P2P 网络,分布式系统,密码学,共识算法的重新而又巧妙的应用。

在钱包和交易生成验证的过程中,都需要使用到密码学的计算。这里我们先介绍一下比特币中会使用到的几种密码学技术。

更多精彩内容且看:

  • 区块链从入门到放弃系列教程 - 涵盖密码学, 超级账本, 以太坊,Libra, 比特币等持续更新
  • Spring Boot 2.X 系列教程: 七天从无到有掌握 Spring Boot- 持续更新
  • Spring 5.X 系列教程: 满足你对 Spring5 的一切想象 - 持续更新
  • java 程序员从小工到专家成神之路(2020 版)- 持续更新中, 附详细文章教程

单向散列函数(hash 算法)

在介绍单向散列函数之前,我们先了解一下什么情况下需要使用到单向散列函数。

如果你需要从国外的网站上下载一个软件,但是因为种种原因,国外的网络太慢了,下载几个 G 的数据几乎是不可能的。刚好国内有镜像网站,可以从国内下载数据。但是如何保证国内的镜像不是被篡改过后的呢?这个时候就需要单向散列函数了。一般来说网站会提供 MD5 或者 SHA 的值作为验证值。

单向散列函数有一个输入和输出。输入称为消息,输出称为散列值。

散列值的长度跟消息的长度无关,不论多少大小的长度的消息,都会计算出固定长度的散列值。

hash 算法有下面几个特点:

  1. 能够根据任意长度的消息计算出固定长度的散列值。
  2. 计算速度要快。
  3. 消息不同,散列值也不同。

    这就意味着,如果仅仅是一点点的变动都会引起整个散列值的巨大变化。

    因为散列值的大小是固定的,所以有可能会出现不同的消息产生相同散列值的情况。这种情况叫做碰撞。

    难以发现碰撞的性质被称为抗碰撞性。当给定某条消息的散列值时,必须保证很难找到和该消息具有相同散列值的另一条消息。

  4. 单向散列函数必须具有单向性。所谓单向性是指无法通过散列值来反推出消息的性质。

比特币使用的散列算法是 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 值的出来的,如下图所示:

  1. 首先使用随机数发生器生成一个『私钥』。一般来说这是一个 256bits 的数,拥有了这串数字就可以对相应『钱包地址』中的比特币进行操作,所以必须被安全地保存起来。
  2. 『私钥』经过 SECP256K1 算法处理生成了『公钥』。SECP256K1 是一种椭圆曲线算法,通过一个已知『私钥』时可以算得『公钥』,而『公钥』已知时却无法反向计算出『私钥』。这是保障比特币安全的算法基础。
  3. 同 SHA256 一样,RIPEMD160 也是一种 Hash 算法,由『公钥』可以计算得到『公钥哈希』,而反过来是行不通的。
  4. 将一个字节的地址版本号连接到『公钥哈希』头部(对于比特币网络的 pubkey 地址,这一字节为“0”),然后对其进行两次 SHA256 运算,将结果的前 4 字节作为『公钥哈希』的校验值,连接在其尾部。
  5. 将上一步结果使用 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)。

比特币脚本语言不是图灵完备的,具有一定的局限性,它没有循环语句和复杂的条件控制语句。

总结

本文介绍了比特币的钱包和交易的概念,希望大家能够喜欢。

本文作者:flydean 程序那些事

本文链接:http://www.flydean.com/bitcoin-transactions/

本文来源:flydean 的博客

欢迎关注我的公众号: 程序那些事,更多精彩等着您!

正文完
 0