public void DivideSingleByte(BigInteger bi2) { int resultPos = 0; ulong divisor = (ulong)bi2.Data[0]; int pos = Length - 1; ulong dividend = (ulong)Data[pos]; var remainder = new BigInteger(this); if (dividend >= divisor) { ulong quotient = dividend / divisor; Data[resultPos++] = (uint)quotient; remainder.Data[pos] = (uint)(dividend % divisor); } pos--; while (pos >= 0) { //Console.WriteLine(pos); dividend = ((ulong)remainder.Data[pos + 1] << 32) + (ulong)remainder.Data[pos]; ulong quotient = dividend / divisor; Data[resultPos++] = (uint)quotient; remainder.Data[pos + 1] = 0; remainder.Data[pos--] = (uint)(dividend % divisor); //Console.WriteLine(">>>> " + bi1); } Length = resultPos; remainder.Recycle(); }
public void DivideMultiByte(BigInteger bi2) { int remainderLen = Length + 1; uint mask = 0x80000000; uint val = bi2.Data[bi2.Length - 1]; int shift = 0, resultPos = 0; while (mask != 0 && (val & mask) == 0) { shift++; mask >>= 1; } var remainder = new BigInteger(this) { Length = remainderLen }; shiftLeft(remainder.Data, shift); bi2 = bi2 << shift; int j = remainderLen - bi2.Length; int pos = remainderLen - 1; ulong firstDivisorByte = bi2.Data[bi2.Length - 1]; ulong secondDivisorByte = bi2.Data[bi2.Length - 2]; int divisorLen = bi2.Length + 1; var kk = new BigInteger(0) { Length = divisorLen }; var ss = new BigInteger(0); while (j > 0) { ulong dividend = ((ulong)remainder.Data[pos] << 32) + (ulong)remainder.Data[pos - 1]; ulong q_hat = dividend / firstDivisorByte; ulong r_hat = dividend % firstDivisorByte; bool done = false; while (!done) { done = true; if (q_hat == 0x100000000 || (q_hat * secondDivisorByte) > ((r_hat << 32) + remainder.Data[pos - 2])) { q_hat--; r_hat += firstDivisorByte; if (r_hat < 0x100000000) { done = false; } } } kk.Length = divisorLen; Array.Copy(remainder.Data, pos - divisorLen + 1, kk.Data, 0, divisorLen); while (kk.Length > 1 && kk.Data[kk.Length - 1] == 0) { kk.Length--; } // BigInteger ss = bi2 * (long)q_hat; Multiply(bi2, q_hat, ref ss); while (ss > kk) { q_hat--; ss.Subtract(bi2); } kk.Subtract(ss); Array.Copy(kk.Data, 0, remainder.Data, pos - divisorLen + 1, divisorLen); Data[resultPos++] = (uint)q_hat; pos--; j--; } Length = resultPos; Array.Reverse(Data, 0, Length); Array.Clear(Data, Length, maxLength - Length); while (Length > 1 && Data[Length - 1] == 0) { Length--; } if (Length == 0) { Length = 1; } kk.Recycle(); ss.Recycle(); remainder.Recycle(); }
//*********************************************************************** // 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 void BarrettReduction(ref BigInteger x1, BigInteger x2, BigInteger n, BigInteger constant, ref BigInteger temp) { Multiply(x1, x2, ref temp); int k = n.Length, kPlusOne = k + 1, kMinusOne = k - 1; //var q1 = new BigInteger(0); //// q1 = x / b^(k-1) //for (int i = kMinusOne, j = 0; i < x.Length; i++, j++) // q1.Data[j] = x.Data[i]; //q1.Length = x.Length - kMinusOne; //if(q1.Length <= 0) // q1.Length = 1; //var q2 = q1 * constant; //q1.Recycle(); //q1 = q2; var q1 = new BigIntegerShell(temp, kMinusOne, temp.Length - kMinusOne) * constant; // r1 = x mod b^(k+1) // i.e. keep the lowest (k+1) words //var r1 = new BigInteger(0); //int lengthToCopy = (x.Length > kPlusOne) ? kPlusOne : x.Length; temp.Length = (temp.Length > kPlusOne) ? kPlusOne : temp.Length; //for(int i = 0; i < lengthToCopy; i++) // r1.Data[i] = x.Data[i]; //r1.Length = lengthToCopy; // r2 = (q3 * n) mod b^(k+1) // partial multiplication of q3 and n var r2 = new BigInteger(0); for (int i = kPlusOne; i < q1.Length; i++) { if (q1.Data[i] == 0) { continue; } ulong mcarry = 0; int t = i - kPlusOne; for (int j = 0; j < n.Length && t < kPlusOne; j++, t++) { // t = i + j ulong val = (q1.Data[i] * (ulong)n.Data[j]) + r2.Data[t] + mcarry; r2.Data[t] = (uint)val; mcarry = (val >> 32); } if (t < kPlusOne) { r2.Data[t] = (uint)mcarry; } } r2.Length = kPlusOne; while (r2.Length > 1 && r2.Data[r2.Length - 1] == 0) { r2.Length--; } temp.Subtract(r2); r2.Recycle(); if ((temp.Data[maxLength - 1] & 0x80000000) != 0) // negative { ulong carry = 1; for (var i = kPlusOne; carry != 0 && i < maxLength; i++) { var sum = temp.Data[i] + carry; carry = sum >> 32; temp.Data[i] = (uint)sum; } } while (temp >= n) { temp.Subtract(n); } q1.Recycle(); q1 = temp; temp = x1; x1 = q1; }
//*********************************************************************** // 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 var constant = new BigInteger(0); int i = n.Length << 1; constant.Data[i] = 0x00000001; constant.Length = i + 1; constant.Divide(n); //constant /= n; int totalBits = exp.bitCount(); int count = 0; var temp = new BigInteger(0); // perform squaring and multiply exponentiation for (var pos = 0; pos < exp.Length; pos++) { uint mask = 0x01; //Console.WriteLine("pos = " + pos); for (var index = 0; index < 32; index++) { if ((exp.Data[pos] & mask) != 0) { BarrettReduction(ref resultNum, tempNum, n, constant, ref temp); } mask <<= 1; BarrettReduction(ref tempNum, tempNum, n, constant, ref temp); if (tempNum.Length == 1 && tempNum.Data[0] == 1) { if (thisNegative && (exp.Data[0] & 0x1) != 0) //odd exp { resultNum.Negative(); } return(resultNum); } count++; if (count == totalBits) { break; } } } constant.Recycle(); temp.Recycle(); if (thisNegative && (exp.Data[0] & 0x1) != 0) //odd exp { resultNum.Negative(); } return(resultNum); }
public BigInteger GetRemainderMultiByte(BigInteger bi2) { var remainder = new BigInteger(this); remainder.Length++; uint mask = 0x80000000; uint val = bi2.Data[bi2.Length - 1]; int shift = 0; while (mask != 0 && (val & mask) == 0) { shift++; mask >>= 1; } shiftLeft(remainder.Data, shift); bi2 = bi2 << shift; int j = remainder.Length - bi2.Length; int pos = remainder.Length - 1; ulong firstDivisorByte = bi2.Data[bi2.Length - 1]; ulong secondDivisorByte = bi2.Data[bi2.Length - 2]; int divisorLen = bi2.Length + 1; var kk = new BigInteger(0) { Length = divisorLen }; var ss = new BigInteger(0); while (j > 0) { ulong dividend = ((ulong)remainder.Data[pos] << 32) + (ulong)remainder.Data[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.Data[pos - 2])) { q_hat--; r_hat += firstDivisorByte; if (r_hat < 0x100000000) { done = false; } } } kk.Length = divisorLen; Array.Copy(remainder.Data, pos - divisorLen + 1, kk.Data, 0, divisorLen); while (kk.Length > 1 && kk.Data[kk.Length - 1] == 0) { kk.Length--; } //var ss = bi2 * (long)q_hat; Multiply(bi2, q_hat, ref ss); while (ss > kk) { q_hat--; ss.Subtract(bi2); } kk.Subtract(ss); Array.Copy(kk.Data, 0, remainder.Data, pos - divisorLen + 1, divisorLen); pos--; j--; } ss.Recycle(); kk.Recycle(); remainder.Length = shiftRight(remainder.Data, shift); return(remainder); }
public BigInteger GetRemainderMultiByte(BigInteger bi2) { var remainder = new BigInteger(this); remainder.Length++; uint mask = 0x80000000; uint val = bi2.Data[bi2.Length - 1]; int shift = 0; while (mask != 0 && (val & mask) == 0) { shift++; mask >>= 1; } shiftLeft(remainder.Data, shift); bi2 = bi2 << shift; int j = remainder.Length - bi2.Length; int pos = remainder.Length - 1; ulong firstDivisorByte = bi2.Data[bi2.Length - 1]; ulong secondDivisorByte = bi2.Data[bi2.Length - 2]; int divisorLen = bi2.Length + 1; var kk = new BigInteger(0) { Length = divisorLen }; var ss = new BigInteger(0); while (j > 0) { ulong dividend = ((ulong)remainder.Data[pos] << 32) + (ulong)remainder.Data[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.Data[pos - 2])) { q_hat--; r_hat += firstDivisorByte; if (r_hat < 0x100000000) done = false; } } kk.Length = divisorLen; Array.Copy(remainder.Data, pos - divisorLen + 1, kk.Data, 0, divisorLen); while (kk.Length > 1 && kk.Data[kk.Length - 1] == 0)kk.Length--; //var ss = bi2 * (long)q_hat; Multiply(bi2, q_hat, ref ss); while (ss > kk) { q_hat--; ss.Subtract(bi2); } kk.Subtract(ss); Array.Copy(kk.Data, 0, remainder.Data, pos - divisorLen + 1, divisorLen); pos--; j--; } ss.Recycle(); kk.Recycle(); remainder.Length = shiftRight(remainder.Data, shift); return remainder; }
public void DivideMultiByte(BigInteger bi2) { int remainderLen = Length + 1; uint mask = 0x80000000; uint val = bi2.Data[bi2.Length - 1]; int shift = 0, resultPos = 0; while (mask != 0 && (val & mask) == 0) { shift++; mask >>= 1; } var remainder = new BigInteger(this) {Length = remainderLen}; shiftLeft(remainder.Data, shift); bi2 = bi2 << shift; int j = remainderLen - bi2.Length; int pos = remainderLen - 1; ulong firstDivisorByte = bi2.Data[bi2.Length - 1]; ulong secondDivisorByte = bi2.Data[bi2.Length - 2]; int divisorLen = bi2.Length + 1; var kk = new BigInteger(0) {Length = divisorLen}; var ss = new BigInteger(0); while (j > 0) { ulong dividend = ((ulong)remainder.Data[pos] << 32) + (ulong)remainder.Data[pos - 1]; ulong q_hat = dividend / firstDivisorByte; ulong r_hat = dividend % firstDivisorByte; bool done = false; while (!done) { done = true; if (q_hat == 0x100000000 || (q_hat * secondDivisorByte) > ((r_hat << 32) + remainder.Data[pos - 2])) { q_hat--; r_hat += firstDivisorByte; if (r_hat < 0x100000000) done = false; } } kk.Length = divisorLen; Array.Copy(remainder.Data, pos - divisorLen + 1 ,kk.Data, 0, divisorLen); while (kk.Length > 1 && kk.Data[kk.Length - 1] == 0) kk.Length--; // BigInteger ss = bi2 * (long)q_hat; Multiply(bi2,q_hat,ref ss); while (ss > kk) { q_hat--; ss.Subtract(bi2); } kk.Subtract(ss); Array.Copy(kk.Data,0, remainder.Data, pos - divisorLen + 1, divisorLen); Data[resultPos++] = (uint)q_hat; pos--; j--; } Length = resultPos; Array.Reverse(Data,0,Length); Array.Clear(Data,Length,maxLength-Length); while (Length > 1 && Data[Length - 1] == 0) Length--; if (Length == 0) Length = 1; kk.Recycle(); ss.Recycle(); remainder.Recycle(); }
//*********************************************************************** // 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 void BarrettReduction(ref BigInteger x1,BigInteger x2, BigInteger n, BigInteger constant,ref BigInteger temp) { Multiply(x1, x2, ref temp); int k = n.Length, kPlusOne = k+1, kMinusOne = k-1; //var q1 = new BigInteger(0); //// q1 = x / b^(k-1) //for (int i = kMinusOne, j = 0; i < x.Length; i++, j++) // q1.Data[j] = x.Data[i]; //q1.Length = x.Length - kMinusOne; //if(q1.Length <= 0) // q1.Length = 1; //var q2 = q1 * constant; //q1.Recycle(); //q1 = q2; var q1 = new BigIntegerShell(temp, kMinusOne, temp.Length - kMinusOne) * constant; // r1 = x mod b^(k+1) // i.e. keep the lowest (k+1) words //var r1 = new BigInteger(0); //int lengthToCopy = (x.Length > kPlusOne) ? kPlusOne : x.Length; temp.Length = (temp.Length > kPlusOne) ? kPlusOne : temp.Length; //for(int i = 0; i < lengthToCopy; i++) // r1.Data[i] = x.Data[i]; //r1.Length = lengthToCopy; // r2 = (q3 * n) mod b^(k+1) // partial multiplication of q3 and n var r2 = new BigInteger(0); for (int i = kPlusOne; i < q1.Length; i++) { if(q1.Data[i] == 0) continue; ulong mcarry = 0; int t = i - kPlusOne; for(int j = 0; j < n.Length && t < kPlusOne; j++, t++) { // t = i + j ulong val = (q1.Data[i] * (ulong)n.Data[j]) + r2.Data[t] + mcarry; r2.Data[t] = (uint)val; mcarry = (val >> 32); } if(t < kPlusOne) r2.Data[t] = (uint)mcarry; } r2.Length = kPlusOne; while(r2.Length > 1 && r2.Data[r2.Length-1] == 0) r2.Length--; temp.Subtract(r2); r2.Recycle(); if ((temp.Data[maxLength - 1] & 0x80000000) != 0) // negative { ulong carry = 1; for (var i = kPlusOne; carry != 0 && i<maxLength; i++) { var sum = temp.Data[i] + carry; carry = sum >> 32; temp.Data[i] = (uint)sum; } } while (temp >= n) temp.Subtract(n); q1.Recycle(); q1 = temp; temp = x1; x1 = q1; }
//*********************************************************************** // 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 var constant = new BigInteger(0); int i = n.Length << 1; constant.Data[i] = 0x00000001; constant.Length = i + 1; constant.Divide(n); //constant /= n; int totalBits = exp.bitCount(); int count = 0; var temp = new BigInteger(0); // perform squaring and multiply exponentiation for(var pos = 0; pos < exp.Length; pos++) { uint mask = 0x01; //Console.WriteLine("pos = " + pos); for(var index = 0; index < 32; index++) { if ((exp.Data[pos] & mask) != 0) { BarrettReduction(ref resultNum, tempNum, n, constant, ref temp); } mask <<= 1; BarrettReduction(ref tempNum, tempNum, n, constant, ref temp); if(tempNum.Length == 1 && tempNum.Data[0] == 1) { if(thisNegative && (exp.Data[0] & 0x1) != 0) //odd exp resultNum.Negative(); return resultNum; } count++; if(count == totalBits) break; } } constant.Recycle(); temp.Recycle(); if(thisNegative && (exp.Data[0] & 0x1) != 0) //odd exp resultNum.Negative(); return resultNum; }