tip: 7913
title: Signature Verifiers
description: Interface for the verification of signatures by address-less keys
author: yanghang8612@gmail.com
discussions-to: https://github.com/tronprotocol/tips/issues/903
status: Draft
type: Standards Track
category: TRC
created: 2026-07-02
requires: 712, 1271
Simple Summary
A standard interface for verifying signatures from cryptographic keys that have no on-chain address of their own — such as secp256r1/passkeys, RSA keys, or ZK-proven Web2 credentials — through reusable, stateless verifier contracts.
Abstract
Externally Owned Accounts (EOA) can sign messages with their associated private keys. Additionally TRC-1271 defines a method for signature verification by smart accounts such as multisig. In both cases the identity of the signer is a TRON address. We propose a standard to extend this concept of signer description, and signature verification, to keys that do not have a TRON identity of their own, in the sense that they don't have their own address to represent them.
This new mechanism can be used to integrate new signers such as non-secp256k1 cryptographic curves, hardware devices, or even email addresses. This is particularly relevant when dealing with things like social recovery of smart accounts.
Motivation
With the development of account abstraction, there is an increasing need for signature verification beyond the natively supported secp256k1. Cryptographic algorithms are being used for controlling smart accounts. In particular, curves such as secp256r1 (supported by many mobile devices, and available on TVM as a precompile via TIP-7951) and RSA keys (that are distributed by traditional institutions, and verifiable on TVM through the MODEXP precompile as bounded and repriced by TIP-7823 and TIP-7883) are widely available. Beyond these two examples, we also see the emergence of ZK solutions for signing with emails or JWT from big Web2 services.
All these signature mechanisms have one thing in common: they do not have a canonical TRON address to represent them onchain. While users could deploy TRC-1271 compatible contracts for each key individually, this would be cumbersome and expensive. As account abstraction tries to separate account addresses (that hold assets) from the key that controls them, giving fixed on-chain addresses to keys (and possibly sending assets to these addresses by mistake) is not the right approach. Instead, using a small number of verifier contracts that can process signatures in a standard way, and having the accounts rely on these verifiers, feels like the correct approach. This has the advantage that once the verifier is deployed, any key can be represented using a (verifier, key) pair without requiring any setup cost.
The (verifier, key) pairs can be given permission to control a smart account, perform social recovery, or do any other operation without ever having a dedicated on-chain address. Systems that want to adopt this approach need to transition away from the model where signers are identified by their address to a new model where signers may not have an address, and are identified by a bytes object.
This definition is backward compatible with EOA and TRC-1271 contracts: in that case, we use the address of the identity (EOA or contract) as the verifier and the key is empty.
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Nomenclature
- Keys are represented using
bytes objects of arbitrary length. For example a P256 or RSA public key. Keys MUST NOT be empty.
- Verifiers are smart contracts in charge of signature verification for a given type of key. They have a TRON address.
Signature Verifier interface
Verifiers MUST implement the following interface:
interface ITRC7913SignatureVerifier {
/**
* @dev Verifies `signature` as a valid signature of `hash` by `key`.
*
* MUST return the bytes4 magic value 0x024ad318 (ITRC7913SignatureVerifier.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
*/
function verify(bytes calldata key, bytes32 hash, bytes calldata signature) external view returns (bytes4);
}
Verifiers SHOULD be stateless.
The magic value 0x024ad318 is the selector of verify(bytes,bytes32,bytes) and is therefore unchanged from the original standard, allowing a verifier written for another chain to be reused on TVM without modification. A natural TRON verifier for secp256r1/passkey keys wraps the TIP-7951 precompile, which verifies a P-256 signature against an explicit public key (key = the 64-byte uncompressed point, signature = r || s) and, unlike ecrecover, does not recover an address — exactly the shape this interface expects. A WebAuthn/passkey verifier additionally parses authenticatorData and clientDataJSON before delegating to that primitive.
Rationale
Verifiers can be used to avoid deploying many TRC-1271 "identity contracts" (one per key), which would be expensive. Using this model, new keys can be used without any deployment costs.
TRC-1271 already covers the cases where a key is not necessary. To avoid ambiguity, the verifier contracts should not support (or be expected to support) empty keys. Signers that are 20 bytes long (empty key) should be handled using TRC-1271.
Consistency with existing systems (ecrecover and TRC-1271) requires the message to be a bytes32 hash. On TRON this is usually produced following TIP-712. Cryptographic systems that use different hashing methods SHOULD see this hash as a message, and possibly rehash it following the relevant standards. Wallets producing the hash for a verifier flow MUST NOT wrap it with a TRON personal-message prefix, which would break verification.
Backwards Compatibility
A system can support TRC-7913 signers alongside EOAs and TRC-1271 in the following way.
A signer is a bytes object that is the concatenation of an address and optionally a key: verifier || key. A signer is at least 20 bytes long. The 20-byte verifier is the ABI-level TRON address (the account body with the 0x41 prefix stripped, consistent with TIP-712 and TIP-2612); wallets may display it as Base58Check.
Given a signer signer, a message hash hash, and a signature sign, verification is done as follows:
- if
signer.length < 20: verification fails;
- split
signer into (verifier, key) with verifier being the first 20 bytes and key being the rest (potentially empty);
- if
key is empty, then consider that verifier is the identity.
- verification is done using TRC-1271's
isValidSignature if there is code at verifier address, or ecrecover otherwise;
- if
key is not empty, call ITRC7913SignatureVerifier(verifier).verify(key, hash, signature)
- if the return value is the expected magic value (
0x024ad318) then verification is successful,
- otherwise, verification fails.
Note that TRON's protocol-level weighted-multisignature permission system (TIP-16, TIP-105) is not visible to TVM code and is a separate layer: native permissions gate transaction signing, whereas TRC-7913 governs in-contract signature checks.
Reference Implementation
In Solidity, signature verification could be implemented in the following library:
import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol';
/// @dev Extension of OpenZeppelin's SignatureChecker library
library SignatureCheckerExtended {
function isValidSignatureNow(bytes calldata signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
if (signer.length < 20 ) {
return false;
} else if (signer.length == 20) {
return SignatureChecker.isValidSignatureNow(address(bytes20(signer)), hash, signature);
} else {
try ITRC7913SignatureVerifier(address(bytes20(signer[0:20]))).verify(signer[20:], hash, signature) returns (bytes4 magic) {
return magic == ITRC7913SignatureVerifier.verify.selector;
} catch {
return false;
}
}
}
}
Security Considerations
Signers may be used for anything from a smart-account session key (with a short lifetime of a few hours/days) to social-recovery "guardians" that may only be used several years after they are set up. In order to ensure that these signers remain valid "in perpetuity", the verifier contract should be trustless. This means that the verifiers should not be upgradeable contracts.
Verifiers should also not depend on any value that can be modified after deployment. In Solidity terms, the verify function should be pure. Any parameters that are involved in signature verification should either be part of the key, or part of the immutable code of the verifier. Using an immutable variable (in Solidity) would be safe. The stateless aspect of the verifier also keeps it compatible with the validation-scope rules that a future TRON account-abstraction alt-mempool would impose during the validation phase.
For the empty-key fallback path, the usual ecrecover edge cases apply: a malformed signature returns address(0), so an address(0) result MUST be treated as failure, and s/v normalization (low-s, v ∈ {27, 28}) SHOULD be enforced as in TRC-1271 and TIP-2612.
Copyright
Copyright and related rights waived via CC0.
Simple Summary
A standard interface for verifying signatures from cryptographic keys that have no on-chain address of their own — such as secp256r1/passkeys, RSA keys, or ZK-proven Web2 credentials — through reusable, stateless verifier contracts.
Abstract
Externally Owned Accounts (EOA) can sign messages with their associated private keys. Additionally TRC-1271 defines a method for signature verification by smart accounts such as multisig. In both cases the identity of the signer is a TRON address. We propose a standard to extend this concept of signer description, and signature verification, to keys that do not have a TRON identity of their own, in the sense that they don't have their own address to represent them.
This new mechanism can be used to integrate new signers such as non-secp256k1 cryptographic curves, hardware devices, or even email addresses. This is particularly relevant when dealing with things like social recovery of smart accounts.
Motivation
With the development of account abstraction, there is an increasing need for signature verification beyond the natively supported secp256k1. Cryptographic algorithms are being used for controlling smart accounts. In particular, curves such as secp256r1 (supported by many mobile devices, and available on TVM as a precompile via TIP-7951) and RSA keys (that are distributed by traditional institutions, and verifiable on TVM through the MODEXP precompile as bounded and repriced by TIP-7823 and TIP-7883) are widely available. Beyond these two examples, we also see the emergence of ZK solutions for signing with emails or JWT from big Web2 services.
All these signature mechanisms have one thing in common: they do not have a canonical TRON address to represent them onchain. While users could deploy TRC-1271 compatible contracts for each key individually, this would be cumbersome and expensive. As account abstraction tries to separate account addresses (that hold assets) from the key that controls them, giving fixed on-chain addresses to keys (and possibly sending assets to these addresses by mistake) is not the right approach. Instead, using a small number of verifier contracts that can process signatures in a standard way, and having the accounts rely on these verifiers, feels like the correct approach. This has the advantage that once the verifier is deployed, any key can be represented using a
(verifier, key)pair without requiring any setup cost.The
(verifier, key)pairs can be given permission to control a smart account, perform social recovery, or do any other operation without ever having a dedicated on-chain address. Systems that want to adopt this approach need to transition away from the model where signers are identified by their address to a new model where signers may not have an address, and are identified by abytesobject.This definition is backward compatible with EOA and TRC-1271 contracts: in that case, we use the address of the identity (EOA or contract) as the verifier and the key is empty.
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Nomenclature
bytesobjects of arbitrary length. For example a P256 or RSA public key. Keys MUST NOT be empty.Signature Verifier interface
Verifiers MUST implement the following interface:
Verifiers SHOULD be stateless.
The magic value
0x024ad318is the selector ofverify(bytes,bytes32,bytes)and is therefore unchanged from the original standard, allowing a verifier written for another chain to be reused on TVM without modification. A natural TRON verifier for secp256r1/passkey keys wraps the TIP-7951 precompile, which verifies a P-256 signature against an explicit public key (key= the 64-byte uncompressed point,signature=r || s) and, unlikeecrecover, does not recover an address — exactly the shape this interface expects. A WebAuthn/passkey verifier additionally parsesauthenticatorDataandclientDataJSONbefore delegating to that primitive.Rationale
Verifiers can be used to avoid deploying many TRC-1271 "identity contracts" (one per key), which would be expensive. Using this model, new keys can be used without any deployment costs.
TRC-1271 already covers the cases where a key is not necessary. To avoid ambiguity, the verifier contracts should not support (or be expected to support) empty keys. Signers that are 20 bytes long (empty key) should be handled using TRC-1271.
Consistency with existing systems (
ecrecoverand TRC-1271) requires the message to be abytes32hash. On TRON this is usually produced following TIP-712. Cryptographic systems that use different hashing methods SHOULD see this hash as a message, and possibly rehash it following the relevant standards. Wallets producing thehashfor a verifier flow MUST NOT wrap it with a TRON personal-message prefix, which would break verification.Backwards Compatibility
A system can support TRC-7913 signers alongside EOAs and TRC-1271 in the following way.
A signer is a
bytesobject that is the concatenation of an address and optionally a key:verifier || key. A signer is at least 20 bytes long. The 20-byteverifieris the ABI-level TRON address (the account body with the0x41prefix stripped, consistent with TIP-712 and TIP-2612); wallets may display it as Base58Check.Given a signer
signer, a message hashhash, and a signaturesign, verification is done as follows:signer.length < 20: verification fails;signerinto(verifier, key)withverifierbeing the first 20 bytes andkeybeing the rest (potentially empty);keyis empty, then consider thatverifieris the identity.isValidSignatureif there is code atverifieraddress, orecrecoverotherwise;keyis not empty, callITRC7913SignatureVerifier(verifier).verify(key, hash, signature)0x024ad318) then verification is successful,Note that TRON's protocol-level weighted-multisignature permission system (TIP-16, TIP-105) is not visible to TVM code and is a separate layer: native permissions gate transaction signing, whereas TRC-7913 governs in-contract signature checks.
Reference Implementation
In Solidity, signature verification could be implemented in the following library:
Security Considerations
Signers may be used for anything from a smart-account session key (with a short lifetime of a few hours/days) to social-recovery "guardians" that may only be used several years after they are set up. In order to ensure that these signers remain valid "in perpetuity", the verifier contract should be trustless. This means that the verifiers should not be upgradeable contracts.
Verifiers should also not depend on any value that can be modified after deployment. In Solidity terms, the
verifyfunction should be pure. Any parameters that are involved in signature verification should either be part of the key, or part of the immutable code of the verifier. Using animmutablevariable (in Solidity) would be safe. The stateless aspect of the verifier also keeps it compatible with the validation-scope rules that a future TRON account-abstraction alt-mempool would impose during the validation phase.For the empty-key fallback path, the usual
ecrecoveredge cases apply: a malformed signature returnsaddress(0), so anaddress(0)result MUST be treated as failure, ands/vnormalization (low-s,v ∈ {27, 28}) SHOULD be enforced as in TRC-1271 and TIP-2612.Copyright
Copyright and related rights waived via CC0.