币安停止注册

2019/07/25 栏目:币安教程
原文标题:币安停止注册

前言

上一篇文章 中,我们开始初步实现交易,也理解交易的非个人性质:没有用户帐户,您的个人数据(例如,姓名,护照号码或SSN)不是必需的,也不会存储在比特币的任何地方。但必须有一些东西来确定你是交易输出的所有者(即你是锁定在那些输出上的硬币的所有者),这是比特币需要的地址。到目前为止,我们已经使用任何用户定义的字符串作为地址,现在我们将实现像比特币这样的真实地址。

本节介绍重要的代码更改,因此在此解释所有内容没有意义。请参考 本页 查看自上一篇文章以来的所有更改。


比特币地址

以下是比特币地址的一个例子:   1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa  。这是第一个比特币地址,据称属于Satoshi Nakamoto,比特币地址是公开的。如果您想向某人发送硬币,您需要知道他们的地址。但地址(尽管它是唯一的)并不能确定您是“钱包”的所有者。事实上,所谓的地址只是将公钥表示为人类可读的形式,因为人们很难阅读本机公钥。在比特币中,您的身份( 身份 )是一对(或成对)存储在您的计算机上的公钥(或您可以获得的公钥)( 公钥 )和私钥( 私钥 ) 。比特币基于加密算法的组合创建这些密钥,并保证除非您获得密钥,否则世界上没有其他人可以拿走您的硬币。我们来讨论一下这些算法是什么。使用密钥对的公钥加密


公钥和私钥。公钥不敏感,可以向任何人透露。相反,私钥不能公开:除了所有者之外,没有人可以访问它们,因为它是用作所有者标识符的私钥。在加密货币世界中,您的私钥代表您,和私钥就是一切。

基本上,比特币钱包就是这样的密钥对。当您安装钱包应用程序或使用比特币客户端生成新地址时,会为您生成一对密钥。控制私钥的人控制发送到比特币中的密钥的所有硬币。

私钥和公钥只是随机的字节序列,因此不能在屏幕上打印或由人读取。这就是比特币使用算法将公钥转换为人类可读字符串的原因。

如果您使用过比特币钱包应用程序,您可能会为您生成助记符密码。这些短语用于代替私钥,可用于生成它们。这个机制是我实现的n BIP-039

好的,我们现在知道使用比特币来识别用户的内容。但比特币如何检查交易输出的所有权(以及存储在其上的硬币)?

数学签名


数学和在密码学中,存在数字签名的概念,并且算法可以保证:

1.  当发送者被转移到接收者时,数据未被修改;

2.  数据由发件人创建;

3.  发件人无法拒绝数据的事实。

通过对数据应用签名算法(即签名数据),签名可以获得并可以在以后验证。使用私钥进行数字签名,验证需要公钥。

为了签署数据,我们需要以下内容:

1.  要签署的数据;

2.  私钥。

应用程序签名算法可以生成签名,并且此签名将存储在事务输入中。为了验证签名,我们需要以下三件事:

1.签署数据;

2。&nbsp ; 签名;

3.  公钥。

简而言之,验证过程可以描述为:检查签名是否来自签名数据加上私有e键,并且公钥恰好由私钥生成。

数字签名未加密,您无法从签名重建数据。这类似于哈希:您通过哈希算法运行数据并获得数据的唯一表示。签名和散列之间的区别是密钥对:它们使签名验证成为可能。但是,密钥对也可用于加密数据:私钥用于加密,公钥用于解密数据。比特币请勿使用加密算法。

比特币中的每个交易条目都由创建交易的人签名。在进入块之前,必须验证比特币中的每笔交易。验证方式(其他除外)程序):

1.  检查输入是否可以访问上一个交易的输出。

2.  检查交易签名是否正确。

如图所示,签署数据和验证签名的过程如下:

[

[123

现在让我们回顾一下交易的整个生命周期:

1.   最初,有一个包含coinbase事务的创建块。 coinbase交易中没有真正的输入,因此不需要签名。 coinbase事务的输出包含散列公钥(使用


RIPEMD16(SHA256(PubKey))

算法)。

2.  当人们发送硬币时,会创建一个交易。事务的输入将引用先前事务的输出。每个输入都将存储公钥(不是哈希)和整个事务的签名。 3.  比特币网络中接收交易的其他节点将验证它们。除此之外,他们检查输入中公钥的哈希是否与参考输出的哈希相匹配(这确保发件人只花费属于他们的硬币);签名是正确的(这确保了交易) )由硬币的真正所有者创建)。

4.  当矿工节点准备开采新区块时,它将交易放入区块并开始挖掘它。

