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