This repository has been archived by the owner on Jan 13, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 159
/
Copy pathTypedSignature.sol
120 lines (96 loc) · 3.66 KB
/
TypedSignature.sol
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
/*
Copyright 2019 dYdX Trading Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity 0.5.7;
pragma experimental ABIEncoderV2;
import { Require } from "../../protocol/lib/Require.sol";
/**
* @title TypedSignature
* @author dYdX
*
* Library to unparse typed signatures
*/
library TypedSignature {
// ============ Constants ============
bytes32 constant private FILE = "TypedSignature";
// prepended message with the length of the signed hash in decimal
bytes constant private PREPEND_DEC = "\x19Ethereum Signed Message:\n32";
// prepended message with the length of the signed hash in hexadecimal
bytes constant private PREPEND_HEX = "\x19Ethereum Signed Message:\n\x20";
// Number of bytes in a typed signature
uint256 constant private NUM_SIGNATURE_BYTES = 66;
// ============ Enums ============
// Different RPC providers may implement signing methods differently, so we allow different
// signature types depending on the string prepended to a hash before it was signed.
enum SignatureType {
NoPrepend, // No string was prepended.
Decimal, // PREPEND_DEC was prepended.
Hexadecimal, // PREPEND_HEX was prepended.
Invalid // Not a valid type. Used for bound-checking.
}
// ============ Functions ============
/**
* Gives the address of the signer of a hash. Also allows for the commonly prepended string of
* '\x19Ethereum Signed Message:\n' + message.length
*
* @param hash Hash that was signed (does not include prepended message)
* @param signatureWithType Type and ECDSA signature with structure: {32:r}{32:s}{1:v}{1:type}
* @return address of the signer of the hash
*/
function recover(
bytes32 hash,
bytes memory signatureWithType
)
internal
pure
returns (address)
{
Require.that(
signatureWithType.length == NUM_SIGNATURE_BYTES,
FILE,
"Invalid signature length"
);
bytes32 r;
bytes32 s;
uint8 v;
uint8 rawSigType;
/* solium-disable-next-line security/no-inline-assembly */
assembly {
r := mload(add(signatureWithType, 0x20))
s := mload(add(signatureWithType, 0x40))
let lastSlot := mload(add(signatureWithType, 0x60))
v := byte(0, lastSlot)
rawSigType := byte(1, lastSlot)
}
Require.that(
rawSigType < uint8(SignatureType.Invalid),
FILE,
"Invalid signature type"
);
SignatureType sigType = SignatureType(rawSigType);
bytes32 signedHash;
if (sigType == SignatureType.NoPrepend) {
signedHash = hash;
} else if (sigType == SignatureType.Decimal) {
signedHash = keccak256(abi.encodePacked(PREPEND_DEC, hash));
} else {
assert(sigType == SignatureType.Hexadecimal);
signedHash = keccak256(abi.encodePacked(PREPEND_HEX, hash));
}
return ecrecover(
signedHash,
v,
r,
s
);
}
}