Created
March 15, 2025 19:57
-
-
Save nickjuntilla/7aa315d707f4d11fc36f3bfb86791e93 to your computer and use it in GitHub Desktop.
Solidity On chain signature verification
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Signature Verification | |
# mostly from here https://solidity-by-example.org/signature/ | |
*/ | |
function getMessageHash( | |
uint256 _nonce, | |
uint16 _qty | |
) public pure returns (bytes32) { | |
return keccak256(abi.encodePacked(_nonce, _qty)); | |
} | |
function getEthSignedMessageHash(bytes32 _messageHash) | |
public | |
pure | |
returns (bytes32) | |
{ | |
/* | |
Signature is produced by signing a keccak256 hash with the following format: | |
"\x19Ethereum Signed Message\n" + len(msg) + msg | |
In this case it's always 32 because it's a hash | |
*/ | |
return | |
keccak256( | |
abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash) | |
); | |
} | |
function verify( | |
uint256 _nonce, | |
uint16 _qty, | |
bytes memory signature | |
) public view returns (bool) { | |
bytes32 messageHash = getMessageHash(_nonce, _qty); | |
bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash); | |
return recoverSigner(ethSignedMessageHash, signature) == owner(); | |
} | |
function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) | |
public | |
pure | |
returns (address) | |
{ | |
(bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature); | |
return ecrecover(_ethSignedMessageHash, v, r, s); | |
} | |
function splitSignature(bytes memory sig) | |
public | |
pure | |
returns ( | |
bytes32 r, | |
bytes32 s, | |
uint8 v | |
) | |
{ | |
require(sig.length == 65, "invalid signature length"); | |
assembly { | |
/* | |
First 32 bytes stores the length of the signature | |
add(sig, 32) = pointer of sig + 32 | |
effectively, skips first 32 bytes of signature | |
mload(p) loads next 32 bytes starting at the memory address p into memory | |
*/ | |
// first 32 bytes, after the length prefix | |
r := mload(add(sig, 32)) | |
// second 32 bytes | |
s := mload(add(sig, 64)) | |
// final byte (first byte of the next 32 bytes) | |
v := byte(0, mload(add(sig, 96))) | |
} | |
// implicitly return (r, s, v) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment