├── FUNDING.yml ├── MLAPI.Cryptography.Examples ├── EmptyClass.cs ├── MLAPI.Cryptography.Examples.csproj └── Program.cs ├── MLAPI.Cryptography ├── Math │ ├── UnsignedIntegerArrayExtensions.cs │ └── BigInteger.cs ├── MLAPI.Cryptography.csproj ├── Utils │ └── ComparisonUtils.cs ├── EllipticCurves │ ├── CurvePoint.cs │ └── EllipticCurve.cs └── KeyExchanges │ ├── ECDiffieHellman.cs │ └── ECDiffieHellmanRSA.cs ├── LICENCE ├── MLAPI.Cryptography.sln ├── README.md └── .gitignore /FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: TwoTenPvP -------------------------------------------------------------------------------- /MLAPI.Cryptography.Examples/EmptyClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace MLAPI.Cryptography.Examples 3 | { 4 | public class EmptyClass 5 | { 6 | public EmptyClass() 7 | { 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /MLAPI.Cryptography/Math/UnsignedIntegerArrayExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace MLAPI.Cryptography.Math 2 | { 3 | internal static class UnsignedIntegerArrayExtensions 4 | { 5 | public static bool BitAt(this uint[] data, long index) => (data[index / 32] & (1 << (int)(index % 32))) != 0; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /MLAPI.Cryptography/MLAPI.Cryptography.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net35;net45;net471;netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /MLAPI.Cryptography.Examples/MLAPI.Cryptography.Examples.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net35 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /MLAPI.Cryptography/Utils/ComparisonUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace MLAPI.Cryptography.Utils 4 | { 5 | public static class ComparisonUtils 6 | { 7 | public static bool ConstTimeArrayEqual(byte[] a, byte[] b) 8 | { 9 | if (a.Length != b.Length) 10 | return false; 11 | 12 | int i = a.Length; 13 | int cmp = 0; 14 | 15 | while (i != 0) 16 | { 17 | --i; 18 | cmp |= (a[i] ^ b[i]); 19 | } 20 | 21 | return cmp == 0; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /MLAPI.Cryptography/EllipticCurves/CurvePoint.cs: -------------------------------------------------------------------------------- 1 | using MLAPI.Cryptography.Math; 2 | 3 | namespace MLAPI.Cryptography.EllipticCurves 4 | { 5 | public class CurvePoint 6 | { 7 | public static readonly CurvePoint POINT_AT_INFINITY = new CurvePoint(); 8 | public BigInteger X { get; private set; } 9 | public BigInteger Y { get; private set; } 10 | private readonly bool pai = false; 11 | 12 | public CurvePoint(BigInteger x, BigInteger y) 13 | { 14 | X = x; 15 | Y = y; 16 | } 17 | 18 | private CurvePoint() 19 | { 20 | pai = true; 21 | } // Accessing corrdinates causes undocumented behaviour 22 | 23 | public override string ToString() 24 | { 25 | return pai ? "(POINT_AT_INFINITY)" : "(" + X + ", " + Y + ")"; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Albin Corén 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MLAPI.Cryptography.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLAPI.Cryptography", "MLAPI.Cryptography\MLAPI.Cryptography.csproj", "{DE2A4003-40E3-406D-B5FF-E6F1C8B0B64A}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLAPI.Cryptography.Examples", "MLAPI.Cryptography.Examples\MLAPI.Cryptography.Examples.csproj", "{F91BE960-52E2-4F36-9196-1EEA1FFA0380}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {DE2A4003-40E3-406D-B5FF-E6F1C8B0B64A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {DE2A4003-40E3-406D-B5FF-E6F1C8B0B64A}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {DE2A4003-40E3-406D-B5FF-E6F1C8B0B64A}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {DE2A4003-40E3-406D-B5FF-E6F1C8B0B64A}.Release|Any CPU.Build.0 = Release|Any CPU 18 | {F91BE960-52E2-4F36-9196-1EEA1FFA0380}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {F91BE960-52E2-4F36-9196-1EEA1FFA0380}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {F91BE960-52E2-4F36-9196-1EEA1FFA0380}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {F91BE960-52E2-4F36-9196-1EEA1FFA0380}.Release|Any CPU.Build.0 = Release|Any CPU 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MLAPI.Cryptography 2 | MLAPI.Cryptography is a Unity friendly crypto library to fill the missing features of Unity's Mono runtime framework. 3 | 4 | Currently it offers a BigInt, ECDHE, ECDHE_RSA and EllipticCurve implementation. Note that MLAPI.Cryptography is **NOT** designed to be an extensive crypto library such as NaCL or replace the .NET Framework. It's simply there to fill the missing gaps in the Unity Engine. Behind the scenes, MLAPI.Cryptography will use as much of the avalible .NET surface as possible. An example of this is the ECDHE_RSA implementation which uses MLAPI.Cryptographys BigInt, EllipticCurve and DiffieHellman implementations while it uses .NET's RSA implementation. 5 | 6 | 7 | ### ECDHE Usage 8 | ```csharp 9 | // Both create their instances 10 | ECDiffieHellman serverDiffie = new ECDiffieHellman(); 11 | ECDiffieHellman clientDiffie = new ECDiffieHellman(); 12 | 13 | // Exchange publics 14 | 15 | /* START TRANSMISSION */ 16 | byte[] serverPublic = serverDiffie.GetPublicKey(); 17 | byte[] clientPublic = clientDiffie.GetPublicKey(); 18 | /* END TRANSMISSION */ 19 | 20 | // Calculate shared 21 | byte[] key1 = serverDiffie.GetSharedSecretRaw(clientPublic); 22 | byte[] key2 = clientDiffie.GetSharedSecretRaw(serverPublic); 23 | ``` 24 | 25 | ### ECDHERSA Usage 26 | ```csharp 27 | // Key pairs 28 | RSAParameters privateKey; 29 | RSAParameters publicKey; 30 | 31 | // Generate keys, you can use X509Certificate2 instead of raw RSA keys. 32 | using (RSACryptoServiceProvider rsaGen = new RSACryptoServiceProvider(2048)) 33 | { 34 | privateKey = rsaGen.ExportParameters(true); 35 | publicKey = rsaGen.ExportParameters(false); 36 | } 37 | 38 | using (RSACryptoServiceProvider serverRSA = new RSACryptoServiceProvider()) 39 | using (RSACryptoServiceProvider clientRSA = new RSACryptoServiceProvider()) 40 | { 41 | serverRSA.ImportParameters(privateKey); 42 | clientRSA.ImportParameters(publicKey); 43 | 44 | // Both create their instances, constructor can take certificate instead or RSA key. 45 | ECDiffieHellmanRSA serverDiffie = new ECDiffieHellmanRSA(serverRSA); 46 | ECDiffieHellmanRSA clientDiffie = new ECDiffieHellmanRSA(clientRSA); 47 | 48 | // Exchange publics 49 | 50 | /* START TRANSMISSION */ 51 | byte[] serverPublic = serverDiffie.GetSecurePublicPart(); 52 | byte[] clientPublic = clientDiffie.GetSecurePublicPart(); 53 | /* END TRANSMISSION */ 54 | 55 | // Calculate shared 56 | byte[] key1 = serverDiffie.GetVerifiedSharedPart(clientPublic); 57 | byte[] key2 = clientDiffie.GetVerifiedSharedPart(serverPublic); 58 | } 59 | ``` 60 | ### Timing Side Channel Attack Prevention 61 | ```csharp 62 | byte[] array1 = new byte[120]; 63 | byte[] array2 = new byte[120]; 64 | array[50] = 67; 65 | 66 | // This comparison will take constant time, no matter where the diff is (if any). 67 | bool equal = ComparisonUtils.ConstTimeArrayEqual(array1, array2); 68 | ``` -------------------------------------------------------------------------------- /MLAPI.Cryptography/KeyExchanges/ECDiffieHellman.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | using System.Text; 4 | using MLAPI.Cryptography.EllipticCurves; 5 | using MLAPI.Cryptography.Math; 6 | 7 | namespace MLAPI.Cryptography.KeyExchanges 8 | { 9 | public class ECDiffieHellman 10 | { 11 | protected static readonly RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider(); 12 | 13 | public static readonly BigInteger DEFAULT_PRIME = (new BigInteger("1") << 255) - 19; 14 | public static readonly BigInteger DEFAULT_ORDER = (new BigInteger(1) << 252) + new BigInteger("27742317777372353535851937790883648493"); 15 | public static EllipticCurve DEFAULT_CURVE = new EllipticCurve(486662, 1, DEFAULT_PRIME, EllipticCurve.CurveType.Montgomery); 16 | public static CurvePoint DEFAULT_GENERATOR = new CurvePoint(9, new BigInteger("14781619447589544791020593568409986887264606134616475288964881837755586237401")); 17 | 18 | protected readonly EllipticCurve curve; 19 | public readonly BigInteger priv; 20 | protected readonly CurvePoint generator, pub; 21 | 22 | public ECDiffieHellman(byte[] priv = null) : this(DEFAULT_CURVE, DEFAULT_GENERATOR, DEFAULT_ORDER, priv) 23 | { 24 | 25 | } 26 | 27 | public ECDiffieHellman(EllipticCurve curve, CurvePoint generator, BigInteger order, byte[] priv = null) 28 | { 29 | this.curve = curve; 30 | this.generator = generator; 31 | 32 | // Generate private key 33 | if (priv == null) 34 | { 35 | this.priv = new BigInteger(); 36 | this.priv.GenRandomBits(order.DataLength * 8, rand); 37 | } 38 | else this.priv = new BigInteger(priv); 39 | 40 | // Generate public key 41 | pub = curve.Multiply(generator, this.priv); 42 | } 43 | 44 | public byte[] GetPublicKey() 45 | { 46 | byte[] p1 = pub.X.GetBytes(); 47 | byte[] p2 = pub.Y.GetBytes(); 48 | 49 | byte[] ser = new byte[4 + p1.Length + p2.Length]; 50 | ser[0] = (byte)(p1.Length & 255); 51 | ser[1] = (byte)((p1.Length >> 8) & 255); 52 | ser[2] = (byte)((p1.Length >> 16) & 255); 53 | ser[3] = (byte)((p1.Length >> 24) & 255); 54 | Array.Copy(p1, 0, ser, 4, p1.Length); 55 | Array.Copy(p2, 0, ser, 4 + p1.Length, p2.Length); 56 | 57 | return ser; 58 | } 59 | 60 | public byte[] GetPrivateKey() => priv.GetBytes(); 61 | 62 | public byte[] GetSharedSecretStretchedToBytes(byte[] pK, int bytes, int iterations, string salt) 63 | { 64 | return GetSharedSecretStretchedToBytes(pK, bytes, iterations, Encoding.UTF8.GetBytes(salt)); 65 | } 66 | 67 | public byte[] GetSharedSecretStretchedToBytes(byte[] pK, int bytes, int iterations, byte[] salt) 68 | { 69 | // PBKDF2-HMAC-SHA1 (Common shared secret generation method) 70 | return new Rfc2898DeriveBytes(GetSharedSecretRaw(pK), salt, iterations).GetBytes(bytes); 71 | } 72 | 73 | public byte[] GetSharedSecretRaw(byte[] pK) 74 | { 75 | byte[] p1 = new byte[pK[0] | (pK[1] << 8) | (pK[2] << 16) | (pK[3] << 24)]; // Reconstruct x-axis size 76 | byte[] p2 = new byte[pK.Length - p1.Length - 4]; 77 | Array.Copy(pK, 4, p1, 0, p1.Length); 78 | Array.Copy(pK, 4 + p1.Length, p2, 0, p2.Length); 79 | 80 | CurvePoint remotePublic = new CurvePoint(new BigInteger(p1), new BigInteger(p2)); 81 | 82 | byte[] secret = curve.Multiply(remotePublic, priv).X.GetBytes(); // Use the x-coordinate as the shared secret 83 | 84 | return secret; 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /MLAPI.Cryptography.Examples/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Security.Cryptography; 4 | using MLAPI.Cryptography.KeyExchanges; 5 | 6 | namespace MLAPI.Cryptography.Examples 7 | { 8 | class Program 9 | { 10 | public static void Main(string[] args) 11 | { 12 | RunECDHERSA(100); 13 | RunECDHE(100); 14 | } 15 | 16 | public static void RunECDHERSA(int iterations) 17 | { 18 | Console.WriteLine("Running " + iterations + " diffie hellman + rsa key exchanges"); 19 | 20 | Stopwatch watch = new Stopwatch(); 21 | 22 | RSAParameters privateKey; 23 | RSAParameters publicKey; 24 | 25 | using (RSACryptoServiceProvider rsaGen = new RSACryptoServiceProvider(2048)) 26 | { 27 | privateKey = rsaGen.ExportParameters(true); 28 | publicKey = rsaGen.ExportParameters(false); 29 | } 30 | 31 | for (int i = 0; i < iterations; i++) 32 | { 33 | watch.Start(); 34 | 35 | using (RSACryptoServiceProvider serverRSA = new RSACryptoServiceProvider()) 36 | using (RSACryptoServiceProvider clientRSA = new RSACryptoServiceProvider()) 37 | { 38 | serverRSA.ImportParameters(privateKey); 39 | clientRSA.ImportParameters(publicKey); 40 | 41 | // Both create their instances 42 | ECDiffieHellmanRSA serverDiffie = new ECDiffieHellmanRSA(serverRSA); 43 | ECDiffieHellmanRSA clientDiffie = new ECDiffieHellmanRSA(clientRSA); 44 | 45 | // Exchange publics 46 | 47 | /* START TRANSMISSION */ 48 | byte[] serverPublic = serverDiffie.GetSecurePublicPart(); 49 | byte[] clientPublic = clientDiffie.GetSecurePublicPart(); 50 | /* END TRANSMISSION */ 51 | 52 | // Calculate shared 53 | byte[] key1 = serverDiffie.GetVerifiedSharedPart(clientPublic); 54 | byte[] key2 = clientDiffie.GetVerifiedSharedPart(serverPublic); 55 | 56 | watch.Stop(); 57 | 58 | if (key1.Length != key2.Length) 59 | { 60 | Console.WriteLine("CRITICAL: LENGTH MISSMATCH"); 61 | continue; 62 | } 63 | 64 | for (int x = 0; x < key1.Length; x++) 65 | { 66 | if (key1[x] != key2[x]) 67 | { 68 | Console.WriteLine("CRITICAL: MISSMATCH"); 69 | break; 70 | } 71 | } 72 | } 73 | } 74 | 75 | Console.WriteLine("Completed in " + watch.ElapsedMilliseconds + " ms, " + (watch.ElapsedMilliseconds / iterations) + " ms per exchange"); 76 | } 77 | 78 | public static void RunECDHE(int iterations) 79 | { 80 | Console.WriteLine("Running " + iterations + " diffie hellman key exchanges"); 81 | 82 | Stopwatch watch = new Stopwatch(); 83 | 84 | for (int i = 0; i < iterations; i++) 85 | { 86 | watch.Start(); 87 | 88 | // Both create their instances 89 | ECDiffieHellman serverDiffie = new ECDiffieHellman(); 90 | ECDiffieHellman clientDiffie = new ECDiffieHellman(); 91 | 92 | // Exchange publics 93 | 94 | /* START TRANSMISSION */ 95 | byte[] serverPublic = serverDiffie.GetPublicKey(); 96 | byte[] clientPublic = clientDiffie.GetPublicKey(); 97 | /* END TRANSMISSION */ 98 | 99 | // Calculate shared 100 | byte[] key1 = serverDiffie.GetSharedSecretRaw(clientPublic); 101 | byte[] key2 = clientDiffie.GetSharedSecretRaw(serverPublic); 102 | 103 | watch.Stop(); 104 | 105 | if (key1.Length != key2.Length) 106 | { 107 | Console.WriteLine("CRITICAL: LENGTH MISSMATCH"); 108 | continue; 109 | } 110 | 111 | for (int x = 0; x < key1.Length; x++) 112 | { 113 | if (key1[x] != key2[x]) 114 | { 115 | Console.WriteLine("CRITICAL: MISSMATCH"); 116 | break; 117 | } 118 | } 119 | } 120 | 121 | Console.WriteLine("Completed in " + watch.ElapsedMilliseconds + " ms, " + (watch.ElapsedMilliseconds / iterations) + " ms per exchange"); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /MLAPI.Cryptography/KeyExchanges/ECDiffieHellmanRSA.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | using System.Security.Cryptography.X509Certificates; 4 | using MLAPI.Cryptography.Utils; 5 | 6 | namespace MLAPI.Cryptography.KeyExchanges 7 | { 8 | public class ECDiffieHellmanRSA 9 | { 10 | private readonly ECDiffieHellman _diffieHellanInstance = new ECDiffieHellman(); 11 | private readonly RSACryptoServiceProvider _rsa; 12 | 13 | private bool _isSigner => !_rsa.PublicOnly; 14 | 15 | public ECDiffieHellmanRSA(X509Certificate2 certificate) 16 | { 17 | if (certificate.HasPrivateKey) 18 | { 19 | _rsa = certificate.PrivateKey as RSACryptoServiceProvider; 20 | } 21 | else 22 | { 23 | _rsa = certificate.PublicKey.Key as RSACryptoServiceProvider; 24 | } 25 | 26 | if (_rsa == null) 27 | { 28 | throw new CryptographicException("Only RSA certificates are supported. No valid RSA key was found"); 29 | } 30 | } 31 | 32 | public ECDiffieHellmanRSA(RSACryptoServiceProvider rsa) 33 | { 34 | _rsa = rsa; 35 | 36 | if (_rsa == null) 37 | { 38 | throw new CryptographicException("Key cannot be null"); 39 | } 40 | } 41 | 42 | public byte[] GetSecurePublicPart() 43 | { 44 | byte[] publicPart = _diffieHellanInstance.GetPublicKey(); 45 | 46 | using (SHA256Managed sha = new SHA256Managed()) 47 | { 48 | byte[] proofPart; 49 | 50 | if (_isSigner) 51 | { 52 | // Sign the hash with the private key 53 | proofPart = _rsa.SignData(publicPart, sha); 54 | } 55 | else 56 | { 57 | // Encrypt the public part with the opposite public 58 | proofPart = _rsa.Encrypt(sha.ComputeHash(publicPart), false); 59 | } 60 | 61 | // Final has two lengths appended 62 | byte[] final = new byte[(sizeof(ushort) * 2) + publicPart.Length + proofPart.Length]; 63 | 64 | // Write lengths to final 65 | for (byte i = 0; i < sizeof(ushort); i++) final[i] = ((byte)(publicPart.Length >> (i * 8))); 66 | for (byte i = 0; i < sizeof(ushort); i++) final[i + sizeof(ushort)] = ((byte)(proofPart.Length >> (i * 8))); 67 | 68 | // Copy parts 69 | Buffer.BlockCopy(publicPart, 0, final, (sizeof(ushort) * 2), publicPart.Length); 70 | Buffer.BlockCopy(proofPart, 0, final, (sizeof(ushort) * 2) + publicPart.Length, proofPart.Length); 71 | 72 | return final; 73 | } 74 | } 75 | 76 | public byte[] GetVerifiedSharedPart(byte[] securePart) 77 | { 78 | if (securePart.Length < 4) 79 | { 80 | throw new ArgumentException("Signed part was too short"); 81 | } 82 | 83 | // Read lengths 84 | ushort publicLength = (ushort)(((ushort)securePart[0]) | ((ushort)securePart[1] << 8)); 85 | ushort proofLength = (ushort)(((ushort)securePart[2]) | ((ushort)securePart[3] << 8)); 86 | 87 | if (securePart.Length != publicLength + proofLength + (sizeof(ushort) * 2)) 88 | { 89 | throw new CryptographicException("Part lengths did not match"); 90 | } 91 | 92 | // Alloc parts 93 | byte[] publicPart = new byte[publicLength]; 94 | byte[] proofPart = new byte[proofLength]; 95 | 96 | // Copy parts 97 | Buffer.BlockCopy(securePart, sizeof(ushort) * 2, publicPart, 0, publicLength); 98 | Buffer.BlockCopy(securePart, sizeof(ushort) * 2 + publicLength, proofPart, 0, proofLength); 99 | 100 | if (_isSigner) 101 | { 102 | using (SHA256Managed sha = new SHA256Managed()) 103 | { 104 | byte[] claimedHash = _rsa.Decrypt(proofPart, false); 105 | byte[] realHash = sha.ComputeHash(publicPart); 106 | 107 | // Prevent timing attacks by using constant time 108 | if (ComparisonUtils.ConstTimeArrayEqual(claimedHash, realHash)) 109 | { 110 | return _diffieHellanInstance.GetSharedSecretRaw(publicPart); 111 | } 112 | else 113 | { 114 | throw new CryptographicException("Hash did not match the signed hash"); 115 | } 116 | } 117 | } 118 | else 119 | { 120 | using (SHA256Managed sha = new SHA256Managed()) 121 | { 122 | if (_rsa.VerifyData(publicPart, sha, proofPart)) 123 | { 124 | return _diffieHellanInstance.GetSharedSecretRaw(publicPart); 125 | } 126 | else 127 | { 128 | throw new CryptographicException("Signature was invalid"); 129 | } 130 | } 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /MLAPI.Cryptography/EllipticCurves/EllipticCurve.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MLAPI.Cryptography.Math; 4 | 5 | namespace MLAPI.Cryptography.EllipticCurves 6 | { 7 | public class EllipticCurve 8 | { 9 | public enum CurveType { Weierstrass, Montgomery } 10 | 11 | protected readonly BigInteger a, b, modulo; 12 | protected readonly CurveType type; 13 | 14 | public EllipticCurve(BigInteger a, BigInteger b, BigInteger modulo, CurveType type = CurveType.Weierstrass) 15 | { 16 | if ( 17 | (type == CurveType.Weierstrass && (4 * a * a * a) + (27 * b * b) == 0) || // Unfavourable Weierstrass curves 18 | (type == CurveType.Montgomery && b * (a * a - 4) == 0) // Unfavourable Montgomery curves 19 | ) throw new Exception("Unfavourable curve"); 20 | this.a = a; 21 | this.b = b; 22 | this.modulo = modulo; 23 | this.type = type; 24 | } 25 | 26 | public CurvePoint Add(CurvePoint p1, CurvePoint p2) 27 | { 28 | #if SAFE_MATH 29 | CheckOnCurve(p1); 30 | CheckOnCurve(p2); 31 | #endif 32 | 33 | // Special cases 34 | if (p1 == CurvePoint.POINT_AT_INFINITY && p2 == CurvePoint.POINT_AT_INFINITY) return CurvePoint.POINT_AT_INFINITY; 35 | else if (p1 == CurvePoint.POINT_AT_INFINITY) return p2; 36 | else if (p2 == CurvePoint.POINT_AT_INFINITY) return p1; 37 | else if (p1.X == p2.X && p1.Y == Inverse(p2).Y) return CurvePoint.POINT_AT_INFINITY; 38 | 39 | BigInteger x3 = 0, y3 = 0; 40 | if (type == CurveType.Weierstrass) 41 | { 42 | BigInteger slope = p1.X == p2.X && p1.Y == p2.Y ? Mod((3 * p1.X * p1.X + a) * MulInverse(2 * p1.Y)) : Mod(Mod(p2.Y - p1.Y) * MulInverse(p2.X - p1.X)); 43 | x3 = Mod((slope * slope) - p1.X - p2.X); 44 | y3 = Mod(-((slope * x3) + p1.Y - (slope * p1.X))); 45 | } 46 | else if (type == CurveType.Montgomery) 47 | { 48 | if ((p1.X == p2.X && p1.Y == p2.Y)) 49 | { 50 | BigInteger q = 3 * p1.X; 51 | BigInteger w = q * p1.X; 52 | 53 | BigInteger e = 2 * a; 54 | BigInteger r = e * p1.X; 55 | 56 | BigInteger t = 2 * b; 57 | BigInteger y = t * p1.Y; 58 | 59 | BigInteger u = MulInverse(y); 60 | 61 | BigInteger o = w + e + 1; 62 | BigInteger p = o * u; 63 | } 64 | BigInteger co = p1.X == p2.X && p1.Y == p2.Y ? Mod((3 * p1.X * p1.X + 2 * a * p1.X + 1) * MulInverse(2 * b * p1.Y)) : Mod(Mod(p2.Y - p1.Y) * MulInverse(p2.X - p1.X)); // Compute a commonly used coefficient 65 | x3 = Mod(b * co * co - a - p1.X - p2.X); 66 | y3 = Mod(((2 * p1.X + p2.X + a) * co) - (b * co * co * co) - p1.Y); 67 | } 68 | 69 | return new CurvePoint(x3, y3); 70 | } 71 | 72 | public CurvePoint Multiply(CurvePoint p, BigInteger scalar) 73 | { 74 | if (scalar <= 0) throw new Exception("Cannot multiply by a scalar which is <= 0"); 75 | if (p == CurvePoint.POINT_AT_INFINITY) return CurvePoint.POINT_AT_INFINITY; 76 | 77 | CurvePoint p1 = new CurvePoint(p.X, p.Y); 78 | uint[] u = scalar.GetInternalState(); 79 | long high_bit = -1; 80 | for (int i = u.Length - 1; i >= 0; --i) 81 | if (u[i] != 0) 82 | { 83 | for (int j = 31; j >= 0; --j) 84 | if ((u[i] & (1 << j)) != 0) 85 | { 86 | high_bit = j + i * 32; 87 | goto Next; 88 | } 89 | } 90 | Next: 91 | 92 | // Double-and-add method 93 | while (high_bit >= 0) 94 | { 95 | p1 = Add(p1, p1); // Double 96 | if ((u.BitAt(high_bit))) 97 | p1 = Add(p1, p); // Add 98 | --high_bit; 99 | } 100 | 101 | return p1; 102 | } 103 | 104 | protected BigInteger MulInverse(BigInteger eq) => MulInverse(eq, modulo); 105 | 106 | public static BigInteger MulInverse(BigInteger eq, BigInteger modulo) 107 | { 108 | eq = Mod(eq, modulo); 109 | Stack collect = new Stack(); 110 | BigInteger v = modulo; // Copy modulo 111 | BigInteger m; 112 | while ((m = v % eq) != 0) 113 | { 114 | collect.Push(-v / eq/*-(m.l_div)*/); 115 | v = eq; 116 | eq = m; 117 | } 118 | if (collect.Count == 0) return 1; 119 | v = 1; 120 | m = collect.Pop(); 121 | while (collect.Count > 0) 122 | { 123 | eq = m; 124 | m = v + (m * collect.Pop()); 125 | v = eq; 126 | } 127 | return Mod(m, modulo); 128 | } 129 | 130 | public CurvePoint Inverse(CurvePoint p) => Inverse(p, modulo); 131 | 132 | protected static CurvePoint Inverse(CurvePoint p, BigInteger modulo) => new CurvePoint(p.X, Mod(-p.Y, modulo)); 133 | 134 | public bool IsOnCurve(CurvePoint p) 135 | { 136 | try { CheckOnCurve(p); } 137 | catch { return false; } 138 | return true; 139 | } 140 | 141 | protected void CheckOnCurve(CurvePoint p) 142 | { 143 | if ( 144 | p != CurvePoint.POINT_AT_INFINITY && // The point at infinity is asserted to be on the curve 145 | (type == CurveType.Weierstrass && Mod(p.Y * p.Y) != Mod((p.X * p.X * p.X) + (p.X * a) + b)) || // Weierstrass formula 146 | (type == CurveType.Montgomery && Mod(b * p.Y * p.Y) != Mod((p.X * p.X * p.X) + (p.X * p.X * a) + p.X)) // Montgomery formula 147 | ) throw new Exception("Point is not on curve"); 148 | } 149 | 150 | protected BigInteger Mod(BigInteger b) => Mod(b, modulo); 151 | 152 | private static BigInteger Mod(BigInteger x, BigInteger m) 153 | { 154 | BigInteger r = x.Abs() > m ? x % m : x; 155 | return r < 0 ? r + m : r; 156 | } 157 | 158 | protected static BigInteger ModPow(BigInteger x, BigInteger power, BigInteger prime) 159 | { 160 | BigInteger result = 1; 161 | bool setBit = false; 162 | while (power > 0) 163 | { 164 | x %= prime; 165 | setBit = (power & 1) == 1; 166 | power >>= 1; 167 | if (setBit) result *= x; 168 | x *= x; 169 | } 170 | 171 | return result; 172 | } 173 | } 174 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # globs 2 | Makefile.in 3 | *.userprefs 4 | *.usertasks 5 | config.make 6 | config.status 7 | aclocal.m4 8 | install-sh 9 | autom4te.cache/ 10 | *.tar.gz 11 | tarballs/ 12 | test-results/ 13 | 14 | # Mac bundle stuff 15 | *.dmg 16 | *.app 17 | 18 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore 19 | # General 20 | .DS_Store 21 | .AppleDouble 22 | .LSOverride 23 | 24 | # Icon must end with two \r 25 | Icon 26 | 27 | 28 | # Thumbnails 29 | ._* 30 | 31 | # Files that might appear in the root of a volume 32 | .DocumentRevisions-V100 33 | .fseventsd 34 | .Spotlight-V100 35 | .TemporaryItems 36 | .Trashes 37 | .VolumeIcon.icns 38 | .com.apple.timemachine.donotpresent 39 | 40 | # Directories potentially created on remote AFP share 41 | .AppleDB 42 | .AppleDesktop 43 | Network Trash Folder 44 | Temporary Items 45 | .apdisk 46 | 47 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore 48 | # Windows thumbnail cache files 49 | Thumbs.db 50 | ehthumbs.db 51 | ehthumbs_vista.db 52 | 53 | # Dump file 54 | *.stackdump 55 | 56 | # Folder config file 57 | [Dd]esktop.ini 58 | 59 | # Recycle Bin used on file shares 60 | $RECYCLE.BIN/ 61 | 62 | # Windows Installer files 63 | *.cab 64 | *.msi 65 | *.msix 66 | *.msm 67 | *.msp 68 | 69 | # Windows shortcuts 70 | *.lnk 71 | 72 | # content below from: https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 73 | ## Ignore Visual Studio temporary files, build results, and 74 | ## files generated by popular Visual Studio add-ons. 75 | ## 76 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 77 | 78 | # User-specific files 79 | *.suo 80 | *.user 81 | *.userosscache 82 | *.sln.docstates 83 | 84 | # User-specific files (MonoDevelop/Xamarin Studio) 85 | *.userprefs 86 | 87 | # Build results 88 | [Dd]ebug/ 89 | [Dd]ebugPublic/ 90 | [Rr]elease/ 91 | [Rr]eleases/ 92 | x64/ 93 | x86/ 94 | bld/ 95 | [Bb]in/ 96 | [Oo]bj/ 97 | [Ll]og/ 98 | 99 | # Visual Studio 2015/2017 cache/options directory 100 | .vs/ 101 | # Uncomment if you have tasks that create the project's static files in wwwroot 102 | #wwwroot/ 103 | 104 | # Visual Studio 2017 auto generated files 105 | Generated\ Files/ 106 | 107 | # MSTest test Results 108 | [Tt]est[Rr]esult*/ 109 | [Bb]uild[Ll]og.* 110 | 111 | # NUNIT 112 | *.VisualState.xml 113 | TestResult.xml 114 | 115 | # Build Results of an ATL Project 116 | [Dd]ebugPS/ 117 | [Rr]eleasePS/ 118 | dlldata.c 119 | 120 | # Benchmark Results 121 | BenchmarkDotNet.Artifacts/ 122 | 123 | # .NET Core 124 | project.lock.json 125 | project.fragment.lock.json 126 | artifacts/ 127 | 128 | # StyleCop 129 | StyleCopReport.xml 130 | 131 | # Files built by Visual Studio 132 | *_i.c 133 | *_p.c 134 | *_h.h 135 | *.ilk 136 | *.meta 137 | *.obj 138 | *.iobj 139 | *.pch 140 | *.pdb 141 | *.ipdb 142 | *.pgc 143 | *.pgd 144 | *.rsp 145 | *.sbr 146 | *.tlb 147 | *.tli 148 | *.tlh 149 | *.tmp 150 | *.tmp_proj 151 | *_wpftmp.csproj 152 | *.log 153 | *.vspscc 154 | *.vssscc 155 | .builds 156 | *.pidb 157 | *.svclog 158 | *.scc 159 | 160 | # Chutzpah Test files 161 | _Chutzpah* 162 | 163 | # Visual C++ cache files 164 | ipch/ 165 | *.aps 166 | *.ncb 167 | *.opendb 168 | *.opensdf 169 | *.sdf 170 | *.cachefile 171 | *.VC.db 172 | *.VC.VC.opendb 173 | 174 | # Visual Studio profiler 175 | *.psess 176 | *.vsp 177 | *.vspx 178 | *.sap 179 | 180 | # Visual Studio Trace Files 181 | *.e2e 182 | 183 | # TFS 2012 Local Workspace 184 | $tf/ 185 | 186 | # Guidance Automation Toolkit 187 | *.gpState 188 | 189 | # ReSharper is a .NET coding add-in 190 | _ReSharper*/ 191 | *.[Rr]e[Ss]harper 192 | *.DotSettings.user 193 | 194 | # JustCode is a .NET coding add-in 195 | .JustCode 196 | 197 | # TeamCity is a build add-in 198 | _TeamCity* 199 | 200 | # DotCover is a Code Coverage Tool 201 | *.dotCover 202 | 203 | # AxoCover is a Code Coverage Tool 204 | .axoCover/* 205 | !.axoCover/settings.json 206 | 207 | # Visual Studio code coverage results 208 | *.coverage 209 | *.coveragexml 210 | 211 | # NCrunch 212 | _NCrunch_* 213 | .*crunch*.local.xml 214 | nCrunchTemp_* 215 | 216 | # MightyMoose 217 | *.mm.* 218 | AutoTest.Net/ 219 | 220 | # Web workbench (sass) 221 | .sass-cache/ 222 | 223 | # Installshield output folder 224 | [Ee]xpress/ 225 | 226 | # DocProject is a documentation generator add-in 227 | DocProject/buildhelp/ 228 | DocProject/Help/*.HxT 229 | DocProject/Help/*.HxC 230 | DocProject/Help/*.hhc 231 | DocProject/Help/*.hhk 232 | DocProject/Help/*.hhp 233 | DocProject/Help/Html2 234 | DocProject/Help/html 235 | 236 | # Click-Once directory 237 | publish/ 238 | 239 | # Publish Web Output 240 | *.[Pp]ublish.xml 241 | *.azurePubxml 242 | # Note: Comment the next line if you want to checkin your web deploy settings, 243 | # but database connection strings (with potential passwords) will be unencrypted 244 | *.pubxml 245 | *.publishproj 246 | 247 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 248 | # checkin your Azure Web App publish settings, but sensitive information contained 249 | # in these scripts will be unencrypted 250 | PublishScripts/ 251 | 252 | # NuGet Packages 253 | *.nupkg 254 | # The packages folder can be ignored because of Package Restore 255 | **/[Pp]ackages/* 256 | # except build/, which is used as an MSBuild target. 257 | !**/[Pp]ackages/build/ 258 | # Uncomment if necessary however generally it will be regenerated when needed 259 | #!**/[Pp]ackages/repositories.config 260 | # NuGet v3's project.json files produces more ignorable files 261 | *.nuget.props 262 | *.nuget.targets 263 | 264 | # Microsoft Azure Build Output 265 | csx/ 266 | *.build.csdef 267 | 268 | # Microsoft Azure Emulator 269 | ecf/ 270 | rcf/ 271 | 272 | # Windows Store app package directories and files 273 | AppPackages/ 274 | BundleArtifacts/ 275 | Package.StoreAssociation.xml 276 | _pkginfo.txt 277 | *.appx 278 | 279 | # Visual Studio cache files 280 | # files ending in .cache can be ignored 281 | *.[Cc]ache 282 | # but keep track of directories ending in .cache 283 | !*.[Cc]ache/ 284 | 285 | # Others 286 | ClientBin/ 287 | ~$* 288 | *~ 289 | *.dbmdl 290 | *.dbproj.schemaview 291 | *.jfm 292 | *.pfx 293 | *.publishsettings 294 | orleans.codegen.cs 295 | 296 | # Including strong name files can present a security risk 297 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 298 | #*.snk 299 | 300 | # Since there are multiple workflows, uncomment next line to ignore bower_components 301 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 302 | #bower_components/ 303 | 304 | # RIA/Silverlight projects 305 | Generated_Code/ 306 | 307 | # Backup & report files from converting an old project file 308 | # to a newer Visual Studio version. Backup files are not needed, 309 | # because we have git ;-) 310 | _UpgradeReport_Files/ 311 | Backup*/ 312 | UpgradeLog*.XML 313 | UpgradeLog*.htm 314 | ServiceFabricBackup/ 315 | *.rptproj.bak 316 | 317 | # SQL Server files 318 | *.mdf 319 | *.ldf 320 | *.ndf 321 | 322 | # Business Intelligence projects 323 | *.rdl.data 324 | *.bim.layout 325 | *.bim_*.settings 326 | *.rptproj.rsuser 327 | 328 | # Microsoft Fakes 329 | FakesAssemblies/ 330 | 331 | # GhostDoc plugin setting file 332 | *.GhostDoc.xml 333 | 334 | # Node.js Tools for Visual Studio 335 | .ntvs_analysis.dat 336 | node_modules/ 337 | 338 | # Visual Studio 6 build log 339 | *.plg 340 | 341 | # Visual Studio 6 workspace options file 342 | *.opt 343 | 344 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 345 | *.vbw 346 | 347 | # Visual Studio LightSwitch build output 348 | **/*.HTMLClient/GeneratedArtifacts 349 | **/*.DesktopClient/GeneratedArtifacts 350 | **/*.DesktopClient/ModelManifest.xml 351 | **/*.Server/GeneratedArtifacts 352 | **/*.Server/ModelManifest.xml 353 | _Pvt_Extensions 354 | 355 | # Paket dependency manager 356 | .paket/paket.exe 357 | paket-files/ 358 | 359 | # FAKE - F# Make 360 | .fake/ 361 | 362 | # JetBrains Rider 363 | .idea/ 364 | *.sln.iml 365 | 366 | # CodeRush personal settings 367 | .cr/personal 368 | 369 | # Python Tools for Visual Studio (PTVS) 370 | __pycache__/ 371 | *.pyc 372 | 373 | # Cake - Uncomment if you are using it 374 | # tools/** 375 | # !tools/packages.config 376 | 377 | # Tabs Studio 378 | *.tss 379 | 380 | # Telerik's JustMock configuration file 381 | *.jmconfig 382 | 383 | # BizTalk build output 384 | *.btp.cs 385 | *.btm.cs 386 | *.odx.cs 387 | *.xsd.cs 388 | 389 | # OpenCover UI analysis results 390 | OpenCover/ 391 | 392 | # Azure Stream Analytics local run output 393 | ASALocalRun/ 394 | 395 | # MSBuild Binary and Structured Log 396 | *.binlog 397 | 398 | # NVidia Nsight GPU debugger configuration file 399 | *.nvuser 400 | 401 | # MFractors (Xamarin productivity tool) working folder 402 | .mfractor/ 403 | 404 | # Local History for Visual Studio 405 | .localhistory/ -------------------------------------------------------------------------------- /MLAPI.Cryptography/Math/BigInteger.cs: -------------------------------------------------------------------------------- 1 | /* 2 | BigInteger Class Version 1.03 3 | 4 | Copyright (c) 2002 Chew Keong TAN All rights reserved. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, and/or sell copies of the 10 | Software, and to permit persons to whom the Software is furnished to do so, 11 | provided that the above copyright notice(s) and this permission notice appear in 12 | all copies of the Software and that both the above copyright notice(s) and this 13 | permission notice appear in supporting documentation. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT 18 | SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY 19 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 20 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 21 | CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 22 | WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23 | */ 24 | 25 | using System; 26 | using System.Security.Cryptography; 27 | 28 | namespace MLAPI.Cryptography.Math 29 | { 30 | /// 31 | /// This is a BigInteger class. Holds integer that is more than 64-bit (long). 32 | /// 33 | /// 34 | /// This class contains overloaded arithmetic operators(+, -, *, /, %), bitwise operators(&, |) and other 35 | /// operations that can be done with normal integer. It also contains implementation of various prime test. 36 | /// This class also contains methods dealing with cryptography such as generating prime number, generating 37 | /// a coprime number. 38 | /// 39 | public class BigInteger 40 | { 41 | // maximum length of the BigInteger in uint (4 bytes) 42 | // change this to suit the required level of precision. 43 | private const int MaxLength = 70; 44 | 45 | // primes smaller than 2000 to test the generated prime number 46 | public static readonly int[] PrimesBelow2000 = new int[] 47 | { 48 | 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 49 | 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 50 | 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 51 | 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 52 | 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 53 | 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 54 | 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 55 | 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 56 | 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 57 | 1069, 58 | 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 59 | 1217, 1223, 60 | 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 61 | 1367, 1373, 62 | 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 63 | 1499, 1511, 64 | 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 65 | 1637, 1657, 66 | 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 67 | 1801, 1811, 68 | 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 69 | 1979, 1987, 70 | 1993, 1997, 1999 71 | }; 72 | 73 | private uint[] _data = null; // stores bytes from the Big Integer 74 | public int DataLength; // number of actual chars used 75 | 76 | /// 77 | /// Default constructor for BigInteger of value 0 78 | /// 79 | public BigInteger() 80 | { 81 | _data = new uint[MaxLength]; 82 | DataLength = 1; 83 | } 84 | 85 | /// 86 | /// Constructor (Default value provided by long) 87 | /// 88 | /// Turn the long value into BigInteger type 89 | public BigInteger(long value) 90 | { 91 | _data = new uint[MaxLength]; 92 | long tempVal = value; 93 | 94 | // copy bytes from long to BigInteger without any assumption of 95 | // the length of the long datatype 96 | DataLength = 0; 97 | while (value != 0 && DataLength < MaxLength) 98 | { 99 | _data[DataLength] = (uint)(value & 0xFFFFFFFF); 100 | value >>= 32; 101 | DataLength++; 102 | } 103 | 104 | if (tempVal > 0) // overflow check for +ve value 105 | { 106 | if (value != 0 || (_data[MaxLength - 1] & 0x80000000) != 0) 107 | throw (new ArithmeticException("Positive overflow in constructor.")); 108 | } 109 | else if (tempVal < 0) // underflow check for -ve value 110 | { 111 | if (value != -1 || (_data[DataLength - 1] & 0x80000000) == 0) 112 | throw (new ArithmeticException("Negative underflow in constructor.")); 113 | } 114 | 115 | if (DataLength == 0) 116 | DataLength = 1; 117 | } 118 | 119 | /// 120 | /// Constructor (Default value provided by ulong) 121 | /// 122 | /// Turn the unsigned long value into BigInteger type 123 | public BigInteger(ulong value) 124 | { 125 | _data = new uint[MaxLength]; 126 | 127 | // copy bytes from ulong to BigInteger without any assumption of 128 | // the length of the ulong datatype 129 | DataLength = 0; 130 | while (value != 0 && DataLength < MaxLength) 131 | { 132 | _data[DataLength] = (uint)(value & 0xFFFFFFFF); 133 | value >>= 32; 134 | DataLength++; 135 | } 136 | 137 | if (value != 0 || (_data[MaxLength - 1] & 0x80000000) != 0) 138 | throw (new ArithmeticException("Positive overflow in constructor.")); 139 | 140 | if (DataLength == 0) 141 | DataLength = 1; 142 | } 143 | 144 | /// 145 | /// Constructor (Default value provided by BigInteger) 146 | /// 147 | /// 148 | public BigInteger(BigInteger bi) 149 | { 150 | _data = new uint[MaxLength]; 151 | 152 | DataLength = bi.DataLength; 153 | 154 | for (int i = 0; i < DataLength; i++) 155 | _data[i] = bi._data[i]; 156 | } 157 | 158 | /// 159 | /// Constructor (Default value provided by a string of digits of the specified base) 160 | /// 161 | /// 162 | /// To initialize "a" with the default value of 1234 in base 10: 163 | /// BigInteger a = new BigInteger("1234", 10) 164 | /// To initialize "a" with the default value of -0x1D4F in base 16: 165 | /// BigInteger a = new BigInteger("-1D4F", 16) 166 | /// 167 | /// 168 | /// String value in the format of [sign][magnitude] 169 | /// The base of value 170 | public BigInteger(string value, int radix = 10) 171 | { 172 | BigInteger multiplier = new BigInteger(1); 173 | BigInteger result = new BigInteger(); 174 | value = (value.ToUpper()).Trim(); 175 | int limit = 0; 176 | 177 | if (value[0] == '-') 178 | limit = 1; 179 | 180 | for (int i = value.Length - 1; i >= limit; i--) 181 | { 182 | int posVal = value[i]; 183 | 184 | if (posVal >= '0' && posVal <= '9') 185 | posVal -= '0'; 186 | else if (posVal >= 'A' && posVal <= 'Z') 187 | posVal = (posVal - 'A') + 10; 188 | else 189 | posVal = 9999999; // arbitrary large 190 | 191 | if (posVal >= radix) 192 | throw (new ArithmeticException("Invalid string in constructor.")); 193 | else 194 | { 195 | if (value[0] == '-') 196 | posVal = -posVal; 197 | 198 | result = result + (multiplier * posVal); 199 | 200 | if ((i - 1) >= limit) 201 | multiplier = multiplier * radix; 202 | } 203 | } 204 | 205 | if (value[0] == '-') // negative values 206 | { 207 | if ((result._data[MaxLength - 1] & 0x80000000) == 0) 208 | throw (new ArithmeticException("Negative underflow in constructor.")); 209 | } 210 | else // positive values 211 | { 212 | if ((result._data[MaxLength - 1] & 0x80000000) != 0) 213 | throw (new ArithmeticException("Positive overflow in constructor.")); 214 | } 215 | 216 | _data = new uint[MaxLength]; 217 | for (int i = 0; i < result.DataLength; i++) 218 | _data[i] = result._data[i]; 219 | 220 | DataLength = result.DataLength; 221 | } 222 | 223 | public BigInteger(byte[] inData) : this((System.Collections.Generic.IList)inData) 224 | { 225 | } 226 | 227 | /// 228 | /// Constructor (Default value provided by an array of bytes of the specified length.) 229 | /// 230 | /// A list of byte values 231 | /// Default -1 232 | /// Default 0 233 | public BigInteger(System.Collections.Generic.IList inData, int length = -1, int offset = 0) 234 | { 235 | int inLen = length == -1 ? inData.Count - offset : length; 236 | 237 | DataLength = inLen >> 2; 238 | 239 | int leftOver = inLen & 0x3; 240 | if (leftOver != 0) // length not multiples of 4 241 | DataLength++; 242 | 243 | if (DataLength > MaxLength || inLen > inData.Count - offset) 244 | throw (new ArithmeticException("Byte overflow in constructor.")); 245 | 246 | _data = new uint[MaxLength]; 247 | 248 | for (int i = inLen - 1, j = 0; i >= 3; i -= 4, j++) 249 | { 250 | _data[j] = (uint)((inData[offset + i - 3] << 24) + (inData[offset + i - 2] << 16) + 251 | (inData[offset + i - 1] << 8) + inData[offset + i]); 252 | } 253 | 254 | if (leftOver == 1) 255 | _data[DataLength - 1] = inData[offset + 0]; 256 | else if (leftOver == 2) 257 | _data[DataLength - 1] = (uint)((inData[offset + 0] << 8) + inData[offset + 1]); 258 | else if (leftOver == 3) 259 | _data[DataLength - 1] = 260 | (uint)((inData[offset + 0] << 16) + (inData[offset + 1] << 8) + inData[offset + 2]); 261 | 262 | if (DataLength == 0) 263 | DataLength = 1; 264 | 265 | while (DataLength > 1 && _data[DataLength - 1] == 0) 266 | DataLength--; 267 | } 268 | 269 | /// 270 | /// Constructor (Default value provided by an array of unsigned integers) 271 | /// 272 | /// Array of unsigned integer 273 | public BigInteger(uint[] inData) 274 | { 275 | DataLength = inData.Length; 276 | 277 | if (DataLength > MaxLength) 278 | throw (new ArithmeticException("Byte overflow in constructor.")); 279 | 280 | _data = new uint[MaxLength]; 281 | 282 | for (int i = DataLength - 1, j = 0; i >= 0; i--, j++) 283 | _data[j] = inData[i]; 284 | 285 | while (DataLength > 1 && _data[DataLength - 1] == 0) 286 | DataLength--; 287 | } 288 | 289 | /// 290 | /// Cast a type long value to type BigInteger value 291 | /// 292 | /// A long value 293 | public static implicit operator BigInteger(long value) 294 | { 295 | return (new BigInteger(value)); 296 | } 297 | 298 | /// 299 | /// Cast a type ulong value to type BigInteger value 300 | /// 301 | /// An unsigned long value 302 | public static implicit operator BigInteger(ulong value) 303 | { 304 | return (new BigInteger(value)); 305 | } 306 | 307 | /// 308 | /// Cast a type int value to type BigInteger value 309 | /// 310 | /// An int value 311 | public static implicit operator BigInteger(int value) 312 | { 313 | return (new BigInteger(value)); 314 | } 315 | 316 | /// 317 | /// Cast a type uint value to type BigInteger value 318 | /// 319 | /// An unsigned int value 320 | public static implicit operator BigInteger(uint value) 321 | { 322 | return (new BigInteger((ulong)value)); 323 | } 324 | 325 | /// 326 | /// Overloading of addition operator 327 | /// 328 | /// First BigInteger 329 | /// Second BigInteger 330 | /// Result of the addition of 2 BigIntegers 331 | public static BigInteger operator +(BigInteger bi1, BigInteger bi2) 332 | { 333 | BigInteger result = new BigInteger() 334 | { 335 | DataLength = (bi1.DataLength > bi2.DataLength) ? bi1.DataLength : bi2.DataLength 336 | }; 337 | 338 | long carry = 0; 339 | for (int i = 0; i < result.DataLength; i++) 340 | { 341 | long sum = bi1._data[i] + (long)bi2._data[i] + carry; 342 | carry = sum >> 32; 343 | result._data[i] = (uint)(sum & 0xFFFFFFFF); 344 | } 345 | 346 | if (carry != 0 && result.DataLength < MaxLength) 347 | { 348 | result._data[result.DataLength] = (uint)(carry); 349 | result.DataLength++; 350 | } 351 | 352 | while (result.DataLength > 1 && result._data[result.DataLength - 1] == 0) 353 | result.DataLength--; 354 | 355 | // overflow check 356 | int lastPos = MaxLength - 1; 357 | if ((bi1._data[lastPos] & 0x80000000) == (bi2._data[lastPos] & 0x80000000) && 358 | (result._data[lastPos] & 0x80000000) != (bi1._data[lastPos] & 0x80000000)) 359 | { 360 | throw (new ArithmeticException()); 361 | } 362 | 363 | return result; 364 | } 365 | 366 | /// 367 | /// Overloading of the unary ++ operator, which increments BigInteger by 1 368 | /// 369 | /// A BigInteger 370 | /// Incremented BigInteger 371 | public static BigInteger operator ++(BigInteger bi1) 372 | { 373 | BigInteger result = new BigInteger(bi1); 374 | 375 | long val, carry = 1; 376 | int index = 0; 377 | 378 | while (carry != 0 && index < MaxLength) 379 | { 380 | val = result._data[index]; 381 | val++; 382 | 383 | result._data[index] = (uint)(val & 0xFFFFFFFF); 384 | carry = val >> 32; 385 | 386 | index++; 387 | } 388 | 389 | if (index > result.DataLength) 390 | result.DataLength = index; 391 | else 392 | { 393 | while (result.DataLength > 1 && result._data[result.DataLength - 1] == 0) 394 | result.DataLength--; 395 | } 396 | 397 | // overflow check 398 | int lastPos = MaxLength - 1; 399 | 400 | // overflow if initial value was +ve but ++ caused a sign 401 | // change to negative. 402 | 403 | if ((bi1._data[lastPos] & 0x80000000) == 0 && 404 | (result._data[lastPos] & 0x80000000) != (bi1._data[lastPos] & 0x80000000)) 405 | { 406 | throw (new ArithmeticException("Overflow in ++.")); 407 | } 408 | 409 | return result; 410 | } 411 | 412 | /// 413 | /// Overloading of subtraction operator 414 | /// 415 | /// First BigInteger 416 | /// Second BigInteger 417 | /// Result of the subtraction of 2 BigIntegers 418 | public static BigInteger operator -(BigInteger bi1, BigInteger bi2) 419 | { 420 | BigInteger result = new BigInteger() 421 | { 422 | DataLength = (bi1.DataLength > bi2.DataLength) ? bi1.DataLength : bi2.DataLength 423 | }; 424 | 425 | long carryIn = 0; 426 | for (int i = 0; i < result.DataLength; i++) 427 | { 428 | long diff; 429 | 430 | diff = bi1._data[i] - (long)bi2._data[i] - carryIn; 431 | result._data[i] = (uint)(diff & 0xFFFFFFFF); 432 | 433 | if (diff < 0) 434 | carryIn = 1; 435 | else 436 | carryIn = 0; 437 | } 438 | 439 | // roll over to negative 440 | if (carryIn != 0) 441 | { 442 | for (int i = result.DataLength; i < MaxLength; i++) 443 | result._data[i] = 0xFFFFFFFF; 444 | result.DataLength = MaxLength; 445 | } 446 | 447 | // fixed in v1.03 to give correct datalength for a - (-b) 448 | while (result.DataLength > 1 && result._data[result.DataLength - 1] == 0) 449 | result.DataLength--; 450 | 451 | // overflow check 452 | 453 | int lastPos = MaxLength - 1; 454 | if ((bi1._data[lastPos] & 0x80000000) != (bi2._data[lastPos] & 0x80000000) && 455 | (result._data[lastPos] & 0x80000000) != (bi1._data[lastPos] & 0x80000000)) 456 | { 457 | throw (new ArithmeticException()); 458 | } 459 | 460 | return result; 461 | } 462 | 463 | /// 464 | /// Overloading of the unary -- operator, decrements BigInteger by 1 465 | /// 466 | /// A BigInteger 467 | /// Decremented BigInteger 468 | public static BigInteger operator --(BigInteger bi1) 469 | { 470 | BigInteger result = new BigInteger(bi1); 471 | 472 | long val; 473 | bool carryIn = true; 474 | int index = 0; 475 | 476 | while (carryIn && index < MaxLength) 477 | { 478 | val = result._data[index]; 479 | val--; 480 | 481 | result._data[index] = (uint)(val & 0xFFFFFFFF); 482 | 483 | if (val >= 0) 484 | carryIn = false; 485 | 486 | index++; 487 | } 488 | 489 | if (index > result.DataLength) 490 | result.DataLength = index; 491 | 492 | while (result.DataLength > 1 && result._data[result.DataLength - 1] == 0) 493 | result.DataLength--; 494 | 495 | // overflow check 496 | int lastPos = MaxLength - 1; 497 | 498 | // overflow if initial value was -ve but -- caused a sign 499 | // change to positive. 500 | 501 | if ((bi1._data[lastPos] & 0x80000000) != 0 && 502 | (result._data[lastPos] & 0x80000000) != (bi1._data[lastPos] & 0x80000000)) 503 | { 504 | throw (new ArithmeticException("Underflow in --.")); 505 | } 506 | 507 | return result; 508 | } 509 | 510 | /// 511 | /// Overloading of multiplication operator 512 | /// 513 | /// First BigInteger 514 | /// Second BigInteger 515 | /// Result of the multiplication of 2 BigIntegers 516 | public static BigInteger operator *(BigInteger bi1, BigInteger bi2) 517 | { 518 | int lastPos = MaxLength - 1; 519 | bool bi1Neg = false, bi2Neg = false; 520 | 521 | // take the absolute value of the inputs 522 | try 523 | { 524 | if ((bi1._data[lastPos] & 0x80000000) != 0) // bi1 negative 525 | { 526 | bi1Neg = true; 527 | bi1 = -bi1; 528 | } 529 | 530 | if ((bi2._data[lastPos] & 0x80000000) != 0) // bi2 negative 531 | { 532 | bi2Neg = true; 533 | bi2 = -bi2; 534 | } 535 | } 536 | catch (Exception) 537 | { 538 | } 539 | 540 | BigInteger result = new BigInteger(); 541 | 542 | // multiply the absolute values 543 | try 544 | { 545 | for (int i = 0; i < bi1.DataLength; i++) 546 | { 547 | if (bi1._data[i] == 0) continue; 548 | 549 | ulong mcarry = 0; 550 | for (int j = 0, k = i; j < bi2.DataLength; j++, k++) 551 | { 552 | // k = i + j 553 | ulong val = (bi1._data[i] * (ulong)bi2._data[j]) + 554 | result._data[k] + mcarry; 555 | 556 | result._data[k] = (uint)(val & 0xFFFFFFFF); 557 | mcarry = (val >> 32); 558 | } 559 | 560 | if (mcarry != 0) 561 | result._data[i + bi2.DataLength] = (uint)mcarry; 562 | } 563 | } 564 | catch (Exception) 565 | { 566 | throw (new ArithmeticException("Multiplication overflow.")); 567 | } 568 | 569 | result.DataLength = bi1.DataLength + bi2.DataLength; 570 | if (result.DataLength > MaxLength) 571 | result.DataLength = MaxLength; 572 | 573 | while (result.DataLength > 1 && result._data[result.DataLength - 1] == 0) 574 | result.DataLength--; 575 | 576 | // overflow check (result is -ve) 577 | if ((result._data[lastPos] & 0x80000000) != 0) 578 | { 579 | if (bi1Neg != bi2Neg && result._data[lastPos] == 0x80000000) // different sign 580 | { 581 | // handle the special case where multiplication produces 582 | // a max negative number in 2's complement. 583 | 584 | if (result.DataLength == 1) 585 | return result; 586 | else 587 | { 588 | bool isMaxNeg = true; 589 | for (int i = 0; i < result.DataLength - 1 && isMaxNeg; i++) 590 | { 591 | if (result._data[i] != 0) 592 | isMaxNeg = false; 593 | } 594 | 595 | if (isMaxNeg) 596 | return result; 597 | } 598 | } 599 | 600 | throw (new ArithmeticException("Multiplication overflow.")); 601 | } 602 | 603 | // if input has different signs, then result is -ve 604 | if (bi1Neg != bi2Neg) 605 | return -result; 606 | 607 | return result; 608 | } 609 | 610 | /// 611 | /// Overloading of the unary << operator (left shift) 612 | /// 613 | /// 614 | /// Shifting by a negative number is an undefined behaviour (UB). 615 | /// 616 | /// A BigInteger 617 | /// Left shift by shiftVal bit 618 | /// Left-shifted BigInteger 619 | public static BigInteger operator <<(BigInteger bi1, int shiftVal) 620 | { 621 | BigInteger result = new BigInteger(bi1); 622 | result.DataLength = ShiftLeft(result._data, shiftVal); 623 | 624 | return result; 625 | } 626 | 627 | // least significant bits at lower part of buffer 628 | private static int ShiftLeft(uint[] buffer, int shiftVal) 629 | { 630 | int shiftAmount = 32; 631 | int bufLen = buffer.Length; 632 | 633 | while (bufLen > 1 && buffer[bufLen - 1] == 0) 634 | bufLen--; 635 | 636 | for (int count = shiftVal; count > 0;) 637 | { 638 | if (count < shiftAmount) 639 | shiftAmount = count; 640 | 641 | ulong carry = 0; 642 | for (int i = 0; i < bufLen; i++) 643 | { 644 | ulong val = ((ulong)buffer[i]) << shiftAmount; 645 | val |= carry; 646 | 647 | buffer[i] = (uint)(val & 0xFFFFFFFF); 648 | carry = val >> 32; 649 | } 650 | 651 | if (carry != 0) 652 | { 653 | if (bufLen + 1 <= buffer.Length) 654 | { 655 | buffer[bufLen] = (uint)carry; 656 | bufLen++; 657 | } 658 | } 659 | 660 | count -= shiftAmount; 661 | } 662 | 663 | return bufLen; 664 | } 665 | 666 | /// 667 | /// Overloading of the unary >> operator (right shift) 668 | /// 669 | /// 670 | /// Shifting by a negative number is an undefined behaviour (UB). 671 | /// 672 | /// A BigInteger 673 | /// Right shift by shiftVal bit 674 | /// Right-shifted BigInteger 675 | public static BigInteger operator >>(BigInteger bi1, int shiftVal) 676 | { 677 | BigInteger result = new BigInteger(bi1); 678 | result.DataLength = ShiftRight(result._data, shiftVal); 679 | 680 | if ((bi1._data[MaxLength - 1] & 0x80000000) != 0) // negative 681 | { 682 | for (int i = MaxLength - 1; i >= result.DataLength; i--) 683 | result._data[i] = 0xFFFFFFFF; 684 | 685 | uint mask = 0x80000000; 686 | for (int i = 0; i < 32; i++) 687 | { 688 | if ((result._data[result.DataLength - 1] & mask) != 0) 689 | break; 690 | 691 | result._data[result.DataLength - 1] |= mask; 692 | mask >>= 1; 693 | } 694 | 695 | result.DataLength = MaxLength; 696 | } 697 | 698 | return result; 699 | } 700 | 701 | private static int ShiftRight(uint[] buffer, int shiftVal) 702 | { 703 | int shiftAmount = 32; 704 | int invShift = 0; 705 | int bufLen = buffer.Length; 706 | 707 | while (bufLen > 1 && buffer[bufLen - 1] == 0) 708 | bufLen--; 709 | 710 | for (int count = shiftVal; count > 0;) 711 | { 712 | if (count < shiftAmount) 713 | { 714 | shiftAmount = count; 715 | invShift = 32 - shiftAmount; 716 | } 717 | 718 | ulong carry = 0; 719 | for (int i = bufLen - 1; i >= 0; i--) 720 | { 721 | ulong val = ((ulong)buffer[i]) >> shiftAmount; 722 | val |= carry; 723 | 724 | carry = (((ulong)buffer[i]) << invShift) & 0xFFFFFFFF; 725 | buffer[i] = (uint)(val); 726 | } 727 | 728 | count -= shiftAmount; 729 | } 730 | 731 | while (bufLen > 1 && buffer[bufLen - 1] == 0) 732 | bufLen--; 733 | 734 | return bufLen; 735 | } 736 | 737 | /// 738 | /// Overloading of the bit-wise NOT operator (1's complement) 739 | /// 740 | /// A BigInteger 741 | /// Complemented BigInteger 742 | public static BigInteger operator ~(BigInteger bi1) 743 | { 744 | BigInteger result = new BigInteger(bi1); 745 | 746 | for (int i = 0; i < MaxLength; i++) 747 | result._data[i] = ~(bi1._data[i]); 748 | 749 | result.DataLength = MaxLength; 750 | 751 | while (result.DataLength > 1 && result._data[result.DataLength - 1] == 0) 752 | result.DataLength--; 753 | 754 | return result; 755 | } 756 | 757 | /// 758 | /// Overloading of the NEGATE operator (2's complement) 759 | /// 760 | /// A BigInteger 761 | /// Negated BigInteger or default BigInteger value if bi1 is 0 762 | public static BigInteger operator -(BigInteger bi1) 763 | { 764 | // handle neg of zero separately since it'll cause an overflow 765 | // if we proceed. 766 | 767 | if (bi1.DataLength == 1 && bi1._data[0] == 0) 768 | return (new BigInteger()); 769 | 770 | BigInteger result = new BigInteger(bi1); 771 | 772 | // 1's complement 773 | for (int i = 0; i < MaxLength; i++) 774 | result._data[i] = ~(bi1._data[i]); 775 | 776 | // add one to result of 1's complement 777 | long val, carry = 1; 778 | int index = 0; 779 | 780 | while (carry != 0 && index < MaxLength) 781 | { 782 | val = result._data[index]; 783 | val++; 784 | 785 | result._data[index] = (uint)(val & 0xFFFFFFFF); 786 | carry = val >> 32; 787 | 788 | index++; 789 | } 790 | 791 | if ((bi1._data[MaxLength - 1] & 0x80000000) == (result._data[MaxLength - 1] & 0x80000000)) 792 | throw (new ArithmeticException("Overflow in negation.\n")); 793 | 794 | result.DataLength = MaxLength; 795 | 796 | while (result.DataLength > 1 && result._data[result.DataLength - 1] == 0) 797 | result.DataLength--; 798 | return result; 799 | } 800 | 801 | /// 802 | /// Overloading of equality operator, allows comparing 2 BigIntegers with == operator 803 | /// 804 | /// First BigInteger 805 | /// Second BigInteger 806 | /// Boolean result of the comparison 807 | public static bool operator ==(BigInteger bi1, BigInteger bi2) 808 | { 809 | return object.ReferenceEquals(bi1, bi2) || bi1.Equals(bi2); 810 | } 811 | 812 | /// 813 | /// Overloading of not equal operator, allows comparing 2 BigIntegers with != operator 814 | /// 815 | /// First BigInteger 816 | /// Second BigInteger 817 | /// Boolean result of the comparison 818 | public static bool operator !=(BigInteger bi1, BigInteger bi2) 819 | { 820 | return !object.ReferenceEquals(bi1, bi2) && !(bi1.Equals(bi2)); 821 | } 822 | 823 | /// 824 | /// Overriding of Equals method, allows comparing BigInteger with an arbitary object 825 | /// 826 | /// Input object, to be casted into BigInteger type for comparison 827 | /// Boolean result of the comparison 828 | public override bool Equals(object o) 829 | { 830 | if (object.ReferenceEquals(null, o)) 831 | { 832 | return false; 833 | } 834 | 835 | BigInteger bi = (BigInteger)o; 836 | 837 | 838 | 839 | if (this.DataLength != bi.DataLength) 840 | return false; 841 | 842 | for (int i = 0; i < this.DataLength; i++) 843 | { 844 | if (this._data[i] != bi._data[i]) 845 | return false; 846 | } 847 | 848 | return true; 849 | } 850 | 851 | public override int GetHashCode() 852 | { 853 | return this.ToString().GetHashCode(); 854 | } 855 | 856 | /// 857 | /// Overloading of greater than operator, allows comparing 2 BigIntegers with > operator 858 | /// 859 | /// First BigInteger 860 | /// Second BigInteger 861 | /// Boolean result of the comparison 862 | public static bool operator >(BigInteger bi1, BigInteger bi2) 863 | { 864 | int pos = MaxLength - 1; 865 | 866 | // bi1 is negative, bi2 is positive 867 | if ((bi1._data[pos] & 0x80000000) != 0 && (bi2._data[pos] & 0x80000000) == 0) 868 | return false; 869 | 870 | // bi1 is positive, bi2 is negative 871 | else if ((bi1._data[pos] & 0x80000000) == 0 && (bi2._data[pos] & 0x80000000) != 0) 872 | return true; 873 | 874 | // same sign 875 | int len = (bi1.DataLength > bi2.DataLength) ? bi1.DataLength : bi2.DataLength; 876 | for (pos = len - 1; pos >= 0 && bi1._data[pos] == bi2._data[pos]; pos--) ; 877 | 878 | if (pos >= 0) 879 | { 880 | if (bi1._data[pos] > bi2._data[pos]) 881 | return true; 882 | return false; 883 | } 884 | 885 | return false; 886 | } 887 | 888 | /// 889 | /// Overloading of greater than operator, allows comparing 2 BigIntegers with < operator 890 | /// 891 | /// First BigInteger 892 | /// Second BigInteger 893 | /// Boolean result of the comparison 894 | public static bool operator <(BigInteger bi1, BigInteger bi2) 895 | { 896 | int pos = MaxLength - 1; 897 | 898 | // bi1 is negative, bi2 is positive 899 | if ((bi1._data[pos] & 0x80000000) != 0 && (bi2._data[pos] & 0x80000000) == 0) 900 | return true; 901 | 902 | // bi1 is positive, bi2 is negative 903 | else if ((bi1._data[pos] & 0x80000000) == 0 && (bi2._data[pos] & 0x80000000) != 0) 904 | return false; 905 | 906 | // same sign 907 | int len = (bi1.DataLength > bi2.DataLength) ? bi1.DataLength : bi2.DataLength; 908 | for (pos = len - 1; pos >= 0 && bi1._data[pos] == bi2._data[pos]; pos--) ; 909 | 910 | if (pos >= 0) 911 | { 912 | if (bi1._data[pos] < bi2._data[pos]) 913 | return true; 914 | return false; 915 | } 916 | 917 | return false; 918 | } 919 | 920 | /// 921 | /// Overloading of greater than or equal to operator, allows comparing 2 BigIntegers with >= operator 922 | /// 923 | /// First BigInteger 924 | /// Second BigInteger 925 | /// Boolean result of the comparison 926 | public static bool operator >=(BigInteger bi1, BigInteger bi2) 927 | { 928 | return (bi1 == bi2 || bi1 > bi2); 929 | } 930 | 931 | /// 932 | /// Overloading of less than or equal to operator, allows comparing 2 BigIntegers with <= operator 933 | /// 934 | /// First BigInteger 935 | /// Second BigInteger 936 | /// Boolean result of the comparison 937 | public static bool operator <=(BigInteger bi1, BigInteger bi2) 938 | { 939 | return (bi1 == bi2 || bi1 < bi2); 940 | } 941 | 942 | //*********************************************************************** 943 | // Private function that supports the division of two numbers with 944 | // a divisor that has more than 1 digit. 945 | // 946 | // Algorithm taken from [1] 947 | //*********************************************************************** 948 | private static void MultiByteDivide(BigInteger bi1, BigInteger bi2, BigInteger outQuotient, BigInteger outRemainder) 949 | { 950 | uint[] result = new uint[MaxLength]; 951 | 952 | int remainderLen = bi1.DataLength + 1; 953 | uint[] remainder = new uint[remainderLen]; 954 | 955 | uint mask = 0x80000000; 956 | uint val = bi2._data[bi2.DataLength - 1]; 957 | int shift = 0, resultPos = 0; 958 | 959 | while (mask != 0 && (val & mask) == 0) 960 | { 961 | shift++; 962 | mask >>= 1; 963 | } 964 | 965 | for (int i = 0; i < bi1.DataLength; i++) 966 | remainder[i] = bi1._data[i]; 967 | ShiftLeft(remainder, shift); 968 | bi2 = bi2 << shift; 969 | 970 | int j = remainderLen - bi2.DataLength; 971 | int pos = remainderLen - 1; 972 | 973 | ulong firstDivisorByte = bi2._data[bi2.DataLength - 1]; 974 | ulong secondDivisorByte = bi2._data[bi2.DataLength - 2]; 975 | 976 | int divisorLen = bi2.DataLength + 1; 977 | uint[] dividendPart = new uint[divisorLen]; 978 | 979 | while (j > 0) 980 | { 981 | ulong dividend = ((ulong)remainder[pos] << 32) + remainder[pos - 1]; 982 | 983 | ulong qHat = dividend / firstDivisorByte; 984 | ulong rHat = dividend % firstDivisorByte; 985 | 986 | bool done = false; 987 | while (!done) 988 | { 989 | done = true; 990 | 991 | if (qHat == 0x100000000 || 992 | (qHat * secondDivisorByte) > ((rHat << 32) + remainder[pos - 2])) 993 | { 994 | qHat--; 995 | rHat += firstDivisorByte; 996 | 997 | if (rHat < 0x100000000) 998 | done = false; 999 | } 1000 | } 1001 | 1002 | for (int h = 0; h < divisorLen; h++) 1003 | dividendPart[h] = remainder[pos - h]; 1004 | 1005 | BigInteger kk = new BigInteger(dividendPart); 1006 | BigInteger ss = bi2 * (long)qHat; 1007 | 1008 | while (ss > kk) 1009 | { 1010 | qHat--; 1011 | ss -= bi2; 1012 | } 1013 | 1014 | BigInteger yy = kk - ss; 1015 | 1016 | for (int h = 0; h < divisorLen; h++) 1017 | remainder[pos - h] = yy._data[bi2.DataLength - h]; 1018 | 1019 | result[resultPos++] = (uint)qHat; 1020 | 1021 | pos--; 1022 | j--; 1023 | } 1024 | 1025 | outQuotient.DataLength = resultPos; 1026 | int y = 0; 1027 | for (int x = outQuotient.DataLength - 1; x >= 0; x--, y++) 1028 | outQuotient._data[y] = result[x]; 1029 | for (; y < MaxLength; y++) 1030 | outQuotient._data[y] = 0; 1031 | 1032 | while (outQuotient.DataLength > 1 && outQuotient._data[outQuotient.DataLength - 1] == 0) 1033 | outQuotient.DataLength--; 1034 | 1035 | if (outQuotient.DataLength == 0) 1036 | outQuotient.DataLength = 1; 1037 | 1038 | outRemainder.DataLength = ShiftRight(remainder, shift); 1039 | 1040 | for (y = 0; y < outRemainder.DataLength; y++) 1041 | outRemainder._data[y] = remainder[y]; 1042 | for (; y < MaxLength; y++) 1043 | outRemainder._data[y] = 0; 1044 | } 1045 | 1046 | //*********************************************************************** 1047 | // Private function that supports the division of two numbers with 1048 | // a divisor that has only 1 digit. 1049 | //*********************************************************************** 1050 | private static void SingleByteDivide(BigInteger bi1, BigInteger bi2, BigInteger outQuotient, BigInteger outRemainder) 1051 | { 1052 | uint[] result = new uint[MaxLength]; 1053 | int resultPos = 0; 1054 | 1055 | // copy dividend to reminder 1056 | for (int i = 0; i < MaxLength; i++) 1057 | outRemainder._data[i] = bi1._data[i]; 1058 | outRemainder.DataLength = bi1.DataLength; 1059 | 1060 | while (outRemainder.DataLength > 1 && outRemainder._data[outRemainder.DataLength - 1] == 0) 1061 | outRemainder.DataLength--; 1062 | 1063 | ulong divisor = bi2._data[0]; 1064 | int pos = outRemainder.DataLength - 1; 1065 | ulong dividend = outRemainder._data[pos]; 1066 | 1067 | if (dividend >= divisor) 1068 | { 1069 | ulong quotient = dividend / divisor; 1070 | result[resultPos++] = (uint)quotient; 1071 | 1072 | outRemainder._data[pos] = (uint)(dividend % divisor); 1073 | } 1074 | 1075 | pos--; 1076 | 1077 | while (pos >= 0) 1078 | { 1079 | dividend = ((ulong)outRemainder._data[pos + 1] << 32) + outRemainder._data[pos]; 1080 | ulong quotient = dividend / divisor; 1081 | result[resultPos++] = (uint)quotient; 1082 | 1083 | outRemainder._data[pos + 1] = 0; 1084 | outRemainder._data[pos--] = (uint)(dividend % divisor); 1085 | } 1086 | 1087 | outQuotient.DataLength = resultPos; 1088 | int j = 0; 1089 | for (int i = outQuotient.DataLength - 1; i >= 0; i--, j++) 1090 | outQuotient._data[j] = result[i]; 1091 | for (; j < MaxLength; j++) 1092 | outQuotient._data[j] = 0; 1093 | 1094 | while (outQuotient.DataLength > 1 && outQuotient._data[outQuotient.DataLength - 1] == 0) 1095 | outQuotient.DataLength--; 1096 | 1097 | if (outQuotient.DataLength == 0) 1098 | outQuotient.DataLength = 1; 1099 | 1100 | while (outRemainder.DataLength > 1 && outRemainder._data[outRemainder.DataLength - 1] == 0) 1101 | outRemainder.DataLength--; 1102 | } 1103 | 1104 | /// 1105 | /// Overloading of division operator 1106 | /// 1107 | /// The dataLength of the divisor's absolute value must be less than maxLength 1108 | /// Dividend 1109 | /// Divisor 1110 | /// Quotient of the division 1111 | public static BigInteger operator /(BigInteger bi1, BigInteger bi2) 1112 | { 1113 | BigInteger quotient = new BigInteger(); 1114 | BigInteger remainder = new BigInteger(); 1115 | 1116 | int lastPos = MaxLength - 1; 1117 | bool divisorNeg = false, dividendNeg = false; 1118 | 1119 | if ((bi1._data[lastPos] & 0x80000000) != 0) // bi1 negative 1120 | { 1121 | bi1 = -bi1; 1122 | dividendNeg = true; 1123 | } 1124 | 1125 | if ((bi2._data[lastPos] & 0x80000000) != 0) // bi2 negative 1126 | { 1127 | bi2 = -bi2; 1128 | divisorNeg = true; 1129 | } 1130 | 1131 | if (bi1 < bi2) 1132 | { 1133 | return quotient; 1134 | } 1135 | else 1136 | { 1137 | if (bi2.DataLength == 1) 1138 | SingleByteDivide(bi1, bi2, quotient, remainder); 1139 | else 1140 | MultiByteDivide(bi1, bi2, quotient, remainder); 1141 | 1142 | if (dividendNeg != divisorNeg) 1143 | return -quotient; 1144 | 1145 | return quotient; 1146 | } 1147 | } 1148 | 1149 | /// 1150 | /// Overloading of modulus operator 1151 | /// 1152 | /// The dataLength of the divisor's absolute value must be less than maxLength 1153 | /// Dividend 1154 | /// Divisor 1155 | /// Remainder of the division 1156 | public static BigInteger operator %(BigInteger bi1, BigInteger bi2) 1157 | { 1158 | BigInteger quotient = new BigInteger(); 1159 | BigInteger remainder = new BigInteger(bi1); 1160 | 1161 | int lastPos = MaxLength - 1; 1162 | bool dividendNeg = false; 1163 | 1164 | if ((bi1._data[lastPos] & 0x80000000) != 0) // bi1 negative 1165 | { 1166 | bi1 = -bi1; 1167 | dividendNeg = true; 1168 | } 1169 | 1170 | if ((bi2._data[lastPos] & 0x80000000) != 0) // bi2 negative 1171 | bi2 = -bi2; 1172 | 1173 | if (bi1 < bi2) 1174 | { 1175 | return remainder; 1176 | } 1177 | else 1178 | { 1179 | if (bi2.DataLength == 1) 1180 | SingleByteDivide(bi1, bi2, quotient, remainder); 1181 | else 1182 | MultiByteDivide(bi1, bi2, quotient, remainder); 1183 | 1184 | if (dividendNeg) 1185 | return -remainder; 1186 | 1187 | return remainder; 1188 | } 1189 | } 1190 | 1191 | /// 1192 | /// Overloading of bitwise AND operator 1193 | /// 1194 | /// First BigInteger 1195 | /// Second BigInteger 1196 | /// BigInteger result after performing & operation 1197 | public static BigInteger operator &(BigInteger bi1, BigInteger bi2) 1198 | { 1199 | BigInteger result = new BigInteger(); 1200 | 1201 | int len = (bi1.DataLength > bi2.DataLength) ? bi1.DataLength : bi2.DataLength; 1202 | 1203 | for (int i = 0; i < len; i++) 1204 | { 1205 | uint sum = bi1._data[i] & bi2._data[i]; 1206 | result._data[i] = sum; 1207 | } 1208 | 1209 | result.DataLength = MaxLength; 1210 | 1211 | while (result.DataLength > 1 && result._data[result.DataLength - 1] == 0) 1212 | result.DataLength--; 1213 | 1214 | return result; 1215 | } 1216 | 1217 | /// 1218 | /// Overloading of bitwise OR operator 1219 | /// 1220 | /// First BigInteger 1221 | /// Second BigInteger 1222 | /// BigInteger result after performing | operation 1223 | public static BigInteger operator |(BigInteger bi1, BigInteger bi2) 1224 | { 1225 | BigInteger result = new BigInteger(); 1226 | 1227 | int len = (bi1.DataLength > bi2.DataLength) ? bi1.DataLength : bi2.DataLength; 1228 | 1229 | for (int i = 0; i < len; i++) 1230 | { 1231 | uint sum = bi1._data[i] | bi2._data[i]; 1232 | result._data[i] = sum; 1233 | } 1234 | 1235 | result.DataLength = MaxLength; 1236 | 1237 | while (result.DataLength > 1 && result._data[result.DataLength - 1] == 0) 1238 | result.DataLength--; 1239 | 1240 | return result; 1241 | } 1242 | 1243 | /// 1244 | /// Overloading of bitwise XOR operator 1245 | /// 1246 | /// First BigInteger 1247 | /// Second BigInteger 1248 | /// BigInteger result after performing ^ operation 1249 | public static BigInteger operator ^(BigInteger bi1, BigInteger bi2) 1250 | { 1251 | BigInteger result = new BigInteger(); 1252 | 1253 | int len = (bi1.DataLength > bi2.DataLength) ? bi1.DataLength : bi2.DataLength; 1254 | 1255 | for (int i = 0; i < len; i++) 1256 | { 1257 | uint sum = bi1._data[i] ^ bi2._data[i]; 1258 | result._data[i] = sum; 1259 | } 1260 | 1261 | result.DataLength = MaxLength; 1262 | 1263 | while (result.DataLength > 1 && result._data[result.DataLength - 1] == 0) 1264 | result.DataLength--; 1265 | 1266 | return result; 1267 | } 1268 | 1269 | /// 1270 | /// Compare this and a BigInteger and find the maximum one 1271 | /// 1272 | /// BigInteger to be compared with this 1273 | /// The bigger value of this and bi 1274 | public BigInteger Max(BigInteger bi) 1275 | { 1276 | if (this > bi) 1277 | return (new BigInteger(this)); 1278 | else 1279 | return (new BigInteger(bi)); 1280 | } 1281 | 1282 | /// 1283 | /// Compare this and a BigInteger and find the minimum one 1284 | /// 1285 | /// BigInteger to be compared with this 1286 | /// The smaller value of this and bi 1287 | public BigInteger Min(BigInteger bi) 1288 | { 1289 | if (this < bi) 1290 | return (new BigInteger(this)); 1291 | else 1292 | return (new BigInteger(bi)); 1293 | } 1294 | 1295 | /// 1296 | /// Returns the absolute value 1297 | /// 1298 | /// Absolute value of this 1299 | public BigInteger Abs() 1300 | { 1301 | if ((this._data[MaxLength - 1] & 0x80000000) != 0) 1302 | return (-this); 1303 | else 1304 | return (new BigInteger(this)); 1305 | } 1306 | 1307 | /// 1308 | /// Returns a string representing the BigInteger in base 10 1309 | /// 1310 | /// string representation of the BigInteger 1311 | public override string ToString() 1312 | { 1313 | return ToString(10); 1314 | } 1315 | 1316 | /// 1317 | /// Returns a string representing the BigInteger in [sign][magnitude] format in the specified radix 1318 | /// 1319 | /// If the value of BigInteger is -255 in base 10, then ToString(16) returns "-FF" 1320 | /// Base 1321 | /// string representation of the BigInteger in [sign][magnitude] format 1322 | public string ToString(int radix) 1323 | { 1324 | if (radix < 2 || radix > 36) 1325 | throw (new ArgumentException("Radix must be >= 2 and <= 36")); 1326 | 1327 | string charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 1328 | string result = ""; 1329 | 1330 | BigInteger a = this; 1331 | 1332 | bool negative = false; 1333 | if ((a._data[MaxLength - 1] & 0x80000000) != 0) 1334 | { 1335 | negative = true; 1336 | try 1337 | { 1338 | a = -a; 1339 | } 1340 | catch (Exception) 1341 | { 1342 | } 1343 | } 1344 | 1345 | BigInteger quotient = new BigInteger(); 1346 | BigInteger remainder = new BigInteger(); 1347 | BigInteger biRadix = new BigInteger(radix); 1348 | 1349 | if (a.DataLength == 1 && a._data[0] == 0) 1350 | result = "0"; 1351 | else 1352 | { 1353 | while (a.DataLength > 1 || (a.DataLength == 1 && a._data[0] != 0)) 1354 | { 1355 | SingleByteDivide(a, biRadix, quotient, remainder); 1356 | 1357 | if (remainder._data[0] < 10) 1358 | result = remainder._data[0] + result; 1359 | else 1360 | result = charSet[(int)remainder._data[0] - 10] + result; 1361 | 1362 | a = quotient; 1363 | } 1364 | 1365 | if (negative) 1366 | result = "-" + result; 1367 | } 1368 | 1369 | return result; 1370 | } 1371 | 1372 | /// 1373 | /// Returns a hex string showing the contains of the BigInteger 1374 | /// 1375 | /// 1376 | /// 1) If the value of BigInteger is 255 in base 10, then ToHexString() returns "FF" 1377 | /// 2) If the value of BigInteger is -255 in base 10, thenToHexString() returns ".....FFFFFFFFFF01", which is the 2's complement representation of -255. 1378 | /// 1379 | /// 1380 | public string ToHexString() 1381 | { 1382 | string result = _data[DataLength - 1].ToString("X"); 1383 | 1384 | for (int i = DataLength - 2; i >= 0; i--) 1385 | { 1386 | result += _data[i].ToString("X8"); 1387 | } 1388 | 1389 | return result; 1390 | } 1391 | 1392 | /// 1393 | /// Modulo Exponentiation 1394 | /// 1395 | /// Exponential 1396 | /// Modulo 1397 | /// BigInteger result of raising this to the power of exp and then modulo n 1398 | public BigInteger ModPow(BigInteger exp, BigInteger n) 1399 | { 1400 | if ((exp._data[MaxLength - 1] & 0x80000000) != 0) 1401 | throw (new ArithmeticException("Positive exponents only.")); 1402 | 1403 | BigInteger resultNum = 1; 1404 | BigInteger tempNum; 1405 | bool thisNegative = false; 1406 | 1407 | if ((this._data[MaxLength - 1] & 0x80000000) != 0) // negative this 1408 | { 1409 | tempNum = -this % n; 1410 | thisNegative = true; 1411 | } 1412 | else 1413 | tempNum = this % n; // ensures (tempNum * tempNum) < b^(2k) 1414 | 1415 | if ((n._data[MaxLength - 1] & 0x80000000) != 0) // negative n 1416 | n = -n; 1417 | 1418 | // calculate constant = b^(2k) / m 1419 | BigInteger constant = new BigInteger(); 1420 | 1421 | int i = n.DataLength << 1; 1422 | constant._data[i] = 0x00000001; 1423 | constant.DataLength = i + 1; 1424 | 1425 | constant = constant / n; 1426 | int totalBits = exp.BitCount(); 1427 | int count = 0; 1428 | 1429 | // perform squaring and multiply exponentiation 1430 | for (int pos = 0; pos < exp.DataLength; pos++) 1431 | { 1432 | uint mask = 0x01; 1433 | 1434 | for (int index = 0; index < 32; index++) 1435 | { 1436 | if ((exp._data[pos] & mask) != 0) 1437 | resultNum = BarrettReduction(resultNum * tempNum, n, constant); 1438 | 1439 | mask <<= 1; 1440 | 1441 | tempNum = BarrettReduction(tempNum * tempNum, n, constant); 1442 | 1443 | if (tempNum.DataLength == 1 && tempNum._data[0] == 1) 1444 | { 1445 | if (thisNegative && (exp._data[0] & 0x1) != 0) //odd exp 1446 | return -resultNum; 1447 | return resultNum; 1448 | } 1449 | 1450 | count++; 1451 | if (count == totalBits) 1452 | break; 1453 | } 1454 | } 1455 | 1456 | if (thisNegative && (exp._data[0] & 0x1) != 0) //odd exp 1457 | return -resultNum; 1458 | 1459 | return resultNum; 1460 | } 1461 | 1462 | /// 1463 | /// Fast calculation of modular reduction using Barrett's reduction 1464 | /// 1465 | /// 1466 | /// Requires x < b^(2k), where b is the base. In this case, base is 2^32 (uint). 1467 | /// 1468 | /// Reference [4] 1469 | /// 1470 | /// 1471 | /// 1472 | /// 1473 | /// 1474 | private BigInteger BarrettReduction(BigInteger x, BigInteger n, BigInteger constant) 1475 | { 1476 | int k = n.DataLength, 1477 | kPlusOne = k + 1, 1478 | kMinusOne = k - 1; 1479 | 1480 | BigInteger q1 = new BigInteger(); 1481 | 1482 | // q1 = x / b^(k-1) 1483 | for (int i = kMinusOne, j = 0; i < x.DataLength; i++, j++) 1484 | q1._data[j] = x._data[i]; 1485 | q1.DataLength = x.DataLength - kMinusOne; 1486 | if (q1.DataLength <= 0) 1487 | q1.DataLength = 1; 1488 | 1489 | BigInteger q2 = q1 * constant; 1490 | BigInteger q3 = new BigInteger(); 1491 | 1492 | // q3 = q2 / b^(k+1) 1493 | for (int i = kPlusOne, j = 0; i < q2.DataLength; i++, j++) 1494 | q3._data[j] = q2._data[i]; 1495 | q3.DataLength = q2.DataLength - kPlusOne; 1496 | if (q3.DataLength <= 0) 1497 | q3.DataLength = 1; 1498 | 1499 | // r1 = x mod b^(k+1) 1500 | // i.e. keep the lowest (k+1) words 1501 | BigInteger r1 = new BigInteger(); 1502 | int lengthToCopy = (x.DataLength > kPlusOne) ? kPlusOne : x.DataLength; 1503 | for (int i = 0; i < lengthToCopy; i++) 1504 | r1._data[i] = x._data[i]; 1505 | r1.DataLength = lengthToCopy; 1506 | 1507 | // r2 = (q3 * n) mod b^(k+1) 1508 | // partial multiplication of q3 and n 1509 | 1510 | BigInteger r2 = new BigInteger(); 1511 | for (int i = 0; i < q3.DataLength; i++) 1512 | { 1513 | if (q3._data[i] == 0) continue; 1514 | 1515 | ulong mcarry = 0; 1516 | int t = i; 1517 | for (int j = 0; j < n.DataLength && t < kPlusOne; j++, t++) 1518 | { 1519 | // t = i + j 1520 | ulong val = (q3._data[i] * (ulong)n._data[j]) + 1521 | r2._data[t] + mcarry; 1522 | 1523 | r2._data[t] = (uint)(val & 0xFFFFFFFF); 1524 | mcarry = (val >> 32); 1525 | } 1526 | 1527 | if (t < kPlusOne) 1528 | r2._data[t] = (uint)mcarry; 1529 | } 1530 | 1531 | r2.DataLength = kPlusOne; 1532 | while (r2.DataLength > 1 && r2._data[r2.DataLength - 1] == 0) 1533 | r2.DataLength--; 1534 | 1535 | r1 -= r2; 1536 | if ((r1._data[MaxLength - 1] & 0x80000000) != 0) // negative 1537 | { 1538 | BigInteger val = new BigInteger(); 1539 | val._data[kPlusOne] = 0x00000001; 1540 | val.DataLength = kPlusOne + 1; 1541 | r1 += val; 1542 | } 1543 | 1544 | while (r1 >= n) 1545 | r1 -= n; 1546 | 1547 | return r1; 1548 | } 1549 | 1550 | /// 1551 | /// Returns gcd(this, bi) 1552 | /// 1553 | /// 1554 | /// Greatest Common Divisor of this and bi 1555 | public BigInteger Gcd(BigInteger bi) 1556 | { 1557 | BigInteger x; 1558 | BigInteger y; 1559 | 1560 | if ((_data[MaxLength - 1] & 0x80000000) != 0) // negative 1561 | x = -this; 1562 | else 1563 | x = this; 1564 | 1565 | if ((bi._data[MaxLength - 1] & 0x80000000) != 0) // negative 1566 | y = -bi; 1567 | else 1568 | y = bi; 1569 | 1570 | BigInteger g = y; 1571 | 1572 | while (x.DataLength > 1 || (x.DataLength == 1 && x._data[0] != 0)) 1573 | { 1574 | g = x; 1575 | x = y % x; 1576 | y = g; 1577 | } 1578 | 1579 | return g; 1580 | } 1581 | 1582 | /// 1583 | /// Populates "this" with the specified amount of random bits 1584 | /// 1585 | /// 1586 | /// 1587 | public void GenRandomBits(int bits, Random rand) 1588 | { 1589 | int dwords = bits >> 5; 1590 | int remBits = bits & 0x1F; 1591 | 1592 | if (remBits != 0) 1593 | dwords++; 1594 | 1595 | if (dwords > MaxLength || bits <= 0) 1596 | throw (new ArithmeticException("Number of required bits is not valid.")); 1597 | 1598 | byte[] randBytes = new byte[dwords * 4]; 1599 | rand.NextBytes(randBytes); 1600 | 1601 | for (int i = 0; i < dwords; i++) 1602 | _data[i] = BitConverter.ToUInt32(randBytes, i * 4); 1603 | 1604 | for (int i = dwords; i < MaxLength; i++) 1605 | _data[i] = 0; 1606 | 1607 | if (remBits != 0) 1608 | { 1609 | uint mask; 1610 | 1611 | if (bits != 1) 1612 | { 1613 | mask = (uint)(0x01 << (remBits - 1)); 1614 | _data[dwords - 1] |= mask; 1615 | } 1616 | 1617 | mask = 0xFFFFFFFF >> (32 - remBits); 1618 | _data[dwords - 1] &= mask; 1619 | } 1620 | else 1621 | _data[dwords - 1] |= 0x80000000; 1622 | 1623 | DataLength = dwords; 1624 | 1625 | if (DataLength == 0) 1626 | DataLength = 1; 1627 | } 1628 | 1629 | /// 1630 | /// Populates "this" with the specified amount of random bits (secured version) 1631 | /// 1632 | /// 1633 | /// 1634 | public void GenRandomBits(int bits, RNGCryptoServiceProvider rng) 1635 | { 1636 | int dwords = bits >> 5; 1637 | int remBits = bits & 0x1F; 1638 | 1639 | if (remBits != 0) 1640 | dwords++; 1641 | 1642 | if (dwords > MaxLength || bits <= 0) 1643 | throw (new ArithmeticException("Number of required bits is not valid.")); 1644 | 1645 | byte[] randomBytes = new byte[dwords * 4]; 1646 | rng.GetBytes(randomBytes); 1647 | 1648 | for (int i = 0; i < dwords; i++) 1649 | _data[i] = BitConverter.ToUInt32(randomBytes, i * 4); 1650 | 1651 | for (int i = dwords; i < MaxLength; i++) 1652 | _data[i] = 0; 1653 | 1654 | if (remBits != 0) 1655 | { 1656 | uint mask; 1657 | 1658 | if (bits != 1) 1659 | { 1660 | mask = (uint)(0x01 << (remBits - 1)); 1661 | _data[dwords - 1] |= mask; 1662 | } 1663 | 1664 | mask = 0xFFFFFFFF >> (32 - remBits); 1665 | _data[dwords - 1] &= mask; 1666 | } 1667 | else 1668 | _data[dwords - 1] |= 0x80000000; 1669 | 1670 | DataLength = dwords; 1671 | 1672 | if (DataLength == 0) 1673 | DataLength = 1; 1674 | } 1675 | 1676 | /// 1677 | /// Returns the position of the most significant bit in the BigInteger 1678 | /// 1679 | /// 1680 | /// 1) The result is 1, if the value of BigInteger is 0...0000 0000 1681 | /// 2) The result is 1, if the value of BigInteger is 0...0000 0001 1682 | /// 3) The result is 2, if the value of BigInteger is 0...0000 0010 1683 | /// 4) The result is 2, if the value of BigInteger is 0...0000 0011 1684 | /// 5) The result is 5, if the value of BigInteger is 0...0001 0011 1685 | /// 1686 | /// 1687 | public int BitCount() 1688 | { 1689 | while (DataLength > 1 && _data[DataLength - 1] == 0) 1690 | DataLength--; 1691 | 1692 | uint value = _data[DataLength - 1]; 1693 | uint mask = 0x80000000; 1694 | int bits = 32; 1695 | 1696 | while (bits > 0 && (value & mask) == 0) 1697 | { 1698 | bits--; 1699 | mask >>= 1; 1700 | } 1701 | 1702 | bits += ((DataLength - 1) << 5); 1703 | 1704 | return bits == 0 ? 1 : bits; 1705 | } 1706 | 1707 | /// 1708 | /// Probabilistic prime test based on Fermat's little theorem 1709 | /// 1710 | /// 1711 | /// for any a < p (p does not divide a) if 1712 | /// a^(p-1) mod p != 1 then p is not prime. 1713 | /// 1714 | /// Otherwise, p is probably prime (pseudoprime to the chosen base). 1715 | /// 1716 | /// This method is fast but fails for Carmichael numbers when the randomly chosen base is a factor of the number. 1717 | /// 1718 | /// Number of chosen bases 1719 | /// True if this is a pseudoprime to randomly chosen bases 1720 | public bool FermatLittleTest(int confidence) 1721 | { 1722 | BigInteger thisVal; 1723 | if ((this._data[MaxLength - 1] & 0x80000000) != 0) // negative 1724 | thisVal = -this; 1725 | else 1726 | thisVal = this; 1727 | 1728 | if (thisVal.DataLength == 1) 1729 | { 1730 | // test small numbers 1731 | if (thisVal._data[0] == 0 || thisVal._data[0] == 1) 1732 | return false; 1733 | else if (thisVal._data[0] == 2 || thisVal._data[0] == 3) 1734 | return true; 1735 | } 1736 | 1737 | if ((thisVal._data[0] & 0x1) == 0) // even numbers 1738 | return false; 1739 | 1740 | int bits = thisVal.BitCount(); 1741 | BigInteger a = new BigInteger(); 1742 | BigInteger pSub1 = thisVal - (new BigInteger(1)); 1743 | Random rand = new Random(); 1744 | 1745 | for (int round = 0; round < confidence; round++) 1746 | { 1747 | bool done = false; 1748 | 1749 | while (!done) // generate a < n 1750 | { 1751 | int testBits = 0; 1752 | 1753 | // make sure "a" has at least 2 bits 1754 | while (testBits < 2) 1755 | testBits = (int)(rand.NextDouble() * bits); 1756 | 1757 | a.GenRandomBits(testBits, rand); 1758 | 1759 | int byteLen = a.DataLength; 1760 | 1761 | // make sure "a" is not 0 1762 | if (byteLen > 1 || (byteLen == 1 && a._data[0] != 1)) 1763 | done = true; 1764 | } 1765 | 1766 | // check whether a factor exists (fix for version 1.03) 1767 | BigInteger gcdTest = a.Gcd(thisVal); 1768 | if (gcdTest.DataLength == 1 && gcdTest._data[0] != 1) 1769 | return false; 1770 | 1771 | // calculate a^(p-1) mod p 1772 | BigInteger expResult = a.ModPow(pSub1, thisVal); 1773 | 1774 | int resultLen = expResult.DataLength; 1775 | 1776 | // is NOT prime is a^(p-1) mod p != 1 1777 | 1778 | if (resultLen > 1 || (resultLen == 1 && expResult._data[0] != 1)) 1779 | return false; 1780 | } 1781 | 1782 | return true; 1783 | } 1784 | 1785 | /// 1786 | /// Probabilistic prime test based on Rabin-Miller's 1787 | /// 1788 | /// 1789 | /// for any p > 0 with p - 1 = 2^s * t 1790 | /// 1791 | /// p is probably prime (strong pseudoprime) if for any a < p, 1792 | /// 1) a^t mod p = 1 or 1793 | /// 2) a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1 1794 | /// 1795 | /// Otherwise, p is composite. 1796 | /// 1797 | /// Number of chosen bases 1798 | /// True if this is a strong pseudoprime to randomly chosen bases 1799 | public bool RabinMillerTest(int confidence) 1800 | { 1801 | BigInteger thisVal; 1802 | if ((this._data[MaxLength - 1] & 0x80000000) != 0) // negative 1803 | thisVal = -this; 1804 | else 1805 | thisVal = this; 1806 | 1807 | if (thisVal.DataLength == 1) 1808 | { 1809 | // test small numbers 1810 | if (thisVal._data[0] == 0 || thisVal._data[0] == 1) 1811 | return false; 1812 | else if (thisVal._data[0] == 2 || thisVal._data[0] == 3) 1813 | return true; 1814 | } 1815 | 1816 | if ((thisVal._data[0] & 0x1) == 0) // even numbers 1817 | return false; 1818 | 1819 | // calculate values of s and t 1820 | BigInteger pSub1 = thisVal - (new BigInteger(1)); 1821 | int s = 0; 1822 | 1823 | for (int index = 0; index < pSub1.DataLength; index++) 1824 | { 1825 | uint mask = 0x01; 1826 | 1827 | for (int i = 0; i < 32; i++) 1828 | { 1829 | if ((pSub1._data[index] & mask) != 0) 1830 | { 1831 | index = pSub1.DataLength; // to break the outer loop 1832 | break; 1833 | } 1834 | 1835 | mask <<= 1; 1836 | s++; 1837 | } 1838 | } 1839 | 1840 | BigInteger t = pSub1 >> s; 1841 | 1842 | int bits = thisVal.BitCount(); 1843 | BigInteger a = new BigInteger(); 1844 | Random rand = new Random(); 1845 | 1846 | for (int round = 0; round < confidence; round++) 1847 | { 1848 | bool done = false; 1849 | 1850 | while (!done) // generate a < n 1851 | { 1852 | int testBits = 0; 1853 | 1854 | // make sure "a" has at least 2 bits 1855 | while (testBits < 2) 1856 | testBits = (int)(rand.NextDouble() * bits); 1857 | 1858 | a.GenRandomBits(testBits, rand); 1859 | 1860 | int byteLen = a.DataLength; 1861 | 1862 | // make sure "a" is not 0 1863 | if (byteLen > 1 || (byteLen == 1 && a._data[0] != 1)) 1864 | done = true; 1865 | } 1866 | 1867 | // check whether a factor exists (fix for version 1.03) 1868 | BigInteger gcdTest = a.Gcd(thisVal); 1869 | if (gcdTest.DataLength == 1 && gcdTest._data[0] != 1) 1870 | return false; 1871 | 1872 | BigInteger b = a.ModPow(t, thisVal); 1873 | 1874 | bool result = false; 1875 | 1876 | if (b.DataLength == 1 && b._data[0] == 1) // a^t mod p = 1 1877 | result = true; 1878 | 1879 | for (int j = 0; result == false && j < s; j++) 1880 | { 1881 | if (b == pSub1) // a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1 1882 | { 1883 | result = true; 1884 | break; 1885 | } 1886 | 1887 | b = (b * b) % thisVal; 1888 | } 1889 | 1890 | if (result == false) 1891 | return false; 1892 | } 1893 | 1894 | return true; 1895 | } 1896 | 1897 | /// 1898 | /// Probabilistic prime test based on Solovay-Strassen (Euler Criterion) 1899 | /// 1900 | /// 1901 | /// p is probably prime if for any a < p (a is not multiple of p), 1902 | /// a^((p-1)/2) mod p = J(a, p) 1903 | /// 1904 | /// where J is the Jacobi symbol. 1905 | /// 1906 | /// Otherwise, p is composite. 1907 | /// 1908 | /// Number of chosen bases 1909 | /// True if this is a Euler pseudoprime to randomly chosen bases 1910 | public bool SolovayStrassenTest(int confidence) 1911 | { 1912 | BigInteger thisVal; 1913 | if ((this._data[MaxLength - 1] & 0x80000000) != 0) // negative 1914 | thisVal = -this; 1915 | else 1916 | thisVal = this; 1917 | 1918 | if (thisVal.DataLength == 1) 1919 | { 1920 | // test small numbers 1921 | if (thisVal._data[0] == 0 || thisVal._data[0] == 1) 1922 | return false; 1923 | else if (thisVal._data[0] == 2 || thisVal._data[0] == 3) 1924 | return true; 1925 | } 1926 | 1927 | if ((thisVal._data[0] & 0x1) == 0) // even numbers 1928 | return false; 1929 | 1930 | int bits = thisVal.BitCount(); 1931 | BigInteger a = new BigInteger(); 1932 | BigInteger pSub1 = thisVal - 1; 1933 | BigInteger pSub1Shift = pSub1 >> 1; 1934 | 1935 | Random rand = new Random(); 1936 | 1937 | for (int round = 0; round < confidence; round++) 1938 | { 1939 | bool done = false; 1940 | 1941 | while (!done) // generate a < n 1942 | { 1943 | int testBits = 0; 1944 | 1945 | // make sure "a" has at least 2 bits 1946 | while (testBits < 2) 1947 | testBits = (int)(rand.NextDouble() * bits); 1948 | 1949 | a.GenRandomBits(testBits, rand); 1950 | 1951 | int byteLen = a.DataLength; 1952 | 1953 | // make sure "a" is not 0 1954 | if (byteLen > 1 || (byteLen == 1 && a._data[0] != 1)) 1955 | done = true; 1956 | } 1957 | 1958 | // check whether a factor exists (fix for version 1.03) 1959 | BigInteger gcdTest = a.Gcd(thisVal); 1960 | if (gcdTest.DataLength == 1 && gcdTest._data[0] != 1) 1961 | return false; 1962 | 1963 | // calculate a^((p-1)/2) mod p 1964 | 1965 | BigInteger expResult = a.ModPow(pSub1Shift, thisVal); 1966 | if (expResult == pSub1) 1967 | expResult = -1; 1968 | 1969 | // calculate Jacobi symbol 1970 | BigInteger jacob = Jacobi(a, thisVal); 1971 | 1972 | // if they are different then it is not prime 1973 | if (expResult != jacob) 1974 | return false; 1975 | } 1976 | 1977 | return true; 1978 | } 1979 | 1980 | /// 1981 | /// Implementation of the Lucas Strong Pseudo Prime test 1982 | /// 1983 | /// 1984 | /// Let n be an odd number with gcd(n,D) = 1, and n - J(D, n) = 2^s * d 1985 | /// with d odd and s >= 0. 1986 | /// 1987 | /// If Ud mod n = 0 or V2^r*d mod n = 0 for some 0 <= r < s, then n 1988 | /// is a strong Lucas pseudoprime with parameters (P, Q). We select 1989 | /// P and Q based on Selfridge. 1990 | /// 1991 | /// True if number is a strong Lucus pseudo prime 1992 | public bool LucasStrongTest() 1993 | { 1994 | BigInteger thisVal; 1995 | if ((this._data[MaxLength - 1] & 0x80000000) != 0) // negative 1996 | thisVal = -this; 1997 | else 1998 | thisVal = this; 1999 | 2000 | if (thisVal.DataLength == 1) 2001 | { 2002 | // test small numbers 2003 | if (thisVal._data[0] == 0 || thisVal._data[0] == 1) 2004 | return false; 2005 | else if (thisVal._data[0] == 2 || thisVal._data[0] == 3) 2006 | return true; 2007 | } 2008 | 2009 | if ((thisVal._data[0] & 0x1) == 0) // even numbers 2010 | return false; 2011 | 2012 | return LucasStrongTestHelper(thisVal); 2013 | } 2014 | 2015 | private bool LucasStrongTestHelper(BigInteger thisVal) 2016 | { 2017 | // Do the test (selects D based on Selfridge) 2018 | // Let D be the first element of the sequence 2019 | // 5, -7, 9, -11, 13, ... for which J(D,n) = -1 2020 | // Let P = 1, Q = (1-D) / 4 2021 | 2022 | long d = 5, sign = -1, dCount = 0; 2023 | bool done = false; 2024 | 2025 | while (!done) 2026 | { 2027 | int jresult = BigInteger.Jacobi(d, thisVal); 2028 | 2029 | if (jresult == -1) 2030 | done = true; // J(D, this) = 1 2031 | else 2032 | { 2033 | if (jresult == 0 && System.Math.Abs(d) < thisVal) // divisor found 2034 | return false; 2035 | 2036 | if (dCount == 20) 2037 | { 2038 | // check for square 2039 | BigInteger root = thisVal.Sqrt(); 2040 | if (root * root == thisVal) 2041 | return false; 2042 | } 2043 | 2044 | d = (System.Math.Abs(d) + 2) * sign; 2045 | sign = -sign; 2046 | } 2047 | 2048 | dCount++; 2049 | } 2050 | 2051 | long q = (1 - d) >> 2; 2052 | 2053 | BigInteger pAdd1 = thisVal + 1; 2054 | int s = 0; 2055 | 2056 | for (int index = 0; index < pAdd1.DataLength; index++) 2057 | { 2058 | uint mask = 0x01; 2059 | 2060 | for (int i = 0; i < 32; i++) 2061 | { 2062 | if ((pAdd1._data[index] & mask) != 0) 2063 | { 2064 | index = pAdd1.DataLength; // to break the outer loop 2065 | break; 2066 | } 2067 | 2068 | mask <<= 1; 2069 | s++; 2070 | } 2071 | } 2072 | 2073 | BigInteger t = pAdd1 >> s; 2074 | 2075 | // calculate constant = b^(2k) / m 2076 | // for Barrett Reduction 2077 | BigInteger constant = new BigInteger(); 2078 | 2079 | int nLen = thisVal.DataLength << 1; 2080 | constant._data[nLen] = 0x00000001; 2081 | constant.DataLength = nLen + 1; 2082 | 2083 | constant = constant / thisVal; 2084 | 2085 | BigInteger[] lucas = LucasSequenceHelper(1, q, t, thisVal, constant, 0); 2086 | bool isPrime = false; 2087 | 2088 | if ((lucas[0].DataLength == 1 && lucas[0]._data[0] == 0) || 2089 | (lucas[1].DataLength == 1 && lucas[1]._data[0] == 0)) 2090 | { 2091 | // u(t) = 0 or V(t) = 0 2092 | isPrime = true; 2093 | } 2094 | 2095 | for (int i = 1; i < s; i++) 2096 | { 2097 | if (!isPrime) 2098 | { 2099 | // doubling of index 2100 | lucas[1] = thisVal.BarrettReduction(lucas[1] * lucas[1], thisVal, constant); 2101 | lucas[1] = (lucas[1] - (lucas[2] << 1)) % thisVal; 2102 | 2103 | if ((lucas[1].DataLength == 1 && lucas[1]._data[0] == 0)) 2104 | isPrime = true; 2105 | } 2106 | 2107 | lucas[2] = thisVal.BarrettReduction(lucas[2] * lucas[2], thisVal, constant); //Q^k 2108 | } 2109 | 2110 | if (isPrime) // additional checks for composite numbers 2111 | { 2112 | // If n is prime and gcd(n, Q) == 1, then 2113 | // Q^((n+1)/2) = Q * Q^((n-1)/2) is congruent to (Q * J(Q, n)) mod n 2114 | 2115 | BigInteger g = thisVal.Gcd(q); 2116 | if (g.DataLength == 1 && g._data[0] == 1) // gcd(this, Q) == 1 2117 | { 2118 | if ((lucas[2]._data[MaxLength - 1] & 0x80000000) != 0) 2119 | lucas[2] += thisVal; 2120 | 2121 | BigInteger temp = (q * BigInteger.Jacobi(q, thisVal)) % thisVal; 2122 | if ((temp._data[MaxLength - 1] & 0x80000000) != 0) 2123 | temp += thisVal; 2124 | 2125 | if (lucas[2] != temp) 2126 | isPrime = false; 2127 | } 2128 | } 2129 | 2130 | return isPrime; 2131 | } 2132 | 2133 | /// 2134 | /// Determines whether a number is probably prime using the Rabin-Miller's test 2135 | /// 2136 | /// 2137 | /// Before applying the test, the number is tested for divisibility by primes < 2000 2138 | /// 2139 | /// Number of chosen bases 2140 | /// True if this is probably prime 2141 | public bool IsProbablePrime(int confidence) 2142 | { 2143 | BigInteger thisVal; 2144 | if ((this._data[MaxLength - 1] & 0x80000000) != 0) // negative 2145 | thisVal = -this; 2146 | else 2147 | thisVal = this; 2148 | 2149 | // test for divisibility by primes < 2000 2150 | for (int p = 0; p < PrimesBelow2000.Length; p++) 2151 | { 2152 | BigInteger divisor = PrimesBelow2000[p]; 2153 | 2154 | if (divisor >= thisVal) 2155 | break; 2156 | 2157 | BigInteger resultNum = thisVal % divisor; 2158 | if (resultNum.IntValue() == 0) 2159 | return false; 2160 | } 2161 | 2162 | if (thisVal.RabinMillerTest(confidence)) 2163 | return true; 2164 | else 2165 | return false; 2166 | } 2167 | 2168 | /// 2169 | /// Determines whether this BigInteger is probably prime using a combination of base 2 strong pseudoprime test and Lucas strong pseudoprime test 2170 | /// 2171 | /// 2172 | /// The sequence of the primality test is as follows, 2173 | /// 2174 | /// 1) Trial divisions are carried out using prime numbers below 2000. 2175 | /// if any of the primes divides this BigInteger, then it is not prime. 2176 | /// 2177 | /// 2) Perform base 2 strong pseudoprime test. If this BigInteger is a 2178 | /// base 2 strong pseudoprime, proceed on to the next step. 2179 | /// 2180 | /// 3) Perform strong Lucas pseudoprime test. 2181 | /// 2182 | /// For a detailed discussion of this primality test, see [6]. 2183 | /// 2184 | /// True if this is probably prime 2185 | public bool IsProbablePrime() 2186 | { 2187 | BigInteger thisVal; 2188 | if ((this._data[MaxLength - 1] & 0x80000000) != 0) // negative 2189 | thisVal = -this; 2190 | else 2191 | thisVal = this; 2192 | 2193 | if (thisVal.DataLength == 1) 2194 | { 2195 | // test small numbers 2196 | if (thisVal._data[0] == 0 || thisVal._data[0] == 1) 2197 | return false; 2198 | else if (thisVal._data[0] == 2 || thisVal._data[0] == 3) 2199 | return true; 2200 | } 2201 | 2202 | if ((thisVal._data[0] & 0x1) == 0) // even numbers 2203 | return false; 2204 | 2205 | // test for divisibility by primes < 2000 2206 | for (int p = 0; p < PrimesBelow2000.Length; p++) 2207 | { 2208 | BigInteger divisor = PrimesBelow2000[p]; 2209 | 2210 | if (divisor >= thisVal) 2211 | break; 2212 | 2213 | BigInteger resultNum = thisVal % divisor; 2214 | if (resultNum.IntValue() == 0) 2215 | return false; 2216 | } 2217 | 2218 | // Perform BASE 2 Rabin-Miller Test 2219 | 2220 | // calculate values of s and t 2221 | BigInteger pSub1 = thisVal - (new BigInteger(1)); 2222 | int s = 0; 2223 | 2224 | for (int index = 0; index < pSub1.DataLength; index++) 2225 | { 2226 | uint mask = 0x01; 2227 | 2228 | for (int i = 0; i < 32; i++) 2229 | { 2230 | if ((pSub1._data[index] & mask) != 0) 2231 | { 2232 | index = pSub1.DataLength; // to break the outer loop 2233 | break; 2234 | } 2235 | 2236 | mask <<= 1; 2237 | s++; 2238 | } 2239 | } 2240 | 2241 | BigInteger t = pSub1 >> s; 2242 | 2243 | int bits = thisVal.BitCount(); 2244 | BigInteger a = 2; 2245 | 2246 | // b = a^t mod p 2247 | BigInteger b = a.ModPow(t, thisVal); 2248 | bool result = false; 2249 | 2250 | if (b.DataLength == 1 && b._data[0] == 1) // a^t mod p = 1 2251 | result = true; 2252 | 2253 | for (int j = 0; result == false && j < s; j++) 2254 | { 2255 | if (b == pSub1) // a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1 2256 | { 2257 | result = true; 2258 | break; 2259 | } 2260 | 2261 | b = (b * b) % thisVal; 2262 | } 2263 | 2264 | // if number is strong pseudoprime to base 2, then do a strong lucas test 2265 | if (result) 2266 | result = LucasStrongTestHelper(thisVal); 2267 | 2268 | return result; 2269 | } 2270 | 2271 | /// 2272 | /// Returns the lowest 4 bytes of the BigInteger as an int 2273 | /// 2274 | /// Lowest 4 bytes as integer 2275 | public int IntValue() 2276 | { 2277 | return (int)_data[0]; 2278 | } 2279 | 2280 | /// 2281 | /// Returns the lowest 8 bytes of the BigInteger as a long 2282 | /// 2283 | /// Lowest 8 bytes as long 2284 | public long LongValue() 2285 | { 2286 | long val = 0; 2287 | 2288 | val = _data[0]; 2289 | try 2290 | { 2291 | // exception if maxLength = 1 2292 | val |= (long)_data[1] << 32; 2293 | } 2294 | catch (Exception) 2295 | { 2296 | if ((_data[0] & 0x80000000) != 0) // negative 2297 | val = (int)_data[0]; 2298 | } 2299 | 2300 | return val; 2301 | } 2302 | 2303 | /// 2304 | /// Computes the Jacobi Symbol for 2 BigInteger a and b 2305 | /// 2306 | /// 2307 | /// Algorithm adapted from [3] and [4] with some optimizations 2308 | /// 2309 | /// Any BigInteger 2310 | /// Odd BigInteger 2311 | /// Jacobi Symbol 2312 | public static int Jacobi(BigInteger a, BigInteger b) 2313 | { 2314 | // Jacobi defined only for odd integers 2315 | if ((b._data[0] & 0x1) == 0) 2316 | throw (new ArgumentException("Jacobi defined only for odd integers.")); 2317 | 2318 | if (a >= b) a %= b; 2319 | if (a.DataLength == 1 && a._data[0] == 0) return 0; // a == 0 2320 | if (a.DataLength == 1 && a._data[0] == 1) return 1; // a == 1 2321 | 2322 | if (a < 0) 2323 | { 2324 | if ((((b - 1)._data[0]) & 0x2) == 0) //if( (((b-1) >> 1).data[0] & 0x1) == 0) 2325 | return Jacobi(-a, b); 2326 | else 2327 | return -Jacobi(-a, b); 2328 | } 2329 | 2330 | int e = 0; 2331 | for (int index = 0; index < a.DataLength; index++) 2332 | { 2333 | uint mask = 0x01; 2334 | 2335 | for (int i = 0; i < 32; i++) 2336 | { 2337 | if ((a._data[index] & mask) != 0) 2338 | { 2339 | index = a.DataLength; // to break the outer loop 2340 | break; 2341 | } 2342 | 2343 | mask <<= 1; 2344 | e++; 2345 | } 2346 | } 2347 | 2348 | BigInteger a1 = a >> e; 2349 | 2350 | int s = 1; 2351 | if ((e & 0x1) != 0 && ((b._data[0] & 0x7) == 3 || (b._data[0] & 0x7) == 5)) 2352 | s = -1; 2353 | 2354 | if ((b._data[0] & 0x3) == 3 && (a1._data[0] & 0x3) == 3) 2355 | s = -s; 2356 | 2357 | if (a1.DataLength == 1 && a1._data[0] == 1) 2358 | return s; 2359 | else 2360 | return (s * Jacobi(b % a1, a1)); 2361 | } 2362 | 2363 | /// 2364 | /// Generates a positive BigInteger that is probably prime 2365 | /// 2366 | /// Number of bit 2367 | /// Number of chosen bases 2368 | /// Random object 2369 | /// A probably prime number 2370 | public static BigInteger GenPseudoPrime(int bits, int confidence, Random rand) 2371 | { 2372 | BigInteger result = new BigInteger(); 2373 | bool done = false; 2374 | 2375 | while (!done) 2376 | { 2377 | result.GenRandomBits(bits, rand); 2378 | result._data[0] |= 0x01; // make it odd 2379 | 2380 | // prime test 2381 | done = result.IsProbablePrime(confidence); 2382 | } 2383 | 2384 | return result; 2385 | } 2386 | 2387 | /// 2388 | /// Generates a positive BigInteger that is probably prime (secured version) 2389 | /// 2390 | /// Number of bit 2391 | /// Number of chosen bases 2392 | /// RNGCryptoServiceProvider object 2393 | /// A probably prime number 2394 | public static BigInteger GenPseudoPrime(int bits, int confidence, RNGCryptoServiceProvider rand) 2395 | { 2396 | BigInteger result = new BigInteger(); 2397 | bool done = false; 2398 | 2399 | while (!done) 2400 | { 2401 | result.GenRandomBits(bits, rand); 2402 | result._data[0] |= 0x01; // make it odd 2403 | 2404 | // prime test 2405 | done = result.IsProbablePrime(confidence); 2406 | } 2407 | 2408 | return result; 2409 | } 2410 | 2411 | /// 2412 | /// Generates a random number with the specified number of bits such that gcd(number, this) = 1 2413 | /// 2414 | /// 2415 | /// The number of bits must be greater than 0 and less than 2209 2416 | /// 2417 | /// Number of bit 2418 | /// Random object 2419 | /// Relatively prime number of this 2420 | public BigInteger GenCoPrime(int bits, Random rand) 2421 | { 2422 | bool done = false; 2423 | BigInteger result = new BigInteger(); 2424 | 2425 | while (!done) 2426 | { 2427 | result.GenRandomBits(bits, rand); 2428 | 2429 | // gcd test 2430 | BigInteger g = result.Gcd(this); 2431 | if (g.DataLength == 1 && g._data[0] == 1) 2432 | done = true; 2433 | } 2434 | 2435 | return result; 2436 | } 2437 | 2438 | /// 2439 | /// Generates a random number with the specified number of bits such that gcd(number, this) = 1 (secured) 2440 | /// 2441 | /// Number of bit 2442 | /// Random object 2443 | /// Relatively prime number of this 2444 | public BigInteger GenCoPrime(int bits, RNGCryptoServiceProvider rand) 2445 | { 2446 | bool done = false; 2447 | BigInteger result = new BigInteger(); 2448 | 2449 | while (!done) 2450 | { 2451 | result.GenRandomBits(bits, rand); 2452 | 2453 | // gcd test 2454 | BigInteger g = result.Gcd(this); 2455 | if (g.DataLength == 1 && g._data[0] == 1) 2456 | done = true; 2457 | } 2458 | 2459 | return result; 2460 | } 2461 | 2462 | /// 2463 | /// Returns the modulo inverse of this 2464 | /// 2465 | /// 2466 | /// Throws ArithmeticException if the inverse does not exist. (i.e. gcd(this, modulus) != 1) 2467 | /// 2468 | /// 2469 | /// Modulo inverse of this 2470 | public BigInteger ModInverse(BigInteger modulus) 2471 | { 2472 | BigInteger[] p = { 0, 1 }; 2473 | BigInteger[] q = new BigInteger[2]; // quotients 2474 | BigInteger[] r = { 0, 0 }; // remainders 2475 | 2476 | int step = 0; 2477 | 2478 | BigInteger a = modulus; 2479 | BigInteger b = this; 2480 | 2481 | while (b.DataLength > 1 || (b.DataLength == 1 && b._data[0] != 0)) 2482 | { 2483 | BigInteger quotient = new BigInteger(); 2484 | BigInteger remainder = new BigInteger(); 2485 | 2486 | if (step > 1) 2487 | { 2488 | BigInteger pval = (p[0] - (p[1] * q[0])) % modulus; 2489 | p[0] = p[1]; 2490 | p[1] = pval; 2491 | } 2492 | 2493 | if (b.DataLength == 1) 2494 | SingleByteDivide(a, b, quotient, remainder); 2495 | else 2496 | MultiByteDivide(a, b, quotient, remainder); 2497 | 2498 | q[0] = q[1]; 2499 | r[0] = r[1]; 2500 | q[1] = quotient; 2501 | r[1] = remainder; 2502 | 2503 | a = b; 2504 | b = remainder; 2505 | 2506 | step++; 2507 | } 2508 | 2509 | if (r[0].DataLength > 1 || (r[0].DataLength == 1 && r[0]._data[0] != 1)) 2510 | throw (new ArithmeticException("No inverse!")); 2511 | 2512 | BigInteger result = ((p[0] - (p[1] * q[0])) % modulus); 2513 | 2514 | if ((result._data[MaxLength - 1] & 0x80000000) != 0) 2515 | result += modulus; // get the least positive modulus 2516 | 2517 | return result; 2518 | } 2519 | 2520 | /// 2521 | /// Returns the value of the BigInteger as a byte array 2522 | /// 2523 | /// 2524 | /// The lowest index contains the MSB 2525 | /// 2526 | /// Byte array containing value of the BigInteger 2527 | public byte[] GetBytes() 2528 | { 2529 | int numBits = BitCount(); 2530 | 2531 | int numBytes = numBits >> 3; 2532 | if ((numBits & 0x7) != 0) 2533 | numBytes++; 2534 | 2535 | byte[] result = new byte[numBytes]; 2536 | 2537 | int pos = 0; 2538 | uint tempVal, val = _data[DataLength - 1]; 2539 | 2540 | if ((tempVal = (val >> 24 & 0xFF)) != 0) 2541 | result[pos++] = (byte)tempVal; 2542 | 2543 | if ((tempVal = (val >> 16 & 0xFF)) != 0) 2544 | result[pos++] = (byte)tempVal; 2545 | else if (pos > 0) 2546 | pos++; 2547 | 2548 | if ((tempVal = (val >> 8 & 0xFF)) != 0) 2549 | result[pos++] = (byte)tempVal; 2550 | else if (pos > 0) 2551 | pos++; 2552 | 2553 | if ((tempVal = (val & 0xFF)) != 0) 2554 | result[pos++] = (byte)tempVal; 2555 | else if (pos > 0) 2556 | pos++; 2557 | 2558 | for (int i = DataLength - 2; i >= 0; i--, pos += 4) 2559 | { 2560 | val = _data[i]; 2561 | result[pos + 3] = (byte)(val & 0xFF); 2562 | val >>= 8; 2563 | result[pos + 2] = (byte)(val & 0xFF); 2564 | val >>= 8; 2565 | result[pos + 1] = (byte)(val & 0xFF); 2566 | val >>= 8; 2567 | result[pos] = (byte)(val & 0xFF); 2568 | } 2569 | 2570 | return result; 2571 | } 2572 | 2573 | public uint[] GetInternalState() 2574 | { 2575 | uint[] result = new UInt32[_data.Length]; 2576 | _data.CopyTo(result, 0); 2577 | return result; 2578 | } 2579 | 2580 | /// 2581 | /// Sets the value of the specified bit to 1 2582 | /// 2583 | /// 2584 | /// The Least Significant Bit position is 0 2585 | /// 2586 | /// The position of bit to be changed 2587 | public void SetBit(uint bitNum) 2588 | { 2589 | uint bytePos = bitNum >> 5; // divide by 32 2590 | byte bitPos = (byte)(bitNum & 0x1F); // get the lowest 5 bits 2591 | 2592 | uint mask = (uint)1 << bitPos; 2593 | this._data[bytePos] |= mask; 2594 | 2595 | if (bytePos >= this.DataLength) 2596 | this.DataLength = (int)bytePos + 1; 2597 | } 2598 | 2599 | /// 2600 | /// Sets the value of the specified bit to 0 2601 | /// 2602 | /// 2603 | /// The Least Significant Bit position is 0 2604 | /// 2605 | /// The position of bit to be changed 2606 | public void UnsetBit(uint bitNum) 2607 | { 2608 | uint bytePos = bitNum >> 5; 2609 | 2610 | if (bytePos < this.DataLength) 2611 | { 2612 | byte bitPos = (byte)(bitNum & 0x1F); 2613 | 2614 | uint mask = (uint)1 << bitPos; 2615 | uint mask2 = 0xFFFFFFFF ^ mask; 2616 | 2617 | this._data[bytePos] &= mask2; 2618 | 2619 | if (this.DataLength > 1 && this._data[this.DataLength - 1] == 0) 2620 | this.DataLength--; 2621 | } 2622 | } 2623 | 2624 | /// 2625 | /// Returns a value that is equivalent to the integer square root of this 2626 | /// 2627 | /// 2628 | /// The integer square root of "this" is defined as the largest integer n, such that (n * n) <= this. 2629 | /// Square root of negative integer is an undefined behaviour (UB). 2630 | /// 2631 | /// Integer square root of this 2632 | public BigInteger Sqrt() 2633 | { 2634 | uint numBits = (uint)this.BitCount(); 2635 | 2636 | if ((numBits & 0x1) != 0) // odd number of bits 2637 | numBits = (numBits >> 1) + 1; 2638 | else 2639 | numBits = (numBits >> 1); 2640 | 2641 | uint bytePos = numBits >> 5; 2642 | byte bitPos = (byte)(numBits & 0x1F); 2643 | 2644 | uint mask; 2645 | 2646 | BigInteger result = new BigInteger(); 2647 | if (bitPos == 0) 2648 | mask = 0x80000000; 2649 | else 2650 | { 2651 | mask = (uint)1 << bitPos; 2652 | bytePos++; 2653 | } 2654 | 2655 | result.DataLength = (int)bytePos; 2656 | 2657 | for (int i = (int)bytePos - 1; i >= 0; i--) 2658 | { 2659 | while (mask != 0) 2660 | { 2661 | // guess 2662 | result._data[i] ^= mask; 2663 | 2664 | // undo the guess if its square is larger than this 2665 | if ((result * result) > this) 2666 | result._data[i] ^= mask; 2667 | 2668 | mask >>= 1; 2669 | } 2670 | 2671 | mask = 0x80000000; 2672 | } 2673 | 2674 | return result; 2675 | } 2676 | 2677 | /// 2678 | /// Returns the k_th number in the Lucas Sequence reduced modulo n 2679 | /// 2680 | /// 2681 | /// Uses index doubling to speed up the process. For example, to calculate V(k), 2682 | /// we maintain two numbers in the sequence V(n) and V(n+1). 2683 | /// 2684 | /// To obtain V(2n), we use the identity 2685 | /// V(2n) = (V(n) * V(n)) - (2 * Q^n) 2686 | /// To obtain V(2n+1), we first write it as 2687 | /// V(2n+1) = V((n+1) + n) 2688 | /// and use the identity 2689 | /// V(m+n) = V(m) * V(n) - Q * V(m-n) 2690 | /// Hence, 2691 | /// V((n+1) + n) = V(n+1) * V(n) - Q^n * V((n+1) - n) 2692 | /// = V(n+1) * V(n) - Q^n * V(1) 2693 | /// = V(n+1) * V(n) - Q^n * P 2694 | /// 2695 | /// We use k in its binary expansion and perform index doubling for each 2696 | /// bit position. For each bit position that is set, we perform an 2697 | /// index doubling followed by an index addition. This means that for V(n), 2698 | /// we need to update it to V(2n+1). For V(n+1), we need to update it to 2699 | /// V((2n+1)+1) = V(2*(n+1)) 2700 | /// 2701 | /// This function returns 2702 | /// [0] = U(k) 2703 | /// [1] = V(k) 2704 | /// [2] = Q^n 2705 | /// 2706 | /// Where U(0) = 0 % n, U(1) = 1 % n 2707 | /// V(0) = 2 % n, V(1) = P % n 2708 | /// 2709 | /// 2710 | /// 2711 | /// 2712 | /// 2713 | /// 2714 | public static BigInteger[] LucasSequence(BigInteger p, BigInteger q, BigInteger k, BigInteger n) 2715 | { 2716 | if (k.DataLength == 1 && k._data[0] == 0) 2717 | { 2718 | BigInteger[] result = new BigInteger[3]; 2719 | 2720 | result[0] = 0; 2721 | result[1] = 2 % n; 2722 | result[2] = 1 % n; 2723 | return result; 2724 | } 2725 | 2726 | // calculate constant = b^(2k) / m 2727 | // for Barrett Reduction 2728 | BigInteger constant = new BigInteger(); 2729 | 2730 | int nLen = n.DataLength << 1; 2731 | constant._data[nLen] = 0x00000001; 2732 | constant.DataLength = nLen + 1; 2733 | 2734 | constant = constant / n; 2735 | 2736 | // calculate values of s and t 2737 | int s = 0; 2738 | 2739 | for (int index = 0; index < k.DataLength; index++) 2740 | { 2741 | uint mask = 0x01; 2742 | 2743 | for (int i = 0; i < 32; i++) 2744 | { 2745 | if ((k._data[index] & mask) != 0) 2746 | { 2747 | index = k.DataLength; // to break the outer loop 2748 | break; 2749 | } 2750 | 2751 | mask <<= 1; 2752 | s++; 2753 | } 2754 | } 2755 | 2756 | BigInteger t = k >> s; 2757 | 2758 | return LucasSequenceHelper(p, q, t, n, constant, s); 2759 | } 2760 | 2761 | //*********************************************************************** 2762 | // Performs the calculation of the kth term in the Lucas Sequence. 2763 | // For details of the algorithm, see reference [9]. 2764 | // 2765 | // k must be odd. i.e LSB == 1 2766 | //*********************************************************************** 2767 | private static BigInteger[] LucasSequenceHelper(BigInteger p, BigInteger q, BigInteger k, BigInteger n, BigInteger constant, int s) 2768 | { 2769 | BigInteger[] result = new BigInteger[3]; 2770 | 2771 | if ((k._data[0] & 0x00000001) == 0) 2772 | throw (new ArgumentException("Argument k must be odd.")); 2773 | 2774 | int numbits = k.BitCount(); 2775 | uint mask = (uint)0x1 << ((numbits & 0x1F) - 1); 2776 | 2777 | // v = v0, v1 = v1, u1 = u1, Q_k = Q^0 2778 | 2779 | BigInteger v = 2 % n, 2780 | qK = 1 % n, 2781 | v1 = p % n, 2782 | u1 = qK; 2783 | bool flag = true; 2784 | 2785 | for (int i = k.DataLength - 1; i >= 0; i--) // iterate on the binary expansion of k 2786 | { 2787 | while (mask != 0) 2788 | { 2789 | if (i == 0 && mask == 0x00000001) // last bit 2790 | break; 2791 | 2792 | if ((k._data[i] & mask) != 0) // bit is set 2793 | { 2794 | // index doubling with addition 2795 | 2796 | u1 = (u1 * v1) % n; 2797 | 2798 | v = ((v * v1) - (p * qK)) % n; 2799 | v1 = n.BarrettReduction(v1 * v1, n, constant); 2800 | v1 = (v1 - ((qK * q) << 1)) % n; 2801 | 2802 | if (flag) 2803 | flag = false; 2804 | else 2805 | qK = n.BarrettReduction(qK * qK, n, constant); 2806 | 2807 | qK = (qK * q) % n; 2808 | } 2809 | else 2810 | { 2811 | // index doubling 2812 | u1 = ((u1 * v) - qK) % n; 2813 | 2814 | v1 = ((v * v1) - (p * qK)) % n; 2815 | v = n.BarrettReduction(v * v, n, constant); 2816 | v = (v - (qK << 1)) % n; 2817 | 2818 | if (flag) 2819 | { 2820 | qK = q % n; 2821 | flag = false; 2822 | } 2823 | else 2824 | qK = n.BarrettReduction(qK * qK, n, constant); 2825 | } 2826 | 2827 | mask >>= 1; 2828 | } 2829 | 2830 | mask = 0x80000000; 2831 | } 2832 | 2833 | // at this point u1 = u(n+1) and v = v(n) 2834 | // since the last bit always 1, we need to transform u1 to u(2n+1) and v to v(2n+1) 2835 | 2836 | u1 = ((u1 * v) - qK) % n; 2837 | v = ((v * v1) - (p * qK)) % n; 2838 | if (flag) 2839 | flag = false; 2840 | else 2841 | qK = n.BarrettReduction(qK * qK, n, constant); 2842 | 2843 | qK = (qK * q) % n; 2844 | 2845 | for (int i = 0; i < s; i++) 2846 | { 2847 | // index doubling 2848 | u1 = (u1 * v) % n; 2849 | v = ((v * v) - (qK << 1)) % n; 2850 | 2851 | if (flag) 2852 | { 2853 | qK = q % n; 2854 | flag = false; 2855 | } 2856 | else 2857 | qK = n.BarrettReduction(qK * qK, n, constant); 2858 | } 2859 | 2860 | result[0] = u1; 2861 | result[1] = v; 2862 | result[2] = qK; 2863 | 2864 | return result; 2865 | } 2866 | } 2867 | } --------------------------------------------------------------------------------