Skip to content

Falcon: seeded keygen and cross-platform stability? #2305

@Federico2014

Description

@Federico2014

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:

  1. 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.
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions