55

I was stuck on this issue as well for a very long time. So the solution is: Add this prefix string to your Solidity smart contract. function verify(bytes32 hash, uint8 v, bytes32 r, bytes32 s) constant returns(bool) { bytes memory prefix = "\x19Ethereum Signed Message:\n32"; bytes32 prefixedHash = keccak256(prefix, hash); return ecrecover(...


18

v, r, and s are parameters that can be parsed from the signature. Here's a good example from the ethereumjs utils library: var sig = secp256k1.sign(msgHash, privateKey) var ret = {} ret.r = sig.signature.slice(0, 32) ret.s = sig.signature.slice(32, 64) ret.v = sig.recovery + 27 Note how you can parse each value from a given signature. Even ...


14

According to issue #3731: Geth prepends the string \x19Ethereum Signed Message:\n<length of message> to all data before signing it (https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign). If you want to verify such a signature from Solidity, you'll have to prepend the same string in solidity before doing the ecrecovery. Here's a working example I ...


13

According to issue #3731: Geth prepends the string \x19Ethereum Signed Message:\n<length of message> to all data before signing it (https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign). If you want to verify such a signature from Solidity, you'll have to prepend the same string in solidity before doing the ecrecovery. Here's a working example I ...


12

Geth adds prefix to the message before siginig it in web3.eth.sign (see JSON-PRC spec). Without this it can be possible to trick user to sign transaction (more here). So, the correct code to sign message with web3.eth.sign and recover address with ethereumjs-util.ecrecover or (Solidity's ecrecover) should add the prefix explicitly. const util = require('...


12

ecrecover returns public key, you need to convert it to address with pubToAddress. pub = ethJsUtil.ecrecover(msg, v, r, s); addrBuf = ethJsUtil.pubToAddress(pub); addr = ethJsUtil.bufferToHex(addrBuf); Also, you can use fromRpcSig to get v, r, s sig = web3.eth.sign(myAccount,msg) res = ethJsUtil.fromRpcSig(sig) pub = ethJsUtil.ecrecover(msg, res.v, ...


7

So, with thanks to Adil (see above), here is the finished code that I used that definitely works with the process as outlined by me above: pragma solidity ^0.4.0; contract test { function test() { } function verify(bytes32 _message, uint8 _v, bytes32 _r, bytes32 _s) constant returns (address) { bytes memory prefix = "\x19Ethereum Signed Message:...


6

The main issue is that you're signing "TEST" but then trying to recover the signer as though you signed a hash of "\x19Ethereum Signed Message:\n4TEST". I'm also not confident you're emitting the public key properly, but you presumably only want the address anyway. Here's some working code: Go: package main import ( "crypto/ecdsa" "fmt" "...


6

No, you cannot recover the message hash from an ECDSA signature. The siagnture is calculated by generating (x, y) = kG where k is the secret nonce and G is the generator for the curve. Then r = x and s = k^(-1)(z + rd) where z is the message and d is the private key. We can retrieve the public key dG by seeing that r^(-1) (kGs - zG) = dG. But trying to do ...


5

The problem was actually double hashing. Looking at the Web3j's signMessage() method Sign.SignatureData sig =Sign.signMessage(messageBytes, ecKeyPair); and signedMessageToKey() method String pubKey = Sign.signedMessageToKey(messageBytes, sig).toString(16); These methods internally hash(sha3) the input messageBytes before signing and on verification. This ...


4

The easiest solution is to use ethereumjs-tx module. If you use web3@0.20: const Transaction = require('ethereumjs-tx') const tx = web3.eth.getTransaction(txHash) // insert txhash here const pubkey = new Transaction({ nonce: tx.nonce, gasPrice: `0x${tx.gasPrice.toString(16)}`, gasLimit: tx.gas, to: tx.to, value: `0x${tx.value.toString(16)}`, ...


4

This gist is a good example how to use ecrecover. It uses assembly to filter out the r,s,v parts of a signature and fills it into the ecrecover function. assembly { r := mload(add(sig, 32)) s := mload(add(sig, 64)) // Here we are loading the last 32 bytes, including 31 bytes // of 's'. There is no 'mload8' to ...


4

I'm not sure if this is your only problem but at the very least, the v you're getting is wrong - it should be 27 or 28. Unfortunately a lot of signature functions won't give it to you, but you can just try both and see which one gives you the right address. No need to use hex for "v" - just literally feed it 27 or 28 as an int. The other bit of trickiness ...


4

You need to prefix the message with the string "\x19Ethereum Signed Message:\n" and the length of the message const prefix = new Buffer("\x19Ethereum Signed Message:\n"); const prefixedMsg = util.sha3( Buffer.concat([prefix, new Buffer(String(msg.length)), msg]) ); And then use the prefixed string in ecrecover. code taken from answer here https://...


3

Both Ethereum and Bitcoin uses the same elliptic curve for private keys secp256k1. The difference is Ethereum formats addresses as hexadecimal and bitcoin as base58. It can be made such that ecrecover to work for both, it returns the raw 20 bytes without address formatting. One possible issue is that Ethereum uses keccak256 for signing, and bitcoin ...


3

Since you mention it's an ECDSA key, I assume you're talking about using the same crypto that Ethereum uses for signatures. If you want to do this in Solidity, the simplest and most efficient thing will still be to use ecrecover. As you say ecrecover returns an address, not a public key. But an Ethereum address is derived from the public key, so if you want ...


3

Yes, at address 0x8 the EVM has a precompiled contract for optimal ate pairing check on the elliptic curve alt_bn128 described in EIP 197. How can we verify BGLS aggregate signatures in Solidity? has a gist containing the following code which may be useful: pragma solidity ^0.4.14; /* Example of how to verify BLS signatures and BGLS aggregate signatures ...


3

I stumbled upon this thread, then I discovered this document and I now understand that setting v as any (positive?) number other than 27 or 28 will deterministically return 0x0 as the origin signer address. Test it for yourself in solidity: function getSignerZero(bytes32 msgHash, bytes32 r, bytes32 s) public returns (address _signer) { uint8 wrongV = ...


3

The problem is that eth.sign returns a signature where v is 0 or 1 and ecrecover expect it to be 27 or 28. A note in the documentation for web3 v0.20 is clear: Note that if you are using ecrecover, v will be either "00" or "01". As a result, in order to use this value, you will have to parse it to an integer and then add 27. This will result in ...


2

I came across the answer myself, See working code below. I was following this guide which I would not recommend!. I was also using parity in geth mode to sign the data, which I also would not recommend. Switching to plain old geth RPC gave me more sane results. That being said, beware of v!. There is a bug between implementations of geth which will return ...


2

From Web3 JavaScript-API docs: After the hex prefix, characters correspond to ECDSA values like this: r = signature[0:64] s = signature[64:128] v = signature[128:130] Note that if you are using ecrecover, v will be either "00" or "01". As a result, in order to use this value, you will have to parse it to an integer and then add 27. This will ...


2

The initial cost of storing it in a bytes is approximately 20% more than using 4x bytes32 and 1x bytes2. You should also consider what your contract is going to do with the signature. If it's going to do some computation on the parts, you may not want the overhead of splitting the bytes into pieces again. On the other hand, if you're only going to pass the ...


2

There is a couple of things wrongs. 1- Your encoded message must be encoded = web3.sha3('\x19Ethereum Signed Message:\n32' + web3.sha3(message)) 32 is the length of the hash (sha3(message)) Instead of dealing with complex machine readable string, use other's people library that works ... const util = require('ethereumjs-util') encoded = util....


2

Apparently it's an issue with Truffle, see this issue here. More info here and here.


2

You can pass dynamically-sized arrays to a function and loop. E.g.: pragma solidity ^0.4.21; contract Test { ... function check(bytes32[] msgHash, uint8[] v, bytes32[] r, bytes32[] s) public view returns (bool) { for (uint256 i = 0; i < msgHash.length; i++) { address signer = recoverAddr(msgHash[i], v[i], r[i], s[i]); ...


2

The prefix has no intrinsic connection to the signature or validation function. ecrecover is simply recovering the public key (and from there the address) used to sign the 32 bytes of data you're feeding it. There is a convention in Ethereum for signed messages (ie not signed transactions) to prefix some data to a message before you sign it. This is done to ...


2

Looks like the docs should be updated. publicKey is a non-standard key returned by parity only, I believe.


2

You have not provided many details of your setup. What backend node are you using? What signature is returned when you sign the message? Web3.js sign method just calls through to the nodes implementation. As outlined in this answer, Geth previously did not return the v value in the appropriate format. You had to add 27. I suspect from brief consideration ...


2

Prefix your private key with 0x. I'm not sure how it's interpreted without that, but with the 0x prefix you'll get the expected result.


2

According to the documentation, it’s web3.eth.sign(data, address). I think you inversed the parameters. See https://web3js.readthedocs.io/en/1.0/web3-eth.html#sign. Also, do you send the good hash in the call_ecover function? I think you need to send the hash of msg (in your case, a hash of a hash: web3.sha3(msg)).


Only top voted, non community-wiki answers of a minimum length are eligible