5.  当开采新块时,网络中的每个其他节点都会收到一条消息,指出该块已被挖掘并添加到区块链中。

6.  在块链中添加块后,事务完成,其输出可在新事务中引用。

椭圆曲线加密


如上公钥和私钥是随机字节序列。由于它是用于识别硬币所有者的私钥,因此要求随机性算法必须产生真正的随机字节。我们不希望意外生成其他人拥有的私钥。

比特币使用椭圆曲线生成私钥。椭圆曲线是一个复杂的数学概念,我们在这里不会详细解释(如果你很好奇,请查看http://andrea.corbellini.name/2015/05/17/elliptic-curve-cryptography-a-gentle - 介绍/)。我们需要知道的是,这些曲线可用于生成非常大且随机的数字。比特币使用的曲线可以随机选取0到2256之间的数字(当可见宇宙中存在1078到1082之间的原子时)。如此巨大的上限意味着几乎不可能两次生成相同的私钥。

此外,比特币使用ECDSA(椭圆曲线数字签名算法)算法来签署交易。

Base58


现在让我们吧o回到上面提到的比特币地址:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa。现在我们知道这是一个人类可读的公钥表示。如果我们解码它,这就是公钥的样子(作为以十六进制系统编写的字节序列):

比特币使用Base58算法转换人类可读格式的公钥。该算法与着名的Base64非常相似,但它使用较短的字母表:从字母表中删除一些字母以避免一些使用字母相似性的攻击。因此,没有这样的符号:0(零),O(大写o),I(大写i)和l(小写L),因为它们看起来相似。此外,没有+和/符号。

让我们示意地想象o的过程从公钥获取地址:


因此,上述解码公钥由三部分组成:


由于哈希函数是一种方式(即它们不能被反转),所以无法从哈希中提取公钥。但我们可以运行它来检查是否使用公钥来获取哈希值,并保存哈希函数并比较哈希值。

好了,现在我们已经完成了所有部分,让我们写一些代码。在编写代码时,一些概念应该更清晰。


执行地址

我们将从

钱包

结构开始:

钱包不是什么比钥匙更重要。我们仍然需要这 Wallets

类型来保存多个钱包集合,将它们保存到文件中,然后从中加载它们。在


Wallet 中,在新密钥对的构造函数中。 newKeyPair 功能很简单:ECDSA基于椭圆曲线,因此我们需要一条椭圆曲线。接下来,使用该曲线生成私钥并从私钥生成公钥。需要注意的一点是,在基于椭圆曲线的算法中,公钥是曲线上的点。因此,公钥是X,Y坐标的组合。在比特币中,这些坐标被连接起来并形成公钥。 现在让我们生成一个地址: 这是将公钥转换为Base58地址的步骤:

1.  使用公钥并使用

RIPEMD160(SHA256(PubKey))

哈希算法哈希值两次。

2.  将地址生成算法的版本添加到哈希。 3.  通过散列步骤2 SHA256(SHA256(有效载荷))

的结果来计算校验和。校验和是结果哈希的前四个字节。

4.  将校验和附加到 版本+ PubKeyHash 组合。

5.&nBsp;  版本+ PubKeyHash +校验和 使用Base58 编码组合。

所以你会我得到一个真正的比特币地址,你甚至可以去 blockchain.info 查看其余额。但我可以向您保证,无论您生成新地址多少次并检查其余额,均衡为0.这就是选择适当的公钥加密算法很重要的原因:考虑私钥是随机数,产生相同数字的机会必须尽可能低。理想情况下,它必须低至

永远 将不再重复。   另外,请注意您不需要连接到比特币节点来获取地址。地址生成算法利用在许多编程语言和库中实现的开放算法的组合。 现在我们需要修改他们的输入和输出以使用地址:

请注意我们不再使用 ]

ScriptPubKey


ScriptSig 字段,因为我们不会实现脚本语言。相反, ScriptSig 将其分为 签名 ] PubKey 字段, ScriptPubKey 并重命名为 PubKeyHash ] 。我们将实现与比特币相同的输出锁定/解锁和输入签名逻辑,但我们将在该方法中执行此操作。 UsesKey 方法检查输入是否使用特定键解锁o本安输出。请注意,输入存储原始公钥,但该函数采用哈希值。

IsLockedWithKey 检查是否提供了公钥哈希以锁定输出。这是 UsesKey 的辅助函数 ,两者都在 中使用 FindUnspentTransactions 在交易之间建立联系。 只需锁定输出即可。当我们向某人发送硬币时,我们只知道他们的地址,因此该函数将地址作为唯一参数。然后解码该地址并从中提取公钥哈希并保存在 PubKeyHash

