Resolved
The basic process flow of what I'm writing goes as follows.
- Sign a message with a private key and create an Ethereum address from the private key (AKA the
vettingAddress
) - Pass the signature constituents to the contract along with a special hashed version of the hashed message (See #Cheking If Correct)
I don't have any problem doing with natively with Go, see below:
Signing With Golang :
func sign(message string, ecdsaKey *ecdsa.PrivateKey) []byte { hash := crypto.Keccak256([]byte(message)) signature, _ := crypto.Sign(hash, ecdsaKey) }
The resulting signature is validated easily with the Golang Ethereum lib using the following golang code:
Validating / Verifying with Golang :
func validate(ecdsaPubBytes []byte, signature []byte, messageHash []byte) bool { return crypto.VerifySignature(ecdsaPubBytes, messageHash , signature[:64]) }
So far so good this work perfectly.
My problem is with validating / verifying with an Ethereum smart contract, I have the following code:
My Golang Code:
type Signature struct { Hash [32]byte R [32]byte S [32]byte V uint8 } func Sign(message string) Signature { hashRaw := crypto.Keccak256([]byte(message)) signature, err := crypto.Sign(hashRaw, ecdsaKey) p.errorHandler.Handle(err, "Signature error") validationMsg := "\x19Ethereum Signed Message:\n" + strconv.Itoa(len(message)) + message println(validationMsg) validationHash := crypto.Keccak256([]byte(validationMsg)) return Signature{ p.bytes32(validationHash), p.bytes32(signature[:32]), p.bytes32(signature[32:64]), uint8(binary.LittleEndian.Uint32(signature[:65]))+27, // Yes add 27, weird Ethereum quirk } }
Passing to the network
contract, _ := Signature(common.HexToAddress("..."), etherClient) println(contract.VerifySig(callOpts, sig.Hash, sig.R, sig.S, sig.V, vettingAddress))
My Solidity contract:
pragma solidity ^0.4.20; library Signature { function verify(bytes32 hash, bytes32 r, bytes32 s, uint8 v, address vettingAddress) internal pure returns(bool) { return ecrecover(hash, v, r, s) == vettingAddress; } }
The contract is always returning false. There are very few resources for handling ecrecover
, I've read this article), but I don't see what I'm doing incorrectly.
EDIT
I've solved this issue. The problem was related to how I parse the 65th byte of the signature. Below was incorrect for a number of reasons:
Parse the Int correctly
uint8(binary.LittleEndian.Uint32(signature[:65]))+27, // Yes add 27, weird Ethereum quirk
Should look like:
uint8(int(signature[65])) + 27, // Yes add 27, weird Ethereum quirk
Don't need a special hash
Also the validation hash was not needed.
p.bytes32(validationHash),
Should be:
p.bytes32(hashRaw),
So all in all the new signature method looked like this:
type Signature struct { Raw []byte Hash [32]byte R [32]byte S [32]byte V uint8 } func Sign(message string) Signature { hashRaw := crypto.Keccak256([]byte(message)) signature, err := crypto.Sign(hashRaw, p.ecdsa) p.errorHandler.Handle(err, "Signature error") return Signature{ signature, p.bytes32(hashRaw), p.bytes32(signature[:32]), p.bytes32(signature[32:64]), uint8(int(signature[65])) + 27, // Yes add 27, weird Ethereum quirk } }