]> Git Repo - secp256k1.git/blob - src/java/org/bitcoin/NativeSecp256k1.java
Merge #679: Add SECURITY.md
[secp256k1.git] / src / java / org / bitcoin / NativeSecp256k1.java
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      */
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      */
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      */
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
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      */
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
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      */
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      */
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      */
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      */
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      */
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      */
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
420     private static native long secp256k1_ctx_clone(long context);
421
422     private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
423
424     private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
425
426     private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
427
428     private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
429
430     private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
431
432     private static native void secp256k1_destroy_context(long context);
433
434     private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
435
436     private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
437
438     private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
439
440     private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
441
442     private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
443
444     private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
445
446 }
This page took 0.050877 seconds and 4 git commands to generate.