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 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 = new NativeAllocationRegistry(
     30             BigInt.class.getClassLoader(), NativeBN.getNativeFinalizer(), NativeBN.size());
     31 
     32     /* Fields used for the internal representation. */
     33     @ReachabilitySensitive
     34     private transient long bignum = 0;
     35 
     36     @Override
     37     public String toString() {
     38         return this.decString();
     39     }
     40 
     41     boolean hasNativeBignum() {
     42         return this.bignum != 0;
     43     }
     44 
     45     private void makeValid() {
     46         if (this.bignum == 0) {
     47             this.bignum = NativeBN.BN_new();
     48             registry.registerNativeAllocation(this, this.bignum);
     49         }
     50     }
     51 
     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 
     60     static int cmp(BigInt a, BigInt b) {
     61         return NativeBN.BN_cmp(a.bignum, b.bignum);
     62     }
     63 
     64 
     65     void putCopy(BigInt from) {
     66         this.makeValid();
     67         NativeBN.BN_copy(this.bignum, from.bignum);
     68     }
     69 
     70     BigInt copy() {
     71         BigInt bi = new BigInt();
     72         bi.putCopy(this);
     73         return bi;
     74     }
     75 
     76 
     77     void putLongInt(long val) {
     78         this.makeValid();
     79         NativeBN.putLongInt(this.bignum, val);
     80     }
     81 
     82     void putULongInt(long val, boolean neg) {
     83         this.makeValid();
     84         NativeBN.putULongInt(this.bignum, val, neg);
     85     }
     86 
     87     private NumberFormatException invalidBigInteger(String s) {
     88         throw new NumberFormatException("Invalid BigInteger: " + s);
     89     }
     90 
     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 
    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      */
    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.
    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 
    168     void putBigEndian(byte[] a, boolean neg) {
    169         this.makeValid();
    170         NativeBN.BN_bin2bn(a, a.length, neg, this.bignum);
    171     }
    172 
    173     void putLittleEndianInts(int[] a, boolean neg) {
    174         this.makeValid();
    175         NativeBN.litEndInts2bn(a, a.length, neg, this.bignum);
    176     }
    177 
    178     void putBigEndianTwosComplement(byte[] a) {
    179         this.makeValid();
    180         NativeBN.twosComp2bn(a, a.length, this.bignum);
    181     }
    182 
    183 
    184     long longInt() {
    185         return NativeBN.longInt(this.bignum);
    186     }
    187 
    188     String decString() {
    189         return NativeBN.BN_bn2dec(this.bignum);
    190     }
    191 
    192     String hexString() {
    193         return NativeBN.BN_bn2hex(this.bignum);
    194     }
    195 
    196     byte[] bigEndianMagnitude() {
    197         return NativeBN.BN_bn2bin(this.bignum);
    198     }
    199 
    200     int[] littleEndianIntsMagnitude() {
    201         return NativeBN.bn2litEndInts(this.bignum);
    202     }
    203 
    204     int sign() {
    205         return NativeBN.sign(this.bignum);
    206     }
    207 
    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 
    216     boolean twosCompFitsIntoBytes(int desiredByteCount) {
    217         int actualByteCount = (NativeBN.bitLength(this.bignum) + 7) / 8;
    218         return actualByteCount <= desiredByteCount;
    219     }
    220 
    221     int bitLength() {
    222         return NativeBN.bitLength(this.bignum);
    223     }
    224 
    225     boolean isBitSet(int n) {
    226         return NativeBN.BN_is_bit_set(this.bignum, n);
    227     }
    228 
    229     // n > 0: shift left (multiply)
    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 
    236     void shift(int n) {
    237         NativeBN.BN_shift(this.bignum, this.bignum, n);
    238     }
    239 
    240     void addPositiveInt(int w) {
    241         NativeBN.BN_add_word(this.bignum, w);
    242     }
    243 
    244     void multiplyByPositiveInt(int w) {
    245         NativeBN.BN_mul_word(this.bignum, w);
    246     }
    247 
    248     static int remainderByPositiveInt(BigInt a, int w) {
    249         return NativeBN.BN_mod_word(a.bignum, w);
    250     }
    251 
    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 
    258     void add(BigInt a) {
    259         NativeBN.BN_add(this.bignum, this.bignum, a.bignum);
    260     }
    261 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    343     boolean isPrime(int certainty) {
    344         return NativeBN.BN_primality_test(bignum, certainty, false);
    345     }
    346 }
    347