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