您的位置:首頁(yè) > 區(qū)塊鏈 >

QIP-6減小智能合約的開發(fā)成本 完備Qtum的智能合約系統(tǒng)

2019-09-26 14:12:41 來(lái)源: 區(qū)塊網(wǎng)

背 景以太坊中的ecrecover函數(shù)可以用來(lái)獲取對(duì)一條消息簽名的地址。這對(duì)于證明一條消息或者一段數(shù)據(jù)被一個(gè)指定的賬戶簽名過(guò)(而不是被篡改過(guò))

背 景

以太坊中的ecrecover函數(shù)可以用來(lái)獲取對(duì)一條消息簽名的地址。這對(duì)于證明一條消息或者一段數(shù)據(jù)被一個(gè)指定的賬戶簽名過(guò)(而不是被篡改過(guò))非常有用。但是 Qtum 沒有使用以太坊的賬戶模型,而是采用比特幣的 UTXO 模型,地址的算法也和以太坊不同,因此這個(gè)函數(shù)并不適用于 Qtum。

在一些需要驗(yàn)證簽名來(lái)源信息的情況下, Qtum 開發(fā)者并不能方便的在智能合約中完成這個(gè)驗(yàn)證,而是需要在合約中完整實(shí)現(xiàn)或者調(diào)用一次從簽名和消息獲取簽名者公鑰的合約,會(huì)造成非常大的開銷,進(jìn)而使得相應(yīng)合約的調(diào)用費(fèi)用非常高。

問(wèn)題的細(xì)節(jié)

ecrecover接受一個(gè)消息的哈希和消息的簽名,然后計(jì)算出簽名的私鑰對(duì)應(yīng)的公鑰,并將該公鑰轉(zhuǎn)換為以太坊地址格式。然而以太坊的地址算法和 Qtum 不同,而且ecrecover返回的是公鑰經(jīng)過(guò)哈希以后的結(jié)果,這個(gè)過(guò)程不可逆,因此在 Qtum 上無(wú)法使用這個(gè)函數(shù)。

在以太坊中,地址計(jì)算方法如下:

keccak256(pubkey)

而在 Qtum 上,地址的計(jì)算方式和比特幣相同,使用如下計(jì)算方法:

ripemd160(sha256(pubkey))

在 Qtum 的合約中,msg.sender是一個(gè) Qtum 地址。由于從公鑰開始轉(zhuǎn)換為地址的每一步操作都是不可逆的,ecrecover返回的以太坊地址無(wú)法和msg.sender中的 Qtum 地址進(jìn)行比較。而現(xiàn)有的 Qtum 智能合約中并沒有提供任何函數(shù)來(lái)從消息簽名中獲取 Qtum 地址,這導(dǎo)致 Qtum 智能合約開發(fā)者們不得不開發(fā)或使用Secp256k1相關(guān)的庫(kù)來(lái)計(jì)算簽名公鑰和地址,造成更大的計(jì)算開銷和更高的合約費(fèi)用。

另一個(gè)需要注意的細(xì)節(jié)是,Qtum 沿用的比特幣消息簽名算法和以太坊的消息簽名算法的實(shí)現(xiàn)上有一些細(xì)微的差別:

以太坊的簽名按如下格式組成:

[r][s][v]

而 Qtum 的簽名則是:

[v][r][s]

其中v是 recover id,r是橢圓曲線上的一個(gè)點(diǎn)R的X坐標(biāo),s是這個(gè)點(diǎn)R的Y坐標(biāo)。如上的不同導(dǎo)致 Qtum 和以太坊的 recover 算法的實(shí)現(xiàn)細(xì)節(jié)也不相同。

QIP-6 的解決方案

通過(guò)在 Qtum 的虛擬機(jī)中增加一個(gè)預(yù)編譯的合約,以提供一個(gè)用來(lái)調(diào)用 Qtum 核心代碼中的 recover 代碼的接口。智能合約開發(fā)者只需要寫簡(jiǎn)單的一兩個(gè)函數(shù)就能從簽名消息中獲取到簽名者的地址。新增的預(yù)編譯合約的接口和ecrecover保持一致。

