-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVerifySignature.sol
More file actions
136 lines (111 loc) · 3.95 KB
/
Copy pathVerifySignature.sol
File metadata and controls
136 lines (111 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/* Signature Verification
How to Sign and Verify
# Signing
1. Create message to sign
2. Hash the message
3. Sign the hash (off chain) // message is signed by the private key
# Signing Off Chain through metamask supported browser
1. Unlock MetaMask account
ethereum.enable()
2. Get message hash to sign
getMessageHash(
0x5B38Da6a701c568545dCfcB03FcB875f56beddC4,
500,
"Thanks for landing on my Github",
1
)
hash = "0xcf36ac4f97dc10d91fc2cbb20d718e94a8cbfe0f82eaedc6a4aa38946fb797cd"
3. Sign message hash
# using browser developer console
account = "signer address here"
ethereum.request({ method: "personal_sign", params: [account, hash]}).then(console.log)
# using web3
web3.personal.sign(hash, web3.eth.defaultAccount, console.log)
Signature will be different for different accounts
0x55ba47fac73e7f8b9b24ef7b433b698dee7b785d9a5e2ec93c096dd2dcde5933402e589589d1d171482fca8b0b7ab8fc64b74e8325cdd75327ee8c13de8e13391c
# Verify
1. Recreate hash from the original message
2. Recover signer from signature and hash
3. Compare recovered signer to claimed signer
4. Verify signature
signer = 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1 // signer address
to = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4
amount = 500
message = "Thanks for landing on my Github"
nonce = 1
signature =
0x55ba47fac73e7f8b9b24ef7b433b698dee7b785d9a5e2ec93c096dd2dcde5933402e589589d1d171482fca8b0b7ab8fc64b74e8325cdd75327ee8c13de8e13391c
*/
contract VerifySignature {
// Generate keccak256 hash from digest(can consist of message string & other useful parameters )
function getMessageHash(
address _to,
uint _amount,
string memory _message,
uint _nonce
) public pure returns (bytes32) {
return keccak256(abi.encodePacked(_to, _amount, _message, _nonce));
}
function getEthSignedMessageHash(bytes32 _messageHash)
internal
pure
returns (bytes32)
{
/*
Signature is obtained by signing a keccak256 hash with the following format:
"\x19Ethereum Signed Message\n" + length of _messageHash in string + _messageHash
*/
return
keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash)
);
}
// Verifies if the signature is signed by the signer
function verify(
address _signer,
address _to,
uint _amount,
string memory _message,
uint _nonce,
bytes memory signature
) public pure returns (bool) {
bytes32 messageHash = getMessageHash(_to, _amount, _message, _nonce);
bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);
return recoverSigner(ethSignedMessageHash, signature) == _signer;
}
function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature)
internal
pure
returns (address)
{
(uint8 v,bytes32 r, bytes32 s) = splitSignature(_signature);
return ecrecover(_ethSignedMessageHash, v, r, s);
}
function splitSignature(bytes memory sig)
internal
pure
returns (
uint8 v,
bytes32 r,
bytes32 s
)
{
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)))
}
}
}