-
Notifications
You must be signed in to change notification settings - Fork 12.4k
ECDSA: add parse and tryParse #5814
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
f839be4
144b0e2
e9d04b3
65f0059
7b80596
d409599
ec112c7
069e9d4
a63d6a0
4ead44c
23c393f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| 'openzeppelin-solidity': minor | ||
| --- | ||
|
|
||
| `ECDSA`: Add `parse` and `parseCalldata` to parse bytes signatures of length 65 or 64 (eip-2098) into its v,r,s components. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,6 +43,13 @@ library ECDSA { | |
| * this function rejects them by requiring the `s` value to be in the lower | ||
| * half order, and the `v` value to be either 27 or 28. | ||
| * | ||
| * NOTE: This function also prevents signature malleability by only supporting 65 bytes long signatures, and | ||
| * rejecting eip-2098 short signatures. While this guarantee is still present, it is DEPRECATED and will be | ||
| * removed in the next major release (v6.0). Developers SHOULD NOT use signatures as unique identifiers. If an | ||
| * operation must me marked as consumed to prevent replayability, either the `hash` (or the `hash`/`recovered` | ||
| * pair if multiple accounts are to sign the same hash) should be invalidated. Nonces are also a viable solution. | ||
| * Marking the signatures as consumed is very strongly discouraged. | ||
| * | ||
| * IMPORTANT: `hash` _must_ be the result of a hash operation for the | ||
| * verification to be secure: it is possible to craft signatures that | ||
| * recover to arbitrary addresses for non-hashed data. A safe way to ensure | ||
|
|
@@ -106,6 +113,13 @@ library ECDSA { | |
| * this function rejects them by requiring the `s` value to be in the lower | ||
| * half order, and the `v` value to be either 27 or 28. | ||
| * | ||
| * NOTE: This function also prevents signature malleability by only supporting 65 bytes long signatures, and | ||
| * rejecting eip-2098 short signatures. While this guarantee is still present, it is DEPRECATED and will be | ||
| * removed in the next major release (v6.0). Developers SHOULD NOT use signatures as unique identifiers. If an | ||
| * operation must me marked as consumed to prevent replayability, either the `hash` (or the `hash`/`recovered` | ||
| * pair if multiple accounts are to sign the same hash) should be invalidated. Nonces are also a viable solution. | ||
| * Marking the signatures as consumed is very strongly discouraged. | ||
| * | ||
| * IMPORTANT: `hash` _must_ be the result of a hash operation for the | ||
| * verification to be secure: it is possible to craft signatures that | ||
| * recover to arbitrary addresses for non-hashed data. A safe way to ensure | ||
|
|
@@ -196,6 +210,63 @@ library ECDSA { | |
| return recovered; | ||
| } | ||
|
|
||
| /** | ||
| * @dev Parse a signature into its `v`, `r` and `s` components. Supports both 65 bytes and 64 bytes (eip-2098) | ||
Amxx marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * signature formats. Returns 0, 0, 0 is the signature is not in a proper format. | ||
ernestognw marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| */ | ||
Amxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| function parse(bytes memory signature) internal pure returns (int8 v, bytes32 r, bytes32 s) { | ||
|
||
| assembly ("memory-safe") { | ||
| // Check the signature length | ||
| switch mload(signature) | ||
| // - case 65: r,s,v signature (standard) | ||
| case 65 { | ||
| r := mload(add(signature, 0x20)) | ||
| s := mload(add(signature, 0x40)) | ||
| v := byte(0, mload(add(signature, 0x60))) | ||
| } | ||
| // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) | ||
| case 64 { | ||
| let vs := mload(add(signature, 0x40)) | ||
| r := mload(add(signature, 0x20)) | ||
| s := and(vs, shr(1, not(0))) | ||
| v := add(shr(255, vs), 27) | ||
| } | ||
| default { | ||
| r := 0 | ||
| s := 0 | ||
| v := 0 | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @dev Variant of {parse} that takes a signature in calldata | ||
| */ | ||
| function parseCalldata(bytes calldata signature) internal pure returns (int8 v, bytes32 r, bytes32 s) { | ||
| assembly ("memory-safe") { | ||
| // Check the signature length | ||
| switch signature.length | ||
| // - case 65: r,s,v signature (standard) | ||
| case 65 { | ||
| r := calldataload(signature.offset) | ||
| s := calldataload(add(signature.offset, 0x20)) | ||
| v := byte(0, calldataload(add(signature.offset, 0x40))) | ||
| } | ||
| // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) | ||
| case 64 { | ||
| let vs := calldataload(add(signature.offset, 0x20)) | ||
| r := calldataload(signature.offset) | ||
| s := and(vs, shr(1, not(0))) | ||
| v := add(shr(255, vs), 27) | ||
| } | ||
| default { | ||
| r := 0 | ||
| s := 0 | ||
| v := 0 | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. | ||
| */ | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.