{"action":"created","comment":{"url":"https://api.github.com/repos/bitcoin/secp256k1/pulls/comments/47827590","id":47827590,"diff_hunk":"@@ -12,49 +15,737 @@\n  * https://github.com/sipa/secp256k1\n  */\n public class NativeSecp256k1 {\n-    public static final boolean enabled;\n-    static {\n-        boolean isEnabled = true;\n-        try {\n-            System.loadLibrary(\"javasecp256k1\");\n-        } catch (UnsatisfiedLinkError e) {\n-            isEnabled = false;\n-        }\n-        enabled = isEnabled;\n-    }\n-    \n+\n+    private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();\n+    private static final Lock r = rwl.readLock();\n+    private static final Lock w = rwl.writeLock();\n     private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();\n     /**\n      * Verifies the given secp256k1 signature in native code.\n      * Calling when enabled == false is undefined (probably library not loaded)\n-     * \n+     *\n      * @param data The data which was signed, must be exactly 32 bytes\n      * @param signature The signature\n      * @param pub The public key which did the signing\n      */\n-    public static boolean verify(byte[] data, byte[] signature, byte[] pub) {\n+    public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{\n         Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);\n \n         ByteBuffer byteBuff = nativeECDSABuffer.get();\n-        if (byteBuff == null) {\n-            byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520);\n+        if (byteBuff == null || byteBuff.capacity() < 520) {\n+            byteBuff = ByteBuffer.allocateDirect(520);\n             byteBuff.order(ByteOrder.nativeOrder());\n             nativeECDSABuffer.set(byteBuff);\n         }\n         byteBuff.rewind();\n         byteBuff.put(data);\n-        byteBuff.putInt(signature.length);\n-        byteBuff.putInt(pub.length);\n         byteBuff.put(signature);\n         byteBuff.put(pub);\n-        return secp256k1_ecdsa_verify(byteBuff) == 1;\n+\n+        byte[][] retByteArray;\n+\n+        r.lock();\n+        try {\n+          return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;\n+        } finally {\n+          r.unlock();\n+        }\n+    }\n+\n+    /**\n+     * recover the given secp256k1 pubkey in native code.\n+     *\n+     * @param data The data which was signed, must be exactly 32 bytes\n+     * @param signature The signature\n+     * @param compressed whether to recover a compressed pubkey\n+     * @param pub The public key which did the signing\n+     */\n+    //TODO recoverCompact()\n+    public static byte[] recoverCompact(byte[] data, byte[] signature,int compressed, int recID) throws AssertFailException{\n+        Preconditions.checkArgument(data.length == 32 && signature.length == 64 && (compressed == 0 || compressed == 1));\n+\n+        ByteBuffer byteBuff = nativeECDSABuffer.get();\n+        if (byteBuff == null || byteBuff.capacity() < 32 + 64) {\n+            byteBuff = ByteBuffer.allocateDirect(32 + 64);\n+            byteBuff.order(ByteOrder.nativeOrder());\n+            nativeECDSABuffer.set(byteBuff);\n+        }\n+        byteBuff.rewind();\n+        byteBuff.put(data);\n+        byteBuff.put(signature);\n+\n+        byte[][] retByteArray = null;//secp256k1_ecdsa_recover_compact(byteBuff, Secp256k1Context, compressed, recID);\n+\n+        byte[] pubArr = retByteArray[0];\n+        int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();\n+        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();\n+\n+        assertEquals(pubArr.length, pubLen, \"Got bad signature length.\");\n+\n+        assertEquals(retVal, 1, \"Failed return value check.\");\n+\n+        return pubArr;\n+    }\n+\n+    /**\n+     * libsecp256k1 Create an ECDSA signature.\n+     *\n+     * @param data Message hash, 32 bytes\n+     * @param key Secret key, 32 bytes\n+     *\n+     * Return values\n+     * @param sig byte array of signature\n+     */\n+\n+    public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{\n+        Preconditions.checkArgument(data.length == 32 && sec.length <= 32);\n+\n+        ByteBuffer byteBuff = nativeECDSABuffer.get();\n+        if (byteBuff == null || byteBuff.capacity() < 32 + 32) {\n+            byteBuff = ByteBuffer.allocateDirect(32 + 32);\n+            byteBuff.order(ByteOrder.nativeOrder());\n+            nativeECDSABuffer.set(byteBuff);\n+        }\n+        byteBuff.rewind();\n+        byteBuff.put(data);\n+        byteBuff.put(sec);\n+\n+        byte[][] retByteArray;\n+\n+        r.lock();\n+        try {\n+          retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());\n+        } finally {\n+          r.unlock();\n+        }\n+\n+        byte[] sigArr = retByteArray[0];\n+        int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();\n+        int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();\n+\n+        assertEquals(sigArr.length, sigLen, \"Got bad signature length.\");\n+\n+        return retVal == 0 ? new byte[0] : sigArr;\n+    }\n+\n+    /**\n+     * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid\n+     *\n+     * @param seckey ECDSA Secret key, 32 bytes\n+     */\n+\n+    public static boolean secKeyVerify(byte[] seckey) {\n+        Preconditions.checkArgument(seckey.length == 32);\n+\n+        ByteBuffer byteBuff = nativeECDSABuffer.get();\n+        if (byteBuff == null || byteBuff.capacity() < seckey.length) {\n+            byteBuff = ByteBuffer.allocateDirect(seckey.length);\n+            byteBuff.order(ByteOrder.nativeOrder());\n+            nativeECDSABuffer.set(byteBuff);\n+        }\n+        byteBuff.rewind();\n+        byteBuff.put(seckey);\n+\n+        r.lock();\n+        try {\n+          return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;\n+        } finally {\n+          r.unlock();\n+        }\n+    }\n+\n+\n+    /**\n+     * libsecp256k1 Compute Pubkey - computes public key from secret key\n+     *\n+     * @param seckey ECDSA Secret key, 32 bytes\n+     * @param compressed 1 to return compressed key, 0 for uncompressed","path":"src/java/org/bitcoin/NativeSecp256k1.java","position":179,"original_position":179,"commit_id":"0a30103b1e7c8aceacadeecdd1e90b4759a2acbb","original_commit_id":"0a30103b1e7c8aceacadeecdd1e90b4759a2acbb","user":{"login":"sipa","id":548488,"avatar_url":"https://avatars.githubusercontent.com/u/548488?v=3","gravatar_id":"","url":"https://api.github.com/users/sipa","html_url":"https://github.com/sipa","followers_url":"https://api.github.com/users/sipa/followers","following_url":"https://api.github.com/users/sipa/following{/other_user}","gists_url":"https://api.github.com/users/sipa/gists{/gist_id}","starred_url":"https://api.github.com/users/sipa/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sipa/subscriptions","organizations_url":"https://api.github.com/users/sipa/orgs","repos_url":"https://api.github.com/users/sipa/repos","events_url":"https://api.github.com/users/sipa/events{/privacy}","received_events_url":"https://api.github.com/users/sipa/received_events","type":"User","site_admin":false},"body":"Seems unimplemented.","created_at":"2015-12-16T20:13:50Z","updated_at":"2015-12-16T20:13:50Z","html_url":"https://github.com/bitcoin/secp256k1/pull/364#discussion_r47827590","pull_request_url":"https://api.github.com/repos/bitcoin/secp256k1/pulls/364","_links":{"self":{"href":"https://api.github.com/repos/bitcoin/secp256k1/pulls/comments/47827590"},"html":{"href":"https://github.com/bitcoin/secp256k1/pull/364#discussion_r47827590"},"pull_request":{"href":"https://api.github.com/repos/bitcoin/secp256k1/pulls/364"}}},"pull_request":{"url":"https://api.github.com/repos/bitcoin/secp256k1/pulls/364","id":53087534,"html_url":"https://github.com/bitcoin/secp256k1/pull/364","diff_url":"https://github.com/bitcoin/secp256k1/pull/364.diff","patch_url":"https://github.com/bitcoin/secp256k1/pull/364.patch","issue_url":"https://api.github.com/repos/bitcoin/secp256k1/issues/364","number":364,"state":"open","locked":false,"title":"JNI rebased","user":{"login":"greenaddress","id":5269298,"avatar_url":"https://avatars.githubusercontent.com/u/5269298?v=3","gravatar_id":"","url":"https://api.github.com/users/greenaddress","html_url":"https://github.com/greenaddress","followers_url":"https://api.github.com/users/greenaddress/followers","following_url":"https://api.github.com/users/greenaddress/following{/other_user}","gists_url":"https://api.github.com/users/greenaddress/gists{/gist_id}","starred_url":"https://api.github.com/users/greenaddress/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/greenaddress/subscriptions","organizations_url":"https://api.github.com/users/greenaddress/orgs","repos_url":"https://api.github.com/users/greenaddress/repos","events_url":"https://api.github.com/users/greenaddress/events{/privacy}","received_events_url":"https://api.github.com/users/greenaddress/received_events","type":"User","site_admin":false},"body":"This is another continuation of #64 and #248 implementing JNI library for secp256k1, rebased to master.\r\n\r\nAlso it includes a fix for a bug we noticed while including it in GreenBits - buffers were overflowing if two different functions were called consecutively with the second one needing more buffer space.","created_at":"2015-12-09T08:04:22Z","updated_at":"2015-12-16T20:13:50Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4ec243a81662b1eaa0c71d3febf2d68bf9bb0ba9","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/bitcoin/secp256k1/pulls/364/commits","review_comments_url":"https://api.github.com/repos/bitcoin/secp256k1/pulls/364/comments","review_comment_url":"https://api.github.com/repos/bitcoin/secp256k1/pulls/comments{/number}","comments_url":"https://api.github.com/repos/bitcoin/secp256k1/issues/364/comments","statuses_url":"https://api.github.com/repos/bitcoin/secp256k1/statuses/0a30103b1e7c8aceacadeecdd1e90b4759a2acbb","head":{"label":"greenaddress:jni-rebased","ref":"jni-rebased","sha":"0a30103b1e7c8aceacadeecdd1e90b4759a2acbb","user":{"login":"greenaddress","id":5269298,"avatar_url":"https://avatars.githubusercontent.com/u/5269298?v=3","gravatar_id":"","url":"https://api.github.com/users/greenaddress","html_url":"https://github.com/greenaddress","followers_url":"https://api.github.com/users/greenaddress/followers","following_url":"https://api.github.com/users/greenaddress/following{/other_user}","gists_url":"https://api.github.com/users/greenaddress/gists{/gist_id}","starred_url":"https://api.github.com/users/greenaddress/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/greenaddress/subscriptions","organizations_url":"https://api.github.com/users/greenaddress/orgs","repos_url":"https://api.github.com/users/greenaddress/repos","events_url":"https://api.github.com/users/greenaddress/events{/privacy}","received_events_url":"https://api.github.com/users/greenaddress/received_events","type":"User","site_admin":false},"repo":{"id":44805627,"name":"secp256k1","full_name":"greenaddress/secp256k1","owner":{"login":"greenaddress","id":5269298,"avatar_url":"https://avatars.githubusercontent.com/u/5269298?v=3","gravatar_id":"","url":"https://api.github.com/users/greenaddress","html_url":"https://github.com/greenaddress","followers_url":"https://api.github.com/users/greenaddress/followers","following_url":"https://api.github.com/users/greenaddress/following{/other_user}","gists_url":"https://api.github.com/users/greenaddress/gists{/gist_id}","starred_url":"https://api.github.com/users/greenaddress/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/greenaddress/subscriptions","organizations_url":"https://api.github.com/users/greenaddress/orgs","repos_url":"https://api.github.com/users/greenaddress/repos","events_url":"https://api.github.com/users/greenaddress/events{/privacy}","received_events_url":"https://api.github.com/users/greenaddress/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/greenaddress/secp256k1","description":"Optimized C library for EC operations on curve secp256k1","fork":true,"url":"https://api.github.com/repos/greenaddress/secp256k1","forks_url":"https://api.github.com/repos/greenaddress/secp256k1/forks","keys_url":"https://api.github.com/repos/greenaddress/secp256k1/keys{/key_id}","collaborators_url":"https://api.github.com/repos/greenaddress/secp256k1/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/greenaddress/secp256k1/teams","hooks_url":"https://api.github.com/repos/greenaddress/secp256k1/hooks","issue_events_url":"https://api.github.com/repos/greenaddress/secp256k1/issues/events{/number}","events_url":"https://api.github.com/repos/greenaddress/secp256k1/events","assignees_url":"https://api.github.com/repos/greenaddress/secp256k1/assignees{/user}","branches_url":"https://api.github.com/repos/greenaddress/secp256k1/branches{/branch}","tags_url":"https://api.github.com/repos/greenaddress/secp256k1/tags","blobs_url":"https://api.github.com/repos/greenaddress/secp256k1/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/greenaddress/secp256k1/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/greenaddress/secp256k1/git/refs{/sha}","trees_url":"https://api.github.com/repos/greenaddress/secp256k1/git/trees{/sha}","statuses_url":"https://api.github.com/repos/greenaddress/secp256k1/statuses/{sha}","languages_url":"https://api.github.com/repos/greenaddress/secp256k1/languages","stargazers_url":"https://api.github.com/repos/greenaddress/secp256k1/stargazers","contributors_url":"https://api.github.com/repos/greenaddress/secp256k1/contributors","subscribers_url":"https://api.github.com/repos/greenaddress/secp256k1/subscribers","subscription_url":"https://api.github.com/repos/greenaddress/secp256k1/subscription","commits_url":"https://api.github.com/repos/greenaddress/secp256k1/commits{/sha}","git_commits_url":"https://api.github.com/repos/greenaddress/secp256k1/git/commits{/sha}","comments_url":"https://api.github.com/repos/greenaddress/secp256k1/comments{/number}","issue_comment_url":"https://api.github.com/repos/greenaddress/secp256k1/issues/comments{/number}","contents_url":"https://api.github.com/repos/greenaddress/secp256k1/contents/{+path}","compare_url":"https://api.github.com/repos/greenaddress/secp256k1/compare/{base}...{head}","merges_url":"https://api.github.com/repos/greenaddress/secp256k1/merges","archive_url":"https://api.github.com/repos/greenaddress/secp256k1/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/greenaddress/secp256k1/downloads","issues_url":"https://api.github.com/repos/greenaddress/secp256k1/issues{/number}","pulls_url":"https://api.github.com/repos/greenaddress/secp256k1/pulls{/number}","milestones_url":"https://api.github.com/repos/greenaddress/secp256k1/milestones{/number}","notifications_url":"https://api.github.com/repos/greenaddress/secp256k1/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/greenaddress/secp256k1/labels{/name}","releases_url":"https://api.github.com/repos/greenaddress/secp256k1/releases{/id}","created_at":"2015-10-23T10:14:56Z","updated_at":"2015-10-23T10:14:57Z","pushed_at":"2015-12-16T11:37:42Z","git_url":"git://github.com/greenaddress/secp256k1.git","ssh_url":"git@github.com:greenaddress/secp256k1.git","clone_url":"https://github.com/greenaddress/secp256k1.git","svn_url":"https://github.com/greenaddress/secp256k1","homepage":null,"size":1671,"stargazers_count":0,"watchers_count":0,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"bitcoin:master","ref":"master","sha":"c18b869e58aa4d3bff6958f370f6b643d1223c44","user":{"login":"bitcoin","id":528860,"avatar_url":"https://avatars.githubusercontent.com/u/528860?v=3","gravatar_id":"","url":"https://api.github.com/users/bitcoin","html_url":"https://github.com/bitcoin","followers_url":"https://api.github.com/users/bitcoin/followers","following_url":"https://api.github.com/users/bitcoin/following{/other_user}","gists_url":"https://api.github.com/users/bitcoin/gists{/gist_id}","starred_url":"https://api.github.com/users/bitcoin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bitcoin/subscriptions","organizations_url":"https://api.github.com/users/bitcoin/orgs","repos_url":"https://api.github.com/users/bitcoin/repos","events_url":"https://api.github.com/users/bitcoin/events{/privacy}","received_events_url":"https://api.github.com/users/bitcoin/received_events","type":"Organization","site_admin":false},"repo":{"id":16648618,"name":"secp256k1","full_name":"bitcoin/secp256k1","owner":{"login":"bitcoin","id":528860,"avatar_url":"https://avatars.githubusercontent.com/u/528860?v=3","gravatar_id":"","url":"https://api.github.com/users/bitcoin","html_url":"https://github.com/bitcoin","followers_url":"https://api.github.com/users/bitcoin/followers","following_url":"https://api.github.com/users/bitcoin/following{/other_user}","gists_url":"https://api.github.com/users/bitcoin/gists{/gist_id}","starred_url":"https://api.github.com/users/bitcoin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bitcoin/subscriptions","organizations_url":"https://api.github.com/users/bitcoin/orgs","repos_url":"https://api.github.com/users/bitcoin/repos","events_url":"https://api.github.com/users/bitcoin/events{/privacy}","received_events_url":"https://api.github.com/users/bitcoin/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/bitcoin/secp256k1","description":"Optimized C library for EC operations on curve secp256k1","fork":false,"url":"https://api.github.com/repos/bitcoin/secp256k1","forks_url":"https://api.github.com/repos/bitcoin/secp256k1/forks","keys_url":"https://api.github.com/repos/bitcoin/secp256k1/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bitcoin/secp256k1/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bitcoin/secp256k1/teams","hooks_url":"https://api.github.com/repos/bitcoin/secp256k1/hooks","issue_events_url":"https://api.github.com/repos/bitcoin/secp256k1/issues/events{/number}","events_url":"https://api.github.com/repos/bitcoin/secp256k1/events","assignees_url":"https://api.github.com/repos/bitcoin/secp256k1/assignees{/user}","branches_url":"https://api.github.com/repos/bitcoin/secp256k1/branches{/branch}","tags_url":"https://api.github.com/repos/bitcoin/secp256k1/tags","blobs_url":"https://api.github.com/repos/bitcoin/secp256k1/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bitcoin/secp256k1/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bitcoin/secp256k1/git/refs{/sha}","trees_url":"https://api.github.com/repos/bitcoin/secp256k1/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bitcoin/secp256k1/statuses/{sha}","languages_url":"https://api.github.com/repos/bitcoin/secp256k1/languages","stargazers_url":"https://api.github.com/repos/bitcoin/secp256k1/stargazers","contributors_url":"https://api.github.com/repos/bitcoin/secp256k1/contributors","subscribers_url":"https://api.github.com/repos/bitcoin/secp256k1/subscribers","subscription_url":"https://api.github.com/repos/bitcoin/secp256k1/subscription","commits_url":"https://api.github.com/repos/bitcoin/secp256k1/commits{/sha}","git_commits_url":"https://api.github.com/repos/bitcoin/secp256k1/git/commits{/sha}","comments_url":"https://api.github.com/repos/bitcoin/secp256k1/comments{/number}","issue_comment_url":"https://api.github.com/repos/bitcoin/secp256k1/issues/comments{/number}","contents_url":"https://api.github.com/repos/bitcoin/secp256k1/contents/{+path}","compare_url":"https://api.github.com/repos/bitcoin/secp256k1/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bitcoin/secp256k1/merges","archive_url":"https://api.github.com/repos/bitcoin/secp256k1/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bitcoin/secp256k1/downloads","issues_url":"https://api.github.com/repos/bitcoin/secp256k1/issues{/number}","pulls_url":"https://api.github.com/repos/bitcoin/secp256k1/pulls{/number}","milestones_url":"https://api.github.com/repos/bitcoin/secp256k1/milestones{/number}","notifications_url":"https://api.github.com/repos/bitcoin/secp256k1/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bitcoin/secp256k1/labels{/name}","releases_url":"https://api.github.com/repos/bitcoin/secp256k1/releases{/id}","created_at":"2014-02-08T17:30:06Z","updated_at":"2015-11-27T16:39:58Z","pushed_at":"2015-12-16T11:37:42Z","git_url":"git://github.com/bitcoin/secp256k1.git","ssh_url":"git@github.com:bitcoin/secp256k1.git","clone_url":"https://github.com/bitcoin/secp256k1.git","svn_url":"https://github.com/bitcoin/secp256k1","homepage":null,"size":2454,"stargazers_count":149,"watchers_count":149,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":104,"mirror_url":null,"open_issues_count":56,"forks":104,"open_issues":56,"watchers":149,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/bitcoin/secp256k1/pulls/364"},"html":{"href":"https://github.com/bitcoin/secp256k1/pull/364"},"issue":{"href":"https://api.github.com/repos/bitcoin/secp256k1/issues/364"},"comments":{"href":"https://api.github.com/repos/bitcoin/secp256k1/issues/364/comments"},"review_comments":{"href":"https://api.github.com/repos/bitcoin/secp256k1/pulls/364/comments"},"review_comment":{"href":"https://api.github.com/repos/bitcoin/secp256k1/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/bitcoin/secp256k1/pulls/364/commits"},"statuses":{"href":"https://api.github.com/repos/bitcoin/secp256k1/statuses/0a30103b1e7c8aceacadeecdd1e90b4759a2acbb"}}}}