-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
enable libsecp256k1_jni shared lib #64
Conversation
ping @fatefree. After that, you should be able to use the lib as before, with the exception that the name has changed. Would be great if you could test/verify. |
Thanks for your contribution! I gave it a try and ran into two issues..
I changed the make file just to see if it would work and put: After that, the make succeeds and I see a .lo file created, but not an .so. Is there another step to create the shared library out of the library object file? |
Thanks for testing.
'make install' should install shared libs for you. In your case, it should be a dll. |
Grr, I used "windows" rather than win32 for that path. I won't bother fixing it up yet since I'm not sure what to change it to... Do jdk's differentiate between win32 and win64? Or is the "include/win32" path used for both? |
I believe its win32 regardless, since that is the location of a 64bit jdk on my machine. I am using mingw for the record. Here is the pastebin: |
Please paste the entire log so I can see the contents of the vars. I suspect the space in "Program Files" is the culprit. |
@fatefree pushed a new version with improved search, not sure if it'll fix your issue or not. please test and paste the full log if it doesn't. |
Code looks good, but I'd like some confirmation that this solves the issue. |
Needs rebase and testing :) |
@theuni is there a way to link in the library code statically, so the result doesn't need a second shared library? |
On Mac OSX: Configure is failing to find jni.h on OSX 10.9.5 / Java 1.7 and 1.8. JAVA_HOME is self-set to (e.g.) /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home I have an fixed version of m4/ax_jni_include_dir.m4 which does the right thing, which I'll do a pull request for when/if this present request is merged. (or mail me at iang at iang spot org.) |
@sipa: the contents of the fix works for me, altho merging requires care because it is a bit old. |
Sorry, I have a few things to get to for libsecp256k1, but I've been busy with core. Will catch up here asap. |
@sipa I did it that way at first, but decided that a separate lib made more sense going forward. Assuming the functions reachable from jni are stable (sign+verify), the jni lib would hardly ever need to change, and could be packaged with java apps easily. The real lib could then be updated separately with no other intervention from the app side. That's probably naive though, and overlooking real-world complications. If you'd prefer to have them merged, I can put it back that way. |
@theuni a stripped libsecp256k1.so now is 50 kB, so for avoiding storage or memory it's not actually useful. And in practice, yes, I think more (dependent) libraries is a nuisance. |
OK. Will make the change. |
rebased and updated to not use a separate lib. Other changes:
|
Your autodetection doesn't seem to work really - see Travis. |
Grr, I remember fighting with this the first time around. Travis uses oracle's jdk, which has a different layout apparently. I'll dig up the fix needed. |
750b4f9
to
88ec152
Compare
@@ -53,8 +58,11 @@ endif | |||
|
|||
libsecp256k1_la_SOURCES = src/secp256k1.c | |||
libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include $(SECP_INCLUDES) | |||
libsecp256k1_la_LIBADD = $(COMMON_LIB) $(SECP_LIBS) | |||
libsecp256k1_la_LIBADD = $(COMMON_LIB) $(JNI_LIB) $(SECP_LIBS) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, why does libsecp256k1.la need to depend on libsecp256k1_jni.la?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@theuni ping.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you're asking here. If jni is enabled, the objects need to be linked in.
If you're asking why it's a convenience lib and not just an appended source file, I did that because it requires extra include paths, and may require extra libs/lib paths (android for ex).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, why does libsecp256k1.la depend on the jni library? I would expect the other way around?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, maybe we're not in sync here.
After your initial comments, I refactored this so that it doesn't produce a separate jni library anymore. It's all included in libsecp256k1.so. So the "jni library" is just a convenience lib containing org_bitcoin_NativeSecp256k1.o. The LIBADD here just adds the convenience lib into the final shared lib.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I was expecting a separate _jni library, just one that had the libsecp256k1 code statically linked in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry if I wasn't clear. I think it's a bit weird to have the library itself also function as front-end for itself...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand. If you're going to ship 2 libs, one without the jni symbol and 1 with.. why would one ever choose to use/deploy the one without? The size difference and added attack surface are practically zero, so I'm not understanding the benefit.
If _jni was shared and depended on the main lib, I'd agree. But I'm not following you in the static case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, in terms of expected usage, I think you either want the library itself (which offers the API described in the .h file), or you want something to plug into Java (which offers the API described by the .java file). I wasn't expecting one library that could function as both, but in practice there's probably very little benefit in splitting it up.
One alternative could be to have a different top-level .c file which implements the Java API, which may be different (and for now, would definitely just be a subset), but that's probably overkill as well.
Concept ACK.
Rebase? |
ce86bb6
to
2d9055f
Compare
Also silence an unnecessary warning.
Rebased with the following changes:
Btw, I'm happy to make whatever changes you'd like here. I'm not married to any particular configuration, I just wasn't following your logic in the last discussion. |
jni headers will be used if possible, otherwise jni support is disabled
Hi all, i added support for several more secp256k1 functions (sign, pubkey_create, sec/pub_verify) as well as associated testcases, which are all looking good - - this is a preliminary commit as i have yet to go in and clean it up with the appropriate comments, but i wanted to share what i had so that it has some eyes https://github.com/faizkhan00/secp256k1/commit/7838a3ea4aabaa372cb9f4422531502aa6e43e60 |
Chatted with cfields/sipa about this on IRC, need to rebase with contexts handled once and only once in the JNI/Java wrapper, possibly using synch primitives should have something mid-week or so with the update |
Updated branch with pass-by-reference context instead of reinit-per-operation refactor branch: https://github.com/faizkhan00/secp256k1/tree/jni-add-sign-verify-test file-that-needs-review (pls!): https://github.com/faizkhan00/secp256k1/blob/jni-add-sign-verify-test/src/java/org_bitcoin_NativeSecp256k1.c Thanks again |
I think this needs some way of destroying the context. Maybe add a finalize() method that calls into c similar to the context init function? I know nothing of java though, so I'm clueless as to how that works on static members. |
Yes, it seems I missed that method somehow, I've added a context_destroy() method that should now take care of that. About statics: Static fields in Java aren't GC'ed until the class is unloaded or the classloader is unloaded, so the option for that is to move from static methods to a object-instantiation based approach, which would increase the complexity, for about 8 bytes of memory (java longs are 64 bit)- If its wanted I can look into doing this definitely, but I'm unsure if the added complexity would make the trade-off worthwhile. |
@faizkhan00 The java long is just a pointer to malloc'd memory from the native side, which I believe is several hundred kb. |
Worked on this a bit tonight, basically there is a edge case that I'm not 100% sure with how to handle: We have builds on Travis for 32bit Linux , yet Travis doesn't A) support 32 bit JDKs (not sure how to fix) and B) the JNI lib is relatively untested with 32bit (fixable) For the moment, I've disabled Travis for 32bit builds, and added documentation to the runner, but I'm not sure if that is the correct strategy for this instance. (https://travis-ci.org/9fe95262548e/secp256k1/jobs/61240914#L395) Side note: I've also disabled the tests for Interesting |
Ah, I was working on this at the same time. Here's my take on it: https://github.com/theuni/secp256k1/tree/travis-jni . The jar is cached for the future, which should help avoid any website downtime issues. |
ah! nice work @theuni - i think i prefer your makefiles soln over hacky bash scripts ... so I think the only step is to include |
@faizkhan00 it's already in there :) |
Haha I see , yea that works far far better than what I had in mind :) Cool! Nice work @theuni |
@faizkhan00 just taking one last look at this. I think it would make sense to re-work the native functions to pass the size parameters as separate int's rather than through the bytebuffers. As-is, I believe big-endian is broken. So that would make this: JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
{
secp256k1_context_t *ctx = (secp256k1_context_t*)ctx_l;
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
int sigLen = *((int*)(data + 32));
int pubLen = *((int*)(data + 32 + 4)); look more like this:
Obviously the function signature would have to be fixed up. Thoughts? |
@theuni Hey, I'm curious where you might be seeing platform-specific broken-ness... I would have thought this line in the Java code I'm also pretty interested in checking endianness on a VM or via qemu, but I totally can understand if you think thats a tangent here :) Interested to know more, I havent' dealt too heavily with platform-specific endianness issues in the past, and know how important they are to handle in this piece of code. |
@faizkhan00 pushed a quick change to theuni@f69f471. |
@faizkhan00 Yes, it looks like the nativeOrder() probably should've taken care of it. Still, I don't see why we should risk serializing/deserializing when we can pass by value more cleanly. |
@theuni Ok, and yes, reviewing your code, the changes you made definitely make for a cleaner result, which is preferred, and also look good. One question about this |
@theuni I suppose I just was curious what we get from that change, irrespective of what the JVM is doing when using nativeOrder() |
Whoops! Thanks for catching that! I was playing around and forgot to revert that. Pushed a new change with that removed. |
ok! the rest of it looks good to me :) |
hey @theuni , looking over your branch a bit, i'm wondering - - is it worthwhile to add implementations for these functions? I think that with the code we have in place it should be pretty safe (and i feel fairly confident) in bringing these to JNI (perhaps with additional tests as well) - thoughts there?
Perhaps also |
@faizkhan00 Sure. Since you're doing the bulk of the work here now, how about adding the above (though you don't have to of course, it's fine as-is), then opening a new PR for fresh review? I only have 2 complaints left, I believe. It'd be great if you could address them as you work on the other changes:
If you're OK with it, at this point I'll close this PR and invite you re-open a fresh one when you're ready. You're welcome to squash down any of my stuff however it makes sense to you. |
@theuni Ype yep, that sounds like a plan. I'll likely have time to work on this soon/tonight-ish, but I'll need to look into synch locking a bit more before committing anything- Sipa mentioned some really important failure modes that just got documented in the 'assumptions' thread, and I want to make sure we're good there.
Lets hold on closing the PR for the moment, I'll get those nits and funcs above addressed, and then when I open the new one, lets say we close this one *and continue the discussion there, ? Squashing OK |
Hi @faizkhan00, For the record, I think pulling in Rust devtool dependencies to libsecp256k1 is not appropriate for the sake of JNI bindings; it's a lot of extra complexity and it feels weird to have this layer of indirection. When we talked on IRC I did not realize you were working on code to be merged into libsecp256k1 itself. Andrew |
Going to close this as outdated. Anyone feel free to take up the work of a testable JNI/whateverjava interface. |
…haustive Add $(COMMON_LIB) to exhaustive tests to fix ARM asm build
This enables a libsecp256k1_jni shared lib to be built. It depends on libsecp256k1.
./configure --enable-jni
should be all it takes assuming your java environment is setup properly. For now, there's no way to specify where the includes should be found if they're not located in $JAVA_HOME/include, as I'm not sure if that's necessary or not.Notice that the lib has been renamed in the .java to reflect the lib's new name. This was done to match standard distro packaging names.
This is untested in a real java/jni build, verification that it actually works will be needed before merging.