feat(crypto): add post-quantum signature support for nile
Summary
Adds post-quantum (PQ) signature support to TRON across protocol, crypto, transaction/block validation, TVM precompiles, witness configuration, consensus signing, relay handshakes, governance flags, and tests.
Two PQ schemes are supported, each independently gated by a committee proposal:
FN_DSA_512/ Falcon-512 (variable-length signature, max 667 B, pubkey 896 B)ML_DSA_44/ Dilithium-2 (fixed-length signature 2420 B, pubkey 1312 B)
Protocol changes
- Adds
PQSchemeenum:UNKNOWN_PQ_SCHEME,FN_DSA_512,ML_DSA_44. - Adds
PQAuthSig { scheme, public_key, signature }as the shared PQ authentication envelope. - Adds
repeated pq_auth_sigtoTransactionso ECDSA and PQ signatures coexist for account permission threshold checks. - Adds
pq_auth_sigtoBlockHeader; legacywitness_signatureand PQpq_auth_sigare mutually exclusive. - Adds
pq_auth_sigtoHelloMessagefor relay/fast-forward authentication by PQ witnesses.
Address derivation
- PQ addresses:
0x41 || deriveHash(scheme, public_key)[12..32], matching the ECDSA shape. - Both schemes use Keccak-256 as the fingerprint hash.
PQSchemeRegistry.computeAddress(scheme, publicKey)is the single entry point.
Crypto module (crypto)
FNDSA512: Falcon-512 sign/verify; variable-length signatures validated against the canonical[SIGNATURE_MIN_LENGTH, SIGNATURE_MAX_LENGTH]range.MLDSA44: ML-DSA-44 sign/verify; fixed-length 2420-byte signatures.PQSignature,PQSchemeRegistry,PqKeypair: shared PQ abstraction layer.PQSchemeRegistrycentralises key lengths, signature lengths, seed handling, address derivation, sign, verify, and block-size wire-size computation (computePQAuthSigWireSize).
Governance and activation
- Adds
ALLOW_FN_DSA_512(proposal id 99) andALLOW_ML_DSA_44(proposal id 100). - Both proposals are fork-gated on
VERSION_4_8_2. - Runtime checks reject PQ signatures and precompile calls when the scheme is not yet active.
Witness configuration
- PQ witness keys are configured via
localPqWitness.keys— a list of paths to JSON key files (relative paths resolve against the working directory); each file holds one keypair, keeping the long key material out ofconfig.conf. - Each JSON key file names a
schemeand may contain any combination of the following material fields —privateKeytakes priority at load time;seedis retained as a backup field when both are present:seed—FN_DSA_512: 96 hex chars / 48 B (accepted with a drift warning — Falcon keygen is FFT-based and not bit-stable across JVMs or CPU architectures);ML_DSA_44: 64 hex chars / 32 B (deterministic).privateKey—FN_DSA_512must also supplypublicKey(BouncyCastle exposes no API to derive it from the private key);ML_DSA_44suppliesprivateKeyonly —publicKeyis derived automatically, but may optionally be included for verification (if present it must match the derived value, otherwise the node rejects the file).address— informational field written bypq-key new, ignored at load time.
PqKeyFile(Jackson-bound) is the JSON shape.- PQ-only witnesses derive their witness address from the configured PQ public key when no explicit
localPqWitness.accountAddressis set. - A node can host a mix of ECDSA and PQ SRs simultaneously.
Consensus and block production
- Consensus miners carry optional PQ key material and sign blocks with the configured PQ scheme.
- Block production fails fast if a PQ miner is configured for a scheme that is not yet active on-chain.
generateBlockpre-reserves the exact proto3 wire size ofpq_auth_sig(viaPQSchemeRegistry.computePQAuthSigWireSize) before the transaction packing loop, preventing PQ SR blocks from exceeding the receiver-sidemaxBlockSizecheck inBlockMsgHandler.
Transaction validation
TransactionCapsulevalidates mixed ECDSA + PQ signatures against the same account permission threshold.- PQ signer identity is derived from the in-band public key and matched against
Permission.keys[].address. - Duplicate signers are rejected across ECDSA and PQ paths.
- Shielded-transfer validation rejects transparent/PQ signatures on shielded-from transactions.
Block validation
- Block signature validation supports both legacy ECDSA and PQ schemes.
- The derived PQ address must match the on-chain witness permission address.
Bandwidth
- PQ
pq_auth_sigbytes are subtracted from net bandwidth as signature overhead (same treatment as ECDSAsignaturebytes).
Transaction and pending pool limits
- Per-block PQ transaction cap: 1000 (
PQ_TRANS_IN_BLOCK_COUNTS). - Configurable pending pool cap:
node.pqTransInPendingMaxCounts(default 1000).
TVM precompiles
Five new precompiles covering single verify, batch verify, and mixed multi-sign for both PQ schemes:
| Address | Name | Description |
|---|---|---|
0x16 | VerifyFnDsa512 | Single Falcon-512 verify |
0x17 | BatchValidateFnDsa512 | Batch Falcon-512 verify, bitmap result, MAX_SIZE=16 |
0x18 | VerifyMlDsa44 | Single ML-DSA-44 verify |
0x19 | BatchValidateMlDsa44 | Batch ML-DSA-44 verify, bitmap result, MAX_SIZE=16 |
0x1a | ValidateMultiPQSig | Unified ECDSA + PQ permission threshold verify, MAX_SIZE=5 |
Energy values are calibrated via JMH benchmarks (warmup 5×2s, measurement 10×3s, 2 forks, 20 samples) using ECRecover.execute() — precompile 0x01, 3000 energy, 816.9 µs — as the reference unit. All benchmarks call contract.execute(input) to cover the full precompile path (ABI decode, slot scan, address derivation, verify):
| Precompile | Per-call operation | Measured (µs) | Energy |
|---|---|---|---|
0x16 | full path: validate + slot scan + verify() | 44.8 | 170 |
0x17 per entry | full path: ABI + computeAddress() + verify() | 57.5 | 220 |
0x18 | full path: validate + verify() | 114.2 | 420 |
0x19 per entry | full path: ABI + computeAddress() + verify() | 126.6 | 470 |
0x1a FN-DSA entry | same operation as 0x17 per entry | — | 220 |
0x1a ML-DSA entry | same operation as 0x19 per entry | — | 470 |
ECRecover baseline: 816.9 µs → 3000 energy (CV 1.9%); all PQ values rounded up to the nearest 10. 0x1a ValidateMultiPQSig.execute() requires chain DB and cannot be benchmarked in isolation — its per-entry crypto work is identical to 0x17/0x19 respectively, so those values are reused.
These values are proposed based on this benchmark run and subject to community review before mainnet activation.
Relay / fast-forward support
RelayServicesigns and verifiesHelloMessageusing either legacy signatures orPQAuthSig.- PQ hello-message verification checks scheme registration, activation, key/signature lengths, address binding, and cryptographic validity.
Toolkit (plugins)
- New
Toolkit.jar pq-key newcommand generates a post-quantum key JSON file. - Default scheme:
FN_DSA_512; default output directory:Wallet/. - Generated file contains all material fields in one place:
{ "scheme": "FN_DSA_512", "seed": "<96 hex chars>", "privateKey": "<2560 hex chars>", "publicKey": "<1792 hex chars>", "address": "T..." }ML_DSA_44files follow the same structure with scheme-appropriate lengths (seed 64 hex, privateKey 5120 hex, publicKey 2624 hex). - File is written with
0600permissions (owner read/write only). --jsonflag prints a machine-readable summary (address,scheme,file).
Example module (example:pqc-example)
- New Gradle sub-module
example:pqc-example(packageorg.tron.example.pqc). PQWitnessNode: in-process PQ witness node with deterministic keypairs.PQFullNode: fullnode that dialsPQWitnessNodevia P2P and validates PQ-signed blocks.PQClient: broadcasts a single PQ-signed transfer transaction.PQTxSender: continuous multi-scheme (FN-DSA-512, ML-DSA-44, ECDSA) transfer and TRC20 load generator.PQWitnessNode.writeWitnessConfigemits the full key file format (seed,privateKey,publicKey,address), matching thepq-key newoutput.- Run via
./gradlew :example:pqc-example:run -PmainClass=org.tron.example.pqc.PQWitnessNode.
Compatibility
- Pre-activation behavior is legacy-only; PQ fields are rejected when no scheme is active.
UNKNOWN_PQ_SCHEMEis reserved and never treated as a valid signing scheme.- Existing ECDSA transaction and block signing paths remain fully supported.
Tests
- Unit tests: Falcon-512 and ML-DSA-44 sign/verify, KAT regression,
PQSchemeRegistry,PQSignature. - TVM tests: single, batch, and unified multi-sign PQ precompiles.
- Transaction and block capsule tests for PQ authentication.
- Witness config, proposal, relay, bandwidth, JSON, and account-permission tests.