// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.15; import "@openzeppelin/contracts/interfaces/IERC1271.sol"; import "@openzeppelin/contracts/utils/Address.sol"; library Signature { function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. require( uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "LEVX: INVALID_SIGNATURE_S_VALUE" ); require(v == 27 || v == 28, "LEVX: INVALID_SIGNATURE_V_VALUE"); // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); require(signer != address(0), "LEVX: INVALID_SIGNATURE"); return signer; } function verify( bytes32 hash, address signer, uint8 v, bytes32 r, bytes32 s, bytes32 domainSeparator ) internal view { bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, hash)); if (Address.isContract(signer)) { require( IERC1271(signer).isValidSignature(digest, abi.encodePacked(r, s, v)) == 0x1626ba7e, "LEVX: UNAUTHORIZED" ); } else { require(recover(digest, v, r, s) == signer, "LEVX: UNAUTHORIZED"); } } }