使用私鑰對字元串進行簽名,然後使用公鑰進行簽名驗證的工作流程
我知道已經提出並回答了這個問題,但是在嘗試讓一切正常工作時,我遇到了一些問題。這就是我想要做的:
1. take a target string 'Schoolbus' 2. use JSON with geth to eth_sign it 3. obtain v,r,s of signature 4. attempt to verify with a solidity contract, need the hash of 'Schoolbus'
所以這就是我得到的。首先,我們不能都使用相同的私鑰,所以如果有人可以驗證我的工作並了解我的問題的要點,那就太好了。
假裝我的 priv 密鑰是'0xd1ade25ccd3d550a7eb532ac759cac7be09c2719’,以簽署’Schoolbus’,我使用
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sign","params":["0xd1ade25ccd3d550a7eb532ac759cac7be09c2719", "Schoolbus"],"id":1}'
我在哪裡得到結果
0x2ac19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601
我正在使用(我可能在這裡錯了)
v=2a r=c19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407 s=466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601
然後我起草了契約,這是相關執行緒中答案的變體:
contract Auth { function verify( bytes32 hash, uint8 v, bytes32 r, bytes32 s) constant returns(address retAddr) { retAddr= ecrecover(hash, v, r, s); } }
因為我從來沒有得到“Schoolbus”的雜湊值,所以我在 web3.js 中嘗試了一些東西(UTF8 讓我感到困惑,我原以為 {encoding:‘hex’} 版本是正確的):
console.log('1 '+ web3.sha3(web3.toHex('Schoolbus'))); //05ab39621b81764697fcfb6ae4fcf6b023cd644721c67c13a49fbd769c75671c console.log('2 '+ web3.sha3(web3.toHex('Schoolbus'),{encoding:'hex'}));//d030d9a04df643f62a1502b017f51c41a659268091abbd20e2de97b935724d7c console.log('3 '+ web3.sha3('Schoolbus'));//d030d9a04df643f62a1502b017f51c41a659268091abbd20e2de97b935724d7c console.log('4 '+ web3.sha3( unescape(encodeURIComponent('Schoolbus')) ) ); //to UTF8 //d030d9a04df643f62a1502b017f51c41a659268091abbd20e2de97b935724d7c console.log('5 '+ web3.sha3( unescape(encodeURIComponent('Schoolbus')), {encoding:'hex'} ) ); //to UTF8 //8f1cbe7efcf383ffeb1aeaf1e826c778a087153344cbeba144fbe967ad3ab11a
我最終使用了這個,但不知道為什麼:
0xd030d9a04df643f62a1502b017f51c41a659268091abbd20e2de97b935724d7c
然後我打電話給契約:
var contDep=web3.eth.contract( [abi def] ).at( contractAddress); console.log( contDep.verify('d030d9a04df643f62a1502b017f51c41a659268091abbd20e2de97b935724d7c', 2a,'c19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407', '466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601') );
這是我的問題。我不斷收到這個奇怪的地址。它以 0x 開頭,有 20 個字節,但它沒有
$$ a-f $$在裡面:
0x3433663632613135303262303137663531633431
如果我交換 r 和 s,我會得到幾乎相同的結果。
我想知道是否有人可以驗證我的經驗,或者指出我做錯了什麼。我在這裡感覺自己像個瘋子。
感謝你的幫助。
我之前也遇到過同樣的問題,所以我將對它的工作原理給出一個廣泛的答案。我假設您使用 geth 作為客戶端。有一個開放的問題是 geth 客戶端
v
以錯誤的格式返回,所以讓我們記住,如果我們得到一個v
是0
或者1
我們應該添加27
它。如果您正在執行 node 並將 web3 連接到您最喜歡的客戶端:var msg = web3.sha3('Schoolbus') var signature = web3.eth.sign(web3.eth.accounts[0], msg)
就我而言,簽名是:
0x28c412923e03982efdff078f78bb70eaefe32c11751b0c23858191c18dddc4ba72c3667c07672b97c022beb857afb99c49b7084da1608e20392c274adc7dd5851c
該字元串分別按該順序
r
表示、s
和。但是,要將其提供給您的 Auth 合約,您需要轉換為 an並添加,確保在任何地方都有十六進制前綴:v``v``uint8``0x
var r = signature.slice(0, 66) var s = '0x' + signature.slice(66, 130) var v = '0x' + signature.slice(130, 132) v = web3.toDecimal(v) msg = '0x' + msg
記住
v
應該是27
or28
!如果不是,請設置v = v + 27
. 您現在可以呼叫您的驗證功能,如:var addr = Auth_instance.verify.call(msg, v, r, s)
並且您可以檢查它
addr
具有與 相同的值web3.eth.accounts[0]
。
這是我使用松露測試的一個工作範例:
例子.sol
pragma solidity ^0.4.0; contract Example { function testRecovery(bytes32 h, uint8 v, bytes32 r, bytes32 s) returns (address) { /* prefix might be needed for geth only * https://github.com/ethereum/go-ethereum/issues/3731 */ // bytes memory prefix = "\x19Ethereum Signed Message:\n32"; // h = sha3(prefix, h); address addr = ecrecover(h, v, r, s); return addr; } }
下面是一些範例,展示如何使用切片和測試 ecrecover 返回簽名消息的地址來獲取 v、r 和 s 值:
var Example = artifacts.require('./Example.sol') var Web3 = require('web3') var web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')) contract('Example', (accounts) => { var address = accounts[0] it('ecrecover result matches address', async function() { var instance = await Example.deployed() var msg = '0x8CbaC5e4d803bE2A3A5cd3DbE7174504c6DD0c1C' var h = web3.sha3(msg) var sig = web3.eth.sign(address, h).slice(2) var r = `0x${sig.slice(0, 64)}` var s = `0x${sig.slice(64, 128)}` var v = web3.toDecimal(sig.slice(128, 130)) + 27 var result = await instance.testRecovery.call(h, v, r, s) assert.equal(result, address) }) })
執行測試:
$ truffle test Using network 'development'. Compiling ./contracts/Example.sol... Contract: Example ✓ ecrecover result matches address (132ms) 1 passing (147ms)
在應用程序級別而不是在solidity合約中進行前綴可能會更好,因為它會更便宜。
這是一個輔助庫,其方法接受數據和簽名的雜湊並返回簽名地址。智能合約處理獲取 v、r 和 s 值,而不是在應用程序級別進行:
ECVerify.sol
pragma solidity ^0.4.4; /* * @credit https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d */ library ECVerify { function ecrecovery(bytes32 hash, bytes sig) public returns (address) { bytes32 r; bytes32 s; uint8 v; if (sig.length != 65) { return 0; } assembly { r := mload(add(sig, 32)) s := mload(add(sig, 64)) v := and(mload(add(sig, 65)), 255) } // https://github.com/ethereum/go-ethereum/issues/2053 if (v < 27) { v += 27; } if (v != 27 && v != 28) { return 0; } /* prefix might be needed for geth only * https://github.com/ethereum/go-ethereum/issues/3731 */ // bytes memory prefix = "\x19Ethereum Signed Message:\n32"; // hash = sha3(prefix, hash); return ecrecover(hash, v, r, s); } function ecverify(bytes32 hash, bytes sig, address signer) public returns (bool) { return signer == ecrecovery(hash, sig); } }
以下是一些使用 web3 創建簽名並對其進行測試的範例:
var ECVerify = artifacts.require('./ECVerify.sol') contract('ECVerify', (accounts) => { it('should return signing address from signature', async () => { var account = accounts[0] try { var instance = await ECVerify.deployed() var msg = 'some data' var hash = web3.sha3(msg) var sig = web3.eth.sign(account, hash) var signer = await instance.ecrecovery(hash, sig) assert.ok(signer) } catch(error) { console.error(error) assert.equal(error, undefined) } }) it('should verify signature is from address', async () => { var account = accounts[0] try { var instance = await ECVerify.deployed() var msg = 'some data' var hash = web3.sha3(msg) var sig = web3.eth.sign(account, hash) var verified = await instance.ecverify.call(hash, sig, account) assert.ok(verified) } catch(error) { console.error(error) assert.equal(error, undefined) } }) })
測試它是否有效:
$ truffle test Compiling ./contracts/ECVerify.sol... Compiling ./contracts/Migrations.sol... Contract: ECVerify ✓ should return signing address from signature (182ms) ✓ should verify signature is from address (142ms) 2 passing (342ms)
有關的