Utilities

Miscellaneous contracts and libraries containing utility functions you can use to improve security, work with new data types, or safely use low-level primitives.

  • AbstractSigner: Abstract contract for internal signature validation in smart contracts.

  • ERC7739Signer: An abstract contract to validate signatures following the rehashing scheme from ERC7739Utils.

  • ERC7739Utils: Utilities library that implements a defensive rehashing mechanism to prevent replayability of smart contract signatures based on ERC-7739.

  • SignerECDSA, SignerP256, SignerRSA: Implementations of an AbstractSigner with specific signature validation algorithms.

  • Masks: Library to handle bytes32 masks.

Cryptography

AbstractSigner

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

Abstract contract for signature validation.

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

Functions
  • _rawSignatureValidation(hash, signature)

_rawSignatureValidation(bytes32 hash, bytes signature) → bool internal

Signature validation algorithm.

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 (ECDSA, P256 or RSA).

ERC7739Signer

import "@openzeppelin/contracts/utils/cryptography/ERC7739Signer.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 _rawSignatureValidation function, which passes the wrapped message hash, which may be either an typed data or a personal sign nested type.

EIP-712 uses 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
  • isValidSignature(hash, signature)

EIP712
  • _domainSeparatorV4()

  • _hashTypedDataV4(structHash)

  • eip712Domain()

  • _EIP712Name()

  • _EIP712Version()

AbstractSigner
  • _rawSignatureValidation(hash, signature)

Events
IERC5267
  • EIP712DomainChanged()

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)

ERC7739Utils

import "@openzeppelin/contracts/utils/cryptography/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 application’s 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:

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 ECDSA signature, as is for example specified for EIP-712.
Functions
  • encodeTypedDataSig(signature, appSeparator, contentsHash, contentsDescr)

  • decodeTypedDataSig(encodedSignature)

  • personalSignStructHash(contents)

  • typedDataSignStructHash(contentsTypeName, contentsType, contentsHash, domainBytes)

  • typedDataSignStructHash(contentsDescr, contentsHash, domainBytes)

  • typedDataSignTypehash(contentsTypeName, contentsType)

  • decodeContentsDescr(contentsDescr)

Errors
  • InvalidContentsType()

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 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 ‖ DOMAIN_SEPARATOR ‖ contentsHash ‖ contentsDescr ‖ uint16(contentsDescr.length)

  • signature is the original signature for the nested struct hash that includes the "contents" hash

  • DOMAIN_SEPARATOR is the EIP-712 {EIP712-_domainSeparatorV4} of the smart contract verifying the signature

  • 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

personalSignStructHash(bytes32 contents) → bytes32 internal

Nests an ERC-191 digest into a PersonalSign EIP-712 struct, and return 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 contentsTypeName, string contentsType, bytes32 contentsHash, bytes domainBytes) → bytes32 result internal

Nests an EIP-712 hash (contents) into a TypedDataSign EIP-712 struct, and return 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 {typedDataSignStructHash-string-string-bytes32-string-bytes} that takes a content descriptor and decodes the contentsTypeName and contentsType out of it.

typedDataSignTypehash(string contentsTypeName, string contentsType) → bytes32 internal

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

decodeContentsDescr(string contentsDescr) → string contentsTypeName, 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 contentsTypeName 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.

InvalidContentsType() error

Error when the contents type is invalid. See {tryValidateContentsType}.

SignerECDSA

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

Implementation of AbstractSigner using ECDSA signatures.

For Account usage, an _initializeSigner function is provided to set the signer address. Doing so it’s easier for a factory, whose likely to use initializable clones of this contract.

Example of usage:

contract MyAccountECDSA is Account, SignerECDSA {
    constructor() EIP712("MyAccountECDSA", "1") {}

    function initializeSigner(address signerAddr) public virtual initializer {
      // Will revert if the signer is already initialized
      _initializeSigner(signerAddr);
    }
}
Avoiding to call _initializeSigner either during construction (if used standalone) or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.
Functions
  • _initializeSigner(signerAddr)

  • signer()

  • _rawSignatureValidation(hash, signature)

Errors
  • SignerECDSAUninitializedSigner(signer)

_initializeSigner(address signerAddr) internal

Initializes the signer with the address of the native signer. This function can be called only once.

