Add JNI wrapper for org.bitcoin.NativeSecp256k1 (bitcoinj)
This isnt as optimal as it could be, but its also a very simple API which is nice.
This commit is contained in:
parent
1662f086c7
commit
b5efbe5891
8
Makefile
8
Makefile
|
@ -6,6 +6,7 @@ FLAGS_TEST:=-DVERIFY -ggdb3 -O2 -march=native
|
|||
SECP256K1_FILES := src/num.h src/field.h src/field_5x52.h src/group.h src/ecmult.h src/ecdsa.h \
|
||||
src/num.cpp src/field.cpp src/field_5x52.cpp src/group.cpp src/ecmult.cpp src/ecdsa.cpp
|
||||
|
||||
JAVA_FILES := src/java/org_bitcoin_NativeSecp256k1.h src/java/org_bitcoin_NativeSecp256k1.c
|
||||
|
||||
ifndef CONF
|
||||
CONF := gmp
|
||||
|
@ -56,7 +57,7 @@ tests-any: tests-$(CONF)
|
|||
all-$(CONF): bench-$(CONF) tests-$(CONF) libsecp256k1-$(CONF).a
|
||||
|
||||
clean-$(CONF):
|
||||
rm -f bench-$(CONF) tests-$(CONF) libsecp256k1-$(CONF).a obj/*
|
||||
rm -f bench-$(CONF) tests-$(CONF) libsecp256k1-$(CONF).a libjavasecp256k1-$(CONF).so obj/*
|
||||
|
||||
obj/secp256k1-$(CONF).o: $(SECP256K1_FILES) src/secp256k1.cpp include/secp256k1.h
|
||||
$(CXX) $(FLAGS_COMMON) $(FLAGS_PROD) $(FLAGS_CONF) src/secp256k1.cpp -c -o obj/secp256k1-$(CONF).o
|
||||
|
@ -69,3 +70,8 @@ tests-$(CONF): $(OBJS) src/tests.cpp
|
|||
|
||||
libsecp256k1-$(CONF).a: $(OBJS)
|
||||
$(AR) -rs $@ $(OBJS)
|
||||
|
||||
libjavasecp256k1-$(CONF).so: $(OBJS) $(JAVA_FILES)
|
||||
$(CXX) $(FLAGS_COMMON) $(FLAGS_PROD) $(FLAGS_CONF) -I. src/java/org_bitcoin_NativeSecp256k1.c $(LIBS) $(OBJS) -shared -o libjavasecp256k1-$(CONF).so
|
||||
|
||||
java: libjavasecp256k1-$(CONF).so
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package org.bitcoin;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
|
||||
/**
|
||||
* This class holds native methods to handle ECDSA verification.
|
||||
* You can find an example library that can be used for this at
|
||||
* https://github.com/sipa/secp256k1
|
||||
*/
|
||||
public class NativeSecp256k1 {
|
||||
public static final boolean enabled;
|
||||
static {
|
||||
boolean isEnabled = true;
|
||||
try {
|
||||
System.loadLibrary("javasecp256k1");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
isEnabled = false;
|
||||
}
|
||||
enabled = isEnabled;
|
||||
}
|
||||
|
||||
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
|
||||
/**
|
||||
* Verifies the given secp256k1 signature in native code.
|
||||
* Calling when enabled == false is undefined (probably library not loaded)
|
||||
*
|
||||
* @param data The data which was signed, must be exactly 32 bytes
|
||||
* @param signature The signature
|
||||
* @param pub The public key which did the signing
|
||||
*/
|
||||
public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
|
||||
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null) {
|
||||
byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(data);
|
||||
byteBuff.putInt(signature.length);
|
||||
byteBuff.putInt(pub.length);
|
||||
byteBuff.put(signature);
|
||||
byteBuff.put(pub);
|
||||
return secp256k1_ecdsa_verify(byteBuff) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param byteBuff signature format is byte[32] data,
|
||||
* native-endian int signatureLength, native-endian int pubkeyLength,
|
||||
* byte[signatureLength] signature, byte[pubkeyLength] pub
|
||||
* @returns 1 for valid signature, anything else for invalid
|
||||
*/
|
||||
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#include "org_bitcoin_NativeSecp256k1.h"
|
||||
#include "include/secp256k1.h"
|
||||
|
||||
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject)
|
||||
{
|
||||
unsigned char* data = (unsigned char*) env->GetDirectBufferAddress(byteBufferObject);
|
||||
int sigLen = *((int*)(data + 32));
|
||||
int pubLen = *((int*)(data + 32 + 4));
|
||||
|
||||
return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen);
|
||||
}
|
||||
|
||||
static void __javasecp256k1_attach(void) __attribute__((constructor));
|
||||
static void __javasecp256k1_detach(void) __attribute__((destructor));
|
||||
|
||||
static void __javasecp256k1_attach(void) {
|
||||
secp256k1_start();
|
||||
}
|
||||
|
||||
static void __javasecp256k1_detach(void) {
|
||||
secp256k1_stop();
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class org_bitcoin_NativeSecp256k1 */
|
||||
|
||||
#ifndef _Included_org_bitcoin_NativeSecp256k1
|
||||
#define _Included_org_bitcoin_NativeSecp256k1
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ecdsa_verify
|
||||
* Signature: (Ljava/nio/ByteBuffer;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||
(JNIEnv *, jclass, jobject);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
Loading…
Reference in New Issue