Signature validation
How TRON validates transaction signatures using ECDSA over secp256k1, and how multi-signature accounts use weight thresholds.
Every transaction on TRON includes one or more signatures. Validating a signature confirms that the transaction was authorized by the holder of the private key (or, for accounts with active permissions, by enough authorized parties). The verification logic is:
- Recompute
SHA-256(raw_data)— the message hash - Recover the public key from the signature using ECDSA over secp256k1
- Derive the address from the public key
- Check that the derived address has the right permission and weight to authorize this transaction
This page walks through each step and shows how multi-signature accounts aggregate signature weights against a configured threshold.
Prerequisites
The signed message
The message that gets signed is SHA-256(raw_data). The raw_data field contains the contract body, TAPOS reference, expiration, fee_limit, and timestamp — see Transactions for the full layout.
This means a signature commits to all the data in raw_data but not to the signatures themselves (so multi-sig signatures can be added one at a time without invalidating each other).
ECDSA verification
TRON uses ECDSA over the secp256k1 curve — the same scheme as Bitcoin and Ethereum. The canonical signature is 65 bytes in r || s || v order:
| Bytes | Content |
|---|---|
| 0–31 | r value (32 bytes) |
| 32–63 | s value (32 bytes) |
| 64 | recovery byte v (1 byte, value 0 or 1) |
In GreatVoyage-v4.8.2, broadcast APIs and P2P admission accept signatures from 65 through 68 bytes for compatibility with historical data carrying trailing bytes. Before validation, wallet/getsignweight and wallet/getapprovedlist truncate signatures longer than 65 bytes to their first 65 bytes. Newly constructed transactions should still use the canonical 65-byte form and must not rely on compatibility padding.
Wire byte order isr || s || vThe recovery byte comes last. Some Ethereum tooling expresses signatures as
v || r || s(withv + 27as the leading byte); when porting code, convert tor || s || vbefore writing intotransaction.signature[]. Reversing the order produces an invalid signature that recovers the wrong address.
Verification uses the recoverable form: given the message hash and the signature, the verifier recovers the public key directly, derives the corresponding address, and compares against the expected signer.
Signature recovery byteThe recovery byte
vlets the verifier recover the public key from the signature alone — no need for the public key to be transmitted alongside the transaction. This saves bytes and makes signature aggregation cheaper.
Single-signature validation
For an account with default permissions (a regular EOA), the validator:
- Recovers the address from the single signature in the transaction
- Confirms the recovered address matches the
owner_addressinraw_data.contract
If they match, the signature is valid and the transaction proceeds. If they don't, the transaction is rejected.
Multi-signature validation
An account whose Permission has been configured for multi-party control requires multiple signatures. The validator:
- Recovers an address from each signature
- Looks up each address in the relevant permission's
keyslist - Sums the weights
- Compares the sum to the permission's
threshold
The transaction is authorized when the sum of recovered weights is ≥ threshold.
Multi-sig validation is strict.Any of the following conditions rejects the entire transaction with
PermissionException:
- Too many signatures —
signature[]size exceeds the permission'skeyscount- Unknown signer — a signature recovers to an address that is not in the permission's
keyslist (it does not contribute zero weight — it rejects the transaction outright)- Duplicate signer — the same address appears twice in
signature[]All three conditions abort validation before the threshold check runs.
Worked example
A 2-of-3 owner permission on an account:
threshold = 2
keys:
- address: TKey1...AA, weight: 1
- address: TKey2...BB, weight: 1
- address: TKey3...CC, weight: 1- Signed by Key1 + Key3 (sum = 2 ≥ threshold) → authorized
- Signed by Key1 alone (sum = 1 < threshold) → rejected with insufficient weight
- Signed by Key1 + an unknown key → rejected with
PermissionExceptionbecause the unknown signature is not in the keys list (not because the sum is too low) - Signed by Key1 + Key1 (duplicate) → rejected with "has signed twice"
- Four signatures sent for a 3-key permission → rejected with "Signature count is N more than key counts of permission"
For weighted permissions where one party has more authority:
threshold = 3
keys:
- address: TFounder...A, weight: 2
- address: TCofnd1...B, weight: 1
- address: TCofnd2...C, weight: 1A transaction needs the founder plus at least one cofounder (2 + 1 = 3) — or both cofounders working together with the founder absent (1 + 1 = 2, which fails). For setup details, see Account Permission Management.
Permission selection
Each transaction declares which permission level it is signed under via Permission_id in raw_data.contract:
| Permission_id | Permission |
|---|---|
| 0 | Owner permission (default if omitted) |
| 1 | Witness permission — reserved for Super Representative block production; cannot authorize normal contract transactions |
| 2–9 | Active permissions (up to 8 per account, per-operation roles) |
The validator looks up the permission by ID, then runs the multi-signature check above. Each permission has its own threshold and keys list. For any Permission_id != 0, the permission's type field must equal Active — supplying Permission_id = 1 (Witness) on a normal contract call rejects the transaction with "Permission type is wrong!". Active permissions additionally carry an operations bitmap restricting which contract types they may execute; a contract type not authorized by the bitmap is rejected with "Permission denied!".
Cancelling a transaction
TRON has no native transaction cancellation or replacement mechanism. A higher fee or another transaction with the same TAPOS reference cannot supersede the original transaction. For a multi-signature transaction that has not been broadcast and remains under the signers' control, stop collecting or distributing signatures and let it expire. Once a signed transaction has been shared externally or broadcast, it cannot be revoked; monitor the original txID until it is included or expires. The default validity period is about 60 seconds and can be set up to approximately 24 hours from the chain head.
APIs
| API | Description |
|---|---|
wallet/getsignweight | Inspect signature weight on a partially-signed transaction |
wallet/getapprovedlist | List addresses that have signed |
wallet/broadcasttransaction | Submit a fully-signed transaction |
Related resources
- Account Permission Management — Configure permissions and thresholds
- Transactions — Transaction structure
- Account Permission Management transaction example — Full multi-sig transaction walkthrough
Updated about 14 hours ago