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:
Matt Corallo 2013-03-29 21:12:08 -04:00
parent 1662f086c7
commit b5efbe5891
4 changed files with 111 additions and 1 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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