行业新闻

6,通过预编译合约大幅降低开发成本【AG体育|正规平台】

作者:AG体育|正规平台 日期:2021-03-23 点击:52215

ag投注:腹 景以太坊中的ecrecover函数可以用来提供对一条消息亲笔签名的地址。这对于证明一条消息或者一段数据被一个登录的账户亲笔签名过(而不是被伪造过)十分简单。但是 Qtum 没用于以太坊的账户模型,而是使用比特币的 UTXO 模型,地址的算法也和以太坊有所不同,因此这个函数并不限于于 Qtum。在一些必须检验亲笔签名来源信息的情况下, Qtum 开发者并无法便利的在智能合约中已完成这个检验,网卓新闻网,而是必须在合约中原始构建或者调用一次从亲笔签名和消息提供签名者公钥的合约,不会导致十分大的支出,进而使得适当合约的调用费用十分低。

问题的细节ecrecover拒绝接受一个消息的哈希和消息的亲笔签名,然后计算出来出有亲笔签名的私钥对应的公钥,并将该公钥切换为以太坊地址格式。然而以太坊的地址算法和 Qtum 有所不同,而且ecrecover回到的是公钥经过哈希以后的结果,这个过程不可逆,因此在 Qtum 上无法用于这个函数。

AG体育平台

在以太坊中,地址计算方法如下:keccak256(pubkey)而在 Qtum 上,地址的计算出来方式和比特币完全相同,用于如下计算方法:ripemd160(sha256(pubkey))在 Qtum 的合约中,msg.sender是一个 Qtum 地址。由于从公钥开始切换为地址的每一步操作者都是不可逆的,ecrecover回到的以太坊地址无法和msg.sender中的 Qtum 地址展开较为。而现有的 Qtum 智能合约中并没获取任何函数来从消息亲笔签名中提供 Qtum 地址,这造成 Qtum 智能合约开发者们被迫研发或用于Secp256k1涉及的库来计算出来亲笔签名公钥和地址,导致更大的计算出来支出和更高的合约费用。另一个必须留意的细节是,Qtum 延用的比特币消息亲笔签名算法和以太坊的消息亲笔签名算法的构建上有一些微小的差异:以太坊的亲笔签名按如下格式构成:[r][s][v]而 Qtum 的亲笔签名则是:[v][r][s]其中v是 recover id,r是椭圆曲线上的一个点R的X座标,s是这个点R的Y座标。

如上的有所不同造成 Qtum 和以太坊的 recover 算法的构建细节也不完全相同。QIP-6 的解决方案通过在 Qtum 的虚拟机中减少一个实编译器的合约,以获取一个用来调用 Qtum 核心代码中的 recover 代码的模块。

智能合约开发者只必须写出非常简单的一两个函数就能从亲笔签名消息中提供到签名者的地址。追加的预编译器合约的模块和ecrecover保持一致。什么是实编译器合约实编译器合约是 EVM 中为了获取一些不合适写 opcode 的更为简单的库函数(多数用作加密、哈希等简单计算出来)而使用的一种折衷方案。

由于它是用底层代码构建的,继续执行速度快,对于开发者来说就比必要用运营在 EVM 上的函数消耗更加较低。以太坊中用于实编译器合约获取一些常用的更为繁复的操作者,比如sha256、ripemd160hash等。实编译器合约的构建实编译器合约的核心代码由虚拟机底层(C++)构建,通过在虚拟机的初始化过程中登记到人为登录的相同地址上来获取智能合约调用的模块。

ag投注

实编译器合约的用于一个典型的调用方式:assembly { if iszero(call(gasLimit, contractAddress, value, input, inputLength, output, outputLength)) { revert(0, 0) }}在新版本的虚拟机中,还可以用于staticcall:assembly { success := staticcall(gasLimit, contractAddress, input, inputLength, output, outputLength)}其中contractAddress就是要调用的预编译器合约的地址,本次 Qtum 追加的 btc_ecrecover 的地址是0x85。input是调用合约的参数列表。这个调用的返回值代表了调用否顺利,1回应顺利,0回应告终。而回到的数据不会载入到output里面。