什么是預(yù)編譯合約

預(yù)編譯合約是 EVM 中為了提供一些不適合寫成 opcode 的較為復(fù)雜的庫(kù)函數(shù)(多數(shù)用于加密、哈希等復(fù)雜計(jì)算)而采用的一種折中方案。由于它是用底層代碼實(shí)現(xiàn)的,執(zhí)行速度快,對(duì)于開發(fā)者來(lái)說(shuō)就比直接用運(yùn)行在 EVM 上的函數(shù)消耗更低。以太坊中使用預(yù)編譯合約提供一些常用的較為繁瑣的操作,比如sha256、ripemd160hash等。

預(yù)編譯合約的實(shí)現(xiàn)

預(yù)編譯合約的核心代碼由虛擬機(jī)底層(C++)實(shí)現(xiàn),通過(guò)在虛擬機(jī)的初始化過(guò)程中注冊(cè)到人為指定的固定地址上來(lái)提供智能合約調(diào)用的接口。

預(yù)編譯合約的使用

一個(gè)典型的調(diào)用方式:

assembly {

if iszero(call(gasLimit, contractAddress, value, input, inputLength, output, outputLength)) {

revert(0, 0)

}

}

在新版本的虛擬機(jī)中,還可以使用staticcall:

assembly {

success := staticcall(gasLimit, contractAddress, input, inputLength, output, outputLength)

}

其中contractAddress就是要調(diào)用的預(yù)編譯合約的地址,本次 Qtum 新增的 btc_ecrecover 的地址是0x85。input是調(diào)用合約的參數(shù)列表。這個(gè)調(diào)用的返回值代表了調(diào)用是否成功,1表示成功,0表示失敗。而返回的數(shù)據(jù)會(huì)寫入到output里面。

下面我們看一個(gè)例子:

pragma solidity ^0.5.0;

