资讯专栏INFORMATION COLUMN

是的我想说的技术!

focusj / 2986人阅读

摘要:有效的数字签名使收件人有理由相信该信息是由已知的发件人认证创建的,发件人不能否认已发送的信息不可否认,并且信息在传输过程中未被更改完整性。当我们说签署交易时,我们实际上是指签署序列化交易数据的哈希。

特殊交易:合约注册

有一种特殊的带有data,没有value的交易。表示注册一个新的合约。合约登记交易被发送到一个特殊的目的地地址,即零地址。简而言之,合约注册交易中的+to+字段包含地址 0x0。该地址既不代表EOA(没有相应的私人/公共密钥对)也不代表合约。它永远不会花费ether或启动交易。它仅用作目的地,具有“注册此合约”的特殊含义。

尽管零地址仅用于合约注册,但它有时会收到来自各个地址的付款。对此有两种解释:无论是偶然的,导致ether的丧失,还是故意的_ ether燃烧_(见[burning_ether])。如果你想进行有意识的ether燃烧,你应该向网络明确你的意图,并使用专门指定的燃烧地址:

0x000000000000000000000000000000000000dEaD
Warning

发送至合约注册地址 0x0 或指定燃烧地址 0x0 ... dEaD 的任何ether将变得不可消费并永远丢失。

合约注册交易不应包含ether value,只能包含合约编译字节码的data。此次交易的唯一影响是注册合约。

作为例子,我们可以发布 [intro] 中使用的 Faucet.sol。合约需要编译成二进制十六进制表示。这可以用Solidiy编译器完成。

solc --bin Faucet.sol
======= Faucet.sol:Faucet =======
Binary:
6060604052341561000f57600080fd5b60e58061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d146041575b005b3415604b57600080fd5b605f60048080359060200190919050506061565b005b67016345785d8a00008111151515607757600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151560b657600080fd5b505600a165627a7a72305820d276ffffd56041f7dc2d2eab69f01dd0a0146446562e25236cf4ba5095d2ee802f0029
相同的信息也可以从Remix在线编译器获得。 现在我们可以创建交易。

src = web3.eth.accounts[0];> faucet_code = "0x6060604052341561000f57600080fd5b60e58061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d146041575b005b3415604b57600080fd5b605f60048080359060200190919050506061565b005b67016345785d8a00008111151515607757600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151560b657600080fd5b505600a165627a7a72305820d276ffffd56041f7dc2d2eab69f01dd0a0146446562e25236cf4ba5095d2ee802f0029"> web3.eth.sendTransaction({from: src, data: faucet_code, gas: 113558, gasPrice: 200000000000})"0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b"
不需要指定+to+参数,将使用默认的零地址。你可以指定 gasPrice 和 gas 限制。 一旦合约被开采,我们可以在etherscan区块浏览器上看到它。

Etherscan showing the contract successully mined

Figure 5. Etherscan showing the contract successully minded

你可以查看交易的接收者以获取有关合约的信息。

eth.getTransactionReceipt("0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b");

{
blockHash: "0x6fa7d8bf982490de6246875deb2c21e5f3665b4422089c060138fc3907a95bb2",
blockNumber: 3105256,
contractAddress: "0xb226270965b43373e98ffc6e2c7693c17e2cf40b",
cumulativeGasUsed: 113558,
from: "0x2a966a87db5913c1b22a59b0d8a11cc51c167a89",
gasUsed: 113558,
logs: [],
logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
status: "0x1",
to: null,
transactionHash: "0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b",
transactionIndex: 0}
在这里我们可以看到合约的地址。我们可以按照 将数据传输到EOA或合约 所示,从合约发送和接收资金。

contract_address = "0xb226270965b43373e98ffc6e2c7693c17e2cf40b"> web3.eth.sendTransaction({from: src, to: contract_address, value: web3.toWei(0.1, "ether"), data: ""});"0x6ebf2e1fe95cc9c1fe2e1a0dc45678ccd127d374fdf145c5c8e6cd4ea2e6ca9f"> web3.eth.sendTransaction({from: src, to: contract_address, value: 0, data: "0x2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000"});"0x59836029e7ce43e92daf84313816ca31420a76a9a571b69e31ec4bf4b37cd16e"
过一段时间,这两个交易都可以在ethescan上看到

