Bitcoin ABC 0.30.5
P2P Digital Currency
NativeSecp256k1.java
Go to the documentation of this file.
1/*
2 * Copyright 2013 Google Inc.
3 * Copyright 2014-2016 the libsecp256k1 contributors
4 *
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
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
18package org.bitcoin;
19
20import java.nio.ByteBuffer;
21import java.nio.ByteOrder;
22
23import java.math.BigInteger;
24import java.util.concurrent.locks.Lock;
25import java.util.concurrent.locks.ReentrantReadWriteLock;
26import static org.bitcoin.NativeSecp256k1Util.*;
27
39public class NativeSecp256k1 {
40
41 private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
42 private static final Lock r = rwl.readLock();
43 private static final Lock w = rwl.writeLock();
44 private static ThreadLocal<ByteBuffer> nativeByteBuffer = new ThreadLocal<ByteBuffer>();
53 public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
54 checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
55
56 ByteBuffer byteBuff = nativeByteBuffer.get();
57 if (byteBuff == null || byteBuff.capacity() < 520) {
58 byteBuff = ByteBuffer.allocateDirect(520);
59 byteBuff.order(ByteOrder.nativeOrder());
60 nativeByteBuffer.set(byteBuff);
61 }
62 byteBuff.rewind();
63 byteBuff.put(data);
64 byteBuff.put(signature);
65 byteBuff.put(pub);
66
67 r.lock();
68 try {
69 return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
70 } finally {
71 r.unlock();
72 }
73 }
74
84 public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
85 checkArgument(data.length == 32 && sec.length <= 32);
86
87 ByteBuffer byteBuff = nativeByteBuffer.get();
88 if (byteBuff == null || byteBuff.capacity() < 32 + 32) {
89 byteBuff = ByteBuffer.allocateDirect(32 + 32);
90 byteBuff.order(ByteOrder.nativeOrder());
91 nativeByteBuffer.set(byteBuff);
92 }
93 byteBuff.rewind();
94 byteBuff.put(data);
95 byteBuff.put(sec);
96
97 byte[][] retByteArray;
98
99 r.lock();
100 try {
101 retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
102 } finally {
103 r.unlock();
104 }
105
106 byte[] sigArr = retByteArray[0];
107 int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
108 int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
109
110 assertEquals(sigArr.length, sigLen, "Got bad signature length.");
111
112 return retVal == 0 ? new byte[0] : sigArr;
113 }
114
120 public static boolean secKeyVerify(byte[] seckey) {
121 checkArgument(seckey.length == 32);
122
123 ByteBuffer byteBuff = nativeByteBuffer.get();
124 if (byteBuff == null || byteBuff.capacity() < seckey.length) {
125 byteBuff = ByteBuffer.allocateDirect(seckey.length);
126 byteBuff.order(ByteOrder.nativeOrder());
127 nativeByteBuffer.set(byteBuff);
128 }
129 byteBuff.rewind();
130 byteBuff.put(seckey);
131
132 r.lock();
133 try {
135 } finally {
136 r.unlock();
137 }
138 }
139
140
149 //TODO add a 'compressed' arg
150 public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
151 checkArgument(seckey.length == 32);
152
153 ByteBuffer byteBuff = nativeByteBuffer.get();
154 if (byteBuff == null || byteBuff.capacity() < seckey.length) {
155 byteBuff = ByteBuffer.allocateDirect(seckey.length);
156 byteBuff.order(ByteOrder.nativeOrder());
157 nativeByteBuffer.set(byteBuff);
158 }
159 byteBuff.rewind();
160 byteBuff.put(seckey);
161
162 byte[][] retByteArray;
163
164 r.lock();
165 try {
166 retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
167 } finally {
168 r.unlock();
169 }
170
171 byte[] pubArr = retByteArray[0];
172 int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
173 int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
174
175 assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
176
177 return retVal == 0 ? new byte[0]: pubArr;
178 }
179
184 public static synchronized void cleanup() {
185 w.lock();
186 try {
188 } finally {
189 w.unlock();
190 }
191 }
192
193 public static long cloneContext() {
194 r.lock();
195 try {
197 } finally { r.unlock(); }
198 }
199
206 public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
207 checkArgument(privkey.length == 32);
208
209 ByteBuffer byteBuff = nativeByteBuffer.get();
210 if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
211 byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
212 byteBuff.order(ByteOrder.nativeOrder());
213 nativeByteBuffer.set(byteBuff);
214 }
215 byteBuff.rewind();
216 byteBuff.put(privkey);
217 byteBuff.put(tweak);
218
219 byte[][] retByteArray;
220 r.lock();
221 try {
223 } finally {
224 r.unlock();
225 }
226
227 byte[] privArr = retByteArray[0];
228
229 int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
230 int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
231
232 assertEquals(privArr.length, privLen, "Got bad pubkey length.");
233
234 assertEquals(retVal, 1, "Failed return value check.");
235
236 return privArr;
237 }
238
245 public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
246 checkArgument(privkey.length == 32);
247
248 ByteBuffer byteBuff = nativeByteBuffer.get();
249 if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
250 byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
251 byteBuff.order(ByteOrder.nativeOrder());
252 nativeByteBuffer.set(byteBuff);
253 }
254 byteBuff.rewind();
255 byteBuff.put(privkey);
256 byteBuff.put(tweak);
257
258 byte[][] retByteArray;
259 r.lock();
260 try {
262 } finally {
263 r.unlock();
264 }
265
266 byte[] privArr = retByteArray[0];
267
268 int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
269 int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
270
271 assertEquals(privArr.length, privLen, "Got bad pubkey length.");
272
273 assertEquals(retVal, 1, "Failed return value check.");
274
275 return privArr;
276 }
277
284 public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
285 checkArgument(pubkey.length == 33 || pubkey.length == 65);
286
287 ByteBuffer byteBuff = nativeByteBuffer.get();
288 if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
289 byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
290 byteBuff.order(ByteOrder.nativeOrder());
291 nativeByteBuffer.set(byteBuff);
292 }
293 byteBuff.rewind();
294 byteBuff.put(pubkey);
295 byteBuff.put(tweak);
296
297 byte[][] retByteArray;
298 r.lock();
299 try {
300 retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
301 } finally {
302 r.unlock();
303 }
304
305 byte[] pubArr = retByteArray[0];
306
307 int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
308 int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
309
310 assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
311
312 assertEquals(retVal, 1, "Failed return value check.");
313
314 return pubArr;
315 }
316
323 public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
324 checkArgument(pubkey.length == 33 || pubkey.length == 65);
325
326 ByteBuffer byteBuff = nativeByteBuffer.get();
327 if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
328 byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
329 byteBuff.order(ByteOrder.nativeOrder());
330 nativeByteBuffer.set(byteBuff);
331 }
332 byteBuff.rewind();
333 byteBuff.put(pubkey);
334 byteBuff.put(tweak);
335
336 byte[][] retByteArray;
337 r.lock();
338 try {
339 retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
340 } finally {
341 r.unlock();
342 }
343
344 byte[] pubArr = retByteArray[0];
345
346 int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
347 int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
348
349 assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
350
351 assertEquals(retVal, 1, "Failed return value check.");
352
353 return pubArr;
354 }
355
362 public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
363 checkArgument(seckey.length <= 32 && pubkey.length <= 65);
364
365 ByteBuffer byteBuff = nativeByteBuffer.get();
366 if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {
367 byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);
368 byteBuff.order(ByteOrder.nativeOrder());
369 nativeByteBuffer.set(byteBuff);
370 }
371 byteBuff.rewind();
372 byteBuff.put(seckey);
373 byteBuff.put(pubkey);
374
375 byte[][] retByteArray;
376 r.lock();
377 try {
378 retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
379 } finally {
380 r.unlock();
381 }
382
383 byte[] resArr = retByteArray[0];
384 int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
385
386 assertEquals(resArr.length, 32, "Got bad result length.");
387 assertEquals(retVal, 1, "Failed return value check.");
388
389 return resArr;
390 }
391
397 public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
398 checkArgument(seed.length == 32 || seed == null);
399
400 ByteBuffer byteBuff = nativeByteBuffer.get();
401 if (byteBuff == null || byteBuff.capacity() < seed.length) {
402 byteBuff = ByteBuffer.allocateDirect(seed.length);
403 byteBuff.order(ByteOrder.nativeOrder());
404 nativeByteBuffer.set(byteBuff);
405 }
406 byteBuff.rewind();
407 byteBuff.put(seed);
408
409 w.lock();
410 try {
412 } finally {
413 w.unlock();
414 }
415 }
416
424 public static byte[] schnorrSign(byte[] data, byte[] seckey) throws AssertFailException {
425 checkArgument(data.length == 32 && seckey.length <= 32);
426
427 ByteBuffer byteBuff = nativeByteBuffer.get();
428 if (byteBuff == null || byteBuff.capacity() < data.length + seckey.length) {
429 byteBuff = ByteBuffer.allocateDirect(32 + 32);
430 byteBuff.order(ByteOrder.nativeOrder());
431 nativeByteBuffer.set(byteBuff);
432 }
433 byteBuff.rewind();
434 byteBuff.put(data);
435 byteBuff.put(seckey);
436
437 byte[][] retByteArray;
438
439 r.lock();
440 try {
441 retByteArray = secp256k1_schnorr_sign(byteBuff, Secp256k1Context.getContext());
442 } finally {
443 r.unlock();
444 }
445
446 byte[] sigArr = retByteArray[0];
447 int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
448
449 assertEquals(sigArr.length, 64, "Got bad signature length.");
450
451 return retVal == 0 ? new byte[0] : sigArr;
452 }
453
462 public static boolean schnorrVerify(byte[] data, byte[] signature, byte[] pub) {
463 checkArgument(data.length == 32 && signature.length == 64 && (pub.length == 33 || pub.length == 65));
464
465 ByteBuffer byteBuff = nativeByteBuffer.get();
466 if (byteBuff == null || byteBuff.capacity() < 32 + 64 + pub.length) {
467 byteBuff = ByteBuffer.allocateDirect(32 + 64 + pub.length);
468 byteBuff.order(ByteOrder.nativeOrder());
469 nativeByteBuffer.set(byteBuff);
470 }
471 byteBuff.rewind();
472 byteBuff.put(data);
473 byteBuff.put(signature);
474 byteBuff.put(pub);
475
476 r.lock();
477 try {
478 return secp256k1_schnorr_verify(byteBuff, Secp256k1Context.getContext(), pub.length) == 1;
479 } finally {
480 r.unlock();
481 }
482 }
483
484 private static native long secp256k1_ctx_clone(long context);
485
486 private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
487
488 private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
489
490 private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
491
492 private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
493
494 private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
495
496 private static native void secp256k1_destroy_context(long context);
497
498 private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
499
500 private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
501
502 private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
503
504 private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
505
506 private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
507
508 private static native int secp256k1_schnorr_verify(ByteBuffer byteBuff, long context, int pubLen);
509
510 private static native byte[][] secp256k1_schnorr_sign(ByteBuffer byteBuff, long context);
511
512 private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
513
514}
static byte[] createECDHSecret(byte[] seckey, byte[] pubkey)
libsecp256k1 create ECDH secret - constant time ECDH calculation
static boolean schnorrVerify(byte[] data, byte[] signature, byte[] pub)
Verifies the given Schnorr signature in native code.
static native int secp256k1_schnorr_verify(ByteBuffer byteBuff, long context, int pubLen)
static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen)
static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak)
libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
static native byte[][] secp256k1_schnorr_sign(ByteBuffer byteBuff, long context)
static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak)
libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
static ThreadLocal< ByteBuffer > nativeByteBuffer
static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context)
static final ReentrantReadWriteLock rwl
static native long secp256k1_ctx_clone(long context)
static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen)
static byte[] sign(byte[] data, byte[] sec)
libsecp256k1 Create an ECDSA signature.
static synchronized boolean randomize(byte[] seed)
libsecp256k1 randomize - updates the context randomization
static boolean verify(byte[] data, byte[] signature, byte[] pub)
Verifies the given secp256k1 signature in native code.
static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak)
libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen)
static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak)
libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context)
static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context)
static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen)
static native void secp256k1_destroy_context(long context)
static byte[] schnorrSign(byte[] data, byte[] seckey)
libsecp256k1 Create a Schnorr signature.
static byte[] computePubkey(byte[] seckey)
libsecp256k1 Compute Pubkey - computes public key from secret key
static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen)
static synchronized void cleanup()
libsecp256k1 Cleanup - This destroys the secp256k1 context object This should be called at the end of...
static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context)
static boolean secKeyVerify(byte[] seckey)
libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context)
static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context)
This class holds the context reference used in native methods to handle ECDSA operations.