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