Etherscan showing the transactions for sending and receiving funds

Figure 6. Etherscan showing the transactions for sending and receiving funds

数字签名

到目前为止,我们还没有深入探讨“数字签名”的细节。在本节中,我们将探讨数字签名是如何工作的,以及如何在不泄露私钥的情况下提供私钥所有权的证明。

椭圆曲线数字签名算法(ECDSA)

以太坊中使用的数字签名算法是_Elliptic Curve Digital Signature Algorithm_,或_ECDSA_。ECDSA是用于基于椭圆曲线私钥/公钥对的数字签名的算法,如 [elliptic_curve] 中所述。

数字签名在以太坊中有三种用途(请参阅下面的边栏)。首先,签名证明私钥的所有者,暗示着以太坊账户的所有者,已经授权支付ether或执行合约。其次,授权的证明是_undeniable_(不可否认)。第三,签名证明交易数据在交易签名后没有也不能被任何人修改。

Wikipedia对“数字签名”的定义

数字签名是用于证明数字信息或文件真实性的数学方案。有效的数字签名使收件人有理由相信该信息是由已知的发件人(认证)创建的,发件人不能否认已发送的信息(不可否认),并且信息在传输过程中未被更改(完整性) 。 来源: https://en.wikipedia.org/wiki...

数字签名如何工作

数字签名是一种数学签名,由两部分组成。第一部分是使用私钥(签名密钥)从消息(交易)中创建签名的算法。第二部分是允许任何人仅使用消息和公钥来验证签名的算法。

创建数字签名

在以太坊实现的ECDSA中,被签名的“消息”是交易,或者更确切地说,来自交易的RLP编码数据的Keccak256哈希。签名密钥是EOA的私钥。结果是签名:

((Sig = F_{sig}(F_{keccak256}(m), k)))

其中:

_k_是签名私钥

_m_是RLP编码的交易

Fkeccak256 是Keccak256哈希函数

Fsig 是签名算法

Sig 是由此产生的签名

更多关于ECDSA数学的细节可以在 ECDSA数学 中找到。

函数 Fsig 产生一个由两个值组成的签名+Sig+,通常称为+R+和+S+:

Sig = (R, S)
验证签名

要验证签名,必须有签名(R+和+S),序列化交易和公钥(与用于创建签名的私钥对应)。实质上,对签名的验证意味着“只有生成此公钥的私钥的所有者才能在此交易上产生此签名。”

签名验证算法采用消息(交易的散列或其部分),签名者的公钥和签名(+R+和+S+值),如果签名对此消息和公钥有效,则返回TRUE。

ECDSA数学

如前所述,签名由数学函数 Fsig 创建,该函数生成由两个值_R_和_S_组成的签名。在本节中,我们将更详细地讨论函数 Fsig 。

签名算法首先生成_ephemeral_(临时的)私钥/公钥对。在涉及签名私钥和交易哈希的转换之后,此临时密钥对用于计算_R_和_S_值。

临时密钥对由两个输入值生成:

1.一个随机数_q_,用作临时私钥 1.和椭圆曲线生成点_G_

从_q_和_G_开始,我们生成相应的临时公钥_Q_(以_Q = q * G_计算,与以太坊公钥的派生方式相同,参见[pubkey])。数字签名的_R_值就是临时公钥_Q_的x坐标。

然后,算法计算签名的_S_值,以便:

S ≡ q-1 (Keccak256(m) + k * R) (mod p)

其中:

_q_是临时私钥

_R_是临时公钥的x坐标

_k_是签名(EOA所有者)的私钥

_m_是交易数据

_p_是椭圆曲线的素数阶

验证是签名生成函数的反函数,使用_R_,S_值和公钥来计算一个值_Q,它是椭圆曲线上的一个点(签名创建中使用的临时公钥):

Q ≡ S-1 Keccak256(m) G + S-1 R K (mod p)

其中:

_R_和_S_是签名值

_K_是签名者(EOA所有者)的公钥

_m_是被签名的交易数据

