区块链系列十三:sign & verify

要在eth链上验证一个签名, 可以用solidity内置的ecrecover函数, 但是。。。。

ecrecover

可以先用这两个工具试一下:

myetherwallet这个我感觉有点问题, 对于带0x的message签名出来跟我调用web3.eth.sign或者etherscan的签名不一样, 估计是把0x开头的消息特殊处理了。

签名可以直接通过web3.js的web3.eth.sign去签名, 实际上还是走的eth client的签名。 然而要验证签名, 居然eth client没有提供这个功能, 网上教程全是部署一个合约, 然后用solidity的ecrecover去验证的, 感觉好奇怪。

几个坑

r/s/v的获取

根据官方文档说法, 签名出来表示成hex是0x..., 如果把0x一起算上总长度是130哦,最好理解的是如下:

// https://ethereum.stackexchange.com/questions/15364/ecrecover-from-geth-and-web3-eth-sign
    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

注意, v要加27哦, web3.js里的example就没有添加, 而且注意那段代码里的sig是含0x的, 所以长度是132!!!

function splitSig(sig) {
  return {
    v: ethWeb3.toDecimal('0x' + sig.slice(130, 132)),
    r: sig.slice(0, 66),
    s: sig.slice(66, 130)
  }

}

因为sig含了0x, 所以r取sig.slice(0, 66)已经有了0x, 而s还没有, 所以在114行, 加了0x, 导致代码很难读:

 var finalAddress=sigContractInstance.verify.call(strPrefixedMsg, res.v, res.r, '0x'+ res.s);

自定义前缀

为了避免arbitrary payloads的问题, eth里的签名添加了\x19Ethereum Signed Message:\n<length of message>前缀, 所以要用ecrecover去verify的时候, 也要加上!

不用eecrecover

如果我只是要验证签名(不需要在链上验证), 完全没有理由说我还要部署一个smart contract去做这个事情啊。

bitcoin和eth都用的是ECC(elliptic curve cryptography), eth用的是secp256k1, 这个是有标准的, 理论上而言, 你用任何语言都可以实现(实际上也是有各种语言版本的开源代码啦)。

至于为什么都用ECC而不是常见的RSA呢, 简单来说, 同样的安全强度, ECC有更短的private key和更快的速度。

后面专门写一篇介绍ECC。

Refs