1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "NativeBN"
18
19#include "JNIHelp.h"
20#include "JniConstants.h"
21#include "JniException.h"
22#include "ScopedPrimitiveArray.h"
23#include "ScopedUtfChars.h"
24#include "jni.h"
25#include <openssl/bn.h>
26#include <openssl/crypto.h>
27#include <openssl/err.h>
28#include <stdio.h>
29#include <memory>
30
31#if defined(OPENSSL_IS_BORINGSSL)
32/* BoringSSL no longer exports |bn_check_top|. */
33static void bn_check_top(const BIGNUM* bn) {
34  /* This asserts that |bn->top| (which contains the number of elements of
35   * |bn->d| that are valid) is minimal. In other words, that there aren't
36   * superfluous zeros. */
37  if (bn != NULL && bn->top != 0 && bn->d[bn->top-1] == 0) {
38    abort();
39  }
40}
41#endif
42
43struct BN_CTX_Deleter {
44  void operator()(BN_CTX* p) const {
45    BN_CTX_free(p);
46  }
47};
48typedef std::unique_ptr<BN_CTX, BN_CTX_Deleter> Unique_BN_CTX;
49
50static BIGNUM* toBigNum(jlong address) {
51  return reinterpret_cast<BIGNUM*>(static_cast<uintptr_t>(address));
52}
53
54static bool throwExceptionIfNecessary(JNIEnv* env) {
55  long error = ERR_get_error();
56  if (error == 0) {
57    return false;
58  }
59  char message[256];
60  ERR_error_string_n(error, message, sizeof(message));
61  int reason = ERR_GET_REASON(error);
62  if (reason == BN_R_DIV_BY_ZERO) {
63    jniThrowException(env, "java/lang/ArithmeticException", "BigInteger division by zero");
64  } else if (reason == BN_R_NO_INVERSE) {
65    jniThrowException(env, "java/lang/ArithmeticException", "BigInteger not invertible");
66  } else if (reason == ERR_R_MALLOC_FAILURE) {
67    jniThrowOutOfMemoryError(env, message);
68  } else {
69    jniThrowException(env, "java/lang/ArithmeticException", message);
70  }
71  return true;
72}
73
74static int isValidHandle(JNIEnv* env, jlong handle, const char* message) {
75  if (handle == 0) {
76    jniThrowNullPointerException(env, message);
77    return JNI_FALSE;
78  }
79  return JNI_TRUE;
80}
81
82static int oneValidHandle(JNIEnv* env, jlong a) {
83  return isValidHandle(env, a, "Mandatory handle (first) passed as null");
84}
85
86static int twoValidHandles(JNIEnv* env, jlong a, jlong b) {
87  if (!oneValidHandle(env, a)) return JNI_FALSE;
88  return isValidHandle(env, b, "Mandatory handle (second) passed as null");
89}
90
91static int threeValidHandles(JNIEnv* env, jlong a, jlong b, jlong c) {
92  if (!twoValidHandles(env, a, b)) return JNI_FALSE;
93  return isValidHandle(env, c, "Mandatory handle (third) passed as null");
94}
95
96static int fourValidHandles(JNIEnv* env, jlong a, jlong b, jlong c, jlong d) {
97  if (!threeValidHandles(env, a, b, c)) return JNI_FALSE;
98  return isValidHandle(env, d, "Mandatory handle (fourth) passed as null");
99}
100
101static jlong NativeBN_BN_new(JNIEnv* env, jclass) {
102  jlong result = static_cast<jlong>(reinterpret_cast<uintptr_t>(BN_new()));
103  throwExceptionIfNecessary(env);
104  return result;
105}
106
107static jlong NativeBN_getNativeFinalizer(JNIEnv*, jclass) {
108  return static_cast<jlong>(reinterpret_cast<uintptr_t>(&BN_free));
109}
110
111static void NativeBN_BN_free(JNIEnv* env, jclass, jlong a) {
112  if (!oneValidHandle(env, a)) return;
113  BN_free(toBigNum(a));
114}
115
116static int NativeBN_BN_cmp(JNIEnv* env, jclass, jlong a, jlong b) {
117  if (!twoValidHandles(env, a, b)) return 1;
118  return BN_cmp(toBigNum(a), toBigNum(b));
119}
120
121static void NativeBN_BN_copy(JNIEnv* env, jclass, jlong to, jlong from) {
122  if (!twoValidHandles(env, to, from)) return;
123  BN_copy(toBigNum(to), toBigNum(from));
124  throwExceptionIfNecessary(env);
125}
126
127static void NativeBN_putULongInt(JNIEnv* env, jclass, jlong a0, jlong java_dw, jboolean neg) {
128  if (!oneValidHandle(env, a0)) return;
129
130  uint64_t dw = java_dw;
131  BIGNUM* a = toBigNum(a0);
132  int ok;
133
134  static_assert(sizeof(dw) == sizeof(BN_ULONG) ||
135                sizeof(dw) == 2*sizeof(BN_ULONG), "Unknown BN configuration");
136
137  if (sizeof(dw) == sizeof(BN_ULONG)) {
138    ok = BN_set_word(a, dw);
139  } else if (sizeof(dw) == 2 * sizeof(BN_ULONG)) {
140    ok = (bn_wexpand(a, 2) != NULL);
141    if (ok) {
142      a->d[0] = dw;
143      a->d[1] = dw >> 32;
144      a->top = 2;
145      bn_correct_top(a);
146    }
147  }
148
149  BN_set_negative(a, neg);
150
151  if (!ok) {
152    throwExceptionIfNecessary(env);
153  }
154}
155
156static void NativeBN_putLongInt(JNIEnv* env, jclass cls, jlong a, jlong dw) {
157  if (dw >= 0) {
158    NativeBN_putULongInt(env, cls, a, dw, JNI_FALSE);
159  } else {
160    NativeBN_putULongInt(env, cls, a, -dw, JNI_TRUE);
161  }
162}
163
164static int NativeBN_BN_dec2bn(JNIEnv* env, jclass, jlong a0, jstring str) {
165  if (!oneValidHandle(env, a0)) return -1;
166  ScopedUtfChars chars(env, str);
167  if (chars.c_str() == NULL) {
168    return -1;
169  }
170  BIGNUM* a = toBigNum(a0);
171  int result = BN_dec2bn(&a, chars.c_str());
172  throwExceptionIfNecessary(env);
173  return result;
174}
175
176static int NativeBN_BN_hex2bn(JNIEnv* env, jclass, jlong a0, jstring str) {
177  if (!oneValidHandle(env, a0)) return -1;
178  ScopedUtfChars chars(env, str);
179  if (chars.c_str() == NULL) {
180    return -1;
181  }
182  BIGNUM* a = toBigNum(a0);
183  int result = BN_hex2bn(&a, chars.c_str());
184  throwExceptionIfNecessary(env);
185  return result;
186}
187
188static void NativeBN_BN_bin2bn(JNIEnv* env, jclass, jbyteArray arr, int len, jboolean neg, jlong ret) {
189  if (!oneValidHandle(env, ret)) return;
190  ScopedByteArrayRO bytes(env, arr);
191  if (bytes.get() == NULL) {
192    return;
193  }
194  BN_bin2bn(reinterpret_cast<const unsigned char*>(bytes.get()), len, toBigNum(ret));
195  if (!throwExceptionIfNecessary(env) && neg) {
196    BN_set_negative(toBigNum(ret), true);
197  }
198}
199
200/**
201 * Note:
202 * This procedure directly writes the internal representation of BIGNUMs.
203 * We do so as there is no direct interface based on Little Endian Integer Arrays.
204 * Also note that the same representation is used in the Cordoba Java Implementation of BigIntegers,
205 *        whereof certain functionality is still being used.
206 */
207static void NativeBN_litEndInts2bn(JNIEnv* env, jclass, jintArray arr, int len, jboolean neg, jlong ret0) {
208  if (!oneValidHandle(env, ret0)) return;
209  BIGNUM* ret = toBigNum(ret0);
210  bn_check_top(ret);
211  if (len > 0) {
212    ScopedIntArrayRO scopedArray(env, arr);
213    if (scopedArray.get() == NULL) {
214      return;
215    }
216#ifdef __LP64__
217    const int wlen = (len + 1) / 2;
218#else
219    const int wlen = len;
220#endif
221    const unsigned int* tmpInts = reinterpret_cast<const unsigned int*>(scopedArray.get());
222    if ((tmpInts != NULL) && (bn_wexpand(ret, wlen) != NULL)) {
223#ifdef __LP64__
224      if (len % 2) {
225        ret->d[wlen - 1] = tmpInts[--len];
226      }
227      if (len > 0) {
228        for (int i = len - 2; i >= 0; i -= 2) {
229          ret->d[i/2] = ((unsigned long long)tmpInts[i+1] << 32) | tmpInts[i];
230        }
231      }
232#else
233      int i = len; do { i--; ret->d[i] = tmpInts[i]; } while (i > 0);
234#endif
235      ret->top = wlen;
236      ret->neg = neg;
237      // need to call this due to clear byte at top if avoiding
238      // having the top bit set (-ve number)
239      // Basically get rid of top zero ints:
240      bn_correct_top(ret);
241    } else {
242      throwExceptionIfNecessary(env);
243    }
244  } else { // (len = 0) means value = 0 and sign will be 0, too.
245    ret->top = 0;
246  }
247}
248
249
250#ifdef __LP64__
251#define BYTES2ULONG(bytes, k) \
252    ((bytes[k + 7] & 0xffULL)       | (bytes[k + 6] & 0xffULL) <<  8 | (bytes[k + 5] & 0xffULL) << 16 | (bytes[k + 4] & 0xffULL) << 24 | \
253     (bytes[k + 3] & 0xffULL) << 32 | (bytes[k + 2] & 0xffULL) << 40 | (bytes[k + 1] & 0xffULL) << 48 | (bytes[k + 0] & 0xffULL) << 56)
254#else
255#define BYTES2ULONG(bytes, k) \
256    ((bytes[k + 3] & 0xff) | (bytes[k + 2] & 0xff) << 8 | (bytes[k + 1] & 0xff) << 16 | (bytes[k + 0] & 0xff) << 24)
257#endif
258static void negBigEndianBytes2bn(JNIEnv*, jclass, const unsigned char* bytes, int bytesLen, jlong ret0) {
259  BIGNUM* ret = toBigNum(ret0);
260
261  bn_check_top(ret);
262  // FIXME: assert bytesLen > 0
263  int wLen = (bytesLen + sizeof(BN_ULONG) - 1) / sizeof(BN_ULONG);
264  int firstNonzeroDigit = -2;
265  if (bn_wexpand(ret, wLen) != NULL) {
266    BN_ULONG* d = ret->d;
267    BN_ULONG di;
268    ret->top = wLen;
269    int highBytes = bytesLen % sizeof(BN_ULONG);
270    int k = bytesLen;
271    // Put bytes to the int array starting from the end of the byte array
272    int i = 0;
273    while (k > highBytes) {
274      k -= sizeof(BN_ULONG);
275      di = BYTES2ULONG(bytes, k);
276      if (di != 0) {
277        d[i] = -di;
278        firstNonzeroDigit = i;
279        i++;
280        while (k > highBytes) {
281          k -= sizeof(BN_ULONG);
282          d[i] = ~BYTES2ULONG(bytes, k);
283          i++;
284        }
285        break;
286      } else {
287        d[i] = 0;
288        i++;
289      }
290    }
291    if (highBytes != 0) {
292      di = -1;
293      // Put the first bytes in the highest element of the int array
294      if (firstNonzeroDigit != -2) {
295        for (k = 0; k < highBytes; k++) {
296          di = (di << 8) | (bytes[k] & 0xFF);
297        }
298        d[i] = ~di;
299      } else {
300        for (k = 0; k < highBytes; k++) {
301          di = (di << 8) | (bytes[k] & 0xFF);
302        }
303        d[i] = -di;
304      }
305    }
306    // The top may have superfluous zeros, so fix it.
307    bn_correct_top(ret);
308  }
309}
310
311static void NativeBN_twosComp2bn(JNIEnv* env, jclass cls, jbyteArray arr, int bytesLen, jlong ret0) {
312  if (!oneValidHandle(env, ret0)) return;
313  BIGNUM* ret = toBigNum(ret0);
314
315  ScopedByteArrayRO bytes(env, arr);
316  if (bytes.get() == NULL) {
317    return;
318  }
319  const unsigned char* s = reinterpret_cast<const unsigned char*>(bytes.get());
320  if ((bytes[0] & 0X80) == 0) { // Positive value!
321    //
322    // We can use the existing BN implementation for unsigned big endian bytes:
323    //
324    BN_bin2bn(s, bytesLen, ret);
325    BN_set_negative(ret, false);
326  } else { // Negative value!
327    //
328    // We need to apply two's complement:
329    //
330    negBigEndianBytes2bn(env, cls, s, bytesLen, ret0);
331    BN_set_negative(ret, true);
332  }
333  throwExceptionIfNecessary(env);
334}
335
336static jlong NativeBN_longInt(JNIEnv* env, jclass, jlong a0) {
337  if (!oneValidHandle(env, a0)) return -1;
338
339  BIGNUM* a = toBigNum(a0);
340  bn_check_top(a);
341  int wLen = a->top;
342  if (wLen == 0) {
343    return 0;
344  }
345
346#ifdef __LP64__
347  jlong result = a->d[0];
348#else
349  jlong result = static_cast<jlong>(a->d[0]) & 0xffffffff;
350  if (wLen > 1) {
351    result |= static_cast<jlong>(a->d[1]) << 32;
352  }
353#endif
354  return a->neg ? -result : result;
355}
356
357static char* leadingZerosTrimmed(char* s) {
358    char* p = s;
359    if (*p == '-') {
360        p++;
361        while ((*p == '0') && (*(p + 1) != 0)) { p++; }
362        p--;
363        *p = '-';
364    } else {
365        while ((*p == '0') && (*(p + 1) != 0)) { p++; }
366    }
367    return p;
368}
369
370static jstring NativeBN_BN_bn2dec(JNIEnv* env, jclass, jlong a) {
371  if (!oneValidHandle(env, a)) return NULL;
372  char* tmpStr = BN_bn2dec(toBigNum(a));
373  if (tmpStr == NULL) {
374    return NULL;
375  }
376  char* retStr = leadingZerosTrimmed(tmpStr);
377  jstring returnJString = env->NewStringUTF(retStr);
378  OPENSSL_free(tmpStr);
379  return returnJString;
380}
381
382static jstring NativeBN_BN_bn2hex(JNIEnv* env, jclass, jlong a) {
383  if (!oneValidHandle(env, a)) return NULL;
384  char* tmpStr = BN_bn2hex(toBigNum(a));
385  if (tmpStr == NULL) {
386    return NULL;
387  }
388  char* retStr = leadingZerosTrimmed(tmpStr);
389  jstring returnJString = env->NewStringUTF(retStr);
390  OPENSSL_free(tmpStr);
391  return returnJString;
392}
393
394static jbyteArray NativeBN_BN_bn2bin(JNIEnv* env, jclass, jlong a0) {
395  if (!oneValidHandle(env, a0)) return NULL;
396  BIGNUM* a = toBigNum(a0);
397  jbyteArray result = env->NewByteArray(BN_num_bytes(a));
398  if (result == NULL) {
399    return NULL;
400  }
401  ScopedByteArrayRW bytes(env, result);
402  if (bytes.get() == NULL) {
403    return NULL;
404  }
405  BN_bn2bin(a, reinterpret_cast<unsigned char*>(bytes.get()));
406  return result;
407}
408
409static jintArray NativeBN_bn2litEndInts(JNIEnv* env, jclass, jlong a0) {
410  if (!oneValidHandle(env, a0)) return NULL;
411  BIGNUM* a = toBigNum(a0);
412  bn_check_top(a);
413  int wLen = a->top;
414  if (wLen == 0) {
415    return NULL;
416  }
417  jintArray result = env->NewIntArray(wLen * sizeof(BN_ULONG)/sizeof(unsigned int));
418  if (result == NULL) {
419    return NULL;
420  }
421  ScopedIntArrayRW ints(env, result);
422  if (ints.get() == NULL) {
423    return NULL;
424  }
425  unsigned int* uints = reinterpret_cast<unsigned int*>(ints.get());
426  if (uints == NULL) {
427    return NULL;
428  }
429#ifdef __LP64__
430  int i = wLen; do { i--; uints[i*2+1] = a->d[i] >> 32; uints[i*2] = a->d[i]; } while (i > 0);
431#else
432  int i = wLen; do { i--; uints[i] = a->d[i]; } while (i > 0);
433#endif
434  return result;
435}
436
437static int NativeBN_sign(JNIEnv* env, jclass, jlong a) {
438  if (!oneValidHandle(env, a)) return -2;
439  if (BN_is_zero(toBigNum(a))) {
440      return 0;
441  } else if (BN_is_negative(toBigNum(a))) {
442    return -1;
443  }
444  return 1;
445}
446
447static void NativeBN_BN_set_negative(JNIEnv* env, jclass, jlong b, int n) {
448  if (!oneValidHandle(env, b)) return;
449  BN_set_negative(toBigNum(b), n);
450}
451
452static int NativeBN_bitLength(JNIEnv* env, jclass, jlong a0) {
453  if (!oneValidHandle(env, a0)) return JNI_FALSE;
454  BIGNUM* a = toBigNum(a0);
455  bn_check_top(a);
456  int wLen = a->top;
457  if (wLen == 0) return 0;
458  BN_ULONG* d = a->d;
459  int i = wLen - 1;
460  BN_ULONG msd = d[i]; // most significant digit
461  if (a->neg) {
462    // Handle negative values correctly:
463    // i.e. decrement the msd if all other digits are 0:
464    // while ((i > 0) && (d[i] != 0)) { i--; }
465    do { i--; } while (!((i < 0) || (d[i] != 0)));
466    if (i < 0) msd--; // Only if all lower significant digits are 0 we decrement the most significant one.
467  }
468  return (wLen - 1) * sizeof(BN_ULONG) * 8 + BN_num_bits_word(msd);
469}
470
471static jboolean NativeBN_BN_is_bit_set(JNIEnv* env, jclass, jlong a, int n) {
472  if (!oneValidHandle(env, a)) return JNI_FALSE;
473  return BN_is_bit_set(toBigNum(a), n);
474}
475
476static void NativeBN_BN_shift(JNIEnv* env, jclass, jlong r, jlong a, int n) {
477  if (!twoValidHandles(env, r, a)) return;
478  if (n >= 0) {
479    BN_lshift(toBigNum(r), toBigNum(a), n);
480  } else {
481    BN_rshift(toBigNum(r), toBigNum(a), -n);
482  }
483  throwExceptionIfNecessary(env);
484}
485
486static void NativeBN_BN_add_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
487  if (!oneValidHandle(env, a)) return;
488  BN_add_word(toBigNum(a), w);
489  throwExceptionIfNecessary(env);
490}
491
492static void NativeBN_BN_mul_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
493  if (!oneValidHandle(env, a)) return;
494  BN_mul_word(toBigNum(a), w);
495  throwExceptionIfNecessary(env);
496}
497
498static BN_ULONG NativeBN_BN_mod_word(JNIEnv* env, jclass, jlong a, BN_ULONG w) {
499  if (!oneValidHandle(env, a)) return 0;
500  int result = BN_mod_word(toBigNum(a), w);
501  throwExceptionIfNecessary(env);
502  return result;
503}
504
505static void NativeBN_BN_add(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
506  if (!threeValidHandles(env, r, a, b)) return;
507  BN_add(toBigNum(r), toBigNum(a), toBigNum(b));
508  throwExceptionIfNecessary(env);
509}
510
511static void NativeBN_BN_sub(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
512  if (!threeValidHandles(env, r, a, b)) return;
513  BN_sub(toBigNum(r), toBigNum(a), toBigNum(b));
514  throwExceptionIfNecessary(env);
515}
516
517static void NativeBN_BN_gcd(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
518  if (!threeValidHandles(env, r, a, b)) return;
519  Unique_BN_CTX ctx(BN_CTX_new());
520  BN_gcd(toBigNum(r), toBigNum(a), toBigNum(b), ctx.get());
521  throwExceptionIfNecessary(env);
522}
523
524static void NativeBN_BN_mul(JNIEnv* env, jclass, jlong r, jlong a, jlong b) {
525  if (!threeValidHandles(env, r, a, b)) return;
526  Unique_BN_CTX ctx(BN_CTX_new());
527  BN_mul(toBigNum(r), toBigNum(a), toBigNum(b), ctx.get());
528  throwExceptionIfNecessary(env);
529}
530
531static void NativeBN_BN_exp(JNIEnv* env, jclass, jlong r, jlong a, jlong p) {
532  if (!threeValidHandles(env, r, a, p)) return;
533  Unique_BN_CTX ctx(BN_CTX_new());
534  BN_exp(toBigNum(r), toBigNum(a), toBigNum(p), ctx.get());
535  throwExceptionIfNecessary(env);
536}
537
538static void NativeBN_BN_div(JNIEnv* env, jclass, jlong dv, jlong rem, jlong m, jlong d) {
539  if (!fourValidHandles(env, (rem ? rem : dv), (dv ? dv : rem), m, d)) return;
540  Unique_BN_CTX ctx(BN_CTX_new());
541  BN_div(toBigNum(dv), toBigNum(rem), toBigNum(m), toBigNum(d), ctx.get());
542  throwExceptionIfNecessary(env);
543}
544
545static void NativeBN_BN_nnmod(JNIEnv* env, jclass, jlong r, jlong a, jlong m) {
546  if (!threeValidHandles(env, r, a, m)) return;
547  Unique_BN_CTX ctx(BN_CTX_new());
548  BN_nnmod(toBigNum(r), toBigNum(a), toBigNum(m), ctx.get());
549  throwExceptionIfNecessary(env);
550}
551
552static void NativeBN_BN_mod_exp(JNIEnv* env, jclass, jlong r, jlong a, jlong p, jlong m) {
553  if (!fourValidHandles(env, r, a, p, m)) return;
554  Unique_BN_CTX ctx(BN_CTX_new());
555  BN_mod_exp(toBigNum(r), toBigNum(a), toBigNum(p), toBigNum(m), ctx.get());
556  throwExceptionIfNecessary(env);
557}
558
559static void NativeBN_BN_mod_inverse(JNIEnv* env, jclass, jlong ret, jlong a, jlong n) {
560  if (!threeValidHandles(env, ret, a, n)) return;
561  Unique_BN_CTX ctx(BN_CTX_new());
562  BN_mod_inverse(toBigNum(ret), toBigNum(a), toBigNum(n), ctx.get());
563  throwExceptionIfNecessary(env);
564}
565
566static void NativeBN_BN_generate_prime_ex(JNIEnv* env, jclass, jlong ret, int bits,
567                                          jboolean safe, jlong add, jlong rem, jlong cb) {
568  if (!oneValidHandle(env, ret)) return;
569  BN_generate_prime_ex(toBigNum(ret), bits, safe, toBigNum(add), toBigNum(rem),
570                       reinterpret_cast<BN_GENCB*>(cb));
571  throwExceptionIfNecessary(env);
572}
573
574static jboolean NativeBN_BN_is_prime_ex(JNIEnv* env, jclass, jlong p, int nchecks, jlong cb) {
575  if (!oneValidHandle(env, p)) return JNI_FALSE;
576  Unique_BN_CTX ctx(BN_CTX_new());
577  return BN_is_prime_ex(toBigNum(p), nchecks, ctx.get(), reinterpret_cast<BN_GENCB*>(cb));
578}
579
580static JNINativeMethod gMethods[] = {
581   NATIVE_METHOD(NativeBN, BN_add, "(JJJ)V"),
582   NATIVE_METHOD(NativeBN, BN_add_word, "(JI)V"),
583   NATIVE_METHOD(NativeBN, BN_bin2bn, "([BIZJ)V"),
584   NATIVE_METHOD(NativeBN, BN_bn2bin, "(J)[B"),
585   NATIVE_METHOD(NativeBN, BN_bn2dec, "(J)Ljava/lang/String;"),
586   NATIVE_METHOD(NativeBN, BN_bn2hex, "(J)Ljava/lang/String;"),
587   NATIVE_METHOD(NativeBN, BN_cmp, "(JJ)I"),
588   NATIVE_METHOD(NativeBN, BN_copy, "(JJ)V"),
589   NATIVE_METHOD(NativeBN, BN_dec2bn, "(JLjava/lang/String;)I"),
590   NATIVE_METHOD(NativeBN, BN_div, "(JJJJ)V"),
591   NATIVE_METHOD(NativeBN, BN_exp, "(JJJ)V"),
592   NATIVE_METHOD(NativeBN, BN_free, "(J)V"),
593   NATIVE_METHOD(NativeBN, BN_gcd, "(JJJ)V"),
594   NATIVE_METHOD(NativeBN, BN_generate_prime_ex, "(JIZJJJ)V"),
595   NATIVE_METHOD(NativeBN, BN_hex2bn, "(JLjava/lang/String;)I"),
596   NATIVE_METHOD(NativeBN, BN_is_bit_set, "(JI)Z"),
597   NATIVE_METHOD(NativeBN, BN_is_prime_ex, "(JIJ)Z"),
598   NATIVE_METHOD(NativeBN, BN_mod_exp, "(JJJJ)V"),
599   NATIVE_METHOD(NativeBN, BN_mod_inverse, "(JJJ)V"),
600   NATIVE_METHOD(NativeBN, BN_mod_word, "(JI)I"),
601   NATIVE_METHOD(NativeBN, BN_mul, "(JJJ)V"),
602   NATIVE_METHOD(NativeBN, BN_mul_word, "(JI)V"),
603   NATIVE_METHOD(NativeBN, BN_new, "()J"),
604   NATIVE_METHOD(NativeBN, BN_nnmod, "(JJJ)V"),
605   NATIVE_METHOD(NativeBN, BN_set_negative, "(JI)V"),
606   NATIVE_METHOD(NativeBN, BN_shift, "(JJI)V"),
607   NATIVE_METHOD(NativeBN, BN_sub, "(JJJ)V"),
608   NATIVE_METHOD(NativeBN, bitLength, "(J)I"),
609   NATIVE_METHOD(NativeBN, bn2litEndInts, "(J)[I"),
610   NATIVE_METHOD(NativeBN, getNativeFinalizer, "()J"),
611   NATIVE_METHOD(NativeBN, litEndInts2bn, "([IIZJ)V"),
612   NATIVE_METHOD(NativeBN, longInt, "(J)J"),
613   NATIVE_METHOD(NativeBN, putLongInt, "(JJ)V"),
614   NATIVE_METHOD(NativeBN, putULongInt, "(JJZ)V"),
615   NATIVE_METHOD(NativeBN, sign, "(J)I"),
616   NATIVE_METHOD(NativeBN, twosComp2bn, "([BIJ)V"),
617};
618void register_java_math_NativeBN(JNIEnv* env) {
619    jniRegisterNativeMethods(env, "java/math/NativeBN", gMethods, NELEM(gMethods));
620}
621