secp256k1-jdk
is a Java library providing Bitcoin-related Elliptic Curve Cryptography functions using the SECG curve
secp256k1. It provides both ECDSA and Schnorr message signing functions.
It provides a Java API that enables multiple implementations. The proof-of-concept includes an implementation that adapts bitcoin-core/secp256k1, a native C library implementing elliptic curve operations on the secp256k1 curve. We also plan to provide an implementation using the popular Bouncy Castle library.
The library supports other JDK-based languages such as Kotlin, Groovy, Scala, and Clojure (as these languages can all use Java classes directly.) In the future, we may provide documentation, examples, and language-specific extensions for one or more additional JVM languages. (Kotlin examples are in-progress.)
- WARNING
-
This prototype software has had limited testing and has not been reviewed. Do not use this software to store private keys for Bitcoin or any other purpose. It is provided AS-IS for experimentation and feedback.
The API is based on the C-language
API of bitcoin-core/secp256k1, but adapted
to modern, idiomatic, functional-style Java and to use Elliptic Curve types from the Java Class Library, such as ECPublicKey where appropriate.
The API is distributed as an API-only JAR (
) and we expect that there will be multiple implementations of the API. The API JAR currently requires JDK 9 or later but we may backport it to JDK 8 in a future release depending upon feedback from the community.secp-api-version.jar
- NOTE
-
At this point, we are especially interested in feedback on the API.
The provided proof-of-concept implementation uses the bitcoin-core/secp256k1 C-language library via JEP-454: Foreign Function & Memory API (known as Panama.) It is provided in a separate JAR (
) that requires JDK 22 or later.secp-ffm-version.jar
Panama is available in OpenJDK 22 and later. We anticipate secp-ffm
will be
the recommended/preferred secp-api
implementation for use in projects using modern JVMs.
The minimum required JDK for this module will likely be incremented with each new JDK release, with a target of requiring JDK 25 (the next LTS release of the JDK) for the 1.0 release of secp-ffm
.
- WARNING
-
This is a preliminary implementation provided for experimentation and feedback and should not be used in real applications.
An incomplete Bouncy Castle-based submodule is included. Bouncy Castle is a well-regarded cryptography library that includes support for the secp256k1 curve and is currently used by bitcoinj and other Java-based Bitcoin implementations. We expect this implementation to be completed and made available as a pure-Java implementation for those who are unable to use the native libsecp256k1 implementation and/or Panama.
The Bouncy Castle implementation is currently targeting JDK 9, but if the API is backported to JDK 8, so will the Bouncy Castle implementation.
There are currently no plans for an implementation using earlier Java-to-C adapter technologies such as JNI or JNA. However, the secp256k1-jdk
API should support such an implementation. We would be supportive if someone in the community endeavours to create an implementation or adapt one of the existing implementations to use the secp256k1-jdk
API.
This project is hosted by the bitcoinj organization on GitHub, but secp256k1-jdk
does not use or require the bitcoinj library (website / GitHub) and bitcoinj doesn’t (yet) use secp256k1-jdk
for its ECC implementation. bitcoinj is currently being refactored to be more modular, and we would like to have pluggable ECC implementations (and Schnorr signatures!) in the near future, but further refactoring will be required before this can happen.
For information on the in-process refactoring of bitcoinj, see the following:
secp256k1-jdk currently does not use any Java Cryptography Architecture ECC providers nor does it make itself available as a provider. It does use some of the built-in Java ECC interfaces (such as ECPublicKey) for interoperability and to avoid reinventing the wheel.
The SECG secp256K1 curve was removed from Java in the JDK 16 release (see JDK-8251547). It is possible that a secp256k1 JCA provider could be developed, but that is not currently a goal of this project.
The build requires JDK 22 installed to run. (If you are using a version of Gradle earlier than 8.8, you will need to use an earlier JDK version to run Gradle and the Gradle Toolchains feature will use JDK 22 for the build itself.)
We assume you are using Nix with experimental-features = nix-command flakes
:
-
nix profile install nixpkgs#secp256k1
-
Verify that the secp256k1 library is in your
~/.nix-profile/lib
directory.
By default, the Gradle build looks for the secp256k1
library in ~/.nix-profile/lib
. If you have installed it with
a different package manager or built it from source you can use the -PjavaPath
option to Gradle to change the library
path to your location.
Make sure you have installed version (0.5.0) of secp256k1
with nix profile install nixpkgs#secp256k1
-
./gradlew build
Build the script:
-
./gradlew secp-examples-java:installDist
Set the script’s Java options shell variable (this assumes you installed libsecp2565k1
with Nix):
-
export SECP_EXAMPLES_JAVA_OPTS="-Djava.library.path=$HOME/.nix-profile/lib --enable-native-access=org.bitcoinj.secp.ffm"
Run the script:
-
./secp-examples-java/build/install/secp-examples-java/bin/secp-examples-java
- NOTE
-
We currently only support setting up a development environment with Nix. In the future we hope to support a full Nix build.
To start a development shell with all build prerequisites installed and run the Gradle build:
-
nix develop
-
gradle build
To extract the libsecp256k1 headers into Java classes via jextract
using the extract-header.sh
script:
-
nix develop
-
./extract-headers.sh
The extracted headers will be writen to ./build/org/bitcoinj/secp/ffm/jextract
. You can compare the generated headers with the checked-in headers with:
-
diff -r secp-ffm/src/main/java/org/bitcoinj/secp/ffm/jextract build/org/bitcoinj/secp/ffm/jextract
-
bitcoin-core/secp256k1 on GitHub
-
bitcoin-s fork https://bitcoin-s.org/docs/secp256k1/jni-modify
-
Sparrow/Drongo JNI: https://github.com/sparrowwallet/drongo/tree/master/src/main/java/org/bitcoin
-
Kotlin multiplatform wrapper: https://github.com/acinq/secp256k1-kmp
-
Samourai port of Sipa’s Python reference implementation to Java: BIP340_Schnorr
-
OpenJDK Project Brisbane - uses Foreign Function & Memory API to encapsulate the FIPS 140 validated OpenSSL library.
-
BIP 340: Schnorr Signatures for secp256k1
-
https://www.chosenplaintext.ca/articles/beginners-guide-constant-time-cryptography.html
-
Complete addition formulas for prime order elliptic curves: Joost Renes, Craig Costello, and Lejla Batina
-
https://www.novixys.com/blog/generate-bitcoin-addresses-java/ (Obsolete as of JDK 16)