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 }