字段中。 现在让我们检查一切是否正常:[1]23] 太棒了!现在让我们实现交易签名。


执行签字

签字必须是签名因为这是确保发件人不会在比特币中花钱属于其他人的唯一方法。如果签名无效,则该交易也被视为无效,无法添加到区块链中。

我们拥有实现交易签名的所有部分,还有一件事:要签署的数据。交易的哪些部分实际签署了?或者是一个整体签署的交易?选择要签名的数据非常重要。问题是要签名的数据必须包含唯一标识的信息数据。例如,仅对输出值进行签名是没有意义的,因为此类签名不考虑发件人和收件人。 考虑到交易解锁的先前输出,重新分配其值并锁定新输出,必须签署以下数据:

] 1.  公钥哈希存储在未锁定的输出中。这标识了交易的“发件人”。

2.  公钥哈希存储在新的锁定输出中。这标识了交易的“收件人”。

     新的输出值。

在比特币中,锁定/解锁逻辑存储在脚本中,这些脚本存储在输入和输出中

  ] ScriptSig

 

  ScriptPubKey   字段。由于比特币允许不同类型的此类脚本,因此它标记了整个内容 ScriptPubKey 如您所见,我们不需要对输入中存储的公钥进行签名。因此,在比特币中,它不是已签名的事务,而是一个删除部分内容的输入副本,从参考输出中存储 ScriptPubKey

获得修剪交易副本的详细过程见 虽然它可能已经过时,但我还没有找到另一个更可靠的来源。

好吧,它看起来很复杂,所以让我们开始编码。我们将从 Sign 方法开始:

该方法使用私钥和以前的交易地图。如上所述,为了对事务进行签名,我们需要访问事务输入中引用的输出,因此我们需要存储这些输出的事务。 让我们一步一步地分析这个方法:


Coinbase事务没有签名,因为没有实际的输入他们。

将签署一份裁定交易的副本而非全面交易:


]此副本将包括所有输入和输出,但


TXInput.Signature


TXInput.PubKey

设置为零。 接下来,我们浏览副本中的每个输入: 在每个输入中,] [123 ] 签名

设置为

(只是一次双重检查), ] PubKey 设置为 参考PubKeyHash 输出。此时,除当前交易外的所有交易都是“空的”,即他们 签名 PubKey 字段设置为nil。因此,输入是单独签名的,虽然我们的应用程序不需要这样做,但比特币允许事务包含引用不同地址的输入。 哈希[1]23] 方法序列化事务并使用SHA-256算法对它是哈希值,结果哈希值是我们要签名的数据。在获得哈希之后,我们应该重置

PubKey


字段,以便它不会影响进一步的迭代。 现在,关键是: 我们通过   [ 123] privKey

 

签名

 


txCopy.ID

  。 ECDSA签名是一对数字,我们连接并存储在输入 签名 字段中。 现在,验证功能: 这种方法非常简单。首先,我们需要相同的交易副本:

接下来,我们需要用于生成密钥对的相同曲线:


接下来,我们检查每个输入签名:


这一部分与

Sign


方法中的部分相同,因为我们需要在验证期间签署相同的数据。


这里我们解压缩存储在

TXInput.Signature 和[ 123] TXInput.PubKey

,因为签名是一对数字而公钥是一对坐标。我们之前将它们连接在一起进行存储,现在我们需要将它们解压缩以在

crypto / ecdsa 函数中使用它们。 这是:我们创造了一个 ecdsa.PublicKey 使用输入中的摘录公钥由 ecdsa.Verify

执行。

传递从输入中提取的签名。如果验证了所有输入,则返回true; 如果至少有一个输入验证失败,则返回false。

现在我们需要一个函数来获得先前的交易。由于这需要与区块链相互作用,我们将把它放在 区块链 方法

这些函数非常简单: FindTransaction 按ID查找事务(这需要迭代所有块在区块链));  SignTransaction

接受交易,fi找到它引用的交易并签名; 

VerifyTransaction 做同样的事情,而是验证交易。 现在我们需要实际签署并验证交易。签名发生在 NewUTXOTransaction 验证交易之前将其放入街区:

就是这样!让我们再检查一下:

一切都很好,真棒!

我们也想评论


bc.SignTransaction(& tx,wallet.PrivateKey)

致电

123]


NewUTXOTransaction

确保无法开采无签名交易:

结论 到目前为止,我们真的很棒,实现了比特币的许多关键功能!我们已经实施了网络外的几乎所有内容,在下一节中我们将完成交易。