34

The question of signing and verifying signatures with Solidity has been asked in these questions, both of which I have tried to study:

How can I sign a piece of data with the private key of an Ethereum address?

How can I verify a cryptographic signature that was produced by an Ethereum address key pair

However, there are still pieces of information that I appear to be missing.

First off, I would like to start with the question about signing. In the example, the string Schoolbus is signed by the address 0xd1ade25ccd3d550a7eb532ac759cac7be09c2719, and the resulting signature is 0x2ac19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601.

So far, so good. Now, what I'd like to do is verify using ecrecover that the signature is indeed correct for the given address and datum. The thing is, ecrecover takes four arguments: ecrecover(h, v, r, s). Aside from h being the hash, and {v, r, s} somehow comprising the signature, what exactly do v, r, and s stand for? And how do I obtain all the values necessary from the single string 0x2ac19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601?

What I know is that ecrecover returns an address, and verifying a signature is essentially a matter of comparing the resulting address with the expected one. Yet the whole procedure seems unnecessarily complicated.

Aside from this, I was also wondering how I could produce a signature, either like this 0x2ac19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601 or a set of {h, v, r, s} using Solidity alone, without the RPC-JSON detour as is the case in the question – provided I know a private key?

8
  • Check out ethereum.stackexchange.com/questions/1777/… Here I also list the procedure for extracting r, v, and s from the signature string. I agree that this procedure is a bit too complicated, and I expressed this issue here: github.com/ethereum/EIPs/issues/79
    – MrChico
    Mar 23, 2016 at 0:47
  • I'm afraid that the question in question is not in Solidity. What I am trying to accomplish has to be executed within a contract.
    – arik
    Mar 23, 2016 at 0:53
  • Can you expand a bit on why you would want to sign something inside a contract? As has been mentioned this will expose the private key of the signer to everyone
    – MrChico
    Mar 23, 2016 at 0:54
  • I merely want to verify a signature in the format specified above within a contract. The signing part would be just for unit testing.
    – arik
    Mar 23, 2016 at 0:55
  • The verification procedure is done in a solidity contract in the question I linked to
    – MrChico
    Mar 23, 2016 at 0:57

2 Answers 2

19

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 though you may sign two different msgs with the same private key, the signing process (internally) generates a random nonce value (k) that is used as part of the calculation and must be different for each generated signature.

r and s along with the associated public key help to validate if the signature is legit.

Note: I'm no cryptographer. This is what I've dug up trying to answer the same questions you have. I'd suggest looking at some of the online resources for elliptic curves.

Aside from this, I was also wondering how I could produce a signature, either like this 0x2ac19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601 or a set of {h, v, r, s} using Solidity alone, without the RPC-JSON detour as is the case in the question – provided I know a private key?

The problem you'd have generating a signature from within Solidity is you'd have to expose the private key. Alternatively, you could generate a signature outside of the normal Ethereum transaction process using one of the many elliptic curve libraries and send that resulting signature to a contract.

5
  • Thanks for the response! Now, if I have just the signature string, how do I get the signature object from it? The signature string itself does not contain a recovery property, I'm afraid. Also, just making sure: Is the hash necessary for ecrecover sha256?
    – arik
    Mar 22, 2016 at 22:55
  • Is there any way v can be recalculated? I'm afraid ecrecover won't work without passing in the right value.
    – arik
    Mar 22, 2016 at 23:20
  • IIUC when a signature is DER encoded, it only stores the r and s points, and throws away "v". When I want to supply a "v" value I just try them both. So where pubkey_decompressed is the public key that created the ethereum address: v_but_not_really, r, s = bitcoin.der_decode_sig(sig) for possible_v in [27, 28]: possible_pub = bitcoin.encode_pubkey(bitcoin.ecdsa_raw_recover(msg_hash, (possible_v, r, s)), 'hex') if pubkey_decompressed == possible_pub: return possible_v Mar 22, 2016 at 23:21
  • 2
    In the string that is returned when using eth.sign, v is included. The last two hex characters represent v. More on this here: ethereum.stackexchange.com/questions/1777/…
    – MrChico
    Mar 23, 2016 at 0:53
  • to accomplish this signing process, what client or what environment do I need? " 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"
    – Wang
    May 10, 2016 at 5:36
5

What exactly do v, r, and s stand for?

  • r is the R.x value of the signature's R point.
  • s is the signature proof for R.x
  • v is a recovery parameter used to ease the signature verification.

v is not required but often included. But what is v?

Since the signature only includes the x coordinate of the point R, there are either 0, 1, 2, 3, or 4 matching y coordinates over the Secp256k1 elliptic curve. These four potential candidates are encoded in something called recovery_id.

A recovery ID can have the values 0..3 depending on the following conditions:

  • Is R.y even and R.x less than the curve order n: recovery_id := 0
  • Is R.y odd and R.x less than the curve order n: recovery_id := 1
  • Is R.y even and R.x more than the curve order n: recovery_id := 2
  • Is R.y odd and R.x more than the curve order n: recovery_id := 3

Now we know how to get to the recovery ID. v is simply v = recory_id + 27 for Bitcoin. In addition to v values of 27..30 that only reflect the recovery ID, there is also the notion of recovering compressed public keys, using the same recovery ID but a v of v = recovery_id + 31.

But we are not talking about Bitcoin, so last but not least, you want to look at EIP-155 because we no longer use the + 27 part that Bitcoin used to prevent replay protection:

v = chain_id * 2 + 35 + recovery_id

In Ethereum, v reflects the chain for replay protection and the ID for signature recovery.

And how do I obtain all the values necessary from the single string 0x2ac19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601?

This is just a concatenated string of "#{v}#{r}#{s}" with:

  • v = 0x2a
  • r = 0xc19db245478a06032e69cdbd2b54e648b78431d0a47bd1fbab18f79f820ba407
  • s = 0x466e37adbe9e84541cab97ab7d290f4a64a5825c876d22109f3bf813254e8601

The v is 42.

chain_id = (v - 35) / 2

Now, we can verify that the v of 42 is only valid on the chain with ID 3 (Ropsten).

What I know is that ecrecover returns an address, and verifying a signature is essentially a matter of comparing the resulting address with the expected one. Yet the whole procedure seems unnecessarily complicated.

I know this is not a question, but this is literally how elliptic-curve cryptography works: it's just mathematical operations with various points on a curve.

An address is just a pretty-formatted version of the public key; the public key is just a point on the Secp256k1 elliptic curve.

A signature is just another point. And if you do public key magic and signature magic, at the end of this math-heavy process you have two points (public keys) and if they are exact matches, the signature can be considered verified.

That ecrecover returns an address is just for your convenience: you can directly compare if the signature address matches the signer address - and that is much easier to do in Solidity as opposed to deal with uncompressed public keys.

I hope this sheds some light one this question.

2
  • Hi, in what case can there be more than 2 "y" coordinates for one x? as far as I understand, the curve is mirrored horizontally, which means there can be 0 (if the x point is to the left of the curve), 1 (if the x point is at the exact middle of the curve), and 2 everywhere else.
    – J3STER
    Jul 6 at 8:42
  • The curve is not really a "curve," it looks more like a field of sprinkled dots. So, there are x-values where you don't have any corresponding y-value. Approximately half of the possible choices for x correspond to usually two points. crypto.stackexchange.com/a/98364
    – q9f
    Jul 13 at 10:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.