├── 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 | }
--------------------------------------------------------------------------------