Solidity
如何使用 ethereumjs-utils 簽署和驗證數據?
在我的契約中,我正在驗證所有者是否正確簽署了某些數據。它看起來像這樣:
require( owner() == ecrecover(keccak256(abi.encodePacked(this, aCustomId)), v, r, s), "owner should sign aCustomId" );
這意味著我應該從後端檢索 v、r、s,我目前這樣做:
import * as ethUtil from 'ethereumjs-util'; const hash = soliditySha3( 'myContractAddress', '11111', ); const signature = ethUtil.ecsign( ethUtil.toBuffer(hash), wallet.getPrivateKey(), ); return { r: ethUtil.bufferToHex(signature.r), s: ethUtil.bufferToHex(signature.s), v: signature.v, aCustomId: 11111, }; // return the v, r, s
但是,這似乎不正確,因為我不斷收到“所有者應該簽署 aCustomId”。
如何創建正確的雜湊,以便我的 v,r,s 參數正確以便以後恢復?
我正在使用solidity 0.6.12版本
契約的名稱如下:
myContract.methods .someMethod( 11111, vValueAsInt, "sValue", "rValue", ) .send({ from: account }, function( error: any, transactionHash: any ) { console.log(transactionHash); console.log(error); });
這是 web3js 1.3.0、ethereumjs-utils 5.2.5 和solidity 0.6.12 的工作程式碼:
Javascript 部分
//hash the data const hash = web3.utils.soliditySha3( myContractAddress, aCustomId, ); //prefix the hash const prefixedHash = ethUtil.hashPersonalMessage(ethUtil.toBuffer(hash)); //get the ECDSA signature and its r,s,v parameters const privateKey = new Buffer(myPrivateKey, "hex") const signature = ethUtil.ecsign(prefixedHash, privateKey); r = ethUtil.bufferToHex(signature.r), s = ethUtil.bufferToHex(signature.s), v = signature.v; //call the contract method myContract.methods.verifySig(accountAddress, aCustomId, r, s, v) .send({ from: accountAddress }).on('receipt', function(receipt){ console.log(receipt); })
請注意,我們使用
hashPersonalMessage
除了soliditySha3
為了在簽名之前為數據添加前綴。這個前綴是 :"\x19Ethereum Signed Message:\n32"
。這是一種安全標準,可防止諸如惡意嘗試使使用者簽署交易同時讓他相信他正在簽署消息的攻擊。智能合約
function verifySig(address owner, uint256 aCustomId, bytes32 r, bytes32 s, uint8 v) public view { bytes memory prefix = "\x19Ethereum Signed Message:\n32"; bytes32 hash = keccak256(abi.encodePacked(address(this), aCustomId)); bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, hash)); require(ecrecover(prefixedHash, v, r, s) == owner); }
這裡有兩個重要的事情是:
- 獲取我們使用
address(this)
(而不是this
)的合約地址。- 我們執行與後端相同的操作:首先我們散列數據,然後計算前綴散列。