diff --git a/MLAPI/MLAPI.csproj b/MLAPI/MLAPI.csproj
index 757c7d5..446cc8e 100644
--- a/MLAPI/MLAPI.csproj
+++ b/MLAPI/MLAPI.csproj
@@ -44,6 +44,9 @@
Auto
+
+ ..\packages\IntX.1.0.1.0\lib\net20\IntXLib.dll
+
@@ -79,5 +82,8 @@
+
+
+
\ No newline at end of file
diff --git a/MLAPI/NetworkingManagerComponents/DiffieHellman.cs b/MLAPI/NetworkingManagerComponents/DiffieHellman.cs
new file mode 100644
index 0000000..2e675b5
--- /dev/null
+++ b/MLAPI/NetworkingManagerComponents/DiffieHellman.cs
@@ -0,0 +1,104 @@
+using System;
+using IntXLib;
+using System.Text;
+using System.Security.Cryptography;
+
+namespace ECDH
+{
+ public class EllipticDiffieHellman
+ {
+ protected static readonly RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider();
+ public static readonly IntX DEFAULT_PRIME = (new IntX(1) << 255) - 19;
+ public static readonly IntX DEFAULT_ORDER = (new IntX(1) << 252) + IntX.Parse("27742317777372353535851937790883648493");
+ public static readonly EllipticCurve DEFAULT_CURVE = new EllipticCurve(486662, 1, DEFAULT_PRIME, EllipticCurve.CurveType.Montgomery);
+ public static readonly CurvePoint DEFAULT_GENERATOR = new CurvePoint(9, IntX.Parse("14781619447589544791020593568409986887264606134616475288964881837755586237401"));
+
+ protected readonly EllipticCurve curve;
+ public readonly IntX priv;
+ protected readonly CurvePoint generator, pub;
+
+
+ public EllipticDiffieHellman(EllipticCurve curve, CurvePoint generator, IntX order, byte[] priv = null)
+ {
+ this.curve = curve;
+ this.generator = generator;
+
+ // Generate private key
+ if (priv == null)
+ {
+ byte[] max = order.ToArray();
+ do
+ {
+ byte[] p1 = new byte[5 /*rand.Next(max.Length) + 1*/];
+
+ rand.GetBytes(p1);
+
+ if (p1.Length == max.Length) p1[p1.Length - 1] %= max[max.Length - 1];
+ else p1[p1.Length - 1] &= 127;
+
+ this.priv = DHHelper.FromArray(p1);
+ } while (this.priv<2);
+ }
+ else this.priv = DHHelper.FromArray(priv);
+
+ // Generate public key
+ pub = curve.Multiply(generator, this.priv);
+ }
+
+ public byte[] GetPublicKey()
+ {
+ byte[] p1 = pub.X.ToArray();
+ byte[] p2 = pub.Y.ToArray();
+
+ byte[] ser = new byte[4 + p1.Length + p2.Length];
+ ser[0] = (byte)(p1.Length & 255);
+ ser[1] = (byte)((p1.Length >> 8) & 255);
+ ser[2] = (byte)((p1.Length >> 16) & 255);
+ ser[3] = (byte)((p1.Length >> 24) & 255);
+ Array.Copy(p1, 0, ser, 4, p1.Length);
+ Array.Copy(p2, 0, ser, 4 + p1.Length, p2.Length);
+
+ return ser;
+ }
+
+ public byte[] GetPrivateKey() => priv.ToArray();
+
+ public byte[] GetSharedSecret(byte[] pK)
+ {
+ byte[] p1 = new byte[pK[0] | (pK[1]<<8) | (pK[2]<<16) | (pK[3]<<24)]; // Reconstruct x-axis size
+ byte[] p2 = new byte[pK.Length - p1.Length - 4];
+ Array.Copy(pK, 4, p1, 0, p1.Length);
+ Array.Copy(pK, 4 + p1.Length, p2, 0, p2.Length);
+
+ CurvePoint remotePublic = new CurvePoint(DHHelper.FromArray(p1), DHHelper.FromArray(p2));
+
+ byte[] secret = curve.Multiply(remotePublic, priv).X.ToArray(); // Use the x-coordinate as the shared secret
+
+ // PBKDF2-HMAC-SHA1 (Common shared secret generation method)
+ return new Rfc2898DeriveBytes(secret, Encoding.UTF8.GetBytes("P1sN0R4inb0wPl5P1sPls"), 1000).GetBytes(32);
+ }
+ }
+
+ public static class DHHelper
+ {
+ public static byte[] ToArray(this IntX v)
+ {
+ v.GetInternalState(out uint[] digits, out bool negative);
+ byte[] b = DigitConverter.ToBytes(digits);
+ byte[] b1 = new byte[b.Length];
+ Array.Copy(b, b1, b.Length);
+ b1[b.Length] = (byte)(negative ? 1 : 0);
+ return b1;
+ }
+ public static IntX FromArray(byte[] b)
+ {
+ if (b.Length == 0) return new IntX();
+ byte[] b1 = new byte[b.Length - 1];
+ Array.Copy(b, b1, b1.Length);
+ uint[] u = DigitConverter.FromBytes(b1);
+ return new IntX(u, b[b.Length - 1]==1);
+ }
+ public static bool BitAt(this uint[] data, long index) => (data[index/8]&(1<<(int)(index%8)))!=0;
+ public static IntX Abs(this IntX i) => i < 0 ? -i : i;
+ }
+}
diff --git a/MLAPI/NetworkingManagerComponents/EllipticCurve.cs b/MLAPI/NetworkingManagerComponents/EllipticCurve.cs
new file mode 100644
index 0000000..3a37efe
--- /dev/null
+++ b/MLAPI/NetworkingManagerComponents/EllipticCurve.cs
@@ -0,0 +1,189 @@
+using System;
+using System.Collections.Generic;
+using IntXLib;
+
+namespace ECDH
+{
+ public class CurvePoint
+ {
+ public static readonly CurvePoint POINT_AT_INFINITY = new CurvePoint();
+ public IntX X { get; private set; }
+ public IntX Y { get; private set; }
+ private bool pai = false;
+ public CurvePoint(IntX x, IntX y)
+ {
+ X = x;
+ Y = y;
+ }
+ private CurvePoint() { pai = true; } // Accessing corrdinates causes undocumented behaviour
+ public override string ToString()
+ {
+ return pai ? "(POINT_AT_INFINITY)" : "(" + X + ", " + Y + ")";
+ }
+ }
+
+ public class EllipticCurve
+ {
+ public enum CurveType { Weierstrass, Montgomery }
+
+ protected readonly IntX a, b, modulo;
+ protected readonly CurveType type;
+
+ public EllipticCurve(IntX a, IntX b, IntX modulo, CurveType type = CurveType.Weierstrass)
+ {
+ if (
+ (type==CurveType.Weierstrass && (4 * a * a * a) + (27 * b * b) == 0) || // Unfavourable Weierstrass curves
+ (type==CurveType.Montgomery && b * (a * a - 4)==0) // Unfavourable Montgomery curves
+ ) throw new Exception("Unfavourable curve");
+ this.a = a;
+ this.b = b;
+ this.modulo = modulo;
+ this.type = type;
+ }
+
+ public CurvePoint Add(CurvePoint p1, CurvePoint p2)
+ {
+#if SAFE_MATH
+ CheckOnCurve(p1);
+ CheckOnCurve(p2);
+#endif
+
+ // Special cases
+ if (p1 == CurvePoint.POINT_AT_INFINITY && p2 == CurvePoint.POINT_AT_INFINITY) return CurvePoint.POINT_AT_INFINITY;
+ else if (p1 == CurvePoint.POINT_AT_INFINITY) return p2;
+ else if (p2 == CurvePoint.POINT_AT_INFINITY) return p1;
+ else if (p1.X == p2.X && p1.Y == Inverse(p2).Y) return CurvePoint.POINT_AT_INFINITY;
+
+ IntX x3 = 0, y3 = 0;
+ if (type == CurveType.Weierstrass)
+ {
+ IntX 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));
+ x3 = Mod((slope * slope) - p1.X - p2.X);
+ y3 = Mod(-((slope * x3) + p1.Y - (slope * p1.X)));
+ }
+ else if (type == CurveType.Montgomery)
+ {
+ if ((p1.X == p2.X && p1.Y == p2.Y))
+ {
+ IntX q = 3 * p1.X;
+ IntX w = q * p1.X;
+
+ IntX e = 2 * a;
+ IntX r = e * p1.X;
+
+ IntX t = 2 * b;
+ IntX y = t * p1.Y;
+
+ IntX u = MulInverse(y);
+
+ IntX o = w + e + 1;
+ IntX p = o * u;
+ }
+ IntX 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
+ x3 = Mod(b * co * co - a - p1.X - p2.X);
+ y3 = Mod(((2 * p1.X + p2.X + a) * co) - (b * co * co * co) - p1.Y);
+ }
+
+ return new CurvePoint(x3, y3);
+ }
+
+ public CurvePoint Multiply(CurvePoint p, IntX scalar)
+ {
+ if (scalar <= 0) throw new Exception("Cannot multiply by a scalar which is <= 0");
+ if (p == CurvePoint.POINT_AT_INFINITY) return CurvePoint.POINT_AT_INFINITY;
+
+ CurvePoint p1 = new CurvePoint(p.X, p.Y);
+ scalar.GetInternalState(out uint[] u, out bool b);
+ long high_bit = -1;
+ for (int i = u.Length - 1; i>=0; --i)
+ if (u[i] != 0)
+ {
+ for(int j = 31; j>=0; --j)
+ if ((u[i] & (1<= 0)
+ {
+ p1 = Add(p1, p1); // Double
+ if ((u.BitAt(high_bit)))
+ p1 = Add(p1, p); // Add
+ --high_bit;
+ }
+
+ return p1;
+ }
+
+ protected IntX MulInverse(IntX eq) => MulInverse(eq, modulo);
+ public static IntX MulInverse(IntX eq, IntX modulo)
+ {
+ eq = Mod(eq, modulo);
+ Stack collect = new Stack();
+ IntX v = modulo; // Copy modulo
+ IntX m;
+ while((m = v % eq) != 0)
+ {
+ collect.Push(-v/eq/*-(m.l_div)*/);
+ v = eq;
+ eq = m;
+ }
+ if (collect.Count == 0) return 1;
+ v = 1;
+ m = collect.Pop();
+ while (collect.Count > 0)
+ {
+ eq = m;
+ m = v + (m * collect.Pop());
+ v = eq;
+ }
+ return Mod(m, modulo);
+ }
+
+ public CurvePoint Inverse(CurvePoint p) => Inverse(p, modulo);
+ protected static CurvePoint Inverse(CurvePoint p, IntX modulo) => new CurvePoint(p.X, Mod(-p.Y, modulo));
+
+ public bool IsOnCurve(CurvePoint p)
+ {
+ try { CheckOnCurve(p); }
+ catch { return false; }
+ return true;
+ }
+ protected void CheckOnCurve(CurvePoint p)
+ {
+ if (
+ p!=CurvePoint.POINT_AT_INFINITY && // The point at infinity is asserted to be on the curve
+ (type == CurveType.Weierstrass && Mod(p.Y * p.Y) != Mod((p.X * p.X * p.X) + (p.X * a) + b)) || // Weierstrass formula
+ (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
+ ) throw new Exception("Point is not on curve");
+ }
+
+ protected IntX Mod(IntX b) => Mod(b, modulo);
+
+ private static IntX Mod(IntX x, IntX m)
+ {
+ IntX r = x.Abs() > m ? x % m : x;
+ return r < 0 ? r + m : r;
+ }
+
+ protected static IntX ModPow(IntX x, IntX power, IntX prime)
+ {
+ IntX result = 1;
+ bool setBit = false;
+ while(power > 0)
+ {
+ x %= prime;
+ setBit = (power & 1) == 1;
+ power >>= 1;
+ if (setBit) result *= x;
+ x *= x;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/MLAPI/packages.config b/MLAPI/packages.config
new file mode 100644
index 0000000..f41bab7
--- /dev/null
+++ b/MLAPI/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file