Hi BC team — a couple of questions on the Falcon implementation in org.bouncycastle.pqc.crypto.falcon (relevant to wallet / HD-key derivation and blockchain consensus use cases). Apologies if any of this is already documented somewhere I missed.
Context
We're evaluating Falcon-512 for a blockchain protocol's post-quantum signature path. Two invariants we need to hold:
- Wallet side — keys derived from a user-controlled seed (e.g. BIP-39 mnemonic) must produce the same public key / address on every platform the user might restore their wallet on. Same seed, same account, everywhere.
- Consensus side — every full node must reach the same verify result (accept/reject) for the same
(publicKey, message, signature) regardless of the host platform. A single divergence would split consensus.
The matrix we care about
Keygen needs to be deterministic and bit-identical across this matrix when driven from the same seed. Signing is randomized in Falcon, so repeated signatures are not expected to be byte-identical; the signing and verification paths still need to be cross-platform stable and interoperable across this matrix:
| Dimension |
Examples |
| OS |
Linux, macOS, Windows, Android, iOS |
| CPU architecture |
x86_64, ARM64, 32-bit ARM |
| JDK / runtime |
OpenJDK 8 / 11 / 17 / 21, GraalVM native-image, Android Runtime (ART), restricted JVMs on hardware wallets |
| JIT / execution mode |
C1, C2, interpreter-only, AOT |
Background: Falcon's reference implementation has two code paths — a native floating-point path (fast, but double arithmetic can drift across FPUs, JIT optimization levels, strictfp settings, and JDK versions) and an emulated floating-point path (software-emulated IEEE 754 over integers, slower but bit-identical across platforms; provided in the upstream Falcon reference at falcon-sign.info and inherited by PQClean). The choice of path is the main determinism risk.
Questions
1. Seed-based deterministic keygen
Does FalconKeyPairGenerator support deterministic keygen from a caller-supplied seed (e.g. by passing a SecureRandom backed by a fixed seed via FalconKeyGenerationParameters)? Concretely: given the same input seed bytes, will two invocations of generateKeyPair() produce the same (publicKey, privateKey) byte-for-byte?
If yes, are there any caveats (JDK version, JVM flags, internal use of ThreadLocalRandom / System.nanoTime / non-seeded sources) that could break determinism?
2. Keygen determinism across the matrix
Assuming question 1 is yes — does FalconKeyPairGenerator produce bit-identical keypairs from the same seed across every cell of the matrix above?
- Which keygen code path does BC use today — native FP or emulated FP?
- If native FP: has anyone tested the matrix for keygen determinism, or is drift known to occur?
- If determinism is not currently guaranteed, would the BC project be open to offering an emulated-FP keygen mode (e.g. opt-in via
FalconParameters) so wallets and the protocol can rely on same-seed → same-key?
3. Signing correctness and cross-platform stability
Falcon signing is randomized, so we do not require repeated signing of the same message with the same private key to produce identical signature bytes.
- Does
FalconSigner use floating-point at sign time?
- Are signatures generated on every supported platform guaranteed to verify correctly on every other supported platform?
- Are there any known platform-dependent floating-point behaviors in signing that can cause invalid signatures or interoperability failures?
4. Verification determinism across the matrix
- Does
FalconSigner.verifySignature use floating-point at verify time? Even if verify is "just" accept/reject, any FP-dependent intermediate computation could in principle drift across platforms and cause a single full-node to disagree.
- Are there tests in BC that exercise verify with fixed
(publicKey, message, signature) vectors and confirm identical accept/reject across the matrix above?
Why this matters
Concrete failure modes we're trying to rule out:
- Wallet portability break — a user's seed derives one Falcon pubkey on a desktop wallet (server-class JDK on x86_64 Linux) and a different pubkey on a mobile wallet (ART on ARM64 Android) or hardware wallet (restricted JVM on 32-bit ARM). Seed backup is no longer portable. Wallet recovery is broken.
- Consensus split — two full nodes verifying the same signature reach different accept/reject results, forking the chain.
- Signer interoperability break — a signature produced by a signer on one supported platform fails to verify on another platform because signing-side platform behavior produces an invalid or non-portable signature.
If BC already guarantees matrix-stable keygen and cross-platform sign / verify interoperability, great — happy to be pointed at the API surface and test coverage. If not, we'd like to discuss whether an emulated-FP path is something the BC project would be open to upstreaming, ideally toggleable so existing perf-sensitive users aren't affected.
Thanks for the work on PQ algorithms in BC — this is one of the few mature Java implementations available.
Hi BC team — a couple of questions on the Falcon implementation in
org.bouncycastle.pqc.crypto.falcon(relevant to wallet / HD-key derivation and blockchain consensus use cases). Apologies if any of this is already documented somewhere I missed.Context
We're evaluating Falcon-512 for a blockchain protocol's post-quantum signature path. Two invariants we need to hold:
(publicKey, message, signature)regardless of the host platform. A single divergence would split consensus.The matrix we care about
Keygen needs to be deterministic and bit-identical across this matrix when driven from the same seed. Signing is randomized in Falcon, so repeated signatures are not expected to be byte-identical; the signing and verification paths still need to be cross-platform stable and interoperable across this matrix:
Background: Falcon's reference implementation has two code paths — a native floating-point path (fast, but
doublearithmetic can drift across FPUs, JIT optimization levels,strictfpsettings, and JDK versions) and an emulated floating-point path (software-emulated IEEE 754 over integers, slower but bit-identical across platforms; provided in the upstream Falcon reference at falcon-sign.info and inherited by PQClean). The choice of path is the main determinism risk.Questions
1. Seed-based deterministic keygen
Does
FalconKeyPairGeneratorsupport deterministic keygen from a caller-supplied seed (e.g. by passing aSecureRandombacked by a fixed seed viaFalconKeyGenerationParameters)? Concretely: given the same input seed bytes, will two invocations ofgenerateKeyPair()produce the same(publicKey, privateKey)byte-for-byte?If yes, are there any caveats (JDK version, JVM flags, internal use of
ThreadLocalRandom/System.nanoTime/ non-seeded sources) that could break determinism?2. Keygen determinism across the matrix
Assuming question 1 is yes — does
FalconKeyPairGeneratorproduce bit-identical keypairs from the same seed across every cell of the matrix above?FalconParameters) so wallets and the protocol can rely on same-seed → same-key?3. Signing correctness and cross-platform stability
Falcon signing is randomized, so we do not require repeated signing of the same message with the same private key to produce identical signature bytes.
FalconSigneruse floating-point at sign time?4. Verification determinism across the matrix
FalconSigner.verifySignatureuse floating-point at verify time? Even if verify is "just" accept/reject, any FP-dependent intermediate computation could in principle drift across platforms and cause a single full-node to disagree.(publicKey, message, signature)vectors and confirm identical accept/reject across the matrix above?Why this matters
Concrete failure modes we're trying to rule out:
If BC already guarantees matrix-stable keygen and cross-platform sign / verify interoperability, great — happy to be pointed at the API surface and test coverage. If not, we'd like to discuss whether an emulated-FP path is something the BC project would be open to upstreaming, ideally toggleable so existing perf-sensitive users aren't affected.
Thanks for the work on PQ algorithms in BC — this is one of the few mature Java implementations available.