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