feat(crypto): add Falcon-512 post-quantum signature support#23
feat(crypto): add Falcon-512 post-quantum signature support#23Federico2014 wants to merge 27 commits into
Conversation
Micro-benchmark comparing keygen/sign/verify latency for secp256k1 ECKey, ML-DSA-44 and ML-DSA-65, for tracking PQ signature integration performance characteristics across releases.
Introduce two TVM precompiles for post-quantum signature verification, gated on the existing ALLOW_ML_DSA proposal: - 0x12 VerifyMlDsa44: ML-DSA-44 (FIPS-204, SHAKE256), 4500 energy. Compatible with EIP-8051 0x12 at the algorithm level; uses raw 1312-byte public keys (BouncyCastle-native form) rather than the 20512-byte expanded form, so wire bytes differ. - 0x14 VerifyMlDsa65: ML-DSA-65 (TRON extension), 7000 energy. Input layout for both: [msg 32B | signature | publicKey], output is a 32-byte word (1 on success, 0 otherwise). Wires VMConfig.allowMlDsa() through ConfigLoader so the flag is loaded from the store on startup.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
7 issues found across 46 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="framework/src/main/java/org/tron/core/consensus/ConsensusService.java">
<violation number="1" location="framework/src/main/java/org/tron/core/consensus/ConsensusService.java:143">
P3: The `requireSupportedPqScheme` check is redundant — `LocalWitnesses.setPqScheme()` already validates the scheme against `PQSchemeRegistry` at config-load time (throwing `TronError(WITNESS_INIT)` for unsupported schemes), and `PQSchemeRegistry.fromSeed()` would throw `IllegalArgumentException` regardless. Consider removing this defensive check and relying on the setter's validation as the single validation point.
(Based on your team's feedback about relying on LocalWitnesses.setPqScheme to validate the PQ signature scheme.) [FEEDBACK_USED]</violation>
</file>
<file name="protocol/src/main/protos/core/contract/account_contract.proto">
<violation number="1" location="protocol/src/main/protos/core/contract/account_contract.proto:30">
P2: Reserve the deleted field name as well as tag number to prevent accidental `pq_key` reuse in future schema changes.</violation>
</file>
<file name="framework/src/main/java/org/tron/core/config/args/Args.java">
<violation number="1" location="framework/src/main/java/org/tron/core/config/args/Args.java:1242">
P2: Remove the hard-coded PQ scheme whitelist in `Args` and rely on `localWitnesses.setPqScheme(scheme)` for validation.
(Based on your team's feedback about using PQ scheme registry/setter as the single source of truth.) [FEEDBACK_USED]</violation>
</file>
<file name="crypto/src/main/java/org/tron/common/crypto/pqc/PQAuthDigest.java">
<violation number="1" location="crypto/src/main/java/org/tron/common/crypto/pqc/PQAuthDigest.java:26">
P1: Make domain byte arrays private to prevent package-level mutation of digest domain separators.</violation>
</file>
<file name="framework/src/test/java/org/tron/core/BandwidthProcessorTest.java">
<violation number="1" location="framework/src/test/java/org/tron/core/BandwidthProcessorTest.java:933">
P3: Don’t swallow the other checked exceptions here; they can make this test pass on unrelated failures and hide a broken cap check.</violation>
</file>
<file name="chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java">
<violation number="1" location="chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java:150">
P1: When PQ witnesses are present, this overwrites instead of accumulates signature overhead; mixed legacy+PQ transactions will have create-account size miscomputed and can be rejected incorrectly.</violation>
</file>
<file name="framework/src/test/java/org/tron/common/runtime/vm/FnDsaPrecompileTest.java">
<violation number="1" location="framework/src/test/java/org/tron/common/runtime/vm/FnDsaPrecompileTest.java:131">
P3: This input is too short to exercise the `sig_len == 0` check. Increase it to at least 931 bytes so the test actually covers the zero-length-signature path.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
ede5eb4 to
e4a47d6
Compare
e4a47d6 to
582068e
Compare
There was a problem hiding this comment.
2 issues found across 36 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="framework/src/main/java/org/tron/core/consensus/ConsensusService.java">
<violation number="1" location="framework/src/main/java/org/tron/core/consensus/ConsensusService.java:109">
P2: Validate that pqPublicKeys is present and the same size as pqPrivateKeys before indexing it; otherwise misconfigured nodes will fail with IndexOutOfBounds during consensus startup.</violation>
</file>
<file name="chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java">
<violation number="1" location="chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java:244">
P2: Renaming the dynamic property key to `ALLOW_FN_DSA_512` drops compatibility with existing `ALLOW_FN_DSA` values in the DB. If a network already stored this flag, the upgrade will silently ignore it and revert to the default value. Consider a backward-compatible read/migration for the legacy key.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Tip: cubic used a learning from your PR history. Let your coding agent read cubic learnings directly with the cubic MCP.
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java">
<violation number="1" location="actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java:2429">
P0: Critical: Falcon-512's randomized signing allows the same PQ key to contribute weight multiple times. An attacker submits N distinct valid signatures from one key, each passes verification and accumulates weight, bypassing the multi-sig threshold. The dedup should reject any address already seen regardless of signature content.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Summary
Adds post-quantum (PQ) signature support to TRON with FN-DSA / Falcon-512 (FIPS-206 draft) as the launch scheme. The change spans the protocol, crypto, chainbase, actuator, framework, and TVM layers, gated behind a single proposal
ALLOW_FN_DSA_512.Protocol changes (
Tron.proto)PQScheme—UNKNOWN_PQ_SCHEME = 0is reserved for forward compatibility;FN_DSA_512 = 1is the launch scheme so on-chain entries pay zero bytes for the default tag.PQAuthSig { PQScheme scheme; bytes public_key; bytes signature; }carries the scheme tag, raw public key (896 B for Falcon-512), and signature (≤ 752 B for Falcon-512).BlockHeader.raw_datagainspq_auth_sig. A block carries exactly one of{witness_signature, pq_auth_sig}— they are mutually exclusive at the header level (no dual-signing).Transactiongainsrepeated PQAuthSig pq_auth_sig. ECDSAsignatureentries andpq_auth_sigentries may co-exist on multi-sig transactions; each co-signer is matched against the permission by its derived address (no positionalkey_idalignment) and contributes weight independently to the permission's threshold.Address derivation
0x41 ‖ Keccak-256(public_key)[12..32]— the same scheme used for ECDSA accounts. The public key acts as the in-band fingerprint, so accounts do not need a separate stored PQ key blob.PQSchemeRegistry.computeAddress(scheme, publicKey).Crypto module
FNDSAwraps BouncyCastle 1.79's Falcon-512 with deterministic key derivation from a 48-byte seed.SEED_LENGTH = 48,PRIVATE_KEY_LENGTH = 1280(f‖g‖F),PUBLIC_KEY_LENGTH = 896,SIGNATURE_LENGTH ≤ 752,PRIVATE_KEY_WITH_PUBLIC_KEY_LENGTH = 2176(f‖g‖F‖h).FNDSA(byte[] seed)— strict 48-byte seed.FNDSA(byte[] priv, byte[] pub)— strict 1280/896 split.FNDSA.fromPrivateKeyWithPublicKey(byte[])— static factory for the 2176-byte extended form. (A secondFNDSA(byte[])overload would clash with the seed constructor, hence the factory method.)derivePublicKey(byte[] extendedPriv)extractshfrom the extended encoding — needed because BouncyCastle has no public API to recomputeh = g · f⁻¹ mod qfrom the bare 1280-byte private key (BC issue Feature/event uint parse tronprotocol/java-tron#2297).PQSchemeRegistryis the single dispatch point forsign / verify / computeAddress / key lengthqueries byPQScheme.Witness configuration
localwitness_pq_scheme = "FN_DSA_512"selects the active scheme.localwitness_pq_keysis now a flat list of hex strings, each the 4352-char extended formf‖g‖F‖h. The redundant{priv, pub}dual-field shape was removed — the public key is derivable from the extended encoding viaderivePublicKey, so storing both fields was pure duplication.Argsparses entries withgetStringList(...), validates the hex length against the active scheme, and slices into the existing(priv, pub)lists used byLocalWitnesses/ConsensusService.TVM precompiles
0x16 verifyFnDsa512(msg, publicKey, signature)— single-signature verification, energy 15 000.0x17 ValidateMultiSignPQ— mixed ECDSA + PQ multi-sign verification against an account permission. Per-signature energy: 1 500 (ECDSA), 15 000 (PQ).0x18 BatchValidateSignPQ(msg, sigs[], pubKeys[])— bitmap-style batch verifier returning a packed result word. Same per-signature pricing as0x17.Account-level wiring
Account.Permissionaccepts entries whoseaddresswas derived from a PQ public key;ValidateMultiSignPQmatches signatures against permission keys by address.AccountCreateContractwhose owner address comes from a PQ permission, signed viaPQAuthSig.Test coverage
0x16/0x17/0x18covering happy path, malformed input, mixed ECDSA+PQ permissions, and bitmap encoding.PQWitnessNode+PQClient): boots an in-process node with a Falcon-512 witness keypair, broadcasts a Falcon-512 TRX transfer (~1670 B vs. 175 B ECDSA), produces a PQ-signed block.Proposal gating
All PQ behaviour is gated on
ALLOW_FN_DSA_512. Pre-activation, every PQ codepath either rejects or is unreachable; post-activation the behaviour above becomes available.Compatibility
pq_auth_sigfields are zero-encoded when absent.