How to Sign Messages in Solidity

pbharrin
2 min readMar 22, 2023

--

Foundry is a way to test smart contracts by writing Solidity the same language used for writing the smart contract. Now some smart contracts might verify that a message has been signed by a trusted source. If you search the internet you will see plenty of examples doing this in Javascript from users of Hardhat the Javascript based Solidity test bench. You will be hard pressed to a way to do this in Solidity.

Below is a function that can sign messages using Solidity. Take note this relies on the Foundry cheat code: vm.sign(). So you couldn’t put this into your contract and deploy it, that would be a bad idea as your private key would be exposed.

function signTokenNum(uint256 ticketNum, address adin) private view returns (bytes memory) {

// create digest: keccak256 gives us the first 32bytes after doing the hash
// so this is always 32 bytes.
bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32",
bytes32(uint256(uint160(adin))),
bytes32(ticketNum))
);
// r and s are the outputs of the ECDSA signature
// r,s and v are packed into the signature. It should be 65 bytes: 32 + 32 + 1
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);

// pack v, r, s into 65bytes signature
// bytes memory signature = abi.encodePacked(r, s, v);
return abi.encodePacked(r, s, v);
}

The digest above is created to look like an message signed in Javascript, note the “\x19Ethereum Signed Message:\n32” portion. I’m only doing that because the receiving contract verifies messages this way. If you remove this on the verification side you would not need to insert it here.

One final note is on private key security. In the above code there is a global variable called privateKey. This was loaded through an environment variable. Foundry also has cheat code for that: vm.envUint(“env_variable_name”). Don’t ever hard code a private key in your code. I’ve heard too many stories of people accidently checking making old repos public and then poof thier private key is exposed and funds are drained. There are many bots searching Github for private keys. Additionally Foundry will expose your private keys in the logs when you sign a message. So if you are signing a message with a real private key make sure the logs are never uploaded, and destroyed.

Displaying the Signature

Another piece of code that may be missing is how to display the signature in ASCII. This is useful if you want to send signed messages in email or to cut and paste into Etherscan or Remix. You’ll note the return type above is bytes. The code below will transform your 65byte signature into ASCII for whatever you like.

    function bytes65ToASCII(bytes memory _bytes) public pure returns (string memory) {
// bytes32 _bytes = bytes32(uint256(_address));
bytes memory HEX = "0123456789abcdef";
bytes memory _string = new bytes(132); // 2 + 65 * 2
_string[0] = "0";
_string[1] = "x";
for (uint256 i = 0; i < 65; i++) {
_string[2 + i * 2] = HEX[uint8(_bytes[i] >> 4)];
_string[3 + i * 2] = HEX[uint8(_bytes[i] & 0x0f)];
}
return string(_string);
}

--

--