1 /*
2  * Copyright 2013 Google Inc.
3  * Copyright 2014-2016 the libsecp256k1 contributors
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *    http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package org.bitcoin;
19 
20 import java.nio.ByteBuffer;
21 import java.nio.ByteOrder;
22 
23 import java.math.BigInteger;
24 import com.google.common.base.Preconditions;
25 import java.util.concurrent.locks.Lock;
26 import java.util.concurrent.locks.ReentrantReadWriteLock;
27 import static org.bitcoin.NativeSecp256k1Util.*;
28 
29 /**
30  * <p>This class holds native methods to handle ECDSA verification.</p>
31  *
32  * <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
33  *
34  * <p>To build secp256k1 for use with bitcoinj, run
35  * `./configure --enable-jni --enable-experimental --enable-module-ecdh`
36  * and `make` then copy `.libs/libsecp256k1.so` to your system library path
37  * or point the JVM to the folder containing it with -Djava.library.path
38  * </p>
39  */
40 public class NativeSecp256k1 {
41 
42     private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
43     private static final Lock r = rwl.readLock();
44     private static final Lock w = rwl.writeLock();
45     private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
46     /**
47      * Verifies the given secp256k1 signature in native code.
48      * Calling when enabled == false is undefined (probably library not loaded)
49      *
50      * @param data The data which was signed, must be exactly 32 bytes
51      * @param signature The signature
52      * @param pub The public key which did the signing
53      */
verify(byte[] data, byte[] signature, byte[] pub)54     public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{
55         Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
56 
57         ByteBuffer byteBuff = nativeECDSABuffer.get();
58         if (byteBuff == null || byteBuff.capacity() < 520) {
59             byteBuff = ByteBuffer.allocateDirect(520);
60             byteBuff.order(ByteOrder.nativeOrder());
61             nativeECDSABuffer.set(byteBuff);
62         }
63         byteBuff.rewind();
64         byteBuff.put(data);
65         byteBuff.put(signature);
66         byteBuff.put(pub);
67 
68         byte[][] retByteArray;
69 
70         r.lock();
71         try {
72           return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
73         } finally {
74           r.unlock();
75         }
76     }
77 
78     /**
79      * libsecp256k1 Create an ECDSA signature.
80      *
81      * @param data Message hash, 32 bytes
82      * @param key Secret key, 32 bytes
83      *
84      * Return values
85      * @param sig byte array of signature
86      */
sign(byte[] data, byte[] sec)87     public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
88         Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
89 
90         ByteBuffer byteBuff = nativeECDSABuffer.get();
91         if (byteBuff == null || byteBuff.capacity() < 32 + 32) {
92             byteBuff = ByteBuffer.allocateDirect(32 + 32);
93             byteBuff.order(ByteOrder.nativeOrder());
94             nativeECDSABuffer.set(byteBuff);
95         }
96         byteBuff.rewind();
97         byteBuff.put(data);
98         byteBuff.put(sec);
99 
100         byte[][] retByteArray;
101 
102         r.lock();
103         try {
104           retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
105         } finally {
106           r.unlock();
107         }
108 
109         byte[] sigArr = retByteArray[0];
110         int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
111         int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
112 
113         assertEquals(sigArr.length, sigLen, "Got bad signature length.");
114 
115         return retVal == 0 ? new byte[0] : sigArr;
116     }
117 
118     /**
119      * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
120      *
121      * @param seckey ECDSA Secret key, 32 bytes
122      */
secKeyVerify(byte[] seckey)123     public static boolean secKeyVerify(byte[] seckey) {
124         Preconditions.checkArgument(seckey.length == 32);
125 
126         ByteBuffer byteBuff = nativeECDSABuffer.get();
127         if (byteBuff == null || byteBuff.capacity() < seckey.length) {
128             byteBuff = ByteBuffer.allocateDirect(seckey.length);
129             byteBuff.order(ByteOrder.nativeOrder());
130             nativeECDSABuffer.set(byteBuff);
131         }
132         byteBuff.rewind();
133         byteBuff.put(seckey);
134 
135         r.lock();
136         try {
137           return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;
138         } finally {
139           r.unlock();
140         }
141     }
142 
143 
144     /**
145      * libsecp256k1 Compute Pubkey - computes public key from secret key
146      *
147      * @param seckey ECDSA Secret key, 32 bytes
148      *
149      * Return values
150      * @param pubkey ECDSA Public key, 33 or 65 bytes
151      */
152     //TODO add a 'compressed' arg
computePubkey(byte[] seckey)153     public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
154         Preconditions.checkArgument(seckey.length == 32);
155 
156         ByteBuffer byteBuff = nativeECDSABuffer.get();
157         if (byteBuff == null || byteBuff.capacity() < seckey.length) {
158             byteBuff = ByteBuffer.allocateDirect(seckey.length);
159             byteBuff.order(ByteOrder.nativeOrder());
160             nativeECDSABuffer.set(byteBuff);
161         }
162         byteBuff.rewind();
163         byteBuff.put(seckey);
164 
165         byte[][] retByteArray;
166 
167         r.lock();
168         try {
169           retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
170         } finally {
171           r.unlock();
172         }
173 
174         byte[] pubArr = retByteArray[0];
175         int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
176         int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
177 
178         assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
179 
180         return retVal == 0 ? new byte[0]: pubArr;
181     }
182 
183     /**
184      * libsecp256k1 Cleanup - This destroys the secp256k1 context object
185      * This should be called at the end of the program for proper cleanup of the context.
186      */
cleanup()187     public static synchronized void cleanup() {
188         w.lock();
189         try {
190           secp256k1_destroy_context(Secp256k1Context.getContext());
191         } finally {
192           w.unlock();
193         }
194     }
195 
cloneContext()196     public static long cloneContext() {
197        r.lock();
198        try {
199         return secp256k1_ctx_clone(Secp256k1Context.getContext());
200        } finally { r.unlock(); }
201     }
202 
203     /**
204      * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
205      *
206      * @param tweak some bytes to tweak with
207      * @param seckey 32-byte seckey
208      */
privKeyTweakMul(byte[] privkey, byte[] tweak)209     public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
210         Preconditions.checkArgument(privkey.length == 32);
211 
212         ByteBuffer byteBuff = nativeECDSABuffer.get();
213         if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
214             byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
215             byteBuff.order(ByteOrder.nativeOrder());
216             nativeECDSABuffer.set(byteBuff);
217         }
218         byteBuff.rewind();
219         byteBuff.put(privkey);
220         byteBuff.put(tweak);
221 
222         byte[][] retByteArray;
223         r.lock();
224         try {
225           retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
226         } finally {
227           r.unlock();
228         }
229 
230         byte[] privArr = retByteArray[0];
231 
232         int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
233         int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
234 
235         assertEquals(privArr.length, privLen, "Got bad pubkey length.");
236 
237         assertEquals(retVal, 1, "Failed return value check.");
238 
239         return privArr;
240     }
241 
242     /**
243      * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
244      *
245      * @param tweak some bytes to tweak with
246      * @param seckey 32-byte seckey
247      */
privKeyTweakAdd(byte[] privkey, byte[] tweak)248     public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
249         Preconditions.checkArgument(privkey.length == 32);
250 
251         ByteBuffer byteBuff = nativeECDSABuffer.get();
252         if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
253             byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
254             byteBuff.order(ByteOrder.nativeOrder());
255             nativeECDSABuffer.set(byteBuff);
256         }
257         byteBuff.rewind();
258         byteBuff.put(privkey);
259         byteBuff.put(tweak);
260 
261         byte[][] retByteArray;
262         r.lock();
263         try {
264           retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
265         } finally {
266           r.unlock();
267         }
268 
269         byte[] privArr = retByteArray[0];
270 
271         int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
272         int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
273 
274         assertEquals(privArr.length, privLen, "Got bad pubkey length.");
275 
276         assertEquals(retVal, 1, "Failed return value check.");
277 
278         return privArr;
279     }
280 
281     /**
282      * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
283      *
284      * @param tweak some bytes to tweak with
285      * @param pubkey 32-byte seckey
286      */
pubKeyTweakAdd(byte[] pubkey, byte[] tweak)287     public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
288         Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
289 
290         ByteBuffer byteBuff = nativeECDSABuffer.get();
291         if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
292             byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
293             byteBuff.order(ByteOrder.nativeOrder());
294             nativeECDSABuffer.set(byteBuff);
295         }
296         byteBuff.rewind();
297         byteBuff.put(pubkey);
298         byteBuff.put(tweak);
299 
300         byte[][] retByteArray;
301         r.lock();
302         try {
303           retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
304         } finally {
305           r.unlock();
306         }
307 
308         byte[] pubArr = retByteArray[0];
309 
310         int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
311         int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
312 
313         assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
314 
315         assertEquals(retVal, 1, "Failed return value check.");
316 
317         return pubArr;
318     }
319 
320     /**
321      * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
322      *
323      * @param tweak some bytes to tweak with
324      * @param pubkey 32-byte seckey
325      */
pubKeyTweakMul(byte[] pubkey, byte[] tweak)326     public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
327         Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
328 
329         ByteBuffer byteBuff = nativeECDSABuffer.get();
330         if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
331             byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
332             byteBuff.order(ByteOrder.nativeOrder());
333             nativeECDSABuffer.set(byteBuff);
334         }
335         byteBuff.rewind();
336         byteBuff.put(pubkey);
337         byteBuff.put(tweak);
338 
339         byte[][] retByteArray;
340         r.lock();
341         try {
342           retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
343         } finally {
344           r.unlock();
345         }
346 
347         byte[] pubArr = retByteArray[0];
348 
349         int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
350         int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
351 
352         assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
353 
354         assertEquals(retVal, 1, "Failed return value check.");
355 
356         return pubArr;
357     }
358 
359     /**
360      * libsecp256k1 create ECDH secret - constant time ECDH calculation
361      *
362      * @param seckey byte array of secret key used in exponentiaion
363      * @param pubkey byte array of public key used in exponentiaion
364      */
createECDHSecret(byte[] seckey, byte[] pubkey)365     public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
366         Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);
367 
368         ByteBuffer byteBuff = nativeECDSABuffer.get();
369         if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {
370             byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);
371             byteBuff.order(ByteOrder.nativeOrder());
372             nativeECDSABuffer.set(byteBuff);
373         }
374         byteBuff.rewind();
375         byteBuff.put(seckey);
376         byteBuff.put(pubkey);
377 
378         byte[][] retByteArray;
379         r.lock();
380         try {
381           retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
382         } finally {
383           r.unlock();
384         }
385 
386         byte[] resArr = retByteArray[0];
387         int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
388 
389         assertEquals(resArr.length, 32, "Got bad result length.");
390         assertEquals(retVal, 1, "Failed return value check.");
391 
392         return resArr;
393     }
394 
395     /**
396      * libsecp256k1 randomize - updates the context randomization
397      *
398      * @param seed 32-byte random seed
399      */
randomize(byte[] seed)400     public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
401         Preconditions.checkArgument(seed.length == 32 || seed == null);
402 
403         ByteBuffer byteBuff = nativeECDSABuffer.get();
404         if (byteBuff == null || byteBuff.capacity() < seed.length) {
405             byteBuff = ByteBuffer.allocateDirect(seed.length);
406             byteBuff.order(ByteOrder.nativeOrder());
407             nativeECDSABuffer.set(byteBuff);
408         }
409         byteBuff.rewind();
410         byteBuff.put(seed);
411 
412         w.lock();
413         try {
414           return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;
415         } finally {
416           w.unlock();
417         }
418     }
419 
secp256k1_ctx_clone(long context)420     private static native long secp256k1_ctx_clone(long context);
421 
secp256k1_context_randomize(ByteBuffer byteBuff, long context)422     private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
423 
secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context)424     private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
425 
secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context)426     private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
427 
secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen)428     private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
429 
secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen)430     private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
431 
secp256k1_destroy_context(long context)432     private static native void secp256k1_destroy_context(long context);
433 
secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen)434     private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
435 
secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context)436     private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
437 
secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context)438     private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
439 
secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context)440     private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
441 
secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen)442     private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
443 
secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen)444     private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
445 
446 }
447