--- /dev/null
+//
+// BigInteger.cs - Big Integer implementation
+//
+// Authors:
+// Chew Keong TAN
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// Copyright (c) 2002 Chew Keong TAN
+// All rights reserved.
+//
+// Modifications from original
+// - Removed all reference to Random class (not secure enough)
+// - Moved all static Test function into BigIntegerTest.cs (for NUnit)
+//
+
+//************************************************************************************
+// BigInteger Class Version 1.03
+//
+// Copyright (c) 2002 Chew Keong TAN
+// All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, provided that the above
+// copyright notice(s) and this permission notice appear in all copies of
+// the Software and that both the above copyright notice(s) and this
+// permission notice appear in supporting documentation.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+// OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+// HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+// INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+//
+// Disclaimer
+// ----------
+// Although reasonable care has been taken to ensure the correctness of this
+// implementation, this code should never be used in any application without
+// proper verification and testing. I disclaim all liability and responsibility
+// to any person or entity with respect to any loss or damage caused, or alleged
+// to be caused, directly or indirectly, by the use of this BigInteger class.
+//
+// Comments, bugs and suggestions to
+// (http://www.codeproject.com/csharp/biginteger.asp)
+//
+//
+// Overloaded Operators +, -, *, /, %, >>, <<, ==, !=, >, <, >=, <=, &, |, ^, ++, --, ~
+//
+// Features
+// --------
+// 1) Arithmetic operations involving large signed integers (2's complement).
+// 2) Primality test using Fermat little theorm, Rabin Miller's method,
+// Solovay Strassen's method and Lucas strong pseudoprime.
+// 3) Modulo exponential with Barrett's reduction.
+// 4) Inverse modulo.
+// 5) Pseudo prime generation.
+// 6) Co-prime generation.
+//
+//
+// Known Problem
+// -------------
+// This pseudoprime passes my implementation of
+// primality test but failed in JDK's isProbablePrime test.
+//
+// byte[] pseudoPrime1 = { (byte)0x00,
+// (byte)0x85, (byte)0x84, (byte)0x64, (byte)0xFD, (byte)0x70, (byte)0x6A,
+// (byte)0x9F, (byte)0xF0, (byte)0x94, (byte)0x0C, (byte)0x3E, (byte)0x2C,
+// (byte)0x74, (byte)0x34, (byte)0x05, (byte)0xC9, (byte)0x55, (byte)0xB3,
+// (byte)0x85, (byte)0x32, (byte)0x98, (byte)0x71, (byte)0xF9, (byte)0x41,
+// (byte)0x21, (byte)0x5F, (byte)0x02, (byte)0x9E, (byte)0xEA, (byte)0x56,
+// (byte)0x8D, (byte)0x8C, (byte)0x44, (byte)0xCC, (byte)0xEE, (byte)0xEE,
+// (byte)0x3D, (byte)0x2C, (byte)0x9D, (byte)0x2C, (byte)0x12, (byte)0x41,
+// (byte)0x1E, (byte)0xF1, (byte)0xC5, (byte)0x32, (byte)0xC3, (byte)0xAA,
+// (byte)0x31, (byte)0x4A, (byte)0x52, (byte)0xD8, (byte)0xE8, (byte)0xAF,
+// (byte)0x42, (byte)0xF4, (byte)0x72, (byte)0xA1, (byte)0x2A, (byte)0x0D,
+// (byte)0x97, (byte)0xB1, (byte)0x31, (byte)0xB3,
+// };
+//
+//
+// Change Log
+// ----------
+// 1) September 23, 2002 (Version 1.03)
+// - Fixed operator- to give correct data length.
+// - Added Lucas sequence generation.
+// - Added Strong Lucas Primality test.
+// - Added integer square root method.
+// - Added setBit/unsetBit methods.
+// - New isProbablePrime() method which do not require the
+// confident parameter.
+//
+// 2) August 29, 2002 (Version 1.02)
+// - Fixed bug in the exponentiation of negative numbers.
+// - Faster modular exponentiation using Barrett reduction.
+// - Added getBytes() method.
+// - Fixed bug in ToHexString method.
+// - Added overloading of ^ operator.
+// - Faster computation of Jacobi symbol.
+//
+// 3) August 19, 2002 (Version 1.01)
+// - Big integer is stored and manipulated as unsigned integers (4 bytes) instead of
+// individual bytes this gives significant performance improvement.
+// - Updated Fermat's Little Theorem test to use a^(p-1) mod p = 1
+// - Added isProbablePrime method.
+// - Updated documentation.
+//
+// 4) August 9, 2002 (Version 1.0)
+// - Initial Release.
+//
+//
+// References
+// [1] D. E. Knuth, "Seminumerical Algorithms", The Art of Computer Programming Vol. 2,
+// 3rd Edition, Addison-Wesley, 1998.
+//
+// [2] K. H. Rosen, "Elementary Number Theory and Its Applications", 3rd Ed,
+// Addison-Wesley, 1993.
+//
+// [3] B. Schneier, "Applied Cryptography", 2nd Ed, John Wiley & Sons, 1996.
+//
+// [4] A. Menezes, P. van Oorschot, and S. Vanstone, "Handbook of Applied Cryptography",
+// CRC Press, 1996, www.cacr.math.uwaterloo.ca/hac
+//
+// [5] A. Bosselaers, R. Govaerts, and J. Vandewalle, "Comparison of Three Modular
+// Reduction Functions," Proc. CRYPTO'93, pp.175-186.
+//
+// [6] R. Baillie and S. S. Wagstaff Jr, "Lucas Pseudoprimes", Mathematics of Computation,
+// Vol. 35, No. 152, Oct 1980, pp. 1391-1417.
+//
+// [7] H. C. Williams, "Édouard Lucas and Primality Testing", Canadian Mathematical
+// Society Series of Monographs and Advance Texts, vol. 22, John Wiley & Sons, New York,
+// NY, 1998.
+//
+// [8] P. Ribenboim, "The new book of prime number records", 3rd edition, Springer-Verlag,
+// New York, NY, 1995.
+//
+// [9] M. Joye and J.-J. Quisquater, "Efficient computation of full Lucas sequences",
+// Electronics Letters, 32(6), 1996, pp 537-538.
+//
+//************************************************************************************
+
+using System;
+
+namespace System.Security.Cryptography {
+
+internal class BigRandom {
+ RandomNumberGenerator rng;
+
+ public BigRandom ()
+ {
+ rng = RandomNumberGenerator.Create ();
+ }
+
+ public void Get (uint[] data)
+ {
+ byte[] random = new byte [4 * data.Length];
+ rng.GetBytes (random);
+ int n = 0;
+ for (int i=0; i < data.Length; i++) {
+ data[i] = BitConverter.ToUInt32 (random, n);
+ n+=4;
+ }
+ }
+
+ public int GetInt (int maxValue)
+ {
+ // calculate mask
+ int mask = Int32.MaxValue;
+ while ((mask & maxValue) == maxValue)
+ mask >>= 1;
+ // undo last iteration
+ mask <<= 1;
+ mask |= 0x01;
+ byte[] data = new byte [4];
+ int result = -1;
+ while ((result < 0) || (result > maxValue)) {
+ rng.GetBytes (data);
+ result = (BitConverter.ToInt32 (data, 0) & mask);
+ }
+ return result;
+ }
+
+ public byte GetByte()
+ {
+ byte[] data = new byte [1];
+ rng.GetBytes (data);
+ return data [0];
+ }
+}
+
+internal class BigInteger {
+ // maximum length of the BigInteger in uint (4 bytes)
+ // change this to suit the required level of precision.
+
+ //private const int maxLength = 70;
+ // FIXME: actually this limit us to approx. 2048 bits keypair for RSA
+ private const int maxLength = 140;
+
+ private BigRandom random;
+
+ // primes smaller than 2000 to test the generated prime number
+
+ public static readonly int[] primesBelow2000 = {
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
+ 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
+ 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293,
+ 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397,
+ 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499,
+ 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599,
+ 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691,
+ 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797,
+ 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887,
+ 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,
+ 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097,
+ 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193,
+ 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297,
+ 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399,
+ 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499,
+ 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597,
+ 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699,
+ 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789,
+ 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,
+ 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999 };
+
+ private uint[] data = null; // stores bytes from the Big Integer
+ public int dataLength; // number of actual chars used
+
+ // Constructor (Default value for BigInteger is 0
+ public BigInteger()
+ {
+ data = new uint[maxLength];
+ dataLength = 1;
+ }
+
+ // Constructor (Default value provided by long)
+ public BigInteger(long value)
+ {
+ data = new uint[maxLength];
+ long tempVal = value;
+ // copy bytes from long to BigInteger without any assumption of
+ // the length of the long datatype
+ dataLength = 0;
+ while(value != 0 && dataLength < maxLength) {
+ data[dataLength] = (uint)(value & 0xFFFFFFFF);
+ value >>= 32;
+ dataLength++;
+ }
+
+ if(tempVal > 0) { // overflow check for +ve value
+ if(value != 0 || (data[maxLength-1] & 0x80000000) != 0)
+ throw(new ArithmeticException("Positive overflow in constructor."));
+ }
+ else if(tempVal < 0) { // underflow check for -ve value
+ if(value != -1 || (data[dataLength-1] & 0x80000000) == 0)
+ throw(new ArithmeticException("Negative underflow in constructor."));
+ }
+
+ if(dataLength == 0)
+ dataLength = 1;
+ }
+
+ // Constructor (Default value provided by ulong)
+ public BigInteger(ulong value)
+ {
+ data = new uint[maxLength];
+ // copy bytes from ulong to BigInteger without any assumption of
+ // the length of the ulong datatype
+
+ dataLength = 0;
+ while(value != 0 && dataLength < maxLength) {
+ data[dataLength] = (uint)(value & 0xFFFFFFFF);
+ value >>= 32;
+ dataLength++;
+ }
+
+ if(value != 0 || (data[maxLength-1] & 0x80000000) != 0)
+ throw(new ArithmeticException("Positive overflow in constructor."));
+
+ if(dataLength == 0)
+ dataLength = 1;
+ }
+
+ // Constructor (Default value provided by BigInteger)
+ public BigInteger(BigInteger bi)
+ {
+ data = new uint[maxLength];
+ dataLength = bi.dataLength;
+ for(int i = 0; i < dataLength; i++)
+ data[i] = bi.data[i];
+ }
+
+ // Constructor (Default value provided by a string of digits of the
+ // specified base)
+ // Example (base 10)
+ // -----------------
+ // To initialize "a" with the default value of 1234 in base 10
+ // BigInteger a = new BigInteger("1234", 10)
+ //
+ // To initialize "a" with the default value of -1234
+ // BigInteger a = new BigInteger("-1234", 10)
+ //
+ // Example (base 16)
+ // -----------------
+ // To initialize "a" with the default value of 0x1D4F in base 16
+ // BigInteger a = new BigInteger("1D4F", 16)
+ //
+ // To initialize "a" with the default value of -0x1D4F
+ // BigInteger a = new BigInteger("-1D4F", 16)
+ //
+ // Note that string values are specified in the <sign><magnitude>
+ // format.
+ public BigInteger(string value, int radix)
+ {
+ BigInteger multiplier = new BigInteger(1);
+ BigInteger result = new BigInteger();
+ value = (value.ToUpper()).Trim();
+ int limit = 0;
+
+ if(value[0] == '-')
+ limit = 1;
+
+ for(int i = value.Length - 1; i >= limit ; i--) {
+ int posVal = (int)value[i];
+
+ if(posVal >= '0' && posVal <= '9')
+ posVal -= '0';
+ else if(posVal >= 'A' && posVal <= 'Z')
+ posVal = (posVal - 'A') + 10;
+ else
+ posVal = 9999999; // arbitrary large
+
+
+ if(posVal >= radix)
+ throw(new ArithmeticException("Invalid string in constructor."));
+ else {
+ if(value[0] == '-')
+ posVal = -posVal;
+
+ result = result + (multiplier * posVal);
+
+ if((i - 1) >= limit)
+ multiplier = multiplier * radix;
+ }
+ }
+
+ if(value[0] == '-') { // negative values
+ if((result.data[maxLength-1] & 0x80000000) == 0)
+ throw(new ArithmeticException("Negative underflow in constructor."));
+ }
+ else { // positive values
+ if((result.data[maxLength-1] & 0x80000000) != 0)
+ throw(new ArithmeticException("Positive overflow in constructor."));
+ }
+
+ data = new uint[maxLength];
+ for(int i = 0; i < result.dataLength; i++)
+ data[i] = result.data[i];
+
+ dataLength = result.dataLength;
+ }
+
+
+ // Constructor (Default value provided by an array of bytes)
+ //
+ // The lowest index of the input byte array (i.e [0]) should contain the
+ // most significant byte of the number, and the highest index should
+ // contain the least significant byte.
+ //
+ // E.g.
+ // To initialize "a" with the default value of 0x1D4F in base 16
+ // byte[] temp = { 0x1D, 0x4F };
+ // BigInteger a = new BigInteger(temp)
+ //
+ // Note that this method of initialization does not allow the
+ // sign to be specified.
+ public BigInteger(byte[] inData)
+ {
+ dataLength = inData.Length >> 2;
+
+ int leftOver = inData.Length & 0x3;
+ if(leftOver != 0) // length not multiples of 4
+ dataLength++;
+
+
+ if(dataLength > maxLength)
+ throw(new ArithmeticException("Byte overflow in constructor."));
+
+ data = new uint[maxLength];
+
+ for(int i = inData.Length - 1, j = 0; i >= 3; i -= 4, j++) {
+ data[j] = (uint)((inData[i-3] << 24) + (inData[i-2] << 16) +
+ (inData[i-1] << 8) + inData[i]);
+ }
+
+ if(leftOver == 1)
+ data[dataLength-1] = (uint)inData[0];
+ else if(leftOver == 2)
+ data[dataLength-1] = (uint)((inData[0] << 8) + inData[1]);
+ else if(leftOver == 3)
+ data[dataLength-1] = (uint)((inData[0] << 16) + (inData[1] << 8) + inData[2]);
+
+
+ while(dataLength > 1 && data[dataLength-1] == 0)
+ dataLength--;
+
+ //Console.WriteLine("Len = " + dataLength);
+ }
+
+ // Constructor (Default value provided by an array of bytes of the
+ // specified length.)
+ public BigInteger(byte[] inData, int inLen)
+ {
+ dataLength = inLen >> 2;
+
+ int leftOver = inLen & 0x3;
+ if(leftOver != 0) // length not multiples of 4
+ dataLength++;
+
+ if(dataLength > maxLength || inLen > inData.Length)
+ throw(new ArithmeticException("Byte overflow in constructor."));
+
+
+ data = new uint[maxLength];
+
+ for(int i = inLen - 1, j = 0; i >= 3; i -= 4, j++) {
+ data[j] = (uint)((inData[i-3] << 24) + (inData[i-2] << 16) +
+ (inData[i-1] << 8) + inData[i]);
+ }
+
+ if(leftOver == 1)
+ data[dataLength-1] = (uint)inData[0];
+ else if(leftOver == 2)
+ data[dataLength-1] = (uint)((inData[0] << 8) + inData[1]);
+ else if(leftOver == 3)
+ data[dataLength-1] = (uint)((inData[0] << 16) + (inData[1] << 8) + inData[2]);
+
+
+ if(dataLength == 0)
+ dataLength = 1;
+
+ while(dataLength > 1 && data[dataLength-1] == 0)
+ dataLength--;
+
+ //Console.WriteLine("Len = " + dataLength);
+ }
+
+
+ // Constructor (Default value provided by an array of unsigned integers)
+ public BigInteger(uint[] inData)
+ {
+ dataLength = inData.Length;
+
+ if(dataLength > maxLength)
+ throw(new ArithmeticException("Byte overflow in constructor."));
+
+ data = new uint[maxLength];
+
+ for(int i = dataLength - 1, j = 0; i >= 0; i--, j++)
+ data[j] = inData[i];
+
+ while(dataLength > 1 && data[dataLength-1] == 0)
+ dataLength--;
+
+ //Console.WriteLine("Len = " + dataLength);
+ }
+
+ private BigRandom rng {
+ get {
+ if (random == null)
+ random = new BigRandom ();
+ return random;
+ }
+ }
+
+ // Overloading of the typecast operator.
+ // For BigInteger bi = 10;
+ public static implicit operator BigInteger (long value)
+ {
+ return (new BigInteger (value));
+ }
+
+ public static implicit operator BigInteger (ulong value)
+ {
+ return (new BigInteger (value));
+ }
+
+ public static implicit operator BigInteger (int value)
+ {
+ return (new BigInteger ( (long)value));
+ }
+
+ public static implicit operator BigInteger (uint value)
+ {
+ return (new BigInteger ( (ulong)value));
+ }
+
+ // Overloading of addition operator
+ public static BigInteger operator + (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger result = new BigInteger ();
+
+ result.dataLength = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+
+ long carry = 0;
+ for(int i = 0; i < result.dataLength; i++) {
+ long sum = (long)bi1.data[i] + (long)bi2.data[i] + carry;
+ carry = sum >> 32;
+ result.data[i] = (uint)(sum & 0xFFFFFFFF);
+ }
+
+ if(carry != 0 && result.dataLength < maxLength) {
+ result.data[result.dataLength] = (uint)(carry);
+ result.dataLength++;
+ }
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+
+ // overflow check
+ int lastPos = maxLength - 1;
+ if((bi1.data[lastPos] & 0x80000000) == (bi2.data[lastPos] & 0x80000000) &&
+ (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) {
+ throw (new ArithmeticException());
+ }
+
+ return result;
+ }
+
+ // Overloading of the unary ++ operator
+ public static BigInteger operator ++ (BigInteger bi1)
+ {
+ BigInteger result = new BigInteger (bi1);
+
+ long val, carry = 1;
+ int index = 0;
+
+ while(carry != 0 && index < maxLength) {
+ val = (long)(result.data[index]);
+ val++;
+
+ result.data[index] = (uint)(val & 0xFFFFFFFF);
+ carry = val >> 32;
+
+ index++;
+ }
+
+ if(index > result.dataLength)
+ result.dataLength = index;
+ else {
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+ }
+
+ // overflow check
+ int lastPos = maxLength - 1;
+
+ // overflow if initial value was +ve but ++ caused a sign
+ // change to negative.
+
+ if((bi1.data[lastPos] & 0x80000000) == 0 &&
+ (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) {
+ throw (new ArithmeticException("Overflow in ++."));
+ }
+ return result;
+ }
+
+ // Overloading of subtraction operator
+ public static BigInteger operator - (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger result = new BigInteger ();
+
+ result.dataLength = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+
+ long carryIn = 0;
+ for(int i = 0; i < result.dataLength; i++) {
+ long diff;
+
+ diff = (long)bi1.data[i] - (long)bi2.data[i] - carryIn;
+ result.data[i] = (uint)(diff & 0xFFFFFFFF);
+
+ if(diff < 0)
+ carryIn = 1;
+ else
+ carryIn = 0;
+ }
+
+ // roll over to negative
+ if(carryIn != 0) {
+ for(int i = result.dataLength; i < maxLength; i++)
+ result.data[i] = 0xFFFFFFFF;
+ result.dataLength = maxLength;
+ }
+
+ // fixed in v1.03 to give correct datalength for a - (-b)
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ // overflow check
+
+ int lastPos = maxLength - 1;
+ if((bi1.data[lastPos] & 0x80000000) != (bi2.data[lastPos] & 0x80000000) &&
+ (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) {
+ throw (new ArithmeticException());
+ }
+
+ return result;
+ }
+
+
+ // Overloading of the unary -- operator
+ public static BigInteger operator -- (BigInteger bi1)
+ {
+ BigInteger result = new BigInteger (bi1);
+
+ long val;
+ bool carryIn = true;
+ int index = 0;
+
+ while(carryIn && index < maxLength) {
+ val = (long)(result.data[index]);
+ val--;
+
+ result.data[index] = (uint)(val & 0xFFFFFFFF);
+
+ if(val >= 0)
+ carryIn = false;
+
+ index++;
+ }
+
+ if(index > result.dataLength)
+ result.dataLength = index;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ // overflow check
+ int lastPos = maxLength - 1;
+
+ // overflow if initial value was -ve but -- caused a sign
+ // change to positive.
+
+ if((bi1.data[lastPos] & 0x80000000) != 0 &&
+ (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) {
+ throw (new ArithmeticException("Underflow in --."));
+ }
+
+ return result;
+ }
+
+ // Overloading of multiplication operator
+ public static BigInteger operator * (BigInteger bi1, BigInteger bi2)
+ {
+ int lastPos = maxLength-1;
+ bool bi1Neg = false, bi2Neg = false;
+
+ // take the absolute value of the inputs
+ try {
+ if((bi1.data[lastPos] & 0x80000000) != 0) { // bi1 negative
+ bi1Neg = true; bi1 = -bi1;
+ }
+ if((bi2.data[lastPos] & 0x80000000) != 0) { // bi2 negative
+ bi2Neg = true; bi2 = -bi2;
+ }
+ }
+ catch(Exception) {}
+
+ BigInteger result = new BigInteger();
+
+ // multiply the absolute values
+ try {
+ for(int i = 0; i < bi1.dataLength; i++) {
+ if(bi1.data[i] == 0) continue;
+
+ ulong mcarry = 0;
+ for(int j = 0, k = i; j < bi2.dataLength; j++, k++) {
+ // k = i + j
+ ulong val = ((ulong)bi1.data[i] * (ulong)bi2.data[j]) +
+ (ulong)result.data[k] + mcarry;
+
+ result.data[k] = (uint)(val & 0xFFFFFFFF);
+ mcarry = (val >> 32);
+ }
+
+ if(mcarry != 0)
+ result.data[i+bi2.dataLength] = (uint)mcarry;
+ }
+ }
+ catch(Exception) {
+ throw(new ArithmeticException("Multiplication overflow."));
+ }
+
+
+ result.dataLength = bi1.dataLength + bi2.dataLength;
+ if(result.dataLength > maxLength)
+ result.dataLength = maxLength;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ // overflow check (result is -ve)
+ if((result.data[lastPos] & 0x80000000) != 0) {
+ if(bi1Neg != bi2Neg && result.data[lastPos] == 0x80000000) { // different sign
+ // handle the special case where multiplication produces
+ // a max negative number in 2's complement.
+
+ if(result.dataLength == 1)
+ return result;
+ else {
+ bool isMaxNeg = true;
+ for(int i = 0; i < result.dataLength - 1 && isMaxNeg; i++) {
+ if(result.data[i] != 0)
+ isMaxNeg = false;
+ }
+
+ if(isMaxNeg)
+ return result;
+ }
+ }
+
+ throw(new ArithmeticException("Multiplication overflow."));
+ }
+
+ // if input has different signs, then result is -ve
+ if(bi1Neg != bi2Neg)
+ return -result;
+
+ return result;
+ }
+
+ // Overloading of unary << operators
+ public static BigInteger operator << (BigInteger bi1, int shiftVal)
+ {
+ BigInteger result = new BigInteger (bi1);
+ result.dataLength = shiftLeft(result.data, shiftVal);
+
+ return result;
+ }
+
+ // least significant bits at lower part of buffer
+ private static int shiftLeft (uint[] buffer, int shiftVal)
+ {
+ int shiftAmount = 32;
+ int bufLen = buffer.Length;
+
+ while(bufLen > 1 && buffer[bufLen-1] == 0)
+ bufLen--;
+
+ for(int count = shiftVal; count > 0;) {
+ if(count < shiftAmount)
+ shiftAmount = count;
+
+ //Console.WriteLine("shiftAmount = {0}", shiftAmount);
+
+ ulong carry = 0;
+ for(int i = 0; i < bufLen; i++) {
+ ulong val = ((ulong)buffer[i]) << shiftAmount;
+ val |= carry;
+
+ buffer[i] = (uint)(val & 0xFFFFFFFF);
+ carry = val >> 32;
+ }
+
+ if(carry != 0) {
+ if(bufLen + 1 <= buffer.Length) {
+ buffer[bufLen] = (uint)carry;
+ bufLen++;
+ }
+ }
+ count -= shiftAmount;
+ }
+ return bufLen;
+ }
+
+ // Overloading of unary >> operators
+ public static BigInteger operator >> (BigInteger bi1, int shiftVal)
+ {
+ BigInteger result = new BigInteger(bi1);
+ result.dataLength = shiftRight(result.data, shiftVal);
+
+ if((bi1.data[maxLength-1] & 0x80000000) != 0) { // negative
+ for(int i = maxLength - 1; i >= result.dataLength; i--)
+ result.data[i] = 0xFFFFFFFF;
+
+ uint mask = 0x80000000;
+ for(int i = 0; i < 32; i++) {
+ if((result.data[result.dataLength-1] & mask) != 0)
+ break;
+
+ result.data[result.dataLength-1] |= mask;
+ mask >>= 1;
+ }
+ result.dataLength = maxLength;
+ }
+
+ return result;
+ }
+
+ private static int shiftRight (uint[] buffer, int shiftVal)
+ {
+ int shiftAmount = 32;
+ int invShift = 0;
+ int bufLen = buffer.Length;
+
+ while(bufLen > 1 && buffer[bufLen-1] == 0)
+ bufLen--;
+
+ //Console.WriteLine("bufLen = " + bufLen + " buffer.Length = " + buffer.Length);
+
+ for(int count = shiftVal; count > 0;) {
+ if(count < shiftAmount) {
+ shiftAmount = count;
+ invShift = 32 - shiftAmount;
+ }
+
+ //Console.WriteLine("shiftAmount = {0}", shiftAmount);
+
+ ulong carry = 0;
+ for(int i = bufLen - 1; i >= 0; i--) {
+ ulong val = ((ulong)buffer[i]) >> shiftAmount;
+ val |= carry;
+
+ carry = ((ulong)buffer[i]) << invShift;
+ buffer[i] = (uint)(val);
+ }
+
+ count -= shiftAmount;
+ }
+
+ while(bufLen > 1 && buffer[bufLen-1] == 0)
+ bufLen--;
+
+ return bufLen;
+ }
+
+
+ // Overloading of the NOT operator (1's complement)
+ public static BigInteger operator ~ (BigInteger bi1)
+ {
+ BigInteger result = new BigInteger (bi1);
+
+ for(int i = 0; i < maxLength; i++)
+ result.data[i] = (uint)(~(bi1.data[i]));
+
+ result.dataLength = maxLength;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ return result;
+ }
+
+ // Overloading of the NEGATE operator (2's complement)
+ public static BigInteger operator - (BigInteger bi1)
+ {
+ // handle neg of zero separately since it'll cause an overflow
+ // if we proceed.
+ if(bi1.dataLength == 1 && bi1.data[0] == 0)
+ return (new BigInteger ());
+
+ BigInteger result = new BigInteger (bi1);
+
+ // 1's complement
+ for(int i = 0; i < maxLength; i++)
+ result.data[i] = (uint)(~(bi1.data[i]));
+
+ // add one to result of 1's complement
+ long val, carry = 1;
+ int index = 0;
+
+ while(carry != 0 && index < maxLength) {
+ val = (long)(result.data[index]);
+ val++;
+
+ result.data[index] = (uint)(val & 0xFFFFFFFF);
+ carry = val >> 32;
+
+ index++;
+ }
+
+ if((bi1.data[maxLength-1] & 0x80000000) == (result.data[maxLength-1] & 0x80000000))
+ throw (new ArithmeticException("Overflow in negation.\n"));
+
+ result.dataLength = maxLength;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+ return result;
+ }
+
+
+ // Overloading of equality operator
+ public static bool operator == (BigInteger bi1, BigInteger bi2)
+ {
+ return bi1.Equals (bi2);
+ }
+
+ public static bool operator !=( BigInteger bi1, BigInteger bi2)
+ {
+ return !(bi1.Equals (bi2));
+ }
+
+ public override bool Equals (object o)
+ {
+ BigInteger bi = (BigInteger) o;
+
+ if(this.dataLength != bi.dataLength)
+ return false;
+
+ for(int i = 0; i < this.dataLength; i++) {
+ if(this.data [i] != bi.data [i])
+ return false;
+ }
+ return true;
+ }
+
+ public override int GetHashCode ()
+ {
+ return this.ToString ().GetHashCode ();
+ }
+
+ // Overloading of inequality operator
+ public static bool operator > (BigInteger bi1, BigInteger bi2)
+ {
+ int pos = maxLength - 1;
+
+ // bi1 is negative, bi2 is positive
+ if((bi1.data[pos] & 0x80000000) != 0 && (bi2.data[pos] & 0x80000000) == 0)
+ return false;
+
+ // bi1 is positive, bi2 is negative
+ else if((bi1.data[pos] & 0x80000000) == 0 && (bi2.data[pos] & 0x80000000) != 0)
+ return true;
+
+ // same sign
+ int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+ for(pos = len - 1; pos >= 0 && bi1.data[pos] == bi2.data[pos]; pos--);
+
+ if(pos >= 0) {
+ if(bi1.data[pos] > bi2.data[pos])
+ return true;
+ return false;
+ }
+ return false;
+ }
+
+ public static bool operator < (BigInteger bi1, BigInteger bi2)
+ {
+ int pos = maxLength - 1;
+
+ // bi1 is negative, bi2 is positive
+ if((bi1.data[pos] & 0x80000000) != 0 && (bi2.data[pos] & 0x80000000) == 0)
+ return true;
+
+ // bi1 is positive, bi2 is negative
+ else if((bi1.data[pos] & 0x80000000) == 0 && (bi2.data[pos] & 0x80000000) != 0)
+ return false;
+
+ // same sign
+ int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+ for(pos = len - 1; pos >= 0 && bi1.data[pos] == bi2.data[pos]; pos--);
+
+ if(pos >= 0) {
+ if(bi1.data[pos] < bi2.data[pos])
+ return true;
+ return false;
+ }
+ return false;
+ }
+
+ public static bool operator >= (BigInteger bi1, BigInteger bi2)
+ {
+ return (bi1 == bi2 || bi1 > bi2);
+ }
+
+ public static bool operator <= (BigInteger bi1, BigInteger bi2)
+ {
+ return (bi1 == bi2 || bi1 < bi2);
+ }
+
+ // Private function that supports the division of two numbers with
+ // a divisor that has more than 1 digit.
+ // Algorithm taken from [1]
+ private static void multiByteDivide (BigInteger bi1, BigInteger bi2,
+ BigInteger outQuotient, BigInteger outRemainder)
+ {
+ uint[] result = new uint[maxLength];
+
+ int remainderLen = bi1.dataLength + 1;
+ uint[] remainder = new uint[remainderLen];
+
+ uint mask = 0x80000000;
+ uint val = bi2.data[bi2.dataLength - 1];
+ int shift = 0, resultPos = 0;
+
+ while(mask != 0 && (val & mask) == 0) {
+ shift++; mask >>= 1;
+ }
+
+ //Console.WriteLine("shift = {0}", shift);
+ //Console.WriteLine("Before bi1 Len = {0}, bi2 Len = {1}", bi1.dataLength, bi2.dataLength);
+
+ for (int i = 0; i < bi1.dataLength; i++)
+ remainder[i] = bi1.data[i];
+ shiftLeft (remainder, shift);
+ bi2 = bi2 << shift;
+
+ /*
+ Console.WriteLine("bi1 Len = {0}, bi2 Len = {1}", bi1.dataLength, bi2.dataLength);
+ Console.WriteLine("dividend = " + bi1 + "\ndivisor = " + bi2);
+ for(int q = remainderLen - 1; q >= 0; q--)
+ Console.Write("{0:x2}", remainder[q]);
+ Console.WriteLine();
+ */
+
+ int j = remainderLen - bi2.dataLength;
+ int pos = remainderLen - 1;
+
+ ulong firstDivisorByte = bi2.data[bi2.dataLength-1];
+ ulong secondDivisorByte = bi2.data[bi2.dataLength-2];
+
+ int divisorLen = bi2.dataLength + 1;
+ uint[] dividendPart = new uint[divisorLen];
+
+ while(j > 0) {
+ ulong dividend = ((ulong)remainder[pos] << 32) + (ulong)remainder[pos-1];
+ //Console.WriteLine("dividend = {0}", dividend);
+
+ ulong q_hat = dividend / firstDivisorByte;
+ ulong r_hat = dividend % firstDivisorByte;
+
+ //Console.WriteLine("q_hat = {0:X}, r_hat = {1:X}", q_hat, r_hat);
+
+ bool done = false;
+ while(!done) {
+ done = true;
+
+ if(q_hat == 0x100000000 ||
+ (q_hat * secondDivisorByte) > ((r_hat << 32) + remainder[pos-2])) {
+ q_hat--;
+ r_hat += firstDivisorByte;
+
+ if(r_hat < 0x100000000)
+ done = false;
+ }
+ }
+
+ for (int h = 0; h < divisorLen; h++)
+ dividendPart[h] = remainder[pos-h];
+
+ BigInteger kk = new BigInteger (dividendPart);
+ BigInteger ss = bi2 * (long)q_hat;
+
+ //Console.WriteLine("ss before = " + ss);
+ while(ss > kk) {
+ q_hat--;
+ ss -= bi2;
+ //Console.WriteLine(ss);
+ }
+ BigInteger yy = kk - ss;
+
+ //Console.WriteLine("ss = " + ss);
+ //Console.WriteLine("kk = " + kk);
+ //Console.WriteLine("yy = " + yy);
+
+ for(int h = 0; h < divisorLen; h++)
+ remainder[pos-h] = yy.data[bi2.dataLength-h];
+
+ /*
+ Console.WriteLine("dividend = ");
+ for(int q = remainderLen - 1; q >= 0; q--)
+ Console.Write("{0:x2}", remainder[q]);
+ Console.WriteLine("\n************ q_hat = {0:X}\n", q_hat);
+ */
+
+ result[resultPos++] = (uint)q_hat;
+
+ pos--;
+ j--;
+ }
+
+ outQuotient.dataLength = resultPos;
+ int y = 0;
+ for(int x = outQuotient.dataLength - 1; x >= 0; x--, y++)
+ outQuotient.data[y] = result[x];
+ for(; y < maxLength; y++)
+ outQuotient.data[y] = 0;
+
+ while(outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength-1] == 0)
+ outQuotient.dataLength--;
+
+ if(outQuotient.dataLength == 0)
+ outQuotient.dataLength = 1;
+
+ outRemainder.dataLength = shiftRight(remainder, shift);
+
+ for(y = 0; y < outRemainder.dataLength; y++)
+ outRemainder.data[y] = remainder[y];
+ for(; y < maxLength; y++)
+ outRemainder.data[y] = 0;
+ }
+
+ // Private function that supports the division of two numbers with
+ // a divisor that has only 1 digit.
+ private static void singleByteDivide (BigInteger bi1, BigInteger bi2,
+ BigInteger outQuotient, BigInteger outRemainder)
+ {
+ uint[] result = new uint[maxLength];
+ int resultPos = 0;
+
+ // copy dividend to reminder
+ for(int i = 0; i < maxLength; i++)
+ outRemainder.data[i] = bi1.data[i];
+ outRemainder.dataLength = bi1.dataLength;
+
+ while(outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength-1] == 0)
+ outRemainder.dataLength--;
+
+ ulong divisor = (ulong)bi2.data[0];
+ int pos = outRemainder.dataLength - 1;
+ ulong dividend = (ulong)outRemainder.data[pos];
+
+ //Console.WriteLine("divisor = " + divisor + " dividend = " + dividend);
+ //Console.WriteLine("divisor = " + bi2 + "\ndividend = " + bi1);
+
+ if(dividend >= divisor) {
+ ulong quotient = dividend / divisor;
+ result[resultPos++] = (uint)quotient;
+
+ outRemainder.data[pos] = (uint)(dividend % divisor);
+ }
+ pos--;
+
+ while(pos >= 0) {
+ //Console.WriteLine(pos);
+
+ dividend = ((ulong)outRemainder.data[pos+1] << 32) + (ulong)outRemainder.data[pos];
+ ulong quotient = dividend / divisor;
+ result[resultPos++] = (uint)quotient;
+
+ outRemainder.data[pos+1] = 0;
+ outRemainder.data[pos--] = (uint)(dividend % divisor);
+ //Console.WriteLine(">>>> " + bi1);
+ }
+
+ outQuotient.dataLength = resultPos;
+ int j = 0;
+ for(int i = outQuotient.dataLength - 1; i >= 0; i--, j++)
+ outQuotient.data[j] = result[i];
+ for(; j < maxLength; j++)
+ outQuotient.data[j] = 0;
+
+ while(outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength-1] == 0)
+ outQuotient.dataLength--;
+
+ if(outQuotient.dataLength == 0)
+ outQuotient.dataLength = 1;
+
+ while(outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength-1] == 0)
+ outRemainder.dataLength--;
+ }
+
+ // Overloading of division operator
+ public static BigInteger operator / (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger quotient = new BigInteger();
+ BigInteger remainder = new BigInteger();
+
+ int lastPos = maxLength-1;
+ bool divisorNeg = false, dividendNeg = false;
+
+ if((bi1.data[lastPos] & 0x80000000) != 0) { // bi1 negative
+ bi1 = -bi1;
+ dividendNeg = true;
+ }
+ if((bi2.data[lastPos] & 0x80000000) != 0) { // bi2 negative
+ bi2 = -bi2;
+ divisorNeg = true;
+ }
+
+ if(bi1 < bi2) {
+ return quotient;
+ }
+
+ else {
+ if(bi2.dataLength == 1)
+ singleByteDivide(bi1, bi2, quotient, remainder);
+ else
+ multiByteDivide(bi1, bi2, quotient, remainder);
+
+ if(dividendNeg != divisorNeg)
+ return -quotient;
+
+ return quotient;
+ }
+ }
+
+ // Overloading of modulus operator
+ public static BigInteger operator % (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger quotient = new BigInteger();
+ BigInteger remainder = new BigInteger(bi1);
+
+ int lastPos = maxLength-1;
+ bool dividendNeg = false;
+
+ if((bi1.data[lastPos] & 0x80000000) != 0) { // bi1 negative
+ bi1 = -bi1;
+ dividendNeg = true;
+ }
+ if((bi2.data[lastPos] & 0x80000000) != 0) // bi2 negative
+ bi2 = -bi2;
+
+ if(bi1 < bi2) {
+ return remainder;
+ }
+
+ else {
+ if(bi2.dataLength == 1)
+ singleByteDivide(bi1, bi2, quotient, remainder);
+ else
+ multiByteDivide(bi1, bi2, quotient, remainder);
+
+ if(dividendNeg)
+ return -remainder;
+
+ return remainder;
+ }
+ }
+
+ // Overloading of bitwise AND operator
+ public static BigInteger operator & (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger result = new BigInteger();
+
+ int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+
+ for(int i = 0; i < len; i++) {
+ uint sum = (uint)(bi1.data[i] & bi2.data[i]);
+ result.data[i] = sum;
+ }
+
+ result.dataLength = maxLength;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ return result;
+ }
+
+ // Overloading of bitwise OR operator
+ public static BigInteger operator | (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger result = new BigInteger();
+
+ int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+
+ for(int i = 0; i < len; i++) {
+ uint sum = (uint)(bi1.data[i] | bi2.data[i]);
+ result.data[i] = sum;
+ }
+
+ result.dataLength = maxLength;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ return result;
+ }
+
+ // Overloading of bitwise XOR operator
+ public static BigInteger operator ^ (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger result = new BigInteger();
+
+ int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+
+ for(int i = 0; i < len; i++) {
+ uint sum = (uint)(bi1.data[i] ^ bi2.data[i]);
+ result.data[i] = sum;
+ }
+
+ result.dataLength = maxLength;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ return result;
+ }
+
+ // Returns max(this, bi)
+ public BigInteger max (BigInteger bi)
+ {
+ if(this > bi)
+ return (new BigInteger(this));
+ else
+ return (new BigInteger(bi));
+ }
+
+ // Returns min(this, bi)
+ public BigInteger min (BigInteger bi)
+ {
+ if (this < bi)
+ return (new BigInteger (this));
+ else
+ return (new BigInteger (bi));
+ }
+
+ // Returns the absolute value
+ public BigInteger abs ()
+ {
+ if((this.data[maxLength - 1] & 0x80000000) != 0)
+ return (-this);
+ else
+ return (new BigInteger (this));
+ }
+
+ // Returns a string representing the BigInteger in base 10.
+ public override string ToString ()
+ {
+ return ToString (10);
+ }
+
+ // Returns a string representing the BigInteger in sign-and-magnitude
+ // format in the specified radix.
+ //
+ // Example
+ // -------
+ // If the value of BigInteger is -255 in base 10, then
+ // ToString(16) returns "-FF"
+ public string ToString (int radix)
+ {
+ if(radix < 2 || radix > 36)
+ throw (new ArgumentException("Radix must be >= 2 and <= 36"));
+
+ string charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ string result = "";
+
+ BigInteger a = this;
+
+ bool negative = false;
+ if((a.data[maxLength-1] & 0x80000000) != 0) {
+ negative = true;
+ try {
+ a = -a;
+ }
+ catch(Exception) {}
+ }
+
+ BigInteger quotient = new BigInteger();
+ BigInteger remainder = new BigInteger();
+ BigInteger biRadix = new BigInteger(radix);
+
+ if(a.dataLength == 1 && a.data[0] == 0)
+ result = "0";
+ else {
+ while(a.dataLength > 1 || (a.dataLength == 1 && a.data[0] != 0)) {
+ singleByteDivide(a, biRadix, quotient, remainder);
+
+ if(remainder.data[0] < 10)
+ result = remainder.data[0] + result;
+ else
+ result = charSet[(int)remainder.data[0] - 10] + result;
+
+ a = quotient;
+ }
+ if(negative)
+ result = "-" + result;
+ }
+
+ return result;
+ }
+
+
+ // Returns a hex string showing the contains of the BigInteger
+ //
+ // Examples
+ // -------
+ // 1) If the value of BigInteger is 255 in base 10, then
+ // ToHexString() returns "FF"
+ //
+ // 2) If the value of BigInteger is -255 in base 10, then
+ // ToHexString() returns ".....FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01",
+ // which is the 2's complement representation of -255.
+ public string ToHexString ()
+ {
+ string result = data[dataLength - 1].ToString("X");
+
+ for(int i = dataLength - 2; i >= 0; i--) {
+ result += data[i].ToString("X8");
+ }
+
+ return result;
+ }
+
+ // Modulo Exponentiation
+ public BigInteger modPow(BigInteger exp, BigInteger n)
+ {
+ if((exp.data[maxLength-1] & 0x80000000) != 0)
+ throw (new ArithmeticException("Positive exponents only."));
+
+ BigInteger resultNum = 1;
+ BigInteger tempNum;
+ bool thisNegative = false;
+
+ if((this.data[maxLength-1] & 0x80000000) != 0) { // negative this
+ tempNum = -this % n;
+ thisNegative = true;
+ }
+ else
+ tempNum = this % n; // ensures (tempNum * tempNum) < b^(2k)
+
+ if((n.data[maxLength-1] & 0x80000000) != 0) // negative n
+ n = -n;
+
+ // calculate constant = b^(2k) / m
+ BigInteger constant = new BigInteger ();
+
+ int i = n.dataLength << 1;
+ constant.data[i] = 0x00000001;
+ constant.dataLength = i + 1;
+
+ constant = constant / n;
+ int totalBits = exp.bitCount ();
+ int count = 0;
+
+ // perform squaring and multiply exponentiation
+ for(int pos = 0; pos < exp.dataLength; pos++) {
+ uint mask = 0x01;
+ //Console.WriteLine("pos = " + pos);
+
+ for(int index = 0; index < 32; index++) {
+ if((exp.data[pos] & mask) != 0)
+ resultNum = BarrettReduction(resultNum * tempNum, n, constant);
+
+ mask <<= 1;
+
+ tempNum = BarrettReduction(tempNum * tempNum, n, constant);
+
+
+ if(tempNum.dataLength == 1 && tempNum.data[0] == 1) {
+ if(thisNegative && (exp.data[0] & 0x1) != 0) //odd exp
+ return -resultNum;
+ return resultNum;
+ }
+ count++;
+ if(count == totalBits)
+ break;
+ }
+ }
+
+ if(thisNegative && (exp.data[0] & 0x1) != 0) //odd exp
+ return -resultNum;
+
+ return resultNum;
+ }
+
+ // Fast calculation of modular reduction using Barrett's reduction.
+ // Requires x < b^(2k), where b is the base. In this case, base is
+ // 2^32 (uint).
+ // Reference [4]
+ private BigInteger BarrettReduction(BigInteger x, BigInteger n, BigInteger constant)
+ {
+ int k = n.dataLength,
+ kPlusOne = k+1,
+ kMinusOne = k-1;
+
+ BigInteger q1 = new BigInteger ();
+
+ // q1 = x / b^(k-1)
+ for(int i = kMinusOne, j = 0; i < x.dataLength; i++, j++)
+ q1.data[j] = x.data[i];
+ q1.dataLength = x.dataLength - kMinusOne;
+ if(q1.dataLength <= 0)
+ q1.dataLength = 1;
+
+
+ BigInteger q2 = q1 * constant;
+ BigInteger q3 = new BigInteger();
+
+ // q3 = q2 / b^(k+1)
+ for(int i = kPlusOne, j = 0; i < q2.dataLength; i++, j++)
+ q3.data[j] = q2.data[i];
+ q3.dataLength = q2.dataLength - kPlusOne;
+ if(q3.dataLength <= 0)
+ q3.dataLength = 1;
+
+ // r1 = x mod b^(k+1)
+ // i.e. keep the lowest (k+1) words
+ BigInteger r1 = new BigInteger();
+ int lengthToCopy = (x.dataLength > kPlusOne) ? kPlusOne : x.dataLength;
+ for(int i = 0; i < lengthToCopy; i++)
+ r1.data[i] = x.data[i];
+ r1.dataLength = lengthToCopy;
+
+ // r2 = (q3 * n) mod b^(k+1)
+ // partial multiplication of q3 and n
+
+ BigInteger r2 = new BigInteger();
+ for(int i = 0; i < q3.dataLength; i++) {
+ if(q3.data[i] == 0) continue;
+
+ ulong mcarry = 0;
+ int t = i;
+ for(int j = 0; j < n.dataLength && t < kPlusOne; j++, t++) {
+ // t = i + j
+ ulong val = ((ulong)q3.data[i] * (ulong)n.data[j]) +
+ (ulong)r2.data[t] + mcarry;
+
+ r2.data[t] = (uint)(val & 0xFFFFFFFF);
+ mcarry = (val >> 32);
+ }
+
+ if(t < kPlusOne)
+ r2.data[t] = (uint)mcarry;
+ }
+ r2.dataLength = kPlusOne;
+ while(r2.dataLength > 1 && r2.data[r2.dataLength-1] == 0)
+ r2.dataLength--;
+
+ r1 -= r2;
+ if((r1.data[maxLength-1] & 0x80000000) != 0) { // negative
+ BigInteger val = new BigInteger();
+ val.data[kPlusOne] = 0x00000001;
+ val.dataLength = kPlusOne + 1;
+ r1 += val;
+ }
+
+ while(r1 >= n)
+ r1 -= n;
+
+ return r1;
+ }
+
+ // Returns gcd(this, bi)
+ public BigInteger gcd(BigInteger bi)
+ {
+ BigInteger x;
+ BigInteger y;
+
+ if((data[maxLength-1] & 0x80000000) != 0) // negative
+ x = -this;
+ else
+ x = this;
+
+ if((bi.data[maxLength-1] & 0x80000000) != 0) // negative
+ y = -bi;
+ else
+ y = bi;
+
+ BigInteger g = y;
+
+ while(x.dataLength > 1 || (x.dataLength == 1 && x.data[0] != 0)) {
+ g = x;
+ x = y % x;
+ y = g;
+ }
+
+ return g;
+ }
+
+ // Populates "this" with the specified amount of random bits
+ public void genRandomBits (int bits)
+ {
+ genRandomBits (bits, new BigRandom ());
+ }
+
+ public void genRandomBits (int bits, BigRandom rng)
+ {
+ int dwords = bits >> 5;
+ int remBits = bits & 0x1F;
+
+ if (remBits != 0)
+ dwords++;
+
+ if (dwords > maxLength)
+ throw (new ArithmeticException("Number of required bits > maxLength."));
+
+ rng.Get (data);
+ for (int i = dwords; i < maxLength; i++)
+ data[i] = 0;
+
+ if (remBits != 0) {
+ uint mask = (uint)(0x01 << (remBits-1));
+ data[dwords-1] |= mask;
+
+ mask = (uint)(0xFFFFFFFF >> (32 - remBits));
+ data[dwords-1] &= mask;
+ }
+ else
+ data[dwords-1] |= 0x80000000;
+
+ dataLength = dwords;
+
+ if (dataLength == 0)
+ dataLength = 1;
+ }
+
+ // Returns the position of the most significant bit in the BigInteger.
+ // Eg. The result is 0, if the value of BigInteger is 0...0000 0000
+ // The result is 1, if the value of BigInteger is 0...0000 0001
+ // The result is 2, if the value of BigInteger is 0...0000 0010
+ // The result is 2, if the value of BigInteger is 0...0000 0011
+ public int bitCount ()
+ {
+ while(dataLength > 1 && data[dataLength-1] == 0)
+ dataLength--;
+
+ uint value = data[dataLength - 1];
+ uint mask = 0x80000000;
+ int bits = 32;
+
+ while(bits > 0 && (value & mask) == 0) {
+ bits--;
+ mask >>= 1;
+ }
+ bits += ((dataLength - 1) << 5);
+
+ return bits;
+ }
+
+ // Probabilistic prime test based on Fermat's little theorem
+ //
+ // for any a < p (p does not divide a) if
+ // a^(p-1) mod p != 1 then p is not prime.
+ //
+ // Otherwise, p is probably prime (pseudoprime to the chosen base).
+ //
+ // Returns
+ // -------
+ // True if "this" is a pseudoprime to randomly chosen
+ // bases. The number of chosen bases is given by the "confidence"
+ // parameter.
+ //
+ // False if "this" is definitely NOT prime.
+ //
+ // Note - this method is fast but fails for Carmichael numbers except
+ // when the randomly chosen base is a factor of the number.
+ public bool FermatLittleTest (int confidence)
+ {
+ BigInteger thisVal;
+ if((this.data[maxLength-1] & 0x80000000) != 0) // negative
+ thisVal = -this;
+ else
+ thisVal = this;
+
+ if(thisVal.dataLength == 1) {
+ // test small numbers
+ if(thisVal.data[0] == 0 || thisVal.data[0] == 1)
+ return false;
+ else if(thisVal.data[0] == 2 || thisVal.data[0] == 3)
+ return true;
+ }
+
+ if((thisVal.data[0] & 0x1) == 0) // even numbers
+ return false;
+
+ int bits = thisVal.bitCount();
+ BigInteger a = new BigInteger();
+ BigInteger p_sub1 = thisVal - (new BigInteger(1));
+
+ for(int round = 0; round < confidence; round++) {
+ bool done = false;
+
+ while(!done) { // generate a < n
+ int testBits = 0;
+
+ // make sure "a" has at least 2 bits
+ while(testBits < 2)
+ testBits = rng.GetInt (bits);
+
+ a.genRandomBits (testBits);
+
+ int byteLen = a.dataLength;
+
+ // make sure "a" is not 0
+ if(byteLen > 1 || (byteLen == 1 && a.data[0] != 1))
+ done = true;
+ }
+
+ // check whether a factor exists (fix for version 1.03)
+ BigInteger gcdTest = a.gcd(thisVal);
+ if(gcdTest.dataLength == 1 && gcdTest.data[0] != 1)
+ return false;
+
+ // calculate a^(p-1) mod p
+ BigInteger expResult = a.modPow(p_sub1, thisVal);
+
+ int resultLen = expResult.dataLength;
+
+ // is NOT prime is a^(p-1) mod p != 1
+
+ if(resultLen > 1 || (resultLen == 1 && expResult.data[0] != 1)) {
+ //Console.WriteLine("a = " + a.ToString());
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // Probabilistic prime test based on Rabin-Miller's
+ //
+ // for any p > 0 with p - 1 = 2^s * t
+ //
+ // p is probably prime (strong pseudoprime) if for any a < p,
+ // 1) a^t mod p = 1 or
+ // 2) a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1
+ //
+ // Otherwise, p is composite.
+ //
+ // Returns
+ // -------
+ // True if "this" is a strong pseudoprime to randomly chosen
+ // bases. The number of chosen bases is given by the "confidence"
+ // parameter.
+ //
+ // False if "this" is definitely NOT prime.
+ public bool RabinMillerTest(int confidence)
+ {
+ BigInteger thisVal;
+ if((this.data[maxLength-1] & 0x80000000) != 0) // negative
+ thisVal = -this;
+ else
+ thisVal = this;
+
+ if(thisVal.dataLength == 1) {
+ // test small numbers
+ if(thisVal.data[0] == 0 || thisVal.data[0] == 1)
+ return false;
+ else if(thisVal.data[0] == 2 || thisVal.data[0] == 3)
+ return true;
+ }
+
+ if((thisVal.data[0] & 0x1) == 0) // even numbers
+ return false;
+
+ // calculate values of s and t
+ BigInteger p_sub1 = thisVal - (new BigInteger(1));
+ int s = 0;
+
+ for(int index = 0; index < p_sub1.dataLength; index++) {
+ uint mask = 0x01;
+
+ for(int i = 0; i < 32; i++) {
+ if((p_sub1.data[index] & mask) != 0) {
+ index = p_sub1.dataLength; // to break the outer loop
+ break;
+ }
+ mask <<= 1;
+ s++;
+ }
+ }
+
+ BigInteger t = p_sub1 >> s;
+
+ int bits = thisVal.bitCount();
+ BigInteger a = new BigInteger();
+
+ for(int round = 0; round < confidence; round++) {
+ bool done = false;
+
+ while(!done) { // generate a < n
+ int testBits = 0;
+
+ // make sure "a" has at least 2 bits
+ while(testBits < 2)
+ testBits = rng.GetInt (bits);
+
+ a.genRandomBits (testBits);
+
+ int byteLen = a.dataLength;
+
+ // make sure "a" is not 0
+ if(byteLen > 1 || (byteLen == 1 && a.data[0] != 1))
+ done = true;
+ }
+
+ // check whether a factor exists (fix for version 1.03)
+ BigInteger gcdTest = a.gcd(thisVal);
+ if(gcdTest.dataLength == 1 && gcdTest.data[0] != 1)
+ return false;
+
+ BigInteger b = a.modPow(t, thisVal);
+
+ /*
+ Console.WriteLine("a = " + a.ToString(10));
+ Console.WriteLine("b = " + b.ToString(10));
+ Console.WriteLine("t = " + t.ToString(10));
+ Console.WriteLine("s = " + s);
+ */
+
+ bool result = false;
+
+ if(b.dataLength == 1 && b.data[0] == 1) // a^t mod p = 1
+ result = true;
+
+ for(int j = 0; result == false && j < s; j++) {
+ if(b == p_sub1) { // a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1
+ result = true;
+ break;
+ }
+
+ b = (b * b) % thisVal;
+ }
+
+ if(result == false)
+ return false;
+ }
+ return true;
+ }
+
+ // Probabilistic prime test based on Solovay-Strassen (Euler Criterion)
+ //
+ // p is probably prime if for any a < p (a is not multiple of p),
+ // a^((p-1)/2) mod p = J(a, p)
+ //
+ // where J is the Jacobi symbol.
+ //
+ // Otherwise, p is composite.
+ //
+ // Returns
+ // -------
+ // True if "this" is a Euler pseudoprime to randomly chosen
+ // bases. The number of chosen bases is given by the "confidence"
+ // parameter.
+ //
+ // False if "this" is definitely NOT prime.
+ public bool SolovayStrassenTest(int confidence)
+ {
+ BigInteger thisVal;
+ if((this.data[maxLength-1] & 0x80000000) != 0) // negative
+ thisVal = -this;
+ else
+ thisVal = this;
+
+ if(thisVal.dataLength == 1) {
+ // test small numbers
+ if(thisVal.data[0] == 0 || thisVal.data[0] == 1)
+ return false;
+ else if(thisVal.data[0] == 2 || thisVal.data[0] == 3)
+ return true;
+ }
+
+ if((thisVal.data[0] & 0x1) == 0) // even numbers
+ return false;
+
+ int bits = thisVal.bitCount();
+ BigInteger a = new BigInteger();
+ BigInteger p_sub1 = thisVal - 1;
+ BigInteger p_sub1_shift = p_sub1 >> 1;
+
+ for(int round = 0; round < confidence; round++) {
+ bool done = false;
+
+ while(!done) { // generate a < n
+ int testBits = 0;
+
+ // make sure "a" has at least 2 bits
+ while(testBits < 2)
+ testBits = rng.GetInt (bits);
+
+ a.genRandomBits (testBits);
+
+ int byteLen = a.dataLength;
+
+ // make sure "a" is not 0
+ if(byteLen > 1 || (byteLen == 1 && a.data[0] != 1))
+ done = true;
+ }
+
+ // check whether a factor exists (fix for version 1.03)
+ BigInteger gcdTest = a.gcd(thisVal);
+ if(gcdTest.dataLength == 1 && gcdTest.data[0] != 1)
+ return false;
+
+ // calculate a^((p-1)/2) mod p
+
+ BigInteger expResult = a.modPow(p_sub1_shift, thisVal);
+ if(expResult == p_sub1)
+ expResult = -1;
+
+ // calculate Jacobi symbol
+ BigInteger jacob = Jacobi(a, thisVal);
+
+ //Console.WriteLine("a = " + a.ToString(10) + " b = " + thisVal.ToString(10));
+ //Console.WriteLine("expResult = " + expResult.ToString(10) + " Jacob = " + jacob.ToString(10));
+
+ // if they are different then it is not prime
+ if(expResult != jacob)
+ return false;
+ }
+
+ return true;
+ }
+
+ // Implementation of the Lucas Strong Pseudo Prime test.
+ //
+ // Let n be an odd number with gcd(n,D) = 1, and n - J(D, n) = 2^s * d
+ // with d odd and s >= 0.
+ //
+ // If Ud mod n = 0 or V2^r*d mod n = 0 for some 0 <= r < s, then n
+ // is a strong Lucas pseudoprime with parameters (P, Q). We select
+ // P and Q based on Selfridge.
+ //
+ // Returns True if number is a strong Lucus pseudo prime.
+ // Otherwise, returns False indicating that number is composite.
+ public bool LucasStrongTest()
+ {
+ BigInteger thisVal;
+ if((this.data[maxLength-1] & 0x80000000) != 0) // negative
+ thisVal = -this;
+ else
+ thisVal = this;
+
+ if(thisVal.dataLength == 1) {
+ // test small numbers
+ if(thisVal.data[0] == 0 || thisVal.data[0] == 1)
+ return false;
+ else if(thisVal.data[0] == 2 || thisVal.data[0] == 3)
+ return true;
+ }
+
+ if((thisVal.data[0] & 0x1) == 0) // even numbers
+ return false;
+
+ return LucasStrongTestHelper(thisVal);
+ }
+
+ private bool LucasStrongTestHelper(BigInteger thisVal)
+ {
+ // Do the test (selects D based on Selfridge)
+ // Let D be the first element of the sequence
+ // 5, -7, 9, -11, 13, ... for which J(D,n) = -1
+ // Let P = 1, Q = (1-D) / 4
+
+ long D = 5, sign = -1, dCount = 0;
+ bool done = false;
+
+ while(!done) {
+ int Jresult = BigInteger.Jacobi(D, thisVal);
+
+ if(Jresult == -1)
+ done = true; // J(D, this) = 1
+ else {
+ if(Jresult == 0 && System.Math.Abs(D) < thisVal) // divisor found
+ return false;
+
+ if(dCount == 20) {
+ // check for square
+ BigInteger root = thisVal.sqrt();
+ if(root * root == thisVal)
+ return false;
+ }
+
+ //Console.WriteLine(D);
+ D = (System.Math.Abs(D) + 2) * sign;
+ sign = -sign;
+ }
+ dCount++;
+ }
+
+ long Q = (1 - D) >> 2;
+
+ /*
+ Console.WriteLine("D = " + D);
+ Console.WriteLine("Q = " + Q);
+ Console.WriteLine("(n,D) = " + thisVal.gcd(D));
+ Console.WriteLine("(n,Q) = " + thisVal.gcd(Q));
+ Console.WriteLine("J(D|n) = " + BigInteger.Jacobi(D, thisVal));
+ */
+
+ BigInteger p_add1 = thisVal + 1;
+ int s = 0;
+
+ for(int index = 0; index < p_add1.dataLength; index++) {
+ uint mask = 0x01;
+
+ for(int i = 0; i < 32; i++) {
+ if((p_add1.data[index] & mask) != 0) {
+ index = p_add1.dataLength; // to break the outer loop
+ break;
+ }
+ mask <<= 1;
+ s++;
+ }
+ }
+
+ BigInteger t = p_add1 >> s;
+
+ // calculate constant = b^(2k) / m
+ // for Barrett Reduction
+ BigInteger constant = new BigInteger();
+
+ int nLen = thisVal.dataLength << 1;
+ constant.data[nLen] = 0x00000001;
+ constant.dataLength = nLen + 1;
+
+ constant = constant / thisVal;
+
+ BigInteger[] lucas = LucasSequenceHelper(1, Q, t, thisVal, constant, 0);
+ bool isPrime = false;
+
+ if((lucas[0].dataLength == 1 && lucas[0].data[0] == 0) ||
+ (lucas[1].dataLength == 1 && lucas[1].data[0] == 0)) {
+ // u(t) = 0 or V(t) = 0
+ isPrime = true;
+ }
+
+ for(int i = 1; i < s; i++) {
+ if(!isPrime) {
+ // doubling of index
+ lucas[1] = thisVal.BarrettReduction(lucas[1] * lucas[1], thisVal, constant);
+ lucas[1] = (lucas[1] - (lucas[2] << 1)) % thisVal;
+
+ //lucas[1] = ((lucas[1] * lucas[1]) - (lucas[2] << 1)) % thisVal;
+
+ if((lucas[1].dataLength == 1 && lucas[1].data[0] == 0))
+ isPrime = true;
+ }
+
+ lucas[2] = thisVal.BarrettReduction(lucas[2] * lucas[2], thisVal, constant); //Q^k
+ }
+
+
+ if(isPrime) { // additional checks for composite numbers
+ // If n is prime and gcd(n, Q) == 1, then
+ // Q^((n+1)/2) = Q * Q^((n-1)/2) is congruent to (Q * J(Q, n)) mod n
+
+ BigInteger g = thisVal.gcd(Q);
+ if(g.dataLength == 1 && g.data[0] == 1) { // gcd(this, Q) == 1
+ if((lucas[2].data[maxLength-1] & 0x80000000) != 0)
+ lucas[2] += thisVal;
+
+ BigInteger temp = (Q * BigInteger.Jacobi(Q, thisVal)) % thisVal;
+ if((temp.data[maxLength-1] & 0x80000000) != 0)
+ temp += thisVal;
+
+ if(lucas[2] != temp)
+ isPrime = false;
+ }
+ }
+
+ return isPrime;
+ }
+
+ // Determines whether a number is probably prime, using the Rabin-Miller's
+ // test. Before applying the test, the number is tested for divisibility
+ // by primes < 2000
+ //
+ // Returns true if number is probably prime.
+ public bool isProbablePrime(int confidence)
+ {
+ BigInteger thisVal;
+ if((this.data[maxLength-1] & 0x80000000) != 0) // negative
+ thisVal = -this;
+ else
+ thisVal = this;
+
+
+ // test for divisibility by primes < 2000
+ for(int p = 0; p < primesBelow2000.Length; p++) {
+ BigInteger divisor = primesBelow2000[p];
+
+ if(divisor >= thisVal)
+ break;
+
+ BigInteger resultNum = thisVal % divisor;
+ if(resultNum.IntValue() == 0) {
+ /*
+ Console.WriteLine("Not prime! Divisible by {0}\n",
+ primesBelow2000[p]);
+ */
+ return false;
+ }
+ }
+
+ if(thisVal.RabinMillerTest(confidence))
+ return true;
+ else {
+ //Console.WriteLine("Not prime! Failed primality test\n");
+ return false;
+ }
+ }
+
+ // Determines whether this BigInteger is probably prime using a
+ // combination of base 2 strong pseudoprime test and Lucas strong
+ // pseudoprime test.
+ //
+ // The sequence of the primality test is as follows,
+ //
+ // 1) Trial divisions are carried out using prime numbers below 2000.
+ // if any of the primes divides this BigInteger, then it is not prime.
+ //
+ // 2) Perform base 2 strong pseudoprime test. If this BigInteger is a
+ // base 2 strong pseudoprime, proceed on to the next step.
+ //
+ // 3) Perform strong Lucas pseudoprime test.
+ //
+ // Returns True if this BigInteger is both a base 2 strong pseudoprime
+ // and a strong Lucas pseudoprime.
+ //
+ // For a detailed discussion of this primality test, see [6].
+ public bool isProbablePrime()
+ {
+ BigInteger thisVal;
+ if((this.data[maxLength-1] & 0x80000000) != 0) // negative
+ thisVal = -this;
+ else
+ thisVal = this;
+
+ if(thisVal.dataLength == 1) {
+ // test small numbers
+ if(thisVal.data[0] == 0 || thisVal.data[0] == 1)
+ return false;
+ else if(thisVal.data[0] == 2 || thisVal.data[0] == 3)
+ return true;
+ }
+
+ if((thisVal.data[0] & 0x1) == 0) // even numbers
+ return false;
+
+ // test for divisibility by primes < 2000
+ for(int p = 0; p < primesBelow2000.Length; p++) {
+ BigInteger divisor = primesBelow2000[p];
+
+ if(divisor >= thisVal)
+ break;
+
+ BigInteger resultNum = thisVal % divisor;
+ if(resultNum.IntValue() == 0) {
+ //Console.WriteLine("Not prime! Divisible by {0}\n",
+ // primesBelow2000[p]);
+
+ return false;
+ }
+ }
+
+ // Perform BASE 2 Rabin-Miller Test
+
+ // calculate values of s and t
+ BigInteger p_sub1 = thisVal - (new BigInteger(1));
+ int s = 0;
+
+ for(int index = 0; index < p_sub1.dataLength; index++) {
+ uint mask = 0x01;
+
+ for(int i = 0; i < 32; i++) {
+ if((p_sub1.data[index] & mask) != 0) {
+ index = p_sub1.dataLength; // to break the outer loop
+ break;
+ }
+ mask <<= 1;
+ s++;
+ }
+ }
+
+ BigInteger t = p_sub1 >> s;
+
+ int bits = thisVal.bitCount();
+ BigInteger a = 2;
+
+ // b = a^t mod p
+ BigInteger b = a.modPow(t, thisVal);
+ bool result = false;
+
+ if(b.dataLength == 1 && b.data[0] == 1) // a^t mod p = 1
+ result = true;
+
+ for(int j = 0; result == false && j < s; j++) {
+ if(b == p_sub1) { // a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1
+ result = true;
+ break;
+ }
+
+ b = (b * b) % thisVal;
+ }
+
+ // if number is strong pseudoprime to base 2, then do a strong lucas test
+ if(result)
+ result = LucasStrongTestHelper(thisVal);
+
+ return result;
+ }
+
+ // Returns the lowest 4 bytes of the BigInteger as an int.
+ public int IntValue ()
+ {
+ return (int)data[0];
+ }
+
+ // Returns the lowest 8 bytes of the BigInteger as a long.
+ public long LongValue ()
+ {
+ long val = 0;
+
+ val = (long)data[0];
+ try {
+ // exception if maxLength = 1
+ val |= (long)data[1] << 32;
+ }
+ catch(Exception) {
+ if((data[0] & 0x80000000) != 0) // negative
+ val = (int)data[0];
+ }
+
+ return val;
+ }
+
+ // Computes the Jacobi Symbol for a and b.
+ // Algorithm adapted from [3] and [4] with some optimizations
+ public static int Jacobi (BigInteger a, BigInteger b)
+ {
+ // Jacobi defined only for odd integers
+ if((b.data[0] & 0x1) == 0)
+ throw (new ArgumentException("Jacobi defined only for odd integers."));
+
+ if(a >= b) a %= b;
+ if(a.dataLength == 1 && a.data[0] == 0) return 0; // a == 0
+ if(a.dataLength == 1 && a.data[0] == 1) return 1; // a == 1
+
+ if(a < 0) {
+ if( (((b-1).data[0]) & 0x2) == 0) //if( (((b-1) >> 1).data[0] & 0x1) == 0)
+ return Jacobi(-a, b);
+ else
+ return -Jacobi(-a, b);
+ }
+
+ int e = 0;
+ for(int index = 0; index < a.dataLength; index++) {
+ uint mask = 0x01;
+
+ for(int i = 0; i < 32; i++) {
+ if((a.data[index] & mask) != 0) {
+ index = a.dataLength; // to break the outer loop
+ break;
+ }
+ mask <<= 1;
+ e++;
+ }
+ }
+
+ BigInteger a1 = a >> e;
+
+ int s = 1;
+ if((e & 0x1) != 0 && ((b.data[0] & 0x7) == 3 || (b.data[0] & 0x7) == 5))
+ s = -1;
+
+ if((b.data[0] & 0x3) == 3 && (a1.data[0] & 0x3) == 3)
+ s = -s;
+
+ if(a1.dataLength == 1 && a1.data[0] == 1)
+ return s;
+ else
+ return (s * Jacobi(b % a1, a1));
+ }
+
+ // Generates a positive BigInteger that is probably prime.
+ public static BigInteger genPseudoPrime (int bits, int confidence)
+ {
+ BigInteger result = new BigInteger ();
+ bool done = false;
+
+ while (!done) {
+ result.genRandomBits (bits);
+ result.data[0] |= 0x01; // make it odd
+ // prime test
+ done = result.isProbablePrime(confidence);
+ }
+ return result;
+ }
+
+ // Generates a random number with the specified number of bits such
+ // that gcd(number, this) = 1
+ public BigInteger genCoPrime (int bits)
+ {
+ bool done = false;
+ BigInteger result = new BigInteger ();
+
+ while(!done) {
+ result.genRandomBits (bits);
+ //Console.WriteLine(result.ToString(16));
+
+ // gcd test
+ BigInteger g = result.gcd(this);
+ if (g.dataLength == 1 && g.data[0] == 1)
+ done = true;
+ }
+
+ return result;
+ }
+
+ // Returns the modulo inverse of this. Throws ArithmeticException if
+ // the inverse does not exist. (i.e. gcd(this, modulus) != 1)
+ public BigInteger modInverse (BigInteger modulus)
+ {
+ BigInteger[] p = { 0, 1 };
+ BigInteger[] q = new BigInteger[2]; // quotients
+ BigInteger[] r = { 0, 0 }; // remainders
+
+ int step = 0;
+
+ BigInteger a = modulus;
+ BigInteger b = this;
+
+ while(b.dataLength > 1 || (b.dataLength == 1 && b.data[0] != 0)) {
+ BigInteger quotient = new BigInteger();
+ BigInteger remainder = new BigInteger();
+
+ if(step > 1) {
+ BigInteger pval = (p[0] - (p[1] * q[0])) % modulus;
+ p[0] = p[1];
+ p[1] = pval;
+ }
+
+ if(b.dataLength == 1)
+ singleByteDivide(a, b, quotient, remainder);
+ else
+ multiByteDivide(a, b, quotient, remainder);
+
+ /*
+ Console.WriteLine(quotient.dataLength);
+ Console.WriteLine("{0} = {1}({2}) + {3} p = {4}", a.ToString(10),
+ b.ToString(10), quotient.ToString(10), remainder.ToString(10),
+ p[1].ToString(10));
+ */
+
+ q[0] = q[1];
+ r[0] = r[1];
+ q[1] = quotient; r[1] = remainder;
+
+ a = b;
+ b = remainder;
+
+ step++;
+ }
+
+ if(r[0].dataLength > 1 || (r[0].dataLength == 1 && r[0].data[0] != 1))
+ throw (new ArithmeticException("No inverse!"));
+
+ BigInteger result = ((p[0] - (p[1] * q[0])) % modulus);
+
+ if((result.data[maxLength - 1] & 0x80000000) != 0)
+ result += modulus; // get the least positive modulus
+
+ return result;
+ }
+
+ // Returns the value of the BigInteger as a byte array. The lowest
+ // index contains the MSB.
+ public byte[] getBytes()
+ {
+ int numBits = bitCount();
+ byte[] result = null;
+ if(numBits == 0) {
+ result = new byte[1];
+ result[0] = 0;
+ }
+ else {
+ int numBytes = numBits >> 3;
+ if((numBits & 0x7) != 0)
+ numBytes++;
+ result = new byte[numBytes];
+ //Console.WriteLine(result.Length);
+ int numBytesInWord = numBytes & 0x3;
+ if(numBytesInWord == 0)
+ numBytesInWord = 4;
+ int pos = 0;
+ for(int i = dataLength - 1; i >= 0; i--) {
+ uint val = data[i];
+ for(int j = numBytesInWord - 1; j >= 0; j--) {
+ result[pos+j] = (byte)(val & 0xFF);
+ val >>= 8;
+ }
+ pos += numBytesInWord;
+ numBytesInWord = 4;
+ }
+ }
+ return result;
+ }
+
+ // Return true if the value of the specified bit is 1, false otherwise
+ public bool testBit (uint bitNum)
+ {
+ uint bytePos = bitNum >> 5; // divide by 32
+ byte bitPos = (byte)(bitNum & 0x1F); // get the lowest 5 bits
+
+ uint mask = (uint)1 << bitPos;
+ return ((this.data[bytePos] | mask) == this.data[bytePos]);
+ }
+
+ // Sets the value of the specified bit to 1
+ // The Least Significant Bit position is 0.
+ public void setBit(uint bitNum)
+ {
+ uint bytePos = bitNum >> 5; // divide by 32
+ byte bitPos = (byte)(bitNum & 0x1F); // get the lowest 5 bits
+
+ uint mask = (uint)1 << bitPos;
+ this.data[bytePos] |= mask;
+
+ if(bytePos >= this.dataLength)
+ this.dataLength = (int)bytePos + 1;
+ }
+
+ // Sets the value of the specified bit to 0
+ // The Least Significant Bit position is 0.
+ public void unsetBit(uint bitNum)
+ {
+ uint bytePos = bitNum >> 5;
+
+ if(bytePos < this.dataLength) {
+ byte bitPos = (byte)(bitNum & 0x1F);
+
+ uint mask = (uint)1 << bitPos;
+ uint mask2 = 0xFFFFFFFF ^ mask;
+
+ this.data[bytePos] &= mask2;
+
+ if(this.dataLength > 1 && this.data[this.dataLength - 1] == 0)
+ this.dataLength--;
+ }
+ }
+
+ // Returns a value that is equivalent to the integer square root
+ // of the BigInteger.
+ // The integer square root of "this" is defined as the largest integer n
+ // such that (n * n) <= this
+ public BigInteger sqrt ()
+ {
+ uint numBits = (uint)this.bitCount();
+
+ if((numBits & 0x1) != 0) // odd number of bits
+ numBits = (numBits >> 1) + 1;
+ else
+ numBits = (numBits >> 1);
+
+ uint bytePos = numBits >> 5;
+ byte bitPos = (byte)(numBits & 0x1F);
+
+ uint mask;
+
+ BigInteger result = new BigInteger();
+ if(bitPos == 0)
+ mask = 0x80000000;
+ else {
+ mask = (uint)1 << bitPos;
+ bytePos++;
+ }
+ result.dataLength = (int)bytePos;
+
+ for(int i = (int)bytePos - 1; i >= 0; i--) {
+ while(mask != 0) {
+ // guess
+ result.data[i] ^= mask;
+
+ // undo the guess if its square is larger than this
+ if((result * result) > this)
+ result.data[i] ^= mask;
+
+ mask >>= 1;
+ }
+ mask = 0x80000000;
+ }
+ return result;
+ }
+
+ // Returns the k_th number in the Lucas Sequence reduced modulo n.
+ //
+ // Uses index doubling to speed up the process. For example, to calculate V(k),
+ // we maintain two numbers in the sequence V(n) and V(n+1).
+ //
+ // To obtain V(2n), we use the identity
+ // V(2n) = (V(n) * V(n)) - (2 * Q^n)
+ // To obtain V(2n+1), we first write it as
+ // V(2n+1) = V((n+1) + n)
+ // and use the identity
+ // V(m+n) = V(m) * V(n) - Q * V(m-n)
+ // Hence,
+ // V((n+1) + n) = V(n+1) * V(n) - Q^n * V((n+1) - n)
+ // = V(n+1) * V(n) - Q^n * V(1)
+ // = V(n+1) * V(n) - Q^n * P
+ //
+ // We use k in its binary expansion and perform index doubling for each
+ // bit position. For each bit position that is set, we perform an
+ // index doubling followed by an index addition. This means that for V(n),
+ // we need to update it to V(2n+1). For V(n+1), we need to update it to
+ // V((2n+1)+1) = V(2*(n+1))
+ //
+ // This function returns
+ // [0] = U(k)
+ // [1] = V(k)
+ // [2] = Q^n
+ //
+ // Where U(0) = 0 % n, U(1) = 1 % n
+ // V(0) = 2 % n, V(1) = P % n
+ public static BigInteger[] LucasSequence (BigInteger P, BigInteger Q,
+ BigInteger k, BigInteger n)
+ {
+ if(k.dataLength == 1 && k.data[0] == 0) {
+ BigInteger[] result = new BigInteger[3];
+
+ result[0] = 0; result[1] = 2 % n; result[2] = 1 % n;
+ return result;
+ }
+
+ // calculate constant = b^(2k) / m
+ // for Barrett Reduction
+ BigInteger constant = new BigInteger();
+
+ int nLen = n.dataLength << 1;
+ constant.data[nLen] = 0x00000001;
+ constant.dataLength = nLen + 1;
+
+ constant = constant / n;
+
+ // calculate values of s and t
+ int s = 0;
+
+ for(int index = 0; index < k.dataLength; index++) {
+ uint mask = 0x01;
+
+ for(int i = 0; i < 32; i++) {
+ if((k.data[index] & mask) != 0) {
+ index = k.dataLength; // to break the outer loop
+ break;
+ }
+ mask <<= 1;
+ s++;
+ }
+ }
+
+ BigInteger t = k >> s;
+
+ //Console.WriteLine("s = " + s + " t = " + t);
+ return LucasSequenceHelper(P, Q, t, n, constant, s);
+ }
+
+ // Performs the calculation of the kth term in the Lucas Sequence.
+ // For details of the algorithm, see reference [9].
+ // k must be odd. i.e LSB == 1
+ private static BigInteger[] LucasSequenceHelper(BigInteger P, BigInteger Q,
+ BigInteger k, BigInteger n, BigInteger constant, int s)
+ {
+ BigInteger[] result = new BigInteger[3];
+
+ if((k.data[0] & 0x00000001) == 0)
+ throw (new ArgumentException("Argument k must be odd."));
+
+ int numbits = k.bitCount();
+ uint mask = (uint)0x1 << ((numbits & 0x1F) - 1);
+
+ // v = v0, v1 = v1, u1 = u1, Q_k = Q^0
+
+ BigInteger v = 2 % n, Q_k = 1 % n,
+ v1 = P % n, u1 = Q_k;
+ bool flag = true;
+
+ for(int i = k.dataLength - 1; i >= 0 ; i--) { // iterate on the binary expansion of k
+ //Console.WriteLine("round");
+ while(mask != 0) {
+ if(i == 0 && mask == 0x00000001) // last bit
+ break;
+
+ if((k.data[i] & mask) != 0) { // bit is set
+ // index doubling with addition
+
+ u1 = (u1 * v1) % n;
+
+ v = ((v * v1) - (P * Q_k)) % n;
+ v1 = n.BarrettReduction(v1 * v1, n, constant);
+ v1 = (v1 - ((Q_k * Q) << 1)) % n;
+
+ if(flag)
+ flag = false;
+ else
+ Q_k = n.BarrettReduction(Q_k * Q_k, n, constant);
+
+ Q_k = (Q_k * Q) % n;
+ }
+ else {
+ // index doubling
+ u1 = ((u1 * v) - Q_k) % n;
+
+ v1 = ((v * v1) - (P * Q_k)) % n;
+ v = n.BarrettReduction(v * v, n, constant);
+ v = (v - (Q_k << 1)) % n;
+
+ if(flag) {
+ Q_k = Q % n;
+ flag = false;
+ }
+ else
+ Q_k = n.BarrettReduction(Q_k * Q_k, n, constant);
+ }
+
+ mask >>= 1;
+ }
+ mask = 0x80000000;
+ }
+
+ // at this point u1 = u(n+1) and v = v(n)
+ // since the last bit always 1, we need to transform u1 to u(2n+1) and v to v(2n+1)
+
+ u1 = ((u1 * v) - Q_k) % n;
+ v = ((v * v1) - (P * Q_k)) % n;
+ if(flag)
+ flag = false;
+ else
+ Q_k = n.BarrettReduction(Q_k * Q_k, n, constant);
+
+ Q_k = (Q_k * Q) % n;
+
+
+ for (int i = 0; i < s; i++) {
+ // index doubling
+ u1 = (u1 * v) % n;
+ v = ((v * v) - (Q_k << 1)) % n;
+
+ if(flag) {
+ Q_k = Q % n;
+ flag = false;
+ }
+ else
+ Q_k = n.BarrettReduction(Q_k * Q_k, n, constant);
+ }
+
+ result[0] = u1;
+ result[1] = v;
+ result[2] = Q_k;
+
+ return result;
+ }
+}
+
+}
\ No newline at end of file
--- /dev/null
+//
+// System.Security.Cryptography.MiniParser: Internal XML parser implementation
+//
+// Authors:
+// Sergey Chaban
+//
+
+/*
+ * Copyright (c) 2001, 2002 Wild West Software
+ * Copyright (c) 2002 Sergey Chaban
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+using System;
+using System.Text;
+using System.Collections;
+using System.Globalization;
+
+namespace System.Security.Cryptography {
+
+internal class MiniParser {
+
+ public interface IReader {
+ int Read();
+ }
+
+ public interface IAttrList {
+ int Length {get;}
+ bool IsEmpty {get;}
+ string GetName(int i);
+ string GetValue(int i);
+ string GetValue(string name);
+ void ChangeValue(string name, string newValue);
+ string[] Names {get;}
+ string[] Values {get;}
+ }
+
+ public interface IMutableAttrList : IAttrList {
+ void Clear();
+ void Add(string name, string value);
+ void CopyFrom(IAttrList attrs);
+ void Remove(int i);
+ void Remove(string name);
+ }
+
+ public interface IHandler {
+ void OnStartParsing(MiniParser parser);
+ void OnStartElement(string name, IAttrList attrs);
+ void OnEndElement(string name);
+ void OnChars(string ch);
+ void OnEndParsing(MiniParser parser);
+ }
+
+ public class HandlerAdapter : IHandler {
+ public HandlerAdapter() {}
+ public void OnStartParsing(MiniParser parser) {}
+ public void OnStartElement(string name, IAttrList attrs) {}
+ public void OnEndElement(string name) {}
+ public void OnChars(string ch) {}
+ public void OnEndParsing(MiniParser parser) {}
+ }
+
+ private enum CharKind : byte {
+ LEFT_BR = 0,
+ RIGHT_BR = 1,
+ SLASH = 2,
+ PI_MARK = 3,
+ EQ = 4,
+ AMP = 5,
+ SQUOTE = 6,
+ DQUOTE = 7,
+ BANG = 8,
+ LEFT_SQBR = 9,
+ SPACE = 0xA,
+ RIGHT_SQBR = 0xB,
+ TAB = 0xC,
+ CR = 0xD,
+ EOL = 0xE,
+ CHARS = 0xF,
+ UNKNOWN = 0x1F
+ }
+
+ private enum ActionCode : byte {
+ START_ELEM = 0,
+ END_ELEM = 1,
+ END_NAME = 2,
+ SET_ATTR_NAME = 3,
+ SET_ATTR_VAL = 4,
+ SEND_CHARS = 5,
+ START_CDATA = 6,
+ END_CDATA = 7,
+ ERROR = 8,
+ STATE_CHANGE = 9,
+ FLUSH_CHARS_STATE_CHANGE = 0xA,
+ ACC_CHARS_STATE_CHANGE = 0xB,
+ ACC_CDATA = 0xC,
+ PROC_CHAR_REF = 0xD,
+ UNKNOWN = 0xF
+ }
+
+ public class AttrListImpl : IMutableAttrList {
+ protected ArrayList names;
+ protected ArrayList values;
+
+ public AttrListImpl() : this(0) {}
+
+ public AttrListImpl(int initialCapacity) {
+ if (initialCapacity <= 0) {
+ names = new ArrayList();
+ values = new ArrayList();
+ } else {
+ names = new ArrayList(initialCapacity);
+ values = new ArrayList(initialCapacity);
+ }
+ }
+
+ public AttrListImpl(IAttrList attrs)
+ : this(attrs != null ? attrs.Length : 0) {
+ if (attrs != null) this.CopyFrom(attrs);
+ }
+
+ public int Length {
+ get {return names.Count;}
+ }
+
+ public bool IsEmpty {
+ get {return this.Length != 0;}
+ }
+
+ public string GetName(int i) {
+ string res = null;
+ if (i >= 0 && i < this.Length) {
+ res = names[i] as string;
+ }
+ return res;
+ }
+
+ public string GetValue(int i) {
+ string res = null;
+ if (i >= 0 && i < this.Length) {
+ res = values[i] as string;
+ }
+ return res;
+ }
+
+ public string GetValue(string name) {
+ return this.GetValue(names.IndexOf(name));
+ }
+
+ public void ChangeValue(string name, string newValue) {
+ int i = names.IndexOf(name);
+ if (i >= 0 && i < this.Length) {
+ values[i] = newValue;
+ }
+ }
+
+ public string[] Names {
+ get {return names.ToArray(typeof(string)) as string[];}
+ }
+
+ public string[] Values {
+ get {return values.ToArray(typeof(string)) as string[];}
+ }
+
+ public void Clear() {
+ names.Clear();
+ values.Clear();
+ }
+
+ public void Add(string name, string value) {
+ names.Add(name);
+ values.Add(value);
+ }
+
+ public void Remove(int i) {
+ if (i >= 0) {
+ names.RemoveAt(i);
+ values.RemoveAt(i);
+ }
+ }
+
+ public void Remove(string name) {
+ this.Remove(names.IndexOf(name));
+ }
+
+ public void CopyFrom(IAttrList attrs) {
+ if (attrs != null && ((object)this == (object)attrs)) {
+ this.Clear();
+ int n = attrs.Length;
+ for (int i = 0; i < n; i++) {
+ this.Add(attrs.GetName(i), attrs.GetValue(i));
+ }
+ }
+ }
+ }
+
+ public class XMLError : Exception {
+ protected string descr;
+ protected int line, column;
+ public XMLError() : this("Unknown") {}
+ public XMLError(string descr) : this(descr, -1, -1) {}
+ public XMLError(string descr, int line, int column)
+ : base(descr) {
+ this.descr = descr;
+ this.line = line;
+ this.column = column;
+ }
+ public int Line {get {return line;}}
+ public int Column {get {return column;}}
+ public override string ToString() {
+ return (String.Format("{0} @ (line = {1}, col = {2})", descr, line, column));
+ }
+ }
+
+ private static readonly int INPUT_RANGE = 13;
+ private static readonly ushort[] tbl = {
+ ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 1, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 128,
+ ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 2, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 133, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 16, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.FLUSH_CHARS_STATE_CHANGE << 8) | 4,
+ ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.END_ELEM << 8) | 0, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 2, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 2, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
+ ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 5, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3,
+ ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 4, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.END_NAME << 8) | 6, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.END_NAME << 8) | 7, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.END_NAME << 8) | 8, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
+ ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3,
+ ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
+ ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.FLUSH_CHARS_STATE_CHANGE << 8) | 1, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 10, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 7, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10,
+ ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_ELEM << 8) | 6, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.START_ELEM << 8) | 7, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 8, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
+ ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.SET_ATTR_NAME << 8) | 11, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 12, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130,
+ ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 13, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 10, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10,
+ ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 14, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 15, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 11, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 132,
+ ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.SET_ATTR_NAME << 8) | 11, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 12, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 130,
+ ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.SEND_CHARS << 8) | 2, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 16, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 134,
+ ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.SET_ATTR_VAL << 8) | 17, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 14, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14,
+ ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.SET_ATTR_VAL << 8) | 17, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 15, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15,
+ ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 18, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19,
+ ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_ELEM << 8) | 6, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.START_ELEM << 8) | 7, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 17, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
+ ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.END_CDATA << 8) | 10, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18,
+ ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19,
+ 0xFFFF
+ };
+
+ protected static string[] errors = {
+ /* 0 */ "Expected element",
+ /* 1 */ "Invalid character in tag",
+ /* 2 */ "No '='",
+ /* 3 */ "Invalid character entity",
+ /* 4 */ "Invalid attr value",
+ /* 5 */ "Empty tag",
+ /* 6 */ "No end tag",
+ /* 7 */ "Bad entity ref"
+ };
+
+ protected int line;
+ protected int col;
+ protected int[] twoCharBuff;
+ protected bool splitCData;
+
+ public MiniParser() {
+ twoCharBuff = new int[2];
+ splitCData = false;
+ Reset();
+ }
+
+ public void Reset() {
+ line = 0;
+ col = 0;
+ }
+
+ protected static bool StrEquals(string str, StringBuilder sb, int sbStart, int len) {
+ if (len != str.Length) return false;
+ for (int i = 0; i < len; i++) {
+ if (str[i] != sb[sbStart + i]) return false;
+ }
+ return true;
+ }
+
+ protected void FatalErr(string descr) {
+ throw new XMLError(descr, this.line, this.col);
+ }
+
+ protected static int Xlat(int charCode, int state) {
+ int p = state * INPUT_RANGE;
+ int n = Math.Min(tbl.Length - p, INPUT_RANGE);
+ for (;--n >= 0;) {
+ ushort code = tbl[p];
+ if (charCode == (code >> 12)) return (code & 0xFFF);
+ p++;
+ }
+ return 0xFFF;
+ }
+
+ public void Parse(IReader reader, IHandler handler) {
+ if (reader == null) throw new ArgumentNullException("reader");
+ if (handler == null) handler = new HandlerAdapter();
+
+ AttrListImpl attrList = new AttrListImpl();
+ string lastAttrName = null;
+ Stack tagStack = new Stack();
+ string elementName = null;
+ line = 1;
+ col = 0;
+ int currCh = 0;
+ int stateCode = 0;
+ StringBuilder sbChars = new StringBuilder();
+ bool seenCData = false;
+ bool isComment = false;
+ bool isDTD = false;
+ int bracketSwitch = 0;
+
+ handler.OnStartParsing(this);
+
+ while (true) {
+ ++this.col;
+ int prevCh = currCh;
+
+ currCh = reader.Read();
+
+ if (currCh == -1) {
+ if (stateCode != 0) {
+ FatalErr("Unexpected EOF");
+ }
+ break;
+ }
+
+ int charCode = "<>/?=&'\"![ ]\t\r\n".IndexOf((char)currCh) & 0xF;
+ if (charCode == (int)CharKind.CR) continue; // ignore
+ // whitepace ::= (#x20 | #x9 | #xd | #xa)+
+ if (charCode == (int)CharKind.TAB) charCode = (int)CharKind.SPACE; // tab == space
+ if (charCode == (int)CharKind.EOL) {
+ this.col = 0;
+ this.line++;
+ charCode = (int)CharKind.SPACE;
+ }
+
+ int actionCode = MiniParser.Xlat(charCode, stateCode);
+ stateCode = actionCode & 0xFF;
+ // Ignore newline inside attribute value.
+ if (currCh == '\n' && (stateCode == 0xE || stateCode == 0xF)) continue;
+ actionCode >>= 8;
+
+ if (stateCode >= 0x80) {
+ if (stateCode == 0xFF) {
+ FatalErr("State dispatch error.");
+ } else {
+ FatalErr(errors[stateCode ^ 0x80]);
+ }
+ }
+
+ switch (actionCode) {
+ case (int)ActionCode.START_ELEM:
+ handler.OnStartElement(elementName, attrList);
+ if (currCh != '/') {
+ tagStack.Push(elementName);
+ } else {
+ handler.OnEndElement(elementName);
+ }
+ attrList.Clear();
+ break;
+
+ case (int)ActionCode.END_ELEM:
+ elementName = sbChars.ToString();
+ sbChars = new StringBuilder();
+ string endName = null;
+ if (tagStack.Count == 0 ||
+ elementName != (endName = tagStack.Pop() as string)) {
+ if (endName == null) {
+ FatalErr("Tag stack underflow");
+ } else {
+ FatalErr(String.Format("Expected end tag '{0}' but found '{1}'", elementName, endName));
+ }
+ }
+ handler.OnEndElement(elementName);
+ break;
+
+ case (int)ActionCode.END_NAME:
+ elementName = sbChars.ToString();
+ sbChars = new StringBuilder();
+ if (currCh != '/' && currCh != '>') break;
+ goto case (int)ActionCode.START_ELEM;
+
+ case (int)ActionCode.SET_ATTR_NAME:
+ lastAttrName = sbChars.ToString();
+ sbChars = new StringBuilder();
+ break;
+
+ case (int)ActionCode.SET_ATTR_VAL:
+ if (lastAttrName == null) FatalErr("Internal error.");
+ attrList.Add(lastAttrName, sbChars.ToString());
+ sbChars = new StringBuilder();
+ lastAttrName = null;
+ break;
+
+ case (int)ActionCode.SEND_CHARS:
+ handler.OnChars(sbChars.ToString());
+ sbChars = new StringBuilder();
+ break;
+
+ case (int)ActionCode.START_CDATA:
+ string cdata = "CDATA[";
+ isComment = false;
+ isDTD = false;
+
+ if (currCh == '-') {
+ currCh = reader.Read();
+
+ if (currCh != '-') FatalErr("Invalid comment");
+
+ this.col++;
+ isComment = true;
+ twoCharBuff[0] = -1;
+ twoCharBuff[1] = -1;
+ } else {
+ if (currCh != '[') {
+ isDTD = true;
+ bracketSwitch = 0;
+ break;
+ }
+
+ for (int i = 0; i < cdata.Length; i++) {
+ if (reader.Read() != cdata[i]) {
+ this.col += i+1;
+ break;
+ }
+ }
+ this.col += cdata.Length;
+ seenCData = true;
+ }
+ break;
+
+ case (int)ActionCode.END_CDATA:
+ int n = 0;
+ currCh = ']';
+
+ while (currCh == ']') {
+ currCh = reader.Read();
+ n++;
+ }
+
+ if (currCh != '>') {
+ for (int i = 0; i < n; i++) sbChars.Append(']');
+ sbChars.Append((char)currCh);
+ stateCode = 0x12;
+ } else {
+ for (int i = 0; i < n-2; i++) sbChars.Append(']');
+ seenCData = false;
+ }
+
+ this.col += n;
+ break;
+
+ case (int)ActionCode.ERROR:
+ FatalErr(String.Format("Error {0}", stateCode));
+ break;
+
+ case (int)ActionCode.STATE_CHANGE:
+ break;
+
+ case (int)ActionCode.FLUSH_CHARS_STATE_CHANGE:
+ sbChars = new StringBuilder();
+ if (currCh != '<') goto case (int)ActionCode.ACC_CHARS_STATE_CHANGE;
+ break;
+
+ case (int)ActionCode.ACC_CHARS_STATE_CHANGE:
+ sbChars.Append((char)currCh);
+ break;
+
+ case (int)ActionCode.ACC_CDATA:
+ if (isComment) {
+ if (currCh == '>'
+ && twoCharBuff[0] == '-'
+ && twoCharBuff[1] == '-') {
+ isComment = false;
+ stateCode = 0;
+ } else {
+ twoCharBuff[0] = twoCharBuff[1];
+ twoCharBuff[1] = currCh;
+ }
+ } else if (isDTD) {
+ if (currCh == '<' || currCh == '>') bracketSwitch ^= 1;
+ if (currCh == '>' && bracketSwitch != 0) {
+ isDTD = false;
+ stateCode = 0;
+ }
+ } else {
+ if (this.splitCData
+ && sbChars.Length > 0
+ && seenCData) {
+ handler.OnChars(sbChars.ToString());
+ sbChars = new StringBuilder();
+ }
+ seenCData = false;
+ sbChars.Append((char)currCh);
+ }
+ break;
+
+ case (int)ActionCode.PROC_CHAR_REF:
+ currCh = reader.Read();
+ int cl = this.col + 1;
+ if (currCh == '#') { // character reference
+ int r = 10;
+ int chCode = 0;
+ int nDigits = 0;
+ currCh = reader.Read();
+ cl++;
+
+ if (currCh == 'x') {
+ currCh = reader.Read();
+ cl++;
+ r=16;
+ }
+
+ NumberStyles style = r == 16 ? NumberStyles.HexNumber : NumberStyles.Integer;
+
+ while (true) {
+ int x = -1;
+ if (Char.IsNumber((char)currCh) || "abcdef".IndexOf(Char.ToLower((char)currCh)) != -1) {
+ try {
+ x = Int32.Parse(new string((char)currCh, 1), style);
+ } catch (FormatException) {x = -1;}
+ }
+ if (x == -1) break;
+ chCode *= r;
+ chCode += x;
+ nDigits++;
+ currCh = reader.Read();
+ cl++;
+ }
+
+ if (currCh == ';' && nDigits > 0) {
+ sbChars.Append((char)chCode);
+ } else {
+ FatalErr("Bad char ref");
+ }
+ } else {
+ // entity reference
+ string entityRefChars = "aglmopqstu"; // amp | apos | quot | gt | lt
+ string entities = "&'\"><";
+
+ int pos = 0;
+ int entIdx = 0xF;
+ int pred = 0;
+ int predShift = 0;
+
+ int sbLen = sbChars.Length;
+
+ while (true) {
+ if (pos != 0xF) pos = entityRefChars.IndexOf((char)currCh) & 0xF;
+ if (pos == 0xF) FatalErr(errors[7]);
+ sbChars.Append((char)currCh);
+
+ int path = "\uFF35\u3F8F\u4F8F\u0F5F\uFF78\uE1F4\u2299\uEEFF\uEEFF\uFF4F"[pos];
+ int lBr = (path >> 4) & 0xF;
+ int rBr = path & 0xF;
+ int lPred = path >> 12;
+ int rPred = (path >> 8) & 0xF;
+ currCh = reader.Read();
+ cl++;
+ pos = 0xF;
+ if (lBr != 0xF && currCh == entityRefChars[lBr]) {
+ if (lPred < 0xE) entIdx = lPred;
+ pred = lPred;
+ predShift = 12; // left
+ } else if (rBr != 0xF && currCh == entityRefChars[rBr]) {
+ if (rPred < 0xE) entIdx = rPred;
+ pred = rPred;
+ predShift = 8; // right
+ } else if (currCh == ';') {
+ if (entIdx != 0xF
+ && predShift != 0
+ && ((path >> predShift) & 0xF) == 0xE) break;
+ continue; // pos == 0xF
+ }
+
+ pos=0;
+
+ }
+
+ int l = cl - this.col - 1;
+
+ if ((l > 0 && l < 5)
+ &&(StrEquals("amp", sbChars, sbLen, l)
+ || StrEquals("apos", sbChars, sbLen, l)
+ || StrEquals("quot", sbChars, sbLen, l)
+ || StrEquals("lt", sbChars, sbLen, l)
+ || StrEquals("gt", sbChars, sbLen, l))
+ ) {
+ sbChars.Length = sbLen;
+ sbChars.Append(entities[entIdx]);
+ } else FatalErr(errors[7]);
+ }
+
+ this.col = cl;
+ break;
+
+ default:
+ FatalErr(String.Format("Unexpected action code - {0}.", actionCode));
+ break;
+ }
+ } // while (true)
+
+ handler.OnEndParsing(this);
+
+ } // Parse
+
+}
+
+}
-//\r
-// System.Security.Cryptography.AsymmetricAlgorithm Class implementation\r
-//\r
-// Authors:\r
-// Thomas Neidhart (tome@sbox.tugraz.at)\r
-// Sebastien Pouliot (spouliot@motus.com)\r
-//\r
-// Portions (C) 2002 Motus Technologies Inc. (http://www.motus.com)\r
-//\r
-\r
-using System;\r
-\r
-namespace System.Security.Cryptography {\r
-\r
- /// <summary>\r
- /// Abstract base class for all cryptographic asymmetric algorithms.\r
- /// Available algorithms include:\r
- /// RSA, DSA\r
- /// </summary>\r
- public abstract class AsymmetricAlgorithm : IDisposable {\r
-\r
- protected int KeySizeValue; // The size of the secret key used by the symmetric algorithm in bits. \r
- protected KeySizes[] LegalKeySizesValue; // Specifies the key sizes that are supported by the symmetric algorithm. \r
-\r
- /// <summary>\r
- /// Called from constructor of derived class.\r
- /// </summary>\r
- protected AsymmetricAlgorithm () {}\r
- \r
- /// <summary>\r
- /// Gets the key exchange algorithm\r
- /// </summary>\r
- public abstract string KeyExchangeAlgorithm {get;}\r
- \r
- /// <summary>\r
- /// Gets or sets the actual key size\r
- /// </summary>\r
- public virtual int KeySize {\r
- get {\r
- return this.KeySizeValue;\r
- }\r
- set {\r
- if (!IsLegalKeySize (this.LegalKeySizesValue, value))\r
- throw new CryptographicException("key size not supported by algorithm");\r
- \r
- this.KeySizeValue = value;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Gets all legal key sizes\r
- /// </summary>\r
- public virtual KeySizes[] LegalKeySizes {\r
- get {\r
- return this.LegalKeySizesValue;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Gets the signature algorithm\r
- /// </summary>\r
- public abstract string SignatureAlgorithm {get;}\r
-\r
- public void Dispose() \r
- {\r
- Dispose (true);\r
- GC.SuppressFinalize (this); // Finalization is now unnecessary\r
- }\r
-\r
- public void Clear() \r
- {\r
- Dispose (false);\r
- }\r
-\r
- protected abstract void Dispose (bool disposing);\r
-\r
-/* Commented to remove cyclic dependency between corlib and System.Xml\r
- // helper function for FromXmlString (used in RSA and DSA)\r
- protected byte[] GetElement (XmlDocument xml, string tag) \r
- {\r
- XmlNodeList xnl = xml.GetElementsByTagName (tag);\r
- if (xnl.Count > 0)\r
- return Convert.FromBase64String (xnl[0].InnerText);\r
- else\r
- return null;\r
- }*/\r
-\r
- /// <summary>\r
- /// Reconstructs the AsymmetricAlgorithm Object from an XML-string\r
- /// </summary>\r
- public abstract void FromXmlString(string xmlString);\r
- \r
- /// <summary>\r
- /// Returns an XML string representation the current AsymmetricAlgorithm object\r
- /// </summary>\r
- public abstract string ToXmlString(bool includePrivateParameters); \r
- \r
- private bool IsLegalKeySize(KeySizes[] LegalKeys, int Size) \r
- {\r
- foreach (KeySizes LegalKeySize in LegalKeys) {\r
- for (int i=LegalKeySize.MinSize; i<=LegalKeySize.MaxSize; i+=LegalKeySize.SkipSize) {\r
- if (i == Size)\r
- return true;\r
- }\r
- }\r
- return false;\r
- }\r
- \r
- /// <summary>\r
- /// Checks wether the given keyLength is valid for the current algorithm\r
- /// </summary>\r
- /// <param name="bitLength">the given keyLength</param>\r
- public bool ValidKeySize(int bitLength) \r
- {\r
- return IsLegalKeySize(LegalKeySizesValue, bitLength);\r
- }\r
- \r
- /// <summary>\r
- /// Creates the default implementation of the default asymmetric algorithm (RSA).\r
- /// </summary>\r
- public static AsymmetricAlgorithm Create () \r
- {\r
- return Create ("System.Security.Cryptography.AsymmetricAlgorithm");\r
- }\r
- \r
- /// <summary>\r
- /// Creates a specific implementation of the given asymmetric algorithm.\r
- /// </summary>\r
- /// <param name="algo">Specifies which derived class to create</param>\r
- public static AsymmetricAlgorithm Create (string algName) \r
- {\r
- return (AsymmetricAlgorithm) CryptoConfig.CreateFromName (algName);\r
- }\r
- }\r
-}\r
-\r
+//
+// System.Security.Cryptography.AsymmetricAlgorithm Class implementation
+//
+// Authors:
+// Thomas Neidhart (tome@sbox.tugraz.at)
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// Portions (C) 2002 Motus Technologies Inc. (http://www.motus.com)
+//
+
+using System;
+
+namespace System.Security.Cryptography {
+
+ // to import keypairs parameters using MiniParser
+ internal class AsymmetricParameters : MiniParser.IReader {
+ private string xml;
+ private int pos;
+
+ public AsymmetricParameters (string xml)
+ {
+ this.xml = xml;
+ pos = 0;
+ }
+
+ public int Read ()
+ {
+ try {
+ return (int) xml [pos++];
+ }
+ catch {
+ return -1;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Abstract base class for all cryptographic asymmetric algorithms.
+ /// Available algorithms include:
+ /// RSA, DSA
+ /// </summary>
+ public abstract class AsymmetricAlgorithm : IDisposable {
+
+ protected int KeySizeValue; // The size of the secret key used by the symmetric algorithm in bits.
+ protected KeySizes[] LegalKeySizesValue; // Specifies the key sizes that are supported by the symmetric algorithm.
+
+ /// <summary>
+ /// Called from constructor of derived class.
+ /// </summary>
+ protected AsymmetricAlgorithm () {}
+
+ /// <summary>
+ /// Gets the key exchange algorithm
+ /// </summary>
+ public abstract string KeyExchangeAlgorithm {get;}
+
+ /// <summary>
+ /// Gets or sets the actual key size
+ /// </summary>
+ public virtual int KeySize {
+ get { return this.KeySizeValue; }
+ set {
+ if (!IsLegalKeySize (this.LegalKeySizesValue, value))
+ throw new CryptographicException("key size not supported by algorithm");
+
+ this.KeySizeValue = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets all legal key sizes
+ /// </summary>
+ public virtual KeySizes[] LegalKeySizes {
+ get { return this.LegalKeySizesValue; }
+ }
+
+ /// <summary>
+ /// Gets the signature algorithm
+ /// </summary>
+ public abstract string SignatureAlgorithm {get;}
+
+ void IDisposable.Dispose ()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this); // Finalization is now unnecessary
+ }
+
+ public void Clear ()
+ {
+ Dispose (false);
+ }
+
+ protected abstract void Dispose (bool disposing);
+
+ /// <summary>
+ /// Reconstructs the AsymmetricAlgorithm Object from an XML-string
+ /// </summary>
+ public abstract void FromXmlString (string xmlString);
+
+ /// <summary>
+ /// Returns an XML string representation the current AsymmetricAlgorithm object
+ /// </summary>
+ public abstract string ToXmlString (bool includePrivateParameters);
+
+ private bool IsLegalKeySize (KeySizes[] LegalKeys, int Size)
+ {
+ foreach (KeySizes LegalKeySize in LegalKeys) {
+ for (int i=LegalKeySize.MinSize; i<=LegalKeySize.MaxSize; i+=LegalKeySize.SkipSize) {
+ if (i == Size)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Checks wether the given keyLength is valid for the current algorithm
+ /// </summary>
+ /// <param name="bitLength">the given keyLength</param>
+ public bool ValidKeySize (int bitLength)
+ {
+ return IsLegalKeySize (LegalKeySizesValue, bitLength);
+ }
+
+ /// <summary>
+ /// Creates the default implementation of the default asymmetric algorithm (RSA).
+ /// </summary>
+ public static AsymmetricAlgorithm Create ()
+ {
+ return Create ("System.Security.Cryptography.AsymmetricAlgorithm");
+ }
+
+ /// <summary>
+ /// Creates a specific implementation of the given asymmetric algorithm.
+ /// </summary>
+ /// <param name="algo">Specifies which derived class to create</param>
+ public static AsymmetricAlgorithm Create (string algName)
+ {
+ return (AsymmetricAlgorithm) CryptoConfig.CreateFromName (algName);
+ }
+ }
+}
+
--- /dev/null
+//
+// BigInteger.cs - Big Integer implementation
+//
+// Authors:
+// Chew Keong TAN
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// Copyright (c) 2002 Chew Keong TAN
+// All rights reserved.
+//
+// Modifications from original
+// - Removed all reference to Random class (not secure enough)
+// - Moved all static Test function into BigIntegerTest.cs (for NUnit)
+//
+
+//************************************************************************************
+// BigInteger Class Version 1.03
+//
+// Copyright (c) 2002 Chew Keong TAN
+// All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, provided that the above
+// copyright notice(s) and this permission notice appear in all copies of
+// the Software and that both the above copyright notice(s) and this
+// permission notice appear in supporting documentation.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+// OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+// HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+// INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+//
+// Disclaimer
+// ----------
+// Although reasonable care has been taken to ensure the correctness of this
+// implementation, this code should never be used in any application without
+// proper verification and testing. I disclaim all liability and responsibility
+// to any person or entity with respect to any loss or damage caused, or alleged
+// to be caused, directly or indirectly, by the use of this BigInteger class.
+//
+// Comments, bugs and suggestions to
+// (http://www.codeproject.com/csharp/biginteger.asp)
+//
+//
+// Overloaded Operators +, -, *, /, %, >>, <<, ==, !=, >, <, >=, <=, &, |, ^, ++, --, ~
+//
+// Features
+// --------
+// 1) Arithmetic operations involving large signed integers (2's complement).
+// 2) Primality test using Fermat little theorm, Rabin Miller's method,
+// Solovay Strassen's method and Lucas strong pseudoprime.
+// 3) Modulo exponential with Barrett's reduction.
+// 4) Inverse modulo.
+// 5) Pseudo prime generation.
+// 6) Co-prime generation.
+//
+//
+// Known Problem
+// -------------
+// This pseudoprime passes my implementation of
+// primality test but failed in JDK's isProbablePrime test.
+//
+// byte[] pseudoPrime1 = { (byte)0x00,
+// (byte)0x85, (byte)0x84, (byte)0x64, (byte)0xFD, (byte)0x70, (byte)0x6A,
+// (byte)0x9F, (byte)0xF0, (byte)0x94, (byte)0x0C, (byte)0x3E, (byte)0x2C,
+// (byte)0x74, (byte)0x34, (byte)0x05, (byte)0xC9, (byte)0x55, (byte)0xB3,
+// (byte)0x85, (byte)0x32, (byte)0x98, (byte)0x71, (byte)0xF9, (byte)0x41,
+// (byte)0x21, (byte)0x5F, (byte)0x02, (byte)0x9E, (byte)0xEA, (byte)0x56,
+// (byte)0x8D, (byte)0x8C, (byte)0x44, (byte)0xCC, (byte)0xEE, (byte)0xEE,
+// (byte)0x3D, (byte)0x2C, (byte)0x9D, (byte)0x2C, (byte)0x12, (byte)0x41,
+// (byte)0x1E, (byte)0xF1, (byte)0xC5, (byte)0x32, (byte)0xC3, (byte)0xAA,
+// (byte)0x31, (byte)0x4A, (byte)0x52, (byte)0xD8, (byte)0xE8, (byte)0xAF,
+// (byte)0x42, (byte)0xF4, (byte)0x72, (byte)0xA1, (byte)0x2A, (byte)0x0D,
+// (byte)0x97, (byte)0xB1, (byte)0x31, (byte)0xB3,
+// };
+//
+//
+// Change Log
+// ----------
+// 1) September 23, 2002 (Version 1.03)
+// - Fixed operator- to give correct data length.
+// - Added Lucas sequence generation.
+// - Added Strong Lucas Primality test.
+// - Added integer square root method.
+// - Added setBit/unsetBit methods.
+// - New isProbablePrime() method which do not require the
+// confident parameter.
+//
+// 2) August 29, 2002 (Version 1.02)
+// - Fixed bug in the exponentiation of negative numbers.
+// - Faster modular exponentiation using Barrett reduction.
+// - Added getBytes() method.
+// - Fixed bug in ToHexString method.
+// - Added overloading of ^ operator.
+// - Faster computation of Jacobi symbol.
+//
+// 3) August 19, 2002 (Version 1.01)
+// - Big integer is stored and manipulated as unsigned integers (4 bytes) instead of
+// individual bytes this gives significant performance improvement.
+// - Updated Fermat's Little Theorem test to use a^(p-1) mod p = 1
+// - Added isProbablePrime method.
+// - Updated documentation.
+//
+// 4) August 9, 2002 (Version 1.0)
+// - Initial Release.
+//
+//
+// References
+// [1] D. E. Knuth, "Seminumerical Algorithms", The Art of Computer Programming Vol. 2,
+// 3rd Edition, Addison-Wesley, 1998.
+//
+// [2] K. H. Rosen, "Elementary Number Theory and Its Applications", 3rd Ed,
+// Addison-Wesley, 1993.
+//
+// [3] B. Schneier, "Applied Cryptography", 2nd Ed, John Wiley & Sons, 1996.
+//
+// [4] A. Menezes, P. van Oorschot, and S. Vanstone, "Handbook of Applied Cryptography",
+// CRC Press, 1996, www.cacr.math.uwaterloo.ca/hac
+//
+// [5] A. Bosselaers, R. Govaerts, and J. Vandewalle, "Comparison of Three Modular
+// Reduction Functions," Proc. CRYPTO'93, pp.175-186.
+//
+// [6] R. Baillie and S. S. Wagstaff Jr, "Lucas Pseudoprimes", Mathematics of Computation,
+// Vol. 35, No. 152, Oct 1980, pp. 1391-1417.
+//
+// [7] H. C. Williams, "Édouard Lucas and Primality Testing", Canadian Mathematical
+// Society Series of Monographs and Advance Texts, vol. 22, John Wiley & Sons, New York,
+// NY, 1998.
+//
+// [8] P. Ribenboim, "The new book of prime number records", 3rd edition, Springer-Verlag,
+// New York, NY, 1995.
+//
+// [9] M. Joye and J.-J. Quisquater, "Efficient computation of full Lucas sequences",
+// Electronics Letters, 32(6), 1996, pp 537-538.
+//
+//************************************************************************************
+
+using System;
+
+namespace System.Security.Cryptography {
+
+internal class BigRandom {
+ RandomNumberGenerator rng;
+
+ public BigRandom ()
+ {
+ rng = RandomNumberGenerator.Create ();
+ }
+
+ public void Get (uint[] data)
+ {
+ byte[] random = new byte [4 * data.Length];
+ rng.GetBytes (random);
+ int n = 0;
+ for (int i=0; i < data.Length; i++) {
+ data[i] = BitConverter.ToUInt32 (random, n);
+ n+=4;
+ }
+ }
+
+ public int GetInt (int maxValue)
+ {
+ // calculate mask
+ int mask = Int32.MaxValue;
+ while ((mask & maxValue) == maxValue)
+ mask >>= 1;
+ // undo last iteration
+ mask <<= 1;
+ mask |= 0x01;
+ byte[] data = new byte [4];
+ int result = -1;
+ while ((result < 0) || (result > maxValue)) {
+ rng.GetBytes (data);
+ result = (BitConverter.ToInt32 (data, 0) & mask);
+ }
+ return result;
+ }
+
+ public byte GetByte()
+ {
+ byte[] data = new byte [1];
+ rng.GetBytes (data);
+ return data [0];
+ }
+}
+
+internal class BigInteger {
+ // maximum length of the BigInteger in uint (4 bytes)
+ // change this to suit the required level of precision.
+
+ //private const int maxLength = 70;
+ // FIXME: actually this limit us to approx. 2048 bits keypair for RSA
+ private const int maxLength = 140;
+
+ private BigRandom random;
+
+ // primes smaller than 2000 to test the generated prime number
+
+ public static readonly int[] primesBelow2000 = {
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
+ 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
+ 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293,
+ 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397,
+ 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499,
+ 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599,
+ 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691,
+ 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797,
+ 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887,
+ 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,
+ 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097,
+ 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193,
+ 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297,
+ 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399,
+ 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499,
+ 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597,
+ 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699,
+ 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789,
+ 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,
+ 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999 };
+
+ private uint[] data = null; // stores bytes from the Big Integer
+ public int dataLength; // number of actual chars used
+
+ // Constructor (Default value for BigInteger is 0
+ public BigInteger()
+ {
+ data = new uint[maxLength];
+ dataLength = 1;
+ }
+
+ // Constructor (Default value provided by long)
+ public BigInteger(long value)
+ {
+ data = new uint[maxLength];
+ long tempVal = value;
+ // copy bytes from long to BigInteger without any assumption of
+ // the length of the long datatype
+ dataLength = 0;
+ while(value != 0 && dataLength < maxLength) {
+ data[dataLength] = (uint)(value & 0xFFFFFFFF);
+ value >>= 32;
+ dataLength++;
+ }
+
+ if(tempVal > 0) { // overflow check for +ve value
+ if(value != 0 || (data[maxLength-1] & 0x80000000) != 0)
+ throw(new ArithmeticException("Positive overflow in constructor."));
+ }
+ else if(tempVal < 0) { // underflow check for -ve value
+ if(value != -1 || (data[dataLength-1] & 0x80000000) == 0)
+ throw(new ArithmeticException("Negative underflow in constructor."));
+ }
+
+ if(dataLength == 0)
+ dataLength = 1;
+ }
+
+ // Constructor (Default value provided by ulong)
+ public BigInteger(ulong value)
+ {
+ data = new uint[maxLength];
+ // copy bytes from ulong to BigInteger without any assumption of
+ // the length of the ulong datatype
+
+ dataLength = 0;
+ while(value != 0 && dataLength < maxLength) {
+ data[dataLength] = (uint)(value & 0xFFFFFFFF);
+ value >>= 32;
+ dataLength++;
+ }
+
+ if(value != 0 || (data[maxLength-1] & 0x80000000) != 0)
+ throw(new ArithmeticException("Positive overflow in constructor."));
+
+ if(dataLength == 0)
+ dataLength = 1;
+ }
+
+ // Constructor (Default value provided by BigInteger)
+ public BigInteger(BigInteger bi)
+ {
+ data = new uint[maxLength];
+ dataLength = bi.dataLength;
+ for(int i = 0; i < dataLength; i++)
+ data[i] = bi.data[i];
+ }
+
+ // Constructor (Default value provided by a string of digits of the
+ // specified base)
+ // Example (base 10)
+ // -----------------
+ // To initialize "a" with the default value of 1234 in base 10
+ // BigInteger a = new BigInteger("1234", 10)
+ //
+ // To initialize "a" with the default value of -1234
+ // BigInteger a = new BigInteger("-1234", 10)
+ //
+ // Example (base 16)
+ // -----------------
+ // To initialize "a" with the default value of 0x1D4F in base 16
+ // BigInteger a = new BigInteger("1D4F", 16)
+ //
+ // To initialize "a" with the default value of -0x1D4F
+ // BigInteger a = new BigInteger("-1D4F", 16)
+ //
+ // Note that string values are specified in the <sign><magnitude>
+ // format.
+ public BigInteger(string value, int radix)
+ {
+ BigInteger multiplier = new BigInteger(1);
+ BigInteger result = new BigInteger();
+ value = (value.ToUpper()).Trim();
+ int limit = 0;
+
+ if(value[0] == '-')
+ limit = 1;
+
+ for(int i = value.Length - 1; i >= limit ; i--) {
+ int posVal = (int)value[i];
+
+ if(posVal >= '0' && posVal <= '9')
+ posVal -= '0';
+ else if(posVal >= 'A' && posVal <= 'Z')
+ posVal = (posVal - 'A') + 10;
+ else
+ posVal = 9999999; // arbitrary large
+
+
+ if(posVal >= radix)
+ throw(new ArithmeticException("Invalid string in constructor."));
+ else {
+ if(value[0] == '-')
+ posVal = -posVal;
+
+ result = result + (multiplier * posVal);
+
+ if((i - 1) >= limit)
+ multiplier = multiplier * radix;
+ }
+ }
+
+ if(value[0] == '-') { // negative values
+ if((result.data[maxLength-1] & 0x80000000) == 0)
+ throw(new ArithmeticException("Negative underflow in constructor."));
+ }
+ else { // positive values
+ if((result.data[maxLength-1] & 0x80000000) != 0)
+ throw(new ArithmeticException("Positive overflow in constructor."));
+ }
+
+ data = new uint[maxLength];
+ for(int i = 0; i < result.dataLength; i++)
+ data[i] = result.data[i];
+
+ dataLength = result.dataLength;
+ }
+
+
+ // Constructor (Default value provided by an array of bytes)
+ //
+ // The lowest index of the input byte array (i.e [0]) should contain the
+ // most significant byte of the number, and the highest index should
+ // contain the least significant byte.
+ //
+ // E.g.
+ // To initialize "a" with the default value of 0x1D4F in base 16
+ // byte[] temp = { 0x1D, 0x4F };
+ // BigInteger a = new BigInteger(temp)
+ //
+ // Note that this method of initialization does not allow the
+ // sign to be specified.
+ public BigInteger(byte[] inData)
+ {
+ dataLength = inData.Length >> 2;
+
+ int leftOver = inData.Length & 0x3;
+ if(leftOver != 0) // length not multiples of 4
+ dataLength++;
+
+
+ if(dataLength > maxLength)
+ throw(new ArithmeticException("Byte overflow in constructor."));
+
+ data = new uint[maxLength];
+
+ for(int i = inData.Length - 1, j = 0; i >= 3; i -= 4, j++) {
+ data[j] = (uint)((inData[i-3] << 24) + (inData[i-2] << 16) +
+ (inData[i-1] << 8) + inData[i]);
+ }
+
+ if(leftOver == 1)
+ data[dataLength-1] = (uint)inData[0];
+ else if(leftOver == 2)
+ data[dataLength-1] = (uint)((inData[0] << 8) + inData[1]);
+ else if(leftOver == 3)
+ data[dataLength-1] = (uint)((inData[0] << 16) + (inData[1] << 8) + inData[2]);
+
+
+ while(dataLength > 1 && data[dataLength-1] == 0)
+ dataLength--;
+
+ //Console.WriteLine("Len = " + dataLength);
+ }
+
+ // Constructor (Default value provided by an array of bytes of the
+ // specified length.)
+ public BigInteger(byte[] inData, int inLen)
+ {
+ dataLength = inLen >> 2;
+
+ int leftOver = inLen & 0x3;
+ if(leftOver != 0) // length not multiples of 4
+ dataLength++;
+
+ if(dataLength > maxLength || inLen > inData.Length)
+ throw(new ArithmeticException("Byte overflow in constructor."));
+
+
+ data = new uint[maxLength];
+
+ for(int i = inLen - 1, j = 0; i >= 3; i -= 4, j++) {
+ data[j] = (uint)((inData[i-3] << 24) + (inData[i-2] << 16) +
+ (inData[i-1] << 8) + inData[i]);
+ }
+
+ if(leftOver == 1)
+ data[dataLength-1] = (uint)inData[0];
+ else if(leftOver == 2)
+ data[dataLength-1] = (uint)((inData[0] << 8) + inData[1]);
+ else if(leftOver == 3)
+ data[dataLength-1] = (uint)((inData[0] << 16) + (inData[1] << 8) + inData[2]);
+
+
+ if(dataLength == 0)
+ dataLength = 1;
+
+ while(dataLength > 1 && data[dataLength-1] == 0)
+ dataLength--;
+
+ //Console.WriteLine("Len = " + dataLength);
+ }
+
+
+ // Constructor (Default value provided by an array of unsigned integers)
+ public BigInteger(uint[] inData)
+ {
+ dataLength = inData.Length;
+
+ if(dataLength > maxLength)
+ throw(new ArithmeticException("Byte overflow in constructor."));
+
+ data = new uint[maxLength];
+
+ for(int i = dataLength - 1, j = 0; i >= 0; i--, j++)
+ data[j] = inData[i];
+
+ while(dataLength > 1 && data[dataLength-1] == 0)
+ dataLength--;
+
+ //Console.WriteLine("Len = " + dataLength);
+ }
+
+ private BigRandom rng {
+ get {
+ if (random == null)
+ random = new BigRandom ();
+ return random;
+ }
+ }
+
+ // Overloading of the typecast operator.
+ // For BigInteger bi = 10;
+ public static implicit operator BigInteger (long value)
+ {
+ return (new BigInteger (value));
+ }
+
+ public static implicit operator BigInteger (ulong value)
+ {
+ return (new BigInteger (value));
+ }
+
+ public static implicit operator BigInteger (int value)
+ {
+ return (new BigInteger ( (long)value));
+ }
+
+ public static implicit operator BigInteger (uint value)
+ {
+ return (new BigInteger ( (ulong)value));
+ }
+
+ // Overloading of addition operator
+ public static BigInteger operator + (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger result = new BigInteger ();
+
+ result.dataLength = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+
+ long carry = 0;
+ for(int i = 0; i < result.dataLength; i++) {
+ long sum = (long)bi1.data[i] + (long)bi2.data[i] + carry;
+ carry = sum >> 32;
+ result.data[i] = (uint)(sum & 0xFFFFFFFF);
+ }
+
+ if(carry != 0 && result.dataLength < maxLength) {
+ result.data[result.dataLength] = (uint)(carry);
+ result.dataLength++;
+ }
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+
+ // overflow check
+ int lastPos = maxLength - 1;
+ if((bi1.data[lastPos] & 0x80000000) == (bi2.data[lastPos] & 0x80000000) &&
+ (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) {
+ throw (new ArithmeticException());
+ }
+
+ return result;
+ }
+
+ // Overloading of the unary ++ operator
+ public static BigInteger operator ++ (BigInteger bi1)
+ {
+ BigInteger result = new BigInteger (bi1);
+
+ long val, carry = 1;
+ int index = 0;
+
+ while(carry != 0 && index < maxLength) {
+ val = (long)(result.data[index]);
+ val++;
+
+ result.data[index] = (uint)(val & 0xFFFFFFFF);
+ carry = val >> 32;
+
+ index++;
+ }
+
+ if(index > result.dataLength)
+ result.dataLength = index;
+ else {
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+ }
+
+ // overflow check
+ int lastPos = maxLength - 1;
+
+ // overflow if initial value was +ve but ++ caused a sign
+ // change to negative.
+
+ if((bi1.data[lastPos] & 0x80000000) == 0 &&
+ (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) {
+ throw (new ArithmeticException("Overflow in ++."));
+ }
+ return result;
+ }
+
+ // Overloading of subtraction operator
+ public static BigInteger operator - (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger result = new BigInteger ();
+
+ result.dataLength = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+
+ long carryIn = 0;
+ for(int i = 0; i < result.dataLength; i++) {
+ long diff;
+
+ diff = (long)bi1.data[i] - (long)bi2.data[i] - carryIn;
+ result.data[i] = (uint)(diff & 0xFFFFFFFF);
+
+ if(diff < 0)
+ carryIn = 1;
+ else
+ carryIn = 0;
+ }
+
+ // roll over to negative
+ if(carryIn != 0) {
+ for(int i = result.dataLength; i < maxLength; i++)
+ result.data[i] = 0xFFFFFFFF;
+ result.dataLength = maxLength;
+ }
+
+ // fixed in v1.03 to give correct datalength for a - (-b)
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ // overflow check
+
+ int lastPos = maxLength - 1;
+ if((bi1.data[lastPos] & 0x80000000) != (bi2.data[lastPos] & 0x80000000) &&
+ (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) {
+ throw (new ArithmeticException());
+ }
+
+ return result;
+ }
+
+
+ // Overloading of the unary -- operator
+ public static BigInteger operator -- (BigInteger bi1)
+ {
+ BigInteger result = new BigInteger (bi1);
+
+ long val;
+ bool carryIn = true;
+ int index = 0;
+
+ while(carryIn && index < maxLength) {
+ val = (long)(result.data[index]);
+ val--;
+
+ result.data[index] = (uint)(val & 0xFFFFFFFF);
+
+ if(val >= 0)
+ carryIn = false;
+
+ index++;
+ }
+
+ if(index > result.dataLength)
+ result.dataLength = index;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ // overflow check
+ int lastPos = maxLength - 1;
+
+ // overflow if initial value was -ve but -- caused a sign
+ // change to positive.
+
+ if((bi1.data[lastPos] & 0x80000000) != 0 &&
+ (result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)) {
+ throw (new ArithmeticException("Underflow in --."));
+ }
+
+ return result;
+ }
+
+ // Overloading of multiplication operator
+ public static BigInteger operator * (BigInteger bi1, BigInteger bi2)
+ {
+ int lastPos = maxLength-1;
+ bool bi1Neg = false, bi2Neg = false;
+
+ // take the absolute value of the inputs
+ try {
+ if((bi1.data[lastPos] & 0x80000000) != 0) { // bi1 negative
+ bi1Neg = true; bi1 = -bi1;
+ }
+ if((bi2.data[lastPos] & 0x80000000) != 0) { // bi2 negative
+ bi2Neg = true; bi2 = -bi2;
+ }
+ }
+ catch(Exception) {}
+
+ BigInteger result = new BigInteger();
+
+ // multiply the absolute values
+ try {
+ for(int i = 0; i < bi1.dataLength; i++) {
+ if(bi1.data[i] == 0) continue;
+
+ ulong mcarry = 0;
+ for(int j = 0, k = i; j < bi2.dataLength; j++, k++) {
+ // k = i + j
+ ulong val = ((ulong)bi1.data[i] * (ulong)bi2.data[j]) +
+ (ulong)result.data[k] + mcarry;
+
+ result.data[k] = (uint)(val & 0xFFFFFFFF);
+ mcarry = (val >> 32);
+ }
+
+ if(mcarry != 0)
+ result.data[i+bi2.dataLength] = (uint)mcarry;
+ }
+ }
+ catch(Exception) {
+ throw(new ArithmeticException("Multiplication overflow."));
+ }
+
+
+ result.dataLength = bi1.dataLength + bi2.dataLength;
+ if(result.dataLength > maxLength)
+ result.dataLength = maxLength;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ // overflow check (result is -ve)
+ if((result.data[lastPos] & 0x80000000) != 0) {
+ if(bi1Neg != bi2Neg && result.data[lastPos] == 0x80000000) { // different sign
+ // handle the special case where multiplication produces
+ // a max negative number in 2's complement.
+
+ if(result.dataLength == 1)
+ return result;
+ else {
+ bool isMaxNeg = true;
+ for(int i = 0; i < result.dataLength - 1 && isMaxNeg; i++) {
+ if(result.data[i] != 0)
+ isMaxNeg = false;
+ }
+
+ if(isMaxNeg)
+ return result;
+ }
+ }
+
+ throw(new ArithmeticException("Multiplication overflow."));
+ }
+
+ // if input has different signs, then result is -ve
+ if(bi1Neg != bi2Neg)
+ return -result;
+
+ return result;
+ }
+
+ // Overloading of unary << operators
+ public static BigInteger operator << (BigInteger bi1, int shiftVal)
+ {
+ BigInteger result = new BigInteger (bi1);
+ result.dataLength = shiftLeft(result.data, shiftVal);
+
+ return result;
+ }
+
+ // least significant bits at lower part of buffer
+ private static int shiftLeft (uint[] buffer, int shiftVal)
+ {
+ int shiftAmount = 32;
+ int bufLen = buffer.Length;
+
+ while(bufLen > 1 && buffer[bufLen-1] == 0)
+ bufLen--;
+
+ for(int count = shiftVal; count > 0;) {
+ if(count < shiftAmount)
+ shiftAmount = count;
+
+ //Console.WriteLine("shiftAmount = {0}", shiftAmount);
+
+ ulong carry = 0;
+ for(int i = 0; i < bufLen; i++) {
+ ulong val = ((ulong)buffer[i]) << shiftAmount;
+ val |= carry;
+
+ buffer[i] = (uint)(val & 0xFFFFFFFF);
+ carry = val >> 32;
+ }
+
+ if(carry != 0) {
+ if(bufLen + 1 <= buffer.Length) {
+ buffer[bufLen] = (uint)carry;
+ bufLen++;
+ }
+ }
+ count -= shiftAmount;
+ }
+ return bufLen;
+ }
+
+ // Overloading of unary >> operators
+ public static BigInteger operator >> (BigInteger bi1, int shiftVal)
+ {
+ BigInteger result = new BigInteger(bi1);
+ result.dataLength = shiftRight(result.data, shiftVal);
+
+ if((bi1.data[maxLength-1] & 0x80000000) != 0) { // negative
+ for(int i = maxLength - 1; i >= result.dataLength; i--)
+ result.data[i] = 0xFFFFFFFF;
+
+ uint mask = 0x80000000;
+ for(int i = 0; i < 32; i++) {
+ if((result.data[result.dataLength-1] & mask) != 0)
+ break;
+
+ result.data[result.dataLength-1] |= mask;
+ mask >>= 1;
+ }
+ result.dataLength = maxLength;
+ }
+
+ return result;
+ }
+
+ private static int shiftRight (uint[] buffer, int shiftVal)
+ {
+ int shiftAmount = 32;
+ int invShift = 0;
+ int bufLen = buffer.Length;
+
+ while(bufLen > 1 && buffer[bufLen-1] == 0)
+ bufLen--;
+
+ //Console.WriteLine("bufLen = " + bufLen + " buffer.Length = " + buffer.Length);
+
+ for(int count = shiftVal; count > 0;) {
+ if(count < shiftAmount) {
+ shiftAmount = count;
+ invShift = 32 - shiftAmount;
+ }
+
+ //Console.WriteLine("shiftAmount = {0}", shiftAmount);
+
+ ulong carry = 0;
+ for(int i = bufLen - 1; i >= 0; i--) {
+ ulong val = ((ulong)buffer[i]) >> shiftAmount;
+ val |= carry;
+
+ carry = ((ulong)buffer[i]) << invShift;
+ buffer[i] = (uint)(val);
+ }
+
+ count -= shiftAmount;
+ }
+
+ while(bufLen > 1 && buffer[bufLen-1] == 0)
+ bufLen--;
+
+ return bufLen;
+ }
+
+
+ // Overloading of the NOT operator (1's complement)
+ public static BigInteger operator ~ (BigInteger bi1)
+ {
+ BigInteger result = new BigInteger (bi1);
+
+ for(int i = 0; i < maxLength; i++)
+ result.data[i] = (uint)(~(bi1.data[i]));
+
+ result.dataLength = maxLength;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ return result;
+ }
+
+ // Overloading of the NEGATE operator (2's complement)
+ public static BigInteger operator - (BigInteger bi1)
+ {
+ // handle neg of zero separately since it'll cause an overflow
+ // if we proceed.
+ if(bi1.dataLength == 1 && bi1.data[0] == 0)
+ return (new BigInteger ());
+
+ BigInteger result = new BigInteger (bi1);
+
+ // 1's complement
+ for(int i = 0; i < maxLength; i++)
+ result.data[i] = (uint)(~(bi1.data[i]));
+
+ // add one to result of 1's complement
+ long val, carry = 1;
+ int index = 0;
+
+ while(carry != 0 && index < maxLength) {
+ val = (long)(result.data[index]);
+ val++;
+
+ result.data[index] = (uint)(val & 0xFFFFFFFF);
+ carry = val >> 32;
+
+ index++;
+ }
+
+ if((bi1.data[maxLength-1] & 0x80000000) == (result.data[maxLength-1] & 0x80000000))
+ throw (new ArithmeticException("Overflow in negation.\n"));
+
+ result.dataLength = maxLength;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+ return result;
+ }
+
+
+ // Overloading of equality operator
+ public static bool operator == (BigInteger bi1, BigInteger bi2)
+ {
+ return bi1.Equals (bi2);
+ }
+
+ public static bool operator !=( BigInteger bi1, BigInteger bi2)
+ {
+ return !(bi1.Equals (bi2));
+ }
+
+ public override bool Equals (object o)
+ {
+ BigInteger bi = (BigInteger) o;
+
+ if(this.dataLength != bi.dataLength)
+ return false;
+
+ for(int i = 0; i < this.dataLength; i++) {
+ if(this.data [i] != bi.data [i])
+ return false;
+ }
+ return true;
+ }
+
+ public override int GetHashCode ()
+ {
+ return this.ToString ().GetHashCode ();
+ }
+
+ // Overloading of inequality operator
+ public static bool operator > (BigInteger bi1, BigInteger bi2)
+ {
+ int pos = maxLength - 1;
+
+ // bi1 is negative, bi2 is positive
+ if((bi1.data[pos] & 0x80000000) != 0 && (bi2.data[pos] & 0x80000000) == 0)
+ return false;
+
+ // bi1 is positive, bi2 is negative
+ else if((bi1.data[pos] & 0x80000000) == 0 && (bi2.data[pos] & 0x80000000) != 0)
+ return true;
+
+ // same sign
+ int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+ for(pos = len - 1; pos >= 0 && bi1.data[pos] == bi2.data[pos]; pos--);
+
+ if(pos >= 0) {
+ if(bi1.data[pos] > bi2.data[pos])
+ return true;
+ return false;
+ }
+ return false;
+ }
+
+ public static bool operator < (BigInteger bi1, BigInteger bi2)
+ {
+ int pos = maxLength - 1;
+
+ // bi1 is negative, bi2 is positive
+ if((bi1.data[pos] & 0x80000000) != 0 && (bi2.data[pos] & 0x80000000) == 0)
+ return true;
+
+ // bi1 is positive, bi2 is negative
+ else if((bi1.data[pos] & 0x80000000) == 0 && (bi2.data[pos] & 0x80000000) != 0)
+ return false;
+
+ // same sign
+ int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+ for(pos = len - 1; pos >= 0 && bi1.data[pos] == bi2.data[pos]; pos--);
+
+ if(pos >= 0) {
+ if(bi1.data[pos] < bi2.data[pos])
+ return true;
+ return false;
+ }
+ return false;
+ }
+
+ public static bool operator >= (BigInteger bi1, BigInteger bi2)
+ {
+ return (bi1 == bi2 || bi1 > bi2);
+ }
+
+ public static bool operator <= (BigInteger bi1, BigInteger bi2)
+ {
+ return (bi1 == bi2 || bi1 < bi2);
+ }
+
+ // Private function that supports the division of two numbers with
+ // a divisor that has more than 1 digit.
+ // Algorithm taken from [1]
+ private static void multiByteDivide (BigInteger bi1, BigInteger bi2,
+ BigInteger outQuotient, BigInteger outRemainder)
+ {
+ uint[] result = new uint[maxLength];
+
+ int remainderLen = bi1.dataLength + 1;
+ uint[] remainder = new uint[remainderLen];
+
+ uint mask = 0x80000000;
+ uint val = bi2.data[bi2.dataLength - 1];
+ int shift = 0, resultPos = 0;
+
+ while(mask != 0 && (val & mask) == 0) {
+ shift++; mask >>= 1;
+ }
+
+ //Console.WriteLine("shift = {0}", shift);
+ //Console.WriteLine("Before bi1 Len = {0}, bi2 Len = {1}", bi1.dataLength, bi2.dataLength);
+
+ for (int i = 0; i < bi1.dataLength; i++)
+ remainder[i] = bi1.data[i];
+ shiftLeft (remainder, shift);
+ bi2 = bi2 << shift;
+
+ /*
+ Console.WriteLine("bi1 Len = {0}, bi2 Len = {1}", bi1.dataLength, bi2.dataLength);
+ Console.WriteLine("dividend = " + bi1 + "\ndivisor = " + bi2);
+ for(int q = remainderLen - 1; q >= 0; q--)
+ Console.Write("{0:x2}", remainder[q]);
+ Console.WriteLine();
+ */
+
+ int j = remainderLen - bi2.dataLength;
+ int pos = remainderLen - 1;
+
+ ulong firstDivisorByte = bi2.data[bi2.dataLength-1];
+ ulong secondDivisorByte = bi2.data[bi2.dataLength-2];
+
+ int divisorLen = bi2.dataLength + 1;
+ uint[] dividendPart = new uint[divisorLen];
+
+ while(j > 0) {
+ ulong dividend = ((ulong)remainder[pos] << 32) + (ulong)remainder[pos-1];
+ //Console.WriteLine("dividend = {0}", dividend);
+
+ ulong q_hat = dividend / firstDivisorByte;
+ ulong r_hat = dividend % firstDivisorByte;
+
+ //Console.WriteLine("q_hat = {0:X}, r_hat = {1:X}", q_hat, r_hat);
+
+ bool done = false;
+ while(!done) {
+ done = true;
+
+ if(q_hat == 0x100000000 ||
+ (q_hat * secondDivisorByte) > ((r_hat << 32) + remainder[pos-2])) {
+ q_hat--;
+ r_hat += firstDivisorByte;
+
+ if(r_hat < 0x100000000)
+ done = false;
+ }
+ }
+
+ for (int h = 0; h < divisorLen; h++)
+ dividendPart[h] = remainder[pos-h];
+
+ BigInteger kk = new BigInteger (dividendPart);
+ BigInteger ss = bi2 * (long)q_hat;
+
+ //Console.WriteLine("ss before = " + ss);
+ while(ss > kk) {
+ q_hat--;
+ ss -= bi2;
+ //Console.WriteLine(ss);
+ }
+ BigInteger yy = kk - ss;
+
+ //Console.WriteLine("ss = " + ss);
+ //Console.WriteLine("kk = " + kk);
+ //Console.WriteLine("yy = " + yy);
+
+ for(int h = 0; h < divisorLen; h++)
+ remainder[pos-h] = yy.data[bi2.dataLength-h];
+
+ /*
+ Console.WriteLine("dividend = ");
+ for(int q = remainderLen - 1; q >= 0; q--)
+ Console.Write("{0:x2}", remainder[q]);
+ Console.WriteLine("\n************ q_hat = {0:X}\n", q_hat);
+ */
+
+ result[resultPos++] = (uint)q_hat;
+
+ pos--;
+ j--;
+ }
+
+ outQuotient.dataLength = resultPos;
+ int y = 0;
+ for(int x = outQuotient.dataLength - 1; x >= 0; x--, y++)
+ outQuotient.data[y] = result[x];
+ for(; y < maxLength; y++)
+ outQuotient.data[y] = 0;
+
+ while(outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength-1] == 0)
+ outQuotient.dataLength--;
+
+ if(outQuotient.dataLength == 0)
+ outQuotient.dataLength = 1;
+
+ outRemainder.dataLength = shiftRight(remainder, shift);
+
+ for(y = 0; y < outRemainder.dataLength; y++)
+ outRemainder.data[y] = remainder[y];
+ for(; y < maxLength; y++)
+ outRemainder.data[y] = 0;
+ }
+
+ // Private function that supports the division of two numbers with
+ // a divisor that has only 1 digit.
+ private static void singleByteDivide (BigInteger bi1, BigInteger bi2,
+ BigInteger outQuotient, BigInteger outRemainder)
+ {
+ uint[] result = new uint[maxLength];
+ int resultPos = 0;
+
+ // copy dividend to reminder
+ for(int i = 0; i < maxLength; i++)
+ outRemainder.data[i] = bi1.data[i];
+ outRemainder.dataLength = bi1.dataLength;
+
+ while(outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength-1] == 0)
+ outRemainder.dataLength--;
+
+ ulong divisor = (ulong)bi2.data[0];
+ int pos = outRemainder.dataLength - 1;
+ ulong dividend = (ulong)outRemainder.data[pos];
+
+ //Console.WriteLine("divisor = " + divisor + " dividend = " + dividend);
+ //Console.WriteLine("divisor = " + bi2 + "\ndividend = " + bi1);
+
+ if(dividend >= divisor) {
+ ulong quotient = dividend / divisor;
+ result[resultPos++] = (uint)quotient;
+
+ outRemainder.data[pos] = (uint)(dividend % divisor);
+ }
+ pos--;
+
+ while(pos >= 0) {
+ //Console.WriteLine(pos);
+
+ dividend = ((ulong)outRemainder.data[pos+1] << 32) + (ulong)outRemainder.data[pos];
+ ulong quotient = dividend / divisor;
+ result[resultPos++] = (uint)quotient;
+
+ outRemainder.data[pos+1] = 0;
+ outRemainder.data[pos--] = (uint)(dividend % divisor);
+ //Console.WriteLine(">>>> " + bi1);
+ }
+
+ outQuotient.dataLength = resultPos;
+ int j = 0;
+ for(int i = outQuotient.dataLength - 1; i >= 0; i--, j++)
+ outQuotient.data[j] = result[i];
+ for(; j < maxLength; j++)
+ outQuotient.data[j] = 0;
+
+ while(outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength-1] == 0)
+ outQuotient.dataLength--;
+
+ if(outQuotient.dataLength == 0)
+ outQuotient.dataLength = 1;
+
+ while(outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength-1] == 0)
+ outRemainder.dataLength--;
+ }
+
+ // Overloading of division operator
+ public static BigInteger operator / (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger quotient = new BigInteger();
+ BigInteger remainder = new BigInteger();
+
+ int lastPos = maxLength-1;
+ bool divisorNeg = false, dividendNeg = false;
+
+ if((bi1.data[lastPos] & 0x80000000) != 0) { // bi1 negative
+ bi1 = -bi1;
+ dividendNeg = true;
+ }
+ if((bi2.data[lastPos] & 0x80000000) != 0) { // bi2 negative
+ bi2 = -bi2;
+ divisorNeg = true;
+ }
+
+ if(bi1 < bi2) {
+ return quotient;
+ }
+
+ else {
+ if(bi2.dataLength == 1)
+ singleByteDivide(bi1, bi2, quotient, remainder);
+ else
+ multiByteDivide(bi1, bi2, quotient, remainder);
+
+ if(dividendNeg != divisorNeg)
+ return -quotient;
+
+ return quotient;
+ }
+ }
+
+ // Overloading of modulus operator
+ public static BigInteger operator % (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger quotient = new BigInteger();
+ BigInteger remainder = new BigInteger(bi1);
+
+ int lastPos = maxLength-1;
+ bool dividendNeg = false;
+
+ if((bi1.data[lastPos] & 0x80000000) != 0) { // bi1 negative
+ bi1 = -bi1;
+ dividendNeg = true;
+ }
+ if((bi2.data[lastPos] & 0x80000000) != 0) // bi2 negative
+ bi2 = -bi2;
+
+ if(bi1 < bi2) {
+ return remainder;
+ }
+
+ else {
+ if(bi2.dataLength == 1)
+ singleByteDivide(bi1, bi2, quotient, remainder);
+ else
+ multiByteDivide(bi1, bi2, quotient, remainder);
+
+ if(dividendNeg)
+ return -remainder;
+
+ return remainder;
+ }
+ }
+
+ // Overloading of bitwise AND operator
+ public static BigInteger operator & (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger result = new BigInteger();
+
+ int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+
+ for(int i = 0; i < len; i++) {
+ uint sum = (uint)(bi1.data[i] & bi2.data[i]);
+ result.data[i] = sum;
+ }
+
+ result.dataLength = maxLength;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ return result;
+ }
+
+ // Overloading of bitwise OR operator
+ public static BigInteger operator | (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger result = new BigInteger();
+
+ int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+
+ for(int i = 0; i < len; i++) {
+ uint sum = (uint)(bi1.data[i] | bi2.data[i]);
+ result.data[i] = sum;
+ }
+
+ result.dataLength = maxLength;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ return result;
+ }
+
+ // Overloading of bitwise XOR operator
+ public static BigInteger operator ^ (BigInteger bi1, BigInteger bi2)
+ {
+ BigInteger result = new BigInteger();
+
+ int len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;
+
+ for(int i = 0; i < len; i++) {
+ uint sum = (uint)(bi1.data[i] ^ bi2.data[i]);
+ result.data[i] = sum;
+ }
+
+ result.dataLength = maxLength;
+
+ while(result.dataLength > 1 && result.data[result.dataLength-1] == 0)
+ result.dataLength--;
+
+ return result;
+ }
+
+ // Returns max(this, bi)
+ public BigInteger max (BigInteger bi)
+ {
+ if(this > bi)
+ return (new BigInteger(this));
+ else
+ return (new BigInteger(bi));
+ }
+
+ // Returns min(this, bi)
+ public BigInteger min (BigInteger bi)
+ {
+ if (this < bi)
+ return (new BigInteger (this));
+ else
+ return (new BigInteger (bi));
+ }
+
+ // Returns the absolute value
+ public BigInteger abs ()
+ {
+ if((this.data[maxLength - 1] & 0x80000000) != 0)
+ return (-this);
+ else
+ return (new BigInteger (this));
+ }
+
+ // Returns a string representing the BigInteger in base 10.
+ public override string ToString ()
+ {
+ return ToString (10);
+ }
+
+ // Returns a string representing the BigInteger in sign-and-magnitude
+ // format in the specified radix.
+ //
+ // Example
+ // -------
+ // If the value of BigInteger is -255 in base 10, then
+ // ToString(16) returns "-FF"
+ public string ToString (int radix)
+ {
+ if(radix < 2 || radix > 36)
+ throw (new ArgumentException("Radix must be >= 2 and <= 36"));
+
+ string charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ string result = "";
+
+ BigInteger a = this;
+
+ bool negative = false;
+ if((a.data[maxLength-1] & 0x80000000) != 0) {
+ negative = true;
+ try {
+ a = -a;
+ }
+ catch(Exception) {}
+ }
+
+ BigInteger quotient = new BigInteger();
+ BigInteger remainder = new BigInteger();
+ BigInteger biRadix = new BigInteger(radix);
+
+ if(a.dataLength == 1 && a.data[0] == 0)
+ result = "0";
+ else {
+ while(a.dataLength > 1 || (a.dataLength == 1 && a.data[0] != 0)) {
+ singleByteDivide(a, biRadix, quotient, remainder);
+
+ if(remainder.data[0] < 10)
+ result = remainder.data[0] + result;
+ else
+ result = charSet[(int)remainder.data[0] - 10] + result;
+
+ a = quotient;
+ }
+ if(negative)
+ result = "-" + result;
+ }
+
+ return result;
+ }
+
+
+ // Returns a hex string showing the contains of the BigInteger
+ //
+ // Examples
+ // -------
+ // 1) If the value of BigInteger is 255 in base 10, then
+ // ToHexString() returns "FF"
+ //
+ // 2) If the value of BigInteger is -255 in base 10, then
+ // ToHexString() returns ".....FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01",
+ // which is the 2's complement representation of -255.
+ public string ToHexString ()
+ {
+ string result = data[dataLength - 1].ToString("X");
+
+ for(int i = dataLength - 2; i >= 0; i--) {
+ result += data[i].ToString("X8");
+ }
+
+ return result;
+ }
+
+ // Modulo Exponentiation
+ public BigInteger modPow(BigInteger exp, BigInteger n)
+ {
+ if((exp.data[maxLength-1] & 0x80000000) != 0)
+ throw (new ArithmeticException("Positive exponents only."));
+
+ BigInteger resultNum = 1;
+ BigInteger tempNum;
+ bool thisNegative = false;
+
+ if((this.data[maxLength-1] & 0x80000000) != 0) { // negative this
+ tempNum = -this % n;
+ thisNegative = true;
+ }
+ else
+ tempNum = this % n; // ensures (tempNum * tempNum) < b^(2k)
+
+ if((n.data[maxLength-1] & 0x80000000) != 0) // negative n
+ n = -n;
+
+ // calculate constant = b^(2k) / m
+ BigInteger constant = new BigInteger ();
+
+ int i = n.dataLength << 1;
+ constant.data[i] = 0x00000001;
+ constant.dataLength = i + 1;
+
+ constant = constant / n;
+ int totalBits = exp.bitCount ();
+ int count = 0;
+
+ // perform squaring and multiply exponentiation
+ for(int pos = 0; pos < exp.dataLength; pos++) {
+ uint mask = 0x01;
+ //Console.WriteLine("pos = " + pos);
+
+ for(int index = 0; index < 32; index++) {
+ if((exp.data[pos] & mask) != 0)
+ resultNum = BarrettReduction(resultNum * tempNum, n, constant);
+
+ mask <<= 1;
+
+ tempNum = BarrettReduction(tempNum * tempNum, n, constant);
+
+
+ if(tempNum.dataLength == 1 && tempNum.data[0] == 1) {
+ if(thisNegative && (exp.data[0] & 0x1) != 0) //odd exp
+ return -resultNum;
+ return resultNum;
+ }
+ count++;
+ if(count == totalBits)
+ break;
+ }
+ }
+
+ if(thisNegative && (exp.data[0] & 0x1) != 0) //odd exp
+ return -resultNum;
+
+ return resultNum;
+ }
+
+ // Fast calculation of modular reduction using Barrett's reduction.
+ // Requires x < b^(2k), where b is the base. In this case, base is
+ // 2^32 (uint).
+ // Reference [4]
+ private BigInteger BarrettReduction(BigInteger x, BigInteger n, BigInteger constant)
+ {
+ int k = n.dataLength,
+ kPlusOne = k+1,
+ kMinusOne = k-1;
+
+ BigInteger q1 = new BigInteger ();
+
+ // q1 = x / b^(k-1)
+ for(int i = kMinusOne, j = 0; i < x.dataLength; i++, j++)
+ q1.data[j] = x.data[i];
+ q1.dataLength = x.dataLength - kMinusOne;
+ if(q1.dataLength <= 0)
+ q1.dataLength = 1;
+
+
+ BigInteger q2 = q1 * constant;
+ BigInteger q3 = new BigInteger();
+
+ // q3 = q2 / b^(k+1)
+ for(int i = kPlusOne, j = 0; i < q2.dataLength; i++, j++)
+ q3.data[j] = q2.data[i];
+ q3.dataLength = q2.dataLength - kPlusOne;
+ if(q3.dataLength <= 0)
+ q3.dataLength = 1;
+
+ // r1 = x mod b^(k+1)
+ // i.e. keep the lowest (k+1) words
+ BigInteger r1 = new BigInteger();
+ int lengthToCopy = (x.dataLength > kPlusOne) ? kPlusOne : x.dataLength;
+ for(int i = 0; i < lengthToCopy; i++)
+ r1.data[i] = x.data[i];
+ r1.dataLength = lengthToCopy;
+
+ // r2 = (q3 * n) mod b^(k+1)
+ // partial multiplication of q3 and n
+
+ BigInteger r2 = new BigInteger();
+ for(int i = 0; i < q3.dataLength; i++) {
+ if(q3.data[i] == 0) continue;
+
+ ulong mcarry = 0;
+ int t = i;
+ for(int j = 0; j < n.dataLength && t < kPlusOne; j++, t++) {
+ // t = i + j
+ ulong val = ((ulong)q3.data[i] * (ulong)n.data[j]) +
+ (ulong)r2.data[t] + mcarry;
+
+ r2.data[t] = (uint)(val & 0xFFFFFFFF);
+ mcarry = (val >> 32);
+ }
+
+ if(t < kPlusOne)
+ r2.data[t] = (uint)mcarry;
+ }
+ r2.dataLength = kPlusOne;
+ while(r2.dataLength > 1 && r2.data[r2.dataLength-1] == 0)
+ r2.dataLength--;
+
+ r1 -= r2;
+ if((r1.data[maxLength-1] & 0x80000000) != 0) { // negative
+ BigInteger val = new BigInteger();
+ val.data[kPlusOne] = 0x00000001;
+ val.dataLength = kPlusOne + 1;
+ r1 += val;
+ }
+
+ while(r1 >= n)
+ r1 -= n;
+
+ return r1;
+ }
+
+ // Returns gcd(this, bi)
+ public BigInteger gcd(BigInteger bi)
+ {
+ BigInteger x;
+ BigInteger y;
+
+ if((data[maxLength-1] & 0x80000000) != 0) // negative
+ x = -this;
+ else
+ x = this;
+
+ if((bi.data[maxLength-1] & 0x80000000) != 0) // negative
+ y = -bi;
+ else
+ y = bi;
+
+ BigInteger g = y;
+
+ while(x.dataLength > 1 || (x.dataLength == 1 && x.data[0] != 0)) {
+ g = x;
+ x = y % x;
+ y = g;
+ }
+
+ return g;
+ }
+
+ // Populates "this" with the specified amount of random bits
+ public void genRandomBits (int bits)
+ {
+ genRandomBits (bits, new BigRandom ());
+ }
+
+ public void genRandomBits (int bits, BigRandom rng)
+ {
+ int dwords = bits >> 5;
+ int remBits = bits & 0x1F;
+
+ if (remBits != 0)
+ dwords++;
+
+ if (dwords > maxLength)
+ throw (new ArithmeticException("Number of required bits > maxLength."));
+
+ rng.Get (data);
+ for (int i = dwords; i < maxLength; i++)
+ data[i] = 0;
+
+ if (remBits != 0) {
+ uint mask = (uint)(0x01 << (remBits-1));
+ data[dwords-1] |= mask;
+
+ mask = (uint)(0xFFFFFFFF >> (32 - remBits));
+ data[dwords-1] &= mask;
+ }
+ else
+ data[dwords-1] |= 0x80000000;
+
+ dataLength = dwords;
+
+ if (dataLength == 0)
+ dataLength = 1;
+ }
+
+ // Returns the position of the most significant bit in the BigInteger.
+ // Eg. The result is 0, if the value of BigInteger is 0...0000 0000
+ // The result is 1, if the value of BigInteger is 0...0000 0001
+ // The result is 2, if the value of BigInteger is 0...0000 0010
+ // The result is 2, if the value of BigInteger is 0...0000 0011
+ public int bitCount ()
+ {
+ while(dataLength > 1 && data[dataLength-1] == 0)
+ dataLength--;
+
+ uint value = data[dataLength - 1];
+ uint mask = 0x80000000;
+ int bits = 32;
+
+ while(bits > 0 && (value & mask) == 0) {
+ bits--;
+ mask >>= 1;
+ }
+ bits += ((dataLength - 1) << 5);
+
+ return bits;
+ }
+
+ // Probabilistic prime test based on Fermat's little theorem
+ //
+ // for any a < p (p does not divide a) if
+ // a^(p-1) mod p != 1 then p is not prime.
+ //
+ // Otherwise, p is probably prime (pseudoprime to the chosen base).
+ //
+ // Returns
+ // -------
+ // True if "this" is a pseudoprime to randomly chosen
+ // bases. The number of chosen bases is given by the "confidence"
+ // parameter.
+ //
+ // False if "this" is definitely NOT prime.
+ //
+ // Note - this method is fast but fails for Carmichael numbers except
+ // when the randomly chosen base is a factor of the number.
+ public bool FermatLittleTest (int confidence)
+ {
+ BigInteger thisVal;
+ if((this.data[maxLength-1] & 0x80000000) != 0) // negative
+ thisVal = -this;
+ else
+ thisVal = this;
+
+ if(thisVal.dataLength == 1) {
+ // test small numbers
+ if(thisVal.data[0] == 0 || thisVal.data[0] == 1)
+ return false;
+ else if(thisVal.data[0] == 2 || thisVal.data[0] == 3)
+ return true;
+ }
+
+ if((thisVal.data[0] & 0x1) == 0) // even numbers
+ return false;
+
+ int bits = thisVal.bitCount();
+ BigInteger a = new BigInteger();
+ BigInteger p_sub1 = thisVal - (new BigInteger(1));
+
+ for(int round = 0; round < confidence; round++) {
+ bool done = false;
+
+ while(!done) { // generate a < n
+ int testBits = 0;
+
+ // make sure "a" has at least 2 bits
+ while(testBits < 2)
+ testBits = rng.GetInt (bits);
+
+ a.genRandomBits (testBits);
+
+ int byteLen = a.dataLength;
+
+ // make sure "a" is not 0
+ if(byteLen > 1 || (byteLen == 1 && a.data[0] != 1))
+ done = true;
+ }
+
+ // check whether a factor exists (fix for version 1.03)
+ BigInteger gcdTest = a.gcd(thisVal);
+ if(gcdTest.dataLength == 1 && gcdTest.data[0] != 1)
+ return false;
+
+ // calculate a^(p-1) mod p
+ BigInteger expResult = a.modPow(p_sub1, thisVal);
+
+ int resultLen = expResult.dataLength;
+
+ // is NOT prime is a^(p-1) mod p != 1
+
+ if(resultLen > 1 || (resultLen == 1 && expResult.data[0] != 1)) {
+ //Console.WriteLine("a = " + a.ToString());
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // Probabilistic prime test based on Rabin-Miller's
+ //
+ // for any p > 0 with p - 1 = 2^s * t
+ //
+ // p is probably prime (strong pseudoprime) if for any a < p,
+ // 1) a^t mod p = 1 or
+ // 2) a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1
+ //
+ // Otherwise, p is composite.
+ //
+ // Returns
+ // -------
+ // True if "this" is a strong pseudoprime to randomly chosen
+ // bases. The number of chosen bases is given by the "confidence"
+ // parameter.
+ //
+ // False if "this" is definitely NOT prime.
+ public bool RabinMillerTest(int confidence)
+ {
+ BigInteger thisVal;
+ if((this.data[maxLength-1] & 0x80000000) != 0) // negative
+ thisVal = -this;
+ else
+ thisVal = this;
+
+ if(thisVal.dataLength == 1) {
+ // test small numbers
+ if(thisVal.data[0] == 0 || thisVal.data[0] == 1)
+ return false;
+ else if(thisVal.data[0] == 2 || thisVal.data[0] == 3)
+ return true;
+ }
+
+ if((thisVal.data[0] & 0x1) == 0) // even numbers
+ return false;
+
+ // calculate values of s and t
+ BigInteger p_sub1 = thisVal - (new BigInteger(1));
+ int s = 0;
+
+ for(int index = 0; index < p_sub1.dataLength; index++) {
+ uint mask = 0x01;
+
+ for(int i = 0; i < 32; i++) {
+ if((p_sub1.data[index] & mask) != 0) {
+ index = p_sub1.dataLength; // to break the outer loop
+ break;
+ }
+ mask <<= 1;
+ s++;
+ }
+ }
+
+ BigInteger t = p_sub1 >> s;
+
+ int bits = thisVal.bitCount();
+ BigInteger a = new BigInteger();
+
+ for(int round = 0; round < confidence; round++) {
+ bool done = false;
+
+ while(!done) { // generate a < n
+ int testBits = 0;
+
+ // make sure "a" has at least 2 bits
+ while(testBits < 2)
+ testBits = rng.GetInt (bits);
+
+ a.genRandomBits (testBits);
+
+ int byteLen = a.dataLength;
+
+ // make sure "a" is not 0
+ if(byteLen > 1 || (byteLen == 1 && a.data[0] != 1))
+ done = true;
+ }
+
+ // check whether a factor exists (fix for version 1.03)
+ BigInteger gcdTest = a.gcd(thisVal);
+ if(gcdTest.dataLength == 1 && gcdTest.data[0] != 1)
+ return false;
+
+ BigInteger b = a.modPow(t, thisVal);
+
+ /*
+ Console.WriteLine("a = " + a.ToString(10));
+ Console.WriteLine("b = " + b.ToString(10));
+ Console.WriteLine("t = " + t.ToString(10));
+ Console.WriteLine("s = " + s);
+ */
+
+ bool result = false;
+
+ if(b.dataLength == 1 && b.data[0] == 1) // a^t mod p = 1
+ result = true;
+
+ for(int j = 0; result == false && j < s; j++) {
+ if(b == p_sub1) { // a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1
+ result = true;
+ break;
+ }
+
+ b = (b * b) % thisVal;
+ }
+
+ if(result == false)
+ return false;
+ }
+ return true;
+ }
+
+ // Probabilistic prime test based on Solovay-Strassen (Euler Criterion)
+ //
+ // p is probably prime if for any a < p (a is not multiple of p),
+ // a^((p-1)/2) mod p = J(a, p)
+ //
+ // where J is the Jacobi symbol.
+ //
+ // Otherwise, p is composite.
+ //
+ // Returns
+ // -------
+ // True if "this" is a Euler pseudoprime to randomly chosen
+ // bases. The number of chosen bases is given by the "confidence"
+ // parameter.
+ //
+ // False if "this" is definitely NOT prime.
+ public bool SolovayStrassenTest(int confidence)
+ {
+ BigInteger thisVal;
+ if((this.data[maxLength-1] & 0x80000000) != 0) // negative
+ thisVal = -this;
+ else
+ thisVal = this;
+
+ if(thisVal.dataLength == 1) {
+ // test small numbers
+ if(thisVal.data[0] == 0 || thisVal.data[0] == 1)
+ return false;
+ else if(thisVal.data[0] == 2 || thisVal.data[0] == 3)
+ return true;
+ }
+
+ if((thisVal.data[0] & 0x1) == 0) // even numbers
+ return false;
+
+ int bits = thisVal.bitCount();
+ BigInteger a = new BigInteger();
+ BigInteger p_sub1 = thisVal - 1;
+ BigInteger p_sub1_shift = p_sub1 >> 1;
+
+ for(int round = 0; round < confidence; round++) {
+ bool done = false;
+
+ while(!done) { // generate a < n
+ int testBits = 0;
+
+ // make sure "a" has at least 2 bits
+ while(testBits < 2)
+ testBits = rng.GetInt (bits);
+
+ a.genRandomBits (testBits);
+
+ int byteLen = a.dataLength;
+
+ // make sure "a" is not 0
+ if(byteLen > 1 || (byteLen == 1 && a.data[0] != 1))
+ done = true;
+ }
+
+ // check whether a factor exists (fix for version 1.03)
+ BigInteger gcdTest = a.gcd(thisVal);
+ if(gcdTest.dataLength == 1 && gcdTest.data[0] != 1)
+ return false;
+
+ // calculate a^((p-1)/2) mod p
+
+ BigInteger expResult = a.modPow(p_sub1_shift, thisVal);
+ if(expResult == p_sub1)
+ expResult = -1;
+
+ // calculate Jacobi symbol
+ BigInteger jacob = Jacobi(a, thisVal);
+
+ //Console.WriteLine("a = " + a.ToString(10) + " b = " + thisVal.ToString(10));
+ //Console.WriteLine("expResult = " + expResult.ToString(10) + " Jacob = " + jacob.ToString(10));
+
+ // if they are different then it is not prime
+ if(expResult != jacob)
+ return false;
+ }
+
+ return true;
+ }
+
+ // Implementation of the Lucas Strong Pseudo Prime test.
+ //
+ // Let n be an odd number with gcd(n,D) = 1, and n - J(D, n) = 2^s * d
+ // with d odd and s >= 0.
+ //
+ // If Ud mod n = 0 or V2^r*d mod n = 0 for some 0 <= r < s, then n
+ // is a strong Lucas pseudoprime with parameters (P, Q). We select
+ // P and Q based on Selfridge.
+ //
+ // Returns True if number is a strong Lucus pseudo prime.
+ // Otherwise, returns False indicating that number is composite.
+ public bool LucasStrongTest()
+ {
+ BigInteger thisVal;
+ if((this.data[maxLength-1] & 0x80000000) != 0) // negative
+ thisVal = -this;
+ else
+ thisVal = this;
+
+ if(thisVal.dataLength == 1) {
+ // test small numbers
+ if(thisVal.data[0] == 0 || thisVal.data[0] == 1)
+ return false;
+ else if(thisVal.data[0] == 2 || thisVal.data[0] == 3)
+ return true;
+ }
+
+ if((thisVal.data[0] & 0x1) == 0) // even numbers
+ return false;
+
+ return LucasStrongTestHelper(thisVal);
+ }
+
+ private bool LucasStrongTestHelper(BigInteger thisVal)
+ {
+ // Do the test (selects D based on Selfridge)
+ // Let D be the first element of the sequence
+ // 5, -7, 9, -11, 13, ... for which J(D,n) = -1
+ // Let P = 1, Q = (1-D) / 4
+
+ long D = 5, sign = -1, dCount = 0;
+ bool done = false;
+
+ while(!done) {
+ int Jresult = BigInteger.Jacobi(D, thisVal);
+
+ if(Jresult == -1)
+ done = true; // J(D, this) = 1
+ else {
+ if(Jresult == 0 && System.Math.Abs(D) < thisVal) // divisor found
+ return false;
+
+ if(dCount == 20) {
+ // check for square
+ BigInteger root = thisVal.sqrt();
+ if(root * root == thisVal)
+ return false;
+ }
+
+ //Console.WriteLine(D);
+ D = (System.Math.Abs(D) + 2) * sign;
+ sign = -sign;
+ }
+ dCount++;
+ }
+
+ long Q = (1 - D) >> 2;
+
+ /*
+ Console.WriteLine("D = " + D);
+ Console.WriteLine("Q = " + Q);
+ Console.WriteLine("(n,D) = " + thisVal.gcd(D));
+ Console.WriteLine("(n,Q) = " + thisVal.gcd(Q));
+ Console.WriteLine("J(D|n) = " + BigInteger.Jacobi(D, thisVal));
+ */
+
+ BigInteger p_add1 = thisVal + 1;
+ int s = 0;
+
+ for(int index = 0; index < p_add1.dataLength; index++) {
+ uint mask = 0x01;
+
+ for(int i = 0; i < 32; i++) {
+ if((p_add1.data[index] & mask) != 0) {
+ index = p_add1.dataLength; // to break the outer loop
+ break;
+ }
+ mask <<= 1;
+ s++;
+ }
+ }
+
+ BigInteger t = p_add1 >> s;
+
+ // calculate constant = b^(2k) / m
+ // for Barrett Reduction
+ BigInteger constant = new BigInteger();
+
+ int nLen = thisVal.dataLength << 1;
+ constant.data[nLen] = 0x00000001;
+ constant.dataLength = nLen + 1;
+
+ constant = constant / thisVal;
+
+ BigInteger[] lucas = LucasSequenceHelper(1, Q, t, thisVal, constant, 0);
+ bool isPrime = false;
+
+ if((lucas[0].dataLength == 1 && lucas[0].data[0] == 0) ||
+ (lucas[1].dataLength == 1 && lucas[1].data[0] == 0)) {
+ // u(t) = 0 or V(t) = 0
+ isPrime = true;
+ }
+
+ for(int i = 1; i < s; i++) {
+ if(!isPrime) {
+ // doubling of index
+ lucas[1] = thisVal.BarrettReduction(lucas[1] * lucas[1], thisVal, constant);
+ lucas[1] = (lucas[1] - (lucas[2] << 1)) % thisVal;
+
+ //lucas[1] = ((lucas[1] * lucas[1]) - (lucas[2] << 1)) % thisVal;
+
+ if((lucas[1].dataLength == 1 && lucas[1].data[0] == 0))
+ isPrime = true;
+ }
+
+ lucas[2] = thisVal.BarrettReduction(lucas[2] * lucas[2], thisVal, constant); //Q^k
+ }
+
+
+ if(isPrime) { // additional checks for composite numbers
+ // If n is prime and gcd(n, Q) == 1, then
+ // Q^((n+1)/2) = Q * Q^((n-1)/2) is congruent to (Q * J(Q, n)) mod n
+
+ BigInteger g = thisVal.gcd(Q);
+ if(g.dataLength == 1 && g.data[0] == 1) { // gcd(this, Q) == 1
+ if((lucas[2].data[maxLength-1] & 0x80000000) != 0)
+ lucas[2] += thisVal;
+
+ BigInteger temp = (Q * BigInteger.Jacobi(Q, thisVal)) % thisVal;
+ if((temp.data[maxLength-1] & 0x80000000) != 0)
+ temp += thisVal;
+
+ if(lucas[2] != temp)
+ isPrime = false;
+ }
+ }
+
+ return isPrime;
+ }
+
+ // Determines whether a number is probably prime, using the Rabin-Miller's
+ // test. Before applying the test, the number is tested for divisibility
+ // by primes < 2000
+ //
+ // Returns true if number is probably prime.
+ public bool isProbablePrime(int confidence)
+ {
+ BigInteger thisVal;
+ if((this.data[maxLength-1] & 0x80000000) != 0) // negative
+ thisVal = -this;
+ else
+ thisVal = this;
+
+
+ // test for divisibility by primes < 2000
+ for(int p = 0; p < primesBelow2000.Length; p++) {
+ BigInteger divisor = primesBelow2000[p];
+
+ if(divisor >= thisVal)
+ break;
+
+ BigInteger resultNum = thisVal % divisor;
+ if(resultNum.IntValue() == 0) {
+ /*
+ Console.WriteLine("Not prime! Divisible by {0}\n",
+ primesBelow2000[p]);
+ */
+ return false;
+ }
+ }
+
+ if(thisVal.RabinMillerTest(confidence))
+ return true;
+ else {
+ //Console.WriteLine("Not prime! Failed primality test\n");
+ return false;
+ }
+ }
+
+ // Determines whether this BigInteger is probably prime using a
+ // combination of base 2 strong pseudoprime test and Lucas strong
+ // pseudoprime test.
+ //
+ // The sequence of the primality test is as follows,
+ //
+ // 1) Trial divisions are carried out using prime numbers below 2000.
+ // if any of the primes divides this BigInteger, then it is not prime.
+ //
+ // 2) Perform base 2 strong pseudoprime test. If this BigInteger is a
+ // base 2 strong pseudoprime, proceed on to the next step.
+ //
+ // 3) Perform strong Lucas pseudoprime test.
+ //
+ // Returns True if this BigInteger is both a base 2 strong pseudoprime
+ // and a strong Lucas pseudoprime.
+ //
+ // For a detailed discussion of this primality test, see [6].
+ public bool isProbablePrime()
+ {
+ BigInteger thisVal;
+ if((this.data[maxLength-1] & 0x80000000) != 0) // negative
+ thisVal = -this;
+ else
+ thisVal = this;
+
+ if(thisVal.dataLength == 1) {
+ // test small numbers
+ if(thisVal.data[0] == 0 || thisVal.data[0] == 1)
+ return false;
+ else if(thisVal.data[0] == 2 || thisVal.data[0] == 3)
+ return true;
+ }
+
+ if((thisVal.data[0] & 0x1) == 0) // even numbers
+ return false;
+
+ // test for divisibility by primes < 2000
+ for(int p = 0; p < primesBelow2000.Length; p++) {
+ BigInteger divisor = primesBelow2000[p];
+
+ if(divisor >= thisVal)
+ break;
+
+ BigInteger resultNum = thisVal % divisor;
+ if(resultNum.IntValue() == 0) {
+ //Console.WriteLine("Not prime! Divisible by {0}\n",
+ // primesBelow2000[p]);
+
+ return false;
+ }
+ }
+
+ // Perform BASE 2 Rabin-Miller Test
+
+ // calculate values of s and t
+ BigInteger p_sub1 = thisVal - (new BigInteger(1));
+ int s = 0;
+
+ for(int index = 0; index < p_sub1.dataLength; index++) {
+ uint mask = 0x01;
+
+ for(int i = 0; i < 32; i++) {
+ if((p_sub1.data[index] & mask) != 0) {
+ index = p_sub1.dataLength; // to break the outer loop
+ break;
+ }
+ mask <<= 1;
+ s++;
+ }
+ }
+
+ BigInteger t = p_sub1 >> s;
+
+ int bits = thisVal.bitCount();
+ BigInteger a = 2;
+
+ // b = a^t mod p
+ BigInteger b = a.modPow(t, thisVal);
+ bool result = false;
+
+ if(b.dataLength == 1 && b.data[0] == 1) // a^t mod p = 1
+ result = true;
+
+ for(int j = 0; result == false && j < s; j++) {
+ if(b == p_sub1) { // a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1
+ result = true;
+ break;
+ }
+
+ b = (b * b) % thisVal;
+ }
+
+ // if number is strong pseudoprime to base 2, then do a strong lucas test
+ if(result)
+ result = LucasStrongTestHelper(thisVal);
+
+ return result;
+ }
+
+ // Returns the lowest 4 bytes of the BigInteger as an int.
+ public int IntValue ()
+ {
+ return (int)data[0];
+ }
+
+ // Returns the lowest 8 bytes of the BigInteger as a long.
+ public long LongValue ()
+ {
+ long val = 0;
+
+ val = (long)data[0];
+ try {
+ // exception if maxLength = 1
+ val |= (long)data[1] << 32;
+ }
+ catch(Exception) {
+ if((data[0] & 0x80000000) != 0) // negative
+ val = (int)data[0];
+ }
+
+ return val;
+ }
+
+ // Computes the Jacobi Symbol for a and b.
+ // Algorithm adapted from [3] and [4] with some optimizations
+ public static int Jacobi (BigInteger a, BigInteger b)
+ {
+ // Jacobi defined only for odd integers
+ if((b.data[0] & 0x1) == 0)
+ throw (new ArgumentException("Jacobi defined only for odd integers."));
+
+ if(a >= b) a %= b;
+ if(a.dataLength == 1 && a.data[0] == 0) return 0; // a == 0
+ if(a.dataLength == 1 && a.data[0] == 1) return 1; // a == 1
+
+ if(a < 0) {
+ if( (((b-1).data[0]) & 0x2) == 0) //if( (((b-1) >> 1).data[0] & 0x1) == 0)
+ return Jacobi(-a, b);
+ else
+ return -Jacobi(-a, b);
+ }
+
+ int e = 0;
+ for(int index = 0; index < a.dataLength; index++) {
+ uint mask = 0x01;
+
+ for(int i = 0; i < 32; i++) {
+ if((a.data[index] & mask) != 0) {
+ index = a.dataLength; // to break the outer loop
+ break;
+ }
+ mask <<= 1;
+ e++;
+ }
+ }
+
+ BigInteger a1 = a >> e;
+
+ int s = 1;
+ if((e & 0x1) != 0 && ((b.data[0] & 0x7) == 3 || (b.data[0] & 0x7) == 5))
+ s = -1;
+
+ if((b.data[0] & 0x3) == 3 && (a1.data[0] & 0x3) == 3)
+ s = -s;
+
+ if(a1.dataLength == 1 && a1.data[0] == 1)
+ return s;
+ else
+ return (s * Jacobi(b % a1, a1));
+ }
+
+ // Generates a positive BigInteger that is probably prime.
+ public static BigInteger genPseudoPrime (int bits, int confidence)
+ {
+ BigInteger result = new BigInteger ();
+ bool done = false;
+
+ while (!done) {
+ result.genRandomBits (bits);
+ result.data[0] |= 0x01; // make it odd
+ // prime test
+ done = result.isProbablePrime(confidence);
+ }
+ return result;
+ }
+
+ // Generates a random number with the specified number of bits such
+ // that gcd(number, this) = 1
+ public BigInteger genCoPrime (int bits)
+ {
+ bool done = false;
+ BigInteger result = new BigInteger ();
+
+ while(!done) {
+ result.genRandomBits (bits);
+ //Console.WriteLine(result.ToString(16));
+
+ // gcd test
+ BigInteger g = result.gcd(this);
+ if (g.dataLength == 1 && g.data[0] == 1)
+ done = true;
+ }
+
+ return result;
+ }
+
+ // Returns the modulo inverse of this. Throws ArithmeticException if
+ // the inverse does not exist. (i.e. gcd(this, modulus) != 1)
+ public BigInteger modInverse (BigInteger modulus)
+ {
+ BigInteger[] p = { 0, 1 };
+ BigInteger[] q = new BigInteger[2]; // quotients
+ BigInteger[] r = { 0, 0 }; // remainders
+
+ int step = 0;
+
+ BigInteger a = modulus;
+ BigInteger b = this;
+
+ while(b.dataLength > 1 || (b.dataLength == 1 && b.data[0] != 0)) {
+ BigInteger quotient = new BigInteger();
+ BigInteger remainder = new BigInteger();
+
+ if(step > 1) {
+ BigInteger pval = (p[0] - (p[1] * q[0])) % modulus;
+ p[0] = p[1];
+ p[1] = pval;
+ }
+
+ if(b.dataLength == 1)
+ singleByteDivide(a, b, quotient, remainder);
+ else
+ multiByteDivide(a, b, quotient, remainder);
+
+ /*
+ Console.WriteLine(quotient.dataLength);
+ Console.WriteLine("{0} = {1}({2}) + {3} p = {4}", a.ToString(10),
+ b.ToString(10), quotient.ToString(10), remainder.ToString(10),
+ p[1].ToString(10));
+ */
+
+ q[0] = q[1];
+ r[0] = r[1];
+ q[1] = quotient; r[1] = remainder;
+
+ a = b;
+ b = remainder;
+
+ step++;
+ }
+
+ if(r[0].dataLength > 1 || (r[0].dataLength == 1 && r[0].data[0] != 1))
+ throw (new ArithmeticException("No inverse!"));
+
+ BigInteger result = ((p[0] - (p[1] * q[0])) % modulus);
+
+ if((result.data[maxLength - 1] & 0x80000000) != 0)
+ result += modulus; // get the least positive modulus
+
+ return result;
+ }
+
+ // Returns the value of the BigInteger as a byte array. The lowest
+ // index contains the MSB.
+ public byte[] getBytes()
+ {
+ int numBits = bitCount();
+ byte[] result = null;
+ if(numBits == 0) {
+ result = new byte[1];
+ result[0] = 0;
+ }
+ else {
+ int numBytes = numBits >> 3;
+ if((numBits & 0x7) != 0)
+ numBytes++;
+ result = new byte[numBytes];
+ //Console.WriteLine(result.Length);
+ int numBytesInWord = numBytes & 0x3;
+ if(numBytesInWord == 0)
+ numBytesInWord = 4;
+ int pos = 0;
+ for(int i = dataLength - 1; i >= 0; i--) {
+ uint val = data[i];
+ for(int j = numBytesInWord - 1; j >= 0; j--) {
+ result[pos+j] = (byte)(val & 0xFF);
+ val >>= 8;
+ }
+ pos += numBytesInWord;
+ numBytesInWord = 4;
+ }
+ }
+ return result;
+ }
+
+ // Return true if the value of the specified bit is 1, false otherwise
+ public bool testBit (uint bitNum)
+ {
+ uint bytePos = bitNum >> 5; // divide by 32
+ byte bitPos = (byte)(bitNum & 0x1F); // get the lowest 5 bits
+
+ uint mask = (uint)1 << bitPos;
+ return ((this.data[bytePos] | mask) == this.data[bytePos]);
+ }
+
+ // Sets the value of the specified bit to 1
+ // The Least Significant Bit position is 0.
+ public void setBit(uint bitNum)
+ {
+ uint bytePos = bitNum >> 5; // divide by 32
+ byte bitPos = (byte)(bitNum & 0x1F); // get the lowest 5 bits
+
+ uint mask = (uint)1 << bitPos;
+ this.data[bytePos] |= mask;
+
+ if(bytePos >= this.dataLength)
+ this.dataLength = (int)bytePos + 1;
+ }
+
+ // Sets the value of the specified bit to 0
+ // The Least Significant Bit position is 0.
+ public void unsetBit(uint bitNum)
+ {
+ uint bytePos = bitNum >> 5;
+
+ if(bytePos < this.dataLength) {
+ byte bitPos = (byte)(bitNum & 0x1F);
+
+ uint mask = (uint)1 << bitPos;
+ uint mask2 = 0xFFFFFFFF ^ mask;
+
+ this.data[bytePos] &= mask2;
+
+ if(this.dataLength > 1 && this.data[this.dataLength - 1] == 0)
+ this.dataLength--;
+ }
+ }
+
+ // Returns a value that is equivalent to the integer square root
+ // of the BigInteger.
+ // The integer square root of "this" is defined as the largest integer n
+ // such that (n * n) <= this
+ public BigInteger sqrt ()
+ {
+ uint numBits = (uint)this.bitCount();
+
+ if((numBits & 0x1) != 0) // odd number of bits
+ numBits = (numBits >> 1) + 1;
+ else
+ numBits = (numBits >> 1);
+
+ uint bytePos = numBits >> 5;
+ byte bitPos = (byte)(numBits & 0x1F);
+
+ uint mask;
+
+ BigInteger result = new BigInteger();
+ if(bitPos == 0)
+ mask = 0x80000000;
+ else {
+ mask = (uint)1 << bitPos;
+ bytePos++;
+ }
+ result.dataLength = (int)bytePos;
+
+ for(int i = (int)bytePos - 1; i >= 0; i--) {
+ while(mask != 0) {
+ // guess
+ result.data[i] ^= mask;
+
+ // undo the guess if its square is larger than this
+ if((result * result) > this)
+ result.data[i] ^= mask;
+
+ mask >>= 1;
+ }
+ mask = 0x80000000;
+ }
+ return result;
+ }
+
+ // Returns the k_th number in the Lucas Sequence reduced modulo n.
+ //
+ // Uses index doubling to speed up the process. For example, to calculate V(k),
+ // we maintain two numbers in the sequence V(n) and V(n+1).
+ //
+ // To obtain V(2n), we use the identity
+ // V(2n) = (V(n) * V(n)) - (2 * Q^n)
+ // To obtain V(2n+1), we first write it as
+ // V(2n+1) = V((n+1) + n)
+ // and use the identity
+ // V(m+n) = V(m) * V(n) - Q * V(m-n)
+ // Hence,
+ // V((n+1) + n) = V(n+1) * V(n) - Q^n * V((n+1) - n)
+ // = V(n+1) * V(n) - Q^n * V(1)
+ // = V(n+1) * V(n) - Q^n * P
+ //
+ // We use k in its binary expansion and perform index doubling for each
+ // bit position. For each bit position that is set, we perform an
+ // index doubling followed by an index addition. This means that for V(n),
+ // we need to update it to V(2n+1). For V(n+1), we need to update it to
+ // V((2n+1)+1) = V(2*(n+1))
+ //
+ // This function returns
+ // [0] = U(k)
+ // [1] = V(k)
+ // [2] = Q^n
+ //
+ // Where U(0) = 0 % n, U(1) = 1 % n
+ // V(0) = 2 % n, V(1) = P % n
+ public static BigInteger[] LucasSequence (BigInteger P, BigInteger Q,
+ BigInteger k, BigInteger n)
+ {
+ if(k.dataLength == 1 && k.data[0] == 0) {
+ BigInteger[] result = new BigInteger[3];
+
+ result[0] = 0; result[1] = 2 % n; result[2] = 1 % n;
+ return result;
+ }
+
+ // calculate constant = b^(2k) / m
+ // for Barrett Reduction
+ BigInteger constant = new BigInteger();
+
+ int nLen = n.dataLength << 1;
+ constant.data[nLen] = 0x00000001;
+ constant.dataLength = nLen + 1;
+
+ constant = constant / n;
+
+ // calculate values of s and t
+ int s = 0;
+
+ for(int index = 0; index < k.dataLength; index++) {
+ uint mask = 0x01;
+
+ for(int i = 0; i < 32; i++) {
+ if((k.data[index] & mask) != 0) {
+ index = k.dataLength; // to break the outer loop
+ break;
+ }
+ mask <<= 1;
+ s++;
+ }
+ }
+
+ BigInteger t = k >> s;
+
+ //Console.WriteLine("s = " + s + " t = " + t);
+ return LucasSequenceHelper(P, Q, t, n, constant, s);
+ }
+
+ // Performs the calculation of the kth term in the Lucas Sequence.
+ // For details of the algorithm, see reference [9].
+ // k must be odd. i.e LSB == 1
+ private static BigInteger[] LucasSequenceHelper(BigInteger P, BigInteger Q,
+ BigInteger k, BigInteger n, BigInteger constant, int s)
+ {
+ BigInteger[] result = new BigInteger[3];
+
+ if((k.data[0] & 0x00000001) == 0)
+ throw (new ArgumentException("Argument k must be odd."));
+
+ int numbits = k.bitCount();
+ uint mask = (uint)0x1 << ((numbits & 0x1F) - 1);
+
+ // v = v0, v1 = v1, u1 = u1, Q_k = Q^0
+
+ BigInteger v = 2 % n, Q_k = 1 % n,
+ v1 = P % n, u1 = Q_k;
+ bool flag = true;
+
+ for(int i = k.dataLength - 1; i >= 0 ; i--) { // iterate on the binary expansion of k
+ //Console.WriteLine("round");
+ while(mask != 0) {
+ if(i == 0 && mask == 0x00000001) // last bit
+ break;
+
+ if((k.data[i] & mask) != 0) { // bit is set
+ // index doubling with addition
+
+ u1 = (u1 * v1) % n;
+
+ v = ((v * v1) - (P * Q_k)) % n;
+ v1 = n.BarrettReduction(v1 * v1, n, constant);
+ v1 = (v1 - ((Q_k * Q) << 1)) % n;
+
+ if(flag)
+ flag = false;
+ else
+ Q_k = n.BarrettReduction(Q_k * Q_k, n, constant);
+
+ Q_k = (Q_k * Q) % n;
+ }
+ else {
+ // index doubling
+ u1 = ((u1 * v) - Q_k) % n;
+
+ v1 = ((v * v1) - (P * Q_k)) % n;
+ v = n.BarrettReduction(v * v, n, constant);
+ v = (v - (Q_k << 1)) % n;
+
+ if(flag) {
+ Q_k = Q % n;
+ flag = false;
+ }
+ else
+ Q_k = n.BarrettReduction(Q_k * Q_k, n, constant);
+ }
+
+ mask >>= 1;
+ }
+ mask = 0x80000000;
+ }
+
+ // at this point u1 = u(n+1) and v = v(n)
+ // since the last bit always 1, we need to transform u1 to u(2n+1) and v to v(2n+1)
+
+ u1 = ((u1 * v) - Q_k) % n;
+ v = ((v * v1) - (P * Q_k)) % n;
+ if(flag)
+ flag = false;
+ else
+ Q_k = n.BarrettReduction(Q_k * Q_k, n, constant);
+
+ Q_k = (Q_k * Q) % n;
+
+
+ for (int i = 0; i < s; i++) {
+ // index doubling
+ u1 = (u1 * v) % n;
+ v = ((v * v) - (Q_k << 1)) % n;
+
+ if(flag) {
+ Q_k = Q % n;
+ flag = false;
+ }
+ else
+ Q_k = n.BarrettReduction(Q_k * Q_k, n, constant);
+ }
+
+ result[0] = u1;
+ result[1] = v;
+ result[2] = Q_k;
+
+ return result;
+ }
+}
+
+}
\ No newline at end of file
+2002-11-16 Sebastien Pouliot <spouliot@videotron.ca>
+
+ * AsymmetricAlgorithm.cs: Added internal class AsymmetricParameters
+ (which implements the IReader interface for MiniParser). Corrected
+ Dispose declaration.
+ * BigInteger.cs: New. Internal class for handling BIG integers for
+ asymmetric crypto (both RSA and DSA). Thanks to Chew Keong TAN !
+ * CryptoConfig.cs: Added XMLDSIG URLs in CreateFromName.
+ Will dynamically load System.Security.dll, when required,
+ to return instance of those classes. Also CryptoConfig can now
+ create any object (e.g. System.IO.MemoryStream) !
+ * DSA.cs: Added internal class DSAHandler (which implements IHandler
+ interface for MiniParser) to import DSA keypairs from XML strings.
+ * DSACryptoServiceProvider.cs: Crypto fully implemented using
+ BigInteger. Key generation (group) is VERY long.
+ * MiniParser.cs: New. Minimal XML parser by Sergey Chaban. Used to
+ import keypairs in XML strings.
+ * SignatureDescription.cs: Removed local CreateFromName (to use
+ CryptoConfig - which actually can create anything). Added internal
+ classes DSASignatureDescription and RSAPKCS1SHA1SignatureDescription.
+
2002-11-15 Sebastien Pouliot <spouliot@videotron.ca>
* CryptographicUnexpectedOperationException.cs: Forgot it last time!
using System;
using System.Text;
-//using System.Xml;
// References:
// a. FIPS PUB 186-2: Digital Signature Standard (DSS)
namespace System.Security.Cryptography
{
+ internal class DSAHandler : MiniParser.IHandler {
+
+ private DSAParameters dsa;
+ private bool unknown;
+ private byte[] temp;
+
+ public DSAHandler ()
+ {
+ dsa = new DSAParameters();
+ }
+
+ public DSAParameters GetParams ()
+ {
+ return dsa;
+ }
+
+ public void OnStartParsing (MiniParser parser) {}
+
+ public void OnStartElement (string name, MiniParser.IAttrList attrs) {}
+
+ public void OnEndElement (string name)
+ {
+ switch (name) {
+ case "P":
+ dsa.P = temp;
+ break;
+ case "Q":
+ dsa.Q = temp;
+ break;
+ case "G":
+ dsa.G = temp;
+ break;
+ case "J":
+ dsa.J = temp;
+ break;
+ case "Y":
+ dsa.Y = temp;
+ break;
+ case "X":
+ dsa.X = temp;
+ break;
+ case "Seed":
+ dsa.Seed = temp;
+ break;
+ case "PgenCounter":
+ byte[] counter4b = new byte[4];
+ Array.Copy (temp, 0, counter4b, 0, temp.Length);
+ dsa.Counter = BitConverter.ToInt32 (counter4b, 0);
+ break;
+ default:
+ // unknown tag in parameters
+ break;
+ }
+ }
+
+ public void OnChars (string ch)
+ {
+ temp = Convert.FromBase64String (ch);
+ }
+
+ public void OnEndParsing (MiniParser parser) {}
+ }
+
/// <summary>
/// Abstract base class for all implementations of the DSA algorithm
/// </summary>
public abstract class DSA : AsymmetricAlgorithm
{
- // now public like RSA (but unlike MS which is internal)
- // this caused problems to compile the test suite
- public DSA () {}
+ // LAMESPEC: It says to derive new DSA implemenation from DSA class.
+ // Well it's aint gonna be easy this way.
+ // RSA constructor is public
+ internal DSA () {}
public static new DSA Create ()
{
DSAParameters dsaParams = new DSAParameters ();
try {
-/* XmlDocument xml = new XmlDocument ();
- xml.LoadXml (xmlString);
- dsaParams.P = GetElement (xml, "P");
- dsaParams.Q = GetElement (xml, "Q");
- dsaParams.G = GetElement (xml, "G");
- dsaParams.Y = GetElement (xml, "Y");
- dsaParams.J = GetElement (xml, "J");
- dsaParams.Seed = GetElement (xml, "Seed");
- byte[] counter = GetElement (xml, "PgenCounter");
- // else we may have an exception
- byte[] counter4b = new byte[4];
- Array.Copy (counter, 0, counter4b, 0, counter.Length);
- dsaParams.Counter = BitConverter.ToInt32 (counter4b, 0);
- dsaParams.X = GetElement (xml, "X");*/
- ImportParameters (dsaParams);
+ MiniParser parser = new MiniParser ();
+ AsymmetricParameters reader = new AsymmetricParameters (xmlString);
+ DSAHandler handler = new DSAHandler ();
+ parser.Parse(reader, handler);
+ ImportParameters (handler.GetParams ());
}
catch {
ZeroizePrivateKey (dsaParams);
sb.Append ("</G>");
sb.Append ("<Y>");
- sb.Append (Convert.ToBase64String( dsaParams.Y));
+ sb.Append (Convert.ToBase64String (dsaParams.Y));
sb.Append( "</Y>");
sb.Append ("<J>");
ZeroizePrivateKey (dsaParams);
throw;
}
- finally {
- ZeroizePrivateKey (dsaParams);
- }
return sb.ToString ();
}
-//\r
-// System.Security.Cryptography.DSACryptoServiceProvider.cs\r
-//\r
-// Authors:\r
-// Dan Lewis (dihlewis@yahoo.co.uk)\r
-//\r
-// (C) 2002\r
-//\r
-// Stubbed.\r
-//\r
-\r
-using System;\r
-using System.IO;\r
-\r
-namespace System.Security.Cryptography {\r
- \r
- [MonoTODO]\r
- public class DSACryptoServiceProvider : DSA {\r
- public DSACryptoServiceProvider () { }\r
- public DSACryptoServiceProvider (CspParameters parameters) { }\r
- public DSACryptoServiceProvider (int key_size) { }\r
- public DSACryptoServiceProvider (int key_size, CspParameters parameters) { }\r
-\r
- public override string KeyExchangeAlgorithm {\r
- get { return null; }\r
- }\r
-\r
- public override int KeySize {\r
- get { return 0; }\r
- }\r
-\r
- public override KeySizes[] LegalKeySizes {\r
- get { return null; }\r
- }\r
-\r
- public override string SignatureAlgorithm {\r
- get { return null; }\r
- }\r
-\r
- public bool PersistKeyInCsp {\r
- get { return false; }\r
- set { }\r
- }\r
- \r
- protected override void Dispose (bool disposing) {}\r
-\r
- public override byte[] CreateSignature (byte[] rgb) {\r
- return null;\r
- }\r
- \r
- public override bool VerifySignature(byte[] hash, byte[] sig) {\r
- return false;\r
- }\r
-\r
- public byte[] SignData (byte[] data) {\r
- return SignData (data, 0, data.Length);\r
- }\r
-\r
- public byte[] SignData (byte[] data, int offset, int count) {\r
- return null;\r
- }\r
-\r
- public byte[] SignData (Stream data) {\r
- return null;\r
- }\r
-\r
- public byte[] SignHash (byte[] hash, string str) {\r
- return null;\r
- }\r
-\r
- public bool VerifyData (byte[] data, byte[] sig) {\r
- return false;\r
- }\r
-\r
- public override DSAParameters ExportParameters (bool include) {\r
- return new DSAParameters ();\r
- }\r
-\r
- public override void ImportParameters (DSAParameters parameters) {\r
- }\r
-\r
- public override void FromXmlString(string xmlString) {\r
- }\r
-\r
- public override string ToXmlString(bool includePrivateParameters) {\r
- return null;\r
- }\r
- }\r
-}\r
+//
+// System.Security.Cryptography.DSACryptoServiceProvider.cs
+//
+// Authors:
+// Dan Lewis (dihlewis@yahoo.co.uk)
+// Sebastien Pouliot (spouliot@motus.com)
+//
+// (C) 2002
+// Portions (C) 2002 Motus Technologies Inc. (http://www.motus.com)
+// Key generation translated from Bouncy Castle JCE (http://www.bouncycastle.org/)
+// See bouncycastle.txt for license.
+//
+
+using System;
+using System.IO;
+
+namespace System.Security.Cryptography {
+
+public class DSACryptoServiceProvider : DSA {
+
+ private CspParameters cspParams;
+ private RandomNumberGenerator rng;
+
+ private bool privateKeyExportable = true;
+ private bool m_disposed = false;
+ private bool keypairGenerated = false;
+ private bool persistKey = false;
+
+ private BigInteger p;
+ private BigInteger q;
+ private BigInteger g;
+ private BigInteger x; // private key
+ private BigInteger y;
+ private BigInteger j;
+ private BigInteger seed;
+ private int counter;
+
+ public DSACryptoServiceProvider ()
+ {
+ // Here it's not clear if we need to generate a keypair
+ // (note: MS implementation generates a keypair in this case).
+ // However we:
+ // (a) often use this constructor to import an existing keypair.
+ // (b) take a LOT of time to generate the DSA group
+ // So we'll generate the keypair only when (and if) it's being
+ // used (or exported). This should save us a lot of time (at
+ // least in the unit tests).
+ Common (null);
+ }
+
+ public DSACryptoServiceProvider (CspParameters parameters)
+ {
+ Common (parameters);
+ // no keypair generation done at this stage
+ }
+
+ // This constructor will generate a new keypair
+ public DSACryptoServiceProvider (int dwKeySize)
+ {
+ // Here it's clear that we need to generate a new keypair
+ Common (null);
+ Generate (dwKeySize);
+ }
+
+ // This constructor will generate a new keypair
+ public DSACryptoServiceProvider (int dwKeySize, CspParameters parameters)
+ {
+ Common (parameters);
+ Generate (dwKeySize);
+ }
+
+ ~DSACryptoServiceProvider ()
+ {
+ Dispose (false);
+ }
+
+ [MonoTODO("Persistance")]
+ private void Common (CspParameters p)
+ {
+ rng = RandomNumberGenerator.Create ();
+ cspParams = new CspParameters ();
+ if (p == null) {
+ // TODO: set default values (for keypair persistance)
+ }
+ else {
+ cspParams = p;
+ // FIXME: We'll need this to support some kind of persistance
+ throw new NotSupportedException ("CspParameters not supported");
+ }
+ LegalKeySizesValue = new KeySizes [1];
+ LegalKeySizesValue [0] = new KeySizes (512, 1024, 64);
+ }
+
+ // generate both the group and the keypair
+ private void Generate (int keyLength)
+ {
+ // will throw an exception is key size isn't supported
+ base.KeySize = keyLength;
+ GenerateParams (keyLength);
+ GenerateKeyPair ();
+ keypairGenerated = true;
+ }
+
+ // this part is quite fast
+ private void GenerateKeyPair ()
+ {
+ x = new BigInteger ();
+ do {
+ // size of x (private key) isn't affected by the keysize (512-1024)
+ x.genRandomBits (160);
+ }
+ while ((x == 0) || (x >= q));
+
+ // calculate the public key y = g^x % p
+ y = g.modPow (x, p);
+ }
+
+ private void add (byte[] a, byte[] b, int value)
+ {
+ uint x = (uint) ((b [b.Length - 1] & 0xff) + value);
+
+ a [b.Length - 1] = (byte)x;
+ x >>= 8;
+
+ for (int i = b.Length - 2; i >= 0; i--) {
+ x += (uint) (b [i] & 0xff);
+ a [i] = (byte)x;
+ x >>= 8;
+ }
+ }
+
+ private void GenerateParams (int keyLength)
+ {
+ byte[] seed = new byte[20];
+ byte[] part1 = new byte[20];
+ byte[] part2 = new byte[20];
+ byte[] u = new byte[20];
+
+ SHA1 sha = SHA1.Create ();
+
+ int n = (keyLength - 1) / 160;
+ byte[] w = new byte [keyLength / 8];
+ bool primesFound = false;
+ int certainty = 80; // FIPS186-2
+
+ while (!primesFound) {
+ do {
+ rng.GetBytes (seed);
+ part1 = sha.ComputeHash (seed);
+ Array.Copy(seed, 0, part2, 0, seed.Length);
+
+ add (part2, seed, 1);
+
+ part2 = sha.ComputeHash (part2);
+
+ for (int i = 0; i != u.Length; i++)
+ u [i] = (byte)(part1 [i] ^ part2 [i]);
+
+ // first bit must be set (to respect key length)
+ u[0] |= (byte)0x80;
+ // last bit must be set (prime are all odds - except 2)
+ u[19] |= (byte)0x01;
+
+ q = new BigInteger (u);
+ }
+ while (!q.isProbablePrime (certainty));
+
+ counter = 0;
+ int offset = 2;
+ while (counter < 4096) {
+ for (int k = 0; k < n; k++) {
+ add(part1, seed, offset + k);
+ part1 = sha.ComputeHash (part1);
+ Array.Copy (part1, 0, w, w.Length - (k + 1) * part1.Length, part1.Length);
+ }
+
+ add(part1, seed, offset + n);
+ part1 = sha.ComputeHash (part1);
+ Array.Copy (part1, part1.Length - ((w.Length - (n) * part1.Length)), w, 0, w.Length - n * part1.Length);
+
+ w[0] |= (byte)0x80;
+ BigInteger x = new BigInteger (w);
+
+ BigInteger c = x % (q * 2);
+
+ p = x - (c - 1);
+
+ if (p.testBit ((uint)(keyLength - 1))) {
+ if (p.isProbablePrime (certainty)) {
+ primesFound = true;
+ break;
+ }
+ }
+
+ counter += 1;
+ offset += n + 1;
+ }
+ }
+
+ // calculate the generator g
+ BigInteger pMinusOneOverQ = (p - 1) / q;
+ for (;;) {
+ BigInteger h = new BigInteger ();
+ h.genRandomBits (keyLength);
+ if ((h <= 1) || (h >= (p - 1)))
+ continue;
+
+ g = h.modPow (pMinusOneOverQ, p);
+ if (g <= 1)
+ continue;
+ break;
+ }
+
+ this.seed = new BigInteger (seed);
+ j = (p - 1) / q;
+ }
+
+ [MonoTODO()]
+ private bool Validate ()
+ {
+ // J is optional
+ bool okJ = ((j == 0) || (j == ((p - 1) / q)));
+ // TODO: Validate the key parameters (P, Q, G, J) using the Seed and Counter
+ return okJ;
+ }
+
+ // DSA isn't used for key exchange
+ public override string KeyExchangeAlgorithm {
+ get { return ""; }
+ }
+
+ public override int KeySize {
+ get { return p.bitCount (); }
+ }
+
+ public override KeySizes[] LegalKeySizes {
+ get { return LegalKeySizesValue; }
+ }
+
+ public override string SignatureAlgorithm {
+ get { return "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; }
+ }
+
+ [MonoTODO("Persistance")]
+ public bool PersistKeyInCsp {
+ get { return persistKey; }
+ set {
+ persistKey = value;
+ // FIXME: We'll need this to support some kind of persistance
+ if (value)
+ throw new NotSupportedException ("CspParameters not supported");
+ }
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (!m_disposed) {
+ // TODO: always zeroize private key
+ if(disposing) {
+ // TODO: Dispose managed resources
+ }
+
+ // TODO: Dispose unmanaged resources
+ }
+ // call base class
+ // no need as they all are abstract before us
+ m_disposed = true;
+ }
+
+ public override byte[] CreateSignature (byte[] rgbHash)
+ {
+ return SignHash (rgbHash, "SHA1");
+ }
+
+ public byte[] SignData (byte[] data)
+ {
+ return SignData (data, 0, data.Length);
+ }
+
+ public byte[] SignData (byte[] data, int offset, int count)
+ {
+ // right now only SHA1 is supported by FIPS186-2
+ HashAlgorithm hash = SHA1.Create ();
+ byte[] toBeSigned = hash.ComputeHash (data, offset, count);
+ return SignHash (toBeSigned, "SHA1");
+ }
+
+ public byte[] SignData (Stream inputStream)
+ {
+ // right now only SHA1 is supported by FIPS186-2
+ HashAlgorithm hash = SHA1.Create ();
+ byte[] toBeSigned = hash.ComputeHash (inputStream);
+ return SignHash (toBeSigned, "SHA1");
+ }
+
+ public byte[] SignHash (byte[] rgbHash, string str)
+ {
+ if (rgbHash == null)
+ throw new ArgumentNullException ();
+ // right now only SHA1 is supported by FIPS186-2
+ if (str.ToUpper () != "SHA1")
+ throw new Exception( ); // not documented
+ if (rgbHash.Length != 20)
+ throw new Exception (); // not documented
+
+ if (!keypairGenerated)
+ Generate (1024);
+
+ BigInteger m = new BigInteger (rgbHash);
+ // (a) Select a random secret integer k; 0 < k < q.
+ BigInteger k = new BigInteger ();
+ k.genRandomBits (160);
+ while (k >= q)
+ k.genRandomBits (160);
+ // (b) Compute r = (\v k mod p) mod q
+ BigInteger r = (g.modPow (k, p)) % q;
+ // (c) Compute k -1 mod q (e.g., using Algorithm 2.142).
+ // (d) Compute s = k -1 fh(m) +arg mod q.
+ BigInteger s = (k.modInverse (q) * (m + x * r)) % q;
+ // (e) A\92s signature for m is the pair (r; s).
+ byte[] signature = new byte [40];
+ byte[] part1 = r.getBytes ();
+ byte[] part2 = s.getBytes ();
+ Array.Copy (part1, 0, signature, 0, 20);
+ Array.Copy (part2, 0, signature, 20, 20);
+ return signature;
+ }
+
+ public bool VerifyData (byte[] rgbData, byte[] rgbSignature)
+ {
+ // signature is always 40 bytes (no matter the size of the
+ // public key). In fact it is 2 times the size of the private
+ // key (which is 20 bytes for 512 to 1024 bits DSA keypairs)
+ if (rgbSignature.Length != 40)
+ throw new Exception(); // not documented
+ // right now only SHA1 is supported by FIPS186-2
+ HashAlgorithm hash = SHA1.Create();
+ byte[] toBeVerified = hash.ComputeHash (rgbData);
+ return VerifyHash (toBeVerified, "SHA1", rgbSignature);
+ }
+
+ // LAMESPEC: MD5 isn't allowed with DSA
+ public bool VerifyHash (byte[] rgbHash, string str, byte[] rgbSignature)
+ {
+ if (rgbHash == null)
+ throw new ArgumentNullException ("rgbHash");
+ if (rgbSignature == null)
+ throw new ArgumentNullException ("rgbSignature");
+ if (str == null)
+ str = "SHA1"; // default value
+ if (str != "SHA1")
+ throw new CryptographicException ();
+
+ // it would be stupid to verify a signature with a newly
+ // generated keypair - so we return false
+ if (!keypairGenerated)
+ return false;
+
+ try {
+ BigInteger m = new BigInteger (rgbHash);
+ byte[] half = new byte [20];
+ Array.Copy (rgbSignature, 0, half, 0, 20);
+ BigInteger r = new BigInteger (half);
+ Array.Copy (rgbSignature, 20, half, 0, 20);
+ BigInteger s = new BigInteger (half);
+
+ if ((r < 0) || (q <= r))
+ return false;
+
+ if ((s < 0) || (q <= s))
+ return false;
+
+ BigInteger w = s.modInverse(q);
+ BigInteger u1 = m * w % q;
+ BigInteger u2 = r * w % q;
+
+ u1 = g.modPow(u1, p);
+ u2 = y.modPow(u2, p);
+
+ BigInteger v = ((u1 * u2 % p) % q);
+ return (v == r);
+ }
+ catch {
+ throw new CryptographicException ();
+ }
+ }
+
+ public override bool VerifySignature(byte[] rgbHash, byte[] rgbSignature)
+ {
+ return VerifyHash (rgbHash, "SHA1", rgbSignature);
+ }
+
+ private byte[] NormalizeArray (byte[] array)
+ {
+ int n = (array.Length % 4);
+ if (n > 0) {
+ byte[] temp = new byte [array.Length + 4 - n];
+ Array.Copy (array, 0, temp, (4 - n), array.Length);
+ return temp;
+ }
+ else
+ return array;
+ }
+
+ public override DSAParameters ExportParameters (bool includePrivateParameters)
+ {
+ if ((includePrivateParameters) && (!privateKeyExportable))
+ throw new CryptographicException ("cannot export private key");
+ DSAParameters param = new DSAParameters();
+ // all parameters must be in multiple of 4 bytes arrays
+ // this isn't (generally) a problem for most of the parameters
+ // except for J (but we won't take a chance)
+ param.P = NormalizeArray (p.getBytes ());
+ param.Q = NormalizeArray (q.getBytes ());
+ param.G = NormalizeArray (g.getBytes ());
+ param.Y = NormalizeArray (y.getBytes ());
+ param.J = NormalizeArray (j.getBytes ());
+ if (seed != 0) {
+ param.Seed = NormalizeArray (seed.getBytes ());
+ param.Counter = counter;
+ }
+ if (includePrivateParameters)
+ param.X = NormalizeArray (x.getBytes ());
+ return param;
+ }
+
+ public override void ImportParameters (DSAParameters parameters)
+ {
+ // if missing "mandatory" parameters
+ if ((parameters.P == null) || (parameters.Q == null) || (parameters.G == null) || (parameters.Y == null))
+ throw new CryptographicException ();
+ p = new BigInteger (parameters.P);
+ q = new BigInteger (parameters.Q);
+ g = new BigInteger (parameters.G);
+ y = new BigInteger (parameters.Y);
+ // optional parameter - private key
+ if (parameters.X != null)
+ x = new BigInteger (parameters.X);
+ else
+ x = new BigInteger (0);
+ // optional parameter - pre-computation
+ if (parameters.J != null)
+ j = new BigInteger (parameters.J);
+ else
+ j = (p - 1) / q;
+ // optional - seed and counter must both be present (or absent)
+ if (parameters.Seed != null) {
+ seed = new BigInteger (parameters.Seed);
+ counter = parameters.Counter;
+ }
+ else
+ seed = new BigInteger (0);
+ // we now have a keypair
+ keypairGenerated = true;
+ }
+}
+
+}
--- /dev/null
+//
+// System.Security.Cryptography.MiniParser: Internal XML parser implementation
+//
+// Authors:
+// Sergey Chaban
+//
+
+/*
+ * Copyright (c) 2001, 2002 Wild West Software
+ * Copyright (c) 2002 Sergey Chaban
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+using System;
+using System.Text;
+using System.Collections;
+using System.Globalization;
+
+namespace System.Security.Cryptography {
+
+internal class MiniParser {
+
+ public interface IReader {
+ int Read();
+ }
+
+ public interface IAttrList {
+ int Length {get;}
+ bool IsEmpty {get;}
+ string GetName(int i);
+ string GetValue(int i);
+ string GetValue(string name);
+ void ChangeValue(string name, string newValue);
+ string[] Names {get;}
+ string[] Values {get;}
+ }
+
+ public interface IMutableAttrList : IAttrList {
+ void Clear();
+ void Add(string name, string value);
+ void CopyFrom(IAttrList attrs);
+ void Remove(int i);
+ void Remove(string name);
+ }
+
+ public interface IHandler {
+ void OnStartParsing(MiniParser parser);
+ void OnStartElement(string name, IAttrList attrs);
+ void OnEndElement(string name);
+ void OnChars(string ch);
+ void OnEndParsing(MiniParser parser);
+ }
+
+ public class HandlerAdapter : IHandler {
+ public HandlerAdapter() {}
+ public void OnStartParsing(MiniParser parser) {}
+ public void OnStartElement(string name, IAttrList attrs) {}
+ public void OnEndElement(string name) {}
+ public void OnChars(string ch) {}
+ public void OnEndParsing(MiniParser parser) {}
+ }
+
+ private enum CharKind : byte {
+ LEFT_BR = 0,
+ RIGHT_BR = 1,
+ SLASH = 2,
+ PI_MARK = 3,
+ EQ = 4,
+ AMP = 5,
+ SQUOTE = 6,
+ DQUOTE = 7,
+ BANG = 8,
+ LEFT_SQBR = 9,
+ SPACE = 0xA,
+ RIGHT_SQBR = 0xB,
+ TAB = 0xC,
+ CR = 0xD,
+ EOL = 0xE,
+ CHARS = 0xF,
+ UNKNOWN = 0x1F
+ }
+
+ private enum ActionCode : byte {
+ START_ELEM = 0,
+ END_ELEM = 1,
+ END_NAME = 2,
+ SET_ATTR_NAME = 3,
+ SET_ATTR_VAL = 4,
+ SEND_CHARS = 5,
+ START_CDATA = 6,
+ END_CDATA = 7,
+ ERROR = 8,
+ STATE_CHANGE = 9,
+ FLUSH_CHARS_STATE_CHANGE = 0xA,
+ ACC_CHARS_STATE_CHANGE = 0xB,
+ ACC_CDATA = 0xC,
+ PROC_CHAR_REF = 0xD,
+ UNKNOWN = 0xF
+ }
+
+ public class AttrListImpl : IMutableAttrList {
+ protected ArrayList names;
+ protected ArrayList values;
+
+ public AttrListImpl() : this(0) {}
+
+ public AttrListImpl(int initialCapacity) {
+ if (initialCapacity <= 0) {
+ names = new ArrayList();
+ values = new ArrayList();
+ } else {
+ names = new ArrayList(initialCapacity);
+ values = new ArrayList(initialCapacity);
+ }
+ }
+
+ public AttrListImpl(IAttrList attrs)
+ : this(attrs != null ? attrs.Length : 0) {
+ if (attrs != null) this.CopyFrom(attrs);
+ }
+
+ public int Length {
+ get {return names.Count;}
+ }
+
+ public bool IsEmpty {
+ get {return this.Length != 0;}
+ }
+
+ public string GetName(int i) {
+ string res = null;
+ if (i >= 0 && i < this.Length) {
+ res = names[i] as string;
+ }
+ return res;
+ }
+
+ public string GetValue(int i) {
+ string res = null;
+ if (i >= 0 && i < this.Length) {
+ res = values[i] as string;
+ }
+ return res;
+ }
+
+ public string GetValue(string name) {
+ return this.GetValue(names.IndexOf(name));
+ }
+
+ public void ChangeValue(string name, string newValue) {
+ int i = names.IndexOf(name);
+ if (i >= 0 && i < this.Length) {
+ values[i] = newValue;
+ }
+ }
+
+ public string[] Names {
+ get {return names.ToArray(typeof(string)) as string[];}
+ }
+
+ public string[] Values {
+ get {return values.ToArray(typeof(string)) as string[];}
+ }
+
+ public void Clear() {
+ names.Clear();
+ values.Clear();
+ }
+
+ public void Add(string name, string value) {
+ names.Add(name);
+ values.Add(value);
+ }
+
+ public void Remove(int i) {
+ if (i >= 0) {
+ names.RemoveAt(i);
+ values.RemoveAt(i);
+ }
+ }
+
+ public void Remove(string name) {
+ this.Remove(names.IndexOf(name));
+ }
+
+ public void CopyFrom(IAttrList attrs) {
+ if (attrs != null && ((object)this == (object)attrs)) {
+ this.Clear();
+ int n = attrs.Length;
+ for (int i = 0; i < n; i++) {
+ this.Add(attrs.GetName(i), attrs.GetValue(i));
+ }
+ }
+ }
+ }
+
+ public class XMLError : Exception {
+ protected string descr;
+ protected int line, column;
+ public XMLError() : this("Unknown") {}
+ public XMLError(string descr) : this(descr, -1, -1) {}
+ public XMLError(string descr, int line, int column)
+ : base(descr) {
+ this.descr = descr;
+ this.line = line;
+ this.column = column;
+ }
+ public int Line {get {return line;}}
+ public int Column {get {return column;}}
+ public override string ToString() {
+ return (String.Format("{0} @ (line = {1}, col = {2})", descr, line, column));
+ }
+ }
+
+ private static readonly int INPUT_RANGE = 13;
+ private static readonly ushort[] tbl = {
+ ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 1, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 128,
+ ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 2, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 133, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 16, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.FLUSH_CHARS_STATE_CHANGE << 8) | 4,
+ ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.END_ELEM << 8) | 0, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 2, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 2, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
+ ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 5, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3,
+ ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 4, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.END_NAME << 8) | 6, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.END_NAME << 8) | 7, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.END_NAME << 8) | 8, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
+ ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3,
+ ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
+ ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.FLUSH_CHARS_STATE_CHANGE << 8) | 1, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 10, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 7, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10,
+ ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_ELEM << 8) | 6, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.START_ELEM << 8) | 7, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 8, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
+ ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.SET_ATTR_NAME << 8) | 11, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 12, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130,
+ ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 13, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 10, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10,
+ ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 14, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 15, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 11, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 132,
+ ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.SET_ATTR_NAME << 8) | 11, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 12, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 130,
+ ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.SEND_CHARS << 8) | 2, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 16, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 134,
+ ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.SET_ATTR_VAL << 8) | 17, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 14, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14,
+ ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.SET_ATTR_VAL << 8) | 17, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 15, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15,
+ ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 18, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19,
+ ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_ELEM << 8) | 6, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.START_ELEM << 8) | 7, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 17, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
+ ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.END_CDATA << 8) | 10, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18,
+ ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19,
+ 0xFFFF
+ };
+
+ protected static string[] errors = {
+ /* 0 */ "Expected element",
+ /* 1 */ "Invalid character in tag",
+ /* 2 */ "No '='",
+ /* 3 */ "Invalid character entity",
+ /* 4 */ "Invalid attr value",
+ /* 5 */ "Empty tag",
+ /* 6 */ "No end tag",
+ /* 7 */ "Bad entity ref"
+ };
+
+ protected int line;
+ protected int col;
+ protected int[] twoCharBuff;
+ protected bool splitCData;
+
+ public MiniParser() {
+ twoCharBuff = new int[2];
+ splitCData = false;
+ Reset();
+ }
+
+ public void Reset() {
+ line = 0;
+ col = 0;
+ }
+
+ protected static bool StrEquals(string str, StringBuilder sb, int sbStart, int len) {
+ if (len != str.Length) return false;
+ for (int i = 0; i < len; i++) {
+ if (str[i] != sb[sbStart + i]) return false;
+ }
+ return true;
+ }
+
+ protected void FatalErr(string descr) {
+ throw new XMLError(descr, this.line, this.col);
+ }
+
+ protected static int Xlat(int charCode, int state) {
+ int p = state * INPUT_RANGE;
+ int n = Math.Min(tbl.Length - p, INPUT_RANGE);
+ for (;--n >= 0;) {
+ ushort code = tbl[p];
+ if (charCode == (code >> 12)) return (code & 0xFFF);
+ p++;
+ }
+ return 0xFFF;
+ }
+
+ public void Parse(IReader reader, IHandler handler) {
+ if (reader == null) throw new ArgumentNullException("reader");
+ if (handler == null) handler = new HandlerAdapter();
+
+ AttrListImpl attrList = new AttrListImpl();
+ string lastAttrName = null;
+ Stack tagStack = new Stack();
+ string elementName = null;
+ line = 1;
+ col = 0;
+ int currCh = 0;
+ int stateCode = 0;
+ StringBuilder sbChars = new StringBuilder();
+ bool seenCData = false;
+ bool isComment = false;
+ bool isDTD = false;
+ int bracketSwitch = 0;
+
+ handler.OnStartParsing(this);
+
+ while (true) {
+ ++this.col;
+ int prevCh = currCh;
+
+ currCh = reader.Read();
+
+ if (currCh == -1) {
+ if (stateCode != 0) {
+ FatalErr("Unexpected EOF");
+ }
+ break;
+ }
+
+ int charCode = "<>/?=&'\"![ ]\t\r\n".IndexOf((char)currCh) & 0xF;
+ if (charCode == (int)CharKind.CR) continue; // ignore
+ // whitepace ::= (#x20 | #x9 | #xd | #xa)+
+ if (charCode == (int)CharKind.TAB) charCode = (int)CharKind.SPACE; // tab == space
+ if (charCode == (int)CharKind.EOL) {
+ this.col = 0;
+ this.line++;
+ charCode = (int)CharKind.SPACE;
+ }
+
+ int actionCode = MiniParser.Xlat(charCode, stateCode);
+ stateCode = actionCode & 0xFF;
+ // Ignore newline inside attribute value.
+ if (currCh == '\n' && (stateCode == 0xE || stateCode == 0xF)) continue;
+ actionCode >>= 8;
+
+ if (stateCode >= 0x80) {
+ if (stateCode == 0xFF) {
+ FatalErr("State dispatch error.");
+ } else {
+ FatalErr(errors[stateCode ^ 0x80]);
+ }
+ }
+
+ switch (actionCode) {
+ case (int)ActionCode.START_ELEM:
+ handler.OnStartElement(elementName, attrList);
+ if (currCh != '/') {
+ tagStack.Push(elementName);
+ } else {
+ handler.OnEndElement(elementName);
+ }
+ attrList.Clear();
+ break;
+
+ case (int)ActionCode.END_ELEM:
+ elementName = sbChars.ToString();
+ sbChars = new StringBuilder();
+ string endName = null;
+ if (tagStack.Count == 0 ||
+ elementName != (endName = tagStack.Pop() as string)) {
+ if (endName == null) {
+ FatalErr("Tag stack underflow");
+ } else {
+ FatalErr(String.Format("Expected end tag '{0}' but found '{1}'", elementName, endName));
+ }
+ }
+ handler.OnEndElement(elementName);
+ break;
+
+ case (int)ActionCode.END_NAME:
+ elementName = sbChars.ToString();
+ sbChars = new StringBuilder();
+ if (currCh != '/' && currCh != '>') break;
+ goto case (int)ActionCode.START_ELEM;
+
+ case (int)ActionCode.SET_ATTR_NAME:
+ lastAttrName = sbChars.ToString();
+ sbChars = new StringBuilder();
+ break;
+
+ case (int)ActionCode.SET_ATTR_VAL:
+ if (lastAttrName == null) FatalErr("Internal error.");
+ attrList.Add(lastAttrName, sbChars.ToString());
+ sbChars = new StringBuilder();
+ lastAttrName = null;
+ break;
+
+ case (int)ActionCode.SEND_CHARS:
+ handler.OnChars(sbChars.ToString());
+ sbChars = new StringBuilder();
+ break;
+
+ case (int)ActionCode.START_CDATA:
+ string cdata = "CDATA[";
+ isComment = false;
+ isDTD = false;
+
+ if (currCh == '-') {
+ currCh = reader.Read();
+
+ if (currCh != '-') FatalErr("Invalid comment");
+
+ this.col++;
+ isComment = true;
+ twoCharBuff[0] = -1;
+ twoCharBuff[1] = -1;
+ } else {
+ if (currCh != '[') {
+ isDTD = true;
+ bracketSwitch = 0;
+ break;
+ }
+
+ for (int i = 0; i < cdata.Length; i++) {
+ if (reader.Read() != cdata[i]) {
+ this.col += i+1;
+ break;
+ }
+ }
+ this.col += cdata.Length;
+ seenCData = true;
+ }
+ break;
+
+ case (int)ActionCode.END_CDATA:
+ int n = 0;
+ currCh = ']';
+
+ while (currCh == ']') {
+ currCh = reader.Read();
+ n++;
+ }
+
+ if (currCh != '>') {
+ for (int i = 0; i < n; i++) sbChars.Append(']');
+ sbChars.Append((char)currCh);
+ stateCode = 0x12;
+ } else {
+ for (int i = 0; i < n-2; i++) sbChars.Append(']');
+ seenCData = false;
+ }
+
+ this.col += n;
+ break;
+
+ case (int)ActionCode.ERROR:
+ FatalErr(String.Format("Error {0}", stateCode));
+ break;
+
+ case (int)ActionCode.STATE_CHANGE:
+ break;
+
+ case (int)ActionCode.FLUSH_CHARS_STATE_CHANGE:
+ sbChars = new StringBuilder();
+ if (currCh != '<') goto case (int)ActionCode.ACC_CHARS_STATE_CHANGE;
+ break;
+
+ case (int)ActionCode.ACC_CHARS_STATE_CHANGE:
+ sbChars.Append((char)currCh);
+ break;
+
+ case (int)ActionCode.ACC_CDATA:
+ if (isComment) {
+ if (currCh == '>'
+ && twoCharBuff[0] == '-'
+ && twoCharBuff[1] == '-') {
+ isComment = false;
+ stateCode = 0;
+ } else {
+ twoCharBuff[0] = twoCharBuff[1];
+ twoCharBuff[1] = currCh;
+ }
+ } else if (isDTD) {
+ if (currCh == '<' || currCh == '>') bracketSwitch ^= 1;
+ if (currCh == '>' && bracketSwitch != 0) {
+ isDTD = false;
+ stateCode = 0;
+ }
+ } else {
+ if (this.splitCData
+ && sbChars.Length > 0
+ && seenCData) {
+ handler.OnChars(sbChars.ToString());
+ sbChars = new StringBuilder();
+ }
+ seenCData = false;
+ sbChars.Append((char)currCh);
+ }
+ break;
+
+ case (int)ActionCode.PROC_CHAR_REF:
+ currCh = reader.Read();
+ int cl = this.col + 1;
+ if (currCh == '#') { // character reference
+ int r = 10;
+ int chCode = 0;
+ int nDigits = 0;
+ currCh = reader.Read();
+ cl++;
+
+ if (currCh == 'x') {
+ currCh = reader.Read();
+ cl++;
+ r=16;
+ }
+
+ NumberStyles style = r == 16 ? NumberStyles.HexNumber : NumberStyles.Integer;
+
+ while (true) {
+ int x = -1;
+ if (Char.IsNumber((char)currCh) || "abcdef".IndexOf(Char.ToLower((char)currCh)) != -1) {
+ try {
+ x = Int32.Parse(new string((char)currCh, 1), style);
+ } catch (FormatException) {x = -1;}
+ }
+ if (x == -1) break;
+ chCode *= r;
+ chCode += x;
+ nDigits++;
+ currCh = reader.Read();
+ cl++;
+ }
+
+ if (currCh == ';' && nDigits > 0) {
+ sbChars.Append((char)chCode);
+ } else {
+ FatalErr("Bad char ref");
+ }
+ } else {
+ // entity reference
+ string entityRefChars = "aglmopqstu"; // amp | apos | quot | gt | lt
+ string entities = "&'\"><";
+
+ int pos = 0;
+ int entIdx = 0xF;
+ int pred = 0;
+ int predShift = 0;
+
+ int sbLen = sbChars.Length;
+
+ while (true) {
+ if (pos != 0xF) pos = entityRefChars.IndexOf((char)currCh) & 0xF;
+ if (pos == 0xF) FatalErr(errors[7]);
+ sbChars.Append((char)currCh);
+
+ int path = "\uFF35\u3F8F\u4F8F\u0F5F\uFF78\uE1F4\u2299\uEEFF\uEEFF\uFF4F"[pos];
+ int lBr = (path >> 4) & 0xF;
+ int rBr = path & 0xF;
+ int lPred = path >> 12;
+ int rPred = (path >> 8) & 0xF;
+ currCh = reader.Read();
+ cl++;
+ pos = 0xF;
+ if (lBr != 0xF && currCh == entityRefChars[lBr]) {
+ if (lPred < 0xE) entIdx = lPred;
+ pred = lPred;
+ predShift = 12; // left
+ } else if (rBr != 0xF && currCh == entityRefChars[rBr]) {
+ if (rPred < 0xE) entIdx = rPred;
+ pred = rPred;
+ predShift = 8; // right
+ } else if (currCh == ';') {
+ if (entIdx != 0xF
+ && predShift != 0
+ && ((path >> predShift) & 0xF) == 0xE) break;
+ continue; // pos == 0xF
+ }
+
+ pos=0;
+
+ }
+
+ int l = cl - this.col - 1;
+
+ if ((l > 0 && l < 5)
+ &&(StrEquals("amp", sbChars, sbLen, l)
+ || StrEquals("apos", sbChars, sbLen, l)
+ || StrEquals("quot", sbChars, sbLen, l)
+ || StrEquals("lt", sbChars, sbLen, l)
+ || StrEquals("gt", sbChars, sbLen, l))
+ ) {
+ sbChars.Length = sbLen;
+ sbChars.Append(entities[entIdx]);
+ } else FatalErr(errors[7]);
+ }
+
+ this.col = cl;
+ break;
+
+ default:
+ FatalErr(String.Format("Unexpected action code - {0}.", actionCode));
+ break;
+ }
+ } // while (true)
+
+ handler.OnEndParsing(this);
+
+ } // Parse
+
+}
+
+}
public class RSAPKCS1SignatureFormatter : AsymmetricSignatureFormatter {
- protected RSA rsa;
- protected HashAlgorithm hash;
+ private RSA rsa;
+ private HashAlgorithm hash;
public RSAPKCS1SignatureFormatter ()
{