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