Bitcoin ABC  0.29.2
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 
18 package org.bitcoin;
19 
20 import java.nio.ByteBuffer;
21 import java.nio.ByteOrder;
22 
23 import java.math.BigInteger;
24 import java.util.concurrent.locks.Lock;
25 import java.util.concurrent.locks.ReentrantReadWriteLock;
26 import static org.bitcoin.NativeSecp256k1Util.*;
27 
39 public 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 {
222  retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
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 {
261  retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
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[] pubKeyTweakMul(byte[] pubkey, byte[] tweak)
libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
static boolean schnorrVerify(byte[] data, byte[] signature, byte[] pub)
Verifies the given Schnorr signature in native code.
static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context)
static native int secp256k1_schnorr_verify(ByteBuffer byteBuff, long context, int pubLen)
static native byte[][] secp256k1_schnorr_sign(ByteBuffer byteBuff, long context)
static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context)
static byte[] schnorrSign(byte[] data, byte[] seckey)
libsecp256k1 Create a Schnorr signature.
static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen)
static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak)
libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
static ThreadLocal< ByteBuffer > nativeByteBuffer
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 native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context)
static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen)
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[] computePubkey(byte[] seckey)
libsecp256k1 Compute Pubkey - computes public key from secret key
static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen)
static byte[] createECDHSecret(byte[] seckey, byte[] pubkey)
libsecp256k1 create ECDH secret - constant time ECDH calculation
static byte[] sign(byte[] data, byte[] sec)
libsecp256k1 Create an ECDSA signature.
static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context)
static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak)
libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
static native void secp256k1_destroy_context(long context)
static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak)
libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen)
static synchronized void cleanup()
libsecp256k1 Cleanup - This destroys the secp256k1 context object This should be called at the end of...
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.