tip: 899
title: Post-Quantum Signature Support
author: federico.zhen@tron.network
discussions-to: https://github.com/tronprotocol/tips/issues/899
status: Draft
type: Standards Track
category: Core
created: 2026-06-30
Simple Summary
Introduce post-quantum (PQ) digital signature support at the TRON protocol layer. The initial activation enables two lattice-based signature algorithms — Falcon-512 (FN_DSA_512) and Dilithium2 (ML_DSA_44) — covering all four signature scenarios: transactions, SR block production, node relay handshakes, and TVM. Each algorithm is gated by an independent on-chain governance proposal and is disabled by default. The account address format and Account structure remain unchanged, so the existing ecosystem is entirely unaffected before PQ activation.
Abstract
ECDSA (secp256k1) derives its security from the elliptic-curve discrete-logarithm problem, which can be broken by a quantum computer running Shor's algorithm in minutes. Falcon-512 (FIPS 206 draft) and ML-DSA-44 (FIPS 204, finalized) are instead built on lattice-based hard problems (NTRU / Module-LWE) — Shor's algorithm does not apply to these problems, and no known quantum algorithm can solve them efficiently, making them resistant to quantum attacks.
This TIP introduces an algorithm-agnostic PQAuthSig field (containing scheme / public_key / signature) at the TRON protocol layer and adds it to Transaction, BlockHeader, and HelloMessage payloads. Verification dispatches based on which signature field is set, with both paths converging into the same Permission weight-checking flow, so a single transaction may carry a mix of ECDSA, Falcon, and ML-DSA signers. PQ addresses use the same derivation rule as ECDSA, producing the standard 21-byte T-prefixed address. Algorithm activation is separately gated by two on-chain proposals: ALLOW_FN_DSA_512 / ALLOW_ML_DSA_44. Five new TVM precompiled contracts enable contract-side verification.
In Phase 1, public keys are carried in every transaction; Phase 2[draft] introduces a standalone database for one-time public key storage to reduce bandwidth and storage.
Motivation
TRON and many major blockchain account or transaction layers still rely on non-PQ signatures such as ECDSA, Schnorr, or BLS. Major infrastructure providers have started targeting PQC migration by 2029, reflecting a shrinking preparation window. Bitcoin alone has over 6.9 million BTC (roughly one third of the total supply) sitting in addresses with exposed public keys.
Cryptographic migration is inherently extremely complex: protocol changes, third-party security audits, and adaptation across wallets, exchanges, and contract ecosystems typically take a long time. Waiting until the quantum threat actually arrives would be too late — work must begin now.
Shortcomings of the status quo:
- All TRON transactions and blocks currently use
secp256k1 ECDSA, with address derivation 0x41 ‖ Keccak-256(ecdsa_pk[1:])[12..32]. The protocol layer carries no PQ signature fields.
- The TVM precompiles
ValidateMultiSign, BatchValidateSign, and ECRecover all depend on ECDSA and cannot be reused directly for PQ signatures, which require an explicit public key as an input parameter.
Two core differences between PQ algorithms and ECDSA (which drive the protocol design):
- Significantly larger sizes: compared to ECDSA's 33 B public key / 65 B signature, PQ public keys grow to ~900–2000 B and signatures to ~750–3300 B.
- Verification requires an explicit public key: ECDSA's
ECRecover can recover the public key from the signature and hash alone, so the chain only needs to store a 21-byte address. Falcon, ML-DSA, SLH-DSA, and other PQ algorithms have no equivalent recover primitive in standard mode — a node must have the full public key before it can verify. This is the primary problem this round of protocol changes must solve.
Specification
1. PQ Signature Structure
message PQAuthSig {
PQScheme scheme = 1; // required; UNKNOWN_PQ_SCHEME (proto3 default) is rejected at verification
bytes public_key = 2;
bytes signature = 3;
}
enum PQScheme {
UNKNOWN_PQ_SCHEME = 0; // proto3 default; never registered, rejected at verification
FN_DSA_512 = 1; // Falcon-512 (FIPS 206 draft)
ML_DSA_44 = 2; // ML-DSA-44 (FIPS 204, finalized)
// Values 3..15 are unassigned; new schemes require a TIP + governance proposal
}
message Transaction {
...
repeated bytes signature = 2;
...
repeated PQAuthSig pq_auth_sig = 6; // new field
}
PQ signatures and public keys are lattice-cryptography outputs, statistically close to uniform random, and are not compressible.
Per-scheme public-key / signature length constraints (strictly enforced at verification; out-of-bounds is rejected):
| Scheme |
public_key |
signature |
FN_DSA_512 |
fixed 896 B |
variable, 617–667 B (includes 1-byte 0x39 header) |
ML_DSA_44 |
fixed 1312 B |
fixed 2420 B |
FN-DSA-512 signature length variability is an inherent property of Falcon's compressed encoding; the implementation forcibly converges the upper bound to 667 B (rather than the Falcon spec's theoretical 752 B) to obtain stable on-chain and precompile layouts. In the TVM precompiles, signatures are carried in the headerless 666-byte EIP-8052 slot (salt ‖ s2_compressed, without the 0x39 header), zero-padded (see §5).
2. Four PQ Signature Channels
| Channel |
Field |
Relationship with ECDSA |
| Transaction |
repeated Transaction.pq_auth_sig = 6 |
Can coexist; a multi-sig account can be authorized by a mix of ECDSA + Falcon + ML-DSA signers, with cumulative weight ≥ threshold accepted |
| SR block production |
BlockHeader.pq_auth_sig = 3 |
Mutually exclusive with witness_signature — at most one may be set per block. The SR enables PQ block production by delegating witness permission to a PQ account while keeping the SR address unchanged |
| Relay handshake |
HelloMessage.pq_auth_sig = 12 (set/verified by RelayService) |
Mutually exclusive with HelloMessage.signature — depends on whether the local node is configured with an ECDSA or PQ key |
| TVM signature verification |
New precompiles (see §5) |
Public key must be provided as an input parameter; coexists with ValidateMultiSign, BatchValidateSign, ECRecover |
3. PQ Address Derivation
pq_address = 0x41 ‖ Keccak-256(pq_public_key)[12..32]
PQ address derivation follows the same shape as ECDSA — the rightmost 20 bytes of Keccak-256(public_key), prefixed with 0x41. Addresses remain 21 bytes with a T prefix; all supported signature schemes intentionally share the same 160-bit TRON address space, and cross-scheme address collisions remain cryptographically negligible. The two PQ schemes have different public key lengths (896 vs 1312), and PQSchemeRegistry performs a length check at verification entry to reject malformed or cross-scheme public-key inputs.
4. Signature Targets
- Transaction signature target:
txid = SHA-256(Transaction.raw)
- Block signature target:
blockHash = SHA-256(BlockHeader.raw)
- Relay identity signature target:
SHA-256(BigEndian(timestamp))
5. TVM Precompiles
Precompile addresses reside in the 0x02000016–0x0200001a range (relocated from earlier draft addresses in the implementation to avoid conflicts with existing precompiles). Energy costs were calibrated against the existing ECRecover and ValidateMultiSign (1500 / sig) baselines:
| Address |
Name |
Algorithm |
Energy |
Notes |
0x02000016 |
VerifyFnDsa512 |
Falcon-512 |
3000 (fixed) |
Single verify, EIP-8052 input layout |
0x02000017 |
BatchValidateFnDsa512 |
Falcon-512 |
cnt × 2400 (MAX_SIZE = 16) |
Batch independent verify, 256-bit bitmap output |
0x02000018 |
VerifyMlDsa44 |
ML-DSA-44 |
3000 (fixed) |
Single verify, FIPS 1312 B public key |
0x02000019 |
BatchValidateMlDsa44 |
ML-DSA-44 |
cnt × 2400 (MAX_SIZE = 16) |
Batch independent verify, bitmap output; same ABI as 0x02000017 |
0x0200001a |
ValidateMultiPQSig |
ECDSA + any registered PQ scheme |
ecdsaCnt × 1500 + Σ pqEnergy (FN-DSA-512 = 2400, ML-DSA-44 = 2400; MAX_SIZE = 5) |
Algorithm-agnostic Permission multi-sig; dispatches per entry by explicit scheme tag |
Falcon-512 input layout: the input to VerifyFnDsa512 is [msg 32 B | sig 666 B (zero-padded) | pk 896 B], total length 1594 B. The 666-byte signature slot carries the EIP-8052 headerless encoding (salt ‖ s2_compressed, without the 0x39 header byte). The actual signature body is variable (≤ 665 B after removing the header); encoders write it into the slot prefix and zero-pad the tail to 666 B. The verifier recovers the actual length by scanning backwards for the first non-zero byte (Falcon's compressed_s2 unary coding guarantees that the last meaningful byte is never 0x00), rebuilds the headed signature, and passes it to BouncyCastle for verification. The batch and multi-sig precompiles (0x02000017 / 0x0200001a) use the same 666-byte slot convention. ML-DSA-44 signatures are fixed at 2420 B and public keys at 1312 B, requiring no such padding handling.
Energy calculation details:
- Single verify (
0x02000016 / 0x02000018): fixed 3000, independent of input.
- Batch verify (
0x02000017 / 0x02000019): linearly charged cnt × 2400 per signature; a single call processes at most MAX_SIZE = 16 entries; excess entries are neither processed nor charged. Malformed input (parse exception) is charged MAX_SIZE × 2400 as a backstop.
- Algorithm-agnostic multi-sig (
0x0200001a): ECDSA entries 1500 / sig, PQ entries charged at their respective per-scheme rates (currently 2400 / sig for both FN-DSA-512 and ML-DSA-44); ECDSA + PQ entries combined have an upper limit of MAX_SIZE = 5; excess entries are neither processed nor charged. Out-of-bounds or malformed input is charged MAX_SIZE × max(1500, 2400) as a backstop.
Gating: 0x02000016 / 0x02000017 are registered when VMConfig.allowFnDsa512() is true; 0x02000018 / 0x02000019 when allowMlDsa44() is true; the algorithm-agnostic 0x0200001a is registered when either allowFnDsa512() || allowMlDsa44() is true (entries for an inactive scheme are rejected at execution time as not registered).
6. Governance Activation
| Proposal |
Code |
Scope |
ALLOW_FN_DSA_512 |
1000 |
All Falcon-512 signature channels (Tx / Block / HelloMessage) + Falcon precompiles (0x02000016 / 0x02000017) |
ALLOW_ML_DSA_44 |
1001 |
All ML-DSA-44 signature channels (Tx / Block / HelloMessage) + ML-DSA precompiles (0x02000018 / 0x02000019) |
Both proposals are gated on version flag VERSION_4_8_2_PQ1 (fork version 37), accept only 0 or 1 as values, and reject duplicate proposals for the same value. The proposals are reversible. The algorithm-agnostic multi-sig precompile 0x0200001a ValidateMultiPQSig is enabled when either proposal is activated.
7. Public Key Storage (Two Phases)
-
Phase 1: Transactions carry the signature and full public key.
-
Phase 2 [draft]: A new pq_pubkey database (key = PQ-public-key-derived address, value = proto carrying the public key) enables one-time public key storage without affecting consensus:
- A user's first PQ transaction must include the full public key in
pq_auth_sig[x].public_key; subsequent transactions need only supply the address.
- When an SR packs, or a FullNode broadcasts or executes, a transaction: if the field is a full public key (length far greater than 21 B), verify normally and, on success, write
address → public_key into pq_pubkey; if it is an address (21 B), look up the corresponding public key from pq_pubkey before verification — verification fails if the public key is not present.
8. PQ Witness Key Configuration
PQ witness signing is enabled through the localPqWitness configuration section in config.conf — effective only after the corresponding scheme's activation proposal passes and the witness Permission has been upgraded. ECDSA and PQ witnesses use separate, independent account-address keys (localWitnessAccountAddress vs localPqWitness.accountAddress); the two consensus paths do not interfere and can coexist on the same node.
Each entry in keys is a JSON key file path; the file specifies a scheme and exactly one key-material source:
seed — FN_DSA_512: 96 hex chars (48 bytes); ML_DSA_44: 64 hex chars (32 bytes). FN_DSA_512 (Falcon) key generation is FFT-based and not bit-stable across JVMs or CPU architectures — the same seed may derive different keypairs (i.e., different addresses). For production FN_DSA_512 witnesses, use privateKey + publicKey instead. ML-DSA-44 key generation is pure integer arithmetic and fully reproducible.
privateKey — hex-encoded private key. FN_DSA_512 must also provide publicKey (BouncyCastle cannot derive a public key from the private key). ML-DSA-44 can derive the public key from the private key, so publicKey must be omitted.
localPqWitness = {
# accountAddress = "<PQ witness account address>"
keys = [
# "keys/pq_witness1.json"
]
}
JSON key file examples (hex lengths correspond to each scheme: FN_DSA_512 private key 1280 B / public key 896 B; ML-DSA_44 private key 2560 B):
FN_DSA_512 (privateKey): { "scheme": "FN_DSA_512", "privateKey": "<2560 hex>", "publicKey": "<1792 hex>" }
ML_DSA_44 (privateKey): { "scheme": "ML_DSA_44", "privateKey": "<5120 hex>" }
FN_DSA_512 (seed): { "scheme": "FN_DSA_512", "seed": "<96 hex>" }
ML_DSA_44 (seed): { "scheme": "ML_DSA_44", "seed": "<64 hex>" }
9. PQ Transaction Count Limits
To prevent PQ transaction size inflation from impacting mempool and block throughput, the implementation imposes two independent numeric caps:
- Pending pool:
node.pqTransInPendingMaxCounts (config.conf configurable, default 1000) limits the concurrent number of PQ-authenticated transactions in the pending pool; PQ transactions exceeding the limit are rejected at pushTransaction entry (ECDSA transactions are unaffected).
- Per block:
Manager.PQ_TRANS_IN_BLOCK_COUNTS (hard-coded constant, 1000) limits the number of PQ transactions a single block can pack; the SR block-production loop skips subsequent PQ transactions once the packed PQ transaction count reaches this limit (continues packing ECDSA transactions), constraining PQ throughput together with the block byte-size limit.
10. Key Code Changes by Module
| Module |
Changes |
| Protocol |
New PQScheme enum (FN_DSA_512, ML_DSA_44) and PQAuthSig message; Transaction.pq_auth_sig=6, BlockHeader.pq_auth_sig=3, HelloMessage.pq_auth_sig=12; api.proto adds pq_scheme field for bandwidth estimation |
| Crypto |
New crypto/pqc package wrapping BC's FNDSA512 / MLDSA44 (FN-DSA-512 signature length constrained to 617–667 B, over-size resampling capped at 16 retries); PQSchemeRegistry central management of per-scheme seedLength/signLength/pkLength/deriveHash/verify/computeAddress metadata; includes amd64 / aarch64 native libraries |
| Actuator |
AccountPermissionUpdateActuator accepts PQ-derived addresses as Key entries; TransactionUtil accounts for pq_auth_sig weight; new PQPrecompiledContracts (5 precompiles) registered in PrecompiledContracts |
| Framework |
TransactionCapsule / BlockCapsule PQ verification paths run in parallel with ECDSA; getTotalSignatureCount() unifies ECDSA + PQ counts; Manager enforces two PQ transaction count caps — pending pool (pqTransInPendingMaxCounts) and per-block (PQ_TRANS_IN_BLOCK_COUNTS); JSON-RPC TransactionResult.pqAuthSigList exposes the field; getCanDelegatedMaxSize accounts for PQ size |
| Consensus |
SR block-production path dispatches signing/verification based on which BlockHeader field is set; WitnessInitializer initializes PQ witness keypairs from localPqWitness config using privateKey (or seed) — FN_DSA_512 seed derivation carries cross-platform floating-point drift risk; production environments should use privateKey + publicKey |
| Net |
HelloMessage adds pq_auth_sig with length caps and rejects smuggled unknown nested fields; RelayService signs handshake with the local key, verification performs strict checks (scheme registered + on-chain activated + pubkey/signature length match + derived address binds witness); TransactionsMsgHandler enforces uniform length caps and count limits at ingress |
| VM |
Five new precompiles at 0x02000016–0x0200001a, gated by VMConfig.allowFnDsa512() / allowMlDsa44() |
| Governance |
New ALLOW_FN_DSA_512 (1000) / ALLOW_ML_DSA_44 (1001) proposals, gated on VERSION_4_8_2_PQ1; ProposalUtil strictly rejects illegal values and duplicate settings before activation |
| Config |
config.conf / reference.conf add localPqWitness configuration section and pqTransInPendingMaxCounts field (HOCON structure) |
Rationale
Why "public key in transaction" (Option B) over "public key on chain" (Option A)
PQ verification requires an explicit public key; the design choice reduces to where to store the public key:
- Option A (public key on chain, transaction only references it): transaction size would still inflate ≥ 5× because the Falcon signature alone is roughly 11× an ECDSA signature. Additional costs — passively activated accounts would have no public key record, account state would significantly bloat, wallets could not sign without reading live on-chain data, and the protocol layer itself would require substantial new design — on-chain key-storage layout, transaction referencing mechanism, key rotation semantics, etc. — none of which have validated, mature precedent on any mainstream chain today, implying significant stability risk.
- Option B (public key in every transaction): minimal protocol intrusion (account state fields unchanged), zero friction for passively activated accounts, wallets/SDKs can sign statelessly. The only downside is roughly 10× transaction size growth (a cost that can be optimized over time).
We choose Option B after weighing three dimensions: minimal intrusion into the existing protocol, lowest v1 implementation cost, and smallest ecosystem-side change. Option A's architectural problems (passive activation, Account structure breakage) would be nearly irreversible once deployed, whereas Option B's size cost is reversible and can be mitigated via Falcon key-recovery, signature aggregation, and subsequent Phase 2 optimizations. This trade-off remains a tracked open question (Open Questions §5) to be further validated before mainnet.
Why implement ML-DSA-44 in parallel rather than only Falcon-512
Falcon-512 has the most compact size footprint (~9.5× ECDSA) and is the preferred choice; however, FN-DSA / Falcon-512 is still at the FIPS 206 draft stage — the spec may still change during the review cycle, the implementation would face a moving-target audit, leaving material audit risk. To hedge this risk, ML-DSA-44, finalized as FIPS 204 in August 2024, is implemented in parallel as a natural fallback rather than a paper option. The protocol design makes the two schemes nearly interchangeable: they share the same PQAuthSig wire format (differing only in the scheme enum value), PQSchemeRegistry provides a pluggable dispatch table, and each has an independent governance proposal. The cost is that ML-DSA-44 has a larger per-transaction footprint (~22× ECDSA, ~2.3× Falcon).
Size Comparison of PQ Candidate Algorithms
| Algorithm |
Public Key |
Signature |
secp256k1 ECDSA |
33 B (compressed) |
65 B |
Falcon-512 |
896 B |
617–667 B (variable, headed; implementation cap 667 B, spec theoretical cap 752 B) |
ML-DSA-44 |
1312 B |
2420 B (fixed) |
SLH-DSA-128s |
32 B |
7856 B |
SLH-DSA is out of scope this cycle due to excessive signature size.
Performance Data (500-run average)
| Metric |
ECDSA |
Falcon-512 |
ML-DSA-44 |
| Verify time |
962 μs |
91 μs (~10.5× faster) |
165 μs (~5.8× faster) |
| Sign time |
2378 μs |
590 μs |
628 μs |
| Keygen time |
241 μs |
10180 μs (one-time, off hot path) |
159 μs |
| Avg TRX transfer size |
175 B |
~1668 B (~9.5×) |
~3851 B (~22×) |
Both PQ schemes improve signature-verification CPU on the consensus hot path; the bottleneck is transaction size, not verification cost. TPS ceiling varies with the blended average transaction size:
| PQ adoption ratio |
Blended avg TRX transfer size |
TRX TPS ceiling |
| 0% PQ (pure ECDSA, current) |
175 B |
~3809 (baseline) |
| 10% Falcon + 90% ECDSA |
~324 B |
~2055 (~54% of baseline) |
| 10% ML-DSA + 90% ECDSA |
~543 B |
~1228 (~32% of baseline) |
| 100% Falcon (worst case) |
~1668 B |
~400 (~10.5% of baseline) |
| 100% ML-DSA (worst case) |
~3851 B |
~173 (~4.5% of baseline) |
In the early transition phase, PQ adoption will be limited, keeping the size increase manageable. Falcon-512 (FIPS 206 draft) serves as the default size-efficient choice, while ML-DSA-44 serves as the FIPS 204 finalized fallback for specialized multi-sig use cases. We will continue to optimize in the future, with potential directions including Falcon key-recovery for footprint reduction, signature aggregation to enhance throughput, and broader protocol-level design improvements.
Precompile Energy Pricing
The new precompiles do not reuse the ECDSA precompile interfaces (0x09 / 0x0A) because the PQ verify(pk, msg, sig) → bool interface cannot recover a public key — the caller must explicitly provide the full public key. Energy values are calibrated against ValidateMultiSign's 1500 / sig anchor: single PQ verification is set at 3000; batch and multi-sig charges scale linearly per entry (PQ entries 2400 / sig, ECDSA entries 1500 / sig), with caps on each precompile (batch MAX_SIZE = 16, multi-sig MAX_SIZE = 5), and malformed input is charged at the backstop cap to prevent underpayment attacks. These prices are initial calibration values and require further validation and adjustment under real load.
Backwards Compatibility
This TIP has no breaking changes:
- Before any PQ proposal is activated, node behavior is completely identical to the current mainnet.
- Disabled by default; activation requires a 27-SR on-chain proposal vote to pass (one per scheme).
Account, Permission, and other existing structure and state fields are entirely unchanged.
- JSON-RPC / HTTP API adds
pq_auth_sig fields to transaction, block, and HelloMessage JSON; the old format is unaffected.
- The PBFT module does not introduce PQ signatures at this stage, to minimize the impact surface.
After activation, each scheme can be disabled via a reverse governance proposal under the standard 27-SR maintenance-cycle timeline (disabling a proposal may cause SRs that had adopted PQ signing to miss blocks).
Test Cases
Test scenarios that should be covered for this change (the reference implementation includes corresponding unit and integration tests):
- Sign/verify correctness: cover Falcon-512 and ML-DSA-44 signing, verification, and key generation, including KAT (Known Answer Test) vectors and performance benchmarks; FN-DSA-512 must cover signature-length boundaries (617 / 667 B) and over-size resampling.
- Precompiles: address registration, energy charging, bitmap output, and strict input validation for all five precompiles (including backstop charging for malformed input, and Falcon 666-byte slot zero-padding with length recovery).
- Mixed multi-sig: a single transaction carrying ECDSA + Falcon + ML-DSA signers, with weight accumulation vs.
threshold comparison logic.
- Strict scheme validation:
UNKNOWN_PQ_SCHEME and illegal scheme values are rejected at verification.
- Gating behavior: PQ signatures are rejected before proposal activation, accepted after activation; behavior reverts after a reverse-proposal disables the scheme.
- Count caps: pending-pool and per-block PQ transaction count caps correctly reject/skip PQ transactions respectively upon triggering, while leaving ECDSA transactions unaffected.
- Consensus consistency: the verification cache must compare both ECDSA and
pq_auth_sig to prevent a forged PQ signature sharing the same txid from inheriting an already-verified flag and causing a fork; SR block-production PQ dispatch.
- Ingress hardening:
HelloMessage and transaction ingress (RPC broadcast + P2P) enforce pq_auth_sig length caps, reject smuggled unknown nested fields, and apply uniform count limits.
- Stress-test scenarios (mandatory for consensus changes): evaluate SR miss-block rate, block-generation latency, and byte-throughput bottleneck under varying PQ adoption ratios, confirming the bottleneck is block byte size, not verification CPU. See Open Questions §1 for the detailed stress-test scope.
Implementation
The reference implementation is PR tron-nile-testnet/nile-testnet#59 (based on the v4.8.2 line, hard fork version VERSION_4_8_2_PQ1), covering all module changes described above under Protocol / Crypto / Actuator / Framework / Consensus / Net / VM / Governance / Config. The accompanying Toolkit provides a pq-key new command to generate PQ key files (with --seed support):
java -jar build/libs/Toolkit.jar pq-key new --scheme=ML_DSA_44
This reference implementation is currently deployed on Nile Testnet for testing, to validate PQ signature channels, block-production/sync, and precompile behavior in a real network environment.
Security readiness work before mainnet activation: an external cryptographic and implementation audit, publication of an audit summary (at a minimum before the SR vote), and bug-bounty coverage for crypto/pqc, PQSchemeRegistry, and the new precompiles.
Open Questions
- Fee model and user cost — precompile energy has been initially calibrated against ECDSA pricing; still needs typical-scenario extra-cost estimates, logical discount opportunities, and cross-chain pricing references.
- Smart-contract-layer PQ migration — inventory of major contracts using
ECRecover; design a progressive adoption path and "dual-signature compatible" transition model.
- Wallet / hardware wallet / SDK adoption path — BIP-39/32 derivation extension, hardware wallet RAM constraints, unified SDK APIs and capability detection.
- PQ public key storage: Option B (in-transaction) vs. Option A (on-chain) — validate the crossover point, account state growth, DB access claims, and key rotation semantics.
Future Phases (out of scope this cycle)
- SR emergency proposal channel: 6-hour voting window, 22/27 threshold, immediate effect.
FORBID_ECDSA_SIGN proposal: the entire network accepts only PQ signatures, instantly severing the quantum attack surface.
- ZK proofs for asset recovery: introduce
RecoverAccountByZkContract, relying on post-quantum SNARKs (Plonky2 / STARK).
References
Copyright
Copyright and related rights waived via CC0.
Simple Summary
Introduce post-quantum (PQ) digital signature support at the TRON protocol layer. The initial activation enables two lattice-based signature algorithms — Falcon-512 (
FN_DSA_512) and Dilithium2 (ML_DSA_44) — covering all four signature scenarios: transactions, SR block production, node relay handshakes, and TVM. Each algorithm is gated by an independent on-chain governance proposal and is disabled by default. The account address format andAccountstructure remain unchanged, so the existing ecosystem is entirely unaffected before PQ activation.Abstract
ECDSA (
secp256k1) derives its security from the elliptic-curve discrete-logarithm problem, which can be broken by a quantum computer running Shor's algorithm in minutes. Falcon-512 (FIPS 206 draft) and ML-DSA-44 (FIPS 204, finalized) are instead built on lattice-based hard problems (NTRU / Module-LWE) — Shor's algorithm does not apply to these problems, and no known quantum algorithm can solve them efficiently, making them resistant to quantum attacks.This TIP introduces an algorithm-agnostic
PQAuthSigfield (containingscheme/public_key/signature) at the TRON protocol layer and adds it toTransaction,BlockHeader, andHelloMessagepayloads. Verification dispatches based on which signature field is set, with both paths converging into the samePermissionweight-checking flow, so a single transaction may carry a mix of ECDSA, Falcon, and ML-DSA signers. PQ addresses use the same derivation rule as ECDSA, producing the standard 21-byteT-prefixed address. Algorithm activation is separately gated by two on-chain proposals:ALLOW_FN_DSA_512/ALLOW_ML_DSA_44. Five new TVM precompiled contracts enable contract-side verification.In Phase 1, public keys are carried in every transaction; Phase 2[draft] introduces a standalone database for one-time public key storage to reduce bandwidth and storage.
Motivation
TRON and many major blockchain account or transaction layers still rely on non-PQ signatures such as ECDSA, Schnorr, or BLS. Major infrastructure providers have started targeting PQC migration by 2029, reflecting a shrinking preparation window. Bitcoin alone has over 6.9 million BTC (roughly one third of the total supply) sitting in addresses with exposed public keys.
Cryptographic migration is inherently extremely complex: protocol changes, third-party security audits, and adaptation across wallets, exchanges, and contract ecosystems typically take a long time. Waiting until the quantum threat actually arrives would be too late — work must begin now.
Shortcomings of the status quo:
secp256k1ECDSA, with address derivation0x41 ‖ Keccak-256(ecdsa_pk[1:])[12..32]. The protocol layer carries no PQ signature fields.ValidateMultiSign,BatchValidateSign, andECRecoverall depend on ECDSA and cannot be reused directly for PQ signatures, which require an explicit public key as an input parameter.Two core differences between PQ algorithms and ECDSA (which drive the protocol design):
ECRecovercan recover the public key from the signature and hash alone, so the chain only needs to store a 21-byte address. Falcon, ML-DSA, SLH-DSA, and other PQ algorithms have no equivalent recover primitive in standard mode — a node must have the full public key before it can verify. This is the primary problem this round of protocol changes must solve.Specification
1. PQ Signature Structure
PQ signatures and public keys are lattice-cryptography outputs, statistically close to uniform random, and are not compressible.
Per-scheme public-key / signature length constraints (strictly enforced at verification; out-of-bounds is rejected):
public_keysignatureFN_DSA_5120x39header)ML_DSA_44FN-DSA-512 signature length variability is an inherent property of Falcon's
compressedencoding; the implementation forcibly converges the upper bound to 667 B (rather than the Falcon spec's theoretical 752 B) to obtain stable on-chain and precompile layouts. In the TVM precompiles, signatures are carried in the headerless 666-byte EIP-8052 slot (salt ‖ s2_compressed, without the0x39header), zero-padded (see §5).2. Four PQ Signature Channels
repeated Transaction.pq_auth_sig = 6weight ≥ thresholdacceptedBlockHeader.pq_auth_sig = 3witness_signature— at most one may be set per block. The SR enables PQ block production by delegating witness permission to a PQ account while keeping the SR address unchangedHelloMessage.pq_auth_sig = 12(set/verified byRelayService)HelloMessage.signature— depends on whether the local node is configured with an ECDSA or PQ keyValidateMultiSign,BatchValidateSign,ECRecover3. PQ Address Derivation
PQ address derivation follows the same shape as ECDSA — the rightmost 20 bytes of
Keccak-256(public_key), prefixed with0x41. Addresses remain 21 bytes with aTprefix; all supported signature schemes intentionally share the same 160-bit TRON address space, and cross-scheme address collisions remain cryptographically negligible. The two PQ schemes have different public key lengths (896 vs 1312), andPQSchemeRegistryperforms a length check at verification entry to reject malformed or cross-scheme public-key inputs.4. Signature Targets
txid = SHA-256(Transaction.raw)blockHash = SHA-256(BlockHeader.raw)SHA-256(BigEndian(timestamp))5. TVM Precompiles
Precompile addresses reside in the
0x02000016–0x0200001arange (relocated from earlier draft addresses in the implementation to avoid conflicts with existing precompiles). Energy costs were calibrated against the existingECRecoverandValidateMultiSign(1500 / sig) baselines:0x02000016VerifyFnDsa5123000(fixed)0x02000017BatchValidateFnDsa512cnt × 2400(MAX_SIZE = 16)0x02000018VerifyMlDsa443000(fixed)0x02000019BatchValidateMlDsa44cnt × 2400(MAX_SIZE = 16)0x020000170x0200001aValidateMultiPQSigecdsaCnt × 1500 + Σ pqEnergy(FN-DSA-512 = 2400, ML-DSA-44 = 2400;MAX_SIZE = 5)Permissionmulti-sig; dispatches per entry by explicitschemetagFalcon-512 input layout: the input to
VerifyFnDsa512is[msg 32 B | sig 666 B (zero-padded) | pk 896 B], total length 1594 B. The 666-byte signature slot carries the EIP-8052 headerless encoding (salt ‖ s2_compressed, without the0x39header byte). The actual signature body is variable (≤ 665 B after removing the header); encoders write it into the slot prefix and zero-pad the tail to 666 B. The verifier recovers the actual length by scanning backwards for the first non-zero byte (Falcon'scompressed_s2unary coding guarantees that the last meaningful byte is never0x00), rebuilds the headed signature, and passes it to BouncyCastle for verification. The batch and multi-sig precompiles (0x02000017/0x0200001a) use the same 666-byte slot convention. ML-DSA-44 signatures are fixed at 2420 B and public keys at 1312 B, requiring no such padding handling.Energy calculation details:
0x02000016/0x02000018): fixed3000, independent of input.0x02000017/0x02000019): linearly chargedcnt × 2400per signature; a single call processes at mostMAX_SIZE = 16entries; excess entries are neither processed nor charged. Malformed input (parse exception) is chargedMAX_SIZE × 2400as a backstop.0x0200001a): ECDSA entries1500 / sig, PQ entries charged at their respective per-scheme rates (currently 2400 / sig for both FN-DSA-512 and ML-DSA-44); ECDSA + PQ entries combined have an upper limit ofMAX_SIZE = 5; excess entries are neither processed nor charged. Out-of-bounds or malformed input is chargedMAX_SIZE × max(1500, 2400)as a backstop.Gating:
0x02000016/0x02000017are registered whenVMConfig.allowFnDsa512()is true;0x02000018/0x02000019whenallowMlDsa44()is true; the algorithm-agnostic0x0200001ais registered when eitherallowFnDsa512() || allowMlDsa44()is true (entries for an inactive scheme are rejected at execution time as not registered).
6. Governance Activation
ALLOW_FN_DSA_51210000x02000016/0x02000017)ALLOW_ML_DSA_4410010x02000018/0x02000019)Both proposals are gated on version flag
VERSION_4_8_2_PQ1(fork version 37), accept only0or1as values, and reject duplicate proposals for the same value. The proposals are reversible. The algorithm-agnostic multi-sig precompile0x0200001a ValidateMultiPQSigis enabled when either proposal is activated.7. Public Key Storage (Two Phases)
Phase 1: Transactions carry the signature and full public key.
Phase 2 [draft]: A new
pq_pubkeydatabase (key = PQ-public-key-derived address, value = proto carrying the public key) enables one-time public key storage without affecting consensus:pq_auth_sig[x].public_key; subsequent transactions need only supply the address.address → public_keyintopq_pubkey; if it is an address (21 B), look up the corresponding public key frompq_pubkeybefore verification — verification fails if the public key is not present.8. PQ Witness Key Configuration
PQ witness signing is enabled through the
localPqWitnessconfiguration section inconfig.conf— effective only after the corresponding scheme's activation proposal passes and the witnessPermissionhas been upgraded. ECDSA and PQ witnesses use separate, independent account-address keys (localWitnessAccountAddressvslocalPqWitness.accountAddress); the two consensus paths do not interfere and can coexist on the same node.Each entry in
keysis a JSON key file path; the file specifies aschemeand exactly one key-material source:seed— FN_DSA_512: 96 hex chars (48 bytes); ML_DSA_44: 64 hex chars (32 bytes). FN_DSA_512 (Falcon) key generation is FFT-based and not bit-stable across JVMs or CPU architectures — the same seed may derive different keypairs (i.e., different addresses). For production FN_DSA_512 witnesses, useprivateKey+publicKeyinstead. ML-DSA-44 key generation is pure integer arithmetic and fully reproducible.privateKey— hex-encoded private key. FN_DSA_512 must also providepublicKey(BouncyCastle cannot derive a public key from the private key). ML-DSA-44 can derive the public key from the private key, sopublicKeymust be omitted.JSON key file examples (hex lengths correspond to each scheme: FN_DSA_512 private key 1280 B / public key 896 B; ML-DSA_44 private key 2560 B):
9. PQ Transaction Count Limits
To prevent PQ transaction size inflation from impacting mempool and block throughput, the implementation imposes two independent numeric caps:
node.pqTransInPendingMaxCounts(config.confconfigurable, default 1000) limits the concurrent number of PQ-authenticated transactions in the pending pool; PQ transactions exceeding the limit are rejected atpushTransactionentry (ECDSA transactions are unaffected).Manager.PQ_TRANS_IN_BLOCK_COUNTS(hard-coded constant, 1000) limits the number of PQ transactions a single block can pack; the SR block-production loop skips subsequent PQ transactions once the packed PQ transaction count reaches this limit (continues packing ECDSA transactions), constraining PQ throughput together with the block byte-size limit.10. Key Code Changes by Module
PQSchemeenum (FN_DSA_512,ML_DSA_44) andPQAuthSigmessage;Transaction.pq_auth_sig=6,BlockHeader.pq_auth_sig=3,HelloMessage.pq_auth_sig=12;api.protoaddspq_schemefield for bandwidth estimationcrypto/pqcpackage wrapping BC'sFNDSA512/MLDSA44(FN-DSA-512 signature length constrained to 617–667 B, over-size resampling capped at 16 retries);PQSchemeRegistrycentral management of per-schemeseedLength/signLength/pkLength/deriveHash/verify/computeAddressmetadata; includesamd64/aarch64native librariesAccountPermissionUpdateActuatoraccepts PQ-derived addresses asKeyentries;TransactionUtilaccounts forpq_auth_sigweight; newPQPrecompiledContracts(5 precompiles) registered inPrecompiledContractsTransactionCapsule/BlockCapsulePQ verification paths run in parallel with ECDSA;getTotalSignatureCount()unifies ECDSA + PQ counts;Managerenforces two PQ transaction count caps — pending pool (pqTransInPendingMaxCounts) and per-block (PQ_TRANS_IN_BLOCK_COUNTS); JSON-RPCTransactionResult.pqAuthSigListexposes the field;getCanDelegatedMaxSizeaccounts for PQ sizeBlockHeaderfield is set;WitnessInitializerinitializes PQ witness keypairs fromlocalPqWitnessconfig usingprivateKey(orseed) — FN_DSA_512 seed derivation carries cross-platform floating-point drift risk; production environments should useprivateKey+publicKeyHelloMessageaddspq_auth_sigwith length caps and rejects smuggled unknown nested fields;RelayServicesigns handshake with the local key, verification performs strict checks (scheme registered + on-chain activated + pubkey/signature length match + derived address binds witness);TransactionsMsgHandlerenforces uniform length caps and count limits at ingress0x02000016–0x0200001a, gated byVMConfig.allowFnDsa512()/allowMlDsa44()ALLOW_FN_DSA_512(1000) /ALLOW_ML_DSA_44(1001) proposals, gated onVERSION_4_8_2_PQ1;ProposalUtilstrictly rejects illegal values and duplicate settings before activationconfig.conf/reference.confaddlocalPqWitnessconfiguration section andpqTransInPendingMaxCountsfield (HOCON structure)Rationale
Why "public key in transaction" (Option B) over "public key on chain" (Option A)
PQ verification requires an explicit public key; the design choice reduces to where to store the public key:
We choose Option B after weighing three dimensions: minimal intrusion into the existing protocol, lowest v1 implementation cost, and smallest ecosystem-side change. Option A's architectural problems (passive activation,
Accountstructure breakage) would be nearly irreversible once deployed, whereas Option B's size cost is reversible and can be mitigated via Falcon key-recovery, signature aggregation, and subsequent Phase 2 optimizations. This trade-off remains a tracked open question (Open Questions §5) to be further validated before mainnet.Why implement ML-DSA-44 in parallel rather than only Falcon-512
Falcon-512 has the most compact size footprint (~9.5× ECDSA) and is the preferred choice; however, FN-DSA / Falcon-512 is still at the FIPS 206 draft stage — the spec may still change during the review cycle, the implementation would face a moving-target audit, leaving material audit risk. To hedge this risk, ML-DSA-44, finalized as FIPS 204 in August 2024, is implemented in parallel as a natural fallback rather than a paper option. The protocol design makes the two schemes nearly interchangeable: they share the same
PQAuthSigwire format (differing only in theschemeenum value),PQSchemeRegistryprovides a pluggable dispatch table, and each has an independent governance proposal. The cost is that ML-DSA-44 has a larger per-transaction footprint (~22× ECDSA, ~2.3× Falcon).Size Comparison of PQ Candidate Algorithms
secp256k1 ECDSAFalcon-512ML-DSA-44SLH-DSA-128sSLH-DSA is out of scope this cycle due to excessive signature size.
Performance Data (500-run average)
Both PQ schemes improve signature-verification CPU on the consensus hot path; the bottleneck is transaction size, not verification cost. TPS ceiling varies with the blended average transaction size:
In the early transition phase, PQ adoption will be limited, keeping the size increase manageable. Falcon-512 (FIPS 206 draft) serves as the default size-efficient choice, while ML-DSA-44 serves as the FIPS 204 finalized fallback for specialized multi-sig use cases. We will continue to optimize in the future, with potential directions including Falcon key-recovery for footprint reduction, signature aggregation to enhance throughput, and broader protocol-level design improvements.
Precompile Energy Pricing
The new precompiles do not reuse the ECDSA precompile interfaces (
0x09/0x0A) because the PQverify(pk, msg, sig) → boolinterface cannot recover a public key — the caller must explicitly provide the full public key. Energy values are calibrated againstValidateMultiSign's1500 / siganchor: single PQ verification is set at3000; batch and multi-sig charges scale linearly per entry (PQ entries2400 / sig, ECDSA entries1500 / sig), with caps on each precompile (batchMAX_SIZE = 16, multi-sigMAX_SIZE = 5), and malformed input is charged at the backstop cap to prevent underpayment attacks. These prices are initial calibration values and require further validation and adjustment under real load.Backwards Compatibility
This TIP has no breaking changes:
Account,Permission, and other existing structure and state fields are entirely unchanged.pq_auth_sigfields to transaction, block, andHelloMessageJSON; the old format is unaffected.After activation, each scheme can be disabled via a reverse governance proposal under the standard 27-SR maintenance-cycle timeline (disabling a proposal may cause SRs that had adopted PQ signing to miss blocks).
Test Cases
Test scenarios that should be covered for this change (the reference implementation includes corresponding unit and integration tests):
thresholdcomparison logic.UNKNOWN_PQ_SCHEMEand illegal scheme values are rejected at verification.pq_auth_sigto prevent a forged PQ signature sharing the same txid from inheriting an already-verified flag and causing a fork; SR block-production PQ dispatch.HelloMessageand transaction ingress (RPC broadcast + P2P) enforcepq_auth_siglength caps, reject smuggled unknown nested fields, and apply uniform count limits.Implementation
The reference implementation is PR tron-nile-testnet/nile-testnet#59 (based on the v4.8.2 line, hard fork version
VERSION_4_8_2_PQ1), covering all module changes described above under Protocol / Crypto / Actuator / Framework / Consensus / Net / VM / Governance / Config. The accompanying Toolkit provides apq-key newcommand to generate PQ key files (with--seedsupport):This reference implementation is currently deployed on Nile Testnet for testing, to validate PQ signature channels, block-production/sync, and precompile behavior in a real network environment.
Security readiness work before mainnet activation: an external cryptographic and implementation audit, publication of an audit summary (at a minimum before the SR vote), and bug-bounty coverage for
crypto/pqc,PQSchemeRegistry, and the new precompiles.Open Questions
ECRecover; design a progressive adoption path and "dual-signature compatible" transition model.Future Phases (out of scope this cycle)
FORBID_ECDSA_SIGNproposal: the entire network accepts only PQ signatures, instantly severing the quantum attack surface.RecoverAccountByZkContract, relying on post-quantum SNARKs (Plonky2 / STARK).References
Copyright
Copyright and related rights waived via CC0.