Skip to content

Latest commit

 

History

History
145 lines (95 loc) · 6.37 KB

tip-712.md

File metadata and controls

145 lines (95 loc) · 6.37 KB
tip: 712
title: TRON typed structured data hashing and signing	
author: yanghang8612@163.com
discussions to: https://github.com/tronprotocol/TIPs/issues/443
status: Final
type: Standards Track
category: Interface
created: 2022-07-25

Abstract

This TIP introduces a standard for hashing and signing of typed structured data as opposed to just bytestrings into TRON protocol to solve the problem that hashing structured data is non-trivial and errors result in loss of the security properties of the system, etc.

The encoding function, hashing algorithm and signing algorithm is identical to EIP-712. There are some differences in details. It includes a

  • address: need to remove TRON unique prefixe(0x41) and encoded as uint160
  • trcToken: should be treated as atomic type and encoded as uint256
  • chainId: use block.chainid & 0xffffffff instead

Motivation

This TIP aims to improve the usability of off-chain message signing for use on-chain. We are seeing growing adoption of off-chain message signing as it saves transaction fees and reduces the number of transactions on the blockchain. Currently signed messages are an opaque hex string displayed to the user with little context about the items that make up the message.

A signature scheme consists of hashing algorithm and a signing algorithm. A good hashing algorithm should satisfy security properties such as determinism, second pre-image resistance and collision resistance. Otherwise, it may cause security problems or replay problems, etc. This standard aims to solve these problems.

Specifications

For the structured data 𝕊, they are encoded to bytestrings suitable for hashing and signing as follows:

  • encode(domainSeparator : 𝔹²⁵⁶, message : 𝕊) = "\x19\x01" ‖ domainSeparator ‖ hashStruct(message) where domainSeparator and hashStruct(message) are defined below.

The encoding is compliant with TIP-191 and it`s totaly compatible with EIP-712. The 'version byte' is fixed to 0x01, the version specific data is the 32-byte domain separator domainSeparator and the data to sign is the 32-byte hashStruct(message).

Definition of typed structured data 𝕊

Definitions for all types are identical to EIP-712.

Definition of hashStruct

The hashStruct function is defined as

  • hashStruct(s : 𝕊) = keccak256(typeHash ‖ encodeData(s)) where typeHash = keccak256(encodeType(typeOf(s)))

It's totaly compatible with EIP-712.

Definition of encodeType

The type of a struct is encoded as name ‖ "(" ‖ member₁ ‖ "," ‖ member₂ ‖ "," ‖ … ‖ memberₙ ")" where each member is written as type ‖ " " ‖ name.

It's totaly compatible with EIP-712.

For trcToken, it should be treated as atomic type.

struct AssetTransfer {
    address from;
    address to;
    trcToken id;
    uint256 amount;
    uint8 v;
    bytes32 r;
    bytes32 s;
}

For example, the above AssetTransfer struct is encoded as AssetTransfer(address from,address to,trcToken id,uint256 amount,uint8 v,bytes32 r,bytes32 s).

Definition of encodeData

The encoding of a struct instance is enc(value₁) ‖ enc(value₂) ‖ … ‖ enc(valueₙ), i.e. the concatenation of the encoded member values in the order that they appear in the type. Each encoded member value is exactly 32-byte long.

It's totaly compatible with EIP-712.

The only difference between TRON address and Ethereum address is that TRON address starts with a byte prefix 0x41 and uses base58 encoding, so prefix needs to be removed when the address type is processed.

Definition of domainSeparator

domainSeparator = hashStruct(tip712Domain)

where the type of tip712Domain is identical to EIP712Domain struct defined in EIP-712. It also contains one or more of the below fields.

  • string name the user readable name of signing domain.
  • string version the current major version of the signing domain. Signatures from different versions are not compatible.
  • uint256 chainId the chain id. The user-agent should refuse signing if it does not match the currently active chain.
  • address verifyingContract the address of the contract that will verify the signature. The user-agent may do contract specific phishing prevention.
  • bytes32 salt an disambiguating salt for the protocol. This can be used as a domain separator of last resort.

The only difference is that we define the chainId data used in the domainSeparator to be equal to block.chainid & 0xffffffff. In other words, the chainId data used in the domainSeparator only take the higher four bytes of block.chainId.

The formula for calculating the chainid in domainSeparator is as follows:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract ChainIdExample {

    // after solidity_v0.8.0
    function getChainId() public view returns(bytes32,uint256) {
        uint256 chainId = block.chainid & 0xffffffff;
        return (bytes32(chainId), chainId);
    }

    // before solidity_v0.8.0
    function getChainIdAssembly() public view returns(bytes32,uint256) {
        uint256 chainId;
        assembly {
            chainId := and(chainid(), 0xffffffff)
        }
        return (bytes32(chainId), chainId);
    }
}

Mainnet TIP-712 chainId

In HEX: 0x000000000000000000000000000000000000000000000000000000002b6653dc

In Decimal: 728126428

Example Contract

Nile Testnet TIP-712 chainId

In HEX: 0x00000000000000000000000000000000000000000000000000000000cd8690dc

In Decimal: 3448148188

Example Contract

Backwards Compatibility

The FullNode gRPC calls and SomeStruct.typeHash parameter are currently undefined. Defining them should not affect the behaviour of existing DApps.

The Solidity expression keccak256(someInstance) for an instance someInstance of a struct type SomeStruct is valid syntax. It currently evaluates to the keccak256 hash of the memory address of the instance. This behaviour should be considered dangerous. In some scenarios it will appear to work correctly but in others it will fail determinism and/or injectiveness. DApps that depend on the current behaviour should be considered dangerously broken.