_G_是椭圆曲线生成点

_p_是椭圆曲线的素数阶

如果计算的点_Q_的x坐标等于_R_,则验证者可以断定该签名是有效的。

请注意,在验证签名时,私钥既不被知道也不会透露。

Tip

ECDSA必然是一门相当复杂的数学; 完整的解释超出了本书的范围。许多优秀的在线指南会一步一步地通过它:搜索“ECDSA explained”或尝试这一个:http://bit.ly/2r0HhGB[]。

实践中的交易签名

为了产生有效的交易,发起者必须使用椭圆曲线数字签名算法将数字签名应用于消息。当我们说“签署交易”时,我们实际上是指“签署RLP序列化交易数据的Keccak256哈希”。签名应用于交易数据的哈希,而不是交易本身。

Tip

在#2,675,000块,Ethereum实施了“Spurious Dragon”硬分叉,除其他更改外,还推出了包括交易重播保护的新签名方案。这个新的签名方案在EIP-155中指定(参见[eip155])。此更改会影响签名过程的第一步,在签名之前向交易添加三个字段(v,r,s)。

要在以太坊签署交易,发件人必须:

创建一个包含九个字段的交易数据结构:nonce,gasPrice,startGas,to,value,data,v,r,s

生成交易的RLP编码的序列化消息

计算此序列化消息的Keccak256哈希

计算ECDSA签名,用发起EOA的私钥签名散列

在交易中插入ECDSA签名计算出的 r 和 s 值

原始交易创建和签名

让我们创建一个原始交易并使用 ethereumjs-tx 库对其进行签名。此示例的源代码位于GitHub存储库中的 raw_tx_demo.js 中:

raw_tx_demo.js: Creating and signing a raw transaction in JavaScript

link:code/web3js/raw_tx/raw_tx_demo.js[]
在此处下载: https://github.com/ethereumbo...

运行示例代码:

$ node raw_tx_demo.js
RLP-Encoded Tx: 0xe6808609184e72a0008303000094b0920c523d582040f2bcb1bd7fb1c7c1ecebdb348080
Tx Hash: 0xaa7f03f9f4e52fcf69f836a6d2bbc7706580adce0a068ff6525ba337218e6992
Signed Raw Transaction: 0xf866808609184e72a0008303000094b0920c523d582040f2bcb1bd7fb1c7c1ecebdb3480801ca0ae236e42bd8de1be3e62fea2fafac7ec6a0ac3d699c6156ac4f28356a4c034fda0422e3e6466347ef6e9796df8a3b6b05bed913476dc84bbfca90043e3f65d5224
用EIP-155创建原始交易

EIP-155“简单重播攻击保护”标准在签名之前指定了重播攻击保护(replay-attack-protected)的交易编码,其中包括交易数据中的_chain identifier_。这确保了为一个区块链(例如以太坊主网)创建的交易在另一个区块链(例如Ethereum Classic或Ropsten测试网络)上无效。因此,在一个网络上广播的交易不能在另一个网络上广播,因此得名“重放攻击保护”。

EIP-155向交易数据结构添加了三个字段 v,r+和+s。r+和+s 字段被初始化为零。这三个字段在编码和散列_之前_被添加到交易数据中。因此,三个附加字段会更改交易的散列,稍后将应用签名。通过在被签名的数据中包含链标识符,交易签名可以防止任何更改,因为如果链标识符被修改,签名将失效。因此,EIP-155使交易无法在另一个链上重播,因为签名的有效性取决于链标识符。

签名前缀字段+v+被初始化为链标识符,其值为:

Chain

Chain ID

Ethereum main net

1

Morden (obsolete), Expanse

2

Ropsten

3

Rinkeby

4

Rootstock main net

30

Rootstock test net

31

Kovan

42

Ethereum Classic main net

61

Ethereum Classic test net

62

Geth private testnets

1337

由此产生的交易结构被进行RLP编码,哈希和签名。签名算法也稍作修改,以在+v+前缀中对链ID进行编码。

有关更多详细信息,请参阅EIP-155规范: https://github.com/ethereum/E...

签名前缀值(v)和公钥恢复

