Add a recover(bytes32,bytes32,bytes32) that follows EIP2098 (#2713)

This commit is contained in:
Hadrien Croubois
2021-06-14 20:12:08 +02:00
committed by GitHub
parent 78103f3137
commit 0a05f6fa45

View File

@ -28,15 +28,13 @@ library ECDSA {
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/ */
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
// Divide the signature in r, s and v variables
bytes32 r;
bytes32 s;
uint8 v;
// Check the signature length // Check the signature length
// - case 65: r,s,v signature (standard) // - case 65: r,s,v signature (standard)
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
if (signature.length == 65) { if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them // ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly. // currently is to use assembly.
assembly { assembly {
@ -44,25 +42,45 @@ library ECDSA {
s := mload(add(signature, 0x40)) s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60))) v := byte(0, mload(add(signature, 0x60)))
} }
return recover(hash, v, r, s);
} else if (signature.length == 64) { } else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
// ecrecover takes the signature parameters, and the only way to get them // ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly. // currently is to use assembly.
assembly { assembly {
let vs := mload(add(signature, 0x40))
r := mload(add(signature, 0x20)) r := mload(add(signature, 0x20))
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) vs := mload(add(signature, 0x40))
v := add(shr(255, vs), 27)
} }
return recover(hash, r, vs);
} else { } else {
revert("ECDSA: invalid signature length"); revert("ECDSA: invalid signature length");
} }
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
bytes32 s;
uint8 v;
assembly {
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v := add(shr(255, vs), 27)
}
return recover(hash, v, r, s); return recover(hash, v, r, s);
} }
/** /**
* @dev Overload of {ECDSA-recover} that receives the `v`, * @dev Overload of {ECDSA-recover} that receives the `v`, `r` and `s` signature fields separately.
* `r` and `s` signature fields separately.
*/ */
function recover( function recover(
bytes32 hash, bytes32 hash,