Skip to content

feat(pqc): add post-quantum signature support#1

Open
Federico2014 wants to merge 7 commits into
developfrom
feature/pq-fn-dsa-512
Open

feat(pqc): add post-quantum signature support#1
Federico2014 wants to merge 7 commits into
developfrom
feature/pq-fn-dsa-512

Conversation

@Federico2014

@Federico2014 Federico2014 commented May 14, 2026

Copy link
Copy Markdown
Owner

What does this PR do?
Adds post-quantum signature support to wallet-cli, mirroring the protocol changes introduced by the ALLOW_FN_DSA_512 and ALLOW_ML_DSA_44 proposals in java-tron. Users can generate, store, import, and transact with PQ keypairs in either scheme.

Two PQ schemes are now supported:

  • Falcon-512 / FN-DSA-512 (FIPS-206 draft) — 48-byte seed, 896-byte public key, 2176-byte persisted private key (f‖g‖F‖h), ≤752-byte signature.
  • ML-DSA-44 / Dilithium-2 (FIPS-204) — 32-byte seed, 1312-byte public key, 2560-byte encoded private key (rho‖K‖tr‖s1‖s2‖t0), fixed 2420-byte signature.

Key changes:

  • Proto Sync: Added PQScheme (with FN_DSA_512, ML_DSA_44), PQAuthSig, and pq_auth_sig fields on Transaction, BlockHeader, and HelloMessage (additive, backward-compatible).
  • Crypto Layer: Added FNDSA512, MLDSA44, PQSchemeRegistry, and the PQSignature abstraction. Dispatch is per-wallet via WalletFile.scheme, not process-wide. Address derivation uses 0x41 || Keccak-256(pubkey)[12..32] for both schemes.
  • Keystore (TIP-101 Extension): Implements the v5 dual-ciphertext specification for the post-quantum keystore.
    • WalletFile.scheme acts as a discriminator (FN_DSA_512, ML_DSA_44).
    • The keygen seed and the persisted private key (scheme-specific length) are encrypted independently within the same file.
    • Wallet.createPQ uses a single scrypt KDF run to generate DK, where DK[0..16] keys AES-CTR for both segments using independent IVs, and DK[16..32] generates independent Keccak-256 MACs.
    • Wallet.decryptPQ validates all present MACs before decryption and performs consistency checks.
  • PQ surface is scheme-generic: PQSchemeRegistry is the single dispatch point; per-scheme seed/persisted-key lengths come from the registry and the getPersistedPrivateKey() default abstracts the on-disk encoding asymmetry between Falcon (must append h) and ML-DSA (private encoding is self-contained).
  • Commands: Added generatePQKey, registerWalletPQ, and importWalletPQ to the REPL, and generate-pq-key, register-wallet-pq, and import-wallet-pq to the standard CLI. All three commands accept a --scheme / positional scheme argument (default FN_DSA_512).

Why are these changes required?
To provide a reference user-facing tool for interacting with the upcoming post-quantum signature features in TRON. Supporting both Falcon-512 and ML-DSA-44 from day one mirrors the dual-scheme rollout on the node side and lets users compare the two schemes for their own use cases. The dual-ciphertext keystore design ensures the wallet can securely store the (longer) persisted private key alongside the original seed, allowing full key recovery while preventing keystream reuse.

This PR has been tested by:

  • Unit Tests: FNDSA512Test, MLDSA44Test, PQSchemeRegistryTest (covers dispatch for both schemes), PQSignatureDefaultsTest, WalletPQAddressTest, WalletPQKeystoreTest, WalletPQMlDsa44KeystoreTest. Coverage includes dual-ciphertext roundtrips, ext-only and seed-only paths, missing material, IV independence, segment-specific MAC tamper rejection, and signature-length validation.
  • Manual Testing: REPL and standard CLI flows for PQ key generation, keystore encryption/decryption, and signing, exercised under both schemes.

Follow up

  • PQ support for hardware wallets (Ledger) when available.
  • Mnemonic derivation for PQ keys.

Extra details

  • BouncyCastle has been bumped from 1.78.1 to 1.84 to access org.bouncycastle.pqc.crypto.falcon.* and org.bouncycastle.pqc.crypto.crystals.dilithium.*.
  • Addressed CodeRabbit review comments: scrub secrets from memory in finally blocks, encode exclusivity between EC/PQ signatures (oneof auth) in the proto, harden signPQ against unsupported scheme tags, verify imported seed/private key generate the same keypair, and explicitly check scheme values against the registry.

