2015-09-28 04:01:17 +02:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
namespace TLSharp.Core.MTProto.Crypto
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
[Serializable]
|
2015-09-28 04:01:17 +02:00
|
|
|
|
#endif
|
2016-04-18 12:50:57 +02:00
|
|
|
|
public class BigInteger
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
private const long IMASK = 0xffffffffL;
|
|
|
|
|
|
|
|
|
|
|
|
private const int BitsPerByte = 8;
|
|
|
|
|
|
private const int BitsPerInt = 32;
|
|
|
|
|
|
|
|
|
|
|
|
private const int BytesPerInt = 4;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// The primes b/w 2 and ~2^10
|
|
|
|
|
|
/*
|
|
|
|
|
|
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
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// Each list has a product < 2^31
|
2017-04-13 08:38:01 +02:00
|
|
|
|
private static readonly int[][] primeLists =
|
|
|
|
|
|
{
|
|
|
|
|
|
new[] {3, 5, 7, 11, 13, 17, 19, 23},
|
|
|
|
|
|
new[] {29, 31, 37, 41, 43},
|
|
|
|
|
|
new[] {47, 53, 59, 61, 67},
|
|
|
|
|
|
new[] {71, 73, 79, 83},
|
|
|
|
|
|
new[] {89, 97, 101, 103},
|
|
|
|
|
|
|
|
|
|
|
|
new[] {107, 109, 113, 127},
|
|
|
|
|
|
new[] {131, 137, 139, 149},
|
|
|
|
|
|
new[] {151, 157, 163, 167},
|
|
|
|
|
|
new[] {173, 179, 181, 191},
|
|
|
|
|
|
new[] {193, 197, 199, 211},
|
|
|
|
|
|
|
|
|
|
|
|
new[] {223, 227, 229},
|
|
|
|
|
|
new[] {233, 239, 241},
|
|
|
|
|
|
new[] {251, 257, 263},
|
|
|
|
|
|
new[] {269, 271, 277},
|
|
|
|
|
|
new[] {281, 283, 293},
|
|
|
|
|
|
|
|
|
|
|
|
new[] {307, 311, 313},
|
|
|
|
|
|
new[] {317, 331, 337},
|
|
|
|
|
|
new[] {347, 349, 353},
|
|
|
|
|
|
new[] {359, 367, 373},
|
|
|
|
|
|
new[] {379, 383, 389},
|
|
|
|
|
|
|
|
|
|
|
|
new[] {397, 401, 409},
|
|
|
|
|
|
new[] {419, 421, 431},
|
|
|
|
|
|
new[] {433, 439, 443},
|
|
|
|
|
|
new[] {449, 457, 461},
|
|
|
|
|
|
new[] {463, 467, 479},
|
|
|
|
|
|
|
|
|
|
|
|
new[] {487, 491, 499},
|
|
|
|
|
|
new[] {503, 509, 521},
|
|
|
|
|
|
new[] {523, 541, 547},
|
|
|
|
|
|
new[] {557, 563, 569},
|
|
|
|
|
|
new[] {571, 577, 587},
|
|
|
|
|
|
|
|
|
|
|
|
new[] {593, 599, 601},
|
|
|
|
|
|
new[] {607, 613, 617},
|
|
|
|
|
|
new[] {619, 631, 641},
|
|
|
|
|
|
new[] {643, 647, 653},
|
|
|
|
|
|
new[] {659, 661, 673},
|
|
|
|
|
|
|
|
|
|
|
|
new[] {677, 683, 691},
|
|
|
|
|
|
new[] {701, 709, 719},
|
|
|
|
|
|
new[] {727, 733, 739},
|
|
|
|
|
|
new[] {743, 751, 757},
|
|
|
|
|
|
new[] {761, 769, 773},
|
|
|
|
|
|
|
|
|
|
|
|
new[] {787, 797, 809},
|
|
|
|
|
|
new[] {811, 821, 823},
|
|
|
|
|
|
new[] {827, 829, 839},
|
|
|
|
|
|
new[] {853, 857, 859},
|
|
|
|
|
|
new[] {863, 877, 881},
|
|
|
|
|
|
|
|
|
|
|
|
new[] {883, 887, 907},
|
|
|
|
|
|
new[] {911, 919, 929},
|
|
|
|
|
|
new[] {937, 941, 947},
|
|
|
|
|
|
new[] {953, 967, 971},
|
|
|
|
|
|
new[] {977, 983, 991},
|
|
|
|
|
|
|
|
|
|
|
|
new[] {997, 1009, 1013},
|
|
|
|
|
|
new[] {1019, 1021, 1031}
|
2016-04-18 12:50:57 +02:00
|
|
|
|
};
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
private static readonly int[] primeProducts;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
private static readonly ulong UIMASK = IMASK;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
private static readonly int[] ZeroMagnitude = new int[0];
|
|
|
|
|
|
private static readonly byte[] ZeroEncoding = new byte[0];
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly BigInteger Zero = new BigInteger(0, ZeroMagnitude, false);
|
|
|
|
|
|
public static readonly BigInteger One = createUValueOf(1);
|
|
|
|
|
|
public static readonly BigInteger Two = createUValueOf(2);
|
|
|
|
|
|
public static readonly BigInteger Three = createUValueOf(3);
|
|
|
|
|
|
public static readonly BigInteger Ten = createUValueOf(10);
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly int chunk2 = 1; // TODO Parse 64 bits at a time
|
|
|
|
|
|
private static readonly BigInteger radix2 = ValueOf(2);
|
|
|
|
|
|
private static readonly BigInteger radix2E = radix2.Pow(chunk2);
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly int chunk10 = 19;
|
|
|
|
|
|
private static readonly BigInteger radix10 = ValueOf(10);
|
|
|
|
|
|
private static readonly BigInteger radix10E = radix10.Pow(chunk10);
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly int chunk16 = 16;
|
|
|
|
|
|
private static readonly BigInteger radix16 = ValueOf(16);
|
|
|
|
|
|
private static readonly BigInteger radix16E = radix16.Pow(chunk16);
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly Random RandomSource = new Random();
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
private static readonly byte[] rndMask = {255, 127, 63, 31, 15, 7, 3, 1};
|
|
|
|
|
|
|
|
|
|
|
|
private static readonly byte[] bitCounts =
|
|
|
|
|
|
{
|
|
|
|
|
|
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1,
|
|
|
|
|
|
2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4,
|
|
|
|
|
|
4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3,
|
|
|
|
|
|
4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5,
|
|
|
|
|
|
3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2,
|
|
|
|
|
|
3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3,
|
|
|
|
|
|
3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6,
|
|
|
|
|
|
7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,
|
|
|
|
|
|
5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5,
|
|
|
|
|
|
6, 6, 7, 6, 7, 7, 8
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
private int[] magnitude; // array of ints with [0] being the most significant
|
|
|
|
|
|
private long mQuote = -1L; // -m^(-1) mod b, b = 2^32 (see Montgomery mult.)
|
|
|
|
|
|
private int nBitLength = -1; // cache calcBitLength() value
|
|
|
|
|
|
private int nBits = -1; // cache BitCount() value
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
static BigInteger()
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
primeProducts = new int[primeLists.Length];
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = 0; i < primeLists.Length; ++i)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var primeList = primeLists[i];
|
|
|
|
|
|
var product = 1;
|
|
|
|
|
|
for (var j = 0; j < primeList.Length; ++j)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
product *= primeList[j];
|
|
|
|
|
|
primeProducts[i] = product;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
private BigInteger()
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private BigInteger(
|
|
|
|
|
|
int signum,
|
|
|
|
|
|
int[] mag,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
bool checkMag)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (checkMag)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var i = 0;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (i < mag.Length && mag[i] == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
++i;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (i == mag.Length)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// this.sign = 0;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
magnitude = ZeroMagnitude;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
SignValue = signum;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (i == 0)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
magnitude = mag;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// strip leading 0 words
|
2017-04-13 08:38:01 +02:00
|
|
|
|
magnitude = new int[mag.Length - i];
|
|
|
|
|
|
Array.Copy(mag, i, magnitude, 0, magnitude.Length);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
SignValue = signum;
|
|
|
|
|
|
magnitude = mag;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger(
|
|
|
|
|
|
string value)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
: this(value, 10)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger(
|
|
|
|
|
|
string str,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int radix)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (str.Length == 0)
|
|
|
|
|
|
throw new FormatException("Zero length BigInteger");
|
|
|
|
|
|
|
|
|
|
|
|
NumberStyles style;
|
|
|
|
|
|
int chunk;
|
|
|
|
|
|
BigInteger r;
|
|
|
|
|
|
BigInteger rE;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
switch (radix)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
case 2:
|
|
|
|
|
|
// Is there anyway to restrict to binary digits?
|
|
|
|
|
|
style = NumberStyles.Integer;
|
|
|
|
|
|
chunk = chunk2;
|
|
|
|
|
|
r = radix2;
|
|
|
|
|
|
rE = radix2E;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 10:
|
|
|
|
|
|
// This style seems to handle spaces and minus sign already (our processing redundant?)
|
|
|
|
|
|
style = NumberStyles.Integer;
|
|
|
|
|
|
chunk = chunk10;
|
|
|
|
|
|
r = radix10;
|
|
|
|
|
|
rE = radix10E;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 16:
|
|
|
|
|
|
// TODO Should this be HexNumber?
|
|
|
|
|
|
style = NumberStyles.AllowHexSpecifier;
|
|
|
|
|
|
chunk = chunk16;
|
|
|
|
|
|
r = radix16;
|
|
|
|
|
|
rE = radix16E;
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
throw new FormatException("Only bases 2, 10, or 16 allowed");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var index = 0;
|
|
|
|
|
|
SignValue = 1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (str[0] == '-')
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (str.Length == 1)
|
|
|
|
|
|
throw new FormatException("Zero length BigInteger");
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
SignValue = -1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
index = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// strip leading zeros from the string str
|
2017-04-13 08:38:01 +02:00
|
|
|
|
while (index < str.Length && int.Parse(str[index].ToString(), style) == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
index++;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (index >= str.Length)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// zero value - we're done
|
2017-04-13 08:38:01 +02:00
|
|
|
|
SignValue = 0;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
magnitude = ZeroMagnitude;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////
|
|
|
|
|
|
// could we work out the max number of ints required to store
|
|
|
|
|
|
// str.Length digits in the given base, then allocate that
|
|
|
|
|
|
// storage in one hit?, then Generate the magnitude in one hit too?
|
|
|
|
|
|
//////
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var b = Zero;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var next = index + chunk;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (next <= str.Length)
|
|
|
|
|
|
do
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var s = str.Substring(index, chunk);
|
|
|
|
|
|
var i = ulong.Parse(s, style);
|
|
|
|
|
|
var bi = createUValueOf(i);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
switch (radix)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
case 2:
|
|
|
|
|
|
// TODO Need this because we are parsing in radix 10 above
|
|
|
|
|
|
if (i > 1)
|
|
|
|
|
|
throw new FormatException("Bad character in radix 2 string: " + s);
|
|
|
|
|
|
|
|
|
|
|
|
// TODO Parse 64 bits at a time
|
|
|
|
|
|
b = b.ShiftLeft(1);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 16:
|
|
|
|
|
|
b = b.ShiftLeft(64);
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
b = b.Multiply(rE);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
b = b.Add(bi);
|
|
|
|
|
|
|
|
|
|
|
|
index = next;
|
|
|
|
|
|
next += chunk;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
} while (next <= str.Length);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (index < str.Length)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var s = str.Substring(index);
|
|
|
|
|
|
var i = ulong.Parse(s, style);
|
|
|
|
|
|
var bi = createUValueOf(i);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (b.SignValue > 0)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
|
|
|
|
|
if (radix == 2)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Debug.Assert(false);
|
2016-04-18 12:50:57 +02:00
|
|
|
|
else if (radix == 16)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
b = b.ShiftLeft(s.Length << 2);
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else b = b.Multiply(r.Pow(s.Length));
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
b = b.Add(bi);
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
b = bi;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Note: This is the previous (slower) algorithm
|
|
|
|
|
|
// while (index < value.Length)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// char c = value[index];
|
|
|
|
|
|
// string s = c.ToString();
|
|
|
|
|
|
// int i = Int32.Parse(s, style);
|
|
|
|
|
|
//
|
|
|
|
|
|
// b = b.Multiply(r).Add(ValueOf(i));
|
|
|
|
|
|
// index++;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
magnitude = b.magnitude;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger(
|
|
|
|
|
|
byte[] bytes)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
: this(bytes, 0, bytes.Length)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger(
|
|
|
|
|
|
byte[] bytes,
|
|
|
|
|
|
int offset,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int length)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (length == 0)
|
|
|
|
|
|
throw new FormatException("Zero length BigInteger");
|
|
|
|
|
|
|
|
|
|
|
|
// TODO Move this processing into MakeMagnitude (provide sign argument)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if ((sbyte) bytes[offset] < 0)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
SignValue = -1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var end = offset + length;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
int iBval;
|
|
|
|
|
|
// strip leading sign bytes
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (iBval = offset; iBval < end && (sbyte) bytes[iBval] == -1; iBval++)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (iBval >= end)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
magnitude = One.magnitude;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var numBytes = end - iBval;
|
|
|
|
|
|
var inverse = new byte[numBytes];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var index = 0;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (index < numBytes)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
inverse[index++] = (byte) ~bytes[iBval++];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
Debug.Assert(iBval == end);
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (inverse[--index] == byte.MaxValue)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
inverse[index] = byte.MinValue;
|
|
|
|
|
|
|
|
|
|
|
|
inverse[index]++;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
magnitude = MakeMagnitude(inverse, 0, inverse.Length);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
// strip leading zero bytes and return magnitude bytes
|
|
|
|
|
|
magnitude = MakeMagnitude(bytes, offset, length);
|
|
|
|
|
|
SignValue = magnitude.Length > 0 ? 1 : 0;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger(
|
|
|
|
|
|
int sign,
|
|
|
|
|
|
byte[] bytes)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
: this(sign, bytes, 0, bytes.Length)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger(
|
|
|
|
|
|
int sign,
|
|
|
|
|
|
byte[] bytes,
|
|
|
|
|
|
int offset,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int length)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (sign < -1 || sign > 1)
|
|
|
|
|
|
throw new FormatException("Invalid sign value");
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (sign == 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
//this.sign = 0;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
magnitude = ZeroMagnitude;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// copy bytes
|
2017-04-13 08:38:01 +02:00
|
|
|
|
magnitude = MakeMagnitude(bytes, offset, length);
|
|
|
|
|
|
SignValue = magnitude.Length < 1 ? 0 : sign;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger(
|
|
|
|
|
|
int sizeInBits,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
Random random)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (sizeInBits < 0)
|
|
|
|
|
|
throw new ArgumentException("sizeInBits must be non-negative");
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
nBits = -1;
|
|
|
|
|
|
nBitLength = -1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (sizeInBits == 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// this.sign = 0;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
magnitude = ZeroMagnitude;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var nBytes = GetByteLength(sizeInBits);
|
|
|
|
|
|
var b = new byte[nBytes];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
random.NextBytes(b);
|
|
|
|
|
|
|
|
|
|
|
|
// strip off any excess bits in the MSB
|
|
|
|
|
|
b[0] &= rndMask[BitsPerByte * nBytes - sizeInBits];
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
magnitude = MakeMagnitude(b, 0, b.Length);
|
|
|
|
|
|
SignValue = magnitude.Length < 1 ? 0 : 1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger(
|
|
|
|
|
|
int bitLength,
|
|
|
|
|
|
int certainty,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
Random random)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (bitLength < 2)
|
|
|
|
|
|
throw new ArithmeticException("bitLength < 2");
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
SignValue = 1;
|
|
|
|
|
|
nBitLength = bitLength;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (bitLength == 2)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
magnitude = random.Next(2) == 0
|
2015-09-28 04:01:17 +02:00
|
|
|
|
? Two.magnitude
|
|
|
|
|
|
: Three.magnitude;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var nBytes = GetByteLength(bitLength);
|
|
|
|
|
|
var b = new byte[nBytes];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var xBits = BitsPerByte * nBytes - bitLength;
|
|
|
|
|
|
var mask = rndMask[xBits];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
for (;;)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
random.NextBytes(b);
|
|
|
|
|
|
|
|
|
|
|
|
// strip off any excess bits in the MSB
|
|
|
|
|
|
b[0] &= mask;
|
|
|
|
|
|
|
|
|
|
|
|
// ensure the leading bit is 1 (to meet the strength requirement)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
b[0] |= (byte) (1 << (7 - xBits));
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
// ensure the trailing bit is 1 (i.e. must be odd)
|
|
|
|
|
|
b[nBytes - 1] |= 1;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
magnitude = MakeMagnitude(b, 0, b.Length);
|
|
|
|
|
|
nBits = -1;
|
|
|
|
|
|
mQuote = -1L;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
if (certainty < 1)
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
if (CheckProbablePrime(certainty, random))
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (bitLength > 32)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var rep = 0; rep < 10000; ++rep)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var n = 33 + random.Next(bitLength - 2);
|
|
|
|
|
|
magnitude[magnitude.Length - (n >> 5)] ^= 1 << (n & 31);
|
|
|
|
|
|
magnitude[magnitude.Length - 1] ^= (random.Next() + 1) << 1;
|
|
|
|
|
|
mQuote = -1L;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
if (CheckProbablePrime(certainty, random))
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public int BitCount
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
if (nBits == -1)
|
|
|
|
|
|
if (SignValue < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// TODO Optimise this case
|
|
|
|
|
|
nBits = Not().BitCount;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var sum = 0;
|
|
|
|
|
|
for (var i = 0; i < magnitude.Length; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
sum += bitCounts[(byte) magnitude[i]];
|
|
|
|
|
|
sum += bitCounts[(byte) (magnitude[i] >> 8)];
|
|
|
|
|
|
sum += bitCounts[(byte) (magnitude[i] >> 16)];
|
|
|
|
|
|
sum += bitCounts[(byte) (magnitude[i] >> 24)];
|
|
|
|
|
|
}
|
|
|
|
|
|
nBits = sum;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return nBits;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public int BitLength
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
if (nBitLength == -1)
|
|
|
|
|
|
nBitLength = SignValue == 0
|
|
|
|
|
|
? 0
|
|
|
|
|
|
: calcBitLength(0, magnitude);
|
|
|
|
|
|
|
|
|
|
|
|
return nBitLength;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public int IntValue => SignValue == 0
|
|
|
|
|
|
? 0
|
|
|
|
|
|
: SignValue > 0
|
|
|
|
|
|
? magnitude[magnitude.Length - 1]
|
|
|
|
|
|
: -magnitude[magnitude.Length - 1];
|
|
|
|
|
|
|
|
|
|
|
|
// private bool SolovayStrassenTest(
|
|
|
|
|
|
// int certainty,
|
|
|
|
|
|
// Random random)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// Debug.Assert(certainty > 0);
|
|
|
|
|
|
// Debug.Assert(CompareTo(Two) > 0);
|
|
|
|
|
|
// Debug.Assert(TestBit(0));
|
|
|
|
|
|
//
|
|
|
|
|
|
// BigInteger n = this;
|
|
|
|
|
|
// BigInteger nMinusOne = n.Subtract(One);
|
|
|
|
|
|
// BigInteger e = nMinusOne.ShiftRight(1);
|
|
|
|
|
|
//
|
|
|
|
|
|
// do
|
|
|
|
|
|
// {
|
|
|
|
|
|
// BigInteger a;
|
|
|
|
|
|
// do
|
|
|
|
|
|
// {
|
|
|
|
|
|
// a = new BigInteger(nBitLength, random);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// // NB: Spec says 0 < x < n, but 1 is trivial
|
|
|
|
|
|
// while (a.CompareTo(One) <= 0 || a.CompareTo(n) >= 0);
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
// // TODO Check this is redundant given the way Jacobi() works?
|
|
|
|
|
|
//// if (!a.Gcd(n).Equals(One))
|
|
|
|
|
|
//// return false;
|
|
|
|
|
|
//
|
|
|
|
|
|
// int x = Jacobi(a, n);
|
|
|
|
|
|
//
|
|
|
|
|
|
// if (x == 0)
|
|
|
|
|
|
// return false;
|
|
|
|
|
|
//
|
|
|
|
|
|
// BigInteger check = a.ModPow(e, n);
|
|
|
|
|
|
//
|
|
|
|
|
|
// if (x == 1 && !check.Equals(One))
|
|
|
|
|
|
// return false;
|
|
|
|
|
|
//
|
|
|
|
|
|
// if (x == -1 && !check.Equals(nMinusOne))
|
|
|
|
|
|
// return false;
|
|
|
|
|
|
//
|
|
|
|
|
|
// --certainty;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// while (certainty > 0);
|
|
|
|
|
|
//
|
|
|
|
|
|
// return true;
|
|
|
|
|
|
// }
|
|
|
|
|
|
//
|
|
|
|
|
|
// private static int Jacobi(
|
|
|
|
|
|
// BigInteger a,
|
|
|
|
|
|
// BigInteger b)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// Debug.Assert(a.sign >= 0);
|
|
|
|
|
|
// Debug.Assert(b.sign > 0);
|
|
|
|
|
|
// Debug.Assert(b.TestBit(0));
|
|
|
|
|
|
// Debug.Assert(a.CompareTo(b) < 0);
|
|
|
|
|
|
//
|
|
|
|
|
|
// int totalS = 1;
|
|
|
|
|
|
// for (;;)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if (a.sign == 0)
|
|
|
|
|
|
// return 0;
|
|
|
|
|
|
//
|
|
|
|
|
|
// if (a.Equals(One))
|
|
|
|
|
|
// break;
|
|
|
|
|
|
//
|
|
|
|
|
|
// int e = a.GetLowestSetBit();
|
|
|
|
|
|
//
|
|
|
|
|
|
// int bLsw = b.magnitude[b.magnitude.Length - 1];
|
|
|
|
|
|
// if ((e & 1) != 0 && ((bLsw & 7) == 3 || (bLsw & 7) == 5))
|
|
|
|
|
|
// totalS = -totalS;
|
|
|
|
|
|
//
|
|
|
|
|
|
// // TODO Confirm this is faster than later a1.Equals(One) test
|
|
|
|
|
|
// if (a.BitLength == e + 1)
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// BigInteger a1 = a.ShiftRight(e);
|
|
|
|
|
|
//// if (a1.Equals(One))
|
|
|
|
|
|
//// break;
|
|
|
|
|
|
//
|
|
|
|
|
|
// int a1Lsw = a1.magnitude[a1.magnitude.Length - 1];
|
|
|
|
|
|
// if ((bLsw & 3) == 3 && (a1Lsw & 3) == 3)
|
|
|
|
|
|
// totalS = -totalS;
|
|
|
|
|
|
//
|
|
|
|
|
|
//// a = b.Mod(a1);
|
|
|
|
|
|
// a = b.Remainder(a1);
|
|
|
|
|
|
// b = a1;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// return totalS;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
public long LongValue
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
if (SignValue == 0)
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
long v;
|
|
|
|
|
|
if (magnitude.Length > 1)
|
|
|
|
|
|
v = ((long) magnitude[magnitude.Length - 2] << 32)
|
|
|
|
|
|
| (magnitude[magnitude.Length - 1] & IMASK);
|
|
|
|
|
|
else v = magnitude[magnitude.Length - 1] & IMASK;
|
|
|
|
|
|
|
|
|
|
|
|
return SignValue < 0 ? -v : v;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public int SignValue { get; private set; }
|
|
|
|
|
|
|
|
|
|
|
|
private static int GetByteLength(
|
|
|
|
|
|
int nBits)
|
|
|
|
|
|
{
|
|
|
|
|
|
return (nBits + BitsPerByte - 1) / BitsPerByte;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static int[] MakeMagnitude(
|
|
|
|
|
|
byte[] bytes,
|
|
|
|
|
|
int offset,
|
|
|
|
|
|
int length)
|
|
|
|
|
|
{
|
|
|
|
|
|
var end = offset + length;
|
|
|
|
|
|
|
|
|
|
|
|
// strip leading zeros
|
|
|
|
|
|
int firstSignificant;
|
|
|
|
|
|
for (firstSignificant = offset;
|
|
|
|
|
|
firstSignificant < end
|
|
|
|
|
|
&& bytes[firstSignificant] == 0;
|
|
|
|
|
|
firstSignificant++)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (firstSignificant >= end)
|
|
|
|
|
|
return ZeroMagnitude;
|
|
|
|
|
|
|
|
|
|
|
|
var nInts = (end - firstSignificant + 3) / BytesPerInt;
|
|
|
|
|
|
var bCount = (end - firstSignificant) % BytesPerInt;
|
|
|
|
|
|
if (bCount == 0)
|
|
|
|
|
|
bCount = BytesPerInt;
|
|
|
|
|
|
|
|
|
|
|
|
if (nInts < 1)
|
|
|
|
|
|
return ZeroMagnitude;
|
|
|
|
|
|
|
|
|
|
|
|
var mag = new int[nInts];
|
|
|
|
|
|
|
|
|
|
|
|
var v = 0;
|
|
|
|
|
|
var magnitudeIndex = 0;
|
|
|
|
|
|
for (var i = firstSignificant; i < end; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
v <<= 8;
|
|
|
|
|
|
v |= bytes[i] & 0xff;
|
|
|
|
|
|
bCount--;
|
|
|
|
|
|
if (bCount <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
mag[magnitudeIndex] = v;
|
|
|
|
|
|
magnitudeIndex++;
|
|
|
|
|
|
bCount = BytesPerInt;
|
|
|
|
|
|
v = 0;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
|
|
|
|
|
|
if (magnitudeIndex < mag.Length)
|
|
|
|
|
|
mag[magnitudeIndex] = v;
|
|
|
|
|
|
|
|
|
|
|
|
return mag;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
public BigInteger Abs()
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return SignValue >= 0 ? this : Negate();
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* return a = a + b - b preserved.
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static int[] AddMagnitudes(
|
|
|
|
|
|
int[] a,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] b)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var tI = a.Length - 1;
|
|
|
|
|
|
var vI = b.Length - 1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
long m = 0;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (vI >= 0)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
m += (uint) a[tI] + (long) (uint) b[vI--];
|
|
|
|
|
|
a[tI--] = (int) m;
|
|
|
|
|
|
m = (long) ((ulong) m >> 32);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (m != 0)
|
|
|
|
|
|
while (tI >= 0 && ++a[tI--] == 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return a;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger Add(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger value)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return value;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue != value.SignValue)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (value.SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return this;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (value.SignValue < 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return Subtract(value.Negate());
|
|
|
|
|
|
|
|
|
|
|
|
return value.Subtract(Negate());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return AddToMagnitude(value.magnitude);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private BigInteger AddToMagnitude(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] magToAdd)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
int[] big, small;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (magnitude.Length < magToAdd.Length)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
big = magToAdd;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
small = magnitude;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
big = magnitude;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
small = magToAdd;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Conservatively avoid over-allocation when no overflow possible
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var limit = uint.MaxValue;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (big.Length == small.Length)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
limit -= (uint) small[0];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var possibleOverflow = (uint) big[0] >= limit;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
int[] bigCopy;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (possibleOverflow)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
bigCopy = new int[big.Length + 1];
|
|
|
|
|
|
big.CopyTo(bigCopy, 1);
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
bigCopy = (int[]) big.Clone();
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bigCopy = AddMagnitudes(bigCopy, small);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return new BigInteger(SignValue, bigCopy, possibleOverflow);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger And(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger value)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0 || value.SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return Zero;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var aMag = SignValue > 0
|
|
|
|
|
|
? magnitude
|
2015-09-28 04:01:17 +02:00
|
|
|
|
: Add(One).magnitude;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var bMag = value.SignValue > 0
|
2015-09-28 04:01:17 +02:00
|
|
|
|
? value.magnitude
|
|
|
|
|
|
: value.Add(One).magnitude;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var resultNeg = SignValue < 0 && value.SignValue < 0;
|
|
|
|
|
|
var resultLength = Math.Max(aMag.Length, bMag.Length);
|
|
|
|
|
|
var resultMag = new int[resultLength];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var aStart = resultMag.Length - aMag.Length;
|
|
|
|
|
|
var bStart = resultMag.Length - bMag.Length;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = 0; i < resultMag.Length; ++i)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var aWord = i >= aStart ? aMag[i - aStart] : 0;
|
|
|
|
|
|
var bWord = i >= bStart ? bMag[i - bStart] : 0;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue < 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
aWord = ~aWord;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (value.SignValue < 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
bWord = ~bWord;
|
|
|
|
|
|
|
|
|
|
|
|
resultMag[i] = aWord & bWord;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (resultNeg)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
resultMag[i] = ~resultMag[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var result = new BigInteger(1, resultMag, true);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
// TODO Optimise this case
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (resultNeg)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
result = result.Not();
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger AndNot(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger val)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return And(val.Not());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int calcBitLength(
|
|
|
|
|
|
int indx,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] mag)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (;;)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (indx >= mag.Length)
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (mag[indx] != 0)
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
++indx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// bit length for everything after the first int
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var bitLength = 32 * (mag.Length - indx - 1);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
// and determine bitlength of first int
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var firstMag = mag[indx];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
bitLength += BitLen(firstMag);
|
|
|
|
|
|
|
|
|
|
|
|
// Check for negative powers of two
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue < 0 && (firstMag & -firstMag) == firstMag)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
do
|
|
|
|
|
|
{
|
|
|
|
|
|
if (++indx >= mag.Length)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
--bitLength;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
} while (mag[indx] == 0);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
return bitLength;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
// BitLen(value) is the number of bits in value.
|
|
|
|
|
|
//
|
|
|
|
|
|
private static int BitLen(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int w)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// Binary search - decision tree (5 tests, rarely 6)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return w < 1 << 15
|
|
|
|
|
|
? (w < 1 << 7
|
|
|
|
|
|
? (w < 1 << 3
|
|
|
|
|
|
? (w < 1 << 1
|
|
|
|
|
|
? (w < 1 << 0 ? (w < 0 ? 32 : 0) : 1)
|
|
|
|
|
|
: (w < 1 << 2 ? 2 : 3))
|
|
|
|
|
|
: (w < 1 << 5
|
|
|
|
|
|
? (w < 1 << 4 ? 4 : 5)
|
|
|
|
|
|
: (w < 1 << 6 ? 6 : 7)))
|
|
|
|
|
|
: (w < 1 << 11
|
|
|
|
|
|
? (w < 1 << 9 ? (w < 1 << 8 ? 8 : 9) : (w < 1 << 10 ? 10 : 11))
|
|
|
|
|
|
: (w < 1 << 13 ? (w < 1 << 12 ? 12 : 13) : (w < 1 << 14 ? 14 : 15))))
|
|
|
|
|
|
: (w < 1 << 23
|
|
|
|
|
|
? (w < 1 << 19
|
|
|
|
|
|
? (w < 1 << 17 ? (w < 1 << 16 ? 16 : 17) : (w < 1 << 18 ? 18 : 19))
|
|
|
|
|
|
: (w < 1 << 21 ? (w < 1 << 20 ? 20 : 21) : (w < 1 << 22 ? 22 : 23)))
|
|
|
|
|
|
: (w < 1 << 27
|
|
|
|
|
|
? (w < 1 << 25 ? (w < 1 << 24 ? 24 : 25) : (w < 1 << 26 ? 26 : 27))
|
|
|
|
|
|
: (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31))));
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// private readonly static byte[] bitLengths =
|
|
|
|
|
|
// {
|
|
|
|
|
|
// 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
|
|
|
|
// 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
|
|
|
|
// 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
|
|
|
|
// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
|
|
|
|
// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
|
|
|
|
|
|
// 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
|
|
|
|
// 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
|
|
|
|
// 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
|
|
|
|
// 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
|
|
|
|
// 8, 8, 8, 8, 8, 8, 8, 8
|
|
|
|
|
|
// };
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
private bool QuickPow2Check()
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return SignValue > 0 && nBits == 1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public int CompareTo(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
object obj)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return CompareTo((BigInteger) obj);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* unsigned comparison on two arrays - note the arrays may
|
|
|
|
|
|
* start with leading zeros.
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static int CompareTo(
|
|
|
|
|
|
int xIndx,
|
|
|
|
|
|
int[] x,
|
|
|
|
|
|
int yIndx,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] y)
|
|
|
|
|
|
{
|
|
|
|
|
|
while (xIndx != x.Length && x[xIndx] == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
xIndx++;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (yIndx != y.Length && y[yIndx] == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
yIndx++;
|
|
|
|
|
|
|
|
|
|
|
|
return CompareNoLeadingZeroes(xIndx, x, yIndx, y);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static int CompareNoLeadingZeroes(
|
|
|
|
|
|
int xIndx,
|
|
|
|
|
|
int[] x,
|
|
|
|
|
|
int yIndx,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] y)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var diff = x.Length - y.Length - (xIndx - yIndx);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (diff != 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return diff < 0 ? -1 : 1;
|
|
|
|
|
|
|
|
|
|
|
|
// lengths of magnitudes the same, test the magnitude values
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (xIndx < x.Length)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var v1 = (uint) x[xIndx++];
|
|
|
|
|
|
var v2 = (uint) y[yIndx++];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
if (v1 != v2)
|
|
|
|
|
|
return v1 < v2 ? -1 : 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public int CompareTo(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger value)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return SignValue < value.SignValue
|
|
|
|
|
|
? -1
|
|
|
|
|
|
: SignValue > value.SignValue
|
|
|
|
|
|
? 1
|
|
|
|
|
|
: SignValue == 0
|
|
|
|
|
|
? 0
|
|
|
|
|
|
: SignValue * CompareNoLeadingZeroes(0, magnitude, 0, value.magnitude);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* return z = x / y - done in place (z value preserved, x contains the
|
|
|
|
|
|
* remainder)
|
|
|
|
|
|
*/
|
|
|
|
|
|
private int[] Divide(
|
|
|
|
|
|
int[] x,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] y)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var xStart = 0;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (xStart < x.Length && x[xStart] == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
++xStart;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var yStart = 0;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (yStart < y.Length && y[yStart] == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
++yStart;
|
|
|
|
|
|
|
|
|
|
|
|
Debug.Assert(yStart < y.Length);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
int[] count;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (xyCmp > 0)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var yBitLength = calcBitLength(yStart, y);
|
|
|
|
|
|
var xBitLength = calcBitLength(xStart, x);
|
|
|
|
|
|
var shift = xBitLength - yBitLength;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
int[] iCount;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var iCountStart = 0;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
int[] c;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var cStart = 0;
|
|
|
|
|
|
var cBitLength = yBitLength;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (shift > 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// iCount = ShiftLeft(One.magnitude, shift);
|
|
|
|
|
|
iCount = new int[(shift >> 5) + 1];
|
|
|
|
|
|
iCount[0] = 1 << (shift % 32);
|
|
|
|
|
|
|
|
|
|
|
|
c = ShiftLeft(y, shift);
|
|
|
|
|
|
cBitLength += shift;
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
iCount = new[] {1};
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var len = y.Length - yStart;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
c = new int[len];
|
|
|
|
|
|
Array.Copy(y, yStart, c, 0, len);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
count = new int[iCount.Length];
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
for (;;)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (cBitLength < xBitLength
|
2016-04-18 12:50:57 +02:00
|
|
|
|
|| CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Subtract(xStart, x, cStart, c);
|
|
|
|
|
|
AddMagnitudes(count, iCount);
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (x[xStart] == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (++xStart == x.Length)
|
|
|
|
|
|
return count;
|
|
|
|
|
|
|
|
|
|
|
|
//xBitLength = calcBitLength(xStart, x);
|
|
|
|
|
|
xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]);
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (xBitLength <= yBitLength)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (xBitLength < yBitLength)
|
|
|
|
|
|
return count;
|
|
|
|
|
|
|
|
|
|
|
|
xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
|
|
|
|
|
|
|
|
|
|
|
|
if (xyCmp <= 0)
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
shift = cBitLength - xBitLength;
|
|
|
|
|
|
|
|
|
|
|
|
// NB: The case where c[cStart] is 1-bit is harmless
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (shift == 1)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var firstC = (uint) c[cStart] >> 1;
|
|
|
|
|
|
var firstX = (uint) x[xStart];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (firstC > firstX)
|
|
|
|
|
|
++shift;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (shift < 2)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
ShiftRightOneInPlace(cStart, c);
|
|
|
|
|
|
--cBitLength;
|
|
|
|
|
|
ShiftRightOneInPlace(iCountStart, iCount);
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
ShiftRightInPlace(cStart, c, shift);
|
|
|
|
|
|
cBitLength -= shift;
|
|
|
|
|
|
ShiftRightInPlace(iCountStart, iCount, shift);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//cStart = c.Length - ((cBitLength + 31) / 32);
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (c[cStart] == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
++cStart;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (iCount[iCountStart] == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
++iCountStart;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
count = new int[1];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (xyCmp == 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
AddMagnitudes(count, One.magnitude);
|
|
|
|
|
|
Array.Clear(x, xStart, x.Length - xStart);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger Divide(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger val)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (val.SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
throw new ArithmeticException("Division by zero error");
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return Zero;
|
|
|
|
|
|
|
|
|
|
|
|
if (val.QuickPow2Check()) // val is power of two
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var result = Abs().ShiftRight(val.Abs().BitLength - 1);
|
|
|
|
|
|
return val.SignValue == SignValue ? result : result.Negate();
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var mag = (int[]) magnitude.Clone();
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return new BigInteger(SignValue * val.SignValue, Divide(mag, val.magnitude), true);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger[] DivideAndRemainder(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger val)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (val.SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
throw new ArithmeticException("Division by zero error");
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var biggies = new BigInteger[2];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
biggies[0] = Zero;
|
|
|
|
|
|
biggies[1] = Zero;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (val.QuickPow2Check()) // val is power of two
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var e = val.Abs().BitLength - 1;
|
|
|
|
|
|
var quotient = Abs().ShiftRight(e);
|
|
|
|
|
|
var remainder = LastNBits(e);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
biggies[0] = val.SignValue == SignValue ? quotient : quotient.Negate();
|
|
|
|
|
|
biggies[1] = new BigInteger(SignValue, remainder, true);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var remainder = (int[]) magnitude.Clone();
|
|
|
|
|
|
var quotient = Divide(remainder, val.magnitude);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
biggies[0] = new BigInteger(SignValue * val.SignValue, quotient, true);
|
|
|
|
|
|
biggies[1] = new BigInteger(SignValue, remainder, true);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return biggies;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override bool Equals(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
object obj)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (obj == this)
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var biggie = obj as BigInteger;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (biggie == null)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (biggie.SignValue != SignValue || biggie.magnitude.Length != magnitude.Length)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return false;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = 0; i < magnitude.Length; i++)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (biggie.magnitude[i] != magnitude[i])
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger Gcd(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger value)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (value.SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return Abs();
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return value.Abs();
|
|
|
|
|
|
|
|
|
|
|
|
BigInteger r;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var u = this;
|
|
|
|
|
|
var v = value;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
while (v.SignValue != 0)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
r = u.Mod(v);
|
|
|
|
|
|
u = v;
|
|
|
|
|
|
v = r;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return u;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var hc = magnitude.Length;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (magnitude.Length > 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
hc ^= magnitude[0];
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (magnitude.Length > 1)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
hc ^= magnitude[magnitude.Length - 1];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return SignValue < 0 ? ~hc : hc;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO Make public?
|
2016-04-18 12:50:57 +02:00
|
|
|
|
private BigInteger Inc()
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return One;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue < 0)
|
|
|
|
|
|
return new BigInteger(-1, doSubBigLil(magnitude, One.magnitude), true);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
return AddToMagnitude(One.magnitude);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* return whether or not a BigInteger is probably prime with a
|
|
|
|
|
|
* probability of 1 - (1/2)**certainty.
|
|
|
|
|
|
* <p>From Knuth Vol 2, pg 395.</p>
|
|
|
|
|
|
*/
|
|
|
|
|
|
public bool IsProbablePrime(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int certainty)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (certainty <= 0)
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var n = Abs();
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
if (!n.TestBit(0))
|
|
|
|
|
|
return n.Equals(Two);
|
|
|
|
|
|
|
|
|
|
|
|
if (n.Equals(One))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
return n.CheckProbablePrime(certainty, RandomSource);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool CheckProbablePrime(
|
|
|
|
|
|
int certainty,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
Random random)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Debug.Assert(certainty > 0);
|
|
|
|
|
|
Debug.Assert(CompareTo(Two) > 0);
|
|
|
|
|
|
Debug.Assert(TestBit(0));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Try to reduce the penalty for really small numbers
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var numLists = Math.Min(BitLength - 1, primeLists.Length);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = 0; i < numLists; ++i)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var test = Remainder(primeProducts[i]);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var primeList = primeLists[i];
|
|
|
|
|
|
for (var j = 0; j < primeList.Length; ++j)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var prime = primeList[j];
|
|
|
|
|
|
var qRem = test % prime;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (qRem == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return BitLength < 16 && IntValue == prime;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO Special case for < 10^16 (RabinMiller fixed list)
|
|
|
|
|
|
// if (BitLength < 30)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// RabinMiller against 2, 3, 5, 7, 11, 13, 23 is sufficient
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO Is it worth trying to create a hybrid of these two?
|
|
|
|
|
|
return RabinMillerTest(certainty, random);
|
|
|
|
|
|
// return SolovayStrassenTest(certainty, random);
|
|
|
|
|
|
|
|
|
|
|
|
// bool rbTest = RabinMillerTest(certainty, random);
|
|
|
|
|
|
// bool ssTest = SolovayStrassenTest(certainty, random);
|
|
|
|
|
|
//
|
|
|
|
|
|
// Debug.Assert(rbTest == ssTest);
|
|
|
|
|
|
//
|
|
|
|
|
|
// return rbTest;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
internal bool RabinMillerTest(
|
|
|
|
|
|
int certainty,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
Random random)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Debug.Assert(certainty > 0);
|
|
|
|
|
|
Debug.Assert(BitLength > 2);
|
|
|
|
|
|
Debug.Assert(TestBit(0));
|
|
|
|
|
|
|
|
|
|
|
|
// let n = 1 + d . 2^s
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var n = this;
|
|
|
|
|
|
var nMinusOne = n.Subtract(One);
|
|
|
|
|
|
var s = nMinusOne.GetLowestSetBit();
|
|
|
|
|
|
var r = nMinusOne.ShiftRight(s);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
Debug.Assert(s >= 1);
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
do
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// TODO Make a method for random BigIntegers in range 0 < x < n)
|
|
|
|
|
|
// - Method can be optimized by only replacing examined bits at each trial
|
|
|
|
|
|
BigInteger a;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
do
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
a = new BigInteger(n.BitLength, random);
|
2017-04-13 08:38:01 +02:00
|
|
|
|
} while (a.CompareTo(One) <= 0 || a.CompareTo(nMinusOne) >= 0);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var y = a.ModPow(r, n);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (!y.Equals(One))
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var j = 0;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (!y.Equals(nMinusOne))
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (++j == s)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
y = y.ModPow(Two, n);
|
|
|
|
|
|
|
|
|
|
|
|
if (y.Equals(One))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
certainty -= 2; // composites pass for only 1/4 possible 'a'
|
2017-04-13 08:38:01 +02:00
|
|
|
|
} while (certainty > 0);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger Max(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger value)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return CompareTo(value) > 0 ? this : value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger Min(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger value)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return CompareTo(value) < 0 ? this : value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger Mod(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger m)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (m.SignValue < 1)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
throw new ArithmeticException("Modulus must be positive");
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var biggie = Remainder(m);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return biggie.SignValue >= 0 ? biggie : biggie.Add(m);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger ModInverse(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger m)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (m.SignValue < 1)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
throw new ArithmeticException("Modulus must be positive");
|
|
|
|
|
|
|
|
|
|
|
|
// TODO Too slow at the moment
|
|
|
|
|
|
// // "Fast Key Exchange with Elliptic Curve Systems" R.Schoeppel
|
|
|
|
|
|
// if (m.TestBit(0))
|
|
|
|
|
|
// {
|
|
|
|
|
|
// //The Almost Inverse Algorithm
|
|
|
|
|
|
// int k = 0;
|
|
|
|
|
|
// BigInteger B = One, C = Zero, F = this, G = m, tmp;
|
|
|
|
|
|
//
|
|
|
|
|
|
// for (;;)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// // While F is even, do F=F/u, C=C*u, k=k+1.
|
|
|
|
|
|
// int zeroes = F.GetLowestSetBit();
|
|
|
|
|
|
// if (zeroes > 0)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// F = F.ShiftRight(zeroes);
|
|
|
|
|
|
// C = C.ShiftLeft(zeroes);
|
|
|
|
|
|
// k += zeroes;
|
|
|
|
|
|
// }
|
|
|
|
|
|
//
|
|
|
|
|
|
// // If F = 1, then return B,k.
|
|
|
|
|
|
// if (F.Equals(One))
|
|
|
|
|
|
// {
|
|
|
|
|
|
// BigInteger half = m.Add(One).ShiftRight(1);
|
|
|
|
|
|
// BigInteger halfK = half.ModPow(BigInteger.ValueOf(k), m);
|
|
|
|
|
|
// return B.Multiply(halfK).Mod(m);
|
|
|
|
|
|
// }
|
|
|
|
|
|
//
|
|
|
|
|
|
// if (F.CompareTo(G) < 0)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// tmp = G; G = F; F = tmp;
|
|
|
|
|
|
// tmp = B; B = C; C = tmp;
|
|
|
|
|
|
// }
|
|
|
|
|
|
//
|
|
|
|
|
|
// F = F.Add(G);
|
|
|
|
|
|
// B = B.Add(C);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var x = new BigInteger();
|
|
|
|
|
|
var gcd = ExtEuclid(Mod(m), m, x, null);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
if (!gcd.Equals(One))
|
|
|
|
|
|
throw new ArithmeticException("Numbers not relatively prime.");
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (x.SignValue < 0)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
x.SignValue = 1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
//x = m.Subtract(x);
|
|
|
|
|
|
x.magnitude = doSubBigLil(m.magnitude, x.magnitude);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return x;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Calculate the numbers u1, u2, and u3 such that:
|
|
|
|
|
|
*
|
|
|
|
|
|
* u1 * a + u2 * b = u3
|
|
|
|
|
|
*
|
|
|
|
|
|
* where u3 is the greatest common divider of a and b.
|
|
|
|
|
|
* a and b using the extended Euclid algorithm (refer p. 323
|
|
|
|
|
|
* of The Art of Computer Programming vol 2, 2nd ed).
|
|
|
|
|
|
* This also seems to have the side effect of calculating
|
|
|
|
|
|
* some form of multiplicative inverse.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param a First number to calculate gcd for
|
|
|
|
|
|
* @param b Second number to calculate gcd for
|
|
|
|
|
|
* @param u1Out the return object for the u1 value
|
|
|
|
|
|
* @param u2Out the return object for the u2 value
|
|
|
|
|
|
* @return The greatest common divisor of a and b
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static BigInteger ExtEuclid(
|
|
|
|
|
|
BigInteger a,
|
|
|
|
|
|
BigInteger b,
|
|
|
|
|
|
BigInteger u1Out,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger u2Out)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var u1 = One;
|
|
|
|
|
|
var u3 = a;
|
|
|
|
|
|
var v1 = Zero;
|
|
|
|
|
|
var v3 = b;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
while (v3.SignValue > 0)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var q = u3.DivideAndRemainder(v3);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var tmp = v1.Multiply(q[0]);
|
|
|
|
|
|
var tn = u1.Subtract(tmp);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
u1 = v1;
|
|
|
|
|
|
v1 = tn;
|
|
|
|
|
|
|
|
|
|
|
|
u3 = v3;
|
|
|
|
|
|
v3 = q[1];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (u1Out != null)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
u1Out.SignValue = u1.SignValue;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
u1Out.magnitude = u1.magnitude;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (u2Out != null)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var tmp = u1.Multiply(a);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
tmp = u3.Subtract(tmp);
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var res = tmp.Divide(b);
|
|
|
|
|
|
u2Out.SignValue = res.SignValue;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
u2Out.magnitude = res.magnitude;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return u3;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static void ZeroOut(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] x)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Array.Clear(x, 0, x.Length);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger ModPow(
|
|
|
|
|
|
BigInteger exponent,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger m)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (m.SignValue < 1)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
throw new ArithmeticException("Modulus must be positive");
|
|
|
|
|
|
|
|
|
|
|
|
if (m.Equals(One))
|
|
|
|
|
|
return Zero;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (exponent.SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return One;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return Zero;
|
|
|
|
|
|
|
|
|
|
|
|
int[] zVal = null;
|
|
|
|
|
|
int[] yAccum = null;
|
|
|
|
|
|
int[] yVal;
|
|
|
|
|
|
|
|
|
|
|
|
// Montgomery exponentiation is only possible if the modulus is odd,
|
|
|
|
|
|
// but AFAIK, this is always the case for crypto algo's
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var useMonty = (m.magnitude[m.magnitude.Length - 1] & 1) == 1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
long mQ = 0;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (useMonty)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
mQ = m.GetMQuote();
|
|
|
|
|
|
|
|
|
|
|
|
// tmp = this * R mod m
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var tmp = ShiftLeft(32 * m.magnitude.Length).Mod(m);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
zVal = tmp.magnitude;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
useMonty = zVal.Length <= m.magnitude.Length;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (useMonty)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
yAccum = new int[m.magnitude.Length + 1];
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (zVal.Length < m.magnitude.Length)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var longZ = new int[m.magnitude.Length];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
zVal.CopyTo(longZ, longZ.Length - zVal.Length);
|
|
|
|
|
|
zVal = longZ;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (!useMonty)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (magnitude.Length <= m.magnitude.Length)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
//zAccum = new int[m.magnitude.Length * 2];
|
|
|
|
|
|
zVal = new int[m.magnitude.Length];
|
|
|
|
|
|
magnitude.CopyTo(zVal, zVal.Length - magnitude.Length);
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
//
|
|
|
|
|
|
// in normal practice we'll never see this...
|
|
|
|
|
|
//
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var tmp = Remainder(m);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
//zAccum = new int[m.magnitude.Length * 2];
|
|
|
|
|
|
zVal = new int[m.magnitude.Length];
|
|
|
|
|
|
tmp.magnitude.CopyTo(zVal, zVal.Length - tmp.magnitude.Length);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
yAccum = new int[m.magnitude.Length * 2];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
yVal = new int[m.magnitude.Length];
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
// from LSW to MSW
|
|
|
|
|
|
//
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = 0; i < exponent.magnitude.Length; i++)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var v = exponent.magnitude[i];
|
|
|
|
|
|
var bits = 0;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (i == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
while (v > 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
v <<= 1;
|
|
|
|
|
|
bits++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
// first time in initialise y
|
|
|
|
|
|
//
|
|
|
|
|
|
zVal.CopyTo(yVal, 0);
|
|
|
|
|
|
|
|
|
|
|
|
v <<= 1;
|
|
|
|
|
|
bits++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (v != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (useMonty)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// Montgomery square algo doesn't exist, and a normal
|
|
|
|
|
|
// square followed by a Montgomery reduction proved to
|
|
|
|
|
|
// be almost as heavy as a Montgomery mulitply.
|
|
|
|
|
|
MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ);
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Square(yAccum, yVal);
|
|
|
|
|
|
Remainder(yAccum, m.magnitude);
|
|
|
|
|
|
Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length);
|
|
|
|
|
|
ZeroOut(yAccum);
|
|
|
|
|
|
}
|
|
|
|
|
|
bits++;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (v < 0)
|
|
|
|
|
|
if (useMonty)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ);
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Multiply(yAccum, yVal, zVal);
|
|
|
|
|
|
Remainder(yAccum, m.magnitude);
|
|
|
|
|
|
Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0,
|
|
|
|
|
|
yVal.Length);
|
|
|
|
|
|
ZeroOut(yAccum);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
v <<= 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (bits < 32)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (useMonty)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ);
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Square(yAccum, yVal);
|
|
|
|
|
|
Remainder(yAccum, m.magnitude);
|
|
|
|
|
|
Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length);
|
|
|
|
|
|
ZeroOut(yAccum);
|
|
|
|
|
|
}
|
|
|
|
|
|
bits++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (useMonty)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// Return y * R^(-1) mod m by doing y * 1 * R^(-1) mod m
|
|
|
|
|
|
ZeroOut(zVal);
|
|
|
|
|
|
zVal[zVal.Length - 1] = 1;
|
|
|
|
|
|
MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var result = new BigInteger(1, yVal, true);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return exponent.SignValue > 0
|
2015-09-28 04:01:17 +02:00
|
|
|
|
? result
|
|
|
|
|
|
: result.ModInverse(m);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* return w with w = x * x - w is assumed to have enough space.
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static int[] Square(
|
|
|
|
|
|
int[] w,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] x)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// Note: this method allows w to be only (2 * x.Length - 1) words if result will fit
|
|
|
|
|
|
// if (w.Length != 2 * x.Length)
|
|
|
|
|
|
// throw new ArgumentException("no I don't think so...");
|
|
|
|
|
|
|
|
|
|
|
|
ulong u1, u2, c;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var wBase = w.Length - 1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = x.Length - 1; i != 0; i--)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
ulong v = (uint) x[i];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
u1 = v * v;
|
|
|
|
|
|
u2 = u1 >> 32;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
u1 = (uint) u1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
u1 += (uint) w[wBase];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
w[wBase] = (int) (uint) u1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
c = u2 + (u1 >> 32);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var j = i - 1; j >= 0; j--)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
--wBase;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
u1 = v * (uint) x[j];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
u2 = u1 >> 31; // multiply by 2!
|
2017-04-13 08:38:01 +02:00
|
|
|
|
u1 = (uint) (u1 << 1); // multiply by 2!
|
|
|
|
|
|
u1 += c + (uint) w[wBase];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
w[wBase] = (int) (uint) u1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
c = u2 + (u1 >> 32);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
c += (uint) w[--wBase];
|
|
|
|
|
|
w[wBase] = (int) (uint) c;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (--wBase >= 0)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
w[wBase] = (int) (uint) (c >> 32);
|
|
|
|
|
|
else Debug.Assert((uint) (c >> 32) == 0);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
wBase += i;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
u1 = (uint) x[0];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
u1 = u1 * u1;
|
|
|
|
|
|
u2 = u1 >> 32;
|
|
|
|
|
|
u1 = u1 & IMASK;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
u1 += (uint) w[wBase];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
w[wBase] = (int) (uint) u1;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (--wBase >= 0)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
w[wBase] = (int) (uint) (u2 + (u1 >> 32) + (uint) w[wBase]);
|
|
|
|
|
|
else Debug.Assert((uint) (u2 + (u1 >> 32)) == 0);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
return w;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* return x with x = y * z - x is assumed to have enough space.
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static int[] Multiply(
|
|
|
|
|
|
int[] x,
|
|
|
|
|
|
int[] y,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] z)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var i = z.Length;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
if (i < 1)
|
|
|
|
|
|
return x;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var xBase = x.Length - y.Length;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
for (;;)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var a = z[--i] & IMASK;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
long val = 0;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var j = y.Length - 1; j >= 0; j--)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
val += a * (y[j] & IMASK) + (x[xBase + j] & IMASK);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
x[xBase + j] = (int) val;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
val = (long) ((ulong) val >> 32);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
--xBase;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (i < 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (xBase >= 0)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
x[xBase] = (int) val;
|
|
|
|
|
|
else Debug.Assert(val == 0);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
x[xBase] = (int) val;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return x;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static long FastExtEuclid(
|
|
|
|
|
|
long a,
|
|
|
|
|
|
long b,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
long[] uOut)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
long u1 = 1;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var u3 = a;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
long v1 = 0;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var v3 = b;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (v3 > 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
long q, tn;
|
|
|
|
|
|
|
|
|
|
|
|
q = u3 / v3;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
tn = u1 - v1 * q;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
u1 = v1;
|
|
|
|
|
|
v1 = tn;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
tn = u3 - v3 * q;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
u3 = v3;
|
|
|
|
|
|
v3 = tn;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uOut[0] = u1;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
uOut[1] = (u3 - u1 * a) / b;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
return u3;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static long FastModInverse(
|
|
|
|
|
|
long v,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
long m)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (m < 1)
|
|
|
|
|
|
throw new ArithmeticException("Modulus must be positive");
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var x = new long[2];
|
|
|
|
|
|
var gcd = FastExtEuclid(v, m, x);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
if (gcd != 1)
|
|
|
|
|
|
throw new ArithmeticException("Numbers not relatively prime.");
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (x[0] < 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
x[0] += m;
|
|
|
|
|
|
|
|
|
|
|
|
return x[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// private static BigInteger MQuoteB = One.ShiftLeft(32);
|
|
|
|
|
|
// private static BigInteger MQuoteBSub1 = MQuoteB.Subtract(One);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size)
|
|
|
|
|
|
*/
|
2016-04-18 12:50:57 +02:00
|
|
|
|
private long GetMQuote()
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
Debug.Assert(SignValue > 0);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (mQuote != -1)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return mQuote; // already calculated
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (magnitude.Length == 0 || (magnitude[magnitude.Length - 1] & 1) == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return -1; // not for even numbers
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var v = (~magnitude[magnitude.Length - 1] | 1) & 0xffffffffL;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
mQuote = FastModInverse(v, 0x100000000L);
|
|
|
|
|
|
|
|
|
|
|
|
return mQuote;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Montgomery multiplication: a = x * y * R^(-1) mod m
|
|
|
|
|
|
* <br/>
|
|
|
|
|
|
* Based algorithm 14.36 of Handbook of Applied Cryptography.
|
|
|
|
|
|
* <br/>
|
|
|
|
|
|
* <li> m, x, y should have length n </li>
|
|
|
|
|
|
* <li> a should have length (n + 1) </li>
|
|
|
|
|
|
* <li> b = 2^32, R = b^n </li>
|
|
|
|
|
|
* <br/>
|
|
|
|
|
|
* The result is put in x
|
|
|
|
|
|
* <br/>
|
|
|
|
|
|
* NOTE: the indices of x, y, m, a different in HAC and in Java
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static void MultiplyMonty(
|
2017-04-13 08:38:01 +02:00
|
|
|
|
int[] a,
|
|
|
|
|
|
int[] x,
|
|
|
|
|
|
int[] y,
|
|
|
|
|
|
int[] m,
|
|
|
|
|
|
long mQuote)
|
|
|
|
|
|
// mQuote = -m^(-1) mod b
|
2015-09-28 04:01:17 +02:00
|
|
|
|
{
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (m.Length == 1)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
x[0] = (int) MultiplyMontyNIsOne((uint) x[0], (uint) y[0], (uint) m[0], (ulong) mQuote);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var n = m.Length;
|
|
|
|
|
|
var nMinus1 = n - 1;
|
|
|
|
|
|
var y_0 = y[nMinus1] & IMASK;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
// 1. a = 0 (Notation: a = (a_{n} a_{n-1} ... a_{0})_{b} )
|
|
|
|
|
|
Array.Clear(a, 0, n + 1);
|
|
|
|
|
|
|
|
|
|
|
|
// 2. for i from 0 to (n - 1) do the following:
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = n; i > 0; i--)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var x_i = x[i - 1] & IMASK;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
// 2.1 u = ((a[0] + (x[i] * y[0]) * mQuote) mod b
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var u = ((((a[n] & IMASK) + ((x_i * y_0) & IMASK)) & IMASK) * mQuote) & IMASK;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
// 2.2 a = (a + x_i * y + u * m) / b
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var prod1 = x_i * y_0;
|
|
|
|
|
|
var prod2 = u * (m[nMinus1] & IMASK);
|
|
|
|
|
|
var tmp = (a[n] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK);
|
|
|
|
|
|
var carry = (long) ((ulong) prod1 >> 32) + (long) ((ulong) prod2 >> 32) + (long) ((ulong) tmp >> 32);
|
|
|
|
|
|
for (var j = nMinus1; j > 0; j--)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
prod1 = x_i * (y[j - 1] & IMASK);
|
|
|
|
|
|
prod2 = u * (m[j - 1] & IMASK);
|
|
|
|
|
|
tmp = (a[j] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK) + (carry & IMASK);
|
2017-04-13 08:38:01 +02:00
|
|
|
|
carry = (long) ((ulong) carry >> 32) + (long) ((ulong) prod1 >> 32) +
|
|
|
|
|
|
(long) ((ulong) prod2 >> 32) + (long) ((ulong) tmp >> 32);
|
|
|
|
|
|
a[j + 1] = (int) tmp; // division by b
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
carry += a[0] & IMASK;
|
|
|
|
|
|
a[1] = (int) carry;
|
|
|
|
|
|
a[0] = (int) ((ulong) carry >> 32); // OJO!!!!!
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. if x >= m the x = x - m
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (CompareTo(0, a, 0, m) >= 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Subtract(0, a, 0, m);
|
|
|
|
|
|
|
|
|
|
|
|
// put the result in x
|
|
|
|
|
|
Array.Copy(a, 1, x, 0, n);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static uint MultiplyMontyNIsOne(
|
|
|
|
|
|
uint x,
|
|
|
|
|
|
uint y,
|
|
|
|
|
|
uint m,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
ulong mQuote)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
ulong um = m;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var prod1 = x * (ulong) y;
|
|
|
|
|
|
var u = (prod1 * mQuote) & UIMASK;
|
|
|
|
|
|
var prod2 = u * um;
|
|
|
|
|
|
var tmp = (prod1 & UIMASK) + (prod2 & UIMASK);
|
|
|
|
|
|
var carry = (prod1 >> 32) + (prod2 >> 32) + (tmp >> 32);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (carry > um)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
carry -= um;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return (uint) (carry & UIMASK);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger Multiply(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger val)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0 || val.SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return Zero;
|
|
|
|
|
|
|
|
|
|
|
|
if (val.QuickPow2Check()) // val is power of two
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var result = ShiftLeft(val.Abs().BitLength - 1);
|
|
|
|
|
|
return val.SignValue > 0 ? result : result.Negate();
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (QuickPow2Check()) // this is power of two
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var result = val.ShiftLeft(Abs().BitLength - 1);
|
|
|
|
|
|
return SignValue > 0 ? result : result.Negate();
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var resLength = (BitLength + val.BitLength) / BitsPerInt + 1;
|
|
|
|
|
|
var res = new int[resLength];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (val == this)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
Square(res, magnitude);
|
|
|
|
|
|
else Multiply(res, magnitude, val.magnitude);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return new BigInteger(SignValue * val.SignValue, res, true);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
public BigInteger Negate()
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return this;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return new BigInteger(-SignValue, magnitude, false);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
public BigInteger NextProbablePrime()
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue < 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
throw new ArithmeticException("Cannot be called on value < 0");
|
|
|
|
|
|
|
|
|
|
|
|
if (CompareTo(Two) < 0)
|
|
|
|
|
|
return Two;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var n = Inc().SetBit(0);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (!n.CheckProbablePrime(100, RandomSource))
|
2015-09-28 04:01:17 +02:00
|
|
|
|
n = n.Add(Two);
|
|
|
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
public BigInteger Not()
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return Inc().Negate();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
public BigInteger Pow(int exp)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (exp < 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
throw new ArithmeticException("Negative exponent");
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (exp == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return One;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0 || Equals(One))
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return this;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var y = One;
|
|
|
|
|
|
var z = this;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
for (;;)
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((exp & 0x1) == 1)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
y = y.Multiply(z);
|
|
|
|
|
|
exp >>= 1;
|
|
|
|
|
|
if (exp == 0) break;
|
|
|
|
|
|
z = z.Multiply(z);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return y;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static BigInteger ProbablePrime(
|
|
|
|
|
|
int bitLength,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
Random random)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return new BigInteger(bitLength, 100, random);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int Remainder(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int m)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Debug.Assert(m > 0);
|
|
|
|
|
|
|
|
|
|
|
|
long acc = 0;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var pos = 0; pos < magnitude.Length; ++pos)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
long posVal = (uint) magnitude[pos];
|
|
|
|
|
|
acc = ((acc << 32) | posVal) % m;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return (int) acc;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* return x = x % y - done in place (y value preserved)
|
|
|
|
|
|
*/
|
|
|
|
|
|
private int[] Remainder(
|
|
|
|
|
|
int[] x,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] y)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var xStart = 0;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (xStart < x.Length && x[xStart] == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
++xStart;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var yStart = 0;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (yStart < y.Length && y[yStart] == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
++yStart;
|
|
|
|
|
|
|
|
|
|
|
|
Debug.Assert(yStart < y.Length);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (xyCmp > 0)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var yBitLength = calcBitLength(yStart, y);
|
|
|
|
|
|
var xBitLength = calcBitLength(xStart, x);
|
|
|
|
|
|
var shift = xBitLength - yBitLength;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
int[] c;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var cStart = 0;
|
|
|
|
|
|
var cBitLength = yBitLength;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (shift > 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
c = ShiftLeft(y, shift);
|
|
|
|
|
|
cBitLength += shift;
|
|
|
|
|
|
Debug.Assert(c[0] != 0);
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var len = y.Length - yStart;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
c = new int[len];
|
|
|
|
|
|
Array.Copy(y, yStart, c, 0, len);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
for (;;)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (cBitLength < xBitLength
|
2016-04-18 12:50:57 +02:00
|
|
|
|
|| CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Subtract(xStart, x, cStart, c);
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (x[xStart] == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (++xStart == x.Length)
|
|
|
|
|
|
return x;
|
|
|
|
|
|
|
|
|
|
|
|
//xBitLength = calcBitLength(xStart, x);
|
|
|
|
|
|
xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]);
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (xBitLength <= yBitLength)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (xBitLength < yBitLength)
|
|
|
|
|
|
return x;
|
|
|
|
|
|
|
|
|
|
|
|
xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
|
|
|
|
|
|
|
|
|
|
|
|
if (xyCmp <= 0)
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
shift = cBitLength - xBitLength;
|
|
|
|
|
|
|
|
|
|
|
|
// NB: The case where c[cStart] is 1-bit is harmless
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (shift == 1)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var firstC = (uint) c[cStart] >> 1;
|
|
|
|
|
|
var firstX = (uint) x[xStart];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (firstC > firstX)
|
|
|
|
|
|
++shift;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (shift < 2)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
ShiftRightOneInPlace(cStart, c);
|
|
|
|
|
|
--cBitLength;
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
ShiftRightInPlace(cStart, c, shift);
|
|
|
|
|
|
cBitLength -= shift;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//cStart = c.Length - ((cBitLength + 31) / 32);
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (c[cStart] == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
++cStart;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (xyCmp == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Array.Clear(x, xStart, x.Length - xStart);
|
|
|
|
|
|
|
|
|
|
|
|
return x;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger Remainder(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger n)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (n.SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
throw new ArithmeticException("Division by zero error");
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return Zero;
|
|
|
|
|
|
|
|
|
|
|
|
// For small values, use fast remainder method
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (n.magnitude.Length == 1)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var val = n.magnitude[0];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (val > 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (val == 1)
|
|
|
|
|
|
return Zero;
|
|
|
|
|
|
|
|
|
|
|
|
// TODO Make this func work on uint, and handle val == 1?
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var rem = Remainder(val);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
return rem == 0
|
|
|
|
|
|
? Zero
|
2017-04-13 08:38:01 +02:00
|
|
|
|
: new BigInteger(SignValue, new[] {rem}, false);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude) < 0)
|
|
|
|
|
|
return this;
|
|
|
|
|
|
|
|
|
|
|
|
int[] result;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (n.QuickPow2Check()) // n is power of two
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// TODO Move before small values branch above?
|
|
|
|
|
|
result = LastNBits(n.Abs().BitLength - 1);
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
result = (int[]) magnitude.Clone();
|
2015-09-28 04:01:17 +02:00
|
|
|
|
result = Remainder(result, n.magnitude);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return new BigInteger(SignValue, result, true);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int[] LastNBits(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int n)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (n < 1)
|
|
|
|
|
|
return ZeroMagnitude;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var numWords = (n + BitsPerInt - 1) / BitsPerInt;
|
|
|
|
|
|
numWords = Math.Min(numWords, magnitude.Length);
|
|
|
|
|
|
var result = new int[numWords];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
Array.Copy(magnitude, magnitude.Length - numWords, result, 0, numWords);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var hiBits = n % 32;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (hiBits != 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
result[0] &= ~(-1 << hiBits);
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* do a left shift - this returns a new array.
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static int[] ShiftLeft(
|
|
|
|
|
|
int[] mag,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int n)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var nInts = (int) ((uint) n >> 5);
|
|
|
|
|
|
var nBits = n & 0x1f;
|
|
|
|
|
|
var magLen = mag.Length;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
int[] newMag;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (nBits == 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
newMag = new int[magLen + nInts];
|
|
|
|
|
|
mag.CopyTo(newMag, 0);
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var i = 0;
|
|
|
|
|
|
var nBits2 = 32 - nBits;
|
|
|
|
|
|
var highBits = (int) ((uint) mag[0] >> nBits2);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (highBits != 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
newMag = new int[magLen + nInts + 1];
|
|
|
|
|
|
newMag[i++] = highBits;
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
newMag = new int[magLen + nInts];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var m = mag[0];
|
|
|
|
|
|
for (var j = 0; j < magLen - 1; j++)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var next = mag[j + 1];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
newMag[i++] = (m << nBits) | (int) ((uint) next >> nBits2);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
m = next;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
newMag[i] = mag[magLen - 1] << nBits;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return newMag;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger ShiftLeft(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int n)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0 || magnitude.Length == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return Zero;
|
|
|
|
|
|
|
|
|
|
|
|
if (n == 0)
|
|
|
|
|
|
return this;
|
|
|
|
|
|
|
|
|
|
|
|
if (n < 0)
|
|
|
|
|
|
return ShiftRight(-n);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var result = new BigInteger(SignValue, ShiftLeft(magnitude, n), true);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (nBits != -1)
|
|
|
|
|
|
result.nBits = SignValue > 0
|
|
|
|
|
|
? nBits
|
|
|
|
|
|
: nBits + n;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (nBitLength != -1)
|
|
|
|
|
|
result.nBitLength = nBitLength + n;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* do a right shift - this does it in place.
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static void ShiftRightInPlace(
|
|
|
|
|
|
int start,
|
|
|
|
|
|
int[] mag,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int n)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var nInts = (int) ((uint) n >> 5) + start;
|
|
|
|
|
|
var nBits = n & 0x1f;
|
|
|
|
|
|
var magEnd = mag.Length - 1;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (nInts != start)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var delta = nInts - start;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = magEnd; i >= nInts; i--)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
mag[i] = mag[i - delta];
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = nInts - 1; i >= start; i--)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
mag[i] = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (nBits != 0)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var nBits2 = 32 - nBits;
|
|
|
|
|
|
var m = mag[magEnd];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = magEnd; i > nInts; --i)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var next = mag[i - 1];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
mag[i] = (int) ((uint) m >> nBits) | (next << nBits2);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
m = next;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
mag[nInts] = (int) ((uint) mag[nInts] >> nBits);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* do a right shift by one - this does it in place.
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static void ShiftRightOneInPlace(
|
|
|
|
|
|
int start,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] mag)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var i = mag.Length;
|
|
|
|
|
|
var m = mag[i - 1];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (--i > start)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var next = mag[i - 1];
|
|
|
|
|
|
mag[i] = (int) ((uint) m >> 1) | (next << 31);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
m = next;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
mag[start] = (int) ((uint) mag[start] >> 1);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger ShiftRight(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int n)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (n == 0)
|
|
|
|
|
|
return this;
|
|
|
|
|
|
|
|
|
|
|
|
if (n < 0)
|
|
|
|
|
|
return ShiftLeft(-n);
|
|
|
|
|
|
|
|
|
|
|
|
if (n >= BitLength)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return SignValue < 0 ? One.Negate() : Zero;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
// int[] res = (int[]) this.magnitude.Clone();
|
|
|
|
|
|
//
|
|
|
|
|
|
// ShiftRightInPlace(0, res, n);
|
|
|
|
|
|
//
|
|
|
|
|
|
// return new BigInteger(this.sign, res, true);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var resultLength = (BitLength - n + 31) >> 5;
|
|
|
|
|
|
var res = new int[resultLength];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var numInts = n >> 5;
|
|
|
|
|
|
var numBits = n & 31;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (numBits == 0)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
Array.Copy(magnitude, 0, res, 0, res.Length);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var numBits2 = 32 - numBits;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var magPos = magnitude.Length - 1 - numInts;
|
|
|
|
|
|
for (var i = resultLength - 1; i >= 0; --i)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
res[i] = (int) ((uint) magnitude[magPos--] >> numBits);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (magPos >= 0)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
res[i] |= magnitude[magPos] << numBits2;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Debug.Assert(res[0] != 0);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return new BigInteger(SignValue, res, false);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* returns x = x - y - we assume x is >= y
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static int[] Subtract(
|
|
|
|
|
|
int xStart,
|
|
|
|
|
|
int[] x,
|
|
|
|
|
|
int yStart,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] y)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Debug.Assert(yStart < y.Length);
|
|
|
|
|
|
Debug.Assert(x.Length - xStart >= y.Length - yStart);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var iT = x.Length;
|
|
|
|
|
|
var iV = y.Length;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
long m;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var borrow = 0;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
do
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
m = (x[--iT] & IMASK) - (y[--iV] & IMASK) + borrow;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
x[iT] = (int) m;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
// borrow = (m < 0) ? -1 : 0;
|
2017-04-13 08:38:01 +02:00
|
|
|
|
borrow = (int) (m >> 63);
|
|
|
|
|
|
} while (iV > yStart);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (borrow != 0)
|
|
|
|
|
|
while (--x[--iT] == -1)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return x;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger Subtract(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger n)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (n.SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return this;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return n.Negate();
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue != n.SignValue)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return Add(n.Negate());
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (compare == 0)
|
|
|
|
|
|
return Zero;
|
|
|
|
|
|
|
|
|
|
|
|
BigInteger bigun, lilun;
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (compare < 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
bigun = n;
|
|
|
|
|
|
lilun = this;
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
bigun = this;
|
|
|
|
|
|
lilun = n;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return new BigInteger(SignValue * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static int[] doSubBigLil(
|
|
|
|
|
|
int[] bigMag,
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int[] lilMag)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var res = (int[]) bigMag.Clone();
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
return Subtract(0, res, 0, lilMag);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
public byte[] ToByteArray()
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return ToByteArray(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
public byte[] ToByteArrayUnsigned()
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return ToByteArray(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private byte[] ToByteArray(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
bool unsigned)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return unsigned ? ZeroEncoding : new byte[1];
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var nBits = unsigned && SignValue > 0
|
2015-09-28 04:01:17 +02:00
|
|
|
|
? BitLength
|
|
|
|
|
|
: BitLength + 1;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var nBytes = GetByteLength(nBits);
|
|
|
|
|
|
var bytes = new byte[nBytes];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var magIndex = magnitude.Length;
|
|
|
|
|
|
var bytesIndex = bytes.Length;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue > 0)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
|
|
|
|
|
while (magIndex > 1)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var mag = (uint) magnitude[--magIndex];
|
|
|
|
|
|
bytes[--bytesIndex] = (byte) mag;
|
|
|
|
|
|
bytes[--bytesIndex] = (byte) (mag >> 8);
|
|
|
|
|
|
bytes[--bytesIndex] = (byte) (mag >> 16);
|
|
|
|
|
|
bytes[--bytesIndex] = (byte) (mag >> 24);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var lastMag = (uint) magnitude[0];
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (lastMag > byte.MaxValue)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
bytes[--bytesIndex] = (byte) lastMag;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
lastMag >>= 8;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
bytes[--bytesIndex] = (byte) lastMag;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
else // sign < 0
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var carry = true;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (magIndex > 1)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var mag = ~(uint) magnitude[--magIndex];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (carry)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
carry = ++mag == uint.MinValue;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
bytes[--bytesIndex] = (byte) mag;
|
|
|
|
|
|
bytes[--bytesIndex] = (byte) (mag >> 8);
|
|
|
|
|
|
bytes[--bytesIndex] = (byte) (mag >> 16);
|
|
|
|
|
|
bytes[--bytesIndex] = (byte) (mag >> 24);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var lastMag = (uint) magnitude[0];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (carry)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
--lastMag;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (lastMag > byte.MaxValue)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
bytes[--bytesIndex] = (byte) ~lastMag;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
lastMag >>= 8;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
bytes[--bytesIndex] = (byte) ~lastMag;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (bytesIndex > 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
bytes[--bytesIndex] = byte.MaxValue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return bytes;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
public override string ToString()
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return ToString(10);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string ToString(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int radix)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// TODO Make this method work for other radices (ideally 2 <= radix <= 16)
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
switch (radix)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
case 2:
|
|
|
|
|
|
case 10:
|
|
|
|
|
|
case 16:
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
throw new FormatException("Only bases 2, 10, 16 are allowed");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NB: Can only happen to internally managed instances
|
|
|
|
|
|
if (magnitude == null)
|
|
|
|
|
|
return "null";
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return "0";
|
|
|
|
|
|
|
|
|
|
|
|
Debug.Assert(magnitude.Length > 0);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var sb = new StringBuilder();
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (radix == 16)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
sb.Append(magnitude[0].ToString("x"));
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = 1; i < magnitude.Length; i++)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
sb.Append(magnitude[i].ToString("x8"));
|
|
|
|
|
|
}
|
2016-04-18 12:50:57 +02:00
|
|
|
|
else if (radix == 2)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
sb.Append('1');
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = BitLength - 2; i >= 0; --i)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
sb.Append(TestBit(i) ? '1' : '0');
|
|
|
|
|
|
}
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// This is algorithm 1a from chapter 4.4 in Seminumerical Algorithms, slow but it works
|
|
|
|
|
|
IList S = new List<object>();
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var bs = ValueOf(radix);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
// The sign is handled separatly.
|
|
|
|
|
|
// Notice however that for this to work, radix 16 _MUST_ be a special case,
|
|
|
|
|
|
// unless we want to enter a recursion well. In their infinite wisdom, why did not
|
|
|
|
|
|
// the Sun engineers made a c'tor for BigIntegers taking a BigInteger as parameter?
|
|
|
|
|
|
// (Answer: Becuase Sun's BigIntger is clonable, something bouncycastle's isn't.)
|
|
|
|
|
|
// BigInteger u = new BigInteger(Abs().ToString(16), 16);
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var u = Abs();
|
2015-09-28 04:01:17 +02:00
|
|
|
|
BigInteger b;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
while (u.SignValue != 0)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
b = u.Mod(bs);
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (b.SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
S.Add("0");
|
2017-04-13 08:38:01 +02:00
|
|
|
|
else S.Add(b.magnitude[0].ToString("d"));
|
2015-09-28 04:01:17 +02:00
|
|
|
|
u = u.Divide(bs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Then pop the stack
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = S.Count - 1; i >= 0; --i)
|
|
|
|
|
|
sb.Append((string) S[i]);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var s = sb.ToString();
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
Debug.Assert(s.Length > 0);
|
|
|
|
|
|
|
|
|
|
|
|
// Strip leading zeros. (We know this number is not all zeroes though)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (s[0] == '0')
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var nonZeroPos = 0;
|
|
|
|
|
|
while (s[++nonZeroPos] == '0')
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
s = s.Substring(nonZeroPos);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == -1)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
s = "-" + s;
|
|
|
|
|
|
|
|
|
|
|
|
return s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static BigInteger createUValueOf(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
ulong value)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var msw = (int) (value >> 32);
|
|
|
|
|
|
var lsw = (int) value;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
if (msw != 0)
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return new BigInteger(1, new[] {msw, lsw}, false);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (lsw != 0)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var n = new BigInteger(1, new[] {lsw}, false);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
// Check for a power of two
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if ((lsw & -lsw) == lsw)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
n.nBits = 1;
|
|
|
|
|
|
return n;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return Zero;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static BigInteger createValueOf(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
long value)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (value < 0)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (value == long.MinValue)
|
|
|
|
|
|
return createValueOf(~value).Not();
|
|
|
|
|
|
|
|
|
|
|
|
return createValueOf(-value).Negate();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return createUValueOf((ulong) value);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
// // store value into a byte array
|
|
|
|
|
|
// byte[] b = new byte[8];
|
|
|
|
|
|
// for (int i = 0; i < 8; i++)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// b[7 - i] = (byte)value;
|
|
|
|
|
|
// value >>= 8;
|
|
|
|
|
|
// }
|
|
|
|
|
|
//
|
|
|
|
|
|
// return new BigInteger(b);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static BigInteger ValueOf(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
long value)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (value)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
case 0:
|
|
|
|
|
|
return Zero;
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
return One;
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
return Two;
|
|
|
|
|
|
case 3:
|
|
|
|
|
|
return Three;
|
|
|
|
|
|
case 10:
|
|
|
|
|
|
return Ten;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return createValueOf(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
public int GetLowestSetBit()
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return -1;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var w = magnitude.Length;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (--w > 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (magnitude[w] != 0)
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var word = magnitude[w];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Debug.Assert(word != 0);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var b = (word & 0x0000FFFF) == 0
|
2015-09-28 04:01:17 +02:00
|
|
|
|
? (word & 0x00FF0000) == 0
|
|
|
|
|
|
? 7
|
|
|
|
|
|
: 15
|
|
|
|
|
|
: (word & 0x000000FF) == 0
|
|
|
|
|
|
? 23
|
|
|
|
|
|
: 31;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
while (b > 0)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (word << b == int.MinValue)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
b--;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return (magnitude.Length - w) * 32 - (b + 1);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool TestBit(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int n)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (n < 0)
|
|
|
|
|
|
throw new ArithmeticException("Bit position must not be negative");
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue < 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return !Not().TestBit(n);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var wordNum = n / 32;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (wordNum >= magnitude.Length)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var word = magnitude[magnitude.Length - 1 - wordNum];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return ((word >> (n % 32)) & 1) > 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger Or(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger value)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return value;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (value.SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return this;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var aMag = SignValue > 0
|
|
|
|
|
|
? magnitude
|
2015-09-28 04:01:17 +02:00
|
|
|
|
: Add(One).magnitude;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var bMag = value.SignValue > 0
|
2015-09-28 04:01:17 +02:00
|
|
|
|
? value.magnitude
|
|
|
|
|
|
: value.Add(One).magnitude;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var resultNeg = SignValue < 0 || value.SignValue < 0;
|
|
|
|
|
|
var resultLength = Math.Max(aMag.Length, bMag.Length);
|
|
|
|
|
|
var resultMag = new int[resultLength];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var aStart = resultMag.Length - aMag.Length;
|
|
|
|
|
|
var bStart = resultMag.Length - bMag.Length;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = 0; i < resultMag.Length; ++i)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var aWord = i >= aStart ? aMag[i - aStart] : 0;
|
|
|
|
|
|
var bWord = i >= bStart ? bMag[i - bStart] : 0;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue < 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
aWord = ~aWord;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (value.SignValue < 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
bWord = ~bWord;
|
|
|
|
|
|
|
|
|
|
|
|
resultMag[i] = aWord | bWord;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (resultNeg)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
resultMag[i] = ~resultMag[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var result = new BigInteger(1, resultMag, true);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
// TODO Optimise this case
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (resultNeg)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
result = result.Not();
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger Xor(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
BigInteger value)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return value;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (value.SignValue == 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return this;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var aMag = SignValue > 0
|
|
|
|
|
|
? magnitude
|
2015-09-28 04:01:17 +02:00
|
|
|
|
: Add(One).magnitude;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var bMag = value.SignValue > 0
|
2015-09-28 04:01:17 +02:00
|
|
|
|
? value.magnitude
|
|
|
|
|
|
: value.Add(One).magnitude;
|
|
|
|
|
|
|
|
|
|
|
|
// TODO Can just replace with sign != value.sign?
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var resultNeg = SignValue < 0 && value.SignValue >= 0 || SignValue >= 0 && value.SignValue < 0;
|
|
|
|
|
|
var resultLength = Math.Max(aMag.Length, bMag.Length);
|
|
|
|
|
|
var resultMag = new int[resultLength];
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var aStart = resultMag.Length - aMag.Length;
|
|
|
|
|
|
var bStart = resultMag.Length - bMag.Length;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
for (var i = 0; i < resultMag.Length; ++i)
|
2016-04-18 12:50:57 +02:00
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var aWord = i >= aStart ? aMag[i - aStart] : 0;
|
|
|
|
|
|
var bWord = i >= bStart ? bMag[i - bStart] : 0;
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue < 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
aWord = ~aWord;
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (value.SignValue < 0)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
bWord = ~bWord;
|
|
|
|
|
|
|
|
|
|
|
|
resultMag[i] = aWord ^ bWord;
|
|
|
|
|
|
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (resultNeg)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
resultMag[i] = ~resultMag[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var result = new BigInteger(1, resultMag, true);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
|
|
|
|
|
|
// TODO Optimise this case
|
2016-04-18 12:50:57 +02:00
|
|
|
|
if (resultNeg)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
result = result.Not();
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger SetBit(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int n)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (n < 0)
|
|
|
|
|
|
throw new ArithmeticException("Bit address less than zero");
|
|
|
|
|
|
|
|
|
|
|
|
if (TestBit(n))
|
|
|
|
|
|
return this;
|
|
|
|
|
|
|
|
|
|
|
|
// TODO Handle negative values and zero
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue > 0 && n < BitLength - 1)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return FlipExistingBit(n);
|
|
|
|
|
|
|
|
|
|
|
|
return Or(One.ShiftLeft(n));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger ClearBit(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int n)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (n < 0)
|
|
|
|
|
|
throw new ArithmeticException("Bit address less than zero");
|
|
|
|
|
|
|
|
|
|
|
|
if (!TestBit(n))
|
|
|
|
|
|
return this;
|
|
|
|
|
|
|
|
|
|
|
|
// TODO Handle negative values
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue > 0 && n < BitLength - 1)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return FlipExistingBit(n);
|
|
|
|
|
|
|
|
|
|
|
|
return AndNot(One.ShiftLeft(n));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public BigInteger FlipBit(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int n)
|
|
|
|
|
|
{
|
2015-09-28 04:01:17 +02:00
|
|
|
|
if (n < 0)
|
|
|
|
|
|
throw new ArithmeticException("Bit address less than zero");
|
|
|
|
|
|
|
|
|
|
|
|
// TODO Handle negative values and zero
|
2017-04-13 08:38:01 +02:00
|
|
|
|
if (SignValue > 0 && n < BitLength - 1)
|
2015-09-28 04:01:17 +02:00
|
|
|
|
return FlipExistingBit(n);
|
|
|
|
|
|
|
|
|
|
|
|
return Xor(One.ShiftLeft(n));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private BigInteger FlipExistingBit(
|
2016-04-18 12:50:57 +02:00
|
|
|
|
int n)
|
|
|
|
|
|
{
|
2017-04-13 08:38:01 +02:00
|
|
|
|
Debug.Assert(SignValue > 0);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
Debug.Assert(n >= 0);
|
|
|
|
|
|
Debug.Assert(n < BitLength - 1);
|
|
|
|
|
|
|
2017-04-13 08:38:01 +02:00
|
|
|
|
var mag = (int[]) magnitude.Clone();
|
|
|
|
|
|
mag[mag.Length - 1 - (n >> 5)] ^= 1 << (n & 31); // Flip bit
|
2015-09-28 04:01:17 +02:00
|
|
|
|
//mag[mag.Length - 1 - (n / 32)] ^= (1 << (n % 32));
|
2017-04-13 08:38:01 +02:00
|
|
|
|
return new BigInteger(SignValue, mag, false);
|
2015-09-28 04:01:17 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|