OpenZeppelin ContractsAPI ReferenceUtils

Cryptography

Smart contract cryptography utilities and implementations

A collection of contracts and libraries that implement various signature validation schemes and cryptographic primitives. These utilities enable secure authentication, multisignature operations, and advanced cryptographic operations in smart contracts.

Utils

ECDSA

MessageHashUtils

P256

RSA

SignatureChecker

Hashes

MerkleProof

EIP712

ERC7739Utils

WebAuthn

Abstract Signers

AbstractSigner

ERC7739

SignerECDSA

SignerP256

SignerRSA

SignerERC7702

SignerERC7913

MultiSignerERC7913

MultiSignerERC7913Weighted

Verifiers

ERC7913P256Verifier

ERC7913RSAVerifier

ERC7913WebAuthnVerifier

ECDSA πŸ“

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

Elliptic Curve Digital Signature Algorithm (ECDSA) operations.

These functions can be used to verify that a message was signed by the holder of the private keys of a given address.

Functions

Errors

tryRecover(bytes32 hash, bytes signature) β†’ address recovered, enum ECDSA.RecoverError err, bytes32 errArg

internal

Returns the address that signed a hashed message (hash) with signature or an error. This will not return address(0) without also returning an error description. Errors are documented using an enum (error type) and a bytes32 providing additional information about the error.

If no error is returned, then the address can be used for verification purposes.

The ecrecover EVM precompile allows for malleable (non-unique) signatures: 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 only supports 65-byte signatures. ERC-2098 short signatures are rejected. This restriction is DEPRECATED and will be removed in v6.0. Developers SHOULD NOT use signatures as unique identifiers; use hash invalidation or nonces for replay protection.

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 this is by receiving a hash of the original message (which may otherwise be too long), and then calling MessageHashUtils.toEthSignedMessageHash on it.

Documentation for signature generation:

tryRecoverCalldata(bytes32 hash, bytes signature) β†’ address recovered, enum ECDSA.RecoverError err, bytes32 errArg

internal

Variant of ECDSA.tryRecover that takes a signature in calldata

recover(bytes32 hash, bytes signature) β†’ address

internal

Returns the address that signed a hashed message (hash) with signature. This address can then be used for verification purposes.

The ecrecover EVM precompile allows for malleable (non-unique) signatures: 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 only supports 65-byte signatures. ERC-2098 short signatures are rejected. This restriction is DEPRECATED and will be removed in v6.0. Developers SHOULD NOT use signatures as unique identifiers; use hash invalidation or nonces for replay protection.

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 this is by receiving a hash of the original message (which may otherwise be too long), and then calling MessageHashUtils.toEthSignedMessageHash on it.

recoverCalldata(bytes32 hash, bytes signature) β†’ address

internal

Variant of ECDSA.recover that takes a signature in calldata

tryRecover(bytes32 hash, bytes32 r, bytes32 vs) β†’ address recovered, enum ECDSA.RecoverError err, bytes32 errArg

internal

Overload of ECDSA.tryRecover that receives the r and vs short-signature fields separately.

See ERC-2098 short signatures

recover(bytes32 hash, bytes32 r, bytes32 vs) β†’ address

internal

