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