Ethereum: Signing and Validating
A core primitive of Ethereum and other cryptocurrencies is the ability to sign data that can be verified by anyone. This powers the distributed nature of blockchain. In Bitcoin you sign a transaction saying you want to give Sally 4 bitcoin. Without this property, anyone could make fake transactions giving themselves all coins.
If you go to ecrecover-example on github for the full codebase. Simply follow the instructions in the README.md and see the results in the command line.
What is Signing?
Signing is the act of a user A “signing” data that anyone can validate came from user A. This is used in transactions to check if they are real.
A common question is “how can you validate transactions are real?” The short answer is public-key cryptography. It’s an algorithm with 3 parts.
- Key Creation
Encryption is generally used to hide data in other data. If you encrypt a string like ‘hello world’ you get something like `dqE3gJz/+5CQHfSJwMP2nQ`. Its purpose is to hide the message ‘hello world’. Signing is used to create a different output string, but you also publicize the original message.
The key creation will output two strings, a public and private key. It links them through an algorithm that has the signing and validation properties. A signature will take in a public key, private key, and message. The output will be another string that is the signature.
- Signature = F(public key, private key, message)
- Validation = F(Signature, message)
- Is Valid if: Validation = public key
Notice how validation does not require knowledge of the private key. This is what allows 3rd parties to validate information. If the output of the validation function is equal to the public key then the signature is real, otherwise its fake.
The signature is made up of 3 variables: v, r, s. Ethereum employs Elliptic curve cryptography and those variables are simply part of the underlying math.
Signing is a nice way to know something is being done by the correct person/contract. This means we can trust that someone is actually doing what they say they are.
Instead of real world signatures, which can be faked, the digital ones can not. If you want to know user A did something, make them sign it before moving forward. Then if a dispute arrises, check the signature.
As a developer you want your users to sign a message. There are 3 parts to creating this feature in your respective DApp (Distributed Application).
- Solidity validator function
- Client code to sign a message
- Client code to call Solidity validator
Solidity provides a globally available method
ecrecover that returns an address. If the return address is the same as the signer, then the signature is real.
The code above creates a
Verifier contract with the
isSigned functions. The latter will return an address. Requiring you as a developer to validate, outside of Solidity, that the address is correct. The second method,
isSigned does the check within Solidity.
isSigned will return true or false if the
msgHash is signed by
There are two ways to create a signature:
web3 and attach to an Ethereum node. In the code below, I am running a private Ethereum node bound to
localhost:8545. NOTE: THIS WILL NOT WORK ON TESTRPC
There is no built in function to convert a string to hex. So I used the function
toHex to do the conversion. The users address (
web3.eth.accounts) and message with the
0x prefixed are passed into the
Another way to create a signature is to call the Ethereum RPC API. With
curl you should be able to make a request to an Ethereum node.
The first parameter in
params is the users address, and the second is the hex value of the message. Note for the RPC api to work your account must be unlocked. You will get something like the following back:
The long signature encodes the previously mentioned v, r, s variables. To extract these values, you need to parse the signature into substrings.
NOTE: v must be a decimal number, hence the second
v_decimal that turns hex v into decimal v.
DANGER: The resulting
v_decimal must be either 27 or 28!
Checking if Correct:
With the validator and signing completed, all that is left is to actually check if the signature is real. There is one teeny tiny caveat. Remember when creating the signature we used the string
0x + toHex(msg). Well that is not the same hash that you pass into the validator!
Again, the hash to creating the signature is not the same for the validator. The reason is to protect the user from signing arbitrary payloads.
The solution is to add a custom Ethereum message, and length.
//FOR SIGNATURE Hex:
I really did make this message
//FOR VALIDATOR sha3:
\x19Ethereum Signed Message:\n30I really did make this message
This distinction is VERY necessary! Do not waste your time following any other steps.
The last step is to somehow call your Solidity code. I am using Truffle 3 to deploy the previous smart contract. Please note the location of the Ethereum node must be declared (
localhost:8545) for the contract. Otherwise it will not work as expected.
Truffle creates a deployed function that returns the contract instance. I create my sha3 message and pass the required variables into
instance.verify.call. If the addresses returned by the last two lines are the same then the owner really did sign the message. Otherwise its a forgery that can be ignored.
Signing data can be important for any kinds of DApp. Some obvious applications are rights management, copyright, patent ownership. Users could sign those files and anyone can validate that they did in fact make those things. What use case can you think of?