Transactions

使用私鑰對字元串進行簽名,然後使用公鑰進行簽名驗證的工作流程

  • March 10, 2018

我知道已經提出並回答了這個問題,但是在嘗試讓一切正常工作時,我遇到了一些問題。這就是我想要做的:

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以錯誤的格式返回,所以讓我們記住,如果我們得到一個v0或者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應該是27or 28!如果不是,請設置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)

有關的

引用自:https://ethereum.stackexchange.com/questions/1777