Overload of ECDSA.recover that receives the r and vs` short-signature fields separately.

tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) β†’ address recovered, enum ECDSA.RecoverError err, bytes32 errArg

internal

Overload of ECDSA.tryRecover that receives the v, r and s signature fields separately.

recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) β†’ address

internal

Overload of ECDSA.recover that receives the v, r and s signature fields separately.

parse(bytes signature) β†’ uint8 v, bytes32 r, bytes32 s

internal

Parse a signature into its v, r and s components. Supports 65-byte and 64-byte (ERC-2098) formats. Returns (0,0,0) for invalid signatures. Consider skipping ECDSA.tryRecover or ECDSA.recover if so.

parseCalldata(bytes signature) β†’ uint8 v, bytes32 r, bytes32 s

internal

Variant of CAIP10.parse that takes a signature in calldata

ECDSAInvalidSignature()

error

The signature derives the address(0).

ECDSAInvalidSignatureLength(uint256 length)

error

The signature has an invalid length.

ECDSAInvalidSignatureS(bytes32 s)

error

The signature has an S value that is in the upper half order.

EIP712 πŸ“

import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";

EIP-712 is a standard for hashing and signing of typed structured data.

The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to produce the hash of their typed data using a combination of abi.encode and keccak256.

This contract implements the EIP-712 domain separator (EIP712._domainSeparatorV4) that is used as part of the encoding scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA (EIP712._hashTypedDataV4).

The implementation of the domain separator was designed to be as efficient as possible while still properly updating the chain id to protect against replay attacks on an eventual fork of the chain.

NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method eth_signTypedDataV4 in MetaMask.

NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain separator of the implementation contract. This will cause the EIP712._domainSeparatorV4 function to always rebuild the separator from the immutable values, which is cheaper than accessing a cached version in cold storage.

Functions

IERC5267

Events

IERC5267

constructor(string name, string version)

internal

Initializes the domain separator and parameter caches.

The meaning of name and version is specified in EIP-712:

  • name: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
  • version: the current major version of the signing domain.

NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart contract upgrade].

_domainSeparatorV4() β†’ bytes32

internal

Returns the domain separator for the current chain.

_hashTypedDataV4(bytes32 structHash) β†’ bytes32

internal

Given an already hashed struct, this function returns the hash of the fully encoded EIP712 message for this domain.

This hash can be used together with ECDSA.recover to obtain the signer of a message. For example:

bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
    keccak256("Mail(address to,string contents)"),
    mailTo,
    keccak256(bytes(mailContents))
)));
address signer = ECDSA.recover(digest, signature);

eip712Domain() β†’ bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions

public

returns the fields and values that describe the domain separator used by this contract for EIP-712 signature.

_EIP712Name() β†’ string

internal

The name parameter for the EIP712 domain.

NOTE: By default this function reads _name which is an immutable value. It only reads from storage if necessary (in case the value is too large to fit in a ShortString).

_EIP712Version() β†’ string

internal

The version parameter for the EIP712 domain.

NOTE: By default this function reads _version which is an immutable value. It only reads from storage if necessary (in case the value is too large to fit in a ShortString).

Hashes πŸ“

import "@openzeppelin/contracts/utils/cryptography/Hashes.sol";

Library of standard hash functions.

Available since v5.1.

Functions

commutativeKeccak256(bytes32 a, bytes32 b) β†’ bytes32

internal

Commutative Keccak256 hash of a sorted pair of bytes32. Frequently used when working with merkle proofs.

NOTE: Equivalent to the standardNodeHash in our JavaScript library.

efficientKeccak256(bytes32 a, bytes32 b) β†’ bytes32 value

internal

Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.

MerkleProof πŸ“

import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

These functions deal with verification of Merkle Tree proofs.

The tree and the proofs can be generated using our JavaScript library. You will find a quickstart guide in the readme.

WARNING: You should avoid using leaf values that are 64 bytes long prior to hashing, or use a hash function other than keccak256 for hashing leaves. This is because the concatenation of a sorted pair of internal nodes in the Merkle tree could be reinterpreted as a leaf value. OpenZeppelin's JavaScript library generates Merkle trees that are safe against this attack out of the box.

IMPORTANT: Consider memory side-effects when using custom hashing functions that access memory in an unsafe way.

NOTE: This library supports proof verification for merkle trees built using custom commutative hashing functions (i.e. H(a, b) == H(b, a)). Proving leaf inclusion in trees built using non-commutative hashing functions requires additional logic that is not supported by this library.

Functions

Errors

verify(bytes32[] proof, bytes32 root, bytes32 leaf) β†’ bool

internal

Returns true if a leaf can be proved to be a part of a Merkle tree defined by root. For this, a proof must be provided, containing sibling hashes on the branch from the leaf to the root of the tree. Each pair of leaves and each pair of pre-images are assumed to be sorted.

This version handles proofs in memory with the default hashing function.

processProof(bytes32[] proof, bytes32 leaf) β†’ bytes32

internal

Returns the rebuilt hash obtained by traversing a Merkle tree up from leaf using proof. A proof is valid if and only if the rebuilt hash matches the root of the tree. When processing the proof, the pairs of leaves & pre-images are assumed to be sorted.

This version handles proofs in memory with the default hashing function.

verify(bytes32[] proof, bytes32 root, bytes32 leaf, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ bool

internal

Returns true if a leaf can be proved to be a part of a Merkle tree defined by root. For this, a proof must be provided, containing sibling hashes on the branch from the leaf to the root of the tree. Each pair of leaves and each pair of pre-images are assumed to be sorted.

This version handles proofs in memory with a custom hashing function.

processProof(bytes32[] proof, bytes32 leaf, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ bytes32

internal

Returns the rebuilt hash obtained by traversing a Merkle tree up from leaf using proof. A proof is valid if and only if the rebuilt hash matches the root of the tree. When processing the proof, the pairs of leaves & pre-images are assumed to be sorted.

This version handles proofs in memory with a custom hashing function.

verifyCalldata(bytes32[] proof, bytes32 root, bytes32 leaf) β†’ bool

internal

Returns true if a leaf can be proved to be a part of a Merkle tree defined by root. For this, a proof must be provided, containing sibling hashes on the branch from the leaf to the root of the tree. Each pair of leaves and each pair of pre-images are assumed to be sorted.

This version handles proofs in calldata with the default hashing function.

processProofCalldata(bytes32[] proof, bytes32 leaf) β†’ bytes32

internal

Returns the rebuilt hash obtained by traversing a Merkle tree up from leaf using proof. A proof is valid if and only if the rebuilt hash matches the root of the tree. When processing the proof, the pairs of leaves & pre-images are assumed to be sorted.

This version handles proofs in calldata with the default hashing function.

verifyCalldata(bytes32[] proof, bytes32 root, bytes32 leaf, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ bool

internal

Returns true if a leaf can be proved to be a part of a Merkle tree defined by root. For this, a proof must be provided, containing sibling hashes on the branch from the leaf to the root of the tree. Each pair of leaves and each pair of pre-images are assumed to be sorted.

This version handles proofs in calldata with a custom hashing function.

processProofCalldata(bytes32[] proof, bytes32 leaf, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ bytes32

internal

Returns the rebuilt hash obtained by traversing a Merkle tree up from leaf using proof. A proof is valid if and only if the rebuilt hash matches the root of the tree. When processing the proof, the pairs of leaves & pre-images are assumed to be sorted.

This version handles proofs in calldata with a custom hashing function.

multiProofVerify(bytes32[] proof, bool[] proofFlags, bytes32 root, bytes32[] leaves) β†’ bool

internal

Returns true if the leaves can be simultaneously proven to be a part of a Merkle tree defined by root, according to proof and proofFlags as described in MerkleProof.processMultiProof.

This version handles multiproofs in memory with the default hashing function.

CAUTION: Not all Merkle trees admit multiproofs. See MerkleProof.processMultiProof for details.

NOTE: Consider the case where root == proof[0] && leaves.length == 0 as it will return true. The leaves must be validated independently. See MerkleProof.processMultiProof.

processMultiProof(bytes32[] proof, bool[] proofFlags, bytes32[] leaves) β†’ bytes32 merkleRoot

internal

Returns the root of a tree reconstructed from leaves and sibling nodes in proof. The reconstruction proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another leaf/inner node or a proof sibling node, depending on whether each proofFlags item is true or false respectively.

This version handles multiproofs in memory with the default hashing function.

CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).

NOTE: The empty set (i.e. the case where proof.length == 1 && leaves.length == 0) is considered a no-op, and therefore a valid multiproof (i.e. it returns proof[0]). Consider disallowing this case if you're not validating the leaves elsewhere.

multiProofVerify(bytes32[] proof, bool[] proofFlags, bytes32 root, bytes32[] leaves, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ bool

internal

Returns true if the leaves can be simultaneously proven to be a part of a Merkle tree defined by root, according to proof and proofFlags as described in MerkleProof.processMultiProof.

This version handles multiproofs in memory with a custom hashing function.

CAUTION: Not all Merkle trees admit multiproofs. See MerkleProof.processMultiProof for details.

NOTE: Consider the case where root == proof[0] && leaves.length == 0 as it will return true. The leaves must be validated independently. See MerkleProof.processMultiProof.

processMultiProof(bytes32[] proof, bool[] proofFlags, bytes32[] leaves, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ bytes32 merkleRoot

internal

Returns the root of a tree reconstructed from leaves and sibling nodes in proof. The reconstruction proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another leaf/inner node or a proof sibling node, depending on whether each proofFlags item is true or false respectively.

This version handles multiproofs in memory with a custom hashing function.

CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).

NOTE: The empty set (i.e. the case where proof.length == 1 && leaves.length == 0) is considered a no-op, and therefore a valid multiproof (i.e. it returns proof[0]). Consider disallowing this case if you're not validating the leaves elsewhere.

multiProofVerifyCalldata(bytes32[] proof, bool[] proofFlags, bytes32 root, bytes32[] leaves) β†’ bool

internal

Returns true if the leaves can be simultaneously proven to be a part of a Merkle tree defined by root, according to proof and proofFlags as described in MerkleProof.processMultiProof.

This version handles multiproofs in calldata with the default hashing function.

CAUTION: Not all Merkle trees admit multiproofs. See MerkleProof.processMultiProof for details.

NOTE: Consider the case where root == proof[0] && leaves.length == 0 as it will return true. The leaves must be validated independently. See MerkleProof.processMultiProofCalldata.

processMultiProofCalldata(bytes32[] proof, bool[] proofFlags, bytes32[] leaves) β†’ bytes32 merkleRoot

internal

Returns the root of a tree reconstructed from leaves and sibling nodes in proof. The reconstruction proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another leaf/inner node or a proof sibling node, depending on whether each proofFlags item is true or false respectively.

This version handles multiproofs in calldata with the default hashing function.

CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).

NOTE: The empty set (i.e. the case where proof.length == 1 && leaves.length == 0) is considered a no-op, and therefore a valid multiproof (i.e. it returns proof[0]). Consider disallowing this case if you're not validating the leaves elsewhere.

multiProofVerifyCalldata(bytes32[] proof, bool[] proofFlags, bytes32 root, bytes32[] leaves, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ bool

internal

Returns true if the leaves can be simultaneously proven to be a part of a Merkle tree defined by root, according to proof and proofFlags as described in MerkleProof.processMultiProof.

This version handles multiproofs in calldata with a custom hashing function.

CAUTION: Not all Merkle trees admit multiproofs. See MerkleProof.processMultiProof for details.

NOTE: Consider the case where root == proof[0] && leaves.length == 0 as it will return true. The leaves must be validated independently. See MerkleProof.processMultiProofCalldata.

processMultiProofCalldata(bytes32[] proof, bool[] proofFlags, bytes32[] leaves, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ bytes32 merkleRoot

internal

Returns the root of a tree reconstructed from leaves and sibling nodes in proof. The reconstruction proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another leaf/inner node or a proof sibling node, depending on whether each proofFlags item is true or false respectively.

This version handles multiproofs in calldata with a custom hashing function.

CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).

NOTE: The empty set (i.e. the case where proof.length == 1 && leaves.length == 0) is considered a no-op, and therefore a valid multiproof (i.e. it returns proof[0]). Consider disallowing this case if you're not validating the leaves elsewhere.

MerkleProofInvalidMultiproof()

error

The multiproof provided is not valid.

MessageHashUtils πŸ“

import "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";

Signature message hash utilities for producing digests to be consumed by ECDSA recovery or signing.

The library provides methods for generating a hash of a message that conforms to the ERC-191 and EIP 712 specifications.

Functions

toEthSignedMessageHash(bytes32 messageHash) β†’ bytes32 digest

internal

Returns the keccak256 digest of an ERC-191 signed data with version 0x45 (personal_sign messages).

The digest is calculated by prefixing a bytes32 messageHash with "\x19Ethereum Signed Message:\n32" and hashing the result. It corresponds with the hash signed when using the eth_sign JSON-RPC method.

NOTE: The messageHash parameter is intended to be the result of hashing a raw message with keccak256, although any bytes32 value can be safely used because the final digest will be re-hashed.

See ECDSA.recover.

toEthSignedMessageHash(bytes message) β†’ bytes32

internal

Returns the keccak256 digest of an ERC-191 signed data with version 0x45 (personal_sign messages).

The digest is calculated by prefixing an arbitrary message with "\x19Ethereum Signed Message:\n" + len(message) and hashing the result. It corresponds with the hash signed when using the eth_sign JSON-RPC method.

See ECDSA.recover.

toDataWithIntendedValidatorHash(address validator, bytes data) β†’ bytes32

internal

Returns the keccak256 digest of an ERC-191 signed data with version 0x00 (data with intended validator).

The digest is calculated by prefixing an arbitrary data with "\x19\x00" and the intended validator address. Then hashing the result.

See ECDSA.recover.

toDataWithIntendedValidatorHash(address validator, bytes32 messageHash) β†’ bytes32 digest

internal

Variant of #MessageHashUtils-toDataWithIntendedValidatorHash-address-bytes- optimized for cases where data is a bytes32.

toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) β†’ bytes32 digest

internal

Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version 0x01).

The digest is calculated from a domainSeparator and a structHash, by prefixing them with \x19\x01 and hashing the result. It corresponds to the hash signed by the eth_signTypedData JSON-RPC method as part of EIP-712.

See ECDSA.recover.

P256 πŸ“

import "@openzeppelin/contracts/utils/cryptography/P256.sol";

Implementation of secp256r1 verification and recovery functions.

The secp256r1 curve (also known as P256) is a NIST standard curve with wide support in modern devices and cryptographic standards. Some notable examples include Apple's Secure Enclave and Android's Keystore as well as authentication protocols like FIDO2.

Based on the original implementation of itsobvioustech (GNU General Public License v3.0). Heavily inspired in maxrobot and tdrerup implementations.

Available since v5.1.

Functions

verify(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) β†’ bool

internal

Verifies a secp256r1 signature using the RIP-7212 precompile and falls back to the Solidity implementation if the precompile is not available. This version should work on all chains, but requires the deployment of more bytecode.

verifyNative(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) β†’ bool

internal

Same as IERC7913SignatureVerifier.verify, but it will revert if the required precompile is not available.

Make sure any logic (code or precompile) deployed at that address is the expected one, otherwise the returned value may be misinterpreted as a positive boolean.

verifySolidity(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) β†’ bool

internal

Same as IERC7913SignatureVerifier.verify, but only the Solidity implementation is used.

recovery(bytes32 h, uint8 v, bytes32 r, bytes32 s) β†’ bytes32 x, bytes32 y

internal

Public key recovery

isValidPublicKey(bytes32 x, bytes32 y) β†’ bool result

internal

Checks if (x, y) are valid coordinates of a point on the curve. In particular this function checks that x < P and y < P.

RSA πŸ“

import "@openzeppelin/contracts/utils/cryptography/RSA.sol";

RSA PKCS#1 v1.5 signature verification implementation according to RFC8017.

This library supports PKCS#1 v1.5 padding to avoid malleability via chosen plaintext attacks in practical implementations. The padding follows the EMSA-PKCS1-v1_5-ENCODE encoding definition as per section 9.2 of the RFC. This padding makes RSA semantically secure for signing messages.

Inspired by AdriΓ  Massanet's work (GNU General Public License v3.0).

Available since v5.1.

Functions

pkcs1Sha256(bytes data, bytes s, bytes e, bytes n) β†’ bool

internal

Same as RSA.pkcs1Sha256 but using SHA256 to calculate the digest of data.

pkcs1Sha256(bytes32 digest, bytes s, bytes e, bytes n) β†’ bool

internal

Verifies a PKCSv1.5 signature given a digest according to the verification method described in section 8.2.2 of RFC8017 with support for explicit or implicit NULL parameters in the DigestInfo (no other optional parameters are supported).

IMPORTANT: For security reason, this function requires the signature and modulus to have a length of at least 2048 bits. If you use a smaller key, consider replacing it with a larger, more secure, one.

WARNING: This verification algorithm doesn't prevent replayability. If called multiple times with the same digest, public key and (valid signature), it will return true every time. Consider including an onchain nonce or unique identifier in the message to prevent replay attacks.

WARNING: This verification algorithm supports any exponent. NIST recommends using 65537 (or higher). That is the default value many libraries use, such as OpenSSL. Developers may choose to reject public keys using a low exponent out of security concerns.

SignatureChecker πŸ“

import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";

Signature verification helper that can be used instead of ECDSA.recover to seamlessly support:

  • ECDSA signatures from externally owned accounts (EOAs)
  • ERC-1271 signatures from smart contract wallets like Argent and Safe Wallet (previously Gnosis Safe)
  • ERC-7913 signatures from keys that do not have an Ethereum address of their own

See ERC-1271 and ERC-7913.

Functions

isValidSignatureNow(address signer, bytes32 hash, bytes signature) β†’ bool

internal

Checks if a signature is valid for a given signer and data hash. If the signer has code, the signature is validated against it using ERC-1271, otherwise it's validated using ECDSA.recover.

NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus change through time. It could return true at block N and false at block N+1 (or the opposite).

NOTE: For an extended version of this function that supports ERC-7913 signatures, see #SignatureChecker-isValidSignatureNow-bytes-bytes32-bytes-.

isValidSignatureNowCalldata(address signer, bytes32 hash, bytes signature) β†’ bool

internal

Variant of SignatureChecker.isValidSignatureNow that takes a signature in calldata

isValidERC1271SignatureNow(address signer, bytes32 hash, bytes signature) β†’ bool result

internal

Checks if a signature is valid for a given signer and data hash. The signature is validated against the signer smart contract using ERC-1271.

NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus change through time. It could return true at block N and false at block N+1 (or the opposite).

isValidSignatureNow(bytes signer, bytes32 hash, bytes signature) β†’ bool

internal

Verifies a signature for a given ERC-7913 signer and hash.

The signer is a bytes object that is the concatenation of an address and optionally a key: verifier || key. A signer must be at least 20 bytes long.

Verification is done as follows:

NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus change through time. It could return true at block N and false at block N+1 (or the opposite).

areValidSignaturesNow(bytes32 hash, bytes[] signers, bytes[] signatures) β†’ bool

internal

Verifies multiple ERC-7913 signatures for a given hash using a set of signers. Returns false if the number of signers and signatures is not the same.

The signers should be ordered by their keccak256 hash to ensure efficient duplication check. Unordered signers are supported, but the uniqueness check will be more expensive.

NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus change through time. It could return true at block N and false at block N+1 (or the opposite).

WebAuthn πŸ“

import "@openzeppelin/contracts/utils/cryptography/WebAuthn.sol";

Library for verifying WebAuthn Authentication Assertions.

WebAuthn enables strong authentication for smart contracts using P256 as an alternative to traditional secp256k1 ECDSA signatures. This library verifies signatures generated during WebAuthn authentication ceremonies as specified in the WebAuthn Level 2 standard.

For blockchain use cases, the following WebAuthn validations are intentionally omitted:

  • Origin validation: Origin verification in clientDataJSON is omitted as blockchain contexts rely on authenticator and dapp frontend enforcement. Standard authenticators implement proper origin validation.
  • RP ID hash validation: Verification of rpIdHash in authenticatorData against expected RP ID hash is omitted. This is typically handled by platform-level security measures. Including an expiry timestamp in signed data is recommended for enhanced security.
  • Signature counter: Verification of signature counter increments is omitted. While useful for detecting credential cloning, on-chain operations typically include nonce protection, making this check redundant.
  • Extension outputs: Extension output value verification is omitted as these are not essential for core authentication security in blockchain applications.
  • Attestation: Attestation object verification is omitted as this implementation focuses on authentication (webauthn.get) rather than registration ceremonies.

Inspired by:

Functions

verify(bytes challenge, struct WebAuthn.WebAuthnAuth auth, bytes32 qx, bytes32 qy) β†’ bool

internal

Performs standard verification of a WebAuthn Authentication Assertion.

verify(bytes challenge, struct WebAuthn.WebAuthnAuth auth, bytes32 qx, bytes32 qy, bool requireUV) β†’ bool

internal

Performs verification of a WebAuthn Authentication Assertion. This variants allow the caller to select whether of not to require the UV flag (step 17).

Verifies:

  1. Type is "webauthn.get" (see WebAuthn._validateExpectedTypeHash)
  2. Challenge matches the expected value (see WebAuthn._validateChallenge)
  3. Cryptographic signature is valid for the given public key
  4. confirming physical user presence during authentication
  5. (if requireUV is true) confirming stronger user authentication (biometrics/PIN)
  6. Backup Eligibility (BE) and Backup State (BS) bits relationship is valid

tryDecodeAuth(bytes input) β†’ bool success, struct WebAuthn.WebAuthnAuth auth

internal

Verifies that calldata bytes (input) represents a valid WebAuthnAuth object. If encoding is valid, returns true and the calldata view at the object. Otherwise, returns false and an invalid calldata object.

NOTE: The returned auth object should not be accessed if success is false. Trying to access the data may cause revert/panic.

ERC7739Utils πŸ“

import "@openzeppelin/contracts/utils/cryptography/draft-ERC7739Utils.sol";

Utilities to process ERC-7739 typed data signatures that are specific to an EIP-712 domain.

This library provides methods to wrap, unwrap and operate over typed data signatures with a defensive rehashing mechanism that includes the app's xref:api:utils/cryptography#EIP712-_domainSeparatorV4[EIP-712] and preserves readability of the signed content using an EIP-712 nested approach.

A smart contract domain can validate a signature for a typed data structure in two ways:

NOTE: A provider for a smart contract wallet would need to return this signature as the result of a call to personal_sign or eth_signTypedData, and this may be unsupported by API clients that expect a return value of 129 bytes, or specifically the r,s,v parameters of an xref:api:utils/cryptography#ECDSA[ECDSA] signature, as is for example specified for xref:api:utils/cryptography#EIP712[EIP-712].

Functions

encodeTypedDataSig(bytes signature, bytes32 appSeparator, bytes32 contentsHash, string contentsDescr) β†’ bytes

internal

Nest a signature for a given EIP-712 type into a nested signature for the domain of the app.

Counterpart of ERC7739Utils.decodeTypedDataSig to extract the original signature and the nested components.

decodeTypedDataSig(bytes encodedSignature) β†’ bytes signature, bytes32 appSeparator, bytes32 contentsHash, string contentsDescr

internal

Parses a nested signature into its components.

Constructed as follows:

signature β€– APP_DOMAIN_SEPARATOR β€– contentsHash β€– contentsDescr β€– uint16(contentsDescr.length)

  • signature is the signature for the (ERC-7739) nested struct hash. This signature indirectly signs over the original "contents" hash (from the app) and the account's domain separator.
  • APP_DOMAIN_SEPARATOR is the EIP-712 EIP712._domainSeparatorV4 of the application smart contract that is requesting the signature verification (though ERC-1271).
  • contentsHash is the hash of the underlying data structure or message.
  • contentsDescr is a descriptor of the "contents" part of the the EIP-712 type of the nested signature.

NOTE: This function returns empty if the input format is invalid instead of reverting. data instead.

personalSignStructHash(bytes32 contents) β†’ bytes32

internal

Nests an ERC-191 digest into a PersonalSign EIP-712 struct, and returns the corresponding struct hash. This struct hash must be combined with a domain separator, using MessageHashUtils.toTypedDataHash before being verified/recovered.

This is used to simulates the personal_sign RPC method in the context of smart contracts.

typedDataSignStructHash(string contentsName, string contentsType, bytes32 contentsHash, bytes domainBytes) β†’ bytes32 result

internal

Nests an EIP-712 hash (contents) into a TypedDataSign EIP-712 struct, and returns the corresponding struct hash. This struct hash must be combined with a domain separator, using MessageHashUtils.toTypedDataHash before being verified/recovered.

typedDataSignStructHash(string contentsDescr, bytes32 contentsHash, bytes domainBytes) β†’ bytes32 result

internal

Variant of #ERC7739Utils-typedDataSignStructHash-string-string-bytes32-bytes- that takes a content descriptor and decodes the contentsName and contentsType out of it.

typedDataSignTypehash(string contentsName, string contentsType) β†’ bytes32

internal

Compute the EIP-712 typehash of the TypedDataSign structure for a given type (and typename).

decodeContentsDescr(string contentsDescr) β†’ string contentsName, string contentsType

internal

Parse the type name out of the ERC-7739 contents type description. Supports both the implicit and explicit modes.

Following ERC-7739 specifications, a contentsName is considered invalid if it's empty or it contains any of the following bytes , )\x00

If the contentsType is invalid, this returns an empty string. Otherwise, the return string has non-zero length.

AbstractSigner πŸ“

import "@openzeppelin/contracts/utils/cryptography/signers/AbstractSigner.sol";

Abstract contract for signature validation.

Developers must implement AccountERC7579._rawSignatureValidation and use it as the lowest-level signature validation mechanism.

@custom:stateless

Functions

_rawSignatureValidation(bytes32 hash, bytes signature) β†’ bool

internal

Signature validation algorithm.

WARNING: Implementing a signature validation algorithm is a security-sensitive operation as it involves cryptographic verification. It is important to review and test thoroughly before deployment. Consider using one of the signature verification libraries (xref:api:utils/cryptography#ECDSA[ECDSA], xref:api:utils/cryptography#P256[P256] or xref:api:utils/cryptography#RSA[RSA]).

MultiSignerERC7913 πŸ“

import "@openzeppelin/contracts/utils/cryptography/signers/MultiSignerERC7913.sol";

Implementation of AbstractSigner using multiple ERC-7913 signers with a threshold-based signature verification system.

This contract allows managing a set of authorized signers and requires a minimum number of signatures (threshold) to approve operations. It uses ERC-7913 formatted signers, which makes it natively compatible with ECDSA and ERC-1271 signers.

Example of usage:

contract MyMultiSignerAccount is Account, MultiSignerERC7913, Initializable {
    function initialize(bytes[] memory signers, uint64 threshold) public initializer {
        _addSigners(signers);
        _setThreshold(threshold);
    }

    function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf {
        _addSigners(signers);
    }

    function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf {
        _removeSigners(signers);
    }

    function setThreshold(uint64 threshold) public onlyEntryPointOrSelf {
        _setThreshold(threshold);
    }
}

IMPORTANT: Failing to properly initialize the signers and threshold either during construction (if used standalone) or during initialization (if used as a clone) may leave the contract either front-runnable or unusable.

Functions

AbstractSigner

Events

AbstractSigner

Errors

AbstractSigner

constructor(bytes[] signers_, uint64 threshold_)

internal

getSigners(uint64 start, uint64 end) β†’ bytes[]

public

Returns a slice of the set of authorized signers.

Using start = 0 and end = type(uint64).max will return the entire set of signers.

WARNING: Depending on the start and end, this operation can copy a large amount of data to memory, which can be expensive. This is designed for view accessors queried without gas fees. Using it in state-changing functions may become uncallable if the slice grows too large.

getSignerCount() β†’ uint256

public

Returns the number of authorized signers

isSigner(bytes signer) β†’ bool

public

Returns whether the signer is an authorized signer.

threshold() β†’ uint64

public

Returns the minimum number of signers required to approve a multisignature operation.

_addSigners(bytes[] newSigners)

internal

Adds the newSigners to those allowed to sign on behalf of this contract. Internal version without access control.

Requirements:

_removeSigners(bytes[] oldSigners)

internal

Removes the oldSigners from the authorized signers. Internal version without access control.

Requirements:

_setThreshold(uint64 newThreshold)

internal

Sets the signatures threshold required to approve a multisignature operation. Internal version without access control.

Requirements:

_validateReachableThreshold()

internal

Validates the current threshold is reachable.

Requirements:

_rawSignatureValidation(bytes32 hash, bytes signature) β†’ bool

internal

Decodes, validates the signature and checks the signers are authorized. See MultiSignerERC7913._validateSignatures and MultiSignerERC7913._validateThreshold for more details.

Example of signature encoding:

// Encode signers (verifier || key)
bytes memory signer1 = abi.encodePacked(verifier1, key1);
bytes memory signer2 = abi.encodePacked(verifier2, key2);

// Order signers by their id
if (keccak256(signer1) > keccak256(signer2)) {
    (signer1, signer2) = (signer2, signer1);
    (signature1, signature2) = (signature2, signature1);
}

// Assign ordered signers and signatures
bytes[] memory signers = new bytes[](2);
bytes[] memory signatures = new bytes[](2);
signers[0] = signer1;
signatures[0] = signature1;
signers[1] = signer2;
signatures[1] = signature2;

// Encode the multi signature
bytes memory signature = abi.encode(signers, signatures);

Requirements:

  • The signature must be encoded as abi.encode(signers, signatures).

_validateSignatures(bytes32 hash, bytes[] signers, bytes[] signatures) β†’ bool valid

internal

Validates the signatures using the signers and their corresponding signatures. Returns whether the signers are authorized and the signatures are valid for the given hash.

IMPORTANT: Sorting the signers by their keccak256 hash will improve the gas efficiency of this function.

Requirements:

  • The signatures and signers arrays must be equal in length. Returns false otherwise.

_validateThreshold(bytes[] validatingSigners) β†’ bool

internal

Validates that the number of signers meets the MultiSignerERC7913.threshold requirement. Assumes the signers were already validated. See MultiSignerERC7913._validateSignatures for more details.

ERC7913SignerAdded(bytes indexed signers)

event

Emitted when a signer is added.

ERC7913SignerRemoved(bytes indexed signers)

event

Emitted when a signers is removed.

ERC7913ThresholdSet(uint64 threshold)

event

Emitted when the threshold is updated.

MultiSignerERC7913AlreadyExists(bytes signer)

error

The signer already exists.

MultiSignerERC7913NonexistentSigner(bytes signer)

error

The signer does not exist.

MultiSignerERC7913InvalidSigner(bytes signer)

error

The signer is less than 20 bytes long.

MultiSignerERC7913ZeroThreshold()

error

The threshold is zero.

MultiSignerERC7913UnreachableThreshold(uint64 signers, uint64 threshold)

error

The threshold is unreachable given the number of signers.

MultiSignerERC7913Weighted πŸ“

import "@openzeppelin/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sol";

Extension of MultiSignerERC7913 that supports weighted signatures.

This contract allows assigning different weights to each signer, enabling more flexible governance schemes. For example, some signers could have higher weight than others, allowing for weighted voting or prioritized authorization.

Example of usage:

contract MyWeightedMultiSignerAccount is Account, MultiSignerERC7913Weighted, Initializable {
    function initialize(bytes[] memory signers, uint64[] memory weights, uint64 threshold) public initializer {
        _addSigners(signers);
        _setSignerWeights(signers, weights);
        _setThreshold(threshold);
    }

    function addSigners(bytes[] memory signers) public onlyEntryPointOrSelf {
        _addSigners(signers);
    }

    function removeSigners(bytes[] memory signers) public onlyEntryPointOrSelf {
        _removeSigners(signers);
    }

    function setThreshold(uint64 threshold) public onlyEntryPointOrSelf {
        _setThreshold(threshold);
    }

    function setSignerWeights(bytes[] memory signers, uint64[] memory weights) public onlyEntryPointOrSelf {
        _setSignerWeights(signers, weights);
    }
}

IMPORTANT: When setting a threshold value, ensure it matches the scale used for signer weights. For example, if signers have weights like 1, 2, or 3, then a threshold of 4 would require at least two signers (e.g., one with weight 1 and one with weight 3). See MultiSignerERC7913Weighted.signerWeight.

Functions

MultiSignerERC7913

AbstractSigner

Events

MultiSignerERC7913

AbstractSigner

Errors

MultiSignerERC7913

AbstractSigner

constructor(bytes[] signers_, uint64[] weights_, uint64 threshold_)

internal

signerWeight(bytes signer) β†’ uint64

public

Gets the weight of a signer. Returns 0 if the signer is not authorized.

totalWeight() β†’ uint64

public

Gets the total weight of all signers.

_setSignerWeights(bytes[] signers, uint64[] weights)

internal

Sets weights for multiple signers at once. Internal version without access control.

Requirements:

Emits MultiSignerERC7913Weighted.ERC7913SignerWeightChanged for each signer.

_addSigners(bytes[] newSigners)

internal

See MultiSignerERC7913._addSigners.

In cases where MultiSignerERC7913Weighted.totalWeight is almost type(uint64).max (due to a large _totalExtraWeight), adding new signers could cause the MultiSignerERC7913Weighted.totalWeight computation to overflow. Adding a MultiSignerERC7913Weighted.totalWeight calls after the new signers are added ensures no such overflow happens.

_removeSigners(bytes[] signers)

internal

See MultiSignerERC7913._removeSigners.

Just like MultiSignerERC7913._addSigners, this function does not emit MultiSignerERC7913Weighted.ERC7913SignerWeightChanged events. The MultiSignerERC7913.ERC7913SignerRemoved event emitted by MultiSignerERC7913._removeSigners is enough to track weights here.

_validateReachableThreshold()

internal

Sets the threshold for the multisignature operation. Internal version without access control.

Requirements:

NOTE: This function intentionally does not call super._validateReachableThreshold because the base implementation assumes each signer has a weight of 1, which is a subset of this weighted implementation. Consider that multiple implementations of this function may exist in the contract, so important side effects may be missed depending on the linearization order.

_validateThreshold(bytes[] signers) β†’ bool

internal

Validates that the total weight of signers meets the threshold requirement.

NOTE: This function intentionally does not call super._validateThreshold because the base implementation assumes each signer has a weight of 1, which is a subset of this weighted implementation. Consider that multiple implementations of this function may exist in the contract, so important side effects may be missed depending on the linearization order.

ERC7913SignerWeightChanged(bytes indexed signer, uint64 weight)

event

Emitted when a signer's weight is changed.

NOTE: Not emitted in MultiSignerERC7913._addSigners or MultiSignerERC7913._removeSigners. Indexers must rely on MultiSignerERC7913.ERC7913SignerAdded and MultiSignerERC7913.ERC7913SignerRemoved to index a default weight of 1. See MultiSignerERC7913Weighted.signerWeight.

MultiSignerERC7913WeightedInvalidWeight(bytes signer, uint64 weight)

error

Thrown when a signer's weight is invalid.

MultiSignerERC7913WeightedMismatchedLength()

error

Thrown when the arrays lengths don't match. See MultiSignerERC7913Weighted._setSignerWeights.

SignerECDSA πŸ“

import "@openzeppelin/contracts/utils/cryptography/signers/SignerECDSA.sol";

Implementation of AbstractSigner using xref:api:utils/cryptography#ECDSA[ECDSA] signatures.

For Account usage, a SignerECDSA._setSigner function is provided to set the SignerECDSA.signer address. Doing so is easier for a factory, who is likely to use initializable clones of this contract.

Example of usage:

contract MyAccountECDSA is Account, SignerECDSA, Initializable {
    function initialize(address signerAddr) public initializer {
      _setSigner(signerAddr);
    }
}

IMPORTANT: Failing to call SignerECDSA._setSigner either during construction (if used standalone) or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.

Functions

AbstractSigner

constructor(address signerAddr)

internal

_setSigner(address signerAddr)

internal

Sets the signer with the address of the native signer. This function should be called during construction or through an initializer.

signer() β†’ address

public

Return the signer's address.

_rawSignatureValidation(bytes32 hash, bytes signature) β†’ bool

internal

Signature validation algorithm.

WARNING: Implementing a signature validation algorithm is a security-sensitive operation as it involves cryptographic verification. It is important to review and test thoroughly before deployment. Consider using one of the signature verification libraries (xref:api:utils/cryptography#ECDSA[ECDSA], xref:api:utils/cryptography#P256[P256] or xref:api:utils/cryptography#RSA[RSA]).

SignerERC7702 πŸ“

import "@openzeppelin/contracts/utils/cryptography/signers/SignerERC7702.sol";

Implementation of AbstractSigner for implementation for an EOA. Useful for ERC-7702 accounts.

@custom:stateless

Functions

AbstractSigner

_rawSignatureValidation(bytes32 hash, bytes signature) β†’ bool

internal

Validates the signature using the EOA's address (i.e. address(this)).

SignerERC7913 πŸ“

import "@openzeppelin/contracts/utils/cryptography/signers/SignerERC7913.sol";

Implementation of AbstractSigner using ERC-7913 signature verification.

For Account usage, a SignerECDSA._setSigner function is provided to set the ERC-7913 formatted SignerECDSA.signer. Doing so is easier for a factory, who is likely to use initializable clones of this contract.

The signer is a bytes object that concatenates a verifier address and a key: verifier || key.

Example of usage:

contract MyAccountERC7913 is Account, SignerERC7913, Initializable {
    function initialize(bytes memory signer_) public initializer {
      _setSigner(signer_);
    }

    function setSigner(bytes memory signer_) public onlyEntryPointOrSelf {
      _setSigner(signer_);
    }
}

IMPORTANT: Failing to call SignerECDSA._setSigner either during construction (if used standalone) or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.

Functions

AbstractSigner

constructor(bytes signer_)

internal

signer() β†’ bytes

public

Return the ERC-7913 signer (i.e. verifier || key).

_setSigner(bytes signer_)

internal

Sets the signer (i.e. verifier || key) with an ERC-7913 formatted signer.

_rawSignatureValidation(bytes32 hash, bytes signature) β†’ bool

internal

Verifies a signature using #SignatureChecker-isValidSignatureNow-bytes-bytes32-bytes- with SignerECDSA.signer, hash and signature.

SignerP256 πŸ“

import "@openzeppelin/contracts/utils/cryptography/signers/SignerP256.sol";

Implementation of AbstractSigner using xref:api:utils/cryptography#P256[P256] signatures.

For Account usage, a SignerECDSA._setSigner function is provided to set the SignerECDSA.signer public key. Doing so is easier for a factory, who is likely to use initializable clones of this contract.

Example of usage:

contract MyAccountP256 is Account, SignerP256, Initializable {
    function initialize(bytes32 qx, bytes32 qy) public initializer {
      _setSigner(qx, qy);
    }
}

IMPORTANT: Failing to call SignerECDSA._setSigner either during construction (if used standalone) or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.

Functions

AbstractSigner

Errors

AbstractSigner

constructor(bytes32 qx, bytes32 qy)

internal

_setSigner(bytes32 qx, bytes32 qy)

internal

Sets the signer with a P256 public key. This function should be called during construction or through an initializer.

signer() β†’ bytes32 qx, bytes32 qy

public

Return the signer's P256 public key.

_rawSignatureValidation(bytes32 hash, bytes signature) β†’ bool

internal

Signature validation algorithm.

WARNING: Implementing a signature validation algorithm is a security-sensitive operation as it involves cryptographic verification. It is important to review and test thoroughly before deployment. Consider using one of the signature verification libraries (xref:api:utils/cryptography#ECDSA[ECDSA], xref:api:utils/cryptography#P256[P256] or xref:api:utils/cryptography#RSA[RSA]).

SignerP256InvalidPublicKey(bytes32 qx, bytes32 qy)

error

SignerRSA πŸ“

import "@openzeppelin/contracts/utils/cryptography/signers/SignerRSA.sol";

Implementation of AbstractSigner using xref:api:utils/cryptography#RSA[RSA] signatures.

For Account usage, a SignerECDSA._setSigner function is provided to set the SignerECDSA.signer public key. Doing so is easier for a factory, who is likely to use initializable clones of this contract.

Example of usage:

contract MyAccountRSA is Account, SignerRSA, Initializable {
    function initialize(bytes memory e, bytes memory n) public initializer {
      _setSigner(e, n);
    }
}

IMPORTANT: Failing to call SignerECDSA._setSigner either during construction (if used standalone) or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.

Functions

AbstractSigner

constructor(bytes e, bytes n)

internal

_setSigner(bytes e, bytes n)

internal

Sets the signer with a RSA public key. This function should be called during construction or through an initializer.

signer() β†’ bytes e, bytes n

public

Return the signer's RSA public key.

_rawSignatureValidation(bytes32 hash, bytes signature) β†’ bool

internal

See AbstractSigner._rawSignatureValidation. Verifies a PKCSv1.5 signature by calling xref:api:utils/cryptography.adoc#RSA-pkcs1Sha256-bytes-bytes-bytes-bytes-[RSA.pkcs1Sha256].

IMPORTANT: Following the RSASSA-PKCS1-V1_5-VERIFY procedure outlined in RFC8017 (section 8.2.2), the provided hash is used as the M (message) and rehashed using SHA256 according to EMSA-PKCS1-v1_5 encoding as per section 9.2 (step 1) of the RFC.

SignerWebAuthn πŸ“

import "@openzeppelin/contracts/utils/cryptography/signers/SignerWebAuthn.sol";

Implementation of SignerP256 that supports WebAuthn authentication assertions.

This contract enables signature validation using WebAuthn authentication assertions, leveraging the P256 public key stored in the contract. It allows for both WebAuthn and raw P256 signature validation, providing compatibility with both signature types.

The signature is expected to be an abi-encoded WebAuthn.WebAuthnAuth struct.

Example usage:

contract MyAccountWebAuthn is Account, SignerWebAuthn, Initializable {
    function initialize(bytes32 qx, bytes32 qy) public initializer {
        _setSigner(qx, qy);
    }
}

IMPORTANT: Failing to call SignerECDSA._setSigner either during construction (if used standalone) or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.

Functions

SignerP256

AbstractSigner

Errors

SignerP256

AbstractSigner

_rawSignatureValidation(bytes32 hash, bytes signature) β†’ bool

internal

Validates a raw signature using the WebAuthn authentication assertion.

In case the signature can't be validated, it falls back to the SignerP256._rawSignatureValidation method for raw P256 signature validation by passing the raw r and s values from the signature.

ERC7739 πŸ“

import "@openzeppelin/contracts/utils/cryptography/signers/draft-ERC7739.sol";

Validates signatures wrapping the message hash in a nested EIP712 type. See ERC7739Utils.

Linking the signature to the EIP-712 domain separator is a security measure to prevent signature replay across different EIP-712 domains (e.g. a single offchain owner of multiple contracts).

This contract requires implementing the AccountERC7579._rawSignatureValidation function, which passes the wrapped message hash, which may be either an typed data or a personal sign nested type.

NOTE: xref:api:utils/cryptography#EIP712[EIP-712] uses xref:api:utils/cryptography#ShortStrings[ShortStrings] to optimize gas costs for short strings (up to 31 characters). Consider that strings longer than that will use storage, which may limit the ability of the signer to be used within the ERC-4337 validation phase (due to ERC-7562 storage access rules).

Functions

IERC1271

EIP712

IERC5267

AbstractSigner

Events

IERC1271

EIP712

IERC5267

AbstractSigner

isValidSignature(bytes32 hash, bytes signature) β†’ bytes4 result

public

Attempts validating the signature in a nested EIP-712 type.

A nested EIP-712 type might be presented in 2 different ways:

  • As a nested EIP-712 typed data
  • As a personal signature (an EIP-712 mimic of the eth_personalSign for a smart contract)

ERC7913P256Verifier πŸ“

import "@openzeppelin/contracts/utils/cryptography/verifiers/ERC7913P256Verifier.sol";

ERC-7913 signature verifier that support P256 (secp256r1) keys.

@custom:stateless

Functions

IERC7913SignatureVerifier

verify(bytes key, bytes32 hash, bytes signature) β†’ bytes4

public

Verifies signature as a valid signature of hash by key.

MUST return the bytes4 magic value IERC7913SignatureVerifier.verify.selector if the signature is valid. SHOULD return 0xffffffff or revert if the signature is not valid. SHOULD return 0xffffffff or revert if the key is empty

ERC7913RSAVerifier πŸ“

import "@openzeppelin/contracts/utils/cryptography/verifiers/ERC7913RSAVerifier.sol";

ERC-7913 signature verifier that support RSA keys.

@custom:stateless

Functions

IERC7913SignatureVerifier

verify(bytes key, bytes32 hash, bytes signature) β†’ bytes4

public

Verifies signature as a valid signature of hash by key.

MUST return the bytes4 magic value IERC7913SignatureVerifier.verify.selector if the signature is valid. SHOULD return 0xffffffff or revert if the signature is not valid. SHOULD return 0xffffffff or revert if the key is empty

ERC7913WebAuthnVerifier πŸ“

import "@openzeppelin/contracts/utils/cryptography/verifiers/ERC7913WebAuthnVerifier.sol";

ERC-7913 signature verifier that supports WebAuthn authentication assertions.

This verifier enables the validation of WebAuthn signatures using P256 public keys. The key is expected to be a 64-byte concatenation of the P256 public key coordinates (qx || qy). The signature is expected to be an abi-encoded WebAuthn.WebAuthnAuth struct.

Uses WebAuthn-verifyMinimal for signature verification, which performs the essential WebAuthn checks: type validation, challenge matching, and cryptographic signature verification.

NOTE: Wallets that may require default P256 validation may install a P256 verifier separately.

Functions

IERC7913SignatureVerifier

verify(bytes key, bytes32 hash, bytes signature) β†’ bytes4

public

Verifies signature as a valid signature of hash by key.

MUST return the bytes4 magic value IERC7913SignatureVerifier.verify.selector if the signature is valid. SHOULD return 0xffffffff or revert if the signature is not valid. SHOULD return 0xffffffff or revert if the key is empty

On this page

UtilsAbstract SignersVerifiersECDSA πŸ“FunctionsErrorstryRecover(bytes32 hash, bytes signature) β†’ address recovered, enum ECDSA.RecoverError err, bytes32 errArgtryRecoverCalldata(bytes32 hash, bytes signature) β†’ address recovered, enum ECDSA.RecoverError err, bytes32 errArgrecover(bytes32 hash, bytes signature) β†’ addressrecoverCalldata(bytes32 hash, bytes signature) β†’ addresstryRecover(bytes32 hash, bytes32 r, bytes32 vs) β†’ address recovered, enum ECDSA.RecoverError err, bytes32 errArgrecover(bytes32 hash, bytes32 r, bytes32 vs) β†’ addresstryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) β†’ address recovered, enum ECDSA.RecoverError err, bytes32 errArgrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) β†’ addressparse(bytes signature) β†’ uint8 v, bytes32 r, bytes32 sparseCalldata(bytes signature) β†’ uint8 v, bytes32 r, bytes32 sECDSAInvalidSignature()ECDSAInvalidSignatureLength(uint256 length)ECDSAInvalidSignatureS(bytes32 s)EIP712 πŸ“FunctionsIERC5267EventsIERC5267constructor(string name, string version)_domainSeparatorV4() β†’ bytes32_hashTypedDataV4(bytes32 structHash) β†’ bytes32eip712Domain() β†’ bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions_EIP712Name() β†’ string_EIP712Version() β†’ stringHashes πŸ“FunctionscommutativeKeccak256(bytes32 a, bytes32 b) β†’ bytes32efficientKeccak256(bytes32 a, bytes32 b) β†’ bytes32 valueMerkleProof πŸ“FunctionsErrorsverify(bytes32[] proof, bytes32 root, bytes32 leaf) β†’ boolprocessProof(bytes32[] proof, bytes32 leaf) β†’ bytes32verify(bytes32[] proof, bytes32 root, bytes32 leaf, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ boolprocessProof(bytes32[] proof, bytes32 leaf, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ bytes32verifyCalldata(bytes32[] proof, bytes32 root, bytes32 leaf) β†’ boolprocessProofCalldata(bytes32[] proof, bytes32 leaf) β†’ bytes32verifyCalldata(bytes32[] proof, bytes32 root, bytes32 leaf, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ boolprocessProofCalldata(bytes32[] proof, bytes32 leaf, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ bytes32multiProofVerify(bytes32[] proof, bool[] proofFlags, bytes32 root, bytes32[] leaves) β†’ boolprocessMultiProof(bytes32[] proof, bool[] proofFlags, bytes32[] leaves) β†’ bytes32 merkleRootmultiProofVerify(bytes32[] proof, bool[] proofFlags, bytes32 root, bytes32[] leaves, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ boolprocessMultiProof(bytes32[] proof, bool[] proofFlags, bytes32[] leaves, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ bytes32 merkleRootmultiProofVerifyCalldata(bytes32[] proof, bool[] proofFlags, bytes32 root, bytes32[] leaves) β†’ boolprocessMultiProofCalldata(bytes32[] proof, bool[] proofFlags, bytes32[] leaves) β†’ bytes32 merkleRootmultiProofVerifyCalldata(bytes32[] proof, bool[] proofFlags, bytes32 root, bytes32[] leaves, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ boolprocessMultiProofCalldata(bytes32[] proof, bool[] proofFlags, bytes32[] leaves, function (bytes32,bytes32) view returns (bytes32) hasher) β†’ bytes32 merkleRootMerkleProofInvalidMultiproof()MessageHashUtils πŸ“FunctionstoEthSignedMessageHash(bytes32 messageHash) β†’ bytes32 digesttoEthSignedMessageHash(bytes message) β†’ bytes32toDataWithIntendedValidatorHash(address validator, bytes data) β†’ bytes32toDataWithIntendedValidatorHash(address validator, bytes32 messageHash) β†’ bytes32 digesttoTypedDataHash(bytes32 domainSeparator, bytes32 structHash) β†’ bytes32 digestP256 πŸ“Functionsverify(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) β†’ boolverifyNative(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) β†’ boolverifySolidity(bytes32 h, bytes32 r, bytes32 s, bytes32 qx, bytes32 qy) β†’ boolrecovery(bytes32 h, uint8 v, bytes32 r, bytes32 s) β†’ bytes32 x, bytes32 yisValidPublicKey(bytes32 x, bytes32 y) β†’ bool resultRSA πŸ“Functionspkcs1Sha256(bytes data, bytes s, bytes e, bytes n) β†’ boolpkcs1Sha256(bytes32 digest, bytes s, bytes e, bytes n) β†’ boolSignatureChecker πŸ“FunctionsisValidSignatureNow(address signer, bytes32 hash, bytes signature) β†’ boolisValidSignatureNowCalldata(address signer, bytes32 hash, bytes signature) β†’ boolisValidERC1271SignatureNow(address signer, bytes32 hash, bytes signature) β†’ bool resultisValidSignatureNow(bytes signer, bytes32 hash, bytes signature) β†’ boolareValidSignaturesNow(bytes32 hash, bytes[] signers, bytes[] signatures) β†’ boolWebAuthn πŸ“Functionsverify(bytes challenge, struct WebAuthn.WebAuthnAuth auth, bytes32 qx, bytes32 qy) β†’ boolverify(bytes challenge, struct WebAuthn.WebAuthnAuth auth, bytes32 qx, bytes32 qy, bool requireUV) β†’ booltryDecodeAuth(bytes input) β†’ bool success, struct WebAuthn.WebAuthnAuth authERC7739Utils πŸ“FunctionsencodeTypedDataSig(bytes signature, bytes32 appSeparator, bytes32 contentsHash, string contentsDescr) β†’ bytesdecodeTypedDataSig(bytes encodedSignature) β†’ bytes signature, bytes32 appSeparator, bytes32 contentsHash, string contentsDescrpersonalSignStructHash(bytes32 contents) β†’ bytes32typedDataSignStructHash(string contentsName, string contentsType, bytes32 contentsHash, bytes domainBytes) β†’ bytes32 resulttypedDataSignStructHash(string contentsDescr, bytes32 contentsHash, bytes domainBytes) β†’ bytes32 resulttypedDataSignTypehash(string contentsName, string contentsType) β†’ bytes32decodeContentsDescr(string contentsDescr) β†’ string contentsName, string contentsTypeAbstractSigner πŸ“Functions_rawSignatureValidation(bytes32 hash, bytes signature) β†’ boolMultiSignerERC7913 πŸ“FunctionsAbstractSignerEventsAbstractSignerErrorsAbstractSignerconstructor(bytes[] signers_, uint64 threshold_)getSigners(uint64 start, uint64 end) β†’ bytes[]getSignerCount() β†’ uint256isSigner(bytes signer) β†’ boolthreshold() β†’ uint64_addSigners(bytes[] newSigners)_removeSigners(bytes[] oldSigners)_setThreshold(uint64 newThreshold)_validateReachableThreshold()_rawSignatureValidation(bytes32 hash, bytes signature) β†’ bool_validateSignatures(bytes32 hash, bytes[] signers, bytes[] signatures) β†’ bool valid_validateThreshold(bytes[] validatingSigners) β†’ boolERC7913SignerAdded(bytes indexed signers)ERC7913SignerRemoved(bytes indexed signers)ERC7913ThresholdSet(uint64 threshold)MultiSignerERC7913AlreadyExists(bytes signer)MultiSignerERC7913NonexistentSigner(bytes signer)MultiSignerERC7913InvalidSigner(bytes signer)MultiSignerERC7913ZeroThreshold()MultiSignerERC7913UnreachableThreshold(uint64 signers, uint64 threshold)MultiSignerERC7913Weighted πŸ“FunctionsMultiSignerERC7913AbstractSignerEventsMultiSignerERC7913AbstractSignerErrorsMultiSignerERC7913AbstractSignerconstructor(bytes[] signers_, uint64[] weights_, uint64 threshold_)signerWeight(bytes signer) β†’ uint64totalWeight() β†’ uint64_setSignerWeights(bytes[] signers, uint64[] weights)_addSigners(bytes[] newSigners)_removeSigners(bytes[] signers)_validateReachableThreshold()_validateThreshold(bytes[] signers) β†’ boolERC7913SignerWeightChanged(bytes indexed signer, uint64 weight)MultiSignerERC7913WeightedInvalidWeight(bytes signer, uint64 weight)MultiSignerERC7913WeightedMismatchedLength()SignerECDSA πŸ“FunctionsAbstractSignerconstructor(address signerAddr)_setSigner(address signerAddr)signer() β†’ address_rawSignatureValidation(bytes32 hash, bytes signature) β†’ boolSignerERC7702 πŸ“FunctionsAbstractSigner_rawSignatureValidation(bytes32 hash, bytes signature) β†’ boolSignerERC7913 πŸ“FunctionsAbstractSignerconstructor(bytes signer_)signer() β†’ bytes_setSigner(bytes signer_)_rawSignatureValidation(bytes32 hash, bytes signature) β†’ boolSignerP256 πŸ“FunctionsAbstractSignerErrorsAbstractSignerconstructor(bytes32 qx, bytes32 qy)_setSigner(bytes32 qx, bytes32 qy)signer() β†’ bytes32 qx, bytes32 qy_rawSignatureValidation(bytes32 hash, bytes signature) β†’ boolSignerP256InvalidPublicKey(bytes32 qx, bytes32 qy)SignerRSA πŸ“FunctionsAbstractSignerconstructor(bytes e, bytes n)_setSigner(bytes e, bytes n)signer() β†’ bytes e, bytes n_rawSignatureValidation(bytes32 hash, bytes signature) β†’ boolSignerWebAuthn πŸ“FunctionsSignerP256AbstractSignerErrorsSignerP256AbstractSigner_rawSignatureValidation(bytes32 hash, bytes signature) β†’ boolERC7739 πŸ“FunctionsIERC1271EIP712IERC5267AbstractSignerEventsIERC1271EIP712IERC5267AbstractSignerisValidSignature(bytes32 hash, bytes signature) β†’ bytes4 resultERC7913P256Verifier πŸ“FunctionsIERC7913SignatureVerifierverify(bytes key, bytes32 hash, bytes signature) β†’ bytes4ERC7913RSAVerifier πŸ“FunctionsIERC7913SignatureVerifierverify(bytes key, bytes32 hash, bytes signature) β†’ bytes4ERC7913WebAuthnVerifier πŸ“FunctionsIERC7913SignatureVerifierverify(bytes key, bytes32 hash, bytes signature) β†’ bytes4