Ethereum signature validation app

Ethereum signature validation app

Import: This article is for educational purposes only. Don’t attempt to incorporate the codes and methods presented here into working applications and don’t use keys that are associated with your real Bitcoin/Ethereum wallets.

 

The key pair

Key pair (Asymmetric encryption) is one of the building blocks of current blockchain solutions and cryptocurrencies, without it, Bitcoin, Ethereum and other blockchains were not possible.

The idea behind this tool is quite simple: Encrypting information using one key (public key) and decryption it using another (private key).

This short video gives a great introduction to the concept of key pairs as well as an explanation to the mathematical background behind RSA asymmetric encryption

  • Rememebr that both Bitcoin and Ethereum aren’t using RSA encryption. Instead they’re using ECC (Elliptic Curve). The mathematical background is different for the two, yet the main principle is the same.

 

As seen in the video, asymmetric encryption has been around for quite some time and it’s by no mean a unique feature of the blockchain. However, both Bitcoin and Ethereum (and probably many other blockchains) utilize it in a slightly different way. Rather than using the public key to encrypt a message, they’re using the private key to sign a message.

This signed message has some interesting proprieties, but the one thing what makes it really useful in the blockchain context is that the public key can be used to validate to authenticity of the signer.

 

original_msg = "hello"

private_key = "0x010203..."

public_key = "0x0f0e0d..."

signed_message = sign(original_msg, private_key) = "0xaabbcc..."

validate(public_key, original_msg) = True

As you can see, the idea wasn’t necessarily to hide the information (the original message need to be presented in order to validate authenticity of the signer). Instead, we use this method to prove the owner of a specific private key is indeed the one who signed the original message.

In the blockchain sense, Bob can sign the original_msg -the transaction (which is of course publicly available to anyone who have a copy of the blockchain), and by providing his own public key and the signature, everyone can verify that that specific message was indeed signed by Bob.

 

The validator

Originally, I planned to write some basics codes demonstrating the process in Bitcoin and Ethereum, but while studying Ethereum more in depth, I encountered the Solidity ecrecover method that returns the address associated with the signed message, and I immediately sat down to create the Validator, a simple app that uses web3.js to sign a message at the client side, and then uses smart contract to get the address of the signer (btw, the ability to display the address of the one who signed the message hints at another interesting property which I might go deeper into in another post).

The source code can be found here:
https://github.com/Shultzi/validator

Step by step

The process was very simple, first I created the smart contract:

contract Validator{
    
    function constVerify(bytes32 r, bytes32 s, uint8 v, bytes32 hash) constant returns(address) {
        return ecrecover(hash, v, r, s);    
    
    function verify(bytes32 r, bytes32 s, uint8 v, bytes32 hash) returns(address) {
        return ecrecover(hash, v, r, s);
    } 
}

The contract Validator contains two functions but both are basically doing the same. The only different is that the first one is constant, that means no transaction is sent to the Ethereum network (caution! request might still be sent to a remote node if you don’t run a local Ethereum node!). This function will instantly return the address of the one who signed the original message. The other function is not a constant function, that means that a transaction will be sent to the Ethereum blockchain and the returned result will be verified by all of the users (consider the implications in terms of privacy!) the result however will not be immediately displayed to the end user – instead, in my app the user will receive the hash of the transaction. The user can then look it up on the blockchain.

The ecrecover function itself is very simple to use, all you need is the hash of the original message (hash) and the signed message (r, s, v).

The original message is hashed to ensure that uniform size, so that regardless to the size of the original message, we’ll always have a hash variable of exactly 32 bytes.

The r, s, v are all parameters of the signed message. The signed message itself (as you might already saw in the above video) is actually a combination of 3 variables.

full_sign = 0x042995e2dd996f8d234be59a623f3a2b02d3fb91187f48eaf563723b342225cc16599133550d998c880ecb1a8d29f47216f0397e30e415b95d92490f3b4ca6201b

r = 042995e2dd996f8d234be59a623f3a2b02d3fb91187f48eaf563723b342225cc //32 bytes

s = 16599133550d998c880ecb1a8d29f47216f0397e30e415b95d92490f3b4ca620 //32 bytes

v = 1b //uint8 (1 byte)

The signed message can be received using the web3.js library. I used meteor (based on nodejs) to launch my application.

Once it was launched, I declared web3 object like so:

if(typeof web3 !== 'undefined'){
  web3 = new Web3(web3.currentProvider);
}else{
	web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8080"));
};

The web3 is connected to metamask via chrome extension, but you can of course use your own preferred client like geth, parity or testrpc.

Once web3 is declared, getting the full signature is a very simple thing to do:

web3.eth.sign(web3.eth.accounts[0], web3.sha3(msgToSign.value), function(err, res){signedmsg = res;});

This is the full signature. r + s + v. We’ll need to break it into their component. Just remember that:

  • The first 32 bytes are the r value
  • The second 32 bytes are the s value
  • The last byte is v value (uint8)

You can read more about signature structure here

Breaking the signature into its r, s, v values is a fairly easy process that can be done with the following JavaScript code.

r = "0x" + signedMsg.value.slice(2, 66); //Treated as hex
s = "0x" + signedMsg.value.slice(66, 130); //treated as hex
v = new Buffer(signedMsg.value.slice(130, 132), "hex"); // we care for the numeric value. The Ethereum function expects uint8 and not hex.
v = v[0].valueOf();
h = web3.sha3(originalMsg.value); //we hash the original message to keep it as 32 bytes, regardless to the input size.

Now the only thing that is remained is to send these values along with the original message to smart contract, and get the result back.

Validator.verify(r, s, v, h, function(err,res){         		
    Template.address.set("The transaction id is: " + res);
});

Validator.constVerify(r, s, v, h, function(err,res){
    Template.address.set("The signer address: " + res);
});

The final result

http://nobelgoeshere.com/ (The site isn’t secured. Don’t sign anything of value!)

Signing and validating message in ethereum

 

Leave a Reply

Your email address will not be published. Required fields are marked *