Bitcoin Core  0.19.99
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  * http://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 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.*;
28 
40 public class NativeSecp256k1 {
41 
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>();
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);
56 
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);
62  }
63  byteBuff.rewind();
64  byteBuff.put(data);
65  byteBuff.put(signature);
66  byteBuff.put(pub);
67 
68  byte[][] retByteArray;
69 
70  r.lock();
71  try {
72  return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
73  } finally {
74  r.unlock();
75  }
76  }
77 
87  public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
88  Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
89 
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);
95  }
96  byteBuff.rewind();
97  byteBuff.put(data);
98  byteBuff.put(sec);
99 
100  byte[][] retByteArray;
101 
102  r.lock();
103  try {
104  retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
105  } finally {
106  r.unlock();
107  }
108 
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();
112 
113  assertEquals(sigArr.length, sigLen, "Got bad signature length.");
114 
115  return retVal == 0 ? new byte[0] : sigArr;
116  }
117 
123  public static boolean secKeyVerify(byte[] seckey) {
124  Preconditions.checkArgument(seckey.length == 32);
125 
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);
131  }
132  byteBuff.rewind();
133  byteBuff.put(seckey);
134 
135  r.lock();
136  try {
138  } finally {
139  r.unlock();
140  }
141  }
142 
143 
152  //TODO add a 'compressed' arg
153  public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
154  Preconditions.checkArgument(seckey.length == 32);
155 
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);
161  }
162  byteBuff.rewind();
163  byteBuff.put(seckey);
164 
165  byte[][] retByteArray;
166 
167  r.lock();
168  try {
169  retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
170  } finally {
171  r.unlock();
172  }
173 
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();
177 
178  assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
179 
180  return retVal == 0 ? new byte[0]: pubArr;
181  }
182 
187  public static synchronized void cleanup() {
188  w.lock();
189  try {
191  } finally {
192  w.unlock();
193  }
194  }
195 
196  public static long cloneContext() {
197  r.lock();
198  try {
200  } finally { r.unlock(); }
201  }
202 
209  public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
210  Preconditions.checkArgument(privkey.length == 32);
211 
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);
217  }
218  byteBuff.rewind();
219  byteBuff.put(privkey);
220  byteBuff.put(tweak);
221 
222  byte[][] retByteArray;
223  r.lock();
224  try {
225  retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
226  } finally {
227  r.unlock();
228  }
229 
230  byte[] privArr = retByteArray[0];
231 
232  int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
233  int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
234 
235  assertEquals(privArr.length, privLen, "Got bad pubkey length.");
236 
237  assertEquals(retVal, 1, "Failed return value check.");
238 
239  return privArr;
240  }
241 
248  public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
249  Preconditions.checkArgument(privkey.length == 32);
250 
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);
256  }
257  byteBuff.rewind();
258  byteBuff.put(privkey);
259  byteBuff.put(tweak);
260 
261  byte[][] retByteArray;
262  r.lock();
263  try {
264  retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
265  } finally {
266  r.unlock();
267  }
268 
269  byte[] privArr = retByteArray[0];
270 
271  int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
272  int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
273 
274  assertEquals(privArr.length, privLen, "Got bad pubkey length.");
275 
276  assertEquals(retVal, 1, "Failed return value check.");
277 
278  return privArr;
279  }
280 
287  public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
288  Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
289 
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);
295  }
296  byteBuff.rewind();
297  byteBuff.put(pubkey);
298  byteBuff.put(tweak);
299 
300  byte[][] retByteArray;
301  r.lock();
302  try {
303  retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
304  } finally {
305  r.unlock();
306  }
307 
308  byte[] pubArr = retByteArray[0];
309 
310  int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
311  int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
312 
313  assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
314 
315  assertEquals(retVal, 1, "Failed return value check.");
316 
317  return pubArr;
318  }
319 
326  public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
327  Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
328 
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);
334  }
335  byteBuff.rewind();
336  byteBuff.put(pubkey);
337  byteBuff.put(tweak);
338 
339  byte[][] retByteArray;
340  r.lock();
341  try {
342  retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
343  } finally {
344  r.unlock();
345  }
346 
347  byte[] pubArr = retByteArray[0];
348 
349  int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
350  int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
351 
352  assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
353 
354  assertEquals(retVal, 1, "Failed return value check.");
355 
356  return pubArr;
357  }
358 
365  public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
366  Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);
367 
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);
373  }
374  byteBuff.rewind();
375  byteBuff.put(seckey);
376  byteBuff.put(pubkey);
377 
378  byte[][] retByteArray;
379  r.lock();
380  try {
381  retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
382  } finally {
383  r.unlock();
384  }
385 
386  byte[] resArr = retByteArray[0];
387  int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
388 
389  assertEquals(resArr.length, 32, "Got bad result length.");
390  assertEquals(retVal, 1, "Failed return value check.");
391 
392  return resArr;
393  }
394 
400  public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
401  Preconditions.checkArgument(seed.length == 32 || seed == null);
402 
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);
408  }
409  byteBuff.rewind();
410  byteBuff.put(seed);
411 
412  w.lock();
413  try {
415  } finally {
416  w.unlock();
417  }
418  }
419 
420  private static native long secp256k1_ctx_clone(long context);
421 
422  private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
423 
424  private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
425 
426  private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
427 
428  private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
429 
430  private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
431 
432  private static native void secp256k1_destroy_context(long context);
433 
434  private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
435 
436  private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
437 
438  private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
439 
440  private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
441 
442  private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
443 
444  private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
445 
446 }
static byte [] privKeyTweakAdd(byte[] privkey, byte[] tweak)
libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
static native byte [][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen)
static native byte [][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen)
static native long secp256k1_ctx_clone(long context)
static byte [] privKeyTweakMul(byte[] privkey, byte[] tweak)
libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
static byte [] sign(byte[] data, byte[] sec)
libsecp256k1 Create an ECDSA signature.
static synchronized void cleanup()
libsecp256k1 Cleanup - This destroys the secp256k1 context object This should be called at the end of...
static native byte [][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context)
static native byte [][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context)
static native byte [][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen)
static byte [] pubKeyTweakAdd(byte[] pubkey, byte[] tweak)
libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
static byte [] computePubkey(byte[] seckey)
libsecp256k1 Compute Pubkey - computes public key from secret key
static synchronized boolean randomize(byte[] seed)
libsecp256k1 randomize - updates the context randomization
static ThreadLocal< ByteBuffer > nativeECDSABuffer
static boolean verify(byte[] data, byte[] signature, byte[] pub)
Verifies the given secp256k1 signature in native code.
static boolean secKeyVerify(byte[] seckey)
libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
static native byte [][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen)
static native byte [][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context)
static final ReentrantReadWriteLock rwl
This class holds the context reference used in native methods to handle ECDSA operations.
static native void secp256k1_destroy_context(long context)
static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context)
static native byte [][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context)
static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen)
static byte [] pubKeyTweakMul(byte[] pubkey, byte[] tweak)
libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context)
static byte [] createECDHSecret(byte[] seckey, byte[] pubkey)
libsecp256k1 create ECDH secret - constant time ECDH calculation