如交易的结构所述,交易消息不包含任何“from”字段。这是因为发起者的公钥可以直接从ECDSA签名中计算出来。一旦你有公钥,你可以很容易地计算出地址。恢复签名者公钥的过程称为_公钥恢复_。

给定 ECDSA数学 中计算的值 r 和 s,我们可以计算两个可能的公钥。

首先,我们根据签名中的x坐标 r 值计算两个椭圆曲线点R和R"。有个两点,因为椭圆曲线在x轴上是对称的,所以对于任何值+x+,在x轴的两侧有两个可能的值适合曲线。

从 r 开始,我们也计算r-1这是 r 的倒数。

最后我们计算 z,它是消息散列的最低位,其中n是椭圆曲线的阶数。

然后两个可能的公钥是:

K1 = r-1 (sR - zG)

K2 = r-1 (sR" - zG)

其中:

K1 和 K2 是签名者公钥的两种可能性

r-1是签名的+r+值的倒数

s是签名的+s+值

R和R"是临时公钥_Q_的两种可能性

z是消息散列的最低位

G是椭圆曲线生成点

为了使事情更有效率,交易签名包括一个前缀值 v,它告诉我们两个可能的R值中哪一个是临时的公钥。如果 v 是偶数,那么R是正确的值。如果 v 是奇数,那么选择R"。这样,我们只需要计算R的一个值。

分离签名和传输(离线签名)

一旦交易被签署,它就可以传送到以太坊网络。创建,签署和广播交易的三个步骤通常发生在单个函数中,例如使用+web3.eth.sendTransaction+。但是,正如我们在原始交易创建和签名中看到的那样,你可以通过两个多带带的步骤创建和签署交易。一旦你签署了交易记录,你就可以使用+web3.eth.sendSignedTransaction+传输该交易记录,该方法采用十六进制编码的签名交易信息并在Ethereum网络上传输。

你为什么要分开交易的签署和传输?最常见的原因是安全:签名交易的计算机必须将解锁的私钥加载到内存中。传输的计算机必须连接到互联网并运行以太坊客户端。如果这两个功能都在一台计算机上,那么你的在线系统上有私钥,这非常危险。分离签名和传输功能称为 离线签名 offline signing,是一种常见的安全措施。

根据你所需的安全级别,你的“离线签名”计算机可能与在线计算机存在不同程度的分离,从隔离和防火墙子网(在线但隔离)到完全脱机系统,成为 气隙 _air-gapped_系统 。在气隙系统中根本没有网络连接 - 计算机与在线环境是“空气”隔离的。使用数据存储介质或(更好)网络摄像头和QR码将交易记录到气隙计算机上,以签署交易。当然,这意味着你必须手动传输你想要签名的每个交易,不能批量化。

尽管没有多少环境可以利用完全气隙系统,但即使是小程度的隔离也具有显着的安全优势。例如,带防火墙的隔离子网只允许通过消息队列协议,可以提供大大降低的攻击面,并且比在线系统上签名的安全性高得多。许多公司使用诸如ZeroMQ(0MQ)的协议,因为它为签名计算机提供了减少的攻击面。有了这样的设置,交易就被序列化并排队等待签名。排队协议以类似于TCP套接字的方式将序列化的消息发送到签名计算机。签名计算机从队列中读取序列化的交易(仔细地),使用适当的密钥应用签名,并将它们放置在传出队列中。传出队列将签名的交易传输到使用Ethereum客户端的计算机上,客户端将这些交易出队并传输。

交易传播

以太坊网络使用“泛洪”路由协议。每个以太坊客户端,在_Peer-to-Peer(P2P)中作为_node,(理想情况下)构成_mesh_网络。没有网络节点是“特殊的”,它们都作为平等的对等体。我们将使用术语“节点”来指代连接并参与P2P网络的以太坊客户端。

交易传播开始于创建(或从离线接收)签名交易的以太坊节点。交易被验证,然后传送到_直接_连接到始发节点的所有其他以太坊节点。平均而言,每个以太坊节点保持与至少13个其他节点的连接,称为_邻居_。每个邻居节点在收到交易后立即验证交易。如果他们同意这是有效的,他们会保存一份副本并将其传播给所有的邻居(除了它的邻居)。结果,交易从始发节点向外涟漪式地遍历网络,直到网络中的所有节点都拥有交易的副本。

几秒钟内,以太坊交易就会传播到全球所有以太坊节点。从每个节点的角度来看,不可能辨别交易的起源。发送给我们节点的邻居可能是交易的发起者,或者可能从其邻居那里收到它。为了能够跟踪交易的起源或干扰传播,攻击者必须控制所有节点的相当大的百分比。这是P2P网络安全和隐私设计的一部分,尤其适用于区块链。

记录到区块链中

虽然以太坊中的所有节点都是相同的对等节点,但其中一些节点由_矿工_操作,并将交易和数据块提供给_挖矿农场_,这些节点是具有高性能图形处理单元(GPU)的计算机。挖掘计算机将交易添加到候选块,并尝试查找使得候选块有效的_Proof-of-Work_。我们将在[consensus]中更详细地讨论这一点。

不深入太多细节,有效的交易最终将被包含在一个交易块中,并记录在以太坊区块链中。一旦开采成块,交易还通过修改账户余额(在简单付款的情况下)或通过调用改变其内部状态的合约来修改以太坊单例的状态。这些更改将与交易一起以交易_收据_ receipt 的形式记录,该交易也可能包含_事件_ events。我们将在 [evm] 中更详细地检查所有这些。

我们的交易已经完成了从创建到被EOA签署,传播以及最终采矿的旅程。它改变了单例的状态,并在区块链上留下了不可磨灭的印记。

多重签名(multisig)交易

如果你熟悉比特币的脚本功能,那么你就知道有可能创建一个比特币多重签名账户,该账户只能在多方签署交易时花费资金(例如2个或3个或4个签名)。以太坊的价值交易没有多重签名的规定,尽管可以部署任意条件的任意合约来处理ether和代币的转让。

为了在多重签名情况下保护你的ether,将它们转移到多重签名合约中。无论何时你想将资金转入其他账户,所有必需的用户都需要使用常规钱包软件将交易发送至合约,从而有效授权合约执行最终交易。

这些合约也可以设计为在执行本地代码或触发其他合约之前需要多个签名。该方案的安全性最终由多重签名合约代码确定

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/103041.html

相关文章

  • 你幸福吗? 幸福西饼小程序来袭

    摘要:商城小程序的轮播实现小程序的轮播图实现真是太方便了就是这么简单粗暴。遍历数组,把即选的加起来。商品的分类商品分类中主要是根据商品判断选择类别,在这里参考了林鑫大神的分类。 说在前面 从接触微信小程序到第一次动手实现一个商城小程序,我发现我们怕的不是不会写,而是不敢动手去写,每个人都是从无到有,所以勇敢踏出我们的第一步吧,看官方文档去吧骚年!showImg(https://segment...

    brianway 评论0 收藏0
  • 从程序员兼职优步司机是一种什么样的体验?

    摘要:我想说,学别人注册优步司机做优步是一个确实是很奇葩的一个尝试。从一开始就表明了我是程序员出身说实在的,做优步司机,从注册司机到上路都闹得不是很好。我想说,剩下的没一步是好走的。真心说声程序员兼职做了优步就是为了创业 我是老码农了,从05年码PHP到现在十年了。 最近一直都在找一个方向,一个事业的方向。在我同辈的人有人去创业了,有人创业失败了,有人又创业失败了。总之,到了我这个年龄,确实...

    lolomaco 评论0 收藏0
  • 这恐怕是"前后端混写"的3p家族在"前后端分离"大流中的最后

    摘要:前言前后端分离的风从我第一天当开发的时候就已经在我耳边吹得呼呼作响了听着各种前后端分离的各种牛心里还是有点痒痒后来因为各种原因转向前端慢慢地了解起来了前后端分离虽然说转向了前端但是小公司人不多后端接口还是要我写一点好了上面都是些废话下面开始 前言 前后端分离的风从我第一天当开发的时候 就已经在我耳边吹得呼呼作响了 听着各种前后端分离的各种牛X,心里还是有点痒痒 后来因为各种原因转向前...

    GT 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<