2 * Copyright 2013 Google Inc.
3 * Copyright 2014-2016 the libsecp256k1 contributors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 import java.nio.ByteBuffer;
21 import java.nio.ByteOrder;
23 import java.math.BigInteger;
24 import com.google.common.base.Preconditions;
25 import java.util.concurrent.locks.Lock;
26 import java.util.concurrent.locks.ReentrantReadWriteLock;
27 import static org.bitcoin.NativeSecp256k1Util.*;
30 * <p>This class holds native methods to handle ECDSA verification.</p>
32 * <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
34 * <p>To build secp256k1 for use with bitcoinj, run
35 * `./configure --enable-jni --enable-experimental --enable-module-ecdh`
36 * and `make` then copy `.libs/libsecp256k1.so` to your system library path
37 * or point the JVM to the folder containing it with -Djava.library.path
40 public class NativeSecp256k1 {
42 private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
43 private static final Lock r = rwl.readLock();
44 private static final Lock w = rwl.writeLock();
45 private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
47 * Verifies the given secp256k1 signature in native code.
48 * Calling when enabled == false is undefined (probably library not loaded)
50 * @param data The data which was signed, must be exactly 32 bytes
51 * @param signature The signature
52 * @param pub The public key which did the signing
54 public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{
55 Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
57 ByteBuffer byteBuff = nativeECDSABuffer.get();
58 if (byteBuff == null || byteBuff.capacity() < 520) {
59 byteBuff = ByteBuffer.allocateDirect(520);
60 byteBuff.order(ByteOrder.nativeOrder());
61 nativeECDSABuffer.set(byteBuff);
65 byteBuff.put(signature);
68 byte[][] retByteArray;
72 return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
79 * libsecp256k1 Create an ECDSA signature.
81 * @param data Message hash, 32 bytes
82 * @param key Secret key, 32 bytes
85 * @param sig byte array of signature
87 public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
88 Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
90 ByteBuffer byteBuff = nativeECDSABuffer.get();
91 if (byteBuff == null || byteBuff.capacity() < 32 + 32) {
92 byteBuff = ByteBuffer.allocateDirect(32 + 32);
93 byteBuff.order(ByteOrder.nativeOrder());
94 nativeECDSABuffer.set(byteBuff);
100 byte[][] retByteArray;
104 retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
109 byte[] sigArr = retByteArray[0];
110 int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
111 int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
113 assertEquals(sigArr.length, sigLen, "Got bad signature length.");
115 return retVal == 0 ? new byte[0] : sigArr;
119 * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
121 * @param seckey ECDSA Secret key, 32 bytes
123 public static boolean secKeyVerify(byte[] seckey) {
124 Preconditions.checkArgument(seckey.length == 32);
126 ByteBuffer byteBuff = nativeECDSABuffer.get();
127 if (byteBuff == null || byteBuff.capacity() < seckey.length) {
128 byteBuff = ByteBuffer.allocateDirect(seckey.length);
129 byteBuff.order(ByteOrder.nativeOrder());
130 nativeECDSABuffer.set(byteBuff);
133 byteBuff.put(seckey);
137 return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;
145 * libsecp256k1 Compute Pubkey - computes public key from secret key
147 * @param seckey ECDSA Secret key, 32 bytes
150 * @param pubkey ECDSA Public key, 33 or 65 bytes
152 //TODO add a 'compressed' arg
153 public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
154 Preconditions.checkArgument(seckey.length == 32);
156 ByteBuffer byteBuff = nativeECDSABuffer.get();
157 if (byteBuff == null || byteBuff.capacity() < seckey.length) {
158 byteBuff = ByteBuffer.allocateDirect(seckey.length);
159 byteBuff.order(ByteOrder.nativeOrder());
160 nativeECDSABuffer.set(byteBuff);
163 byteBuff.put(seckey);
165 byte[][] retByteArray;
169 retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
174 byte[] pubArr = retByteArray[0];
175 int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
176 int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
178 assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
180 return retVal == 0 ? new byte[0]: pubArr;
184 * libsecp256k1 Cleanup - This destroys the secp256k1 context object
185 * This should be called at the end of the program for proper cleanup of the context.
187 public static synchronized void cleanup() {
190 secp256k1_destroy_context(Secp256k1Context.getContext());
196 public static long cloneContext() {
199 return secp256k1_ctx_clone(Secp256k1Context.getContext());
200 } finally { r.unlock(); }
204 * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
206 * @param tweak some bytes to tweak with
207 * @param seckey 32-byte seckey
209 public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
210 Preconditions.checkArgument(privkey.length == 32);
212 ByteBuffer byteBuff = nativeECDSABuffer.get();
213 if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
214 byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
215 byteBuff.order(ByteOrder.nativeOrder());
216 nativeECDSABuffer.set(byteBuff);
219 byteBuff.put(privkey);
222 byte[][] retByteArray;
225 retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
230 byte[] privArr = retByteArray[0];
232 int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
233 int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
235 assertEquals(privArr.length, privLen, "Got bad pubkey length.");
237 assertEquals(retVal, 1, "Failed return value check.");
243 * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
245 * @param tweak some bytes to tweak with
246 * @param seckey 32-byte seckey
248 public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
249 Preconditions.checkArgument(privkey.length == 32);
251 ByteBuffer byteBuff = nativeECDSABuffer.get();
252 if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
253 byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
254 byteBuff.order(ByteOrder.nativeOrder());
255 nativeECDSABuffer.set(byteBuff);
258 byteBuff.put(privkey);
261 byte[][] retByteArray;
264 retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
269 byte[] privArr = retByteArray[0];
271 int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
272 int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
274 assertEquals(privArr.length, privLen, "Got bad pubkey length.");
276 assertEquals(retVal, 1, "Failed return value check.");
282 * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
284 * @param tweak some bytes to tweak with
285 * @param pubkey 32-byte seckey
287 public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
288 Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
290 ByteBuffer byteBuff = nativeECDSABuffer.get();
291 if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
292 byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
293 byteBuff.order(ByteOrder.nativeOrder());
294 nativeECDSABuffer.set(byteBuff);
297 byteBuff.put(pubkey);
300 byte[][] retByteArray;
303 retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
308 byte[] pubArr = retByteArray[0];
310 int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
311 int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
313 assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
315 assertEquals(retVal, 1, "Failed return value check.");
321 * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
323 * @param tweak some bytes to tweak with
324 * @param pubkey 32-byte seckey
326 public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
327 Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
329 ByteBuffer byteBuff = nativeECDSABuffer.get();
330 if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
331 byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
332 byteBuff.order(ByteOrder.nativeOrder());
333 nativeECDSABuffer.set(byteBuff);
336 byteBuff.put(pubkey);
339 byte[][] retByteArray;
342 retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
347 byte[] pubArr = retByteArray[0];
349 int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
350 int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
352 assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
354 assertEquals(retVal, 1, "Failed return value check.");
360 * libsecp256k1 create ECDH secret - constant time ECDH calculation
362 * @param seckey byte array of secret key used in exponentiaion
363 * @param pubkey byte array of public key used in exponentiaion
365 public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
366 Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);
368 ByteBuffer byteBuff = nativeECDSABuffer.get();
369 if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {
370 byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);
371 byteBuff.order(ByteOrder.nativeOrder());
372 nativeECDSABuffer.set(byteBuff);
375 byteBuff.put(seckey);
376 byteBuff.put(pubkey);
378 byte[][] retByteArray;
381 retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
386 byte[] resArr = retByteArray[0];
387 int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
389 assertEquals(resArr.length, 32, "Got bad result length.");
390 assertEquals(retVal, 1, "Failed return value check.");
396 * libsecp256k1 randomize - updates the context randomization
398 * @param seed 32-byte random seed
400 public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
401 Preconditions.checkArgument(seed.length == 32 || seed == null);
403 ByteBuffer byteBuff = nativeECDSABuffer.get();
404 if (byteBuff == null || byteBuff.capacity() < seed.length) {
405 byteBuff = ByteBuffer.allocateDirect(seed.length);
406 byteBuff.order(ByteOrder.nativeOrder());
407 nativeECDSABuffer.set(byteBuff);
414 return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;
420 private static native long secp256k1_ctx_clone(long context);
422 private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
424 private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
426 private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
428 private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
430 private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
432 private static native void secp256k1_destroy_context(long context);
434 private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
436 private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
438 private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
440 private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
442 private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
444 private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);