---
cip: 712
title: Core Signature Verification Standard
description: >-
  Standard for Securely Encoding and Verifying Structured Data Signatures in
  Core Blockchain Applications.
keywords:
  - cip
  - cip-712
  - standard
author: Moji
lang: en-US
status: final
tags:
  - cbc
date: 2023-11-27T00:00:00.000Z
---

Core Signature Verification Standard

<!--truncate-->

## Abstract

CIP-712 defines a standard for hashing and signing typed structured data in Core Blockchain applications. It adapts the data model and `\x19\x01` framing of EIP-712 to Core Blockchain while using Core network identifiers, addresses, hashing, and signatures.

The standard provides domain separation between applications, contracts, and Core networks. Replay protection within a single domain is application-specific and is not provided by CIP-712 itself.

## Motivation

Signing an opaque byte string does not communicate the meaning of a message to the signer. Typed structured data gives wallets and applications the information required to present the message as named fields and gives independent implementations a deterministic way to calculate the same digest.

CIP-712 follows EIP-712 where its rules are compatible with Core Blockchain. The Core-specific rules in this document take precedence. In particular, Core uses `networkId`, Core addresses, SHA3-256, and Core EDDSA signatures.

## Specification

The key words **MUST**, **MUST NOT**, **SHOULD**, and **MAY** in this document are to be interpreted as requirements on conforming implementations.

### Hash Function

In this specification, `hash` means the result of Ylem's `keccak256` function, which uses SHA3-256 on Core Blockchain. Implementations MUST NOT substitute Ethereum's legacy Keccak-256 when calculating CIP-712 hashes.

### Typed Data

Typed data consists of a primary struct type, the definitions of all referenced struct types, and the values of the primary struct's fields. Type names, field types, field names, and field order are part of the signed data.

The canonical type encoding follows EIP-712. For example:

```text
Mail(address to,string contents)
```

The type hash and struct hash are calculated as follows:

```text
typeHash = hash(encodeType(typeOf(data)))
structHash = hash(typeHash || encodeData(data))
```

Values MUST be encoded according to the Ylem ABI. Core `address` values are 22-byte addresses and MUST be encoded as Ylem address values. Dynamic `bytes` and `string` values are represented by the hash of their contents. Nested structs are represented by their struct hash, and arrays are represented by the hash of their encoded elements.

### Domain Separator

CIP-712 uses the following domain type:

```text
EIP712Domain(string name,string version,uint256 networkId,address verifyingContract)
```

The literal name `EIP712Domain` is retained for compatibility with the Core OpenZeppelin implementation and MUST be used when calculating the domain type hash. Renaming the encoded type to `CIP712Domain` produces a different domain separator.

The domain type hash and domain separator are calculated as follows:

```text
domainTypeHash = hash("EIP712Domain(string name,string version,uint256 networkId,address verifyingContract)")

domainSeparator = hash(abi.encode(
    domainTypeHash,
    hash(bytes(name)),
    hash(bytes(version)),
    networkId,
    verifyingContract
))
```

The fields have the following meanings:

- `name`: the human-readable name of the application or protocol.
- `version`: the current major version of the signing domain.
- `networkId`: the current Core network identifier. In Ylem contracts this value is obtained from `block.chainid`.
- `verifyingContract`: the Core address of the contract that will verify the signature.

Changing any domain field invalidates signatures created for the previous domain.

### Signed Digest

The digest presented to the Core signing algorithm MUST be:

```text
digest = hash("\x19\x01" || domainSeparator || structHash)
```

Both `domainSeparator` and `structHash` are exactly 32 bytes. The prefix, domain separator, and struct hash are concatenated without additional ABI padding.

### Signatures

The signer signs `digest` using the Core signing algorithm. A Core signature is a 171-byte blob consisting of a 114-byte signature and a 57-byte public key. CIP-712 signatures MUST be handled as a single `bytes` value and not as an Ethereum-style `(v, r, s)` tuple.

### Verification

A verifier MUST reconstruct the domain separator and struct hash from the expected domain and message, calculate `digest`, recover the signer from the Core signature, and compare the recovered address with the expected signer.

In Ylem, verification can be performed with `ecrecover(bytes32 digest, bytes signature)` or through a wrapper such as Core OpenZeppelin's `EDDSA.recover`. Implementations MUST reject signatures whose length is not 171 bytes and MUST treat signature recovery failure as invalid.

### Contract Implementation

The Core OpenZeppelin `EIP712` contract implements the domain separator and final digest:

```solidity
bytes32 private constant _TYPE_HASH =
    keccak256("EIP712Domain(string name,string version,uint256 networkId,address verifyingContract)");

function _buildDomainSeparator(bytes32 hashedName, bytes32 hashedVersion)
    private
    view
    returns (bytes32)
{
    return keccak256(
        abi.encode(_TYPE_HASH, hashedName, hashedVersion, block.chainid, address(this))
    );
}

function _hashTypedDataV4(bytes32 structHash) internal view returns (bytes32) {
    return EDDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
```

The contract does not implement application-specific struct encoding. Applications MUST define their own type hashes and construct their own struct hashes according to this specification.

Implementations MAY expose their domain through `eip712Domain()`. The Core OpenZeppelin implementation reports `name`, `version`, `networkId`, and `verifyingContract`.

### JSON-RPC

Core clients that provide typed-data signing SHOULD expose it through `xcb_signTypedData_v4`. Typed-data payloads MUST use `networkId`, not Ethereum's `chainId`, and all addresses MUST be valid Core addresses for the selected network.

## Usage

CIP-712 can be used for permits, orders, governance votes, meta-transactions, and other actions authorized by an off-chain signature. Applications SHOULD include all values that affect the authorized action in the signed struct.

## Backward Compatibility

CIP-712 retains the EIP-712 typed-data model and final `\x19\x01` framing, but it is not byte-for-byte compatible with Ethereum EIP-712. Core-specific hashing, address encoding, network identifiers, and signatures produce different results.

Existing Core applications that use the domain and digest construction specified above remain compatible. Applications MUST NOT assume that an Ethereum EIP-712 signature can be verified as a CIP-712 signature.

## Security Considerations

CIP-712 does not provide replay protection within one signing domain. Applications authorizing a one-time action SHOULD include and validate a nonce, deadline, consumed-message record, or another application-specific replay-prevention mechanism.

Including `networkId` and `verifyingContract` in the domain prevents a correctly constructed signature from being reused on a different Core network or by a different contract. Applications MUST verify the complete domain and MUST ensure that wallets display the same domain and message that the verifier will hash.

Implementations MUST use the exact type definitions and field order agreed upon by the signer and verifier. A changed type name, domain type name, field order, hash function, or address encoding produces a different digest.

Submission of a valid signature by an unintended third party may be possible. Applications MUST ensure that early submission either has the exact effect authorized by the signer or is otherwise safely rejected.

## Conclusion

CIP-712 provides a deterministic Core-specific procedure for hashing, signing, and verifying typed structured data while retaining the established EIP-712 framing and domain-separation model.

## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
