Skip to content

feat(crypto): add Falcon-512 post-quantum signature support#23

Open
Federico2014 wants to merge 27 commits into
release_pqc_basefrom
feat/pqc-v2-witness-pubkey
Open

feat(crypto): add Falcon-512 post-quantum signature support#23
Federico2014 wants to merge 27 commits into
release_pqc_basefrom
feat/pqc-v2-witness-pubkey

Conversation

@Federico2014
Copy link
Copy Markdown
Owner

@Federico2014 Federico2014 commented Apr 30, 2026

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)

  • New enum PQSchemeUNKNOWN_PQ_SCHEME = 0 is reserved for forward compatibility; FN_DSA_512 = 1 is the launch scheme so on-chain entries pay zero bytes for the default tag.
  • New message 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_data gains pq_auth_sig. A block carries exactly one of {witness_signature, pq_auth_sig} — they are mutually exclusive at the header level (no dual-signing).
  • Transaction gains repeated PQAuthSig pq_auth_sig. ECDSA signature entries and pq_auth_sig entries may co-exist on multi-sig transactions; each co-signer is matched against the permission by its derived address (no positional key_id alignment) and contributes weight independently to the permission's threshold.

Address derivation

  • Address = 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.
  • Implemented uniformly via PQSchemeRegistry.computeAddress(scheme, publicKey).

Crypto module

  • FNDSA wraps BouncyCastle 1.79's Falcon-512 with deterministic key derivation from a 48-byte seed.
  • Constants: 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).
  • Constructor surface kept minimal:
    • 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 second FNDSA(byte[]) overload would clash with the seed constructor, hence the factory method.)
  • derivePublicKey(byte[] extendedPriv) extracts h from the extended encoding — needed because BouncyCastle has no public API to recompute h = g · f⁻¹ mod q from the bare 1280-byte private key (BC issue Feature/event uint parse tronprotocol/java-tron#2297).
  • PQSchemeRegistry is the single dispatch point for sign / verify / computeAddress / key length queries by PQScheme.

Witness configuration

  • localwitness_pq_scheme = "FN_DSA_512" selects the active scheme.
  • localwitness_pq_keys is now a flat list of hex strings, each the 4352-char extended form f‖g‖F‖h. The redundant {priv, pub} dual-field shape was removed — the public key is derivable from the extended encoding via derivePublicKey, so storing both fields was pure duplication.
  • Args parses entries with getStringList(...), validates the hex length against the active scheme, and slices into the existing (priv, pub) lists used by LocalWitnesses / 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 as 0x17.

Account-level wiring

  • Account.Permission accepts entries whose address was derived from a PQ public key; ValidateMultiSignPQ matches signatures against permission keys by address.
  • PQ-native account creation: a new account can be created by an AccountCreateContract whose owner address comes from a PQ permission, signed via PQAuthSig.

Test coverage

  • Falcon-512 sign / verify round-trips, deterministic seed derivation, extended encoding round-trips.
  • TVM precompile tests for 0x16 / 0x17 / 0x18 covering happy path, malformed input, mixed ECDSA+PQ permissions, and bitmap encoding.
  • End-to-end demo (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

  • Pre-activation chains are byte-for-byte unchanged. The pq_auth_sig fields are zero-encoded when absent.
  • The launch finalises the witness layout to a single signature field per block (one of ECDSA or PQ); validators must enforce the mutual-exclusion check on inbound blocks.

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.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dd5ae12b-3833-4a92-92bf-07f307603c7e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/pqc-v2-witness-pubkey

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.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Federico2014 Federico2014 changed the title Feat/pqc v2 witness pubkey feat(crypto): add FN-DSA / Falcon-512 post-quantum signature support Apr 30, 2026
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread crypto/src/main/java/org/tron/common/crypto/pqc/PQAuthDigest.java Outdated
Comment thread chainbase/src/main/java/org/tron/core/db/BandwidthProcessor.java Outdated
Comment thread protocol/src/main/protos/core/contract/account_contract.proto Outdated
Comment thread framework/src/main/java/org/tron/core/config/args/Args.java Outdated
Comment thread framework/src/test/java/org/tron/core/BandwidthProcessorTest.java Outdated
Comment thread framework/src/test/java/org/tron/common/runtime/vm/FnDsaPrecompileTest.java Outdated
@Federico2014 Federico2014 force-pushed the feat/pqc-v2-witness-pubkey branch from ede5eb4 to e4a47d6 Compare May 6, 2026 03:25
@Federico2014 Federico2014 changed the title feat(crypto): add FN-DSA / Falcon-512 post-quantum signature support feat(crypto): add Falcon-512 post-quantum signature support May 6, 2026
@Federico2014 Federico2014 force-pushed the feat/pqc-v2-witness-pubkey branch from e4a47d6 to 582068e Compare May 6, 2026 03:43
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread actuator/src/main/java/org/tron/core/vm/PrecompiledContracts.java
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant