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