ECRecovery.sol 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. pragma solidity ^0.4.11;
  2. /**
  3. * @title Eliptic curve signature operations
  4. *
  5. * @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d
  6. */
  7. library ECRecovery {
  8. /**
  9. * @dev Duplicate Solidity's ecrecover, but catching the CALL return value
  10. * @param hash bytes32 messahe hash from which the signature will be recovered
  11. * @param v uint8 signature version
  12. * @param r bytes32 signature r value
  13. * @param s bytes32 signature s value
  14. */
  15. function safeRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) constant returns (bool, address) {
  16. // We do our own memory management here. Solidity uses memory offset
  17. // 0x40 to store the current end of memory. We write past it (as
  18. // writes are memory extensions), but don't update the offset so
  19. // Solidity will reuse it. The memory used here is only needed for
  20. // this context.
  21. bool ret;
  22. address addr;
  23. assembly {
  24. let size := mload(0x40)
  25. mstore(size, hash)
  26. mstore(add(size, 32), v)
  27. mstore(add(size, 64), r)
  28. mstore(add(size, 96), s)
  29. // NOTE: we can reuse the request memory because we deal with
  30. // the return code
  31. ret := call(3000, 1, 0, size, 128, size, 32)
  32. addr := mload(size)
  33. }
  34. return (ret, addr);
  35. }
  36. /**
  37. * @dev Recover signer address from a message by using his signature
  38. * @param hash bytes32 messahe hash from which the signature will be recovered
  39. * @param sig bytes signature
  40. */
  41. function recover(bytes32 hash, bytes sig) constant returns (address) {
  42. bytes32 r;
  43. bytes32 s;
  44. uint8 v;
  45. if (sig.length != 65)
  46. return (address(0));
  47. assembly {
  48. r := mload(add(sig, 32))
  49. s := mload(add(sig, 64))
  50. v := byte(0, mload(add(sig, 96)))
  51. }
  52. // albeit non-transactional signatures are not specified by the YP, one would expect it
  53. // to match the YP range of [27, 28]
  54. //
  55. // geth uses [0, 1] and some clients have followed. This might change, see:
  56. // https://github.com/ethereum/go-ethereum/issues/2053
  57. if (v < 27)
  58. v += 27;
  59. if (v != 27 && v != 28)
  60. return (address(0));
  61. bool ret;
  62. address addr;
  63. (ret, addr) = safeRecover(hash, v, r, s);
  64. if (!ret)
  65. return address(0);
  66. else
  67. return addr;
  68. }
  69. }