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 org.apache.harmony.math.internal.nls.Messages; 20 import org.openssl.NativeBN; 21 22 import java.util.Random; 23 24 /* 25 * In contrast to BigIntegers this class doesn't fake two's complement representation. 26 * Any Bit-Operations, including Shifting, solely regard the unsigned magnitude. 27 * Moreover BigInt objects are mutable and offer efficient in-place-operations. 28 */ 29 30 class BigInt 31 // extends Number 32 // implements Comparable<BigInt>, 33 // Serializable 34 { 35 36 class Context { 37 int bnctx; 38 Context() { 39 bnctx = NativeBN.BN_CTX_new(); 40 } 41 } 42 static BigInt dummy; 43 static Context defaultContext; 44 45 static { 46 dummy = new BigInt(); 47 defaultContext = dummy.new Context(); 48 } 49 50 static int getCtx (Context t) { 51 return (t != null) ? t.bnctx : defaultContext.bnctx; 52 } 53 54 /** This is the serialVersionUID used by the sun implementation */ 55 private static final long serialVersionUID = -8287574255936472291L; 56 57 /* Fields used for the internal representation. */ 58 transient int bignum = 0; 59 60 61 public void dispose() { 62 if (this.bignum != 0) { 63 NativeBN.BN_free(this.bignum); 64 this.bignum = 0; 65 } 66 } 67 68 @Override 69 protected void finalize() { 70 dispose(); 71 } 72 73 @Override 74 public String toString() { 75 return this.decString(); 76 } 77 78 public int getNativeBIGNUM() { 79 return this.bignum; 80 } 81 82 public static int consumeErrors(StringBuilder sb) { 83 int cnt = 0; 84 int e, reason; 85 while ((e = NativeBN.ERR_get_error()) != 0) { 86 reason = e & 255; 87 if (reason == 103) { 88 // math.17=BigInteger divide by zero 89 throw new ArithmeticException(Messages.getString("math.17")); //$NON-NLS-1$ 90 } 91 if (reason == 108) { 92 // math.19=BigInteger not invertible. 93 throw new ArithmeticException(Messages.getString("math.19")); //$NON-NLS-1$ 94 } 95 if (reason == 65) { 96 throw new OutOfMemoryError(); 97 } 98 sb.append(e).append(": "); 99 String s = NativeBN.ERR_error_string(e); 100 sb.append(s); 101 cnt++; 102 } 103 return cnt; 104 } 105 106 private static void Check(boolean success) { 107 if (!success) { 108 StringBuilder sb = new StringBuilder("(openssl)ERR: "); 109 int cnt = consumeErrors(sb); 110 if (cnt > 0) 111 throw new ArithmeticException(sb.toString()); 112 } 113 } 114 115 116 private void makeValid() { 117 if (this.bignum == 0) { 118 this.bignum = NativeBN.BN_new(); 119 Check(this.bignum != 0); 120 } 121 } 122 123 private static BigInt newBigInt() { 124 BigInt bi = new BigInt(); 125 bi.bignum = NativeBN.BN_new(); 126 Check(bi.bignum != 0); 127 return bi; 128 } 129 130 131 public static int cmp(BigInt a, BigInt b) { 132 return NativeBN.BN_cmp(a.bignum, b.bignum); 133 } 134 135 136 public void putCopy(BigInt from) { 137 this.makeValid(); 138 Check(NativeBN.BN_copy(this.bignum, from.bignum)); 139 } 140 141 public BigInt copy() { 142 BigInt bi = new BigInt(); 143 bi.putCopy(this); 144 return bi; 145 } 146 147 148 public void putLongInt(long val) { 149 this.makeValid(); 150 Check(NativeBN.putLongInt(this.bignum, val)); 151 } 152 153 public void putULongInt(long val, boolean neg) { 154 this.makeValid(); 155 Check(NativeBN.putULongInt(this.bignum, val, neg)); 156 } 157 158 public void putDecString(String str) { 159 if (str == null) throw new NullPointerException(); 160 if (str.length() == 0) { 161 // math.12=Zero length BigInteger 162 throw new NumberFormatException(Messages.getString("math.12")); //$NON-NLS-1$ 163 } 164 this.makeValid(); 165 int usedLen = NativeBN.BN_dec2bn(this.bignum, str); 166 Check((usedLen > 0)); 167 if (usedLen < str.length()) { 168 throw new NumberFormatException(str); 169 } 170 } 171 172 public void putHexString(String str) { 173 if (str == null) throw new NullPointerException(); 174 if (str.length() == 0) { 175 // math.12=Zero length BigInteger 176 throw new NumberFormatException(Messages.getString("math.12")); //$NON-NLS-1$ 177 } 178 this.makeValid(); 179 int usedLen = NativeBN.BN_hex2bn(this.bignum, str); 180 Check((usedLen > 0)); 181 if (usedLen < str.length()) { 182 throw new NumberFormatException(str); 183 } 184 } 185 186 public void putBigEndian(byte[] a, boolean neg) { 187 this.makeValid(); 188 Check(NativeBN.BN_bin2bn(a, a.length, neg, this.bignum)); 189 } 190 191 public void putLittleEndianInts(int[] a, boolean neg) { 192 this.makeValid(); 193 Check(NativeBN.litEndInts2bn(a, a.length, neg, this.bignum)); 194 } 195 196 public void putBigEndianTwosComplement(byte[] a) { 197 this.makeValid(); 198 Check(NativeBN.twosComp2bn(a, a.length, this.bignum)); 199 } 200 201 202 public long longInt() { 203 return NativeBN.longInt(this.bignum); 204 } 205 206 public String decString() { 207 String str = NativeBN.BN_bn2dec(this.bignum); 208 return str; 209 } 210 211 public String hexString() { 212 String str = NativeBN.BN_bn2hex(this.bignum); 213 return str; 214 } 215 216 public byte[] bigEndianMagnitude() { 217 byte[] a = NativeBN.BN_bn2bin(this.bignum, null); 218 return a; 219 } 220 221 public int[] littleEndianIntsMagnitude() { 222 int[] a = NativeBN.bn2litEndInts(this.bignum, null); 223 return a; 224 } 225 226 public int sign() { 227 return NativeBN.sign(this.bignum); 228 } 229 230 public void setSign(int val) { 231 if (val > 0) NativeBN.BN_set_negative(this.bignum, 0); 232 else if (val < 0) NativeBN.BN_set_negative(this.bignum, 1); 233 } 234 235 public boolean twosCompFitsIntoBytes(int desiredByteCount) { 236 int actualByteCount = (NativeBN.bitLength(this.bignum) + 7) / 8; 237 return actualByteCount <= desiredByteCount; 238 } 239 240 public int bitLength() { 241 return NativeBN.bitLength(this.bignum); 242 } 243 244 public boolean isBitSet(int n) { 245 return NativeBN.BN_is_bit_set(this.bignum, n); 246 } 247 248 public void modifyBit(int n, int op) { 249 // op: 0 = reset; 1 = set; -1 = flip 250 Check(NativeBN.modifyBit(this.bignum, n, op)); 251 } 252 253 254 // n > 0: shift left (multiply) 255 public static BigInt shift(BigInt a, int n) { 256 BigInt r = newBigInt(); 257 Check(NativeBN.BN_lshift(r.bignum, a.bignum, n)); 258 return r; 259 } 260 261 public void shift(int n) { 262 Check(NativeBN.BN_lshift(this.bignum, this.bignum, n)); 263 } 264 265 public void addPositiveInt(int w) { 266 Check(NativeBN.BN_add_word(this.bignum, w)); 267 } 268 269 public void subtractPositiveInt(int w) { 270 Check(NativeBN.BN_sub_word(this.bignum, w)); 271 } 272 273 public void multiplyByPositiveInt(int w) { 274 Check(NativeBN.BN_mul_word(this.bignum, w)); 275 } 276 277 public int divideByPositiveInt(int w) { 278 int rem = NativeBN.BN_div_word(this.bignum, w); 279 Check(rem != -1); 280 return rem; 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, Context t) { 307 BigInt r = newBigInt(); 308 Check(NativeBN.BN_gcd(r.bignum, a.bignum, b.bignum, getCtx(t))); 309 return r; 310 } 311 312 public static BigInt product(BigInt a, BigInt b, Context t) { 313 BigInt r = newBigInt(); 314 Check(NativeBN.BN_mul(r.bignum, a.bignum, b.bignum, getCtx(t))); 315 return r; 316 } 317 318 public void multiplyBy(BigInt a, Context t) { 319 Check(NativeBN.BN_mul(this.bignum, this.bignum, a.bignum, getCtx(t))); 320 } 321 322 public static BigInt bigExp(BigInt a, BigInt p, Context t) { 323 // Sign of p is ignored! 324 BigInt r = newBigInt(); 325 Check(NativeBN.BN_exp(r.bignum, a.bignum, p.bignum, getCtx(t))); 326 return r; 327 } 328 329 public static BigInt exp(BigInt a, int p, Context t) { 330 // Sign of p is ignored! 331 BigInt power = new BigInt(); 332 power.putLongInt(p); 333 return bigExp(a, power, t); 334 // OPTIONAL: 335 // public int BN_sqr(BigInteger r, BigInteger a, BN_CTX ctx); 336 // int BN_sqr(BIGNUM *r, const BIGNUM *a,BN_CTX *ctx); 337 } 338 339 public static void division(BigInt dividend, BigInt divisor, Context t, 340 BigInt quotient, BigInt remainder) { 341 int quot, rem; 342 if (quotient != null) { 343 quotient.makeValid(); 344 quot = quotient.bignum; 345 } 346 else quot = 0; 347 if (remainder != null) { 348 remainder.makeValid(); 349 rem = remainder.bignum; 350 } 351 else rem = 0; 352 Check(NativeBN.BN_div(quot, rem, dividend.bignum, divisor.bignum, getCtx(t))); 353 } 354 355 public static BigInt modulus(BigInt a, BigInt m, Context t) { 356 // Sign of p is ignored! ? 357 BigInt r = newBigInt(); 358 Check(NativeBN.BN_nnmod(r.bignum, a.bignum, m.bignum, getCtx(t))); 359 return r; 360 } 361 362 public static BigInt modExp(BigInt a, BigInt p, BigInt m, Context t) { 363 // Sign of p is ignored! 364 BigInt r = newBigInt(); 365 Check(NativeBN.BN_mod_exp(r.bignum, a.bignum, p.bignum, m.bignum, getCtx(t))); 366 367 // OPTIONAL: 368 // int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx); 369 return r; 370 } 371 372 373 public static BigInt modInverse(BigInt a, BigInt m, Context t) { 374 BigInt r = newBigInt(); 375 Check(NativeBN.BN_mod_inverse(r.bignum, a.bignum, m.bignum, getCtx(t))); 376 return r; 377 } 378 379 380 public static BigInt generatePrimeDefault(int bitLength, Random rnd, Context t) { 381 BigInt r = newBigInt(); 382 Check(NativeBN.BN_generate_prime_ex(r.bignum, bitLength, false, 0, 0, 0)); 383 return r; 384 } 385 386 public static BigInt generatePrimeSafe(int bitLength, Random rnd, Context t) { 387 BigInt r = newBigInt(); 388 Check(NativeBN.BN_generate_prime_ex(r.bignum, bitLength, true, 0, 0, 0)); 389 return r; 390 } 391 392 public boolean isPrime(int certainty, Random rnd, Context t) { 393 return NativeBN.BN_is_prime_ex(bignum, certainty, getCtx(t), 0); 394 } 395 } 396