Changeset View
Changeset View
Standalone View
Standalone View
src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java
Show All 32 Lines | |||||
* <p>To build secp256k1 for use with bitcoinj, run | * <p>To build secp256k1 for use with bitcoinj, run | ||||
* `./configure --enable-jni --enable-experimental --enable-module-ecdh` | * `./configure --enable-jni --enable-experimental --enable-module-ecdh` | ||||
* and `make` then copy `.libs/libsecp256k1.so` to your system library path | * and `make` then copy `.libs/libsecp256k1.so` to your system library path | ||||
* or point the JVM to the folder containing it with -Djava.library.path | * or point the JVM to the folder containing it with -Djava.library.path | ||||
* </p> | * </p> | ||||
*/ | */ | ||||
public class NativeSecp256k1 { | public class NativeSecp256k1 { | ||||
private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); | private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); | ||||
private static final Lock r = rwl.readLock(); | private final Lock r = rwl.readLock(); | ||||
private static final Lock w = rwl.writeLock(); | private final Lock w = rwl.writeLock(); | ||||
private static ThreadLocal<ByteBuffer> nativeByteBuffer = new ThreadLocal<ByteBuffer>(); | private ThreadLocal<ByteBuffer> nativeByteBuffer = new ThreadLocal<ByteBuffer>(); | ||||
private long context; | |||||
public NativeSecp256k1() throws IllegalArgumentException { | |||||
checkArgument(Secp256k1Context.isEnabled()); | |||||
context = secp256k1_init_context(); | |||||
} | |||||
public long getContext() throws IllegalArgumentException { | |||||
checkArgument(context != -1); | |||||
return context; | |||||
} | |||||
/** | /** | ||||
* Verifies the given secp256k1 signature in native code. | * Verifies the given secp256k1 signature in native code. | ||||
* Calling when enabled == false is undefined (probably library not loaded) | * Calling when enabled == false is undefined (probably library not loaded) | ||||
* | * | ||||
* @param data The data which was signed, must be exactly 32 bytes | * @param data The data which was signed, must be exactly 32 bytes | ||||
* @param signature The signature | * @param signature The signature | ||||
* @param pub The public key which did the signing | * @param pub The public key which did the signing | ||||
*/ | */ | ||||
public static boolean verify(byte[] data, byte[] signature, byte[] pub) { | public boolean verify(byte[] data, byte[] signature, byte[] pub) { | ||||
checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); | checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); | ||||
ByteBuffer byteBuff = nativeByteBuffer.get(); | ByteBuffer byteBuff = nativeByteBuffer.get(); | ||||
if (byteBuff == null || byteBuff.capacity() < 520) { | if (byteBuff == null || byteBuff.capacity() < 520) { | ||||
byteBuff = ByteBuffer.allocateDirect(520); | byteBuff = ByteBuffer.allocateDirect(520); | ||||
byteBuff.order(ByteOrder.nativeOrder()); | byteBuff.order(ByteOrder.nativeOrder()); | ||||
nativeByteBuffer.set(byteBuff); | nativeByteBuffer.set(byteBuff); | ||||
} | } | ||||
byteBuff.rewind(); | byteBuff.rewind(); | ||||
byteBuff.put(data); | byteBuff.put(data); | ||||
byteBuff.put(signature); | byteBuff.put(signature); | ||||
byteBuff.put(pub); | byteBuff.put(pub); | ||||
r.lock(); | r.lock(); | ||||
try { | try { | ||||
return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1; | return secp256k1_ecdsa_verify(byteBuff, context, signature.length, pub.length) == 1; | ||||
} finally { | } finally { | ||||
r.unlock(); | r.unlock(); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* libsecp256k1 Create an ECDSA signature. | * libsecp256k1 Create an ECDSA signature. | ||||
* | * | ||||
* @param data Message hash, 32 bytes | * @param data Message hash, 32 bytes | ||||
* @param key Secret key, 32 bytes | * @param key Secret key, 32 bytes | ||||
* | * | ||||
* Return values | * Return values | ||||
* @param sig byte array of signature | * @param sig byte array of signature | ||||
*/ | */ | ||||
public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{ | public byte[] sign(byte[] data, byte[] sec) throws AssertFailException{ | ||||
checkArgument(data.length == 32 && sec.length <= 32); | checkArgument(data.length == 32 && sec.length <= 32); | ||||
ByteBuffer byteBuff = nativeByteBuffer.get(); | ByteBuffer byteBuff = nativeByteBuffer.get(); | ||||
if (byteBuff == null || byteBuff.capacity() < 32 + 32) { | if (byteBuff == null || byteBuff.capacity() < 32 + 32) { | ||||
byteBuff = ByteBuffer.allocateDirect(32 + 32); | byteBuff = ByteBuffer.allocateDirect(32 + 32); | ||||
byteBuff.order(ByteOrder.nativeOrder()); | byteBuff.order(ByteOrder.nativeOrder()); | ||||
nativeByteBuffer.set(byteBuff); | nativeByteBuffer.set(byteBuff); | ||||
} | } | ||||
byteBuff.rewind(); | byteBuff.rewind(); | ||||
byteBuff.put(data); | byteBuff.put(data); | ||||
byteBuff.put(sec); | byteBuff.put(sec); | ||||
byte[][] retByteArray; | byte[][] retByteArray; | ||||
r.lock(); | r.lock(); | ||||
try { | try { | ||||
retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext()); | retByteArray = secp256k1_ecdsa_sign(byteBuff, context); | ||||
} finally { | } finally { | ||||
r.unlock(); | r.unlock(); | ||||
} | } | ||||
byte[] sigArr = retByteArray[0]; | byte[] sigArr = retByteArray[0]; | ||||
int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); | int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); | ||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); | int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); | ||||
assertEquals(sigArr.length, sigLen, "Got bad signature length."); | assertEquals(sigArr.length, sigLen, "Got bad signature length."); | ||||
return retVal == 0 ? new byte[0] : sigArr; | return retVal == 0 ? new byte[0] : sigArr; | ||||
} | } | ||||
/** | /** | ||||
* libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid | * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid | ||||
* | * | ||||
* @param seckey ECDSA Secret key, 32 bytes | * @param seckey ECDSA Secret key, 32 bytes | ||||
*/ | */ | ||||
public static boolean secKeyVerify(byte[] seckey) { | public boolean secKeyVerify(byte[] seckey) { | ||||
checkArgument(seckey.length == 32); | checkArgument(seckey.length == 32); | ||||
ByteBuffer byteBuff = nativeByteBuffer.get(); | ByteBuffer byteBuff = nativeByteBuffer.get(); | ||||
if (byteBuff == null || byteBuff.capacity() < seckey.length) { | if (byteBuff == null || byteBuff.capacity() < seckey.length) { | ||||
byteBuff = ByteBuffer.allocateDirect(seckey.length); | byteBuff = ByteBuffer.allocateDirect(seckey.length); | ||||
byteBuff.order(ByteOrder.nativeOrder()); | byteBuff.order(ByteOrder.nativeOrder()); | ||||
nativeByteBuffer.set(byteBuff); | nativeByteBuffer.set(byteBuff); | ||||
} | } | ||||
byteBuff.rewind(); | byteBuff.rewind(); | ||||
byteBuff.put(seckey); | byteBuff.put(seckey); | ||||
r.lock(); | r.lock(); | ||||
try { | try { | ||||
return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1; | return secp256k1_ec_seckey_verify(byteBuff, context) == 1; | ||||
} finally { | } finally { | ||||
r.unlock(); | r.unlock(); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* libsecp256k1 Compute Pubkey - computes public key from secret key | * libsecp256k1 Compute Pubkey - computes public key from secret key | ||||
* | * | ||||
* @param seckey ECDSA Secret key, 32 bytes | * @param seckey ECDSA Secret key, 32 bytes | ||||
* | * | ||||
* Return values | * Return values | ||||
* @param pubkey ECDSA Public key, 33 or 65 bytes | * @param pubkey ECDSA Public key, 33 or 65 bytes | ||||
*/ | */ | ||||
//TODO add a 'compressed' arg | //TODO add a 'compressed' arg | ||||
public static byte[] computePubkey(byte[] seckey) throws AssertFailException{ | public byte[] computePubkey(byte[] seckey) throws AssertFailException{ | ||||
checkArgument(seckey.length == 32); | checkArgument(seckey.length == 32); | ||||
ByteBuffer byteBuff = nativeByteBuffer.get(); | ByteBuffer byteBuff = nativeByteBuffer.get(); | ||||
if (byteBuff == null || byteBuff.capacity() < seckey.length) { | if (byteBuff == null || byteBuff.capacity() < seckey.length) { | ||||
byteBuff = ByteBuffer.allocateDirect(seckey.length); | byteBuff = ByteBuffer.allocateDirect(seckey.length); | ||||
byteBuff.order(ByteOrder.nativeOrder()); | byteBuff.order(ByteOrder.nativeOrder()); | ||||
nativeByteBuffer.set(byteBuff); | nativeByteBuffer.set(byteBuff); | ||||
} | } | ||||
byteBuff.rewind(); | byteBuff.rewind(); | ||||
byteBuff.put(seckey); | byteBuff.put(seckey); | ||||
byte[][] retByteArray; | byte[][] retByteArray; | ||||
r.lock(); | r.lock(); | ||||
try { | try { | ||||
retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext()); | retByteArray = secp256k1_ec_pubkey_create(byteBuff, context); | ||||
} finally { | } finally { | ||||
r.unlock(); | r.unlock(); | ||||
} | } | ||||
byte[] pubArr = retByteArray[0]; | byte[] pubArr = retByteArray[0]; | ||||
int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); | int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); | ||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); | int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); | ||||
assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); | assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); | ||||
return retVal == 0 ? new byte[0]: pubArr; | return retVal == 0 ? new byte[0]: pubArr; | ||||
} | } | ||||
/** | /** | ||||
* libsecp256k1 Cleanup - This destroys the secp256k1 context object | * libsecp256k1 Cleanup - This destroys the secp256k1 context object | ||||
* This should be called at the end of the program for proper cleanup of the context. | * This should be called at the end of the program for proper cleanup of the context. | ||||
*/ | */ | ||||
public static synchronized void cleanup() { | public synchronized void cleanup() { | ||||
w.lock(); | w.lock(); | ||||
try { | try { | ||||
secp256k1_destroy_context(Secp256k1Context.getContext()); | secp256k1_destroy_context(context); | ||||
} finally { | } finally { | ||||
w.unlock(); | w.unlock(); | ||||
} | } | ||||
context = - 1; | |||||
} | } | ||||
public static long cloneContext() { | public long cloneContext() { | ||||
r.lock(); | r.lock(); | ||||
try { | try { | ||||
return secp256k1_ctx_clone(Secp256k1Context.getContext()); | return secp256k1_ctx_clone(context); | ||||
} finally { r.unlock(); } | } finally { r.unlock(); } | ||||
} | } | ||||
/** | /** | ||||
* libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it | * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it | ||||
* | * | ||||
* @param tweak some bytes to tweak with | * @param tweak some bytes to tweak with | ||||
* @param seckey 32-byte seckey | * @param seckey 32-byte seckey | ||||
*/ | */ | ||||
public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{ | public byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{ | ||||
checkArgument(privkey.length == 32); | checkArgument(privkey.length == 32); | ||||
ByteBuffer byteBuff = nativeByteBuffer.get(); | ByteBuffer byteBuff = nativeByteBuffer.get(); | ||||
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { | if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { | ||||
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); | byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); | ||||
byteBuff.order(ByteOrder.nativeOrder()); | byteBuff.order(ByteOrder.nativeOrder()); | ||||
nativeByteBuffer.set(byteBuff); | nativeByteBuffer.set(byteBuff); | ||||
} | } | ||||
byteBuff.rewind(); | byteBuff.rewind(); | ||||
byteBuff.put(privkey); | byteBuff.put(privkey); | ||||
byteBuff.put(tweak); | byteBuff.put(tweak); | ||||
byte[][] retByteArray; | byte[][] retByteArray; | ||||
r.lock(); | r.lock(); | ||||
try { | try { | ||||
retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext()); | retByteArray = secp256k1_privkey_tweak_mul(byteBuff, context); | ||||
} finally { | } finally { | ||||
r.unlock(); | r.unlock(); | ||||
} | } | ||||
byte[] privArr = retByteArray[0]; | byte[] privArr = retByteArray[0]; | ||||
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; | int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; | ||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); | int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); | ||||
assertEquals(privArr.length, privLen, "Got bad pubkey length."); | assertEquals(privArr.length, privLen, "Got bad pubkey length."); | ||||
assertEquals(retVal, 1, "Failed return value check."); | assertEquals(retVal, 1, "Failed return value check."); | ||||
return privArr; | return privArr; | ||||
} | } | ||||
/** | /** | ||||
* libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it | * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it | ||||
* | * | ||||
* @param tweak some bytes to tweak with | * @param tweak some bytes to tweak with | ||||
* @param seckey 32-byte seckey | * @param seckey 32-byte seckey | ||||
*/ | */ | ||||
public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{ | public byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{ | ||||
checkArgument(privkey.length == 32); | checkArgument(privkey.length == 32); | ||||
ByteBuffer byteBuff = nativeByteBuffer.get(); | ByteBuffer byteBuff = nativeByteBuffer.get(); | ||||
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { | if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { | ||||
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); | byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); | ||||
byteBuff.order(ByteOrder.nativeOrder()); | byteBuff.order(ByteOrder.nativeOrder()); | ||||
nativeByteBuffer.set(byteBuff); | nativeByteBuffer.set(byteBuff); | ||||
} | } | ||||
byteBuff.rewind(); | byteBuff.rewind(); | ||||
byteBuff.put(privkey); | byteBuff.put(privkey); | ||||
byteBuff.put(tweak); | byteBuff.put(tweak); | ||||
byte[][] retByteArray; | byte[][] retByteArray; | ||||
r.lock(); | r.lock(); | ||||
try { | try { | ||||
retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext()); | retByteArray = secp256k1_privkey_tweak_add(byteBuff, context); | ||||
} finally { | } finally { | ||||
r.unlock(); | r.unlock(); | ||||
} | } | ||||
byte[] privArr = retByteArray[0]; | byte[] privArr = retByteArray[0]; | ||||
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; | int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; | ||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); | int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); | ||||
assertEquals(privArr.length, privLen, "Got bad pubkey length."); | assertEquals(privArr.length, privLen, "Got bad pubkey length."); | ||||
assertEquals(retVal, 1, "Failed return value check."); | assertEquals(retVal, 1, "Failed return value check."); | ||||
return privArr; | return privArr; | ||||
} | } | ||||
/** | /** | ||||
* libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it | * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it | ||||
* | * | ||||
* @param tweak some bytes to tweak with | * @param tweak some bytes to tweak with | ||||
* @param pubkey 32-byte seckey | * @param pubkey 32-byte seckey | ||||
*/ | */ | ||||
public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{ | public byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{ | ||||
checkArgument(pubkey.length == 33 || pubkey.length == 65); | checkArgument(pubkey.length == 33 || pubkey.length == 65); | ||||
ByteBuffer byteBuff = nativeByteBuffer.get(); | ByteBuffer byteBuff = nativeByteBuffer.get(); | ||||
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { | if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { | ||||
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); | byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); | ||||
byteBuff.order(ByteOrder.nativeOrder()); | byteBuff.order(ByteOrder.nativeOrder()); | ||||
nativeByteBuffer.set(byteBuff); | nativeByteBuffer.set(byteBuff); | ||||
} | } | ||||
byteBuff.rewind(); | byteBuff.rewind(); | ||||
byteBuff.put(pubkey); | byteBuff.put(pubkey); | ||||
byteBuff.put(tweak); | byteBuff.put(tweak); | ||||
byte[][] retByteArray; | byte[][] retByteArray; | ||||
r.lock(); | r.lock(); | ||||
try { | try { | ||||
retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length); | retByteArray = secp256k1_pubkey_tweak_add(byteBuff, context, pubkey.length); | ||||
} finally { | } finally { | ||||
r.unlock(); | r.unlock(); | ||||
} | } | ||||
byte[] pubArr = retByteArray[0]; | byte[] pubArr = retByteArray[0]; | ||||
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; | int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; | ||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); | int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); | ||||
assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); | assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); | ||||
assertEquals(retVal, 1, "Failed return value check."); | assertEquals(retVal, 1, "Failed return value check."); | ||||
return pubArr; | return pubArr; | ||||
} | } | ||||
/** | /** | ||||
* libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it | * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it | ||||
* | * | ||||
* @param tweak some bytes to tweak with | * @param tweak some bytes to tweak with | ||||
* @param pubkey 32-byte seckey | * @param pubkey 32-byte seckey | ||||
*/ | */ | ||||
public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{ | public byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{ | ||||
checkArgument(pubkey.length == 33 || pubkey.length == 65); | checkArgument(pubkey.length == 33 || pubkey.length == 65); | ||||
ByteBuffer byteBuff = nativeByteBuffer.get(); | ByteBuffer byteBuff = nativeByteBuffer.get(); | ||||
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { | if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { | ||||
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); | byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); | ||||
byteBuff.order(ByteOrder.nativeOrder()); | byteBuff.order(ByteOrder.nativeOrder()); | ||||
nativeByteBuffer.set(byteBuff); | nativeByteBuffer.set(byteBuff); | ||||
} | } | ||||
byteBuff.rewind(); | byteBuff.rewind(); | ||||
byteBuff.put(pubkey); | byteBuff.put(pubkey); | ||||
byteBuff.put(tweak); | byteBuff.put(tweak); | ||||
byte[][] retByteArray; | byte[][] retByteArray; | ||||
r.lock(); | r.lock(); | ||||
try { | try { | ||||
retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length); | retByteArray = secp256k1_pubkey_tweak_mul(byteBuff, context, pubkey.length); | ||||
} finally { | } finally { | ||||
r.unlock(); | r.unlock(); | ||||
} | } | ||||
byte[] pubArr = retByteArray[0]; | byte[] pubArr = retByteArray[0]; | ||||
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; | int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; | ||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); | int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); | ||||
assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); | assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); | ||||
assertEquals(retVal, 1, "Failed return value check."); | assertEquals(retVal, 1, "Failed return value check."); | ||||
return pubArr; | return pubArr; | ||||
} | } | ||||
/** | /** | ||||
* libsecp256k1 create ECDH secret - constant time ECDH calculation | * libsecp256k1 create ECDH secret - constant time ECDH calculation | ||||
* | * | ||||
* @param seckey byte array of secret key used in exponentiaion | * @param seckey byte array of secret key used in exponentiaion | ||||
* @param pubkey byte array of public key used in exponentiaion | * @param pubkey byte array of public key used in exponentiaion | ||||
*/ | */ | ||||
public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{ | public byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{ | ||||
checkArgument(seckey.length <= 32 && pubkey.length <= 65); | checkArgument(seckey.length <= 32 && pubkey.length <= 65); | ||||
ByteBuffer byteBuff = nativeByteBuffer.get(); | ByteBuffer byteBuff = nativeByteBuffer.get(); | ||||
if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) { | if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) { | ||||
byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length); | byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length); | ||||
byteBuff.order(ByteOrder.nativeOrder()); | byteBuff.order(ByteOrder.nativeOrder()); | ||||
nativeByteBuffer.set(byteBuff); | nativeByteBuffer.set(byteBuff); | ||||
} | } | ||||
byteBuff.rewind(); | byteBuff.rewind(); | ||||
byteBuff.put(seckey); | byteBuff.put(seckey); | ||||
byteBuff.put(pubkey); | byteBuff.put(pubkey); | ||||
byte[][] retByteArray; | byte[][] retByteArray; | ||||
r.lock(); | r.lock(); | ||||
try { | try { | ||||
retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length); | retByteArray = secp256k1_ecdh(byteBuff, context, pubkey.length); | ||||
} finally { | } finally { | ||||
r.unlock(); | r.unlock(); | ||||
} | } | ||||
byte[] resArr = retByteArray[0]; | byte[] resArr = retByteArray[0]; | ||||
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); | int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); | ||||
assertEquals(resArr.length, 32, "Got bad result length."); | assertEquals(resArr.length, 32, "Got bad result length."); | ||||
assertEquals(retVal, 1, "Failed return value check."); | assertEquals(retVal, 1, "Failed return value check."); | ||||
return resArr; | return resArr; | ||||
} | } | ||||
/** | /** | ||||
* libsecp256k1 randomize - updates the context randomization | * libsecp256k1 randomize - updates the context randomization | ||||
* | * | ||||
* @param seed 32-byte random seed | * @param seed 32-byte random seed | ||||
*/ | */ | ||||
public static synchronized boolean randomize(byte[] seed) throws AssertFailException{ | public synchronized boolean randomize(byte[] seed) throws AssertFailException{ | ||||
checkArgument(seed.length == 32 || seed == null); | checkArgument(seed.length == 32 || seed == null); | ||||
ByteBuffer byteBuff = nativeByteBuffer.get(); | ByteBuffer byteBuff = nativeByteBuffer.get(); | ||||
if (byteBuff == null || byteBuff.capacity() < seed.length) { | if (byteBuff == null || byteBuff.capacity() < seed.length) { | ||||
byteBuff = ByteBuffer.allocateDirect(seed.length); | byteBuff = ByteBuffer.allocateDirect(seed.length); | ||||
byteBuff.order(ByteOrder.nativeOrder()); | byteBuff.order(ByteOrder.nativeOrder()); | ||||
nativeByteBuffer.set(byteBuff); | nativeByteBuffer.set(byteBuff); | ||||
} | } | ||||
byteBuff.rewind(); | byteBuff.rewind(); | ||||
byteBuff.put(seed); | byteBuff.put(seed); | ||||
w.lock(); | w.lock(); | ||||
try { | try { | ||||
return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1; | return secp256k1_context_randomize(byteBuff, context) == 1; | ||||
} finally { | } finally { | ||||
w.unlock(); | w.unlock(); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* libsecp256k1 Create a Schnorr signature. | * libsecp256k1 Create a Schnorr signature. | ||||
* | * | ||||
* @param data Message hash, 32 bytes | * @param data Message hash, 32 bytes | ||||
* @param seckey Secret key, 32 bytes | * @param seckey Secret key, 32 bytes | ||||
* @return sig byte array of signature | * @return sig byte array of signature | ||||
*/ | */ | ||||
public static byte[] schnorrSign(byte[] data, byte[] seckey) throws AssertFailException { | public byte[] schnorrSign(byte[] data, byte[] seckey) throws AssertFailException { | ||||
checkArgument(data.length == 32 && seckey.length <= 32); | checkArgument(data.length == 32 && seckey.length <= 32); | ||||
ByteBuffer byteBuff = nativeByteBuffer.get(); | ByteBuffer byteBuff = nativeByteBuffer.get(); | ||||
if (byteBuff == null || byteBuff.capacity() < data.length + seckey.length) { | if (byteBuff == null || byteBuff.capacity() < data.length + seckey.length) { | ||||
byteBuff = ByteBuffer.allocateDirect(32 + 32); | byteBuff = ByteBuffer.allocateDirect(32 + 32); | ||||
byteBuff.order(ByteOrder.nativeOrder()); | byteBuff.order(ByteOrder.nativeOrder()); | ||||
nativeByteBuffer.set(byteBuff); | nativeByteBuffer.set(byteBuff); | ||||
} | } | ||||
byteBuff.rewind(); | byteBuff.rewind(); | ||||
byteBuff.put(data); | byteBuff.put(data); | ||||
byteBuff.put(seckey); | byteBuff.put(seckey); | ||||
byte[][] retByteArray; | byte[][] retByteArray; | ||||
r.lock(); | r.lock(); | ||||
try { | try { | ||||
retByteArray = secp256k1_schnorr_sign(byteBuff, Secp256k1Context.getContext()); | retByteArray = secp256k1_schnorr_sign(byteBuff, context); | ||||
} finally { | } finally { | ||||
r.unlock(); | r.unlock(); | ||||
} | } | ||||
byte[] sigArr = retByteArray[0]; | byte[] sigArr = retByteArray[0]; | ||||
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); | int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); | ||||
assertEquals(sigArr.length, 64, "Got bad signature length."); | assertEquals(sigArr.length, 64, "Got bad signature length."); | ||||
return retVal == 0 ? new byte[0] : sigArr; | return retVal == 0 ? new byte[0] : sigArr; | ||||
} | } | ||||
/** | /** | ||||
* Verifies the given Schnorr signature in native code. | * Verifies the given Schnorr signature in native code. | ||||
* Calling when enabled == false is undefined (probably library not loaded) | * Calling when enabled == false is undefined (probably library not loaded) | ||||
* | * | ||||
* @param data The data which was signed, must be exactly 32 bytes | * @param data The data which was signed, must be exactly 32 bytes | ||||
* @param signature The signature is exactly 64 bytes | * @param signature The signature is exactly 64 bytes | ||||
* @param pub The public key which did the signing which is the same ECDSA | * @param pub The public key which did the signing which is the same ECDSA | ||||
*/ | */ | ||||
public static boolean schnorrVerify(byte[] data, byte[] signature, byte[] pub) { | public boolean schnorrVerify(byte[] data, byte[] signature, byte[] pub) { | ||||
checkArgument(data.length == 32 && signature.length == 64 && (pub.length == 33 || pub.length == 65)); | checkArgument(data.length == 32 && signature.length == 64 && (pub.length == 33 || pub.length == 65)); | ||||
ByteBuffer byteBuff = nativeByteBuffer.get(); | ByteBuffer byteBuff = nativeByteBuffer.get(); | ||||
if (byteBuff == null || byteBuff.capacity() < 32 + 64 + pub.length) { | if (byteBuff == null || byteBuff.capacity() < 32 + 64 + pub.length) { | ||||
byteBuff = ByteBuffer.allocateDirect(32 + 64 + pub.length); | byteBuff = ByteBuffer.allocateDirect(32 + 64 + pub.length); | ||||
byteBuff.order(ByteOrder.nativeOrder()); | byteBuff.order(ByteOrder.nativeOrder()); | ||||
nativeByteBuffer.set(byteBuff); | nativeByteBuffer.set(byteBuff); | ||||
} | } | ||||
byteBuff.rewind(); | byteBuff.rewind(); | ||||
byteBuff.put(data); | byteBuff.put(data); | ||||
byteBuff.put(signature); | byteBuff.put(signature); | ||||
byteBuff.put(pub); | byteBuff.put(pub); | ||||
r.lock(); | r.lock(); | ||||
try { | try { | ||||
return secp256k1_schnorr_verify(byteBuff, Secp256k1Context.getContext(), pub.length) == 1; | return secp256k1_schnorr_verify(byteBuff, context, pub.length) == 1; | ||||
} finally { | } finally { | ||||
r.unlock(); | r.unlock(); | ||||
} | } | ||||
} | } | ||||
private static native long secp256k1_ctx_clone(long context); | private static native long secp256k1_ctx_clone(long context); | ||||
private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context); | private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context); | ||||
private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context); | private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context); | ||||
private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context); | private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context); | ||||
private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen); | private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen); | ||||
private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen); | private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen); | ||||
private static native void secp256k1_destroy_context(long context); | private static native void secp256k1_destroy_context(long context); | ||||
private static native long secp256k1_init_context(); | |||||
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); | private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); | ||||
private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); | private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); | ||||
private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); | private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); | ||||
private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context); | private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context); | ||||
Show All 9 Lines |