1
0
Fork 0
mirror of https://github.com/bitcoin-s/bitcoin-s.git synced 2025-03-16 04:33:01 +01:00
bitcoin-s/docs/1.7.0/secp256k1/jni-modify.html
Docusaurus bot c32187c6b6 Deploy website
Deploy website version based on be07786171
2021-10-17 17:51:31 +00:00

350 lines
No EOL
52 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><title>Adding to Secp256k1 JNI · bitcoin-s</title><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta name="generator" content="Docusaurus"/><meta name="description" content="Bitcoin-S uses a Java Native Interface (JNI) to execute functions in [secp256k1-zkp](https://github.com/ElementsProject/secp256k1-zkp) from java/scala. The native java bindings used to be a part of the secp256k1 library that was maintained by bitcoin-core, but it was [removed in October 2019](https://github.com/bitcoin-core/secp256k1/pull/682). We maintain a [fork of secp256k1](https://github.com/bitcoin-s/secp256k1) which forks off of bitcoin-core&#x27;s `master` but re-introduces the jni. This is also the easiest way to add functionality from new projects such as [Schnorr signatures](https://github.com/bitcoin-core/secp256k1/pull/558) and [ECDSA adaptor signatures](https://github.com/ElementsProject/secp256k1-zkp/pull/117) by rebasing the bitcoin-s branch with the JNI on top of these experimental branches. That said, it is quite tricky to hook up new functionality in secp256k1 into bitcoin-s and specifically `NativeSecp256k1.java`. The following is a description of this process."/><meta name="docsearch:version" content="1.7.0"/><meta name="docsearch:language" content="en"/><meta property="og:title" content="Adding to Secp256k1 JNI · bitcoin-s"/><meta property="og:type" content="website"/><meta property="og:url" content="https://bitcoin-s.org/"/><meta property="og:description" content="Bitcoin-S uses a Java Native Interface (JNI) to execute functions in [secp256k1-zkp](https://github.com/ElementsProject/secp256k1-zkp) from java/scala. The native java bindings used to be a part of the secp256k1 library that was maintained by bitcoin-core, but it was [removed in October 2019](https://github.com/bitcoin-core/secp256k1/pull/682). We maintain a [fork of secp256k1](https://github.com/bitcoin-s/secp256k1) which forks off of bitcoin-core&#x27;s `master` but re-introduces the jni. This is also the easiest way to add functionality from new projects such as [Schnorr signatures](https://github.com/bitcoin-core/secp256k1/pull/558) and [ECDSA adaptor signatures](https://github.com/ElementsProject/secp256k1-zkp/pull/117) by rebasing the bitcoin-s branch with the JNI on top of these experimental branches. That said, it is quite tricky to hook up new functionality in secp256k1 into bitcoin-s and specifically `NativeSecp256k1.java`. The following is a description of this process."/><meta property="og:image" content="https://bitcoin-s.org/img/undraw_online.svg"/><meta name="twitter:card" content="summary"/><meta name="twitter:image" content="https://bitcoin-s.org/img/undraw_tweetstorm.svg"/><link rel="shortcut icon" href="/img/favicon.ico"/><link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css"/><link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css"/><script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-61958686-2', 'auto');
ga('send', 'pageview');
</script><link rel="stylesheet" href="/css/code-block-buttons.css"/><script type="text/javascript" src="https://buttons.github.io/buttons.js"></script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js"></script><script type="text/javascript" src="https://fonts.googleapis.com/css?family=Montserrat:500"></script><script type="text/javascript" src="https://www.googletagmanager.com/gtag/js?id=UA-61958686-2"></script><script type="text/javascript" src="/js/code-block-buttons.js"></script><script src="/js/scrollSpy.js"></script><link rel="stylesheet" href="/css/main.css"/><script src="/js/codetabs.js"></script></head><body class="sideNavVisible separateOnPageNav"><div class="fixedHeaderContainer"><div class="headerWrapper wrapper"><header><a href="/"><img class="logo" src="/img/favicon.ico" alt="bitcoin-s"/><h2 class="headerTitleWithLogo">bitcoin-s</h2></a><a href="/versions"><h3>1.7.0</h3></a><div class="navigationWrapper navigationSlider"><nav class="slidingNav"><ul class="nav-site nav-site-internal"><li class="siteNavGroupActive"><a href="/docs/1.7.0/core/core-intro" target="_self">Docs</a></li><li class=""><a href="download" target="_self">Download</a></li><li class=""><a href="/api/org/bitcoins" target="_self">API</a></li><li class=""><a href="/help" target="_self">Help</a></li><li class="navSearchWrapper reactNavSearchWrapper"><input type="text" id="search_input_react" placeholder="Search" title="Search"/></li></ul></nav></div></header></div></div><div class="navPusher"><div class="docMainWrapper wrapper"><div class="docsNavContainer" id="docsNav"><nav class="toc"><div class="toggleNav"><section class="navWrapper wrapper"><div class="navBreadcrumb wrapper"><div class="navToggle" id="navToggler"><div class="hamburger-menu"><div class="line1"></div><div class="line2"></div><div class="line3"></div></div></div><h2><i></i><span>Secp256k1</span></h2><div class="tocToggler" id="tocToggler"><i class="icon-toc"></i></div></div><div class="navGroups"><div class="navGroup"><h3 class="navGroupCategoryTitle">Getting Started</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/getting-started">Intro and Getting Started</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/bips">Supported BIPs</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Getting Setup</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/getting-setup">Getting Bitcoin-S installed on your machine</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Applications</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/applications/cli">CLI</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/applications/server">Application Server</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/applications/gui">GUI</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/applications/server-systemd">Systemd installation</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Chain</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/chain/chain">Blockchain Verification</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/chain/filter-sync">Syncing Blockfilters</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/chain/chain-query-api">Chain Query API</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Configuration</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/config/configuration">Application Configuration</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Core Module</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/core/core-intro">Core Module</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/core/addresses">Generating Addresses</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/core/hd-keys">HD Key Generation</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/core/adding-spks">Adding New Script Types</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/core/spending-info">Signing Transactions</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/core/psbts">Partially Signed Bitcoin Transactions</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/core/dlc">Discreet Log Contract Data Structures</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/core/txbuilder">TxBuilder Example</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/core/lightning-network">Lightning Network Data Types</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Crypto Module</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/crypto/crypto-intro">Crypto Module</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/crypto/sign">Sign API</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/crypto/adaptor-signatures">Adaptor Signatures</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Fee Provider</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/fee-provider/fee-provider">Fee Provider</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Key Manager</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/key-manager/server-key-manager">Server Key Manager</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/key-manager/key-manager">Key Manager</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Node</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/node/node">Light Client</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/node/node-api">Node API</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Wallet</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/wallet/wallet">Wallet</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/wallet/wallet-callbacks">Wallet Callbacks</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/wallet/wallet-get-address">Wallet Get Address APIs</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/wallet/address-tagging">Address and UTXO tagging</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/wallet/dlc">Executing A DLC with Bitcoin-S</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/wallet/wallet-rescan">Wallet Rescans</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/wallet/wallet-sync">Wallet Sync</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/wallet/wallet-rpc">Wallet RPC Examples</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/wallet/backups">Wallet Backups</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">RPC Clients</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/rpc/rpc-clients-intro">Introduction</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/rpc/rpc-eclair">Eclair</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/rpc/rpc-bitcoind">bitcoind/Bitcoin Core</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/rpc/lnd-rpc">LND</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Secp256k1</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/secp256k1/secp256k1">Secp256k1</a></li><li class="navListItem navListItemActive"><a class="navItem" href="/docs/1.7.0/secp256k1/jni-modify">Adding to Secp256k1 JNI</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Testkit</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/testkit/testkit">Testkit</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/testkit/testkit-core">Testkit Core</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">DLC Oracle</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/oracle/build-oracle-server">Building the Oracle Server</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/oracle/oracle-server">Oracle Server</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/oracle/oracle-election-example">Election Example</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/oracle/oracle-price-example">Price Example</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Oracle Explorer Client</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/oracle-explorer-client/oracle-explorer-client">Oracle Explorer Client</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Contributing</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/contributing">Contributing</a></li><li class="navListItem"><a class="navItem" href="/docs/1.7.0/contributing-website">Contributing to the website</a></li></ul></div><div class="navGroup"><h3 class="navGroupCategoryTitle">Security</h3><ul class=""><li class="navListItem"><a class="navItem" href="/docs/1.7.0/security">Security</a></li></ul></div></div></section></div><script>
var coll = document.getElementsByClassName('collapsible');
var checkActiveCategory = true;
for (var i = 0; i < coll.length; i++) {
var links = coll[i].nextElementSibling.getElementsByTagName('*');
if (checkActiveCategory){
for (var j = 0; j < links.length; j++) {
if (links[j].classList.contains('navListItemActive')){
coll[i].nextElementSibling.classList.toggle('hide');
coll[i].childNodes[1].classList.toggle('rotate');
checkActiveCategory = false;
break;
}
}
}
coll[i].addEventListener('click', function() {
var arrow = this.childNodes[1];
arrow.classList.toggle('rotate');
var content = this.nextElementSibling;
content.classList.toggle('hide');
});
}
document.addEventListener('DOMContentLoaded', function() {
createToggler('#navToggler', '#docsNav', 'docsSliderActive');
createToggler('#tocToggler', 'body', 'tocActive');
var headings = document.querySelector('.toc-headings');
headings && headings.addEventListener('click', function(event) {
var el = event.target;
while(el !== headings){
if (el.tagName === 'A') {
document.body.classList.remove('tocActive');
break;
} else{
el = el.parentNode;
}
}
}, false);
function createToggler(togglerSelector, targetSelector, className) {
var toggler = document.querySelector(togglerSelector);
var target = document.querySelector(targetSelector);
if (!toggler) {
return;
}
toggler.onclick = function(event) {
event.preventDefault();
target.classList.toggle(className);
};
}
});
</script></nav></div><div class="container mainContainer docsContainer"><div class="wrapper"><div class="post"><header class="postHeader"><a class="edit-page-link button" href="https://github.com/bitcoin-s/bitcoin-s/blob/master/docs/secp256k1/add-to-jni.md" target="_blank" rel="noreferrer noopener">Edit</a><h1 id="__docusaurus" class="postHeaderTitle">Adding to Secp256k1 JNI</h1></header><article><div><span><p>Bitcoin-S uses a Java Native Interface (JNI) to execute functions in <a href="https://github.com/ElementsProject/secp256k1-zkp">secp256k1-zkp</a> from java/scala. The native java bindings used to be a part of the secp256k1 library that was maintained by bitcoin-core, but it was <a href="https://github.com/bitcoin-core/secp256k1/pull/682">removed in October 2019</a>. We maintain a <a href="https://github.com/bitcoin-s/secp256k1">fork of secp256k1</a> which forks off of bitcoin-core's <code>master</code> but re-introduces the jni. This is also the easiest way to add functionality from new projects such as <a href="https://github.com/bitcoin-core/secp256k1/pull/558">Schnorr signatures</a> and <a href="https://github.com/ElementsProject/secp256k1-zkp/pull/117">ECDSA adaptor signatures</a> by rebasing the bitcoin-s branch with the JNI on top of these experimental branches. That said, it is quite tricky to hook up new functionality in secp256k1 into bitcoin-s and specifically <code>NativeSecp256k1.java</code>. The following is a description of this process.</p>
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
<!-- END doctoc -->
<ul>
<li><a href="#adding-a-new-function-to-nativesecp256k1java">Adding a new function to NativeSecp256k1.java</a>
<ul>
<li><a href="#adding-to-srcjavaorg_bitcoin_nativesecp256k1c">Adding to <code>src/java/org_bitcoin_NativeSecp256k1.c</code></a></li>
<li><a href="#adding-to-srcjavaorg_bitcoin_nativesecp256k1h">Adding to <code>src/java/org_bitcoin_NativeSecp256k1.h</code></a></li>
<li><a href="#adding-to-srcjavaorgbitcoinnativesecp256k1java">Adding to <code>src/java/org/bitcoin/NativeSecp256k1.java</code></a></li>
<li><a href="#adding-to-srcjavaorgbitcoinnativesecp256k1testjava">Adding to <code>src/java/org/bitcoin/NativeSecp256k1Test.java</code></a></li>
<li><a href="#adding-to-bitcoin-s">Adding to Bitcoin-S</a></li>
<li><a href="#further-work-to-enable-typed-invocations-and-nice-tests">Further Work to Enable Typed Invocations and Nice Tests</a></li>
</ul></li>
</ul>
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<h2><a class="anchor" aria-hidden="true" id="adding-a-new-function-to-nativesecp256k1java"></a><a href="#adding-a-new-function-to-nativesecp256k1java" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Adding a new function to NativeSecp256k1.java</h2>
<h3><a class="anchor" aria-hidden="true" id="adding-to-srcjavaorg_bitcoin_nativesecp256k1c"></a><a href="#adding-to-srcjavaorg_bitcoin_nativesecp256k1c" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Adding to <code>src/java/org_bitcoin_NativeSecp256k1.c</code></h3>
<ol>
<li><p>Add an <code>#include</code> import at the top (if applicable)</p>
<p>If your secp256k1 functions are not already included, you will need to <code>#include</code> the header file (should be in the <code>secp256k1/include</code> directory).</p></li>
<li><p>Function signature</p>
<p>Your new function signature should begin with</p>
<pre><code class="hljs css language-c">SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_
</code></pre>
<p>followed by the secp256k1 function name where <code>_</code> are replaced with <code>_1</code> (it's a weird jni thing). Finally, you add a parameter list that begins with</p>
<pre><code class="hljs css language-c">(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l
</code></pre>
<p>and ends with any <code>jint</code>s in the case that any of the secp256k1 function inputs have variable length (such as public keys which can be either <code>33</code> or <code>65</code> bytes, or ECDSA signatures), and lastly any <code>jboolean</code>s in case there is some flag like <code>compressed</code> passed in.</p>
<p>As an example that includes everything, if you are making a call to <code>secp256k1_pubkey_tweak_add</code> which takes in public keys that could be <code>33</code> or <code>65</code> bytes and outputs a public key that will either be compressed or decompressed based on an input flag, then the function signature would be</p>
<pre><code class="hljs css language-c"><span class="hljs-function">SECP256K1_API jobjectArray JNICALL <span class="hljs-title">Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add</span>
<span class="hljs-params">(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen, jboolean compressed)</span>
</span></code></pre></li>
<li><p>Reading <code>unsigned char*</code> inputs</p>
<p>It is now time to create pointers for each of the secp256k1 function inputs that where passed in via the <code>byteBufferObject</code>. We must first read in the <code>Secp256k1Context</code> with the line</p>
<pre><code class="hljs css language-c">secp256k1_context *ctx = (secp256k1_context*)(<span class="hljs-keyword">uintptr_t</span>)ctx_l;
</code></pre>
<p>and we can then initialize the first pointer to be the beginning of the <code>byteBufferObject</code> with the line</p>
<pre><code class="hljs css language-c"><span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>* firstArg = (*env)-&gt;GetDirectBufferAddress(env, byteBufferObject);
</code></pre>
<p>and subsequent arguments' pointers where the previous argument's length is known (say <code>32</code> bytes for example) can be instantiated using</p>
<pre><code class="hljs css language-c"><span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>* prevArg = ...
<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>* nextArg = (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>*) (prevArg + <span class="hljs-number">32</span>);
</code></pre>
<p>and in the case that a previous argument has variable length, then a <code>jint</code> has been provided as an input and can be used instead, such as in the example</p>
<pre><code class="hljs css language-c"><span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>* prevArg = ...
<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>* nextArg = (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>*) (prevArg + publen);
</code></pre>
<p>where <code>publen</code> is a <code>jint</code> passed to this C function.</p>
<p>As an example that includes everything, consider the function <code>secp256k1_ecdsa_verify</code> which takes as input a <code>32</code> byte message, a variable length signature and a public key (of length <code>33</code> or <code>65</code> bytes). Our function will begin with</p>
<pre><code class="hljs css language-c">{
secp256k1_context *ctx = (secp256k1_context*)(<span class="hljs-keyword">uintptr_t</span>)ctx_l;
<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>* data = (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>*) (*env)-&gt;GetDirectBufferAddress(env, byteBufferObject);
<span class="hljs-keyword">const</span> <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>* sigdata = (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>*) (data + <span class="hljs-number">32</span>);
<span class="hljs-keyword">const</span> <span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>* pubdata = (<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>*) (sigdata + siglen);
</code></pre>
<p>where <code>siglen</code> is a <code>jint</code> passed into the C function.</p></li>
<li><p>Initialize variables</p>
<p>Next we must declare all variables. We put all decelerations here as it is required by the C framework used by <code>libsecp256k1</code> that definitions and assignments/function calls cannot be interleaved.</p>
<p>Specifically you will need to declare any secp256k1 specific structs here as well as all outputs (such as <code>jobjectArrays</code> and <code>jByteArrays</code>). Generally speaking this will include all inputs which are not raw data (public keys, signatures, etc). Lastly, you will also have an <code>int ret</code> which will store <code>0</code> if an error occurred and <code>1</code> otherwise.</p>
<p>As an example that includes everything, consider again the function <code>secp256k1_pubkey_tweak_add</code> has the following declarations</p>
<pre><code class="hljs css language-c">jobjectArray retArray;
jbyteArray pubArray, intsByteArray;
<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> intsarray[<span class="hljs-number">2</span>];
<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> outputSer[<span class="hljs-number">65</span>];
<span class="hljs-keyword">size_t</span> outputLen = <span class="hljs-number">65</span>;
secp256k1_pubkey pubkey;
<span class="hljs-keyword">int</span> ret;
</code></pre>
<p>Where <code>retArray</code> is eventually going to be the data returned, which will contain the <code>jbyteArray</code>s <code>pubArray</code> and <code>intsByteArray</code>, which will contain <code>outputSer</code> and <code>intsarray</code> respectively. Lastly <code>pubkey</code> will store a deserialized <code>secp256k1_pubkey</code> corresponding to the input <code>unsigned char*</code> public key.</p></li>
<li><p>Parse inputs when applicable</p>
<p>In the case where there are <code>unsigned char*</code> inputs which need to be deserialized into secp256k1 structs, this is done now. As an example, <code>secp256k1_pubkey_tweak_add</code> takes a public key as input:</p>
<pre><code class="hljs css language-c"><span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>* pkey = (*env)-&gt;GetDirectBufferAddress(env, byteBufferObject);
</code></pre>
<p>where a <code>jint publen</code> is passed in as a function parameter. This function already has a declaration for <code>secp256k1_pubkey pubkey;</code>. The first call made after the above declarations is</p>
<pre><code class="hljs css language-c">ret = secp256k1_ec_pubkey_parse(ctx, &amp;pubkey, pkey, publen)
</code></pre>
<p>and if further parsing is necessary, it is put inside of <code>if (ret) { ret = [further parsing here] }</code>.</p></li>
<li><p>Make calls to secp256k1 functions to instantiate outputs</p>
<p>It is finally time to actually call the secp256k1 function we are binding to the jni! This is done by simply calling <code>ret = [call to secp function here];</code> or <code>if (ret) { ret = [secp function call] };</code> if there were any inputs that needed to be parsed. Note that some secp256k1 functions return outputs by populating variables you should have declared and for which pointers are passed as inputs, while other functions will mutate their inputs rather than returning outputs.</p></li>
<li><p>Serialize variable length outputs if applicable</p>
<p>When dealing with variable length outputs such as signatures, you will likely need to serialize these outputs. This is done by having already instantiated such a variable as</p>
<pre><code class="hljs css language-c"><span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span> outputSer[<span class="hljs-number">72</span>];
<span class="hljs-keyword">size_t</span> outputLen = <span class="hljs-number">72</span>;
</code></pre>
<p>where in this case <code>72</code> is an upper bound on signature length. With these variables existing (as well as a <code>secp256k1_ecdsa_signature sig</code> which has been populated), we call a secp256k1 serialization function to populate <code>outputSer</code> and <code>outputLen</code> from <code>sig</code></p>
<pre><code class="hljs css language-c"><span class="hljs-keyword">if</span>(ret) {
<span class="hljs-keyword">int</span> ret2 = secp256k1_ecdsa_signature_serialize_der(ctx, outputSer, &amp;outputLen, &amp;sig);
(<span class="hljs-keyword">void</span>)ret2;
}
</code></pre>
<p>As you can see, in this case we do not which to alter the value returned in <code>ret</code> if serialization fails. If we did then <code>ret2</code> would not be introduced and we would instead do <code>ret = [serialize]</code>.</p></li>
<li><p>Populate return array when applicable</p>
<p>We now begin translating our serialized results back into Java entities. If you are returning any <code>int</code>s containing meta-data (usually <code>ret</code> is included here, as are the variable lengths of outputs when applicable), you will want an <code>unsigned char intsarray[n]</code> to be already declared where <code>n</code> is the number of pieces of meta-data. For example, in <code>secp256k1_ecdsa_sign</code>, we wish to return whether there were any errors (stored in <code>int ret</code>) and the output signature's length, <code>size_t outputLen</code>. Hence we have an <code>unsigned char intsarray[2]</code> and we populate it as follows</p>
<pre><code class="hljs css language-c">intsarray[<span class="hljs-number">0</span>] = outputLen;
intsarray[<span class="hljs-number">1</span>] = ret;
</code></pre>
<p>Next we populate the <code>jobjectArray</code> we wish to return, this will always begin with a call</p>
<pre><code class="hljs css language-c">retArray = (*env)-&gt;NewObjectArray(env, <span class="hljs-number">2</span>,
(*env)-&gt;FindClass(env, <span class="hljs-string">"[B"</span>),
(*env)-&gt;NewByteArray(env, <span class="hljs-number">1</span>));
</code></pre>
<p>to instantiate an empty return array. Next we instantiate our <code>jbyteArray</code>s with calls to</p>
<pre><code class="hljs css language-c">myByteArray = (*env)-&gt;NewByteArray(env, len);
</code></pre>
<p>where <code>myByteArray</code> is replaced with a real name (such as <code>intsByteArray</code>) and <code>len</code> is replaced with the length of this array (either a constant or a populated <code>size_t</code> variable). Next we populate this array with our data by calling</p>
<pre><code class="hljs css language-c">(*env)-&gt;SetByteArrayRegion(env, myByteArray, <span class="hljs-number">0</span>, len, (jbyte*)myData);
</code></pre>
<p>where <code>myData</code> is a C array of <code>unsigned char</code> (of length <code>len</code>). Lastly, we place <code>myByteArray</code> into its place in <code>retArray</code> with</p>
<pre><code class="hljs css language-c">(*env)-&gt;SetObjectArrayElement(env, retArray, index, myByteArray);
</code></pre>
<p>where <code>index</code> is a constant (<code>0</code>, <code>1</code>, <code>2</code>, etc.) for the index of <code>myByteArray</code> within <code>retArray</code>. Note that you should follow our conventions and have index <code>0</code> contain the actual data to be returned and index <code>1</code> (and onward) contain any meta-data.</p>
<p>Please note that if you wish not to return such meta-data (such as if you wish to return only a <code>boolean</code>), then none of the code in this subsection is required</p></li>
<li><p>void <code>classObject</code></p>
<p>Once we are ready to return, we first void the input <code>classObject</code> by making the call</p>
<pre><code class="hljs css language-c">(<span class="hljs-keyword">void</span>)classObject;
</code></pre></li>
<li><p>Return array when applicable, <code>ret</code> when applicable</p>
<p>Lastly, we return <code>retArray</code> in the case where we wish to return a <code>byte[]</code>, or <code>ret</code> in the case that we wish to return a <code>boolean</code>.</p></li>
</ol>
<h3><a class="anchor" aria-hidden="true" id="adding-to-srcjavaorg_bitcoin_nativesecp256k1h"></a><a href="#adding-to-srcjavaorg_bitcoin_nativesecp256k1h" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Adding to <code>src/java/org_bitcoin_NativeSecp256k1.h</code></h3>
<p>Once your function is defined in <code>src/java/org_bitcoin_NativeSecp256k1.c</code>, you must define them in the corresponding header files by simply copying the function signature but without parameter names. For example, if <code>secp256k1_pubkey_tweak_add</code> has the function signature</p>
<pre><code class="hljs css language-c"><span class="hljs-function">SECP256K1_API jobjectArray JNICALL <span class="hljs-title">Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add</span>
<span class="hljs-params">(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen, jboolean compressed)</span>
</span></code></pre>
<p>then in the header file we include</p>
<pre><code class="hljs css language-c"><span class="hljs-comment">/*
* Class: org_bitcoin_NativeSecp256k1
* Method: secp256k1_pubkey_tweak_add
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
*/</span>
<span class="hljs-function">SECP256K1_API jobjectArray JNICALL <span class="hljs-title">Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add</span>
<span class="hljs-params">(JNIEnv *, jclass, jobject, jlong, jint, jboolean)</span></span>;
</code></pre>
<h3><a class="anchor" aria-hidden="true" id="adding-to-srcjavaorgbitcoinnativesecp256k1java"></a><a href="#adding-to-srcjavaorgbitcoinnativesecp256k1java" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Adding to <code>src/java/org/bitcoin/NativeSecp256k1.java</code></h3>
<p>We are now done writing C code! We have completed an interface in C for the JNI to hook up to. However, we must now write the corresponding Java code which hides the Java to C (and back) conversions from other Java code. We accomplish this with a <code>class</code> of <code>static</code> methods called <code>NativeSecp256k1</code>.</p>
<ol>
<li><p>Add <code>private static native</code> secp256k1 function</p>
<p>We begin by adding a <code>private static native</code> method at the bottom of the file corresponding to our secp256k1 function. Notice that the syntax for <code>native</code> methods is similar to that of Java abstract interface methods where instead of providing an implementation we simply end with a semi-colon.</p>
<p>For functions returning <code>boolean</code>s, we have their <code>native</code> methods return <code>int</code> (will be <code>0</code> or <code>1</code>). Otherwise, for functions returning <code>byte[]</code>s, we have their <code>native</code> methods return <code>byte[][]</code> (two dimensional array to allow for meta-data).</p></li>
<li><p>Method signature</p>
<p>Next we add a method to the <code>NativeSecp256k1</code> class</p>
<pre><code class="hljs css language-java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">byte</span>[] myFunc(<span class="hljs-keyword">byte</span>[] input1, <span class="hljs-keyword">byte</span>[] input2, <span class="hljs-keyword">boolean</span> input3) <span class="hljs-keyword">throws</span> AssertFailException
</code></pre>
<p>where <code>boolean</code> could also be the return type instead of <code>byte[]</code>.</p></li>
<li><p><code>checkArgument</code>s</p>
<p>We begin implementing this function by checking the input argument lengths using the <code>checkArument</code> function</p>
<pre><code class="hljs css language-java">checkArgument(input1.length == <span class="hljs-number">32</span> &amp;&amp; (input2.length == <span class="hljs-number">33</span> || input2.length == <span class="hljs-number">65</span>));
</code></pre></li>
<li><p>Initialize <code>ByteBuffer</code></p>
<p>We now initialize the <code>ByteBuffer</code> which we will be passing through the JNI as an input. This is done with a call to</p>
<pre><code class="hljs css language-java">ByteBuffer byteBuff = nativeECDSABuffer.get();
</code></pre>
<p>followed by allocation when necessary as follows</p>
<pre><code class="hljs css language-java"><span class="hljs-keyword">if</span> (byteBuff == <span class="hljs-keyword">null</span> || byteBuff.capacity() &lt; input1.length + input2.length) {
byteBuff = ByteBuffer.allocateDirect(input1.length + input2.length);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
</code></pre>
<p>where <code>input1.length + input2.length</code> is replaced by whatever the total <code>ByteBuffer</code> length needed.</p></li>
<li><p>Fill <code>ByteBuffer</code></p>
<p>We now populate the <code>ByteBuffer</code> as follows</p>
<pre><code class="hljs css language-java">byteBuff.rewind();
byteBuff.put(input1);
byteBuff.put(input2);
</code></pre>
<p>where generally, you will <code>rewind()</code> and then <code>put()</code> all inputs (in order).</p></li>
<li><p>Make <code>native</code> call</p>
<p>It is now time to make a call to our <code>native</code> C function.</p>
<p>In the case where we are returning a <code>byte[]</code>, this is done by first declaring a <code>byte[][]</code> to store the output and then locking the read lock, <code>r</code>. Then we call the <code>native</code> function within a <code>try</code> clause which releases the lock in the <code>finally</code> clause.</p>
<pre><code class="hljs css language-java"><span class="hljs-keyword">byte</span>[][] retByteArray;
r.lock();
<span class="hljs-keyword">try</span> {
retByteArray = secp256k1_my_call(byteBuff, Secp256k1Context.getContext(), input3);
} <span class="hljs-keyword">finally</span> {
r.unlock();
}
</code></pre>
<p>In the case where we are returning a <code>boolean</code>, simply make the call in the <code>try</code> and compare the output to <code>1</code> like so</p>
<pre><code class="hljs css language-java">r.lock();
<span class="hljs-keyword">try</span> {
<span class="hljs-keyword">return</span> secp256k1_my_bool_call(byteBuff, Secp256k1Context.getContext()) == <span class="hljs-number">1</span>;
} <span class="hljs-keyword">finally</span> {
r.unlock();
}
</code></pre>
<p>If this is the case, you are now done and can ignore the following steps.</p></li>
<li><p>Parse outputs</p>
<p><code>retByteArray</code> should now be populated and we want to read its two parts (data and meta-data). Getting the data should be as easy as</p>
<pre><code class="hljs css language-java"><span class="hljs-keyword">byte</span>[] resultArr = retByteArr[<span class="hljs-number">0</span>];
</code></pre>
<p>while for each piece of meta-data, you can read the corresponding <code>int</code> as follows</p>
<pre><code class="hljs css language-java"><span class="hljs-keyword">int</span> metaVal = <span class="hljs-keyword">new</span> BigInteger(<span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[] { retByteArray[<span class="hljs-number">1</span>][index] }).intValue();
</code></pre>
<p>where <code>index</code> is replaced with the index in the meta-data array.</p></li>
<li><p>Validate outputs</p>
<p>In the case where we now have meta-data, we validate it with calls to <code>assertEquals</code>.</p></li>
<li><p>Return output</p>
<p>Finally, we return <code>resultArr</code>.</p></li>
</ol>
<h3><a class="anchor" aria-hidden="true" id="adding-to-srcjavaorgbitcoinnativesecp256k1testjava"></a><a href="#adding-to-srcjavaorgbitcoinnativesecp256k1testjava" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Adding to <code>src/java/org/bitcoin/NativeSecp256k1Test.java</code></h3>
<p>I normally first build the C binaries and add to Bitcoin-S before coming back to this section because I use <code>sbt core/console</code> to generate values and make calls below, but this is not a requirement.</p>
<ol>
<li><p>Generate values and make calls to <code>org.bitcoin.NativeSecp256k1</code> to generate inputs and their expected outputs</p></li>
<li><p>Create regression unit tests with these values in NativeSecp256k1Test</p>
<p>Note that you can use <code>DatatypeConverter.parseHexBinary</code> to convert <code>String</code> hex to a <code>byte[]</code>, and you can use <code>DatatypeConverter.printHexBinary</code> to convert a <code>byte[]</code> to its <code>String</code> hex. Lastly you will make assertions with calls to <code>assertEquals</code>.</p></li>
<li><p>Add test to <code>main</code></p></li>
</ol>
<h3><a class="anchor" aria-hidden="true" id="adding-to-bitcoin-s"></a><a href="#adding-to-bitcoin-s" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Adding to Bitcoin-S</h3>
<ol>
<li><p>Translate <code>NativeSecp256k1</code> and <code>NativeSecp256k1Test</code> to jni project</p>
<p>By translate I mean to say that you must copy the functions from those files to the corresponding files in the <code>bitcoin-s/secp256k1jni</code> project. For tests this will require changing the methods to be non-<code>static</code> as well as adding the <code>@Test</code> annotation above each method (rather than adding to a <code>main</code> method).</p></li>
<li><p>Configure and build <code>secp256k1</code></p>
<p>You will need to go to the <code>bitcoin-s/secp256k1</code> directory in a terminal and running the following where you may need to add to the <code>./configure</code> command if you are introducing a new module.</p>
<p><strong>For Linux or OSx (64-bit)</strong></p>
<p>You will have to make sure <code>JAVA_HOME</code> is set, and build tools are installed, for Linux this requires:</p>
<pre><code class="hljs css language-bashrc">echo <span class="hljs-keyword">JAVA_HOME
</span>sudo apt <span class="hljs-keyword">install </span><span class="hljs-keyword">build-essential </span>autotools-dev libtool automake
</code></pre>
<p>and for Mac this requires:</p>
<pre><code class="hljs css language-bashrc"><span class="hljs-keyword">brew </span><span class="hljs-keyword">install </span>automake libtool
</code></pre>
<p>You should then be able to build <code>libsecp256k1</code> with the following:</p>
<pre><code class="hljs css language-bashrc"><span class="hljs-keyword">.</span>/autogen.sh
<span class="hljs-keyword">.</span>/configure --enable-jni --enable-experimental --enable-module-ecdh --enable-module-schnorrsig --enable-module-ecdsa-adaptor
make CFLAGS=<span class="hljs-string">"-std=c99"</span>
make<span class="hljs-built_in"> check
</span>make<span class="hljs-built_in"> check-java
</span></code></pre>
<p><strong>For Windows (64-bit)</strong></p>
<p>Windows bindings are cross-built on Linux. You need to install the <code>mingw</code> toolchain and have <code>JAVA_HOME</code> point to a Windows JDK:</p>
<pre><code class="hljs css language-bashrc"><span class="hljs-comment">sudo</span> <span class="hljs-comment">apt</span> <span class="hljs-comment">install</span> <span class="hljs-comment">g</span>++<span class="hljs-literal">-</span><span class="hljs-comment">mingw</span><span class="hljs-literal">-</span><span class="hljs-comment">w64</span><span class="hljs-literal">-</span><span class="hljs-comment">x86</span><span class="hljs-literal">-</span><span class="hljs-comment">64</span>
<span class="hljs-comment">sudo</span> <span class="hljs-comment">update</span><span class="hljs-literal">-</span><span class="hljs-comment">alternatives</span> --<span class="hljs-comment">config</span> <span class="hljs-comment">x86_64</span><span class="hljs-literal">-</span><span class="hljs-comment">w64</span><span class="hljs-literal">-</span><span class="hljs-comment">mingw32</span><span class="hljs-literal">-</span><span class="hljs-comment">g</span>++
</code></pre>
<p>You should then be able to build <code>libsecp256k1</code> with the following:</p>
<pre><code class="hljs css language-bashrc"><span class="hljs-keyword">echo</span> <span class="hljs-string">"LDFLAGS = -no-undefined"</span> &gt;&gt; Makefile.am
<span class="hljs-string">./configure</span> <span class="hljs-params">--host=x86_64-w64-mingw32</span> <span class="hljs-params">--enable-jni</span> <span class="hljs-params">--enable-experimental</span> <span class="hljs-params">--enable-module-ecdh</span> <span class="hljs-params">--enable-module-schnorrsig</span> <span class="hljs-params">--enable-module-ecdsa-adaptor</span> &amp;&amp; make clean &amp;&amp; make CFLAGS=<span class="hljs-string">"-std=c99"</span>
</code></pre>
<p>There may be some errors that can be ignored:</p>
<ul>
<li><code>Could not determine the host path corresponding to</code></li>
<li><code>redeclared without dllimport attribute: previous dllimport ignored</code></li>
</ul></li>
<li><p>Copy binaries into bitcoin-s natives for your system</p>
<p>You have now built the C binaries for your JNI bindings for your operating system and you should now find your operating system's directory in <code>bitcoin-s/secp256k1jni/natives</code> and replace its contents with the contents of <code>secp256k1/.libs</code> (which contains the compiled binaries).</p></li>
<li><p>Run <code>secp256k1jni</code> tests</p>
<p>If you have not yet implemented tests, you should now be able to go back and do so as calls to <code>NativeSecp256k1</code> should now succeed.</p>
<p>Once you have tests implemented, and assuming you've copied them correctly to the <code>bitcoin-s/secp256k1jni</code> project, you should be able to run them using</p>
<pre><code class="hljs css language-bashrc">sbt secp256k1jni/<span class="hljs-built_in">test</span>
</code></pre></li>
</ol>
<h3><a class="anchor" aria-hidden="true" id="further-work-to-enable-typed-invocations-and-nice-tests"></a><a href="#further-work-to-enable-typed-invocations-and-nice-tests" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Further Work to Enable Typed Invocations and Nice Tests</h3>
<ol>
<li><p>Add new <code>NetworkElement</code>s where applicable</p>
<p>In the case where you are dealing in new kinds of data that are not yet defined in Bitcoin-S, you should add these as <code>case class</code>es extending the <code>NetworkElement</code> trait, and give them companion objects extending <code>Factory</code> for easy serialization and deserialization.</p>
<p>This step is not necessary if you are only dealing in raw data, <code>ECPrivateKey</code>s, <code>ECPublicKey</code>s, etc.</p></li>
<li><p>Add new typed functions to relevant data types where applicable</p>
<p>In the case where your new function should be a static method, find a good <code>object</code> (or introduce one) and give it a <code>def</code> which takes in typed arguments and outputs typed arguments (using <code>ByteVector</code> in all places dealing with raw data rather than using <code>Array[Byte]</code>). You will then implement these methods using calls to <code>NativeSecp256k1</code> methods and getting the inputs into <code>Array[Byte]</code> form by getting their <code>ByteVector</code>s (usually through a call to <code>_.bytes</code>) and then calling <code>_.toArray</code>.</p>
<p>You will then need to take the data returned and deserialize it.</p>
<p>In the case where your new function belongs naturally as an action performed by some existing or newly introduced type, you can implement your new function as a call made by that class as described for the previous case but where the class will pass a serialized version of itself into the <code>NativeSecp256k1</code> call.</p>
<p>It is often acceptable to implement the call in an <code>object</code> and then also add the call (via a call to the object, passing <code>this</code>) to the interface of relevant types.</p></li>
<li><p>Implement Bouncy Castle fallback in <code>BouncyCastleUtil.scala</code> if you can.</p></li>
<li><p>Add unit and property-based tests.</p></li>
<li><p>If you implemented Bouncy Castle fallback, add tests to <code>BouncyCastleSecp256k1Test</code> to compare implementations</p></li>
</ol>
</span></div></article></div><div class="docLastUpdate"><em>Last updated on 4/21/2021 by Nadav Kohen</em></div><div class="docs-prevnext"><a class="docs-prev button" href="/docs/1.7.0/secp256k1/secp256k1"><span class="arrow-prev"></span><span>Secp256k1</span></a><a class="docs-next button" href="/docs/1.7.0/testkit/testkit"><span>Testkit</span><span class="arrow-next"></span></a></div></div></div><nav class="onPageNav"><ul class="toc-headings"><li><a href="#adding-a-new-function-to-nativesecp256k1java">Adding a new function to NativeSecp256k1.java</a><ul class="toc-headings"><li><a href="#adding-to-srcjavaorg_bitcoin_nativesecp256k1c">Adding to <code>src/java/org_bitcoin_NativeSecp256k1.c</code></a></li><li><a href="#adding-to-srcjavaorg_bitcoin_nativesecp256k1h">Adding to <code>src/java/org_bitcoin_NativeSecp256k1.h</code></a></li><li><a href="#adding-to-srcjavaorgbitcoinnativesecp256k1java">Adding to <code>src/java/org/bitcoin/NativeSecp256k1.java</code></a></li><li><a href="#adding-to-srcjavaorgbitcoinnativesecp256k1testjava">Adding to <code>src/java/org/bitcoin/NativeSecp256k1Test.java</code></a></li><li><a href="#adding-to-bitcoin-s">Adding to Bitcoin-S</a></li><li><a href="#further-work-to-enable-typed-invocations-and-nice-tests">Further Work to Enable Typed Invocations and Nice Tests</a></li></ul></li></ul></nav></div><footer class="nav-footer" id="footer"><section class="sitemap"><a href="/" class="nav-home"><img src="/img/favicon.ico" alt="bitcoin-s" width="66" height="58"/></a><div><h5>Docs</h5><a href="/docs/en/getting-started">Getting Started</a><a href="/docs/en/core/core-intro">Guides</a><a href="/api/org/bitcoins">API Reference</a></div><div><h5>Community</h5><a href="/en/users.html">User Showcase</a><a href="https://join.slack.com/t/suredbits/shared_invite/zt-eavycu0x-WQL7XOakzQo8tAy7jHHZUw" target="_blank" rel="noreferrer noopener">Slack</a><a href="https://gitter.im/bitcoin-s-core/">Gitter chat</a></div><div><h5>More</h5><a href="https://github.com/bitcoin-s/bitcoin-s">GitHub</a><a class="github-button" href="https://github.com/bitcoin-s/bitcoin-s" data-icon="octicon-star" data-count-href="/bitcoin-s/bitcoin-s-core/stargazers" data-show-count="true" data-count-aria-label="# stargazers on GitHub" aria-label="Star this project on GitHub">Star</a></div></section><section class="copyright">Copyright © 2021 Suredbits &amp; the bitcoin-s developers</section></footer></div><script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script><script>
document.addEventListener('keyup', function(e) {
if (e.target !== document.body) {
return;
}
// keyCode for '/' (slash)
if (e.keyCode === 191) {
const search = document.getElementById('search_input_react');
search && search.focus();
}
});
</script><script>
var search = docsearch({
apiKey: '0a510688bf8448e19aeb380377d328d3',
indexName: 'bitcoin-s',
inputSelector: '#search_input_react'
});
</script></body></html>