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 package java.math; 18 19 import dalvik.annotation.optimization.ReachabilitySensitive; 20 import libcore.util.NativeAllocationRegistry; 21 22 /* 23 * In contrast to BigIntegers this class doesn't fake two's complement representation. 24 * Any Bit-Operations, including Shifting, solely regard the unsigned magnitude. 25 * Moreover BigInt objects are mutable and offer efficient in-place-operations. 26 */ 27 final class BigInt { 28 29 private static NativeAllocationRegistry registry = NativeAllocationRegistry.createMalloced( 30 BigInt.class.getClassLoader(), NativeBN.getNativeFinalizer()); 31 32 /* Fields used for the internal representation. */ 33 @ReachabilitySensitive 34 private transient long bignum = 0; 35 36 @Override toString()37 public String toString() { 38 return this.decString(); 39 } 40 hasNativeBignum()41 boolean hasNativeBignum() { 42 return this.bignum != 0; 43 } 44 makeValid()45 private void makeValid() { 46 if (this.bignum == 0) { 47 this.bignum = NativeBN.BN_new(); 48 registry.registerNativeAllocation(this, this.bignum); 49 } 50 } 51 newBigInt()52 private static BigInt newBigInt() { 53 BigInt bi = new BigInt(); 54 bi.bignum = NativeBN.BN_new(); 55 registry.registerNativeAllocation(bi, bi.bignum); 56 return bi; 57 } 58 59 cmp(BigInt a, BigInt b)60 static int cmp(BigInt a, BigInt b) { 61 return NativeBN.BN_cmp(a.bignum, b.bignum); 62 } 63 64 putCopy(BigInt from)65 void putCopy(BigInt from) { 66 this.makeValid(); 67 NativeBN.BN_copy(this.bignum, from.bignum); 68 } 69 copy()70 BigInt copy() { 71 BigInt bi = new BigInt(); 72 bi.putCopy(this); 73 return bi; 74 } 75 76 putLongInt(long val)77 void putLongInt(long val) { 78 this.makeValid(); 79 NativeBN.putLongInt(this.bignum, val); 80 } 81 putULongInt(long val, boolean neg)82 void putULongInt(long val, boolean neg) { 83 this.makeValid(); 84 NativeBN.putULongInt(this.bignum, val, neg); 85 } 86 invalidBigInteger(String s)87 private NumberFormatException invalidBigInteger(String s) { 88 throw new NumberFormatException("Invalid BigInteger: " + s); 89 } 90 putDecString(String original)91 void putDecString(String original) { 92 String s = checkString(original, 10); 93 this.makeValid(); 94 int usedLen = NativeBN.BN_dec2bn(this.bignum, s); 95 if (usedLen < s.length()) { 96 throw invalidBigInteger(original); 97 } 98 } 99 putHexString(String original)100 void putHexString(String original) { 101 String s = checkString(original, 16); 102 this.makeValid(); 103 int usedLen = NativeBN.BN_hex2bn(this.bignum, s); 104 if (usedLen < s.length()) { 105 throw invalidBigInteger(original); 106 } 107 } 108 109 /** 110 * Returns a string suitable for passing to OpenSSL. 111 * Throws if 's' doesn't match Java's rules for valid BigInteger strings. 112 * BN_dec2bn and BN_hex2bn do very little checking, so we need to manually 113 * ensure we comply with Java's rules. 114 * http://code.google.com/p/android/issues/detail?id=7036 115 */ checkString(String s, int base)116 String checkString(String s, int base) { 117 if (s == null) { 118 throw new NullPointerException("s == null"); 119 } 120 // A valid big integer consists of an optional '-' or '+' followed by 121 // one or more digit characters appropriate to the given base, 122 // and no other characters. 123 int charCount = s.length(); 124 int i = 0; 125 if (charCount > 0) { 126 char ch = s.charAt(0); 127 if (ch == '+') { 128 // Java supports leading +, but OpenSSL doesn't, so we need to strip it. 129 s = s.substring(1); 130 --charCount; 131 } else if (ch == '-') { 132 ++i; 133 } 134 } 135 if (charCount - i == 0) { 136 throw invalidBigInteger(s); 137 } 138 boolean nonAscii = false; 139 for (; i < charCount; ++i) { 140 char ch = s.charAt(i); 141 if (Character.digit(ch, base) == -1) { 142 throw invalidBigInteger(s); 143 } 144 if (ch > 128) { 145 nonAscii = true; 146 } 147 } 148 return nonAscii ? toAscii(s, base) : s; 149 } 150 151 // Java supports non-ASCII decimal digits, but OpenSSL doesn't. 152 // We need to translate the decimal digits but leave any other characters alone. 153 // This method assumes it's being called on a string that has already been validated. toAscii(String s, int base)154 private static String toAscii(String s, int base) { 155 int length = s.length(); 156 StringBuilder result = new StringBuilder(length); 157 for (int i = 0; i < length; ++i) { 158 char ch = s.charAt(i); 159 int value = Character.digit(ch, base); 160 if (value >= 0 && value <= 9) { 161 ch = (char) ('0' + value); 162 } 163 result.append(ch); 164 } 165 return result.toString(); 166 } 167 putBigEndian(byte[] a, boolean neg)168 void putBigEndian(byte[] a, boolean neg) { 169 this.makeValid(); 170 NativeBN.BN_bin2bn(a, a.length, neg, this.bignum); 171 } 172 putLittleEndianInts(int[] a, boolean neg)173 void putLittleEndianInts(int[] a, boolean neg) { 174 this.makeValid(); 175 NativeBN.litEndInts2bn(a, a.length, neg, this.bignum); 176 } 177 putBigEndianTwosComplement(byte[] a)178 void putBigEndianTwosComplement(byte[] a) { 179 this.makeValid(); 180 NativeBN.twosComp2bn(a, a.length, this.bignum); 181 } 182 183 longInt()184 long longInt() { 185 return NativeBN.longInt(this.bignum); 186 } 187 decString()188 String decString() { 189 return NativeBN.BN_bn2dec(this.bignum); 190 } 191 hexString()192 String hexString() { 193 return NativeBN.BN_bn2hex(this.bignum); 194 } 195 bigEndianMagnitude()196 byte[] bigEndianMagnitude() { 197 return NativeBN.BN_bn2bin(this.bignum); 198 } 199 littleEndianIntsMagnitude()200 int[] littleEndianIntsMagnitude() { 201 return NativeBN.bn2litEndInts(this.bignum); 202 } 203 sign()204 int sign() { 205 return NativeBN.sign(this.bignum); 206 } 207 setSign(int val)208 void setSign(int val) { 209 if (val > 0) { 210 NativeBN.BN_set_negative(this.bignum, 0); 211 } else { 212 if (val < 0) NativeBN.BN_set_negative(this.bignum, 1); 213 } 214 } 215 twosCompFitsIntoBytes(int desiredByteCount)216 boolean twosCompFitsIntoBytes(int desiredByteCount) { 217 int actualByteCount = (NativeBN.bitLength(this.bignum) + 7) / 8; 218 return actualByteCount <= desiredByteCount; 219 } 220 bitLength()221 int bitLength() { 222 return NativeBN.bitLength(this.bignum); 223 } 224 isBitSet(int n)225 boolean isBitSet(int n) { 226 return NativeBN.BN_is_bit_set(this.bignum, n); 227 } 228 229 // n > 0: shift left (multiply) shift(BigInt a, int n)230 static BigInt shift(BigInt a, int n) { 231 BigInt r = newBigInt(); 232 NativeBN.BN_shift(r.bignum, a.bignum, n); 233 return r; 234 } 235 shift(int n)236 void shift(int n) { 237 NativeBN.BN_shift(this.bignum, this.bignum, n); 238 } 239 addPositiveInt(int w)240 void addPositiveInt(int w) { 241 NativeBN.BN_add_word(this.bignum, w); 242 } 243 multiplyByPositiveInt(int w)244 void multiplyByPositiveInt(int w) { 245 NativeBN.BN_mul_word(this.bignum, w); 246 } 247 remainderByPositiveInt(BigInt a, int w)248 static int remainderByPositiveInt(BigInt a, int w) { 249 return NativeBN.BN_mod_word(a.bignum, w); 250 } 251 addition(BigInt a, BigInt b)252 static BigInt addition(BigInt a, BigInt b) { 253 BigInt r = newBigInt(); 254 NativeBN.BN_add(r.bignum, a.bignum, b.bignum); 255 return r; 256 } 257 add(BigInt a)258 void add(BigInt a) { 259 NativeBN.BN_add(this.bignum, this.bignum, a.bignum); 260 } 261 subtraction(BigInt a, BigInt b)262 static BigInt subtraction(BigInt a, BigInt b) { 263 BigInt r = newBigInt(); 264 NativeBN.BN_sub(r.bignum, a.bignum, b.bignum); 265 return r; 266 } 267 268 gcd(BigInt a, BigInt b)269 static BigInt gcd(BigInt a, BigInt b) { 270 BigInt r = newBigInt(); 271 NativeBN.BN_gcd(r.bignum, a.bignum, b.bignum); 272 return r; 273 } 274 product(BigInt a, BigInt b)275 static BigInt product(BigInt a, BigInt b) { 276 BigInt r = newBigInt(); 277 NativeBN.BN_mul(r.bignum, a.bignum, b.bignum); 278 return r; 279 } 280 bigExp(BigInt a, BigInt p)281 static BigInt bigExp(BigInt a, BigInt p) { 282 // Sign of p is ignored! 283 BigInt r = newBigInt(); 284 NativeBN.BN_exp(r.bignum, a.bignum, p.bignum); 285 return r; 286 } 287 exp(BigInt a, int p)288 static BigInt exp(BigInt a, int p) { 289 // Sign of p is ignored! 290 BigInt power = new BigInt(); 291 power.putLongInt(p); 292 return bigExp(a, power); 293 // OPTIONAL: 294 // int BN_sqr(BigInteger r, BigInteger a, BN_CTX ctx); 295 // int BN_sqr(BIGNUM *r, const BIGNUM *a,BN_CTX *ctx); 296 } 297 division(BigInt dividend, BigInt divisor, BigInt quotient, BigInt remainder)298 static void division(BigInt dividend, BigInt divisor, BigInt quotient, BigInt remainder) { 299 long quot, rem; 300 if (quotient != null) { 301 quotient.makeValid(); 302 quot = quotient.bignum; 303 } else { 304 quot = 0; 305 } 306 if (remainder != null) { 307 remainder.makeValid(); 308 rem = remainder.bignum; 309 } else { 310 rem = 0; 311 } 312 NativeBN.BN_div(quot, rem, dividend.bignum, divisor.bignum); 313 } 314 modulus(BigInt a, BigInt m)315 static BigInt modulus(BigInt a, BigInt m) { 316 // Sign of p is ignored! ? 317 BigInt r = newBigInt(); 318 NativeBN.BN_nnmod(r.bignum, a.bignum, m.bignum); 319 return r; 320 } 321 modExp(BigInt a, BigInt p, BigInt m)322 static BigInt modExp(BigInt a, BigInt p, BigInt m) { 323 // Sign of p is ignored! 324 BigInt r = newBigInt(); 325 NativeBN.BN_mod_exp(r.bignum, a.bignum, p.bignum, m.bignum); 326 return r; 327 } 328 329 modInverse(BigInt a, BigInt m)330 static BigInt modInverse(BigInt a, BigInt m) { 331 BigInt r = newBigInt(); 332 NativeBN.BN_mod_inverse(r.bignum, a.bignum, m.bignum); 333 return r; 334 } 335 336 generatePrimeDefault(int bitLength)337 static BigInt generatePrimeDefault(int bitLength) { 338 BigInt r = newBigInt(); 339 NativeBN.BN_generate_prime_ex(r.bignum, bitLength, false, 0, 0); 340 return r; 341 } 342 isPrime(int certainty)343 boolean isPrime(int certainty) { 344 return NativeBN.BN_primality_test(bignum, certainty, false); 345 } 346 } 347