Skip to content

[Feature] Optimize secp256k1 signature performance #53

Description

@Federico2014

Summary

Introduce an optional JNA-backed native secp256k1 implementation for key construction, deterministic signing, public-key recovery, and signature-address recovery while retaining the existing pure-Java ECKey implementation as the default.

Problem

Motivation

java-tron currently performs secp256k1 signing and signature recovery through the pure-Java ECKey implementation. These operations are used across transaction processing, block production, and PBFT signature validation, so their cost directly affects node throughput and block-processing latency.

The broader cryptographic optimization analysis in tronprotocol/java-tron#6374 compared java-tron with Besu's native secp256k1 implementation. On Ubuntu x86_64, native EcRecover and secp256k1 verification were approximately 18x faster than java-tron. The same issue also identified native libraries as a useful optimization path for other computationally intensive cryptographic primitives.

A preliminary proof-of-concept benchmark produced the following local results on an x86_64 Java 8 environment with 5,000 measured iterations:

Operation ECKey NativeSecp256k1 Speedup
Deterministic signing 2,531,811 ns/op 78,912 ns/op 32.08x
Signature-address recovery 1,394,938 ns/op 84,174 ns/op 16.57x

Current State

  • ECKey uses the existing Java/Bouncy Castle implementation for secp256k1 operations.
  • There is no production API for explicitly performing native deterministic signing.
  • Signature recovery paths cannot be switched between Java and native implementations through node configuration.
  • Some PBFT verification paths call ECKey directly instead of using the shared signature routing abstraction.

Limitations or Risks

  • JNA introduces platform-specific native dependencies and a different failure model from pure Java code.
  • A native crash can terminate the JVM, so native acceleration in consensus-sensitive paths must remain operationally controllable.
  • Signing and recovery results must remain byte-for-byte compatible with ECKey; any difference could affect address recovery or consensus behavior.
  • Availability must be verified across the supported x86_64/JDK 8 and aarch64/JDK 17 build environments.

Proposed Solution

Proposed Design

Add NativeSecp256k1, backed by bitcoin-core's libsecp256k1 through JNA, with the following behavior:

  • Provide constructors compatible with common ECKey usage: default key generation, caller-provided SecureRandom, and caller-provided private-key bytes.
  • Provide an explicit production signing API that returns ECKey.ECDSASignature and preserves deterministic signing, recovery IDs, and canonical low-S encoding.
  • Provide native public-key and TRON-address recovery for both Base64 signatures and ECDSASignature components.
  • Validate message hashes, private-key ranges, signature component sizes, and recovery headers before invoking native code.
  • Clear temporary private-key byte arrays after native operations.
  • Preserve historical signature compatibility, including accepted recovery headers and high-S recovery behavior.

Add an opt-in configuration switch:

crypto {
  engine = "eckey"
  useNativeSecp256k1 = false
}

The switch affects signature verification/address recovery only. Native signing remains an explicit API choice so enabling verification does not silently change existing key-generation or signing behavior.

When native secp256k1 is requested but unavailable, java-tron keeps the Java ECKey verification path. The switch is effective only when crypto.engine = "eckey"; SM2 behavior remains unchanged.

Key Changes

  • Add the native secp256k1 implementation and explicit signing API in the crypto module.
  • Route configurable ECKey signature recovery through SignUtils.
  • Initialize the effective runtime selection from Args and reset it during configuration cleanup.
  • Route PBFT signature checks through SignUtils instead of direct ECKey calls.
  • Add JNA and native secp256k1 dependencies with Gradle dependency verification metadata.
  • Add Java/native interoperability tests and an opt-in local benchmark.

Test Specification

  • Verify that Java and native deterministic signatures are byte-for-byte and Base64 identical.
  • Cross-check Java signatures with native recovery and native signatures with Java recovery across multiple private keys and message hashes.
  • Verify constructor-generated public keys, addresses, and signatures against ECKey.
  • Verify compatibility for high-S signatures and Base64 signatures with historically accepted trailing bytes.
  • Reject invalid hashes, private keys, oversized signature components, and invalid recovery headers without truncation.
  • Verify configuration behavior for eckey, SM2, unavailable native libraries, and configuration cleanup.
  • Run focused PBFT and crypto regression tests.
  • Benchmark signing and signature-address recovery with warmup on supported x86_64 and aarch64 environments.

Impact

  • Reduces secp256k1 signing and signature-recovery latency when native acceleration is used.
  • Improves high-volume transaction and PBFT signature-processing performance.
  • Does not change signature wire formats, recovered addresses, or consensus rules.
  • Does not require a hard fork because the feature is a local implementation choice with identical outputs.
  • Introduces native-library operational risk, mitigated by default-disabled configuration and retention of the Java implementation.

Compatibility

  • Breaking Change: No
  • Default Behavior Change: No; native verification is disabled by default
  • Migration Required: No
  • Configuration Required: Only for operators who explicitly opt in

References

Additional Notes

  • Do you have ideas regarding implementation? Yes; the proposed native JNA design is described above.
  • Are you willing to implement this feature? Yes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions