Home | History | Annotate | Download | only in math
      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