/// <summary> /// Generates a new, random BigInteger of the specified capacity. /// </summary> /// <param name="bits">The number of bits for the new number.</param> /// <param name="rng">A random number generator to use to obtain the bits.</param> /// <returns>A random number of the specified capacity.</returns> public static BigInteger GenerateRandom( int bits, RandomNumberGenerator rng ) { int dwords = bits >> 5; int remBits = bits & 0x1F; if ( remBits != 0 ) dwords++; BigInteger ret = new BigInteger(Sign.Positive, ( uint )dwords + 1); byte[] random = new byte[dwords << 2]; rng.GetBytes(random); Buffer.BlockCopy(random, 0, ret.data, 0, ( int )dwords << 2); if ( remBits != 0 ) { uint mask = ( uint )( 0x01 << ( remBits - 1 ) ); ret.data[dwords - 1] |= mask; mask = ( uint )( 0xFFFFFFFF >> ( 32 - remBits ) ); ret.data[dwords - 1] &= mask; } else ret.data[dwords - 1] |= 0x80000000; ret.Normalize(); return ret; }
public static BigInteger MultiplyByDword( BigInteger n, uint f ) { BigInteger ret = new BigInteger(Sign.Positive, n.length + 1); uint i = 0; ulong c = 0; do { c += ( ulong )n.data[i] * ( ulong )f; ret.data[i] = ( uint )c; c >>= 32; } while ( ++i < n.length ); ret.data[i] = ( uint )c; ret.Normalize(); return ret; }
public static BigInteger operator *( BigInteger bi1, BigInteger bi2 ) { if ( bi1 == 0 || bi2 == 0 ) return 0; // // Validate pointers // if ( bi1.data.Length < bi1.length ) throw new IndexOutOfRangeException("bi1 out of range"); if ( bi2.data.Length < bi2.length ) throw new IndexOutOfRangeException("bi2 out of range"); BigInteger ret = new BigInteger(Sign.Positive, bi1.length + bi2.length); Kernel.Multiply(bi1.data, 0, bi1.length, bi2.data, 0, bi2.length, ret.data, 0); ret.Normalize(); return ret; }
public static BigInteger LeftShift( BigInteger bi, int n ) { if ( n == 0 ) return new BigInteger(bi, bi.length + 1); int w = n >> 5; n &= ( ( 1 << 5 ) - 1 ); BigInteger ret = new BigInteger(Sign.Positive, bi.length + 1 + ( uint )w); uint i = 0, l = bi.length; if ( n != 0 ) { uint x, carry = 0; while ( i < l ) { x = bi.data[i]; ret.data[i + w] = ( x << n ) | carry; carry = x >> ( 32 - n ); i++; } ret.data[i + w] = carry; } else { while ( i < l ) { ret.data[i + w] = bi.data[i]; i++; } } ret.Normalize(); return ret; }
public static BigInteger RightShift( BigInteger bi, int n ) { if ( n == 0 ) return new BigInteger(bi); int w = n >> 5; int s = n & ( ( 1 << 5 ) - 1 ); BigInteger ret = new BigInteger(Sign.Positive, bi.length - ( uint )w + 1); uint l = ( uint )ret.data.Length - 1; if ( s != 0 ) { uint x, carry = 0; while ( l-- > 0 ) { x = bi.data[l + w]; ret.data[l] = ( x >> n ) | carry; carry = x << ( 32 - n ); } } else { while ( l-- > 0 ) ret.data[l] = bi.data[l + w]; } ret.Normalize(); return ret; }
public static BigInteger[] DwordDivMod( BigInteger n, uint d ) { BigInteger ret = new BigInteger(Sign.Positive, n.length); ulong r = 0; uint i = n.length; while ( i-- > 0 ) { r <<= 32; r |= n.data[i]; ret.data[i] = ( uint )( r / d ); r %= d; } ret.Normalize(); BigInteger rem = ( uint )r; return new BigInteger[] { ret, rem }; }
public static BigInteger[] multiByteDivide( BigInteger bi1, BigInteger bi2 ) { if ( Kernel.Compare(bi1, bi2) == Sign.Negative ) return new BigInteger[2] { 0, new BigInteger(bi1) }; bi1.Normalize(); bi2.Normalize(); if ( bi2.length == 1 ) return DwordDivMod(bi1, bi2.data[0]); uint remainderLen = bi1.length + 1; int divisorLen = ( int )bi2.length + 1; uint mask = 0x80000000; uint val = bi2.data[bi2.length - 1]; int shift = 0; int resultPos = ( int )bi1.length - ( int )bi2.length; while ( mask != 0 && ( val & mask ) == 0 ) { shift++; mask >>= 1; } BigInteger quot = new BigInteger(Sign.Positive, bi1.length - bi2.length + 1); BigInteger rem = ( bi1 << shift ); uint[] remainder = rem.data; bi2 = bi2 << shift; int j = ( int )( remainderLen - bi2.length ); int pos = ( int )remainderLen - 1; uint firstDivisorByte = bi2.data[bi2.length - 1]; ulong secondDivisorByte = bi2.data[bi2.length - 2]; while ( j > 0 ) { ulong dividend = ( ( ulong )remainder[pos] << 32 ) + ( ulong )remainder[pos - 1]; ulong q_hat = dividend / ( ulong )firstDivisorByte; ulong r_hat = dividend % ( ulong )firstDivisorByte; do { if ( q_hat == 0x100000000 || ( q_hat * secondDivisorByte ) > ( ( r_hat << 32 ) + remainder[pos - 2] ) ) { q_hat--; r_hat += ( ulong )firstDivisorByte; if ( r_hat < 0x100000000 ) continue; } break; } while ( true ); // // At this point, q_hat is either exact, or one too large // (more likely to be exact) so, we attempt to multiply the // divisor by q_hat, if we get a borrow, we just subtract // one from q_hat and add the divisor back. // uint t; uint dPos = 0; int nPos = pos - divisorLen + 1; ulong mc = 0; uint uint_q_hat = ( uint )q_hat; do { mc += ( ulong )bi2.data[dPos] * ( ulong )uint_q_hat; t = remainder[nPos]; remainder[nPos] -= ( uint )mc; mc >>= 32; if ( remainder[nPos] > t ) mc++; dPos++; nPos++; } while ( dPos < divisorLen ); nPos = pos - divisorLen + 1; dPos = 0; // Overestimate if ( mc != 0 ) { uint_q_hat--; ulong sum = 0; do { sum = ( ( ulong )remainder[nPos] ) + ( ( ulong )bi2.data[dPos] ) + sum; remainder[nPos] = ( uint )sum; sum >>= 32; dPos++; nPos++; } while ( dPos < divisorLen ); } quot.data[resultPos--] = ( uint )uint_q_hat; pos--; j--; } quot.Normalize(); rem.Normalize(); BigInteger[] ret = new BigInteger[2] { quot, rem }; if ( shift != 0 ) ret[1] >>= shift; return ret; }
public static void PlusEq( BigInteger bi1, BigInteger bi2 ) { uint[] x, y; uint yMax, xMax, i = 0; bool flag = false; // x should be bigger if ( bi1.length < bi2.length ) { flag = true; x = bi2.data; xMax = bi2.length; y = bi1.data; yMax = bi1.length; } else { x = bi1.data; xMax = bi1.length; y = bi2.data; yMax = bi2.length; } uint[] r = bi1.data; ulong sum = 0; // Add common parts of both numbers do { sum += ( ( ulong )x[i] ) + ( ( ulong )y[i] ); r[i] = ( uint )sum; sum >>= 32; } while ( ++i < yMax ); // SpecialCopy remainder of longer number while carry propagation is required bool carry = ( sum != 0 ); if ( carry ) { if ( i < xMax ) { do carry = ( ( r[i] = x[i] + 1 ) == 0 ); while ( ++i < xMax && carry ); } if ( carry ) { r[i] = 1; bi1.length = ++i; return; } } // SpecialCopy the rest if ( flag && i < xMax - 1 ) { do r[i] = x[i]; while ( ++i < xMax ); } bi1.length = xMax + 1; bi1.Normalize(); }
/// <summary> /// Performs n / i and n % i in one operation. /// </summary> /// <param name="n">A BigInteger, upon exit this will hold n / i</param> /// <param name="i">The divisor</param> /// <returns>n % i</returns> public static uint SingleByteDivideInPlace( BigInteger n, uint d ) { ulong r = 0; uint i = n.length; while ( i-- > 0 ) { r <<= 32; r |= n.data[i]; n.data[i] = ( uint )( r / d ); r %= d; } n.Normalize(); return ( uint )r; }
public static BigInteger Subtract( BigInteger big, BigInteger small ) { BigInteger result = new BigInteger(Sign.Positive, big.length); uint[] r = result.data, b = big.data, s = small.data; uint i = 0, c = 0; do { uint x = s[i]; if ( ( ( x += c ) < c ) | ( ( r[i] = b[i] - x ) > ~x ) ) c = 1; else c = 0; } while ( ++i < small.length ); if ( i == big.length ) goto fixup; if ( c == 1 ) { do r[i] = b[i] - 1; while ( b[i++] == 0 && i < big.length ); if ( i == big.length ) goto fixup; } do r[i] = b[i]; while ( ++i < big.length ); fixup: result.Normalize(); return result; }
/// <summary> /// Adds two numbers with the same sign. /// </summary> /// <param name="bi1">A BigInteger</param> /// <param name="bi2">A BigInteger</param> /// <returns>bi1 + bi2</returns> public static BigInteger AddSameSign( BigInteger bi1, BigInteger bi2 ) { uint[] x, y; uint yMax, xMax, i = 0; // x should be bigger if ( bi1.length < bi2.length ) { x = bi2.data; xMax = bi2.length; y = bi1.data; yMax = bi1.length; } else { x = bi1.data; xMax = bi1.length; y = bi2.data; yMax = bi2.length; } BigInteger result = new BigInteger(Sign.Positive, xMax + 1); uint[] r = result.data; ulong sum = 0; // Add common parts of both numbers do { sum = ( ( ulong )x[i] ) + ( ( ulong )y[i] ) + sum; r[i] = ( uint )sum; sum >>= 32; } while ( ++i < yMax ); // SpecialCopy remainder of longer number while carry propagation is required bool carry = ( sum != 0 ); if ( carry ) { if ( i < xMax ) { do carry = ( ( r[i] = x[i] + 1 ) == 0 ); while ( ++i < xMax && carry ); } if ( carry ) { r[i] = 1; result.length = ++i; return result; } } // SpecialCopy the rest if ( i < xMax ) { do r[i] = x[i]; while ( ++i < xMax ); } result.Normalize(); return result; }
public static BigInteger ToMont( BigInteger n, BigInteger m ) { n.Normalize(); m.Normalize(); n <<= ( int )m.length * 32; n %= m; return n; }
private unsafe BigInteger EvenPow( uint b, BigInteger exp ) { exp.Normalize(); uint[] wkspace = new uint[mod.length << 1 + 1]; BigInteger resultNum = new BigInteger(( BigInteger )b, mod.length << 1 + 1); uint pos = ( uint )exp.BitCount() - 2; // // We know that the first itr will make the val m // do { // // r = r ^ 2 % m // Kernel.SquarePositive(resultNum, ref wkspace); if ( !( resultNum.length < mod.length ) ) BarrettReduction(resultNum); if ( exp.TestBit(pos) ) { // // r = r * m % m // // TODO: Is Unsafe really speeding things up? fixed ( uint* u = resultNum.data ) { uint i = 0; ulong mc = 0; do { mc += ( ulong )u[i] * ( ulong )b; u[i] = ( uint )mc; mc >>= 32; } while ( ++i < resultNum.length ); if ( resultNum.length < mod.length ) { if ( mc != 0 ) { u[i] = ( uint )mc; resultNum.length++; while ( resultNum >= mod ) Kernel.MinusEq(resultNum, mod); } } else if ( mc != 0 ) { // // First, we estimate the quotient by dividing // the first part of each of the numbers. Then // we correct this, if necessary, with a subtraction. // uint cc = ( uint )mc; // We would rather have this estimate overshoot, // so we add one to the divisor uint divEstimate = ( uint )( ( ( ( ulong )cc << 32 ) | ( ulong )u[i - 1] ) / ( mod.data[mod.length - 1] + 1 ) ); uint t; i = 0; mc = 0; do { mc += ( ulong )mod.data[i] * ( ulong )divEstimate; t = u[i]; u[i] -= ( uint )mc; mc >>= 32; if ( u[i] > t ) mc++; i++; } while ( i < resultNum.length ); cc -= ( uint )mc; if ( cc != 0 ) { uint sc = 0, j = 0; uint[] s = mod.data; do { uint a = s[j]; if ( ( ( a += sc ) < sc ) | ( ( u[j] -= a ) > ~a ) ) sc = 1; else sc = 0; j++; } while ( j < resultNum.length ); cc -= sc; } while ( resultNum >= mod ) Kernel.MinusEq(resultNum, mod); } else { while ( resultNum >= mod ) Kernel.MinusEq(resultNum, mod); } } } } while ( pos-- > 0 ); return resultNum; }
public void BarrettReduction( BigInteger x ) { BigInteger n = mod; uint k = n.length, kPlusOne = k + 1, kMinusOne = k - 1; // x < mod, so nothing to do. if ( x.length < k ) return; BigInteger q3; // // Validate pointers // if ( x.data.Length < x.length ) throw new IndexOutOfRangeException("x out of range"); // q1 = x / m^ (j-1) // q2 = q1 * constant // q3 = q2 / m^ (j+1), Needs to be accessed with an offset of kPlusOne // TODO: We should the method in HAC p 604 to do this (14.45) q3 = new BigInteger(Sign.Positive, x.length - kMinusOne + constant.length); Kernel.Multiply(x.data, kMinusOne, x.length - kMinusOne, constant.data, 0, constant.length, q3.data, 0); // r1 = x mod m^ (j+1) // i.e. keep the lowest (j+1) words uint lengthToCopy = ( x.length > kPlusOne ) ? kPlusOne : x.length; x.length = lengthToCopy; x.Normalize(); // r2 = (q3 * n) mod m^ (j+1) // partial multiplication of q3 and n BigInteger r2 = new BigInteger(Sign.Positive, kPlusOne); Kernel.MultiplyMod2p32pmod(q3.data, ( int )kPlusOne, ( int )q3.length - ( int )kPlusOne, n.data, 0, ( int )n.length, r2.data, 0, ( int )kPlusOne); r2.Normalize(); if ( r2 <= x ) { Kernel.MinusEq(x, r2); } else { BigInteger val = new BigInteger(Sign.Positive, kPlusOne + 1); val.data[kPlusOne] = 0x00000001; Kernel.MinusEq(val, r2); Kernel.PlusEq(x, val); } while ( x >= n ) Kernel.MinusEq(x, n); }