Summary by CodeRabbit

  • New Features

    • Add post-quantum wallet support (FN-DSA-512 & ML-DSA-44): generate, register, and import PQ keys (CLI + REPL) and PQ-authenticated transactions (pq_auth_sig).
  • Documentation

    • README, help text, and CLI examples updated to document PQ commands, keystore "scheme" tagging, address format, and JSON outputs.
  • Chores

    • BouncyCastle provider upgraded to 1.84.

@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds PQ signature primitives (FN-DSA-512 / ML-DSA-44), a scheme registry, WalletFile scheme and seed fields, keystore create/decrypt logic, Transaction PQ signing/validation, provider/hash wiring, CredentialsFalcon adapter, WalletApi/CLI integration, proto additions, docs, and unit tests.

Changes

Post-Quantum Falcon & ML Signature Support

Layer / File(s) Summary
Provider & Hash wiring
src/main/java/org/tron/common/crypto/jce/TronCastleProvider.java, src/main/java/org/tron/common/crypto/Hash.java, src/main/java/org/tron/common/utils/Hash.java
Registers TronCastleProvider into Security (removing BC if present) and switches Hash utilities to use the provider instance for TRON-KECCAK digests.
PQ primitives & registry
src/main/java/org/tron/common/crypto/pqc/PQSignature.java, src/main/java/org/tron/common/crypto/pqc/FNDSA512.java, src/main/java/org/tron/common/crypto/pqc/MLDSA44.java, src/main/java/org/tron/common/crypto/pqc/PQSchemeRegistry.java
Adds PQSignature interface, FNDSA512 and MLDSA44 implementations, and PQSchemeRegistry dispatch with lengths, sign/verify, fromSeed/fromKeypair/fromPersisted, fingerprint hashing, and address derivation.
WalletFile schema updates
src/main/java/org/tron/keystore/WalletFile.java
Adds optional scheme and seed-related crypto fields (seedciphertext, seedcipherparams, seedmac) with JSON omission when null; adds accessors and updates equals/hashCode.
Wallet PQ keystore logic
src/main/java/org/tron/keystore/Wallet.java
Implements createPQ/createStandardPQ and decryptPQ with scrypt+AES-CTR encryption for ext/seed segments, per-segment MACs, IV independence checks, validations, and helpers.
WalletUtils & CredentialsFalcon
src/main/java/org/tron/keystore/WalletUtils.java, src/main/java/org/tron/keystore/CredentialsFalcon.java
loadCredentials detects PQ scheme and returns CredentialsFalcon, which wraps a generic PQSignature and exposes key bytes via a SignInterface while disabling EC/SM2 signing/hash operations.
Transaction PQ signing and validation
src/main/java/org/tron/common/utils/TransactionUtils.java
Adds PQ-aware tx validation (accept transactions with PQAuthSig even when legacy signatures are absent), validates PQAuthSig entries, and implements signPQ overloads that append PQAuthSig.
WalletApi & WalletApiWrapper
src/main/java/org/tron/walletserver/WalletApi.java, src/main/java/org/tron/walletcli/WalletApiWrapper.java
Adds CreatePQWalletFile, getPQSignature, getWalletPQScheme, isPQWallet, and wrapper APIs for registering/importing PQ wallets (CLI and programmatic) that create and persist PQ WalletFiles.
Interactive & CLI commands
src/main/java/org/tron/walletcli/Client.java, src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java, src/main/resources/commands.txt, README.md, CLAUDE.md, src/main/resources/help_summary.txt, build.gradle
Adds interactive REPL handlers and no-auth CLI commands (GeneratePQKey, RegisterWalletPQ, ImportWalletPQ), parsing/validation helpers, non-interactive JSON examples, command docs and help updates, and upgrades BouncyCastle provider to 1.84.
Protobuf changes
src/main/protos/core/Tron.proto
Adds PQScheme enum and PQAuthSig message, extends Transaction with repeated PQAuthSig pq_auth_sig, and adds PQ auth fields to BlockHeader.raw and HelloMessage.
Tests
src/test/java/org/tron/common/crypto/pqc/*, src/test/java/org/tron/keystore/*
Adds unit tests for FNDSA512 and MLDSA44, PQSchemeRegistry behavior, PQSignature defaults, PQ address derivation, and keystore encrypt/decrypt/serialization including negative test cases.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Poem

🐇 I coded keys that hop and sing,
Falcon wings and Dilithium spring,
Keystores hum with scrypt and AES,
PQ sigs hop into tx arrays,
I nibble tests and clap — secure spring!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.81% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The PR title 'feat(pqc): add post-quantum signature support' directly reflects the main change—introduction of post-quantum signature functionality (FN-DSA-512/Falcon-512) to the TRON wallet CLI. It is concise, specific, and covers the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/pq-fn-dsa-512

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): add Falcon-512 / FN-DSA-512 post-quantum signature support feat(pqc): add FN-DSA-512 post-quantum signature support May 14, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/org/tron/keystore/WalletUtils.java (1)

198-204: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not silently ignore non-null scheme tags in credential dispatch.

Line 198 only handles FN_DSA_512; any other non-null scheme currently falls through to isEckey and may pick the wrong decryptor. Fail fast on unknown tags and honor explicit SM2/ECKEY tags.

Proposed fix
   public static Credentials loadCredentials(byte[] password, WalletFile walletFile)
       throws CipherException {
-    if ("FN_DSA_512".equals(walletFile.getScheme())) {
+    String scheme = walletFile.getScheme();
+    if ("FN_DSA_512".equals(scheme)) {
       return CredentialsFalcon.create(Wallet.decryptPQ(password, walletFile));
     }
+    if ("SM2".equals(scheme)) {
+      return CredentialsSM2.create(Wallet.decryptSM2(password, walletFile));
+    }
+    if ("ECKEY".equals(scheme)) {
+      return CredentialsEckey.create(Wallet.decrypt(password, walletFile));
+    }
+    if (scheme != null) {
+      throw new CipherException("Unsupported wallet scheme: " + scheme);
+    }
     if (isEckey) {
       return CredentialsEckey.create(Wallet.decrypt(password, walletFile));
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/org/tron/keystore/WalletUtils.java` around lines 198 - 204, The
dispatch currently only checks for "FN_DSA_512" and otherwise falls through to
isEckey, which misroutes when walletFile.getScheme() is non-null but not
"FN_DSA_512"; update WalletUtils to inspect walletFile.getScheme() and, when
non-null, explicitly branch on known tags ("FN_DSA_512" -> call
CredentialsFalcon.create with Wallet.decryptPQ, "SM2" -> call
CredentialsSM2.create with Wallet.decryptSM2, "ECKEY" -> call
CredentialsEckey.create with Wallet.decrypt); if the scheme is non-null and not
one of these known values throw an IllegalArgumentException (fail fast); retain
the original isEckey-based behavior only when scheme is null.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/org/tron/common/utils/TransactionUtils.java`:
- Around line 357-373: Update validation and signing checks for PQ auth: adjust
the transaction validator (validTransaction) so that transactions containing at
least one PQAuthSig (PQAuthSig entries on the transaction proto) are accepted
even when signatureCount == 0 (i.e., treat presence of pq_auth_sig as satisfying
signature requirements) and ensure you still validate PQAuthSig fields
(publicKey, signature non-empty) as before; and harden signPQ(Transaction,
FNDSA512, PQScheme) to reject unsupported/unknown scheme values (e.g., if scheme
== PQScheme.UNKNOWN_PQ_SCHEME or not one of the explicitly supported enums for
FNDSA512) by throwing an IllegalArgumentException (or similar) before signing,
referencing the signPQ overloads, PQAuthSig, and PQScheme symbols so callers
cannot stamp unsupported schemes onto Falcon signatures.

In `@src/main/java/org/tron/keystore/Wallet.java`:
- Around line 349-355: The code in createPQ builds sensitive byte arrays
(derivedKey, encryptKey, iv, cipherText) and returns without wiping them; update
the createPQ flow to use a try/finally (or try-with-resources equivalent) around
the derivation/encryption steps so that in the finally block you explicitly
overwrite and zero out derivedKey, encryptKey (Arrays.fill(..., (byte)0)), iv,
and any other temporary sensitive buffers (e.g., cipherText or
extendedPrivateKey) after createPQWalletFile is called; ensure you still return
the wallet file but perform the zeroing in finally to guarantee clearing on all
exit paths and reference the methods/vars generateDerivedScryptKey,
performCipherOperation, generateRandomBytes, generateMac, and createPQWalletFile
when locating the code to change.
- Around line 403-406: In decryptPQ in class Wallet, guard the PQScheme parsing
so an invalid or tampered scheme string doesn't throw an uncaught
IllegalArgumentException: wrap the PQScheme.valueOf(walletFile.getScheme()) call
in a try/catch that catches IllegalArgumentException (and NullPointerException
if needed) and rethrow a CipherException with a clear message like "Unsupported
or invalid PQ scheme: <scheme>" (include the original scheme string) so all
failures are surfaced as CipherException; update the existing check that
compares to PQScheme.FN_DSA_512 to run only after successful parsing.

In `@src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java`:
- Around line 136-172: extendedPriv (the decoded extended private key) isn’t
wiped and can remain on the heap; ensure it is zeroed after use by adding a
finally block that calls Arrays.fill(extendedPriv, (byte)0) (guarded with a null
check) around the block that calls wrapper.importWalletPQForCli(...) and uses
result, so the byte[] is cleared on both success and failure; add the necessary
import for java.util.Arrays if missing.

In `@src/main/java/org/tron/walletcli/Client.java`:
- Around line 3238-3276: The password and extPriv buffers in registerWalletPQ
and importWalletPQ can remain in memory if walletApiWrapper.registerWalletPQ or
walletApiWrapper.importWalletPQ throws; move the sensitive-data clearing into
finally blocks so they always run. Concretely, wrap the wrapper calls
(walletApiWrapper.registerWalletPQ in registerWalletPQ;
walletApiWrapper.importWalletPQ in importWalletPQ) in try/finally and call
StringUtils.clear(password) in the finally of both methods, and in
importWalletPQ also call java.util.Arrays.fill(extPriv, (byte)0) (guarding for
null) in the finally so extPriv is zeroed even on exceptions. Ensure you don’t
clear password or extPriv before they’re used and handle the case where password
or extPriv may be null.
- Around line 3285-3305: The input loop in inputPQExtendedPrivateKey currently
accepts any read with len >= hexLen and silently ignores extra bytes; change the
validation so inputs longer than hexLen are rejected instead of truncated: after
reading into temp in inputPQExtendedPrivateKey, verify that the meaningful input
length equals hexLen (or, alternatively, trim trailing newline/whitespace and
then require exact length) and only call StringUtils.hexs2Bytes when the length
matches exactly; if len > hexLen (or trimmed length > hexLen) treat it as
invalid, clear temp via StringUtils.clear(temp), increment nTime and continue
retrying (using the existing retryTime), leaving the rest of the logic
unchanged.

In `@src/main/java/org/tron/walletcli/WalletApiWrapper.java`:
- Around line 252-297: Both registerWalletPQ and importWalletPQ create a
WalletFile but never set a friendly name; call nameWallet(walletFile, false)
after creating the WalletFile (after CreatePQWalletFile) and before calling
WalletApi.store2Keystore so the REPL shows a non-null friendly name. Apply this
to both registerWalletPQ (before keystoreName = WalletApi.store2Keystore(...))
and importWalletPQ (also before store2Keystore; keep the existing
isUnifiedExist()/wallet.getWalletList().add(...) and logout() logic unchanged).

In `@src/main/java/org/tron/walletserver/WalletApi.java`:
- Around line 546-548: The current checks (e.g., in isPQWallet and the branches
that call TransactionUtils.signPQ(...)) treat FN_DSA_512 as a hardcoded gate
instead of resolving the actual keystore scheme from walletFile.getScheme();
change the logic to parse/resolve the scheme enum once from
walletFile.getScheme() (e.g., map to PQScheme or equivalent) and pass that
resolved scheme into TransactionUtils.signPQ(...) so the signing path matches
the wallet metadata; if walletFile.getScheme() is null or cannot be resolved to
a known PQ scheme, fail closed (do not attempt PQ signing) and fall back to the
legacy EC/SM2 path only when appropriate (using the existing isEckey boolean).

In `@src/main/protos/core/Tron.proto`:
- Around line 543-547: The schema currently allows both or neither of the
mutually exclusive auth fields (witness_signature and pq_auth_sig), so change
each paired field group to a protobuf oneof (e.g., oneof auth { bytes
witness_signature = X; PQAuthSig pq_auth_sig = Y; }) to enforce “exactly one” at
the schema level; apply the same oneof refactor to the other pair referenced
(lines 661-663) and update any references to the fields to use the chosen oneof
name (e.g., auth) where necessary.

---

Outside diff comments:
In `@src/main/java/org/tron/keystore/WalletUtils.java`:
- Around line 198-204: The dispatch currently only checks for "FN_DSA_512" and
otherwise falls through to isEckey, which misroutes when walletFile.getScheme()
is non-null but not "FN_DSA_512"; update WalletUtils to inspect
walletFile.getScheme() and, when non-null, explicitly branch on known tags
("FN_DSA_512" -> call CredentialsFalcon.create with Wallet.decryptPQ, "SM2" ->
call CredentialsSM2.create with Wallet.decryptSM2, "ECKEY" -> call
CredentialsEckey.create with Wallet.decrypt); if the scheme is non-null and not
one of these known values throw an IllegalArgumentException (fail fast); retain
the original isEckey-based behavior only when scheme is null.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3cc89e0e-8854-4066-98d3-f60cdfbf3def

📥 Commits

Reviewing files that changed from the base of the PR and between 6712294 and b3070ee.

📒 Files selected for processing (21)
  • CLAUDE.md
  • README.md
  • build.gradle
  • src/main/java/org/tron/common/crypto/pqc/FNDSA512.java
  • src/main/java/org/tron/common/crypto/pqc/PQSchemeRegistry.java
  • src/main/java/org/tron/common/crypto/pqc/PQSignature.java
  • src/main/java/org/tron/common/utils/TransactionUtils.java
  • src/main/java/org/tron/keystore/CredentialsFalcon.java
  • src/main/java/org/tron/keystore/Wallet.java
  • src/main/java/org/tron/keystore/WalletFile.java
  • src/main/java/org/tron/keystore/WalletUtils.java
  • src/main/java/org/tron/walletcli/Client.java
  • src/main/java/org/tron/walletcli/WalletApiWrapper.java
  • src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java
  • src/main/java/org/tron/walletserver/WalletApi.java
  • src/main/protos/core/Tron.proto
  • src/test/java/org/tron/common/crypto/pqc/FNDSA512Test.java
  • src/test/java/org/tron/common/crypto/pqc/PQSchemeRegistryTest.java
  • src/test/java/org/tron/common/crypto/pqc/PQSignatureDefaultsTest.java
  • src/test/java/org/tron/keystore/WalletPQAddressTest.java
  • src/test/java/org/tron/keystore/WalletPQKeystoreTest.java

Comment thread src/main/java/org/tron/common/utils/TransactionUtils.java
Comment thread src/main/java/org/tron/keystore/Wallet.java Outdated
Comment thread src/main/java/org/tron/keystore/Wallet.java Outdated
Comment thread src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java
Comment thread src/main/java/org/tron/walletcli/Client.java Outdated
Comment thread src/main/java/org/tron/walletcli/Client.java Outdated
Comment thread src/main/java/org/tron/walletcli/WalletApiWrapper.java
Comment thread src/main/java/org/tron/walletserver/WalletApi.java Outdated
Comment thread src/main/protos/core/Tron.proto

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

7 issues found across 21 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="src/main/java/org/tron/walletcli/WalletApiWrapper.java">

<violation number="1" location="src/main/java/org/tron/walletcli/WalletApiWrapper.java:261">
P1: Normalize the PQ scheme before persisting the wallet; storing `UNKNOWN_PQ_SCHEME` creates wallets that later fail PQ detection/decryption.</violation>
</file>

<file name="README.md">

<violation number="1" location="README.md:1852">
P2: The README incorrectly says `ImportWalletPQ` can take the extended private key as a second argument, but the command only accepts optional scheme args and always prompts for key input from stdin.</violation>
</file>

<file name="src/main/protos/core/Tron.proto">

<violation number="1" location="src/main/protos/core/Tron.proto:547">
P2: `BlockHeader` documents signature-field exclusivity but does not enforce it; both signature fields can be set simultaneously.</violation>

<violation number="2" location="src/main/protos/core/Tron.proto:663">
P2: `HelloMessage` claims `signature` and `pq_auth_sig` are mutually exclusive, but the proto schema does not enforce that.</violation>
</file>

<file name="src/main/java/org/tron/walletcli/Client.java">

<violation number="1" location="src/main/java/org/tron/walletcli/Client.java:3209">
P2: Normalize the parsed PQ scheme before returning it; returning `UNKNOWN_PQ_SCHEME` unchanged can create keystores that are later treated as non-PQ wallets.</violation>
</file>

<file name="src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java">

<violation number="1" location="src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java:51">
P2: Validate `--scheme` against supported registry entries, not only `UNKNOWN_PQ_SCHEME`; otherwise unsupported enum values can pass parsing and lead to inconsistent command behavior.</violation>
</file>

<file name="src/main/java/org/tron/keystore/CredentialsFalcon.java">

<violation number="1" location="src/main/java/org/tron/keystore/CredentialsFalcon.java:65">
P1: `getPair()` throwing here breaks existing `Credentials` call sites for FN_DSA_512 wallets, causing runtime failures where code still assumes all `Credentials` provide a `SignInterface` pair.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/main/java/org/tron/walletcli/WalletApiWrapper.java Outdated
Comment thread src/main/java/org/tron/keystore/CredentialsFalcon.java Outdated
Comment thread README.md Outdated
Comment thread src/main/protos/core/Tron.proto
Comment thread src/main/protos/core/Tron.proto
Comment thread src/main/java/org/tron/walletcli/Client.java
Comment thread src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

♻️ Duplicate comments (1)
src/main/java/org/tron/walletcli/WalletApiWrapper.java (1)

252-316: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

REPL PQ wallets register with a null friendly name.

Both registerWalletPQ (252-271) and importWalletPQ (278-316) skip the nameWallet(walletFile, false) call that legacy registerWallet (line 213) and importWallet (line 234) perform before store2Keystore. As a result, the PQ wallet entries show as null in selectWalletFileByList until loginAll falls back to the filesystem name at line 674. Add nameWallet(walletFile, false) right after CreatePQWalletFile(...) and before store2Keystore(...) in both REPL methods to match the legacy flow.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/org/tron/walletcli/WalletApiWrapper.java` around lines 252 -
316, registerWalletPQ and importWalletPQ create PQ WalletFile via
WalletApi.CreatePQWalletFile but never assign a friendly name, causing null
entries; after the WalletFile is created (the WalletFile variable from
CreatePQWalletFile) call nameWallet(walletFile, false) before invoking
WalletApi.store2Keystore(...) in both registerWalletPQ and importWalletPQ so the
keystore entry gets the same friendly-name initialization as legacy
registerWallet/importWallet.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 1822-1901: The new PQ docs block in README.md violates
markdownlint rules MD046 and MD028; fix by normalizing all code fences to the
repository style (use triple-backtick fenced blocks with a language tag like
```console consistently for the examples around the "Register a PQ wallet" and
"Import a PQ wallet" sections and the example command blocks) and remove any
blank lines inside blockquotes (ensure lines beginning with '>' such as the CLI
description and the "Why no interactive prompt?" block have no empty lines
between '>' lines). Also ensure blockquote lines are consistently prefixed with
'> ' and that code blocks are separated from surrounding text as per the repo's
linting convention so MD046/MD028 no longer trigger.

In `@src/main/java/org/tron/keystore/Wallet.java`:
- Around line 352-369: createPQ currently only checks key lengths and then uses
the caller-supplied publicKey without verifying it matches the secret material;
derive the public key from the provided secret material (use extendedPrivateKey
when present, otherwise derive from seed) via the PQ scheme's public-key
derivation routine (e.g., the PQSchemeRegistry/PQ scheme implementation
associated with scheme) and compare the derived public key byte-for-byte to the
supplied publicKey; if they differ, throw a CipherException indicating a
mismatched public key. Place this validation in createPQ (after the
extendedPrivateKey/seed length checks and before any address
derivation/serialization) and reference publicKey, extendedPrivateKey, seed,
createPQ, PQSchemeRegistry and decryptPQ in the message for clarity.
- Around line 616-630: The PQ decryption path must only accept scrypt KDFs:
update deriveScryptKey so it only handles WalletFile.ScryptKdfParams
(generateDerivedScryptKey) and remove the branch that accepts
WalletFile.Aes128CtrKdfParams; if the kdfParams is not an instance of
ScryptKdfParams throw a CipherException (do not fall back to PBKDF2/AES-CTR).
Ensure decryptPQ(...) calls this updated deriveScryptKey so FN_DSA_512 and other
PQ keystores cannot be decrypted under PBKDF2 by mistake.

In `@src/main/java/org/tron/walletcli/Client.java`:
- Around line 3269-3286: The method importWalletPQ treats the single-argument
form as a scheme and exits early because parsePQScheme(parameters) returns null;
fix by handling the single-argument (hex|path) case before parsing the scheme:
if parameters.length == 1 (or extractPQHexArg(parameters) != null) treat
parameters[0] as hexOrPathArg and set a default or required scheme accordingly,
otherwise call parsePQScheme(parameters) to read an explicit scheme; update the
logic around parsePQScheme, extractPQHexArg, and the subsequent
expected/key-length checks so the documented one-argument usage reaches the
hex/path handling instead of returning early.

In `@src/main/java/org/tron/walletcli/WalletApiWrapper.java`:
- Around line 278-316: The importWalletPQ implementation must verify that when
both seed and extendedPrivateKey are provided they represent the same keypair:
instantiate two FNDSA512 objects (one via
FNDSA512.fromPrivateKeyWithPublicKey(extendedPrivateKey) and one via new
FNDSA512(seed)), compare their public keys (signer.getPublicKey()) and/or
privateWithPublic (getPrivateKeyWithPublicKey()) for equality, and if they
differ return/throw an error instead of silently persisting inconsistent data
(update the logic around the current branch that picks signer and the call to
WalletApi.CreatePQWalletFile); apply the same check to importWalletPQForCli as
well.

In `@src/main/resources/help_summary.txt`:
- Line 153: The summary for ImportWalletPQ is misleadingly specific to "extended
private key"; update the one-line description for the ImportWalletPQ command to
reflect both supported input formats (seed and extended private key / xprv),
e.g., change the text around the ImportWalletPQ entry so it mentions "seed or
extended private key" (or "seed/xprv") to match the actual accepted formats
implemented by the ImportWalletPQ command.

In `@src/test/java/org/tron/keystore/WalletPQKeystoreTest.java`:
- Around line 117-118: The test currently mutates the MAC with data-dependent
replaces; instead, deterministically flip a single known nibble so the MAC
always changes: read the MAC from walletFile.getCrypto().getMac(), compute a
deterministic mutation of one hex character (e.g. take the last hex char, map it
to a different valid hex digit or xor its nibble value with 0x1), then call
walletFile.getCrypto().setMac(...) with the modified string; apply the same
deterministic-nibble-flip approach to the other instance referenced around
WalletPQKeystoreTest (the second getMac()/setMac() pair).

---

Duplicate comments:
In `@src/main/java/org/tron/walletcli/WalletApiWrapper.java`:
- Around line 252-316: registerWalletPQ and importWalletPQ create PQ WalletFile
via WalletApi.CreatePQWalletFile but never assign a friendly name, causing null
entries; after the WalletFile is created (the WalletFile variable from
CreatePQWalletFile) call nameWallet(walletFile, false) before invoking
WalletApi.store2Keystore(...) in both registerWalletPQ and importWalletPQ so the
keystore entry gets the same friendly-name initialization as legacy
registerWallet/importWallet.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: da6a818e-3679-45d3-94ad-c655a0b9af71

📥 Commits

Reviewing files that changed from the base of the PR and between b3070ee and 11407f2.

📒 Files selected for processing (10)
  • README.md
  • src/main/java/org/tron/keystore/Wallet.java
  • src/main/java/org/tron/keystore/WalletFile.java
  • src/main/java/org/tron/walletcli/Client.java
  • src/main/java/org/tron/walletcli/WalletApiWrapper.java
  • src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java
  • src/main/java/org/tron/walletserver/WalletApi.java
  • src/main/resources/commands.txt
  • src/main/resources/help_summary.txt
  • src/test/java/org/tron/keystore/WalletPQKeystoreTest.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/java/org/tron/walletserver/WalletApi.java
  • src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java

Comment thread README.md
Comment thread src/main/java/org/tron/keystore/Wallet.java
Comment thread src/main/java/org/tron/keystore/Wallet.java Outdated
Comment thread src/main/java/org/tron/walletcli/Client.java
Comment thread src/main/java/org/tron/walletcli/WalletApiWrapper.java
Comment thread src/main/resources/help_summary.txt Outdated
Comment thread src/test/java/org/tron/keystore/WalletPQKeystoreTest.java Outdated
@Federico2014 Federico2014 changed the title feat(pqc): add FN-DSA-512 post-quantum signature support feat(pqc): add Falcon-512 / FN-DSA-512 post-quantum signature support May 14, 2026

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 23 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="src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java">

<violation number="1" location="src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java:98">
P2: When `MASTER_PASSWORD` is missing, the handler returns before wiping decoded PQ key bytes. Clear the decoded buffer before this early return to avoid leaving sensitive key material in memory.</violation>
</file>

<file name="src/main/java/org/tron/walletcli/Client.java">

<violation number="1" location="src/main/java/org/tron/walletcli/Client.java:3216">
P2: `ImportWalletPQ <hex|path>` is currently broken: non-scheme single arguments are rejected as "Unsupported PQ scheme" before key-material extraction runs.</violation>
</file>

<file name="src/main/java/org/tron/keystore/WalletUtils.java">

<violation number="1" location="src/main/java/org/tron/keystore/WalletUtils.java:199">
P1: Returning `CredentialsFalcon` from `loadCredentials` breaks existing call sites that immediately use `credentials.getPair()`, causing runtime `UnsupportedOperationException` for FN_DSA_512 wallets.</violation>
</file>

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Comment thread src/main/java/org/tron/keystore/WalletUtils.java Outdated
Comment thread src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java
Comment thread src/main/java/org/tron/walletcli/Client.java
@Federico2014 Federico2014 changed the title feat(pqc): add Falcon-512 / FN-DSA-512 post-quantum signature support feat(pqc): add FN-DSA-512 post-quantum signature support May 15, 2026
coderabbitai[bot]

This comment was marked as resolved.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

4 issues found across 14 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="src/main/java/org/tron/walletserver/WalletApi.java">

<violation number="1" location="src/main/java/org/tron/walletserver/WalletApi.java:551">
P2: Parsing `walletFile.scheme` as a PQ enum and throwing on mismatch can break signing for non-PQ wallets that carry legacy scheme tags (e.g., `SM2`/`ECKEY`). Treat non-PQ/unknown values as non-PQ so EC/SM2 fallback still works.</violation>
</file>

<file name="src/main/java/org/tron/common/crypto/jce/TronCastleProvider.java">

<violation number="1" location="src/main/java/org/tron/common/crypto/jce/TronCastleProvider.java:42">
P2: Re-registering an existing BC provider (`removeProvider` + `addProvider`) unintentionally changes global provider precedence. This can alter algorithm/provider selection in unrelated crypto calls.</violation>
</file>

<file name="src/main/java/org/tron/common/utils/TransactionUtils.java">

<violation number="1" location="src/main/java/org/tron/common/utils/TransactionUtils.java:344">
P0: PQ transaction validation is only checking field presence, not signature validity/owner binding, so forged `pqAuthSig` entries can be accepted as valid.</violation>
</file>

<file name="src/main/java/org/tron/keystore/Wallet.java">

<violation number="1" location="src/main/java/org/tron/keystore/Wallet.java:370">
P2: Handle `IllegalArgumentException` from extended-key parsing and rethrow `CipherException` so `createPQ` fails through its declared error contract.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src/main/java/org/tron/common/utils/TransactionUtils.java Outdated
Comment thread src/main/java/org/tron/walletserver/WalletApi.java
Comment thread src/main/java/org/tron/common/crypto/jce/TronCastleProvider.java Outdated
Comment thread src/main/java/org/tron/keystore/Wallet.java
@Federico2014 Federico2014 force-pushed the feature/pq-fn-dsa-512 branch from a81b8db to a19f806 Compare May 15, 2026 08:45
@Federico2014 Federico2014 changed the title feat(pqc): add FN-DSA-512 post-quantum signature support feat(pqc): add post-quantum signature support (Falcon-512, ML-DSA-44) May 27, 2026
@Federico2014 Federico2014 changed the title feat(pqc): add post-quantum signature support (Falcon-512, ML-DSA-44) feat(pqc): add post-quantum signature support May 27, 2026
coderabbitai[bot]

This comment was marked as resolved.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

5 issues found across 19 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/main/java/org/tron/keystore/WalletUtils.java
Comment thread src/main/resources/commands.txt
Comment thread src/main/java/org/tron/keystore/CredentialsFalcon.java Outdated
Comment thread src/main/java/org/tron/walletcli/cli/commands/WalletCommands.java
Comment thread src/main/java/org/tron/walletcli/WalletApiWrapper.java Outdated
@Federico2014 Federico2014 force-pushed the feature/pq-fn-dsa-512 branch from dcf663f to a54feda Compare May 27, 2026 12:33
Mirrors the protocol added by java-tron's ALLOW_FN_DSA_512 proposal so
wallet-cli can generate, import, store, and transact with PQ keypairs.

Highlights:
- Proto sync: PQScheme, PQAuthSig, and pq_auth_sig fields on Transaction
  / BlockHeader / HelloMessage (additive, backwards compatible).
- BouncyCastle 1.78.1 -> 1.84 for org.bouncycastle.pqc.crypto.falcon.*.
- Crypto layer (org.tron.common.crypto.pqc): FNDSA512, PQSchemeRegistry,
  PQSignature. Address is 0x41 || Keccak-256(pubkey)[12..32], reusing
  Hash.sha3omit12.
- Keystore: WalletFile.scheme discriminator (null/ECKEY for legacy,
  FN_DSA_512 for Falcon). Wallet.createStandardPQ / decryptPQ reuse the
  existing scrypt+AES-CTR plumbing to encrypt the 2176-byte extended
  private key (f||g||F||h). New CredentialsFalcon wraps the FNDSA512
  signer; deliberately not part of the SignInterface union.
- Signing path: TransactionUtils.signPQ routes signatures into
  Transaction.pq_auth_sig instead of Transaction.signature. WalletApi
  dispatches per-wallet via WalletFile.scheme; the process-wide isEckey
  selector is untouched for ECKey/SM2.
- REPL commands: generatePQKey, registerWalletPQ, importWalletPQ.
- Standard CLI commands: generate-pq-key, register-wallet-pq,
  import-wallet-pq (MASTER_PASSWORD env-var auth, JSON output).
- Tests: FNDSA512Test, PQSchemeRegistryTest, PQSignatureDefaultsTest,
  WalletPQAddressTest, WalletPQKeystoreTest.
- Docs: README.md gains a Post-quantum signatures section; CLAUDE.md
  documents per-wallet dispatch and the pqc package surface.
@Federico2014 Federico2014 force-pushed the feature/pq-fn-dsa-512 branch 2 times, most recently from 2b54cfa to d6d60e8 Compare May 28, 2026 09:23
@Federico2014 Federico2014 force-pushed the feature/pq-fn-dsa-512 branch from d6d60e8 to 1d04b6a Compare May 28, 2026 09:51

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/main/java/org/tron/keystore/Wallet.java Outdated
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