github.com/YoungNK/go-ethereum@v1.9.7/crypto/secp256k1/libsecp256k1/src/java/org/bitcoin/NativeSecp256k1.java (about)

     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  
    29  /**
    30   * <p>This class holds native methods to handle ECDSA verification.</p>
    31   *
    32   * <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
    33   *
    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
    38   * </p>
    39   */
    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>();
    46      /**
    47       * Verifies the given secp256k1 signature in native code.
    48       * Calling when enabled == false is undefined (probably library not loaded)
    49       *
    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
    53       */
    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  
    78      /**
    79       * libsecp256k1 Create an ECDSA signature.
    80       *
    81       * @param data Message hash, 32 bytes
    82       * @param key Secret key, 32 bytes
    83       *
    84       * Return values
    85       * @param sig byte array of signature
    86       */
    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  
   118      /**
   119       * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
   120       *
   121       * @param seckey ECDSA Secret key, 32 bytes
   122       */
   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 {
   137            return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;
   138          } finally {
   139            r.unlock();
   140          }
   141      }
   142  
   143  
   144      /**
   145       * libsecp256k1 Compute Pubkey - computes public key from secret key
   146       *
   147       * @param seckey ECDSA Secret key, 32 bytes
   148       *
   149       * Return values
   150       * @param pubkey ECDSA Public key, 33 or 65 bytes
   151       */
   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  
   183      /**
   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.
   186       */
   187      public static synchronized void cleanup() {
   188          w.lock();
   189          try {
   190            secp256k1_destroy_context(Secp256k1Context.getContext());
   191          } finally {
   192            w.unlock();
   193          }
   194      }
   195  
   196      public static long cloneContext() {
   197         r.lock();
   198         try {
   199          return secp256k1_ctx_clone(Secp256k1Context.getContext());
   200         } finally { r.unlock(); }
   201      }
   202  
   203      /**
   204       * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
   205       *
   206       * @param tweak some bytes to tweak with
   207       * @param seckey 32-byte seckey
   208       */
   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  
   242      /**
   243       * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
   244       *
   245       * @param tweak some bytes to tweak with
   246       * @param seckey 32-byte seckey
   247       */
   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  
   281      /**
   282       * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
   283       *
   284       * @param tweak some bytes to tweak with
   285       * @param pubkey 32-byte seckey
   286       */
   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  
   320      /**
   321       * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
   322       *
   323       * @param tweak some bytes to tweak with
   324       * @param pubkey 32-byte seckey
   325       */
   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  
   359      /**
   360       * libsecp256k1 create ECDH secret - constant time ECDH calculation
   361       *
   362       * @param seckey byte array of secret key used in exponentiaion
   363       * @param pubkey byte array of public key used in exponentiaion
   364       */
   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  
   395      /**
   396       * libsecp256k1 randomize - updates the context randomization
   397       *
   398       * @param seed 32-byte random seed
   399       */
   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 {
   414            return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;
   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  }