/**

* @title Elliptic curve signature operations

* @dev Based on

https://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): 0 < s < secp256k1n ÷ 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 != 27 && v != 28 && v != 31 && v != 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]);

}

}

在上面這個(gè)例子中,只要調(diào)用btc_ecrecover函數(shù)就能獲取到消息簽名者的地址。為了簡(jiǎn)化輸入,例子中也封裝了一個(gè)recover函數(shù),使得開發(fā)者只要傳入原始簽名就能完成合約調(diào)用。

下面我們不使用預(yù)編譯合約,而是完全使用 solidity 代碼實(shí)現(xiàn) btc_ecrecover功能。代碼實(shí)現(xiàn)如下:

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 != 27 && v != 28 && v != 31 && v != 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 % n && isSecondKey) {

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; i < 32; ++i) {

publicKey[32 - i] = byte((P[0] >> (8 * i)) & 0xff);

}

} else {

publicKey = new bytes(65);

publicKey[0] = 4;

for (i = 0; i < 32; ++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])

);

}

}

我們?cè)跍y(cè)試鏈上部署了上述兩個(gè)兩個(gè)合約,地址分別如下:

預(yù)編譯合約: 21ea1d8376d1820d7091084a76f380143b59aaf8

solidity實(shí)現(xiàn): 4fdff1b4bde5edf13360ff0946518a01115ce818

使用地址

qQqip6i2e2buCZZNdqMw4VNpaYpnLm4JAx對(duì)消息btc_ecrecover test進(jìn)行簽名,我們得到btc_ecrecover 的調(diào)用參數(shù):

bytes32 msgh = 0xdfa80e3294fd8806ab908904403db376b3dd35c6356ab2d3b884db4f6ec5e93d

uint8 v = 0x20

bytes32 r = 0xca08c0813407de3a78053c976462eacbde3fd69843e21acf8dd636149bf4b753

bytes32 s = 0x0731bce3ed9b489da0165af79759c1d586ef8fe53b3aab95fcab68d01ed6f156

兩個(gè)合約調(diào)用調(diào)用結(jié)果如下:

1.預(yù)編譯合約

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 實(shí)現(xiàn)

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": []

}

}

可見預(yù)編譯合約調(diào)用btc_ecrecover需要花費(fèi) 32688 gas,而完全用 solidity 實(shí)現(xiàn)需要 886077 gas。預(yù)編譯合約實(shí)現(xiàn)的 gas 花費(fèi)遠(yuǎn)遠(yuǎn)少于 solidity 實(shí)現(xiàn)。

QIP-6 的影響

QIP-6 大大減小了智能合約開發(fā)者的開發(fā)成本。從調(diào)用合約的角度來(lái)說(shuō),如果完全用 solidity 在合約中實(shí)現(xiàn) recover,其 gas 使用量遠(yuǎn)遠(yuǎn)超過(guò)btc_ecrecover函數(shù)。于是使用btc_ecrecover來(lái)獲取消息簽名地址的合約調(diào)用成本也大大降低。此外,QIP-6 也讓 Qtum 的智能合約系統(tǒng)更加完備。

另一方面,QIP-6 沒有對(duì)原有的ecrecover進(jìn)行修改,保持了 Qtum 和以太坊的兼容性,理論上不會(huì)帶來(lái)任何風(fēng)險(xiǎn)。(Qtum量子鏈)

關(guān)鍵詞: QIP-6 智能合約 Qtum

精選 導(dǎo)讀

募資55億港元萬(wàn)物云啟動(dòng)招股 預(yù)計(jì)9月29日登陸港交所主板

萬(wàn)科9月19日早間公告,萬(wàn)物云當(dāng)日啟動(dòng)招股,預(yù)計(jì)發(fā)行價(jià)介乎每股47 1港元至52 7港元,預(yù)計(jì)9月29日登陸港交所主板。按發(fā)行1 167億股計(jì)算,萬(wàn)

發(fā)布時(shí)間: 2022-09-20 10:39
管理   2022-09-20

公募基金二季度持股情況曝光 隱形重倉(cāng)股多為高端制造業(yè)

隨著半年報(bào)披露收官,公募基金二季度持股情況曝光。截至今年二季度末,公募基金全市場(chǎng)基金總數(shù)為9794只,資產(chǎn)凈值為269454 75億元,同比上

發(fā)布時(shí)間: 2022-09-02 10:45
資訊   2022-09-02

又有上市公司宣布變賣房產(chǎn) 上市公司粉飾財(cái)報(bào)動(dòng)作不斷

再有上市公司宣布變賣房產(chǎn)。四川長(zhǎng)虹25日稱,擬以1 66億元的轉(zhuǎn)讓底價(jià)掛牌出售31套房產(chǎn)。今年以來(lái),A股公司出售房產(chǎn)不斷。根據(jù)記者不完全統(tǒng)

發(fā)布時(shí)間: 2022-08-26 09:44
資訊   2022-08-26

16天12連板大港股份回復(fù)深交所關(guān)注函 股份繼續(xù)沖高

回復(fù)交易所關(guān)注函后,大港股份繼續(xù)沖高。8月11日大港股份高開,隨后震蕩走高,接近收盤時(shí)觸及漲停,報(bào)20 2元 股。值得一提的是,在7月21日

發(fā)布時(shí)間: 2022-08-12 09:56
資訊   2022-08-12

萬(wàn)家基金再添第二大股東 中泰證券擬受讓11%基金股權(quán)

7月13日,中泰證券發(fā)布公告,擬受讓齊河眾鑫投資有限公司(以下簡(jiǎn)稱齊河眾鑫)所持有的萬(wàn)家基金11%的股權(quán),交易雙方共同確定本次交易的標(biāo)的資

發(fā)布時(shí)間: 2022-07-14 09:39
管理   2022-07-14

央行連續(xù)7日每天30億元逆回購(gòu) 對(duì)債市影響如何?

央行12日再次開展了30億元逆回購(gòu)操作,中標(biāo)利率2 10%。這已是央行連續(xù)7日每天僅進(jìn)行30億元的逆回購(gòu)縮量投放,創(chuàng)下去年1月以來(lái)的最低操作規(guī)

發(fā)布時(shí)間: 2022-07-13 09:38
資訊   2022-07-13

美元指數(shù)創(chuàng)近20年新高 黃金期貨創(chuàng)出逾9個(gè)月新低

由于對(duì)美聯(lián)儲(chǔ)激進(jìn)加息的擔(dān)憂,美元指數(shù)11日大漲近1%創(chuàng)出近20年新高。受此影響,歐美股市、大宗商品均走弱,而黃金期貨創(chuàng)出逾9個(gè)月新低。美

發(fā)布時(shí)間: 2022-07-13 09:36
資訊   2022-07-13

美股三大股指全線下跌 納斯達(dá)克跌幅創(chuàng)下記錄以來(lái)最大跌幅

今年上半年,美股持續(xù)回落。數(shù)據(jù)顯示,道瓊斯指數(shù)上半年下跌15 3%,納斯達(dá)克綜合指數(shù)下跌29 5%,標(biāo)普500指數(shù)下跌20 6%。其中,納斯達(dá)克連續(xù)

發(fā)布時(shí)間: 2022-07-04 09:51
推薦   2022-07-04

融資客熱情回升 兩市融資余額月內(nèi)增加超344億元

近期A股走強(qiáng),滬指6月以來(lái)上漲4%,融資客熱情明顯回升。數(shù)據(jù)顯示,截至6月16日,兩市融資余額1 479萬(wàn)億元,月內(nèi)增加344 67億元,最近一個(gè)半

發(fā)布時(shí)間: 2022-06-20 09:41
資訊   2022-06-20

4個(gè)交易日凈買入超百億元 北向資金持續(xù)流入A股市場(chǎng)

北向資金凈流入態(tài)勢(shì)延續(xù)。繼6月15日凈買入133 59億元后,北向資金6月16日凈買入44 52億元。自5月27日至今,除6月13日以外,北向資金累計(jì)凈

發(fā)布時(shí)間: 2022-06-17 09:37
推薦   2022-06-17

熱門TAG

more
美聯(lián)儲(chǔ)今年已將基準(zhǔn)利率從接近零大幅上調(diào)至略高于3% EIA報(bào)告:美國(guó)原油庫(kù)存及戰(zhàn)略儲(chǔ)備減少,汽油及精煉油庫(kù)存輕微波動(dòng) 美國(guó)政府更廣泛推動(dòng)從汽油動(dòng)力汽車轉(zhuǎn)向電動(dòng)汽車的一部分 數(shù)據(jù)顯示:今年9月日本船企接單量延續(xù)8月下跌下跌趨勢(shì) 公告顯示:2022年前三季度TCL中環(huán)研發(fā)投入為27億元 占比營(yíng)業(yè)收入5.42% 新的111.75億英鎊注資列在“對(duì)金融機(jī)構(gòu)的援助—支付給英格蘭銀行”標(biāo)題下 本次政府儲(chǔ)備肉投放面向北京18家主要連鎖超市門店及相關(guān)零售終端投放 有交易員預(yù)計(jì):如果LME不采取措施 接下來(lái)可能將有數(shù)十萬(wàn)噸鋁流入LME 據(jù)報(bào)道:繼德國(guó)最大釀酒商拉德貝格啤酒公司9月宣布漲價(jià) 據(jù)報(bào)道:澳大利亞礦商Pilbara的鋰礦拍賣價(jià)再創(chuàng)新高 折算后的碳酸鋰成本 中集天達(dá)首次公開發(fā)行A股股票 招股書顯示此次擬公開發(fā)行股數(shù)不超過(guò)103, 多家銀行加強(qiáng)綠色金融頂層設(shè)計(jì) 致力于為經(jīng)濟(jì)社會(huì)綠色低碳轉(zhuǎn)型貢獻(xiàn)力量 萊特幣 比特幣 數(shù)字資產(chǎn) 火幣 以太經(jīng)典 比特股 EOS 比特幣現(xiàn)金 量子鏈 Hcash 泰達(dá)幣 瑞波幣 Qcash 比特幣鉆石 超級(jí)比特幣 優(yōu)幣 硬分叉 加密貨幣