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