Repository navigation
Optimizing cryptographic algorithm implementations #6374
Description
Background
Currently, the BN128Addition, BN128Multiplication, and BN128Pairing precompiled contracts suffer from performance bottlenecks, leading to transaction timeouts and limiting the application of zero-knowledge proofs on the TRON network, as shown in #4311 and #5492.
The zkBob team has proposed two optimization approaches:
-
The first one, described in #5507, wraps the arkworks cryptographic library via JNI. It offers significantly higher performance, achieving a 3x to 30x speedup for BN128 precompiled contracts.
-
The second one, described in #5611, uses Montgomery optimizations. This results in a 17% performance degradation for
BN128Addition, but offers around 30% improvement forBN128MultiplicationandBN128Pairing.
To optimize BN128 precompiled contract performance, Besu supports two implementations:
-
A pure Java implementation;
-
A gnark-crypto wrapper using JNA.
We conducted a comprehensive benchmark of these implementations:
Test results on macOS (2.6 GHz 6-Core Intel Core i7, 16GB RAM), in microseconds (μs):
| BN128Addition | BN128Multiplication | BN128Pairing (2 pairs) | |
|---|---|---|---|
| java-tron | 32.718 | 2584.739 | 62751.503 |
| arkworks | 12.971 | 97.659 | 1792.001 |
| Montgomery | 41.512 | 1731.617 | 41900.001 |
| besu-java | 6.5 | 14163.3 | 1295543.0 |
| besu-gnark | 4.1 | 55.5 | 654.2 |
On Ubuntu 22.04.5 LTS, AMD x86_64, 16 cores, 32GB RAM, the benchmark results (μs):
| BN128Addition | BN128Multiplication | BN128Pairing (2 pairs) | |
|---|---|---|---|
| java-tron | 23.654 | 1896.336 | 46889.459 |
| arkworks | 5.154 | 83.243 | 1646.457 |
| Montgomery | 29.903 | 1543.336 | 35772.447 |
| besu-java | 2.5 | 10413.6 | 796687.1 |
| besu-gnark | 2.4 | 53.5 | 655.9 |
Taking the Ubuntu results as an example, we can see that integrating arkworks significantly improves the performance of BN128 precompiled contracts on java-tron:
-
BN128Addition: ~2.5× speedup -
BN128Multiplication: ~26× speedup -
BN128Pairing: ~35× speedup
Moreover, java-tron’s performance is far behind the besu-gnark implementation:
-
BN128Addition: ~10× slower -
BN128Multiplication: ~35× slower -
BN128Pairing: ~71× slower
Taking this Groth16 contract example, which involves 6 BN128Addition, 5 BN128Multiplication, and 4 BN128Pairing operations:
-
java-tronexecution time:6×23.654+5×1896.336+2×46889.459≈103402.44 μs
-
arkworksexecution time:6×5.154+5×83.243+2×1646.457≈3740.05 μs( 27.6×faster)
-
besu-gnarkexecution time:6×2.4+5×53.5+2×655.9≈1593.70 μs( 65×faster)
In addition to BN128 precompiled contracts, Besu has also optimized EcRecover and Secp256k1 signature verification. The besu-java implementation uses the BouncyCastle library, while besu-native wraps bitcoin-core/secp256k1 via JNA. We benchmarked and compared their performance as well:
Test results on macOS (2.6 GHz 6-Core Intel Core i7, 16GB RAM), in μs:
| EcRecover | Secp256k1 | ModExp | |
|---|---|---|---|
| java-tron | 1956.975 | 1218.343 | 58.418 |
| besu-java | 959.4 | 891.7 | 21.222 |
| besu-native | 50.6 | 45.3 | 34.585 |
Test results on Ubuntu 22.04.5 LTS, AMD x86_64, 16 cores, 32GB RAM:
| EcRecover | Secp256k1 | ModExp | |
|---|---|---|---|
| java-tron | 916.184 | 875.647 | 20.168 |
| besu-java | 679.2 | 670.2 | 16.428 |
| besu-native | 50.4 | 47.3 | 34.165 |
From the Ubuntu benchmark results, we can see that besu-native achieves ~18× speedup over java-tron in both EcRecover and Secp256k1 signature verification. For ModExp, the performance difference is smaller, possibly due to limited test coverage.
From the above benchmarks, it is clear that optimizing the performance of the BN128 precompiled contracts and other cryptographic algorithms is necessary. The besu-native implementation serves as a strong reference, as it also includes optimized support for Blake2bf and BLS12-381, which can help improve the scalability of the TRON network.
Rationale
Why should this feature exist?
- Optimize the performance of
BN128precompiled contracts to avoid transaction timeouts and promote ZK-based applications on the TRON network; - Accelerate
EcRecoverandSecp256k1signature verification to improve TRON’s scalability; - Optimize additional cryptographic primitives such as
ModExp,Blake2bf, andBLS12-381.
What are the use-cases?
- ZK application developers;
- Reducing signature verification time for all TRON transactions;
Specification
- Replace the current java-tron
BN128precompiled contract implementation with the optimized version; - Replace the current java-tron implementation of
EcRecoverandSecp256k1with optimized versions; - Apply similar performance improvements to other cryptographic primitives.
Test Specification
- Benchmark execution speed of the optimized
BN128precompiled contract and compare it to the current implementation; - Benchmark
EcRecoverandSecp256k1verification performance before and after optimization; - Measure execution time of ZK-related transactions before and after optimization;
- Measure execution time of regular transactions before and after optimization;
Scope Of Impact
BN128andEcRecoverprecompiled contracts;- Reduced transaction processing time by accelerating signature verification;
- Potential gas cost adjustments for affected precompiled contracts;
- Performance improvements must preserve consensus correctness to avoid network forks, requiring proposal-level changes;
- As signature verification is a major performance bottleneck in block production, improvements should be evaluated in the context of block time scheduling.
Implementation
Do you have ideas regarding the implementation of this feature?
Currently, the optimization of BN128 precompiled contracts mainly considers two implementations: arkworks and besu-gnark. The arkworks-based version has already been developed by the zkBob team (see #5507), but recent benchmarks show that besu-gnark performs slightly better. Since besu-native relies on JDK 21, we also need to evaluate how to maintain compatibility with JDK 8.
A thorough discussion is still required to evaluate the advantages and potential risks of each solution before choosing the final optimization path. For EcRecover and Secp256k1, it should also be discussed within the community whether to adopt the optimization strategy used in besu-native.
Are you willing to implement this feature?
Y
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsIn Progress
Activity
jwrct commentedon Jul 2, 2025
@Federico2014 From the benchmark results you provided, it seems that the performance of java-tron's signature verification is really bad, and this optimization seems to be necessary. besu-gnark is undoubtedly the best, but java-tron currently only supports JDK 8, but I see that there are already issues discussing support for higher versions of JDK, for example: #5976.
Federico2014 commentedon Jul 2, 2025
@jwrct
besu-nativeis built with JDK 21, while java-tron is based on JDK 8, so it cannot be used directly. Currently, we haven't decided how to handle the JDK compatibility issue. Alternatively, we could consider modifyingbesu-nativeto downgrade it to JDK 8.jwrct commentedon Jul 2, 2025
@Federico2014 OK, I understand. If there is any progress, please update in time. I am looking forward to the implementation of this optimization.
Federico2014 commentedon Jul 2, 2025
I also tested the execution time for verifying a single Groth16 proof transaction under three scenarios:
java-tron,arkworks, andMontgomery. The test environment was a Mac with a 2.6 GHz 6-core Intel Core i7 and 16GB of RAM. The transaction timeout in java-tron was set to 200 ms.All test cases executed the same transaction for verifying a Groth16 proof, and the execution time was measured separately in the
broadcast,pack, andapplystages. The test results are as follows (unit: ms):java-tron
arkworks
Montgomery
From the above test results, it can be seen that with the
arkworksoptimization, the execution time for verifying a single Groth16 proof transaction stays within 50 ms. However, with the currentjava-tronimplementation andMontgomeryoptimization, the execution time is less stable — even with the transaction timeout set to 200 ms, sometimes the transaction executes successfully, but other times it fails due to a timeout.SeriousCoding789 commentedon Jul 2, 2025
Will downgrade it to JDK 8 decrease the algorithm performance?
Federico2014 commentedon Jul 2, 2025
I think the impact should be relatively small.
Federico2014 commentedon Jul 10, 2025
I have modified
besu-nativeto make it compatible with JDK 8 and integrated it intojava-tron. After that, I conducted benchmarks for theBN128precompiled contract.Test results on macOS (2.6 GHz 6-Core Intel Core i7, 16GB RAM), in μs:
Based on the test results above, after integrating
besu-gnarkintojava-tron, the performance of bothBN128MulandBN128Pairinghas significantly improved. However,BN128Addshows no noticeable performance gain. I noticed that inbesu-native, benchmarking is performed after a warm-up phase, where the precompiled contracts are executed multiple times beforehand. This allows the JVM to complete class loading, method compilation, and other preparations, preventing first-time execution overhead from affecting the benchmark results. After introducing a similar warm-up phase, my test results are as follows:The benchmark results of
java-tron-gnarkare very close to those ofbesu-gnark, indicating that integratingbesu-gnarkintojava-troncan effectively improve the performance ofBN128precompiled contracts. The performance ofBN128Addition,BN128Multiplication, andBN128Pairinghas improved by 6x, 47x, and 97x, respectively. Moreover, it proves to be more efficient than thearkworks-based implementation.Federico2014 commentedon Jul 10, 2025
Similarly, I also tested the execution time of
Groth16proof verification transactions usingjava-tron-gnark. The results are as follows (unit: ms):From the results, we can see that for
Groth16proof verification transactions, the execution time usingjava-tron-gnarkis comparable to thearkworks-optimized implementation — both stay within 40 ms. This ensures smooth execution of zero-knowledge related transactions.lxcmyf commentedon Jul 10, 2025
Glad to see running the benchmarks and sharing the results — the sub-40 ms latency is indeed promising.
Just to clarify:
This distinction would help assess whether the performance can scale in more complex or production settings.
15 remaining items
Federico2014 commentedon Sep 29, 2025
Status Update: Given the critical importance of cryptographic algorithms to overall security, the ongoing optimizations are currently undergoing comprehensive and rigorous testing to ensure robustness, stability, and performance. This feature is scheduled for the next release after 4.8.1. Please stay tuned.
nkoreli commentedon Mar 6, 2026
Hi, @Federico2014 is there an estimated timeline for when this optimization will be merged? We're building a privacy protocol (Hinkal) that relies on zero-knowledge proof verification on TRON. The current BN128 pairing performance causes transaction timeouts during Groth16 proof verification, which is core to our shielded transaction flow. This is a blocker for us on TRON.
Thanks!
Federico2014 commentedon Mar 6, 2026
@nkoreli According to the current plan, the optimized BN128 pairing implementation is expected to be included in v4.8.2, which is scheduled for release in about 3 months. However, to ensure security and stability, whether it will be released will still depend on the actual testing results. Thank you very much for your attention.
simbadMarino commentedon Mar 6, 2026
Hi @Federico2014 thanks a lot for updating on the ETA!, is this issue the best place to look for testing results and updates? If there is any other place we should monitor let us know, as we have several community inquiries regarding this same topic.
Federico2014 commentedon Mar 9, 2026
Yes, all currently published progress will be posted in this issue. Just follow this issue and #6376.
.
bladehan1 commentedon Mar 12, 2026
Concern: Native crypto introduces a different failure model in the consensus execution path
The optimizations discussed in this issue (arkworks, native secp256k1, etc.) can significantly improve performance, especially for BN128 pairing and signature verification. This is important for supporting ZK-related workloads.
However, introducing these implementations will likely require native libraries accessed through JNI/JNA, which changes the runtime failure model of the node.
In the JVM:
SIGSEGV,SIGBUS, memory corruption) terminate the entire JVM process.This difference becomes particularly important because these cryptographic operations are executed inside the block execution / transaction validation path, which is consensus-critical.
In the worst case, the failure mode could look like this:
In distributed systems this is already problematic, but in blockchain systems the impact can be amplified:
If a specific transaction input triggers a native crash, every validator executing the same block may crash at the same point, since they all process identical inputs.
This creates a potential network-wide correlated failure, which is much more severe than an isolated node crash.
Possible mitigation strategies
1. Native acceleration behind a feature flag
Provide a runtime configuration allowing operators to choose between:
Pros:
Cons:
This approach is useful operationally but does not fundamentally change the crash model.
2. Native crypto worker via process isolation (IPC)
Another architecture worth evaluating is isolating native crypto implementations in a separate worker process.
Example architecture:
In this model:
The JVM communicates with the native component via IPC.
If the native worker crashes, only the worker process exits.
The JVM can detect the failure and:
Pros:
Cons:
For batchable cryptographic workloads (e.g. pairing checks or signature verification), IPC overhead may be amortized.
Suggestion
Since these optimizations target consensus-critical code paths, it may be worth evaluating the feasibility of an IPC-isolated native worker.
Even if IPC isolation is not adopted immediately, two steps may still be valuable:
It would be helpful if maintainers could comment on:
The performance benefits of native crypto are clear, but ensuring fault isolation in the consensus path may be equally important for long-term network stability.
liuyifei001 commentedon Mar 12, 2026
@bladehan1
This seems like a novel idea — even if the JNI crashes, it would not cause the node itself to crash. However, there may be several issues:
In fact, our JNI only involves ordinary ECDSA computations. If the testing time and functional coverage are sufficiently complete, the risk should be manageable.
bladehan1 commentedon Mar 13, 2026
@liuyifei001
After separating the process, if JNI crashes, the node can choose to try restarting the JNI process or roll back to the Java version for execution.
IPC communication overhead is a core consideration. A solution is only feasible if it maintains high performance even with added IPC communication overhead.
For IPC communication overhead, consider batching requests and using concurrent requests to reduce average overhead.
Performance evaluation relies on @Federico2014 verification.
Federico2014 commentedon Mar 17, 2026
@bladehan1
I compared three implementations: pure Java, JNA, and JNA + IPC. The benchmark results are as follows (unit: ms):
The results show that the additional latency introduced by IPC is minimal, around ~0.2 ms.
In case of IPC invocation failure or timeout (currently configured as 30 ms), the system will automatically fall back to the pure Java implementation to ensure reliability.
Note: All benchmarks were conducted on a local Mac machine with an Intel CPU. Absolute performance numbers may vary depending on hardware and deployment environments.
waynercheung commentedon May 15, 2026
@Federico2014 Is there any update for this issue?
Federico2014 commentedon May 15, 2026
@waynercheung Thanks for the follow-up. The fix is ready and currently undergoing regression testing. I'll post an update here if there is any new progress.
Federico2014 commentedon Sep 3, 2026
Status update: Federico2014/java-tron#52 contains the latest implementation work for the secp256k1 optimization tracked by this issue.
The PR introduces an optional JNA-backed
NativeSecp256k1implementation for signing, public-key recovery, and address recovery. It also adds explicit configuration and compatibility handling: the native implementation is disabled by default, and java-tron falls back to the existingECKeyimplementation when native acceleration is unavailable or cannot process a legacy-compatible input.This PR is currently being considered as an optimization candidate rather than the confirmed final implementation. Since cryptographic operations are used in consensus-critical execution paths, the implementation still requires careful review and validation of compatibility, security, stability, fallback behavior, and platform support before it can be adopted.
As a result, whether this implementation will be merged and included in v4.8.3 has not yet been decided. v4.8.3 should not be considered a confirmed release target at this stage. This issue will remain open, and further updates will be posted once the evaluation and release plan are confirmed.
yanghang8612 commentedon Sep 11, 2026
Implemented a pure-Java BN128 optimization, without JNI/JNA.
Repository/branch: yanghang8612/java-tron —
perf/optimize-bn128. Both platforms benchmarked1b7ab7983fagainst the originalbd2450fe06.Optimizations
Correctness and compatibility
Boundary coverage includes empty/truncated/padded inputs, non-canonical coordinates, off-curve and non-subgroup points, infinity, cancellation, full-width scalars, and carry/borrow patterns. In particular, G1 infinity must not bypass G2 validation.
Tested return bytes and rejection behavior matched. ABI and Energy pricing remain unchanged. These checks provide regression evidence, not a formal proof.
Performance
Both platforms were rerun on 2026-09-11 against the commits above. Complete-call P50 latency; speedups compare original and optimized implementations within each platform.
Setup: Linux: Xeon Platinum 8175M, CentOS 7.9, Oracle JDK 8u291. Mac: M1 Max, macOS 26.6.2, Corretto 17.0.19 ARM64. Both used the same harness and input fixtures, 1 GiB heap, ParallelGC, and no coverage instrumentation.
Each JVM warmed up for ≥60 seconds AND ≥1,000 pairing calls / ≥10,000 Add/Mul calls. Both platforms used 2 independent JVM forks: 202 samples per pairing configuration and 10,002 per Add/Mul configuration. Implementation order alternated; all samples were retained. Source/harness hashes, actual warmup durations, raw samples and pooled statistics were independently checked.
Both hosts were shared and used different JDKs, so these are within-platform optimization gains, not a CPU-only comparison.