下面我们看一个例子:pragma solidity ^0.5.0;/*** @title Elliptic curve signature operations* @dev Based onhttps://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d* TODO Remove this library once solidity supports passing a signature to ecrecover.* See https://github.com/ethereum/solidity/issues/864*/library ECDSA { /*** @dev Recover signer address from a message by using their signature.* @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address.* @param signature bytes signature, the signature is generated using web3.eth.sign()*/ function recover(bytes32 hash, bytes memory signature) internal view returns (address) { // Check the signature length if (signature.length != 65) { return (address(0)); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { v := byte(0, mload(add(signature, 0x20))) r := mload(add(signature, 0x21)) s := mload(add(signature, 0x41)) } // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0ssecp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s)0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return address(0); } // Support both compressed or uncompressed if (v != 27v != 28v != 31v != 32) { return address(0); } // If the signature is valid (and not malleable), return the signer address return btc_ecrecover(hash, v, r, s); } function btc_ecrecover(bytes32 msgh, uint8 v, bytes32 r, bytes32 s) public view returns(address) { uint256[4] memory input; input[0] = uint256(msgh); input[1] = v; input[2] = uint256(r); input[3] = uint256(s); uint256[1] memory retval; uint256 success; assembly { success := staticcall(not(0), 0x85, input, 0x80, retval, 32) } if (success != 1) { return address(0); } return address(retval[0]); }}在上面这个例子中,只要调用btc_ecrecover函数就能提供到消息签名者的地址。为了修改输出,例子中也PCB了一个recover函数,使得开发者只要起源于完整亲笔签名就能已完成合约调用。下面我们不用于实编译器合约,而是几乎用于 solidity 代码构建 btc_ecrecover功能。

代码构建如下:pragma solidity ^0.4.26;import {ECCMath} from "github.com/androlo/standard-contracts/contracts/src/crypto/ECCMath.sol";import {Secp256k1} from "github.com/androlo/standard-contracts/contracts/src/crypto/Secp256k1.sol";library ECDSA { uint256 constant p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f; uint256 constant n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141; uint256 constant gx = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798; uint256 constant gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8; function recover(bytes32 hash, bytes memory signature) internal view returns (address) { if (signature.length != 65) { return (address(0)); } bytes32 r; bytes32 s; uint8 v; assembly { v := byte(0, mload(add(signature, 0x20))) r := mload(add(signature, 0x21)) s := mload(add(signature, 0x41)) } if (uint256(s)n / 2) { return address(0); } if (v != 27v != 28v != 31v != 32) { return address(0); } return btc_ecrecover(hash, v, r, s); } function btc_ecrecover(bytes32 msgh, uint8 v, bytes32 r, bytes32 s) public view returns (address) { uint i = 0; uint256 rr = uint256(r); uint256 ss = uint256(s); bool isYOdd = ((v - 27)1) != 0; bool isSecondKey = ((v - 27)2) != 0; bool isCompressed = ((v - 27)4) != 0; if (rr = p % nisSecondKey) { return address(0); } uint256[3] memory P = _getPoint(uint256(msgh), rr, ss, isYOdd, isSecondKey); if (P[2] == 0) { return address(0); } ECCMath.toZ1(P, p); bytes memory publicKey; if (isCompressed) { publicKey = new bytes(33); publicKey[0] = byte(P[1] % 2 == 0 ? 2 : 3); for (i = 0; i32; ++i) { publicKey[32 - i] = byte((P[0](8 * i))0xff); } } else { publicKey = new bytes(65); publicKey[0] = 4; for (i = 0; i32; ++i) { publicKey[32 - i] = byte((P[0](8 * i))0xff); publicKey[64 - i] = byte((P[1](8 * i))0xff); } } return address(ripemd160(sha256(publicKey))); } function _getPoint(uint256 msgh, uint256 r, uint256 s, bool isYOdd, bool isSecondKey) internal view returns (uint256[3] memory) { uint256 rx = isSecondKey ? r + n : r; uint256 ry = ECCMath.expmod(ECCMath.expmod(rx, 3, p) + 7, p / 4 + 1, p); if (isYOdd != (ry % 2 == 1)) { ry = p - ry; } uint256 invR = ECCMath.invmod(r, n); return Secp256k1._add( Secp256k1._mul(n - mulmod(msgh, invR, n), [gx, gy]), Secp256k1._mul(mulmod(s, invR, n), [rx, ry]) ); }}我们在测试链上部署了上述两个两个合约,地址分别如下:实编译器合约: 21ea1d8376d1820d7091084a76f380143b59aaf8solidity构建: 4fdff1b4bde5edf13360ff0946518a01115ce818用于地址qQqip6i2e2buCZZNdqMw4VNpaYpnLm4JAx对消息btc_ecrecover test展开亲笔签名,我们获得btc_ecrecover 的调用参数:bytes32 msgh = 0xdfa80e3294fd8806ab908904403db376b3dd35c6356ab2d3b884db4f6ec5e93duint8 v = 0x20bytes32 r = 0xca08c0813407de3a78053c976462eacbde3fd69843e21acf8dd636149bf4b753bytes32 s = 0x0731bce3ed9b489da0165af79759c1d586ef8fe53b3aab95fcab68d01ed6f156两个合约调用调用结果如下:1.实编译器合约callcontract 21ea1d8376d1820d7091084a76f380143b59aaf8 69bc0963dfa80e3294fd8806ab908904403db376b3dd35c6356ab2d3b884db4f6ec5e93d0000000000000000000000000000000000000000000000000000000000000020ca08c0813407de3a78053c976462eacbde3fd69843e21acf8dd636149bf4b7530731bce3ed9b489da0165af79759c1d586ef8fe53b3aab95fcab68d01ed6f156{"address": "21ea1d8376d1820d7091084a76f380143b59aaf8","executionResult": { "gasUsed": 32688, "excepted": "None", "newAddress": "21ea1d8376d1820d7091084a76f380143b59aaf8", "output": "0000000000000000000000004fdff1b4bde5edf13360ff0946518a01115ce818", "codeDeposit": 0, "gasRefunded": 0, "depositSize": 0, "gasForDeposit": 0, "exceptedMessage": ""},"transactionReceipt": { "stateRoot": "5d9e1ad1b5d09e9e7c41d09078434488927366adf8ebf5a0049bb99610a817f1", "gasUsed": 32688, "bloom": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "log": []}}2.solidity 构建callcontract d3764a0b7fbbe2e39ee4adc3908b5b5dbea22c14 69bc0963dfa80e3294fd8806ab908904403db376b3dd35c6356ab2d3b884db4f6ec5e93d0000000000000000000000000000000000000000000000000000000000000020ca08c0813407de3a78053c976462eacbde3fd69843e21acf8dd636149bf4b7530731bce3ed9b489da0165af79759c1d586ef8fe53b3aab95fcab68d01ed6f156{"address": "d3764a0b7fbbe2e39ee4adc3908b5b5dbea22c14","executionResult": { "gasUsed": 886077, "excepted": "None", "newAddress": "d3764a0b7fbbe2e39ee4adc3908b5b5dbea22c14", "output": "0000000000000000000000004fdff1b4bde5edf13360ff0946518a01115ce818", "codeDeposit": 0, "gasRefunded": 0, "depositSize": 0, "gasForDeposit": 0, "exceptedMessage": ""},"transactionReceipt": { "stateRoot": "5d9e1ad1b5d09e9e7c41d09078434488927366adf8ebf5a0049bb99610a817f1", "gasUsed": 886077, "bloom": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "log": []}}可见实编译器合约调用btc_ecrecover必须花费 32688 gas,而几乎用 solidity 构建必须 886077 gas。实编译器合约构建的 gas 花费相比之下多于 solidity 构建。QIP-6 的影响QIP-6 大大增大了智能合约开发者的开发成本。

从调用合约的角度来说,如果几乎用 solidity 在合约中构建 recover,其 gas 使用量相比之下多达btc_ecrecover函数。于是用于btc_ecrecover来提供消息亲笔签名地址的合约调用成本也大大降低。

此外,QIP-6 也让 Qtum 的智能合约系统更为完善。另一方面,QIP-6 没对原先的ecrecover展开改动,维持了 Qtum 和以太坊的兼容性,理论上会带给任何风险。|ag投注。

本文来源:ag体育-www.tsitf.com