signer() → address public

Return the signer’s address.

_rawSignatureValidation(bytes32 hash, bytes signature) → bool internal

Signature validation algorithm.

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 (ECDSA, P256 or RSA).

SignerECDSAUninitializedSigner(address signer) error

The signer is already initialized.

SignerP256

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

Implementation of AbstractSigner using P256 signatures.

For Account usage, an _initializeSigner function is provided to set the signer public key. Doing so it’s easier for a factory, whose likely to use initializable clones of this contract.

Example of usage:

contract MyAccountP256 is Account, SignerP256 {
    constructor() EIP712("MyAccountP256", "1") {}

    function initializeSigner(bytes32 qx, bytes32 qy) public virtual initializer {
      // Will revert if the signer is already initialized
      _initializeSigner(qx, qy);
    }
}
Avoiding to call _initializeSigner either during construction (if used standalone) or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.
Functions
  • _initializeSigner(qx, qy)

  • signer()

  • _rawSignatureValidation(hash, signature)

Errors
  • SignerP256UninitializedSigner(qx, qy)

_initializeSigner(bytes32 qx, bytes32 qy) internal

Initializes the signer with the P256 public key. This function can be called only once.

signer() → bytes32 qx, bytes32 qy public

Return the signer’s P256 public key.

_rawSignatureValidation(bytes32 hash, bytes signature) → bool internal

Signature validation algorithm.

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 (ECDSA, P256 or RSA).

SignerP256UninitializedSigner(bytes32 qx, bytes32 qy) error

The signer is already initialized.

SignerRSA

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

Implementation of AbstractSigner using RSA signatures.

For Account usage, an _initializeSigner function is provided to set the signer public key. Doing so it’s easier for a factory, whose likely to use initializable clones of this contract.

Example of usage:

contract MyAccountRSA is Account, SignerRSA {
    constructor() EIP712("MyAccountRSA", "1") {}

    function initializeSigner(bytes memory e, bytes memory n) external {
      // Will revert if the signer is already initialized
      _initializeSigner(e, n);
    }
}
Avoiding to call _initializeSigner either during construction (if used standalone) or during initialization (if used as a clone) may leave the signer either front-runnable or unusable.
Functions
  • _initializeSigner(e, n)

  • signer()

  • _rawSignatureValidation(hash, signature)

Errors
  • SignerRSAUninitializedSigner(e, n)

_initializeSigner(bytes e, bytes n) internal

Initializes the signer with the RSA public key. This function can be called only once.

signer() → bytes e, bytes n public

Return the signer’s RSA public key.

_rawSignatureValidation(bytes32 hash, bytes signature) → bool internal

Signature validation algorithm.

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 (ECDSA, P256 or RSA).

SignerRSAUninitializedSigner(bytes e, bytes n) error

The signer is already initialized.

Libraries

Masks

import "@openzeppelin/contracts/utils/Masks.sol";

Library for handling bit masks

Functions
  • toMask(group)

  • toMask(groups)

  • get(self, group)

  • isEmpty(self)

  • complement(m1)

  • union(m1, m2)

  • intersection(m1, m2)

  • difference(m1, m2)

  • symmetricDifference(m1, m2)

toMask(uint8 group) → Masks.Mask internal

Returns a new mask with the bit at group index set to 1.

toMask(uint8[] groups) → Masks.Mask internal

Returns a new mask with the bits at groups indices set to 1.

get(Masks.Mask self, uint8 group) → bool internal

Get value of the mask at group index

isEmpty(Masks.Mask self) → bool internal

Whether the mask is bytes32(0)

complement(Masks.Mask m1) → Masks.Mask internal

Invert the bits of a mask

union(Masks.Mask m1, Masks.Mask m2) → Masks.Mask internal

Perform a bitwise OR operation on two masks

intersection(Masks.Mask m1, Masks.Mask m2) → Masks.Mask internal

Perform a bitwise AND operation on two masks

difference(Masks.Mask m1, Masks.Mask m2) → Masks.Mask internal

Perform a bitwise difference operation on two masks (m1 - m2)

symmetricDifference(Masks.Mask m1, Masks.Mask m2) → Masks.Mask internal

Returns the symmetric difference (∆) of two masks, also known as disjunctive union or exclusive OR (XOR)