|  | /* | 
|  | * Copyright (C) 2008 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | package java.math; | 
|  |  | 
|  | import dalvik.annotation.optimization.ReachabilitySensitive; | 
|  | import libcore.util.NativeAllocationRegistry; | 
|  |  | 
|  | /* | 
|  | * In contrast to BigIntegers this class doesn't fake two's complement representation. | 
|  | * Any Bit-Operations, including Shifting, solely regard the unsigned magnitude. | 
|  | * Moreover BigInt objects are mutable and offer efficient in-place-operations. | 
|  | */ | 
|  | final class BigInt { | 
|  |  | 
|  | private static NativeAllocationRegistry registry = new NativeAllocationRegistry( | 
|  | BigInt.class.getClassLoader(), NativeBN.getNativeFinalizer(), NativeBN.size()); | 
|  |  | 
|  | /* Fields used for the internal representation. */ | 
|  | @ReachabilitySensitive | 
|  | private transient long bignum = 0; | 
|  |  | 
|  | @Override | 
|  | public String toString() { | 
|  | return this.decString(); | 
|  | } | 
|  |  | 
|  | boolean hasNativeBignum() { | 
|  | return this.bignum != 0; | 
|  | } | 
|  |  | 
|  | private void makeValid() { | 
|  | if (this.bignum == 0) { | 
|  | this.bignum = NativeBN.BN_new(); | 
|  | registry.registerNativeAllocation(this, this.bignum); | 
|  | } | 
|  | } | 
|  |  | 
|  | private static BigInt newBigInt() { | 
|  | BigInt bi = new BigInt(); | 
|  | bi.bignum = NativeBN.BN_new(); | 
|  | registry.registerNativeAllocation(bi, bi.bignum); | 
|  | return bi; | 
|  | } | 
|  |  | 
|  |  | 
|  | static int cmp(BigInt a, BigInt b) { | 
|  | return NativeBN.BN_cmp(a.bignum, b.bignum); | 
|  | } | 
|  |  | 
|  |  | 
|  | void putCopy(BigInt from) { | 
|  | this.makeValid(); | 
|  | NativeBN.BN_copy(this.bignum, from.bignum); | 
|  | } | 
|  |  | 
|  | BigInt copy() { | 
|  | BigInt bi = new BigInt(); | 
|  | bi.putCopy(this); | 
|  | return bi; | 
|  | } | 
|  |  | 
|  |  | 
|  | void putLongInt(long val) { | 
|  | this.makeValid(); | 
|  | NativeBN.putLongInt(this.bignum, val); | 
|  | } | 
|  |  | 
|  | void putULongInt(long val, boolean neg) { | 
|  | this.makeValid(); | 
|  | NativeBN.putULongInt(this.bignum, val, neg); | 
|  | } | 
|  |  | 
|  | private NumberFormatException invalidBigInteger(String s) { | 
|  | throw new NumberFormatException("Invalid BigInteger: " + s); | 
|  | } | 
|  |  | 
|  | void putDecString(String original) { | 
|  | String s = checkString(original, 10); | 
|  | this.makeValid(); | 
|  | int usedLen = NativeBN.BN_dec2bn(this.bignum, s); | 
|  | if (usedLen < s.length()) { | 
|  | throw invalidBigInteger(original); | 
|  | } | 
|  | } | 
|  |  | 
|  | void putHexString(String original) { | 
|  | String s = checkString(original, 16); | 
|  | this.makeValid(); | 
|  | int usedLen = NativeBN.BN_hex2bn(this.bignum, s); | 
|  | if (usedLen < s.length()) { | 
|  | throw invalidBigInteger(original); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a string suitable for passing to OpenSSL. | 
|  | * Throws if 's' doesn't match Java's rules for valid BigInteger strings. | 
|  | * BN_dec2bn and BN_hex2bn do very little checking, so we need to manually | 
|  | * ensure we comply with Java's rules. | 
|  | * http://code.google.com/p/android/issues/detail?id=7036 | 
|  | */ | 
|  | String checkString(String s, int base) { | 
|  | if (s == null) { | 
|  | throw new NullPointerException("s == null"); | 
|  | } | 
|  | // A valid big integer consists of an optional '-' or '+' followed by | 
|  | // one or more digit characters appropriate to the given base, | 
|  | // and no other characters. | 
|  | int charCount = s.length(); | 
|  | int i = 0; | 
|  | if (charCount > 0) { | 
|  | char ch = s.charAt(0); | 
|  | if (ch == '+') { | 
|  | // Java supports leading +, but OpenSSL doesn't, so we need to strip it. | 
|  | s = s.substring(1); | 
|  | --charCount; | 
|  | } else if (ch == '-') { | 
|  | ++i; | 
|  | } | 
|  | } | 
|  | if (charCount - i == 0) { | 
|  | throw invalidBigInteger(s); | 
|  | } | 
|  | boolean nonAscii = false; | 
|  | for (; i < charCount; ++i) { | 
|  | char ch = s.charAt(i); | 
|  | if (Character.digit(ch, base) == -1) { | 
|  | throw invalidBigInteger(s); | 
|  | } | 
|  | if (ch > 128) { | 
|  | nonAscii = true; | 
|  | } | 
|  | } | 
|  | return nonAscii ? toAscii(s, base) : s; | 
|  | } | 
|  |  | 
|  | // Java supports non-ASCII decimal digits, but OpenSSL doesn't. | 
|  | // We need to translate the decimal digits but leave any other characters alone. | 
|  | // This method assumes it's being called on a string that has already been validated. | 
|  | private static String toAscii(String s, int base) { | 
|  | int length = s.length(); | 
|  | StringBuilder result = new StringBuilder(length); | 
|  | for (int i = 0; i < length; ++i) { | 
|  | char ch = s.charAt(i); | 
|  | int value = Character.digit(ch, base); | 
|  | if (value >= 0 && value <= 9) { | 
|  | ch = (char) ('0' + value); | 
|  | } | 
|  | result.append(ch); | 
|  | } | 
|  | return result.toString(); | 
|  | } | 
|  |  | 
|  | void putBigEndian(byte[] a, boolean neg) { | 
|  | this.makeValid(); | 
|  | NativeBN.BN_bin2bn(a, a.length, neg, this.bignum); | 
|  | } | 
|  |  | 
|  | void putLittleEndianInts(int[] a, boolean neg) { | 
|  | this.makeValid(); | 
|  | NativeBN.litEndInts2bn(a, a.length, neg, this.bignum); | 
|  | } | 
|  |  | 
|  | void putBigEndianTwosComplement(byte[] a) { | 
|  | this.makeValid(); | 
|  | NativeBN.twosComp2bn(a, a.length, this.bignum); | 
|  | } | 
|  |  | 
|  |  | 
|  | long longInt() { | 
|  | return NativeBN.longInt(this.bignum); | 
|  | } | 
|  |  | 
|  | String decString() { | 
|  | return NativeBN.BN_bn2dec(this.bignum); | 
|  | } | 
|  |  | 
|  | String hexString() { | 
|  | return NativeBN.BN_bn2hex(this.bignum); | 
|  | } | 
|  |  | 
|  | byte[] bigEndianMagnitude() { | 
|  | return NativeBN.BN_bn2bin(this.bignum); | 
|  | } | 
|  |  | 
|  | int[] littleEndianIntsMagnitude() { | 
|  | return NativeBN.bn2litEndInts(this.bignum); | 
|  | } | 
|  |  | 
|  | int sign() { | 
|  | return NativeBN.sign(this.bignum); | 
|  | } | 
|  |  | 
|  | void setSign(int val) { | 
|  | if (val > 0) { | 
|  | NativeBN.BN_set_negative(this.bignum, 0); | 
|  | } else { | 
|  | if (val < 0) NativeBN.BN_set_negative(this.bignum, 1); | 
|  | } | 
|  | } | 
|  |  | 
|  | boolean twosCompFitsIntoBytes(int desiredByteCount) { | 
|  | int actualByteCount = (NativeBN.bitLength(this.bignum) + 7) / 8; | 
|  | return actualByteCount <= desiredByteCount; | 
|  | } | 
|  |  | 
|  | int bitLength() { | 
|  | return NativeBN.bitLength(this.bignum); | 
|  | } | 
|  |  | 
|  | boolean isBitSet(int n) { | 
|  | return NativeBN.BN_is_bit_set(this.bignum, n); | 
|  | } | 
|  |  | 
|  | // n > 0: shift left (multiply) | 
|  | static BigInt shift(BigInt a, int n) { | 
|  | BigInt r = newBigInt(); | 
|  | NativeBN.BN_shift(r.bignum, a.bignum, n); | 
|  | return r; | 
|  | } | 
|  |  | 
|  | void shift(int n) { | 
|  | NativeBN.BN_shift(this.bignum, this.bignum, n); | 
|  | } | 
|  |  | 
|  | void addPositiveInt(int w) { | 
|  | NativeBN.BN_add_word(this.bignum, w); | 
|  | } | 
|  |  | 
|  | void multiplyByPositiveInt(int w) { | 
|  | NativeBN.BN_mul_word(this.bignum, w); | 
|  | } | 
|  |  | 
|  | static int remainderByPositiveInt(BigInt a, int w) { | 
|  | return NativeBN.BN_mod_word(a.bignum, w); | 
|  | } | 
|  |  | 
|  | static BigInt addition(BigInt a, BigInt b) { | 
|  | BigInt r = newBigInt(); | 
|  | NativeBN.BN_add(r.bignum, a.bignum, b.bignum); | 
|  | return r; | 
|  | } | 
|  |  | 
|  | void add(BigInt a) { | 
|  | NativeBN.BN_add(this.bignum, this.bignum, a.bignum); | 
|  | } | 
|  |  | 
|  | static BigInt subtraction(BigInt a, BigInt b) { | 
|  | BigInt r = newBigInt(); | 
|  | NativeBN.BN_sub(r.bignum, a.bignum, b.bignum); | 
|  | return r; | 
|  | } | 
|  |  | 
|  |  | 
|  | static BigInt gcd(BigInt a, BigInt b) { | 
|  | BigInt r = newBigInt(); | 
|  | NativeBN.BN_gcd(r.bignum, a.bignum, b.bignum); | 
|  | return r; | 
|  | } | 
|  |  | 
|  | static BigInt product(BigInt a, BigInt b) { | 
|  | BigInt r = newBigInt(); | 
|  | NativeBN.BN_mul(r.bignum, a.bignum, b.bignum); | 
|  | return r; | 
|  | } | 
|  |  | 
|  | static BigInt bigExp(BigInt a, BigInt p) { | 
|  | // Sign of p is ignored! | 
|  | BigInt r = newBigInt(); | 
|  | NativeBN.BN_exp(r.bignum, a.bignum, p.bignum); | 
|  | return r; | 
|  | } | 
|  |  | 
|  | static BigInt exp(BigInt a, int p) { | 
|  | // Sign of p is ignored! | 
|  | BigInt power = new BigInt(); | 
|  | power.putLongInt(p); | 
|  | return bigExp(a, power); | 
|  | // OPTIONAL: | 
|  | // int BN_sqr(BigInteger r, BigInteger a, BN_CTX ctx); | 
|  | // int BN_sqr(BIGNUM *r, const BIGNUM *a,BN_CTX *ctx); | 
|  | } | 
|  |  | 
|  | static void division(BigInt dividend, BigInt divisor, BigInt quotient, BigInt remainder) { | 
|  | long quot, rem; | 
|  | if (quotient != null) { | 
|  | quotient.makeValid(); | 
|  | quot = quotient.bignum; | 
|  | } else { | 
|  | quot = 0; | 
|  | } | 
|  | if (remainder != null) { | 
|  | remainder.makeValid(); | 
|  | rem = remainder.bignum; | 
|  | } else { | 
|  | rem = 0; | 
|  | } | 
|  | NativeBN.BN_div(quot, rem, dividend.bignum, divisor.bignum); | 
|  | } | 
|  |  | 
|  | static BigInt modulus(BigInt a, BigInt m) { | 
|  | // Sign of p is ignored! ? | 
|  | BigInt r = newBigInt(); | 
|  | NativeBN.BN_nnmod(r.bignum, a.bignum, m.bignum); | 
|  | return r; | 
|  | } | 
|  |  | 
|  | static BigInt modExp(BigInt a, BigInt p, BigInt m) { | 
|  | // Sign of p is ignored! | 
|  | BigInt r = newBigInt(); | 
|  | NativeBN.BN_mod_exp(r.bignum, a.bignum, p.bignum, m.bignum); | 
|  | return r; | 
|  | } | 
|  |  | 
|  |  | 
|  | static BigInt modInverse(BigInt a, BigInt m) { | 
|  | BigInt r = newBigInt(); | 
|  | NativeBN.BN_mod_inverse(r.bignum, a.bignum, m.bignum); | 
|  | return r; | 
|  | } | 
|  |  | 
|  |  | 
|  | static BigInt generatePrimeDefault(int bitLength) { | 
|  | BigInt r = newBigInt(); | 
|  | NativeBN.BN_generate_prime_ex(r.bignum, bitLength, false, 0, 0); | 
|  | return r; | 
|  | } | 
|  |  | 
|  | boolean isPrime(int certainty) { | 
|  | return NativeBN.BN_primality_test(bignum, certainty, false); | 
|  | } | 
|  | } |