summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/asn1/anssi/ANSSINamedCurves.cs123
-rw-r--r--crypto/src/asn1/anssi/ANSSIObjectIdentifiers.cs13
-rw-r--r--crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs2
-rw-r--r--crypto/src/asn1/nist/NISTNamedCurves.cs52
-rw-r--r--crypto/src/asn1/sec/SECNamedCurves.cs13
-rw-r--r--crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs42
-rw-r--r--crypto/src/asn1/x9/ECNamedCurveTable.cs23
-rw-r--r--crypto/src/asn1/x9/X962NamedCurves.cs12
-rw-r--r--crypto/src/cms/CMSSignedDataGenerator.cs22
-rw-r--r--crypto/src/crypto/ec/CustomNamedCurves.cs560
-rw-r--r--crypto/src/crypto/generators/DsaParametersGenerator.cs57
-rw-r--r--crypto/src/crypto/generators/ECKeyPairGenerator.cs1
-rw-r--r--crypto/src/crypto/tls/AbstractTlsServer.cs4
-rw-r--r--crypto/src/crypto/tls/DtlsClientProtocol.cs215
-rw-r--r--crypto/src/crypto/tls/DtlsProtocol.cs28
-rw-r--r--crypto/src/crypto/tls/DtlsServerProtocol.cs107
-rw-r--r--crypto/src/crypto/tls/TlsClientProtocol.cs81
-rw-r--r--crypto/src/crypto/tls/TlsProtocol.cs30
-rw-r--r--crypto/src/crypto/tls/TlsServerProtocol.cs32
-rw-r--r--crypto/src/math/ec/ECAlgorithms.cs18
-rw-r--r--crypto/src/math/ec/ECCurve.cs175
-rw-r--r--crypto/src/math/ec/ECFieldElement.cs25
-rw-r--r--crypto/src/math/ec/ECPoint.cs307
-rw-r--r--crypto/src/math/ec/LongArray.cs2
-rw-r--r--crypto/src/math/ec/abc/Tnaf.cs171
-rw-r--r--crypto/src/math/ec/custom/djb/Curve25519.cs2
-rw-r--r--crypto/src/math/ec/custom/djb/Curve25519Field.cs2
-rw-r--r--crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/djb/Curve25519Point.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP128R1Curve.cs78
-rw-r--r--crypto/src/math/ec/custom/sec/SecP128R1Field.cs218
-rw-r--r--crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs198
-rw-r--r--crypto/src/math/ec/custom/sec/SecP128R1Point.cs279
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160K1Curve.cs74
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160K1Point.cs269
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R1Curve.cs78
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R1Field.cs186
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs203
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R1Point.cs279
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R2Curve.cs78
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R2Field.cs178
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs218
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R2Point.cs279
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192K1Field.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192K1Point.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192R1Field.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192R1Point.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224K1Field.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224K1Point.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224R1Field.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224R1Point.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256K1Field.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256K1Point.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256R1Field.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256R1Point.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP384R1Field.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP384R1Point.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP521R1Field.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP521R1Point.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113Field.cs180
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113FieldElement.cs213
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113R1Curve.cs188
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113R1Point.cs281
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113R2Curve.cs190
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113R2Point.cs291
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131Field.cs274
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131FieldElement.cs213
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131R1Curve.cs188
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131R1Point.cs287
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131R2Curve.cs190
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131R2Point.cs283
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163Field.cs272
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163FieldElement.cs213
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163K1Curve.cs194
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163K1Point.cs289
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163R1Curve.cs190
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163R1Point.cs283
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163R2Curve.cs188
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163R2Point.cs290
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233Field.cs243
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233FieldElement.cs213
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233K1Curve.cs196
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233K1Point.cs302
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233R1Curve.cs188
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233R1Point.cs282
-rw-r--r--crypto/src/math/ec/custom/sec/SecT239Field.cs249
-rw-r--r--crypto/src/math/ec/custom/sec/SecT239FieldElement.cs213
-rw-r--r--crypto/src/math/ec/custom/sec/SecT239K1Curve.cs194
-rw-r--r--crypto/src/math/ec/custom/sec/SecT239K1Point.cs297
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283Field.cs335
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283FieldElement.cs213
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283K1Curve.cs194
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283K1Point.cs296
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283R1Curve.cs188
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283R1Point.cs282
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409Field.cs244
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409FieldElement.cs213
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409K1Curve.cs194
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409K1Point.cs296
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409R1Curve.cs188
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409R1Point.cs282
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571Field.cs251
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571FieldElement.cs213
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571K1Curve.cs196
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571K1Point.cs296
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571R1Curve.cs193
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571R1Point.cs286
-rw-r--r--crypto/src/math/ec/multiplier/WTauNafMultiplier.cs71
-rw-r--r--crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs6
-rw-r--r--crypto/src/math/raw/Interleave.cs70
-rw-r--r--crypto/src/math/raw/Mod.cs (renamed from crypto/src/math/ec/Mod.cs)2
-rw-r--r--crypto/src/math/raw/Nat.cs (renamed from crypto/src/math/ec/Nat.cs)42
-rw-r--r--crypto/src/math/raw/Nat128.cs856
-rw-r--r--crypto/src/math/raw/Nat160.cs874
-rw-r--r--crypto/src/math/raw/Nat192.cs (renamed from crypto/src/math/ec/custom/sec/Nat192.cs)88
-rw-r--r--crypto/src/math/raw/Nat224.cs (renamed from crypto/src/math/ec/custom/sec/Nat224.cs)2
-rw-r--r--crypto/src/math/raw/Nat256.cs (renamed from crypto/src/math/ec/custom/sec/Nat256.cs)89
-rw-r--r--crypto/src/math/raw/Nat320.cs98
-rw-r--r--crypto/src/math/raw/Nat384.cs (renamed from crypto/src/math/ec/custom/sec/Nat384.cs)2
-rw-r--r--crypto/src/math/raw/Nat448.cs100
-rw-r--r--crypto/src/math/raw/Nat512.cs (renamed from crypto/src/math/ec/custom/sec/Nat512.cs)2
-rw-r--r--crypto/src/math/raw/Nat576.cs102
-rw-r--r--crypto/src/security/DotNetUtilities.cs4
-rw-r--r--crypto/src/util/Arrays.cs58
132 files changed, 17886 insertions, 792 deletions
diff --git a/crypto/src/asn1/anssi/ANSSINamedCurves.cs b/crypto/src/asn1/anssi/ANSSINamedCurves.cs
new file mode 100644
index 000000000..04e30bb07
--- /dev/null
+++ b/crypto/src/asn1/anssi/ANSSINamedCurves.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Anssi
+{
+    public class AnssiNamedCurves
+    {
+        private static ECCurve ConfigureCurve(ECCurve curve)
+        {
+            return curve;
+        }
+
+        private static BigInteger FromHex(string hex)
+        {
+            return new BigInteger(1, Hex.Decode(hex));
+        }
+
+        /*
+         * FRP256v1
+         */
+        internal class Frp256v1Holder
+            : X9ECParametersHolder
+        {
+            private Frp256v1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Frp256v1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger p = FromHex("F1FD178C0B3AD58F10126DE8CE42435B3961ADBCABC8CA6DE8FCF353D86E9C03");
+                BigInteger a = FromHex("F1FD178C0B3AD58F10126DE8CE42435B3961ADBCABC8CA6DE8FCF353D86E9C00");
+                BigInteger b = FromHex("EE353FCA5428A9300D4ABA754A44C00FDFEC0C9AE4B1A1803075ED967B7BB73F");
+                byte[] S = null;
+                BigInteger n = FromHex("F1FD178C0B3AD58F10126DE8CE42435B53DC67E140D2BF941FFDD459C6D655E1");
+                BigInteger h = BigInteger.One;
+
+                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "B6B3D4C356C139EB31183D4749D423958C27D2DCAF98B70164C97A2DD98F5CFF"
+                    + "6142E0F7C8B204911F9271F0F3ECEF8C2701C307E8E4C9E183115A1554062CFB"));
+
+                return new X9ECParameters(curve, G, n, h, S);
+            }
+        };
+
+
+        private static readonly IDictionary objIds = Platform.CreateHashtable();
+        private static readonly IDictionary curves = Platform.CreateHashtable();
+        private static readonly IDictionary names = Platform.CreateHashtable();
+
+        private static void DefineCurve(
+            string					name,
+            DerObjectIdentifier		oid,
+            X9ECParametersHolder	holder)
+        {
+            objIds.Add(Platform.ToLowerInvariant(name), oid);
+            names.Add(oid, name);
+            curves.Add(oid, holder);
+        }
+
+        static AnssiNamedCurves()
+        {
+            DefineCurve("FRP256v1", AnssiObjectIdentifiers.FRP256v1, Frp256v1Holder.Instance);
+        }
+
+        public static X9ECParameters GetByName(
+            string name)
+        {
+            DerObjectIdentifier oid = GetOid(name);
+            return oid == null ? null : GetByOid(oid);
+        }
+
+        /**
+         * return the X9ECParameters object for the named curve represented by
+         * the passed in object identifier. Null if the curve isn't present.
+         *
+         * @param oid an object identifier representing a named curve, if present.
+         */
+        public static X9ECParameters GetByOid(
+            DerObjectIdentifier oid)
+        {
+            X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
+            return holder == null ? null : holder.Parameters;
+        }
+
+        /**
+         * return the object identifier signified by the passed in name. Null
+         * if there is no object identifier associated with name.
+         *
+         * @return the object identifier associated with name, if present.
+         */
+        public static DerObjectIdentifier GetOid(
+            string name)
+        {
+            return (DerObjectIdentifier)objIds[Platform.ToLowerInvariant(name)];
+        }
+
+        /**
+         * return the named curve name represented by the given object identifier.
+         */
+        public static string GetName(
+            DerObjectIdentifier oid)
+        {
+            return (string)names[oid];
+        }
+
+        /**
+         * returns an enumeration containing the name strings for curves
+         * contained in this structure.
+         */
+        public static IEnumerable Names
+        {
+            get { return new EnumerableProxy(names.Values); }
+        }
+    }
+}
diff --git a/crypto/src/asn1/anssi/ANSSIObjectIdentifiers.cs b/crypto/src/asn1/anssi/ANSSIObjectIdentifiers.cs
new file mode 100644
index 000000000..d230832b5
--- /dev/null
+++ b/crypto/src/asn1/anssi/ANSSIObjectIdentifiers.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Anssi
+{
+    public sealed class AnssiObjectIdentifiers
+    {
+        private AnssiObjectIdentifiers()
+        {
+        }
+
+        public static readonly DerObjectIdentifier FRP256v1 = new DerObjectIdentifier("1.2.250.1.223.101.256.1");
+    }
+}
diff --git a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
index ca57c283d..32d3103af 100644
--- a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
+++ b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
@@ -150,7 +150,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
          */
         public static IEnumerable Names
         {
-            get { return new EnumerableProxy(objIds.Keys); }
+            get { return new EnumerableProxy(names.Values); }
         }
 
         public static ECDomainParameters GetByName(
diff --git a/crypto/src/asn1/nist/NISTNamedCurves.cs b/crypto/src/asn1/nist/NISTNamedCurves.cs
index 0e82dda7a..f6c1598c6 100644
--- a/crypto/src/asn1/nist/NISTNamedCurves.cs
+++ b/crypto/src/asn1/nist/NISTNamedCurves.cs
@@ -21,45 +21,40 @@ namespace Org.BouncyCastle.Asn1.Nist
         private static readonly IDictionary objIds = Platform.CreateHashtable();
         private static readonly IDictionary names = Platform.CreateHashtable();
 
-        private static void DefineCurve(
+        private static void DefineCurveAlias(
             string				name,
             DerObjectIdentifier	oid)
         {
-            objIds.Add(name, oid);
+            objIds.Add(Platform.ToUpperInvariant(name), oid);
             names.Add(oid, name);
         }
 
         static NistNamedCurves()
         {
-            DefineCurve("B-571", SecObjectIdentifiers.SecT571r1);
-            DefineCurve("B-409", SecObjectIdentifiers.SecT409r1);
-            DefineCurve("B-283", SecObjectIdentifiers.SecT283r1);
-            DefineCurve("B-233", SecObjectIdentifiers.SecT233r1);
-            DefineCurve("B-163", SecObjectIdentifiers.SecT163r2);
-            DefineCurve("K-571", SecObjectIdentifiers.SecT571k1);
-            DefineCurve("K-409", SecObjectIdentifiers.SecT409k1);
-            DefineCurve("K-283", SecObjectIdentifiers.SecT283k1);
-            DefineCurve("K-233", SecObjectIdentifiers.SecT233k1);
-            DefineCurve("K-163", SecObjectIdentifiers.SecT163k1);
-            DefineCurve("P-521", SecObjectIdentifiers.SecP521r1);
-            DefineCurve("P-384", SecObjectIdentifiers.SecP384r1);
-            DefineCurve("P-256", SecObjectIdentifiers.SecP256r1);
-            DefineCurve("P-224", SecObjectIdentifiers.SecP224r1);
-            DefineCurve("P-192", SecObjectIdentifiers.SecP192r1);
+            DefineCurveAlias("B-163", SecObjectIdentifiers.SecT163r2);
+            DefineCurveAlias("B-233", SecObjectIdentifiers.SecT233r1);
+            DefineCurveAlias("B-283", SecObjectIdentifiers.SecT283r1);
+            DefineCurveAlias("B-409", SecObjectIdentifiers.SecT409r1);
+            DefineCurveAlias("B-571", SecObjectIdentifiers.SecT571r1);
+
+            DefineCurveAlias("K-163", SecObjectIdentifiers.SecT163k1);
+            DefineCurveAlias("K-233", SecObjectIdentifiers.SecT233k1);
+            DefineCurveAlias("K-283", SecObjectIdentifiers.SecT283k1);
+            DefineCurveAlias("K-409", SecObjectIdentifiers.SecT409k1);
+            DefineCurveAlias("K-571", SecObjectIdentifiers.SecT571k1);
+
+            DefineCurveAlias("P-192", SecObjectIdentifiers.SecP192r1);
+            DefineCurveAlias("P-224", SecObjectIdentifiers.SecP224r1);
+            DefineCurveAlias("P-256", SecObjectIdentifiers.SecP256r1);
+            DefineCurveAlias("P-384", SecObjectIdentifiers.SecP384r1);
+            DefineCurveAlias("P-521", SecObjectIdentifiers.SecP521r1);
         }
 
         public static X9ECParameters GetByName(
             string name)
         {
-            DerObjectIdentifier oid = (DerObjectIdentifier) objIds[
-                Platform.ToUpperInvariant(name)];
-
-            if (oid != null)
-            {
-                return GetByOid(oid);
-            }
-
-            return null;
+            DerObjectIdentifier oid = GetOid(name);
+            return oid == null ? null : GetByOid(oid);
         }
 
         /**
@@ -83,8 +78,7 @@ namespace Org.BouncyCastle.Asn1.Nist
         public static DerObjectIdentifier GetOid(
             string name)
         {
-            return (DerObjectIdentifier) objIds[
-                Platform.ToUpperInvariant(name)];
+            return (DerObjectIdentifier) objIds[Platform.ToUpperInvariant(name)];
         }
 
         /**
@@ -102,7 +96,7 @@ namespace Org.BouncyCastle.Asn1.Nist
         */
         public static IEnumerable Names
         {
-            get { return new EnumerableProxy(objIds.Keys); }
+            get { return new EnumerableProxy(names.Values); }
         }
     }
 }
diff --git a/crypto/src/asn1/sec/SECNamedCurves.cs b/crypto/src/asn1/sec/SECNamedCurves.cs
index 60d456ef0..0bd60b0b8 100644
--- a/crypto/src/asn1/sec/SECNamedCurves.cs
+++ b/crypto/src/asn1/sec/SECNamedCurves.cs
@@ -1154,7 +1154,7 @@ namespace Org.BouncyCastle.Asn1.Sec
             DerObjectIdentifier		oid,
             X9ECParametersHolder	holder)
         {
-            objIds.Add(name, oid);
+            objIds.Add(Platform.ToLowerInvariant(name), oid);
             names.Add(oid, name);
             curves.Add(oid, holder);
         }
@@ -1200,9 +1200,7 @@ namespace Org.BouncyCastle.Asn1.Sec
         public static X9ECParameters GetByName(
             string name)
         {
-            DerObjectIdentifier oid = (DerObjectIdentifier)
-                objIds[Platform.ToLowerInvariant(name)];
-
+            DerObjectIdentifier oid = GetOid(name);
             return oid == null ? null : GetByOid(oid);
         }
 
@@ -1215,8 +1213,7 @@ namespace Org.BouncyCastle.Asn1.Sec
         public static X9ECParameters GetByOid(
             DerObjectIdentifier oid)
         {
-            X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
-
+            X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
             return holder == null ? null : holder.Parameters;
         }
 
@@ -1238,7 +1235,7 @@ namespace Org.BouncyCastle.Asn1.Sec
         public static string GetName(
             DerObjectIdentifier oid)
         {
-            return (string) names[oid];
+            return (string)names[oid];
         }
 
         /**
@@ -1247,7 +1244,7 @@ namespace Org.BouncyCastle.Asn1.Sec
          */
         public static IEnumerable Names
         {
-            get { return new EnumerableProxy(objIds.Keys); }
+            get { return new EnumerableProxy(names.Values); }
         }
     }
 }
diff --git a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
index 05060c109..f476619a7 100644
--- a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
+++ b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
@@ -387,35 +387,33 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
             DerObjectIdentifier		oid,
             X9ECParametersHolder	holder)
         {
-            objIds.Add(name, oid);
+            objIds.Add(Platform.ToLowerInvariant(name), oid);
             names.Add(oid, name);
             curves.Add(oid, holder);
         }
 
         static TeleTrusTNamedCurves()
         {
-            DefineCurve("brainpoolp160r1", TeleTrusTObjectIdentifiers.BrainpoolP160R1, BrainpoolP160r1Holder.Instance);
-            DefineCurve("brainpoolp160t1", TeleTrusTObjectIdentifiers.BrainpoolP160T1, BrainpoolP160t1Holder.Instance);
-            DefineCurve("brainpoolp192r1", TeleTrusTObjectIdentifiers.BrainpoolP192R1, BrainpoolP192r1Holder.Instance);
-            DefineCurve("brainpoolp192t1", TeleTrusTObjectIdentifiers.BrainpoolP192T1, BrainpoolP192t1Holder.Instance);
-            DefineCurve("brainpoolp224r1", TeleTrusTObjectIdentifiers.BrainpoolP224R1, BrainpoolP224r1Holder.Instance);
-            DefineCurve("brainpoolp224t1", TeleTrusTObjectIdentifiers.BrainpoolP224T1, BrainpoolP224t1Holder.Instance);
-            DefineCurve("brainpoolp256r1", TeleTrusTObjectIdentifiers.BrainpoolP256R1, BrainpoolP256r1Holder.Instance);
-            DefineCurve("brainpoolp256t1", TeleTrusTObjectIdentifiers.BrainpoolP256T1, BrainpoolP256t1Holder.Instance);
-            DefineCurve("brainpoolp320r1", TeleTrusTObjectIdentifiers.BrainpoolP320R1, BrainpoolP320r1Holder.Instance);
-            DefineCurve("brainpoolp320t1", TeleTrusTObjectIdentifiers.BrainpoolP320T1, BrainpoolP320t1Holder.Instance);
-            DefineCurve("brainpoolp384r1", TeleTrusTObjectIdentifiers.BrainpoolP384R1, BrainpoolP384r1Holder.Instance);
-            DefineCurve("brainpoolp384t1", TeleTrusTObjectIdentifiers.BrainpoolP384T1, BrainpoolP384t1Holder.Instance);
-            DefineCurve("brainpoolp512r1", TeleTrusTObjectIdentifiers.BrainpoolP512R1, BrainpoolP512r1Holder.Instance);
-            DefineCurve("brainpoolp512t1", TeleTrusTObjectIdentifiers.BrainpoolP512T1, BrainpoolP512t1Holder.Instance);
+            DefineCurve("brainpoolP160r1", TeleTrusTObjectIdentifiers.BrainpoolP160R1, BrainpoolP160r1Holder.Instance);
+            DefineCurve("brainpoolP160t1", TeleTrusTObjectIdentifiers.BrainpoolP160T1, BrainpoolP160t1Holder.Instance);
+            DefineCurve("brainpoolP192r1", TeleTrusTObjectIdentifiers.BrainpoolP192R1, BrainpoolP192r1Holder.Instance);
+            DefineCurve("brainpoolP192t1", TeleTrusTObjectIdentifiers.BrainpoolP192T1, BrainpoolP192t1Holder.Instance);
+            DefineCurve("brainpoolP224r1", TeleTrusTObjectIdentifiers.BrainpoolP224R1, BrainpoolP224r1Holder.Instance);
+            DefineCurve("brainpoolP224t1", TeleTrusTObjectIdentifiers.BrainpoolP224T1, BrainpoolP224t1Holder.Instance);
+            DefineCurve("brainpoolP256r1", TeleTrusTObjectIdentifiers.BrainpoolP256R1, BrainpoolP256r1Holder.Instance);
+            DefineCurve("brainpoolP256t1", TeleTrusTObjectIdentifiers.BrainpoolP256T1, BrainpoolP256t1Holder.Instance);
+            DefineCurve("brainpoolP320r1", TeleTrusTObjectIdentifiers.BrainpoolP320R1, BrainpoolP320r1Holder.Instance);
+            DefineCurve("brainpoolP320t1", TeleTrusTObjectIdentifiers.BrainpoolP320T1, BrainpoolP320t1Holder.Instance);
+            DefineCurve("brainpoolP384r1", TeleTrusTObjectIdentifiers.BrainpoolP384R1, BrainpoolP384r1Holder.Instance);
+            DefineCurve("brainpoolP384t1", TeleTrusTObjectIdentifiers.BrainpoolP384T1, BrainpoolP384t1Holder.Instance);
+            DefineCurve("brainpoolP512r1", TeleTrusTObjectIdentifiers.BrainpoolP512R1, BrainpoolP512r1Holder.Instance);
+            DefineCurve("brainpoolP512t1", TeleTrusTObjectIdentifiers.BrainpoolP512T1, BrainpoolP512t1Holder.Instance);
         }
 
         public static X9ECParameters GetByName(
             string name)
         {
-            DerObjectIdentifier oid = (DerObjectIdentifier)
-                objIds[Platform.ToLowerInvariant(name)];
-
+            DerObjectIdentifier oid = GetOid(name);
             return oid == null ? null : GetByOid(oid);
         }
 
@@ -428,8 +426,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
         public static X9ECParameters GetByOid(
             DerObjectIdentifier oid)
         {
-            X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
-
+            X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
             return holder == null ? null : holder.Parameters;
         }
 
@@ -451,17 +448,16 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
         public static string GetName(
             DerObjectIdentifier oid)
         {
-            return (string) names[oid];
+            return (string)names[oid];
         }
 
-
         /**
          * returns an enumeration containing the name strings for curves
          * contained in this structure.
          */
         public static IEnumerable Names
         {
-            get { return new EnumerableProxy(objIds.Keys); }
+            get { return new EnumerableProxy(names.Values); }
         }
 
         public static DerObjectIdentifier GetOid(
diff --git a/crypto/src/asn1/x9/ECNamedCurveTable.cs b/crypto/src/asn1/x9/ECNamedCurveTable.cs
index 0030d376b..d8315c16f 100644
--- a/crypto/src/asn1/x9/ECNamedCurveTable.cs
+++ b/crypto/src/asn1/x9/ECNamedCurveTable.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections;
 
+using Org.BouncyCastle.Asn1.Anssi;
 using Org.BouncyCastle.Asn1.Nist;
 using Org.BouncyCastle.Asn1.Sec;
 using Org.BouncyCastle.Asn1.TeleTrust;
@@ -32,12 +33,17 @@ namespace Org.BouncyCastle.Asn1.X9
 
             if (ecP == null)
             {
+                ecP = NistNamedCurves.GetByName(name);
+            }
+
+            if (ecP == null)
+            {
                 ecP = TeleTrusTNamedCurves.GetByName(name);
             }
 
             if (ecP == null)
             {
-                ecP = NistNamedCurves.GetByName(name);
+                ecP = AnssiNamedCurves.GetByName(name);
             }
 
             return ecP;
@@ -60,12 +66,17 @@ namespace Org.BouncyCastle.Asn1.X9
 
             if (oid == null)
             {
+                oid = NistNamedCurves.GetOid(name);
+            }
+
+            if (oid == null)
+            {
                 oid = TeleTrusTNamedCurves.GetOid(name);
             }
 
             if (oid == null)
             {
-                oid = NistNamedCurves.GetOid(name);
+                oid = AnssiNamedCurves.GetOid(name);
             }
 
             return oid;
@@ -87,12 +98,17 @@ namespace Org.BouncyCastle.Asn1.X9
                 ecP = SecNamedCurves.GetByOid(oid);
             }
 
+            // NOTE: All the NIST curves are currently from SEC, so no point in redundant OID lookup
+
             if (ecP == null)
             {
                 ecP = TeleTrusTNamedCurves.GetByOid(oid);
             }
 
-            // NOTE: All the NIST curves are currently from SEC, so no point in redundant OID lookup
+            if (ecP == null)
+            {
+                ecP = AnssiNamedCurves.GetByOid(oid);
+            }
 
             return ecP;
         }
@@ -111,6 +127,7 @@ namespace Org.BouncyCastle.Asn1.X9
                 CollectionUtilities.AddRange(v, SecNamedCurves.Names);
                 CollectionUtilities.AddRange(v, NistNamedCurves.Names);
                 CollectionUtilities.AddRange(v, TeleTrusTNamedCurves.Names);
+                CollectionUtilities.AddRange(v, AnssiNamedCurves.Names);
                 return v;
             }
         }
diff --git a/crypto/src/asn1/x9/X962NamedCurves.cs b/crypto/src/asn1/x9/X962NamedCurves.cs
index 6b76c4eb4..a9ea0240c 100644
--- a/crypto/src/asn1/x9/X962NamedCurves.cs
+++ b/crypto/src/asn1/x9/X962NamedCurves.cs
@@ -666,7 +666,7 @@ namespace Org.BouncyCastle.Asn1.X9
             DerObjectIdentifier		oid,
             X9ECParametersHolder	holder)
         {
-            objIds.Add(name, oid);
+            objIds.Add(Platform.ToLowerInvariant(name), oid);
             names.Add(oid, name);
             curves.Add(oid, holder);
         }
@@ -701,8 +701,7 @@ namespace Org.BouncyCastle.Asn1.X9
         public static X9ECParameters GetByName(
             string name)
         {
-            DerObjectIdentifier oid = (DerObjectIdentifier)objIds[Platform.ToLowerInvariant(name)];
-
+            DerObjectIdentifier oid = GetOid(name);
             return oid == null ? null : GetByOid(oid);
         }
 
@@ -715,8 +714,7 @@ namespace Org.BouncyCastle.Asn1.X9
         public static X9ECParameters GetByOid(
             DerObjectIdentifier oid)
         {
-            X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
-
+            X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
             return holder == null ? null : holder.Parameters;
         }
 
@@ -738,7 +736,7 @@ namespace Org.BouncyCastle.Asn1.X9
         public static string GetName(
             DerObjectIdentifier oid)
         {
-            return (string) names[oid];
+            return (string)names[oid];
         }
 
         /**
@@ -747,7 +745,7 @@ namespace Org.BouncyCastle.Asn1.X9
          */
         public static IEnumerable Names
         {
-            get { return new EnumerableProxy(objIds.Keys); }
+            get { return new EnumerableProxy(names.Values); }
         }
     }
 }
diff --git a/crypto/src/cms/CMSSignedDataGenerator.cs b/crypto/src/cms/CMSSignedDataGenerator.cs
index f31105c41..114b9631d 100644
--- a/crypto/src/cms/CMSSignedDataGenerator.cs
+++ b/crypto/src/cms/CMSSignedDataGenerator.cs
@@ -93,19 +93,25 @@ namespace Org.BouncyCastle.Cms
             {
                 AlgorithmIdentifier digAlgId = DigestAlgorithmID;
 				string digestName = Helper.GetDigestAlgName(digestOID);
-				IDigest dig = Helper.GetDigestInstance(digestName);
 
 				string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID);
 				ISigner sig = Helper.GetSignatureInstance(signatureName);
 
-				// TODO Optimise the case where more than one signer with same digest
-				if (content != null)
+                byte[] hash;
+                if (outer._digests.Contains(digestOID))
                 {
-                    content.Write(new DigOutputStream(dig));
-				}
-
-				byte[] hash = DigestUtilities.DoFinal(dig);
-				outer._digests.Add(digestOID, hash.Clone());
+                    hash = (byte[])outer._digests[digestOID];
+                }
+                else
+                {
+                    IDigest dig = Helper.GetDigestInstance(digestName);
+                    if (content != null)
+                    {
+                        content.Write(new DigOutputStream(dig));
+                    }
+                    hash = DigestUtilities.DoFinal(dig);
+                    outer._digests.Add(digestOID, hash.Clone());
+                }
 
 				sig.Init(true, new ParametersWithRandom(key, random));
 #if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT
diff --git a/crypto/src/crypto/ec/CustomNamedCurves.cs b/crypto/src/crypto/ec/CustomNamedCurves.cs
index 8ff1d24c7..9b7935523 100644
--- a/crypto/src/crypto/ec/CustomNamedCurves.cs
+++ b/crypto/src/crypto/ec/CustomNamedCurves.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Collections;
 
 using Org.BouncyCastle.Asn1;
@@ -69,14 +69,110 @@ namespace Org.BouncyCastle.Crypto.EC
         }
 
         /*
+         * secp128r1
+         */
+        internal class SecP128R1Holder
+            : X9ECParametersHolder
+        {
+            private SecP128R1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecP128R1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("000E0D4D696E6768756151750CC03A4473D03679");
+                ECCurve curve = ConfigureCurve(new SecP128R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "161FF7528B899B2D0C28607CA52C5B86"
+                    + "CF5AC8395BAFEB13C02DA292DDED7A83"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * secp160k1
+         */
+        internal class SecP160K1Holder
+            : X9ECParametersHolder
+        {
+            private SecP160K1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecP160K1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = null;
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16),
+                    new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16),
+                    new BigInteger[]{
+                        new BigInteger("9162fbe73984472a0a9e", 16),
+                        new BigInteger("-96341f1138933bc2f505", 16) },
+                    new BigInteger[]{
+                        new BigInteger("127971af8721782ecffa3", 16),
+                        new BigInteger("9162fbe73984472a0a9e", 16) },
+                    new BigInteger("9162fbe73984472a0a9d0590", 16),
+                    new BigInteger("96341f1138933bc2f503fd44", 16),
+                    176);
+                ECCurve curve = ConfigureCurveGlv(new SecP160K1Curve(), glv);
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
+                    + "938CF935318FDCED6BC28286531733C3F03C4FEE"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * secp160r1
+         */
+        internal class SecP160R1Holder
+            : X9ECParametersHolder
+        {
+            private SecP160R1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecP160R1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("1053CDE42C14D696E67687561517533BF3F83345");
+                ECCurve curve = ConfigureCurve(new SecP160R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "4A96B5688EF573284664698968C38BB913CBFC82"
+                    + "23A628553168947D59DCC912042351377AC5FB32"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * secp160r2
+         */
+        internal class SecP160R2Holder
+            : X9ECParametersHolder
+        {
+            private SecP160R2Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecP160R2Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("B99B99B099B323E02709A4D696E6768756151751");
+                ECCurve curve = ConfigureCurve(new SecP160R2Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "52DCB034293A117E1F4FF11B30F7199D3144CE6D"
+                    + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
          * secp192k1
          */
-        internal class Secp192k1Holder
+        internal class SecP192K1Holder
             : X9ECParametersHolder
         {
-            private Secp192k1Holder() { }
+            private SecP192K1Holder() { }
 
-            internal static readonly X9ECParametersHolder Instance = new Secp192k1Holder();
+            internal static readonly X9ECParametersHolder Instance = new SecP192K1Holder();
 
             protected override X9ECParameters CreateParameters()
             {
@@ -104,12 +200,12 @@ namespace Org.BouncyCastle.Crypto.EC
         /*
          * secp192r1
          */
-        internal class Secp192r1Holder
+        internal class SecP192R1Holder
             : X9ECParametersHolder
         {
-            private Secp192r1Holder() { }
+            private SecP192R1Holder() { }
 
-            internal static readonly X9ECParametersHolder Instance = new Secp192r1Holder();
+            internal static readonly X9ECParametersHolder Instance = new SecP192R1Holder();
 
             protected override X9ECParameters CreateParameters()
             {
@@ -125,12 +221,12 @@ namespace Org.BouncyCastle.Crypto.EC
         /*
          * secp224k1
          */
-        internal class Secp224k1Holder
+        internal class SecP224K1Holder
             : X9ECParametersHolder
         {
-            private Secp224k1Holder() { }
+            private SecP224K1Holder() { }
 
-            internal static readonly X9ECParametersHolder Instance = new Secp224k1Holder();
+            internal static readonly X9ECParametersHolder Instance = new SecP224K1Holder();
 
             protected override X9ECParameters CreateParameters()
             {
@@ -158,12 +254,12 @@ namespace Org.BouncyCastle.Crypto.EC
         /*
          * secp224r1
          */
-        internal class Secp224r1Holder
+        internal class SecP224R1Holder
             : X9ECParametersHolder
         {
-            private Secp224r1Holder() { }
+            private SecP224R1Holder() { }
 
-            internal static readonly X9ECParametersHolder Instance = new Secp224r1Holder();
+            internal static readonly X9ECParametersHolder Instance = new SecP224R1Holder();
 
             protected override X9ECParameters CreateParameters()
             {
@@ -179,12 +275,12 @@ namespace Org.BouncyCastle.Crypto.EC
         /*
          * secp256k1
          */
-        internal class Secp256k1Holder
+        internal class SecP256K1Holder
             : X9ECParametersHolder
         {
-            private Secp256k1Holder() {}
+            private SecP256K1Holder() {}
 
-            internal static readonly X9ECParametersHolder Instance = new Secp256k1Holder();
+            internal static readonly X9ECParametersHolder Instance = new SecP256K1Holder();
 
             protected override X9ECParameters CreateParameters()
             {
@@ -212,12 +308,12 @@ namespace Org.BouncyCastle.Crypto.EC
         /*
          * secp256r1
          */
-        internal class Secp256r1Holder
+        internal class SecP256R1Holder
             : X9ECParametersHolder
         {
-            private Secp256r1Holder() {}
+            private SecP256R1Holder() {}
 
-            internal static readonly X9ECParametersHolder Instance = new Secp256r1Holder();
+            internal static readonly X9ECParametersHolder Instance = new SecP256R1Holder();
 
             protected override X9ECParameters CreateParameters()
             {
@@ -233,12 +329,12 @@ namespace Org.BouncyCastle.Crypto.EC
         /*
          * secp384r1
          */
-        internal class Secp384r1Holder
+        internal class SecP384R1Holder
             : X9ECParametersHolder
         {
-            private Secp384r1Holder() { }
+            private SecP384R1Holder() { }
 
-            internal static readonly X9ECParametersHolder Instance = new Secp384r1Holder();
+            internal static readonly X9ECParametersHolder Instance = new SecP384R1Holder();
 
             protected override X9ECParameters CreateParameters()
             {
@@ -254,12 +350,12 @@ namespace Org.BouncyCastle.Crypto.EC
         /*
          * secp521r1
          */
-        internal class Secp521r1Holder
+        internal class SecP521R1Holder
             : X9ECParametersHolder
         {
-            private Secp521r1Holder() { }
+            private SecP521R1Holder() { }
 
-            internal static readonly X9ECParametersHolder Instance = new Secp521r1Holder();
+            internal static readonly X9ECParametersHolder Instance = new SecP521R1Holder();
 
             protected override X9ECParameters CreateParameters()
             {
@@ -272,43 +368,425 @@ namespace Org.BouncyCastle.Crypto.EC
             }
         }
 
+        /*
+         * sect113r1
+         */
+        internal class SecT113R1Holder
+            : X9ECParametersHolder
+        {
+            private SecT113R1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT113R1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("10E723AB14D696E6768756151756FEBF8FCB49A9");
+                ECCurve curve = ConfigureCurve(new SecT113R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "009D73616F35F4AB1407D73562C10F"
+                    + "00A52830277958EE84D1315ED31886"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect113r2
+         */
+        internal class SecT113R2Holder
+            : X9ECParametersHolder
+        {
+            private SecT113R2Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT113R2Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("10C0FB15760860DEF1EEF4D696E676875615175D");
+                ECCurve curve = ConfigureCurve(new SecT113R2Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "01A57A6A7B26CA5EF52FCDB8164797"
+                    + "00B3ADC94ED1FE674C06E695BABA1D"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect131r1
+         */
+        internal class SecT131R1Holder
+            : X9ECParametersHolder
+        {
+            private SecT131R1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT131R1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("4D696E676875615175985BD3ADBADA21B43A97E2");
+                ECCurve curve = ConfigureCurve(new SecT131R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "0081BAF91FDF9833C40F9C181343638399"
+                    + "078C6E7EA38C001F73C8134B1B4EF9E150"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect131r2
+         */
+        internal class SecT131R2Holder
+            : X9ECParametersHolder
+        {
+            private SecT131R2Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT131R2Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("985BD3ADBAD4D696E676875615175A21B43A97E3");
+                ECCurve curve = ConfigureCurve(new SecT131R2Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "0356DCD8F2F95031AD652D23951BB366A8"
+                    + "0648F06D867940A5366D9E265DE9EB240F"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect163k1
+         */
+        internal class SecT163K1Holder
+            : X9ECParametersHolder
+        {
+            private SecT163K1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT163K1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = null;
+                ECCurve curve = ConfigureCurve(new SecT163K1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"
+                    + "0289070FB05D38FF58321F2E800536D538CCDAA3D9"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect163r1
+         */
+        internal class SecT163R1Holder
+            : X9ECParametersHolder
+        {
+            private SecT163R1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT163R1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("24B7B137C8A14D696E6768756151756FD0DA2E5C");
+                ECCurve curve = ConfigureCurve(new SecT163R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "0369979697AB43897789566789567F787A7876A654"
+                    + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect163r2
+         */
+        internal class SecT163R2Holder
+            : X9ECParametersHolder
+        {
+            private SecT163R2Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT163R2Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("85E25BFE5C86226CDB12016F7553F9D0E693A268");
+                ECCurve curve = ConfigureCurve(new SecT163R2Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "03F0EBA16286A2D57EA0991168D4994637E8343E36"
+                    + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect233k1
+         */
+        internal class SecT233K1Holder
+            : X9ECParametersHolder
+        {
+            private SecT233K1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT233K1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = null;
+                ECCurve curve = ConfigureCurve(new SecT233K1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"
+                    + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect233r1
+         */
+        internal class SecT233R1Holder
+            : X9ECParametersHolder
+        {
+            private SecT233R1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT233R1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3");
+                ECCurve curve = ConfigureCurve(new SecT233R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"
+                    + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect239k1
+         */
+        internal class SecT239K1Holder
+            : X9ECParametersHolder
+        {
+            private SecT239K1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT239K1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = null;
+                ECCurve curve = ConfigureCurve(new SecT239K1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"
+                    + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect283k1
+         */
+        internal class SecT283K1Holder
+            : X9ECParametersHolder
+        {
+            private SecT283K1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT283K1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = null;
+                ECCurve curve = ConfigureCurve(new SecT283K1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"
+                    + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect283r1
+         */
+        internal class SecT283R1Holder
+            : X9ECParametersHolder
+        {
+            private SecT283R1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT283R1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE");
+                ECCurve curve = ConfigureCurve(new SecT283R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"
+                    + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect409k1
+         */
+        internal class SecT409K1Holder
+            : X9ECParametersHolder
+        {
+            private SecT409K1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT409K1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = null;
+                ECCurve curve = ConfigureCurve(new SecT409K1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"
+                    + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect409r1
+         */
+        internal class SecT409R1Holder
+            : X9ECParametersHolder
+        {
+            private SecT409R1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT409R1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("4099B5A457F9D69F79213D094C4BCD4D4262210B");
+                ECCurve curve = ConfigureCurve(new SecT409R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"
+                    + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect571k1
+         */
+        internal class SecT571K1Holder
+            : X9ECParametersHolder
+        {
+            private SecT571K1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT571K1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = null;
+                ECCurve curve = ConfigureCurve(new SecT571K1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"
+                    + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+        /*
+         * sect571r1
+         */
+        internal class SecT571R1Holder
+            : X9ECParametersHolder
+        {
+            private SecT571R1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SecT571R1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("2AA058F73A0E33AB486B0F610410C53A7F132310");
+                ECCurve curve = ConfigureCurve(new SecT571R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"
+                    + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        };
+
+
         private static readonly IDictionary nameToCurve = Platform.CreateHashtable();
         private static readonly IDictionary nameToOid = Platform.CreateHashtable();
         private static readonly IDictionary oidToCurve = Platform.CreateHashtable();
         private static readonly IDictionary oidToName = Platform.CreateHashtable();
+        private static readonly IList names = Platform.CreateArrayList();
 
         private static void DefineCurve(string name, X9ECParametersHolder holder)
         {
+            names.Add(name);
+            name = Platform.ToLowerInvariant(name);
             nameToCurve.Add(name, holder);
         }
 
-        private static void DefineCurve(string name, DerObjectIdentifier oid, X9ECParametersHolder holder)
+        private static void DefineCurveWithOid(string name, DerObjectIdentifier oid, X9ECParametersHolder holder)
         {
-            nameToCurve.Add(name, holder);
-            nameToOid.Add(name, oid);
+            names.Add(name);
             oidToName.Add(oid, name);
             oidToCurve.Add(oid, holder);
+            name = Platform.ToLowerInvariant(name);
+            nameToOid.Add(name, oid);
+            nameToCurve.Add(name, holder);
         }
 
-        private static void DefineCurveAlias(string alias, DerObjectIdentifier oid)
+        private static void DefineCurveAlias(string name, DerObjectIdentifier oid)
         {
-            alias = Platform.ToLowerInvariant(alias);
-            nameToOid.Add(alias, oid);
-            nameToCurve.Add(alias, oidToCurve[oid]);
+            object curve = oidToCurve[oid];
+            if (curve == null)
+                throw new InvalidOperationException();
+
+            name = Platform.ToLowerInvariant(name);
+            nameToOid.Add(name, oid);
+            nameToCurve.Add(name, curve);
         }
 
         static CustomNamedCurves()
         {
             DefineCurve("curve25519", Curve25519Holder.Instance);
 
-            DefineCurve("secp192k1", SecObjectIdentifiers.SecP192k1, Secp192k1Holder.Instance);
-            DefineCurve("secp192r1", SecObjectIdentifiers.SecP192r1, Secp192r1Holder.Instance);
-            DefineCurve("secp224k1", SecObjectIdentifiers.SecP224k1, Secp224k1Holder.Instance);
-            DefineCurve("secp224r1", SecObjectIdentifiers.SecP224r1, Secp224r1Holder.Instance);
-            DefineCurve("secp256k1", SecObjectIdentifiers.SecP256k1, Secp256k1Holder.Instance);
-            DefineCurve("secp256r1", SecObjectIdentifiers.SecP256r1, Secp256r1Holder.Instance);
-            DefineCurve("secp384r1", SecObjectIdentifiers.SecP384r1, Secp384r1Holder.Instance);
-            DefineCurve("secp521r1", SecObjectIdentifiers.SecP521r1, Secp521r1Holder.Instance);
+            //DefineCurveWithOid("secp112r1", SecObjectIdentifiers.SecP112r1, SecP112R1Holder.Instance);
+            //DefineCurveWithOid("secp112r2", SecObjectIdentifiers.SecP112r2, SecP112R2Holder.Instance);
+            DefineCurveWithOid("secp128r1", SecObjectIdentifiers.SecP128r1, SecP128R1Holder.Instance);
+            //DefineCurveWithOid("secp128r2", SecObjectIdentifiers.SecP128r2, SecP128R2Holder.Instance);
+            DefineCurveWithOid("secp160k1", SecObjectIdentifiers.SecP160k1, SecP160K1Holder.Instance);
+            DefineCurveWithOid("secp160r1", SecObjectIdentifiers.SecP160r1, SecP160R1Holder.Instance);
+            DefineCurveWithOid("secp160r2", SecObjectIdentifiers.SecP160r2, SecP160R2Holder.Instance);
+            DefineCurveWithOid("secp192k1", SecObjectIdentifiers.SecP192k1, SecP192K1Holder.Instance);
+            DefineCurveWithOid("secp192r1", SecObjectIdentifiers.SecP192r1, SecP192R1Holder.Instance);
+            DefineCurveWithOid("secp224k1", SecObjectIdentifiers.SecP224k1, SecP224K1Holder.Instance);
+            DefineCurveWithOid("secp224r1", SecObjectIdentifiers.SecP224r1, SecP224R1Holder.Instance);
+            DefineCurveWithOid("secp256k1", SecObjectIdentifiers.SecP256k1, SecP256K1Holder.Instance);
+            DefineCurveWithOid("secp256r1", SecObjectIdentifiers.SecP256r1, SecP256R1Holder.Instance);
+            DefineCurveWithOid("secp384r1", SecObjectIdentifiers.SecP384r1, SecP384R1Holder.Instance);
+            DefineCurveWithOid("secp521r1", SecObjectIdentifiers.SecP521r1, SecP521R1Holder.Instance);
+
+            DefineCurveWithOid("sect113r1", SecObjectIdentifiers.SecT113r1, SecT113R1Holder.Instance);
+            DefineCurveWithOid("sect113r2", SecObjectIdentifiers.SecT113r2, SecT113R2Holder.Instance);
+            DefineCurveWithOid("sect131r1", SecObjectIdentifiers.SecT131r1, SecT131R1Holder.Instance);
+            DefineCurveWithOid("sect131r2", SecObjectIdentifiers.SecT131r2, SecT131R2Holder.Instance);
+            DefineCurveWithOid("sect163k1", SecObjectIdentifiers.SecT163k1, SecT163K1Holder.Instance);
+            DefineCurveWithOid("sect163r1", SecObjectIdentifiers.SecT163r1, SecT163R1Holder.Instance);
+            DefineCurveWithOid("sect163r2", SecObjectIdentifiers.SecT163r2, SecT163R2Holder.Instance);
+            DefineCurveWithOid("sect233k1", SecObjectIdentifiers.SecT233k1, SecT233K1Holder.Instance);
+            DefineCurveWithOid("sect233r1", SecObjectIdentifiers.SecT233r1, SecT233R1Holder.Instance);
+            DefineCurveWithOid("sect239k1", SecObjectIdentifiers.SecT239k1, SecT239K1Holder.Instance);
+            DefineCurveWithOid("sect283k1", SecObjectIdentifiers.SecT283k1, SecT283K1Holder.Instance);
+            DefineCurveWithOid("sect283r1", SecObjectIdentifiers.SecT283r1, SecT283R1Holder.Instance);
+            DefineCurveWithOid("sect409k1", SecObjectIdentifiers.SecT409k1, SecT409K1Holder.Instance);
+            DefineCurveWithOid("sect409r1", SecObjectIdentifiers.SecT409r1, SecT409R1Holder.Instance);
+            DefineCurveWithOid("sect571k1", SecObjectIdentifiers.SecT571k1, SecT571K1Holder.Instance);
+            DefineCurveWithOid("sect571r1", SecObjectIdentifiers.SecT571r1, SecT571R1Holder.Instance);
+
+            DefineCurveAlias("B-163", SecObjectIdentifiers.SecT163r2);
+            DefineCurveAlias("B-233", SecObjectIdentifiers.SecT233r1);
+            DefineCurveAlias("B-283", SecObjectIdentifiers.SecT283r1);
+            DefineCurveAlias("B-409", SecObjectIdentifiers.SecT409r1);
+            DefineCurveAlias("B-571", SecObjectIdentifiers.SecT571r1);
+
+            DefineCurveAlias("K-163", SecObjectIdentifiers.SecT163k1);
+            DefineCurveAlias("K-233", SecObjectIdentifiers.SecT233k1);
+            DefineCurveAlias("K-283", SecObjectIdentifiers.SecT283k1);
+            DefineCurveAlias("K-409", SecObjectIdentifiers.SecT409k1);
+            DefineCurveAlias("K-571", SecObjectIdentifiers.SecT571k1);
 
             DefineCurveAlias("P-192", SecObjectIdentifiers.SecP192r1);
             DefineCurveAlias("P-224", SecObjectIdentifiers.SecP224r1);
@@ -360,7 +838,7 @@ namespace Org.BouncyCastle.Crypto.EC
          */
         public static IEnumerable Names
         {
-            get { return new EnumerableProxy(nameToCurve.Keys); }
+            get { return new EnumerableProxy(names); }
         }
     }
 }
diff --git a/crypto/src/crypto/generators/DsaParametersGenerator.cs b/crypto/src/crypto/generators/DsaParametersGenerator.cs
index cf6343a16..d7ae3ec54 100644
--- a/crypto/src/crypto/generators/DsaParametersGenerator.cs
+++ b/crypto/src/crypto/generators/DsaParametersGenerator.cs
@@ -31,13 +31,11 @@ namespace Org.BouncyCastle.Crypto.Generators
             this.digest = digest;
         }
 
-        /**
-         * initialise the key generator.
-         *
-         * @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments)
-         * @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
-         * @param random random byte source.
-         */
+        /// <summary>Initialise the generator</summary>
+        /// <remarks>This form can only be used for older DSA (pre-DSA2) parameters</remarks>
+        /// <param name="size">the size of keys in bits (from 512 up to 1024, and a multiple of 64)</param>
+        /// <param name="certainty">measure of robustness of primes (at least 80 for FIPS 186-2 compliance)</param>
+        /// <param name="random">the source of randomness to use</param>
         public virtual void Init(
             int             size,
             int             certainty,
@@ -53,14 +51,9 @@ namespace Org.BouncyCastle.Crypto.Generators
             this.random = random;
         }
 
-        /**
-         * Initialise the key generator for DSA 2.
-         * <p>
-         *     Use this init method if you need to generate parameters for DSA 2 keys.
-         * </p>
-         *
-         * @param params  DSA 2 key generation parameters.
-         */
+        /// <summary>Initialise the generator for DSA 2</summary>
+        /// <remarks>You must use this Init method if you need to generate parameters for DSA 2 keys</remarks>
+        /// <param name="parameters">An instance of <c>DsaParameterGenerationParameters</c> used to configure this generator</param>
         public virtual void Init(DsaParameterGenerationParameters parameters)
         {
             // TODO Should we enforce the minimum 'certainty' values as per C.3 Table C.1?
@@ -84,35 +77,8 @@ namespace Org.BouncyCastle.Crypto.Generators
                 throw new InvalidOperationException("Digest output size too small for value of N");
         }
 
-//        /**
-//         * add value to b, returning the result in a. The a value is treated
-//         * as a BigInteger of length (a.Length * 8) bits. The result is
-//         * modulo 2^a.Length in case of overflow.
-//         */
-//        private static void Add(
-//            byte[]  a,
-//            byte[]  b,
-//            int     value)
-//        {
-//            int     x = (b[b.Length - 1] & 0xff) + value;
-//
-//            a[b.Length - 1] = (byte)x;
-//            x = (int) ((uint) x >>8);
-//
-//            for (int i = b.Length - 2; i >= 0; i--)
-//            {
-//                x += (b[i] & 0xff);
-//                a[i] = (byte)x;
-//                x = (int) ((uint) x >>8);
-//            }
-//        }
-
-        /**
-         * which Generates the p and g values from the given parameters,
-         * returning the DsaParameters object.
-         * <p>
-         * Note: can take a while...</p>
-         */
+        /// <summary>Generates a set of <c>DsaParameters</c></summary>
+        /// <remarks>Can take a while...</remarks>
         public virtual DsaParameters GenerateParameters()
         {
             return use186_3
@@ -242,8 +208,7 @@ namespace Org.BouncyCastle.Crypto.Generators
                 BigInteger U = new BigInteger(1, output).Mod(BigInteger.One.ShiftLeft(N - 1));
 
 // 7. q = 2^(N–1) + U + 1 – ( U mod 2).
-                BigInteger q = BigInteger.One.ShiftLeft(N - 1).Add(U).Add(BigInteger.One).Subtract(
-                    U.Mod(BigInteger.Two));
+                BigInteger q = U.SetBit(0).SetBit(N - 1);
 
 // 8. Test whether or not q is prime as specified in Appendix C.3.
                 // TODO Review C.3 for primality checking
diff --git a/crypto/src/crypto/generators/ECKeyPairGenerator.cs b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
index 6e777c74c..d4afff750 100644
--- a/crypto/src/crypto/generators/ECKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
@@ -78,6 +78,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 
                 X9ECParameters ecps = FindECCurveByOid(oid);
 
+                this.publicKeyParamSet = oid;
                 this.parameters = new ECDomainParameters(
                     ecps.Curve, ecps.G, ecps.N, ecps.H, ecps.GetSeed());
             }
diff --git a/crypto/src/crypto/tls/AbstractTlsServer.cs b/crypto/src/crypto/tls/AbstractTlsServer.cs
index 7fe3fcbe5..c3e250fd8 100644
--- a/crypto/src/crypto/tls/AbstractTlsServer.cs
+++ b/crypto/src/crypto/tls/AbstractTlsServer.cs
@@ -140,7 +140,11 @@ namespace Org.BouncyCastle.Crypto.Tls
             if (clientExtensions != null)
             {
                 this.mEncryptThenMacOffered = TlsExtensionsUtilities.HasEncryptThenMacExtension(clientExtensions);
+
                 this.mMaxFragmentLengthOffered = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(clientExtensions);
+                if (mMaxFragmentLengthOffered >= 0 && !MaxFragmentLength.IsValid((byte)mMaxFragmentLengthOffered))
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
                 this.mTruncatedHMacOffered = TlsExtensionsUtilities.HasTruncatedHMacExtension(clientExtensions);
 
                 this.mSupportedSignatureAlgorithms = TlsUtilities.GetSignatureAlgorithmsExtension(clientExtensions);
diff --git a/crypto/src/crypto/tls/DtlsClientProtocol.cs b/crypto/src/crypto/tls/DtlsClientProtocol.cs
index 76635065c..411e7cca2 100644
--- a/crypto/src/crypto/tls/DtlsClientProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsClientProtocol.cs
@@ -112,41 +112,12 @@ namespace Org.BouncyCastle.Crypto.Tls
                 throw new TlsFatalAlert(AlertDescription.unexpected_message);
             }
 
-            if (state.maxFragmentLength >= 0)
-            {
-                int plainTextLimit = 1 << (8 + state.maxFragmentLength);
-                recordLayer.SetPlaintextLimit(plainTextLimit);
-            }
-
-            securityParameters.cipherSuite = state.selectedCipherSuite;
-            securityParameters.compressionAlgorithm = (byte)state.selectedCompressionMethod;
-            securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.clientContext, state.selectedCipherSuite);
-
-            /*
-             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
-             * a verify_data_length equal to 12. This includes all existing cipher suites.
-             */
-            securityParameters.verifyDataLength = 12;
-
             handshake.NotifyHelloComplete();
 
-            bool resumedSession = state.selectedSessionID.Length > 0 && state.tlsSession != null
-                && Arrays.AreEqual(state.selectedSessionID, state.tlsSession.SessionID);
+            ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength);
 
-            if (resumedSession)
+            if (state.resumedSession)
             {
-                if (securityParameters.CipherSuite != state.sessionParameters.CipherSuite
-                    || securityParameters.CompressionAlgorithm != state.sessionParameters.CompressionAlgorithm)
-                {
-                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-                }
-
-                IDictionary sessionServerExtensions = state.sessionParameters.ReadServerExtensions();
-
-                // TODO Check encrypt-then-MAC extension and maybe others
-
-                securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
-
                 securityParameters.masterSecret = Arrays.Clone(state.sessionParameters.MasterSecret);
                 recordLayer.InitPendingEpoch(state.client.GetCipher());
 
@@ -366,12 +337,14 @@ namespace Org.BouncyCastle.Crypto.Tls
             if (state.tlsSession != null)
             {
                 state.sessionParameters = new SessionParameters.Builder()
-                    .SetCipherSuite(securityParameters.cipherSuite)
-                    .SetCompressionAlgorithm(securityParameters.compressionAlgorithm)
-                    .SetMasterSecret(securityParameters.masterSecret)
+                    .SetCipherSuite(securityParameters.CipherSuite)
+                    .SetCompressionAlgorithm(securityParameters.CompressionAlgorithm)
+                    .SetMasterSecret(securityParameters.MasterSecret)
                     .SetPeerCertificate(serverCertificate)
-                    .SetPskIdentity(securityParameters.pskIdentity)
-                    .SetSrpIdentity(securityParameters.srpIdentity)
+                    .SetPskIdentity(securityParameters.PskIdentity)
+                    .SetSrpIdentity(securityParameters.SrpIdentity)
+                    // TODO Consider filtering extensions that aren't relevant to resumed sessions
+                    .SetServerExtensions(state.serverExtensions)
                     .Build();
 
                 state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters);
@@ -599,8 +572,10 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             MemoryStream buf = new MemoryStream(body, false);
 
-            ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
-            ReportServerVersion(state, server_version);
+            {
+                ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
+                ReportServerVersion(state, server_version);
+            }
 
             securityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
 
@@ -608,24 +583,24 @@ namespace Org.BouncyCastle.Crypto.Tls
             if (state.selectedSessionID.Length > 32)
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
             state.client.NotifySessionID(state.selectedSessionID);
+            state.resumedSession = state.selectedSessionID.Length > 0 && state.tlsSession != null
+                && Arrays.AreEqual(state.selectedSessionID, state.tlsSession.SessionID);
 
-            state.selectedCipherSuite = TlsUtilities.ReadUint16(buf);
-            if (!Arrays.Contains(state.offeredCipherSuites, state.selectedCipherSuite)
-                || state.selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
-                || CipherSuite.IsScsv(state.selectedCipherSuite)
-                || !TlsUtilities.IsValidCipherSuiteForVersion(state.selectedCipherSuite, server_version))
+            int selectedCipherSuite = TlsUtilities.ReadUint16(buf);
+            if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite)
+                || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
+                || CipherSuite.IsScsv(selectedCipherSuite)
+                || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.clientContext.ServerVersion))
             {
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
             }
+            ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.illegal_parameter);
+            state.client.NotifySelectedCipherSuite(selectedCipherSuite);
 
-            ValidateSelectedCipherSuite(state.selectedCipherSuite, AlertDescription.illegal_parameter);
-
-            state.client.NotifySelectedCipherSuite(state.selectedCipherSuite);
-
-            state.selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
-            if (!Arrays.Contains(state.offeredCompressionMethods, (byte)state.selectedCompressionMethod))
+            byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
+            if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-            state.client.NotifySelectedCompressionMethod((byte)state.selectedCompressionMethod);
+            state.client.NotifySelectedCompressionMethod(selectedCompressionMethod);
 
             /*
              * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
@@ -643,16 +618,16 @@ namespace Org.BouncyCastle.Crypto.Tls
              */
 
             // Integer -> byte[]
-            IDictionary serverExtensions = TlsProtocol.ReadExtensions(buf);
+            state.serverExtensions = TlsProtocol.ReadExtensions(buf);
 
             /*
              * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
              * extended client hello message. However, see RFC 5746 exception below. We always include
              * the SCSV, so an Extended Server Hello is always allowed.
              */
-            if (serverExtensions != null)
+            if (state.serverExtensions != null)
             {
-                foreach (int extType in serverExtensions.Keys)
+                foreach (int extType in state.serverExtensions.Keys)
                 {
                     /*
                      * RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a
@@ -679,64 +654,92 @@ namespace Org.BouncyCastle.Crypto.Tls
                      * extensions appearing in the client hello, and send a server hello containing no
                      * extensions[.]
                      */
-                    // TODO[sessions]
-    //                if (this.mResumedSession)
-    //                {
-    //                    // TODO[compat-gnutls] GnuTLS test server sends server extensions e.g. ec_point_formats
-    //                    // TODO[compat-openssl] OpenSSL test server sends server extensions e.g. ec_point_formats
-    //                    // TODO[compat-polarssl] PolarSSL test server sends server extensions e.g. ec_point_formats
-    ////                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-    //                }
+                    if (state.resumedSession)
+                    {
+                        // TODO[compat-gnutls] GnuTLS test server sends server extensions e.g. ec_point_formats
+                        // TODO[compat-openssl] OpenSSL test server sends server extensions e.g. ec_point_formats
+                        // TODO[compat-polarssl] PolarSSL test server sends server extensions e.g. ec_point_formats
+                        //throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                    }
                 }
+            }
 
+            /*
+             * RFC 5746 3.4. Client Behavior: Initial Handshake
+             */
+            {
                 /*
-                 * RFC 5746 3.4. Client Behavior: Initial Handshake
+                 * When a ServerHello is received, the client MUST check if it includes the
+                 * "renegotiation_info" extension:
                  */
+                byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, ExtensionType.renegotiation_info);
+                if (renegExtData != null)
                 {
                     /*
-                     * When a ServerHello is received, the client MUST check if it includes the
-                     * "renegotiation_info" extension:
-                     */
-                    byte[] renegExtData = (byte[])serverExtensions[ExtensionType.renegotiation_info];
-                    if (renegExtData != null)
-                    {
-                        /*
-                         * If the extension is present, set the secure_renegotiation flag to TRUE. The
-                         * client MUST then verify that the length of the "renegotiated_connection"
-                         * field is zero, and if it is not, MUST abort the handshake (by sending a fatal
-                         * handshake_failure alert).
-                         */
-                        state.secure_renegotiation = true;
-
-                        if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
-                            throw new TlsFatalAlert(AlertDescription.handshake_failure);
-                    }
+                        * If the extension is present, set the secure_renegotiation flag to TRUE. The
+                        * client MUST then verify that the length of the "renegotiated_connection"
+                        * field is zero, and if it is not, MUST abort the handshake (by sending a fatal
+                        * handshake_failure alert).
+                        */
+                    state.secure_renegotiation = true;
+
+                    if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
+                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
                 }
+            }
 
-                /*
-                 * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
-                 * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
-                 * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
-                 * client.
-                 */
-                bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(serverExtensions);
-                if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(state.selectedCipherSuite))
+            // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming
+            state.client.NotifySecureRenegotiation(state.secure_renegotiation);
+
+            IDictionary sessionClientExtensions = state.clientExtensions, sessionServerExtensions = state.serverExtensions;
+            if (state.resumedSession)
+            {
+                if (selectedCipherSuite != state.sessionParameters.CipherSuite
+                    || selectedCompressionMethod != state.sessionParameters.CompressionAlgorithm)
+                {
                     throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
 
-                securityParameters.encryptThenMac = serverSentEncryptThenMAC;
+                sessionClientExtensions = null;
+                sessionServerExtensions = state.sessionParameters.ReadServerExtensions();
+            }
 
-                securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(serverExtensions);
+            securityParameters.cipherSuite = selectedCipherSuite;
+            securityParameters.compressionAlgorithm = selectedCompressionMethod;
 
-                state.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.clientExtensions, serverExtensions,
-                    AlertDescription.illegal_parameter);
+            if (sessionServerExtensions != null)
+            {
+                {
+                    /*
+                     * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
+                     * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
+                     * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
+                     * client.
+                     */
+                    bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
+                    if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(securityParameters.CipherSuite))
+                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                    securityParameters.encryptThenMac = serverSentEncryptThenMAC;
+                }
 
-                securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(serverExtensions);
+                securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
+
+                securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
+                    sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
 
-                state.allowCertificateStatus = TlsUtilities.HasExpectedEmptyExtensionData(serverExtensions,
-                    ExtensionType.status_request, AlertDescription.illegal_parameter);
+                securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);
+
+                /*
+                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be
+                 * sent in a session resumption handshake.
+                 */
+                state.allowCertificateStatus = !state.resumedSession
+                    && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
+                        AlertDescription.illegal_parameter);
 
-                state.expectSessionTicket = TlsUtilities.HasExpectedEmptyExtensionData(serverExtensions,
-                    ExtensionType.session_ticket, AlertDescription.illegal_parameter);
+                state.expectSessionTicket = !state.resumedSession
+                    && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
+                        AlertDescription.illegal_parameter);
             }
 
             /*
@@ -746,12 +749,19 @@ namespace Org.BouncyCastle.Crypto.Tls
              * that do not use the extended master secret [..]. (and see 5.2, 5.3)
              */
 
-            state.client.NotifySecureRenegotiation(state.secure_renegotiation);
-
-            if (state.clientExtensions != null)
+            if (sessionClientExtensions != null)
             {
-                state.client.ProcessServerExtensions(serverExtensions);
+                state.client.ProcessServerExtensions(sessionServerExtensions);
             }
+
+            securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.clientContext,
+                securityParameters.CipherSuite);
+
+            /*
+             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
+             * a verify_data_length equal to 12. This includes all existing cipher suites.
+             */
+            securityParameters.verifyDataLength = 12;
         }
 
         protected virtual void ProcessServerKeyExchange(ClientHandshakeState state, byte[] body)
@@ -813,11 +823,10 @@ namespace Org.BouncyCastle.Crypto.Tls
             internal int[] offeredCipherSuites = null;
             internal byte[] offeredCompressionMethods = null;
             internal IDictionary clientExtensions = null;
+            internal IDictionary serverExtensions = null;
             internal byte[] selectedSessionID = null;
-            internal int selectedCipherSuite = -1;
-            internal short selectedCompressionMethod = -1;
+            internal bool resumedSession = false;
             internal bool secure_renegotiation = false;
-            internal short maxFragmentLength = -1;
             internal bool allowCertificateStatus = false;
             internal bool expectSessionTicket = false;
             internal TlsKeyExchange keyExchange = null;
diff --git a/crypto/src/crypto/tls/DtlsProtocol.cs b/crypto/src/crypto/tls/DtlsProtocol.cs
index 6d62c5a90..e4ebd436c 100644
--- a/crypto/src/crypto/tls/DtlsProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsProtocol.cs
@@ -33,12 +33,32 @@ namespace Org.BouncyCastle.Crypto.Tls
         }
 
         /// <exception cref="IOException"/>
-        protected static short EvaluateMaxFragmentLengthExtension(IDictionary clientExtensions, IDictionary serverExtensions,
-            byte alertDescription)
+        internal static void ApplyMaxFragmentLengthExtension(DtlsRecordLayer recordLayer, short maxFragmentLength)
+        {
+            if (maxFragmentLength >= 0)
+            {
+                if (!MaxFragmentLength.IsValid((byte)maxFragmentLength))
+                    throw new TlsFatalAlert(AlertDescription.internal_error); 
+
+                int plainTextLimit = 1 << (8 + maxFragmentLength);
+                recordLayer.SetPlaintextLimit(plainTextLimit);
+            }
+        }
+
+        /// <exception cref="IOException"/>
+        protected static short EvaluateMaxFragmentLengthExtension(bool resumedSession, IDictionary clientExtensions,
+            IDictionary serverExtensions, byte alertDescription)
         {
             short maxFragmentLength = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(serverExtensions);
-            if (maxFragmentLength >= 0 && maxFragmentLength != TlsExtensionsUtilities.GetMaxFragmentLengthExtension(clientExtensions))
-                throw new TlsFatalAlert(alertDescription);
+            if (maxFragmentLength >= 0)
+            {
+                if (!MaxFragmentLength.IsValid((byte)maxFragmentLength)
+                    || (!resumedSession && maxFragmentLength != TlsExtensionsUtilities
+                        .GetMaxFragmentLengthExtension(clientExtensions)))
+                {
+                    throw new TlsFatalAlert(alertDescription);
+                }
+            }
             return maxFragmentLength;
         }
 
diff --git a/crypto/src/crypto/tls/DtlsServerProtocol.cs b/crypto/src/crypto/tls/DtlsServerProtocol.cs
index f148eb7d7..9c7caf290 100644
--- a/crypto/src/crypto/tls/DtlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsServerProtocol.cs
@@ -94,24 +94,9 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             {
                 byte[] serverHelloBody = GenerateServerHello(state);
-    
-                if (state.maxFragmentLength >= 0)
-                {
-                    int plainTextLimit = 1 << (8 + state.maxFragmentLength);
-                    recordLayer.SetPlaintextLimit(plainTextLimit);
-                }
-    
-                securityParameters.cipherSuite = state.selectedCipherSuite;
-                securityParameters.compressionAlgorithm = (byte)state.selectedCompressionMethod;
-                securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.serverContext,
-                    state.selectedCipherSuite);
 
-                /*
-                 * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length
-                 * has a verify_data_length equal to 12. This includes all existing cipher suites.
-                 */
-                securityParameters.verifyDataLength = 12;
-    
+                ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength);
+
                 handshake.SendMessage(HandshakeType.server_hello, serverHelloBody);
             }
 
@@ -302,17 +287,19 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             MemoryStream buf = new MemoryStream();
 
-            ProtocolVersion server_version = state.server.GetServerVersion();
-            if (!server_version.IsEqualOrEarlierVersionOf(state.serverContext.ClientVersion))
-                throw new TlsFatalAlert(AlertDescription.internal_error);
+            {
+                ProtocolVersion server_version = state.server.GetServerVersion();
+                if (!server_version.IsEqualOrEarlierVersionOf(state.serverContext.ClientVersion))
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
 
-            // TODO Read RFCs for guidance on the expected record layer version number
-            // recordStream.setReadVersion(server_version);
-            // recordStream.setWriteVersion(server_version);
-            // recordStream.setRestrictReadVersion(true);
-            state.serverContext.SetServerVersion(server_version);
+                // TODO Read RFCs for guidance on the expected record layer version number
+                // recordStream.setReadVersion(server_version);
+                // recordStream.setWriteVersion(server_version);
+                // recordStream.setRestrictReadVersion(true);
+                state.serverContext.SetServerVersion(server_version);
 
-            TlsUtilities.WriteVersion(state.serverContext.ServerVersion, buf);
+                TlsUtilities.WriteVersion(state.serverContext.ServerVersion, buf);
+            }
 
             buf.Write(securityParameters.ServerRandom, 0, securityParameters.ServerRandom.Length);
 
@@ -322,23 +309,24 @@ namespace Org.BouncyCastle.Crypto.Tls
              */
             TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);
 
-            state.selectedCipherSuite = state.server.GetSelectedCipherSuite();
-            if (!Arrays.Contains(state.offeredCipherSuites, state.selectedCipherSuite)
-                || state.selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
-                || CipherSuite.IsScsv(state.selectedCipherSuite)
-                || !TlsUtilities.IsValidCipherSuiteForVersion(state.selectedCipherSuite, server_version))
+            int selectedCipherSuite = state.server.GetSelectedCipherSuite();
+            if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite)
+                || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
+                || CipherSuite.IsScsv(selectedCipherSuite)
+                || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.serverContext.ServerVersion))
             {
                 throw new TlsFatalAlert(AlertDescription.internal_error);
             }
+            ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.internal_error);
+            securityParameters.cipherSuite = selectedCipherSuite;
 
-            ValidateSelectedCipherSuite(state.selectedCipherSuite, AlertDescription.internal_error);
-
-            state.selectedCompressionMethod = state.server.GetSelectedCompressionMethod();
-            if (!Arrays.Contains(state.offeredCompressionMethods, (byte)state.selectedCompressionMethod))
+            byte selectedCompressionMethod = state.server.GetSelectedCompressionMethod();
+            if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
                 throw new TlsFatalAlert(AlertDescription.internal_error);
+            securityParameters.compressionAlgorithm = selectedCompressionMethod;
 
-            TlsUtilities.WriteUint16(state.selectedCipherSuite, buf);
-            TlsUtilities.WriteUint8((byte)state.selectedCompressionMethod, buf);
+            TlsUtilities.WriteUint16(selectedCipherSuite, buf);
+            TlsUtilities.WriteUint8(selectedCompressionMethod, buf);
 
             state.serverExtensions = state.server.GetServerExtensions();
 
@@ -375,24 +363,45 @@ namespace Org.BouncyCastle.Crypto.Tls
                 TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.serverExtensions);
             }
 
+            /*
+             * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+             * extensions appearing in the client hello, and send a server hello containing no
+             * extensions.
+             */
+
             if (state.serverExtensions != null)
             {
                 securityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(state.serverExtensions);
 
-                state.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.clientExtensions, state.serverExtensions,
-                    AlertDescription.internal_error);
+                securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
+                    state.clientExtensions, state.serverExtensions, AlertDescription.internal_error);
 
                 securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(state.serverExtensions);
 
-                state.allowCertificateStatus = TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions,
-                    ExtensionType.status_request, AlertDescription.internal_error);
+                /*
+                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
+                 * a session resumption handshake.
+                 */
+                state.allowCertificateStatus = !state.resumedSession
+                    && TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.status_request,
+                        AlertDescription.internal_error);
 
-                state.expectSessionTicket = TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions,
-                    ExtensionType.session_ticket, AlertDescription.internal_error);
+                state.expectSessionTicket = !state.resumedSession
+                    && TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.session_ticket,
+                        AlertDescription.internal_error);
 
                 TlsProtocol.WriteExtensions(buf, state.serverExtensions);
             }
 
+            securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.serverContext,
+                securityParameters.CipherSuite);
+
+            /*
+             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length
+             * has a verify_data_length equal to 12. This includes all existing cipher suites.
+             */
+            securityParameters.verifyDataLength = 12;
+
             return buf.ToArray();
         }
 
@@ -628,16 +637,14 @@ namespace Org.BouncyCastle.Crypto.Tls
         {
             internal TlsServer server = null;
             internal TlsServerContextImpl serverContext = null;
-            internal int[] offeredCipherSuites;
-            internal byte[] offeredCompressionMethods;
-            internal IDictionary clientExtensions;
-            internal int selectedCipherSuite = -1;
-            internal short selectedCompressionMethod = -1;
+            internal int[] offeredCipherSuites = null;
+            internal byte[] offeredCompressionMethods = null;
+            internal IDictionary clientExtensions = null;
+            internal IDictionary serverExtensions = null;
+            internal bool resumedSession = false;
             internal bool secure_renegotiation = false;
-            internal short maxFragmentLength = -1;
             internal bool allowCertificateStatus = false;
             internal bool expectSessionTicket = false;
-            internal IDictionary serverExtensions = null;
             internal TlsKeyExchange keyExchange = null;
             internal TlsCredentials serverCredentials = null;
             internal CertificateRequest certificateRequest = null;
diff --git a/crypto/src/crypto/tls/TlsClientProtocol.cs b/crypto/src/crypto/tls/TlsClientProtocol.cs
index 5b9e81b3f..7b8439acc 100644
--- a/crypto/src/crypto/tls/TlsClientProtocol.cs
+++ b/crypto/src/crypto/tls/TlsClientProtocol.cs
@@ -224,24 +224,10 @@ namespace Org.BouncyCastle.Crypto.Tls
                     ReceiveServerHelloMessage(buf);
                     this.mConnectionState = CS_SERVER_HELLO;
 
-                    if (this.mSecurityParameters.maxFragmentLength >= 0)
-                    {
-                        int plainTextLimit = 1 << (8 + this.mSecurityParameters.maxFragmentLength);
-                        mRecordStream.SetPlaintextLimit(plainTextLimit);
-                    }
-
-                    this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context,
-                        this.mSecurityParameters.CipherSuite);
-
-                    /*
-                     * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify
-                     * verify_data_length has a verify_data_length equal to 12. This includes all
-                     * existing cipher suites.
-                     */
-                    this.mSecurityParameters.verifyDataLength = 12;
-
                     this.mRecordStream.NotifyHelloComplete();
 
+                    ApplyMaxFragmentLengthExtension();
+
                     if (this.mResumedSession)
                     {
                         this.mSecurityParameters.masterSecret = Arrays.Clone(this.mSessionParameters.MasterSecret);
@@ -558,21 +544,23 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
         {
-            ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
-            if (server_version.IsDtls)
-                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            {
+                ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
+                if (server_version.IsDtls)
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
 
-            // Check that this matches what the server is Sending in the record layer
-            if (!server_version.Equals(this.mRecordStream.ReadVersion))
-                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                // Check that this matches what the server is Sending in the record layer
+                if (!server_version.Equals(this.mRecordStream.ReadVersion))
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
 
-            ProtocolVersion client_version = Context.ClientVersion;
-            if (!server_version.IsEqualOrEarlierVersionOf(client_version))
-                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                ProtocolVersion client_version = Context.ClientVersion;
+                if (!server_version.IsEqualOrEarlierVersionOf(client_version))
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
 
-            this.mRecordStream.SetWriteVersion(server_version);
-            ContextAdmin.SetServerVersion(server_version);
-            this.mTlsClient.NotifyServerVersion(server_version);
+                this.mRecordStream.SetWriteVersion(server_version);
+                ContextAdmin.SetServerVersion(server_version);
+                this.mTlsClient.NotifyServerVersion(server_version);
+            }
 
             /*
              * Read the server random
@@ -582,9 +570,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             this.mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
             if (this.mSelectedSessionID.Length > 32)
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-
             this.mTlsClient.NotifySessionID(this.mSelectedSessionID);
-
             this.mResumedSession = this.mSelectedSessionID.Length > 0 && this.mTlsSession != null
                 && Arrays.AreEqual(this.mSelectedSessionID, this.mTlsSession.SessionID);
 
@@ -596,11 +582,10 @@ namespace Org.BouncyCastle.Crypto.Tls
             if (!Arrays.Contains(this.mOfferedCipherSuites, selectedCipherSuite)
                 || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
                 || CipherSuite.IsScsv(selectedCipherSuite)
-                || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, server_version))
+                || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
             {
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
             }
-
             this.mTlsClient.NotifySelectedCipherSuite(selectedCipherSuite);
 
             /*
@@ -610,7 +595,6 @@ namespace Org.BouncyCastle.Crypto.Tls
             byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
             if (!Arrays.Contains(this.mOfferedCompressionMethods, selectedCompressionMethod))
                 throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-
             this.mTlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod);
 
             /*
@@ -714,17 +698,19 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             if (sessionServerExtensions != null)
             {
-                /*
-                 * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
-                 * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
-                 * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
-                 * client.
-                 */
-                bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
-                if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(selectedCipherSuite))
-                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                {
+                    /*
+                     * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
+                     * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
+                     * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
+                     * client.
+                     */
+                    bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
+                    if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(selectedCipherSuite))
+                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
 
-                this.mSecurityParameters.encryptThenMac = serverSentEncryptThenMAC;
+                    this.mSecurityParameters.encryptThenMac = serverSentEncryptThenMAC;
+                }
 
                 this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
 
@@ -757,6 +743,15 @@ namespace Org.BouncyCastle.Crypto.Tls
             {
                 this.mTlsClient.ProcessServerExtensions(sessionServerExtensions);
             }
+
+            this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, this.mSecurityParameters.CipherSuite);
+
+            /*
+             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify
+             * verify_data_length has a verify_data_length equal to 12. This includes all
+             * existing cipher suites.
+             */
+            this.mSecurityParameters.verifyDataLength = 12;
         }
 
         protected virtual void SendCertificateVerifyMessage(DigitallySigned certificateVerify)
diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs
index 4ea72cd57..8eb7beb3f 100644
--- a/crypto/src/crypto/tls/TlsProtocol.cs
+++ b/crypto/src/crypto/tls/TlsProtocol.cs
@@ -99,6 +99,18 @@ namespace Org.BouncyCastle.Crypto.Tls
         {
         }
 
+        protected virtual void ApplyMaxFragmentLengthExtension()
+        {
+            if (mSecurityParameters.maxFragmentLength >= 0)
+            {
+                if (!MaxFragmentLength.IsValid((byte)mSecurityParameters.maxFragmentLength))
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+
+                int plainTextLimit = 1 << (8 + mSecurityParameters.maxFragmentLength);
+                mRecordStream.SetPlaintextLimit(plainTextLimit);
+            }
+        }
+
         protected virtual void CheckReceivedChangeCipherSpec(bool expected)
         {
             if (expected != mReceivedChangeCipherSpec)
@@ -164,12 +176,12 @@ namespace Org.BouncyCastle.Crypto.Tls
                     if (this.mSessionParameters == null)
                     {
                         this.mSessionParameters = new SessionParameters.Builder()
-                            .SetCipherSuite(this.mSecurityParameters.cipherSuite)
-                            .SetCompressionAlgorithm(this.mSecurityParameters.compressionAlgorithm)
-                            .SetMasterSecret(this.mSecurityParameters.masterSecret)
+                            .SetCipherSuite(this.mSecurityParameters.CipherSuite)
+                            .SetCompressionAlgorithm(this.mSecurityParameters.CompressionAlgorithm)
+                            .SetMasterSecret(this.mSecurityParameters.MasterSecret)
                             .SetPeerCertificate(this.mPeerCertificate)
-                            .SetPskIdentity(this.mSecurityParameters.pskIdentity)
-                            .SetSrpIdentity(this.mSecurityParameters.srpIdentity)
+                            .SetPskIdentity(this.mSecurityParameters.PskIdentity)
+                            .SetSrpIdentity(this.mSecurityParameters.SrpIdentity)
                             // TODO Consider filtering extensions that aren't relevant to resumed sessions
                             .SetServerExtensions(this.mServerExtensions)
                             .Build();
@@ -761,10 +773,14 @@ namespace Org.BouncyCastle.Crypto.Tls
             byte alertDescription)
         {
             short maxFragmentLength = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(serverExtensions);
-            if (maxFragmentLength >= 0 && !this.mResumedSession)
+            if (maxFragmentLength >= 0)
             {
-                if (maxFragmentLength != TlsExtensionsUtilities.GetMaxFragmentLengthExtension(clientExtensions))
+                if (!MaxFragmentLength.IsValid((byte)maxFragmentLength)
+                    || (!this.mResumedSession && maxFragmentLength != TlsExtensionsUtilities
+                        .GetMaxFragmentLengthExtension(clientExtensions)))
+                {
                     throw new TlsFatalAlert(alertDescription);
+                }
             }
             return maxFragmentLength;
         }
diff --git a/crypto/src/crypto/tls/TlsServerProtocol.cs b/crypto/src/crypto/tls/TlsServerProtocol.cs
index fd6808382..b73cb5a30 100644
--- a/crypto/src/crypto/tls/TlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/TlsServerProtocol.cs
@@ -106,6 +106,8 @@ namespace Org.BouncyCastle.Crypto.Tls
                     SendServerHelloMessage();
                     this.mConnectionState = CS_SERVER_HELLO;
 
+                    mRecordStream.NotifyHelloComplete();
+
                     IList serverSupplementalData = mTlsServer.GetServerSupplementalData();
                     if (serverSupplementalData != null)
                     {
@@ -618,16 +620,18 @@ namespace Org.BouncyCastle.Crypto.Tls
         {
             HandshakeMessage message = new HandshakeMessage(HandshakeType.server_hello);
 
-            ProtocolVersion server_version = mTlsServer.GetServerVersion();
-            if (!server_version.IsEqualOrEarlierVersionOf(Context.ClientVersion))
-                throw new TlsFatalAlert(AlertDescription.internal_error);
+            {
+                ProtocolVersion server_version = mTlsServer.GetServerVersion();
+                if (!server_version.IsEqualOrEarlierVersionOf(Context.ClientVersion))
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
 
-            mRecordStream.ReadVersion = server_version;
-            mRecordStream.SetWriteVersion(server_version);
-            mRecordStream.SetRestrictReadVersion(true);
-            ContextAdmin.SetServerVersion(server_version);
+                mRecordStream.ReadVersion = server_version;
+                mRecordStream.SetWriteVersion(server_version);
+                mRecordStream.SetRestrictReadVersion(true);
+                ContextAdmin.SetServerVersion(server_version);
 
-            TlsUtilities.WriteVersion(server_version, message);
+                TlsUtilities.WriteVersion(server_version, message);
+            }
 
             message.Write(this.mSecurityParameters.serverRandom);
 
@@ -641,7 +645,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite)
                 || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
                 || CipherSuite.IsScsv(selectedCipherSuite)
-                || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, server_version))
+                || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
             {
                 throw new TlsFatalAlert(AlertDescription.internal_error);
             }
@@ -722,12 +726,6 @@ namespace Org.BouncyCastle.Crypto.Tls
                 WriteExtensions(message, this.mServerExtensions);
             }
 
-            if (mSecurityParameters.maxFragmentLength >= 0)
-            {
-                int plainTextLimit = 1 << (8 + mSecurityParameters.maxFragmentLength);
-                mRecordStream.SetPlaintextLimit(plainTextLimit);
-            }
-
             mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);
 
             /*
@@ -736,9 +734,9 @@ namespace Org.BouncyCastle.Crypto.Tls
              */
             mSecurityParameters.verifyDataLength = 12;
 
-            message.WriteToRecordStream(this);
+            ApplyMaxFragmentLengthExtension();
 
-            this.mRecordStream.NotifyHelloComplete();
+            message.WriteToRecordStream(this);
         }
 
         protected virtual void SendServerHelloDoneMessage()
diff --git a/crypto/src/math/ec/ECAlgorithms.cs b/crypto/src/math/ec/ECAlgorithms.cs
index a1349a9e0..5d60de40f 100644
--- a/crypto/src/math/ec/ECAlgorithms.cs
+++ b/crypto/src/math/ec/ECAlgorithms.cs
@@ -10,14 +10,23 @@ namespace Org.BouncyCastle.Math.EC
     {
         public static bool IsF2mCurve(ECCurve c)
         {
-            IFiniteField field = c.Field;
+            return IsF2mField(c.Field);
+        }
+
+        public static bool IsF2mField(IFiniteField field)
+        {
             return field.Dimension > 1 && field.Characteristic.Equals(BigInteger.Two)
                 && field is IPolynomialExtensionField;
         }
 
         public static bool IsFpCurve(ECCurve c)
         {
-            return c.Field.Dimension == 1;
+            return IsFpField(c.Field);
+        }
+
+        public static bool IsFpField(IFiniteField field)
+        {
+            return field.Dimension == 1;
         }
 
         public static ECPoint SumOfMultiplies(ECPoint[] ps, BigInteger[] ks)
@@ -61,10 +70,9 @@ namespace Org.BouncyCastle.Math.EC
             Q = ImportPoint(cp, Q);
 
             // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
-            if (cp is F2mCurve)
             {
-                F2mCurve f2mCurve = (F2mCurve) cp;
-                if (f2mCurve.IsKoblitz)
+                AbstractF2mCurve f2mCurve = cp as AbstractF2mCurve;
+                if (f2mCurve != null && f2mCurve.IsKoblitz)
                 {
                     return ValidatePoint(P.Multiply(a).Add(Q.Multiply(b)));
                 }
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index 339d37f7c..9fe9e32fd 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -623,6 +623,18 @@ namespace Org.BouncyCastle.Math.EC
     public abstract class AbstractF2mCurve
         : ECCurve
     {
+        public static BigInteger Inverse(int m, int[] ks, BigInteger x)
+        {
+            return new LongArray(x).ModInverse(m, ks).ToBigInteger();
+        }
+
+        /**
+         * The auxiliary values <code>s<sub>0</sub></code> and
+         * <code>s<sub>1</sub></code> used for partial modular reduction for
+         * Koblitz curves.
+         */
+        private BigInteger[] si = null;
+
         private static IFiniteField BuildField(int m, int k1, int k2, int k3)
         {
             if (k1 == 0)
@@ -657,6 +669,69 @@ namespace Org.BouncyCastle.Math.EC
             : base(BuildField(m, k1, k2, k3))
         {
         }
+
+        [Obsolete("Per-point compression property will be removed")]
+        public override ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
+        {
+            ECFieldElement X = FromBigInteger(x), Y = FromBigInteger(y);
+
+            switch (this.CoordinateSystem)
+            {
+            case COORD_LAMBDA_AFFINE:
+            case COORD_LAMBDA_PROJECTIVE:
+            {
+                if (X.IsZero)
+                {
+                    if (!Y.Square().Equals(B))
+                        throw new ArgumentException();
+                }
+                else
+                {
+                    // Y becomes Lambda (X + Y/X) here
+                    Y = Y.Divide(X).Add(X);
+                }
+                break;
+            }
+            default:
+            {
+                break;
+            }
+            }
+
+            return CreateRawPoint(X, Y, withCompression);
+        }
+
+        /**
+         * @return the auxiliary values <code>s<sub>0</sub></code> and
+         * <code>s<sub>1</sub></code> used for partial modular reduction for
+         * Koblitz curves.
+         */
+        internal virtual BigInteger[] GetSi()
+        {
+            if (si == null)
+            {
+                lock (this)
+                {
+                    if (si == null)
+                    {
+                        si = Tnaf.GetSi(this);
+                    }
+                }
+            }
+            return si;
+        }
+
+        /**
+         * Returns true if this is a Koblitz curve (ABC curve).
+         * @return true if this is a Koblitz curve (ABC curve), false otherwise
+         */
+        public virtual bool IsKoblitz
+        {
+            get
+            {
+                return m_order != null && m_cofactor != null && m_b.IsOne && (m_a.IsZero || m_a.IsOne);
+            }
+        }
     }
 
     /**
@@ -705,19 +780,6 @@ namespace Org.BouncyCastle.Math.EC
         protected readonly F2mPoint m_infinity;
 
         /**
-         * The parameter <code>&#956;</code> of the elliptic curve if this is
-         * a Koblitz curve.
-         */
-        private sbyte mu = 0;
-
-        /**
-         * The auxiliary values <code>s<sub>0</sub></code> and
-         * <code>s<sub>1</sub></code> used for partial modular reduction for
-         * Koblitz curves.
-         */
-        private BigInteger[] si = null;
-
-        /**
          * Constructor for Trinomial Polynomial Basis (TPB).
          * @param m  The exponent <code>m</code> of
          * <code>F<sub>2<sup>m</sup></sub></code>.
@@ -917,37 +979,6 @@ namespace Org.BouncyCastle.Math.EC
             return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, x);
         }
 
-        [Obsolete("Per-point compression property will be removed")]
-        public override ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
-        {
-            ECFieldElement X = FromBigInteger(x), Y = FromBigInteger(y);
-
-            switch (this.CoordinateSystem)
-            {
-                case COORD_LAMBDA_AFFINE:
-                case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        if (X.IsZero)
-                        {
-                            if (!Y.Square().Equals(B))
-                                throw new ArgumentException();
-                        }
-                        else
-                        {
-                            // Y becomes Lambda (X + Y/X) here
-                            Y = Y.Divide(X).Add(X);
-                        }
-                        break;
-                    }
-                default:
-                    {
-                        break;
-                    }
-            }
-
-            return CreateRawPoint(X, Y, withCompression);
-        }
-
         protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
         {
             return new F2mPoint(this, x, y, withCompression);
@@ -963,60 +994,6 @@ namespace Org.BouncyCastle.Math.EC
             get { return m_infinity; }
         }
 
-        /**
-         * Returns true if this is a Koblitz curve (ABC curve).
-         * @return true if this is a Koblitz curve (ABC curve), false otherwise
-         */
-        public virtual bool IsKoblitz
-        {
-            get
-            {
-                return m_order != null && m_cofactor != null && m_b.IsOne && (m_a.IsZero || m_a.IsOne);
-            }
-        }
-
-        /**
-         * Returns the parameter <code>&#956;</code> of the elliptic curve.
-         * @return <code>&#956;</code> of the elliptic curve.
-         * @throws ArgumentException if the given ECCurve is not a
-         * Koblitz curve.
-         */
-        internal virtual sbyte GetMu()
-        {
-            if (mu == 0)
-            {
-                lock (this)
-                {
-                    if (mu == 0)
-                    {
-                        mu = Tnaf.GetMu(this);
-                    }
-                }
-            }
-
-            return mu;
-        }
-
-        /**
-         * @return the auxiliary values <code>s<sub>0</sub></code> and
-         * <code>s<sub>1</sub></code> used for partial modular reduction for
-         * Koblitz curves.
-         */
-        internal virtual BigInteger[] GetSi()
-        {
-            if (si == null)
-            {
-                lock (this)
-                {
-                    if (si == null)
-                    {
-                        si = Tnaf.GetSi(this);
-                    }
-                }
-            }
-            return si;
-        }
-
         protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
         {
             ECFieldElement xp = FromBigInteger(X1), yp = null;
@@ -1086,7 +1063,7 @@ namespace Org.BouncyCastle.Math.EC
                 ECFieldElement t = FromBigInteger(new BigInteger(m, rand));
                 z = zeroElement;
                 ECFieldElement w = beta;
-                for (int i = 1; i <= m - 1; i++)
+                for (int i = 1; i < m; i++)
                 {
                     ECFieldElement w2 = w.Square();
                     z = z.Square().Add(w2.Multiply(t));
diff --git a/crypto/src/math/ec/ECFieldElement.cs b/crypto/src/math/ec/ECFieldElement.cs
index e589fc737..844bed649 100644
--- a/crypto/src/math/ec/ECFieldElement.cs
+++ b/crypto/src/math/ec/ECFieldElement.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Diagnostics;
 
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math.EC
@@ -55,6 +56,16 @@ namespace Org.BouncyCastle.Math.EC
             return Square().Add(x.Multiply(y));
         }
 
+        public virtual ECFieldElement SquarePow(int pow)
+        {
+            ECFieldElement r = this;
+            for (int i = 0; i < pow; ++i)
+            {
+                r = r.Square();
+            }
+            return r;
+        }
+
         public virtual bool TestBitZero()
         {
             return ToBigInteger().TestBit(0);
@@ -812,6 +823,11 @@ namespace Org.BouncyCastle.Math.EC
             return new F2mFieldElement(m, ks, aa);
         }
 
+        public override ECFieldElement SquarePow(int pow)
+        {
+            return pow < 1 ? this : new F2mFieldElement(m, ks, x.ModSquareN(pow, m, ks));
+        }
+
         public override ECFieldElement Invert()
         {
             return new F2mFieldElement(this.m, this.ks, this.x.ModInverse(m, ks));
@@ -819,14 +835,7 @@ namespace Org.BouncyCastle.Math.EC
 
         public override ECFieldElement Sqrt()
         {
-            LongArray x1 = this.x;
-            if (x1.IsOne() || x1.IsZero())
-            {
-                return this;
-            }
-
-            LongArray x2 = x1.ModSquareN(m - 1, m, ks);
-            return new F2mFieldElement(m, ks, x2);
+            return (x.IsZero() || x.IsOne()) ? this : SquarePow(m - 1);
         }
 
         /**
diff --git a/crypto/src/math/ec/ECPoint.cs b/crypto/src/math/ec/ECPoint.cs
index 3e206e65f..a5ba515c5 100644
--- a/crypto/src/math/ec/ECPoint.cs
+++ b/crypto/src/math/ec/ECPoint.cs
@@ -1383,6 +1383,139 @@ namespace Org.BouncyCastle.Math.EC
 
             return lhs.Equals(rhs);
         }
+
+        public override ECPoint ScaleX(ECFieldElement scale)
+        {
+            if (this.IsInfinity)
+                return this;
+
+            switch (CurveCoordinateSystem)
+            {
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            {
+                // Y is actually Lambda (X + Y/X) here
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                ECFieldElement X2 = X.Multiply(scale);
+                ECFieldElement L2 = L.Add(X).Divide(scale).Add(X2);
+
+                return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
+            }
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                // Y is actually Lambda (X + Y/X) here
+                ECFieldElement X = RawXCoord, L = RawYCoord, Z = RawZCoords[0];
+
+                // We scale the Z coordinate also, to avoid an inversion
+                ECFieldElement X2 = X.Multiply(scale.Square());
+                ECFieldElement L2 = L.Add(X).Add(X2);
+                ECFieldElement Z2 = Z.Multiply(scale);
+
+                return Curve.CreateRawPoint(X, L2, new ECFieldElement[] { Z2 }, IsCompressed);
+            }
+            default:
+            {
+                return base.ScaleX(scale);
+            }
+            }
+        }
+
+        public override ECPoint ScaleY(ECFieldElement scale)
+        {
+            if (this.IsInfinity)
+                return this;
+
+            switch (CurveCoordinateSystem)
+            {
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                ECFieldElement L2 = L.Add(X).Multiply(scale).Add(X);
+
+                return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
+            }
+            default:
+            {
+                return base.ScaleY(scale);
+            }
+            }
+        }
+
+        public override ECPoint Subtract(ECPoint b)
+        {
+            if (b.IsInfinity)
+                return this;
+
+            // Add -b
+            return Add(b.Negate());
+        }
+
+        public virtual AbstractF2mPoint Tau()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+            int coord = curve.CoordinateSystem;
+
+            ECFieldElement X1 = this.RawXCoord;
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            {
+                ECFieldElement Y1 = this.RawYCoord;
+                return (AbstractF2mPoint)curve.CreateRawPoint(X1.Square(), Y1.Square(), IsCompressed);
+            }
+            case ECCurve.COORD_HOMOGENEOUS:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+                return (AbstractF2mPoint)curve.CreateRawPoint(X1.Square(), Y1.Square(),
+                    new ECFieldElement[] { Z1.Square() }, IsCompressed);
+            }
+            default:
+            {
+                throw new InvalidOperationException("unsupported coordinate system");
+            }
+            }
+        }
+
+        public virtual AbstractF2mPoint TauPow(int pow)
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+            int coord = curve.CoordinateSystem;
+
+            ECFieldElement X1 = this.RawXCoord;
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            {
+                ECFieldElement Y1 = this.RawYCoord;
+                return (AbstractF2mPoint)curve.CreateRawPoint(X1.SquarePow(pow), Y1.SquarePow(pow), IsCompressed);
+            }
+            case ECCurve.COORD_HOMOGENEOUS:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+                return (AbstractF2mPoint)curve.CreateRawPoint(X1.SquarePow(pow), Y1.SquarePow(pow),
+                    new ECFieldElement[] { Z1.SquarePow(pow) }, IsCompressed);
+            }
+            default:
+            {
+                throw new InvalidOperationException("unsupported coordinate system");
+            }
+            }
+        }
     }
 
     /**
@@ -1491,66 +1624,6 @@ namespace Org.BouncyCastle.Math.EC
             }
         }
 
-        public override ECPoint ScaleX(ECFieldElement scale)
-        {
-            if (this.IsInfinity)
-                return this;
-
-            switch (CurveCoordinateSystem)
-            {
-            case ECCurve.COORD_LAMBDA_AFFINE:
-            {
-                // Y is actually Lambda (X + Y/X) here
-                ECFieldElement X = RawXCoord, L = RawYCoord;
-
-                ECFieldElement X2 = X.Multiply(scale);
-                ECFieldElement L2 = L.Add(X).Divide(scale).Add(X2);
-
-                return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
-            }
-            case ECCurve.COORD_LAMBDA_PROJECTIVE:
-            {
-                // Y is actually Lambda (X + Y/X) here
-                ECFieldElement X = RawXCoord, L = RawYCoord, Z = RawZCoords[0];
-
-                // We scale the Z coordinate also, to avoid an inversion
-                ECFieldElement X2 = X.Multiply(scale.Square());
-                ECFieldElement L2 = L.Add(X).Add(X2);
-                ECFieldElement Z2 = Z.Multiply(scale);
-
-                return Curve.CreateRawPoint(X, L2, new ECFieldElement[] { Z2 }, IsCompressed);
-            }
-            default:
-            {
-                return base.ScaleX(scale);
-            }
-            }
-        }
-
-        public override ECPoint ScaleY(ECFieldElement scale)
-        {
-            if (this.IsInfinity)
-                return this;
-
-            switch (CurveCoordinateSystem)
-            {
-            case ECCurve.COORD_LAMBDA_AFFINE:
-            case ECCurve.COORD_LAMBDA_PROJECTIVE:
-            {
-                ECFieldElement X = RawXCoord, L = RawYCoord;
-
-                // Y is actually Lambda (X + Y/X) here
-                ECFieldElement L2 = L.Add(X).Multiply(scale).Add(X);
-
-                return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
-            }
-            default:
-            {
-                return base.ScaleY(scale);
-            }
-            }
-        }
-
         protected internal override bool CompressionYTilde
         {
             get
@@ -1579,44 +1652,8 @@ namespace Org.BouncyCastle.Math.EC
             }
         }
 
-        /**
-         * Check, if two <code>ECPoint</code>s can be added or subtracted.
-         * @param a The first <code>ECPoint</code> to check.
-         * @param b The second <code>ECPoint</code> to check.
-         * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
-         * cannot be added.
-         */
-        private static void CheckPoints(
-            ECPoint	a,
-            ECPoint	b)
-        {
-            // Check, if points are on the same curve
-            if (!a.Curve.Equals(b.Curve))
-                throw new ArgumentException("Only points on the same curve can be added or subtracted");
-
-//			F2mFieldElement.CheckFieldElements(a.x, b.x);
-        }
-
-        /* (non-Javadoc)
-         * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)
-         */
         public override ECPoint Add(ECPoint b)
         {
-            CheckPoints(this, b);
-            return AddSimple((F2mPoint) b);
-        }
-
-        /**
-         * Adds another <code>ECPoints.F2m</code> to <code>this</code> without
-         * checking if both points are on the same curve. Used by multiplication
-         * algorithms, because there all points are a multiple of the same point
-         * and hence the checks can be omitted.
-         * @param b The other <code>ECPoints.F2m</code> to add to
-         * <code>this</code>.
-         * @return <code>this + b</code>
-         */
-        internal F2mPoint AddSimple(F2mPoint b)
-        {
             if (this.IsInfinity)
                 return b;
             if (b.IsInfinity)
@@ -1640,10 +1677,10 @@ namespace Org.BouncyCastle.Math.EC
                     {
                         if (dy.IsZero)
                         {
-                            return (F2mPoint)Twice();
+                            return Twice();
                         }
 
-                        return (F2mPoint)curve.Infinity;
+                        return curve.Infinity;
                     }
 
                     ECFieldElement L = dy.Divide(dx);
@@ -1681,10 +1718,10 @@ namespace Org.BouncyCastle.Math.EC
                     {
                         if (U.IsZero)
                         {
-                            return (F2mPoint)Twice();
+                            return Twice();
                         }
 
-                        return (F2mPoint)curve.Infinity;
+                        return curve.Infinity;
                     }
 
                     ECFieldElement VSq = V.Square();
@@ -1705,9 +1742,9 @@ namespace Org.BouncyCastle.Math.EC
                     if (X1.IsZero)
                     {
                         if (X2.IsZero)
-                            return (F2mPoint)curve.Infinity;
+                            return curve.Infinity;
 
-                        return b.AddSimple(this);
+                        return b.Add(this);
                     }
 
                     ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
@@ -1736,10 +1773,10 @@ namespace Org.BouncyCastle.Math.EC
                     {
                         if (A.IsZero)
                         {
-                            return (F2mPoint)Twice();
+                            return Twice();
                         }
 
-                        return (F2mPoint)curve.Infinity;
+                        return curve.Infinity;
                     }
 
                     ECFieldElement X3, L3, Z3;
@@ -1801,68 +1838,6 @@ namespace Org.BouncyCastle.Math.EC
         }
 
         /* (non-Javadoc)
-         * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)
-         */
-        public override ECPoint Subtract(
-            ECPoint b)
-        {
-            CheckPoints(this, b);
-            return SubtractSimple((F2mPoint) b);
-        }
-
-        /**
-         * Subtracts another <code>ECPoints.F2m</code> from <code>this</code>
-         * without checking if both points are on the same curve. Used by
-         * multiplication algorithms, because there all points are a multiple
-         * of the same point and hence the checks can be omitted.
-         * @param b The other <code>ECPoints.F2m</code> to subtract from
-         * <code>this</code>.
-         * @return <code>this - b</code>
-         */
-        internal F2mPoint SubtractSimple(
-            F2mPoint b)
-        {
-            if (b.IsInfinity)
-                return this;
-
-            // Add -b
-            return AddSimple((F2mPoint) b.Negate());
-        }
-
-        public virtual F2mPoint Tau()
-        {
-            if (this.IsInfinity)
-            {
-                return this;
-            }
-
-            ECCurve curve = this.Curve;
-            int coord = curve.CoordinateSystem;
-
-            ECFieldElement X1 = this.RawXCoord;
-
-            switch (coord)
-            {
-                case ECCurve.COORD_AFFINE:
-                case ECCurve.COORD_LAMBDA_AFFINE:
-                {
-                    ECFieldElement Y1 = this.RawYCoord;
-                    return new F2mPoint(curve, X1.Square(), Y1.Square(), IsCompressed);
-                }
-                case ECCurve.COORD_HOMOGENEOUS:
-                case ECCurve.COORD_LAMBDA_PROJECTIVE:
-                {
-                    ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
-                    return new F2mPoint(curve, X1.Square(), Y1.Square(), new ECFieldElement[] { Z1.Square() }, IsCompressed);
-                }
-                default:
-                {
-                    throw new InvalidOperationException("unsupported coordinate system");
-                }
-            }
-        }
-
-        /* (non-Javadoc)
          * @see Org.BouncyCastle.Math.EC.ECPoint#twice()
          */
         public override ECPoint Twice()
diff --git a/crypto/src/math/ec/LongArray.cs b/crypto/src/math/ec/LongArray.cs
index c4e3dacbc..84462e0ea 100644
--- a/crypto/src/math/ec/LongArray.cs
+++ b/crypto/src/math/ec/LongArray.cs
@@ -13,7 +13,7 @@ namespace Org.BouncyCastle.Math.EC
          * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits.
          * In a binary field, this operation is the same as squaring an 8 bit number.
          */
-        private static readonly int[] INTERLEAVE2_TABLE = new int[]
+        private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[]
         {
             0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
             0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
diff --git a/crypto/src/math/ec/abc/Tnaf.cs b/crypto/src/math/ec/abc/Tnaf.cs
index 9f16886f5..b6e792aa4 100644
--- a/crypto/src/math/ec/abc/Tnaf.cs
+++ b/crypto/src/math/ec/abc/Tnaf.cs
@@ -384,11 +384,11 @@ namespace Org.BouncyCastle.Math.EC.Abc
 
         /**
         * Applies the operation <code>&#964;()</code> to an
-        * <code>F2mPoint</code>. 
-        * @param p The F2mPoint to which <code>&#964;()</code> is applied.
+        * <code>AbstractF2mPoint</code>. 
+        * @param p The AbstractF2mPoint to which <code>&#964;()</code> is applied.
         * @return <code>&#964;(p)</code>
         */
-        public static F2mPoint Tau(F2mPoint p)
+        public static AbstractF2mPoint Tau(AbstractF2mPoint p)
         {
             return p.Tau();
         }
@@ -403,7 +403,7 @@ namespace Org.BouncyCastle.Math.EC.Abc
         * @throws ArgumentException if the given ECCurve is not a Koblitz
         * curve.
         */
-        public static sbyte GetMu(F2mCurve curve)
+        public static sbyte GetMu(AbstractF2mCurve curve)
         {
             BigInteger a = curve.A.ToBigInteger();
 
@@ -423,6 +423,16 @@ namespace Org.BouncyCastle.Math.EC.Abc
             return mu;
         }
 
+        public static sbyte GetMu(ECFieldElement curveA)
+        {
+            return (sbyte)(curveA.IsZero ? -1 : 1);
+        }
+
+        public static sbyte GetMu(int curveA)
+        {
+            return (sbyte)(curveA == 0 ? -1 : 1);
+        }
+
         /**
         * Calculates the Lucas Sequence elements <code>U<sub>k-1</sub></code> and
         * <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code> and
@@ -526,53 +536,60 @@ namespace Org.BouncyCastle.Math.EC.Abc
         * @throws ArgumentException if <code>curve</code> is not a
         * Koblitz curve (Anomalous Binary Curve, ABC).
         */
-        public static BigInteger[] GetSi(F2mCurve curve)
+        public static BigInteger[] GetSi(AbstractF2mCurve curve)
         {
             if (!curve.IsKoblitz)
                 throw new ArgumentException("si is defined for Koblitz curves only");
 
-            int m = curve.M;
+            int m = curve.FieldSize;
             int a = curve.A.ToBigInteger().IntValue;
-            sbyte mu = curve.GetMu();
-            int h = curve.Cofactor.IntValue;
+            sbyte mu = GetMu(a);
+            int shifts = GetShiftsForCofactor(curve.Cofactor);
             int index = m + 3 - a;
             BigInteger[] ui = GetLucas(mu, index, false);
 
-            BigInteger dividend0;
-            BigInteger dividend1;
             if (mu == 1)
             {
-                dividend0 = BigInteger.One.Subtract(ui[1]);
-                dividend1 = BigInteger.One.Subtract(ui[0]);
-            }
-            else if (mu == -1)
-            {
-                dividend0 = BigInteger.One.Add(ui[1]);
-                dividend1 = BigInteger.One.Add(ui[0]);
-            }
-            else
-            {
-                throw new ArgumentException("mu must be 1 or -1");
+                ui[0] = ui[0].Negate();
+                ui[1] = ui[1].Negate();
             }
 
-            BigInteger[] si = new BigInteger[2];
+            BigInteger dividend0 = BigInteger.One.Add(ui[1]).ShiftRight(shifts);
+            BigInteger dividend1 = BigInteger.One.Add(ui[0]).ShiftRight(shifts).Negate();
 
-            if (h == 2)
-            {
-                si[0] = dividend0.ShiftRight(1);
-                si[1] = dividend1.ShiftRight(1).Negate();
-            }
-            else if (h == 4)
+            return new BigInteger[] { dividend0, dividend1 };
+        }
+
+        public static BigInteger[] GetSi(int fieldSize, int curveA, BigInteger cofactor)
+        {
+            sbyte mu = GetMu(curveA);
+            int shifts = GetShiftsForCofactor(cofactor);
+            int index = fieldSize + 3 - curveA;
+            BigInteger[] ui = GetLucas(mu, index, false);
+            if (mu == 1)
             {
-                si[0] = dividend0.ShiftRight(2);
-                si[1] = dividend1.ShiftRight(2).Negate();
+                ui[0] = ui[0].Negate();
+                ui[1] = ui[1].Negate();
             }
-            else
+
+            BigInteger dividend0 = BigInteger.One.Add(ui[1]).ShiftRight(shifts);
+            BigInteger dividend1 = BigInteger.One.Add(ui[0]).ShiftRight(shifts).Negate();
+
+            return new BigInteger[] { dividend0, dividend1 };
+        }
+
+        protected static int GetShiftsForCofactor(BigInteger h)
+        {
+            if (h != null && h.BitLength < 4)
             {
-                throw new ArgumentException("h (Cofactor) must be 2 or 4");
+                int hi = h.IntValue;
+                if (hi == 2)
+                    return 1;
+                if (hi == 4)
+                    return 2;
             }
 
-            return si;
+            throw new ArgumentException("h (Cofactor) must be 2 or 4");
         }
 
         /**
@@ -624,70 +641,77 @@ namespace Org.BouncyCastle.Math.EC.Abc
         }
 
         /**
-        * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+        * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
         * by a <code>BigInteger</code> using the reduced <code>&#964;</code>-adic
         * NAF (RTNAF) method.
-        * @param p The F2mPoint to Multiply.
+        * @param p The AbstractF2mPoint to Multiply.
         * @param k The <code>BigInteger</code> by which to Multiply <code>p</code>.
         * @return <code>k * p</code>
         */
-        public static F2mPoint MultiplyRTnaf(F2mPoint p, BigInteger k)
+        public static AbstractF2mPoint MultiplyRTnaf(AbstractF2mPoint p, BigInteger k)
         {
-            F2mCurve curve = (F2mCurve) p.Curve;
-            int m = curve.M;
-            sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
-            sbyte mu = curve.GetMu();
+            AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
+            int m = curve.FieldSize;
+            int a = curve.A.ToBigInteger().IntValue;
+            sbyte mu = GetMu(a);
             BigInteger[] s = curve.GetSi();
-            ZTauElement rho = PartModReduction(k, m, a, s, mu, (sbyte)10);
+            ZTauElement rho = PartModReduction(k, m, (sbyte)a, s, mu, (sbyte)10);
 
             return MultiplyTnaf(p, rho);
         }
 
         /**
-        * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+        * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
         * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>
         * using the <code>&#964;</code>-adic NAF (TNAF) method.
-        * @param p The F2mPoint to Multiply.
+        * @param p The AbstractF2mPoint to Multiply.
         * @param lambda The element <code>&#955;</code> of
         * <code><b>Z</b>[&#964;]</code>.
         * @return <code>&#955; * p</code>
         */
-        public static F2mPoint MultiplyTnaf(F2mPoint p, ZTauElement lambda)
+        public static AbstractF2mPoint MultiplyTnaf(AbstractF2mPoint p, ZTauElement lambda)
         {
-            F2mCurve curve = (F2mCurve)p.Curve;
-            sbyte mu = curve.GetMu();
+            AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
+            sbyte mu = GetMu(curve.A);
             sbyte[] u = TauAdicNaf(mu, lambda);
 
-            F2mPoint q = MultiplyFromTnaf(p, u);
+            AbstractF2mPoint q = MultiplyFromTnaf(p, u);
 
             return q;
         }
 
         /**
-        * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+        * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
         * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>
         * using the <code>&#964;</code>-adic NAF (TNAF) method, given the TNAF
         * of <code>&#955;</code>.
-        * @param p The F2mPoint to Multiply.
+        * @param p The AbstractF2mPoint to Multiply.
         * @param u The the TNAF of <code>&#955;</code>..
         * @return <code>&#955; * p</code>
         */
-        public static F2mPoint MultiplyFromTnaf(F2mPoint p, sbyte[] u)
+        public static AbstractF2mPoint MultiplyFromTnaf(AbstractF2mPoint p, sbyte[] u)
         {
-            F2mCurve curve = (F2mCurve)p.Curve;
-            F2mPoint q = (F2mPoint) curve.Infinity;
+            ECCurve curve = p.Curve;
+            AbstractF2mPoint q = (AbstractF2mPoint)curve.Infinity;
+            AbstractF2mPoint pNeg = (AbstractF2mPoint)p.Negate();
+            int tauCount = 0;
             for (int i = u.Length - 1; i >= 0; i--)
             {
-                q = Tau(q);
-                if (u[i] == 1)
-                {
-                    q = (F2mPoint)q.AddSimple(p);
-                }
-                else if (u[i] == -1)
+                ++tauCount;
+                sbyte ui = u[i];
+                if (ui != 0)
                 {
-                    q = (F2mPoint)q.SubtractSimple(p);
+                    q = q.TauPow(tauCount);
+                    tauCount = 0;
+
+                    ECPoint x = ui > 0 ? p : pNeg;
+                    q = (AbstractF2mPoint)q.Add(x);
                 }
             }
+            if (tauCount > 0)
+            {
+                q = q.TauPow(tauCount);
+            }
             return q;
         }
 
@@ -800,28 +824,21 @@ namespace Org.BouncyCastle.Math.EC.Abc
         * @param a The parameter <code>a</code> of the elliptic curve.
         * @return The precomputation array for <code>p</code>. 
         */
-        public static F2mPoint[] GetPreComp(F2mPoint p, sbyte a)
+        public static AbstractF2mPoint[] GetPreComp(AbstractF2mPoint p, sbyte a)
         {
-            F2mPoint[] pu;
-            pu = new F2mPoint[16];
-            pu[1] = p;
-            sbyte[][] alphaTnaf;
-            if (a == 0)
-            {
-                alphaTnaf = Tnaf.Alpha0Tnaf;
-            }
-            else
-            {
-                // a == 1
-                alphaTnaf = Tnaf.Alpha1Tnaf;
-            }
+            sbyte[][] alphaTnaf = (a == 0) ? Tnaf.Alpha0Tnaf : Tnaf.Alpha1Tnaf;
+
+            AbstractF2mPoint[] pu = new AbstractF2mPoint[(uint)(alphaTnaf.Length + 1) >> 1];
+            pu[0] = p;
 
-            int precompLen = alphaTnaf.Length;
-            for (int i = 3; i < precompLen; i = i + 2)
+            uint precompLen = (uint)alphaTnaf.Length;
+            for (uint i = 3; i < precompLen; i += 2)
             {
-                pu[i] = Tnaf.MultiplyFromTnaf(p, alphaTnaf[i]);
+                pu[i >> 1] = Tnaf.MultiplyFromTnaf(p, alphaTnaf[i]);
             }
-            
+
+            p.Curve.NormalizeAll(pu);
+
             return pu;
         }
     }
diff --git a/crypto/src/math/ec/custom/djb/Curve25519.cs b/crypto/src/math/ec/custom/djb/Curve25519.cs
index 712b68f29..6ed7c0648 100644
--- a/crypto/src/math/ec/custom/djb/Curve25519.cs
+++ b/crypto/src/math/ec/custom/djb/Curve25519.cs
@@ -1,6 +1,6 @@
 using System;
 
-using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities.Encoders;
 
 namespace Org.BouncyCastle.Math.EC.Custom.Djb
diff --git a/crypto/src/math/ec/custom/djb/Curve25519Field.cs b/crypto/src/math/ec/custom/djb/Curve25519Field.cs
index 809e51b80..837821e1a 100644
--- a/crypto/src/math/ec/custom/djb/Curve25519Field.cs
+++ b/crypto/src/math/ec/custom/djb/Curve25519Field.cs
@@ -1,7 +1,7 @@
 using System;
 using System.Diagnostics;
 
-using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Math.Raw;
 
 namespace Org.BouncyCastle.Math.EC.Custom.Djb
 {
diff --git a/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs b/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
index 8d5a80326..732e9e468 100644
--- a/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
+++ b/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
@@ -1,6 +1,6 @@
 using System;
 
-using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math.EC.Custom.Djb
diff --git a/crypto/src/math/ec/custom/djb/Curve25519Point.cs b/crypto/src/math/ec/custom/djb/Curve25519Point.cs
index bfec1d11d..eb8fc12f2 100644
--- a/crypto/src/math/ec/custom/djb/Curve25519Point.cs
+++ b/crypto/src/math/ec/custom/djb/Curve25519Point.cs
@@ -1,6 +1,6 @@
 using System;
 
-using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Math.Raw;
 
 namespace Org.BouncyCastle.Math.EC.Custom.Djb
 {
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs
new file mode 100644
index 000000000..9da27b470
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP128R1Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = new BigInteger(1,
+            Hex.Decode("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"));
+
+        private const int SecP128R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SecP128R1Point m_infinity;
+
+        public SecP128R1Curve()
+            : base(q)
+        {
+            this.m_infinity = new SecP128R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1,
+                Hex.Decode("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC")));
+            this.m_b = FromBigInteger(new BigInteger(1,
+                Hex.Decode("E87579C11079F43DD824993C2CEE5ED3")));
+            this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFE0000000075A30D1B9038A115"));
+            this.m_cofactor = BigInteger.One;
+
+            this.m_coord = SecP128R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecP128R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_JACOBIAN:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecP128R1FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecP128R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecP128R1Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1Field.cs b/crypto/src/math/ec/custom/sec/SecP128R1Field.cs
new file mode 100644
index 000000000..ff6fb6b65
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP128R1Field.cs
@@ -0,0 +1,218 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP128R1Field
+    {
+        // 2^128 - 2^97 - 1
+        internal static readonly uint[] P = new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFD };
+        internal static readonly uint[] PExt = new uint[] { 0x00000001, 0x00000000, 0x00000000, 0x00000004, 0xFFFFFFFE,
+            0xFFFFFFFF, 0x00000003, 0xFFFFFFFC };
+        private static readonly uint[] PExtInv = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFB,
+            0x00000001, 0x00000000, 0xFFFFFFFC, 0x00000003 };
+        private const uint P3 = 0xFFFFFFFD;
+        private const uint PExt7 = 0xFFFFFFFC;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            uint c = Nat128.Add(x, y, z);
+            if (c != 0 || (z[3] == P3 && Nat128.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            uint c = Nat256.Add(xx, yy, zz);
+            if (c != 0 || (zz[7] == PExt7 && Nat256.Gte(zz, PExt)))
+            {
+                Nat.AddTo(PExtInv.Length, PExtInv, zz);
+            }
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            uint c = Nat.Inc(4, x, z);
+            if (c != 0 || (z[3] == P3 && Nat128.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat128.FromBigInteger(x);
+            if (z[3] == P3 && Nat128.Gte(z, P))
+            {
+                Nat128.SubFrom(P, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            if ((x[0] & 1) == 0)
+            {
+                Nat.ShiftDownBit(4, x, 0, z);
+            }
+            else
+            {
+                uint c = Nat128.Add(x, P, z);
+                Nat.ShiftDownBit(4, z, c);
+            }
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat128.CreateExt();
+            Nat128.Mul(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+        {
+            uint c = Nat128.MulAddTo(x, y, zz);
+            if (c != 0 || (zz[7] == PExt7 && Nat256.Gte(zz, PExt)))
+            {
+                Nat.AddTo(PExtInv.Length, PExtInv, zz);
+            }
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat128.IsZero(x))
+            {
+                Nat128.Zero(z);
+            }
+            else
+            {
+                Nat128.Sub(P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3];
+            ulong x4 = xx[4], x5 = xx[5], x6 = xx[6], x7 = xx[7];
+
+            x3 += x7; x6 += (x7 << 1);
+            x2 += x6; x5 += (x6 << 1);
+            x1 += x5; x4 += (x5 << 1);
+            x0 += x4; x3 += (x4 << 1);
+
+            z[0] = (uint)x0; x1 += (x0 >> 32);
+            z[1] = (uint)x1; x2 += (x1 >> 32);
+            z[2] = (uint)x2; x3 += (x2 >> 32);
+            z[3] = (uint)x3;
+
+            Reduce32((uint)(x3 >> 32), z);
+        }
+
+        public static void Reduce32(uint x, uint[] z)
+        {
+            while (x != 0)
+            {
+                ulong c, x4 = x;
+    
+                c = (ulong)z[0] + x4;
+                z[0] = (uint)c; c >>= 32;
+                if (c != 0)
+                {
+                    c += (ulong)z[1];
+                    z[1] = (uint)c; c >>= 32;
+                    c += (ulong)z[2];
+                    z[2] = (uint)c; c >>= 32;
+                }
+                c += (ulong)z[3] + (x4 << 1);
+                z[3] = (uint)c; c >>= 32;
+
+                Debug.Assert(c >= 0 && c <= 2);
+
+                x = (uint)c;
+            }
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat128.CreateExt();
+            Nat128.Square(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+
+            uint[] tt = Nat128.CreateExt();
+            Nat128.Square(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                Nat128.Square(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat128.Sub(x, y, z);
+            if (c != 0)
+            {
+                SubPInvFrom(z);
+            }
+        }
+
+        public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            int c = Nat.Sub(10, xx, yy, zz);
+            if (c != 0)
+            {
+                Nat.SubFrom(PExtInv.Length, PExtInv, zz);
+            }
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            uint c = Nat.ShiftUpBit(4, x, 0, z);
+            if (c != 0 || (z[3] == P3 && Nat128.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        private static void AddPInvTo(uint[] z)
+        {
+            long c = (long)z[0] + 1;
+            z[0] = (uint)c; c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[1];
+                z[1] = (uint)c; c >>= 32;
+                c += (long)z[2];
+                z[2] = (uint)c; c >>= 32;
+            }
+            c += (long)z[3] + 2;
+            z[3] = (uint)c;
+        }
+
+        private static void SubPInvFrom(uint[] z)
+        {
+            long c = (long)z[0] - 1;
+            z[0] = (uint)c; c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[1];
+                z[1] = (uint)c; c >>= 32;
+                c += (long)z[2];
+                z[2] = (uint)c; c >>= 32;
+            }
+            c += (long)z[3] - 2;
+            z[3] = (uint)c;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs
new file mode 100644
index 000000000..fa7951d5d
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs
@@ -0,0 +1,198 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP128R1FieldElement
+        : ECFieldElement
+    {
+        public static readonly BigInteger Q = SecP128R1Curve.q;
+
+        protected internal readonly uint[] x;
+
+        public SecP128R1FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for SecP128R1FieldElement", "x");
+
+            this.x = SecP128R1Field.FromBigInteger(x);
+        }
+
+        public SecP128R1FieldElement()
+        {
+            this.x = Nat128.Create();
+        }
+
+        protected internal SecP128R1FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat128.IsZero(x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat128.IsOne(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat128.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat128.ToBigInteger(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecP128R1Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat128.Create();
+            SecP128R1Field.Add(x, ((SecP128R1FieldElement)b).x, z);
+            return new SecP128R1FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat128.Create();
+            SecP128R1Field.AddOne(x, z);
+            return new SecP128R1FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat128.Create();
+            SecP128R1Field.Subtract(x, ((SecP128R1FieldElement)b).x, z);
+            return new SecP128R1FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat128.Create();
+            SecP128R1Field.Multiply(x, ((SecP128R1FieldElement)b).x, z);
+            return new SecP128R1FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+    //        return multiply(b.invert());
+            uint[] z = Nat128.Create();
+            Mod.Invert(SecP128R1Field.P, ((SecP128R1FieldElement)b).x, z);
+            SecP128R1Field.Multiply(z, x, z);
+            return new SecP128R1FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat128.Create();
+            SecP128R1Field.Negate(x, z);
+            return new SecP128R1FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat128.Create();
+            SecP128R1Field.Square(x, z);
+            return new SecP128R1FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+    //        return new SecP128R1FieldElement(toBigInteger().modInverse(Q));
+            uint[] z = Nat128.Create();
+            Mod.Invert(SecP128R1Field.P, x, z);
+            return new SecP128R1FieldElement(z);
+        }
+
+        // D.1.4 91
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            /*
+             * Raise this element to the exponent 2^126 - 2^95
+             * 
+             * Breaking up the exponent's binary representation into "repunits", we get:
+             *     { 31 1s } { 95 0s }
+             * 
+             * Therefore we need an addition chain containing 31 (the length of the repunit) We use:
+             *     1, 2, 4, 8, 10, 20, 30, [31] 
+             */
+
+            uint[] x1 = this.x;
+            if (Nat128.IsZero(x1) || Nat128.IsOne(x1))
+                return this;
+
+            uint[] x2 = Nat128.Create();
+            SecP128R1Field.Square(x1, x2);
+            SecP128R1Field.Multiply(x2, x1, x2);
+            uint[] x4 = Nat128.Create();
+            SecP128R1Field.SquareN(x2, 2, x4);
+            SecP128R1Field.Multiply(x4, x2, x4);
+            uint[] x8 = Nat128.Create();
+            SecP128R1Field.SquareN(x4, 4, x8);
+            SecP128R1Field.Multiply(x8, x4, x8);
+            uint[] x10 = x4;
+            SecP128R1Field.SquareN(x8, 2, x10);
+            SecP128R1Field.Multiply(x10, x2, x10);
+            uint[] x20 = x2;
+            SecP128R1Field.SquareN(x10, 10, x20);
+            SecP128R1Field.Multiply(x20, x10, x20);
+            uint[] x30 = x8;
+            SecP128R1Field.SquareN(x20, 10, x30);
+            SecP128R1Field.Multiply(x30, x10, x30);
+            uint[] x31 = x10;
+            SecP128R1Field.Square(x30, x31);
+            SecP128R1Field.Multiply(x31, x1, x31);
+
+            uint[] t1 = x31;
+            SecP128R1Field.SquareN(t1, 95, t1);
+
+            uint[] t2 = x30;
+            SecP128R1Field.Square(t1, t2);
+
+            return Nat128.Eq(x1, t2) ? new SecP128R1FieldElement(t1) : null;        
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecP128R1FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecP128R1FieldElement);
+        }
+
+        public virtual bool Equals(SecP128R1FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat128.Eq(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 4);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1Point.cs b/crypto/src/math/ec/custom/sec/SecP128R1Point.cs
new file mode 100644
index 000000000..ae76d3cd1
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP128R1Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP128R1Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(boolean)}
+         */
+        public SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecP128R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SecP128R1FieldElement X1 = (SecP128R1FieldElement)this.RawXCoord, Y1 = (SecP128R1FieldElement)this.RawYCoord;
+            SecP128R1FieldElement X2 = (SecP128R1FieldElement)b.RawXCoord, Y2 = (SecP128R1FieldElement)b.RawYCoord;
+
+            SecP128R1FieldElement Z1 = (SecP128R1FieldElement)this.RawZCoords[0];
+            SecP128R1FieldElement Z2 = (SecP128R1FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat128.CreateExt();
+            uint[] t2 = Nat128.Create();
+            uint[] t3 = Nat128.Create();
+            uint[] t4 = Nat128.Create();
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SecP128R1Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                SecP128R1Field.Multiply(S2, X2.x, U2);
+
+                SecP128R1Field.Multiply(S2, Z1.x, S2);
+                SecP128R1Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SecP128R1Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                SecP128R1Field.Multiply(S1, X1.x, U1);
+
+                SecP128R1Field.Multiply(S1, Z2.x, S1);
+                SecP128R1Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat128.Create();
+            SecP128R1Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            SecP128R1Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat128.IsZero(H))
+            {
+                if (Nat128.IsZero(R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SecP128R1Field.Square(H, HSquared);
+
+            uint[] G = Nat128.Create();
+            SecP128R1Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SecP128R1Field.Multiply(HSquared, U1, V);
+
+            SecP128R1Field.Negate(G, G);
+            Nat128.Mul(S1, G, tt1);
+
+            c = Nat128.AddBothTo(V, V, G);
+            SecP128R1Field.Reduce32(c, G);
+
+            SecP128R1FieldElement X3 = new SecP128R1FieldElement(t4);
+            SecP128R1Field.Square(R, X3.x);
+            SecP128R1Field.Subtract(X3.x, G, X3.x);
+
+            SecP128R1FieldElement Y3 = new SecP128R1FieldElement(G);
+            SecP128R1Field.Subtract(V, X3.x, Y3.x);
+            SecP128R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+            SecP128R1Field.Reduce(tt1, Y3.x);
+
+            SecP128R1FieldElement Z3 = new SecP128R1FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SecP128R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SecP128R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+            return new SecP128R1Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SecP128R1FieldElement Y1 = (SecP128R1FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SecP128R1FieldElement X1 = (SecP128R1FieldElement)this.RawXCoord, Z1 = (SecP128R1FieldElement)this.RawZCoords[0];
+
+            uint c;
+            uint[] t1 = Nat128.Create();
+            uint[] t2 = Nat128.Create();
+
+            uint[] Y1Squared = Nat128.Create();
+            SecP128R1Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat128.Create();
+            SecP128R1Field.Square(Y1Squared, T);
+
+            bool Z1IsOne = Z1.IsOne;
+
+            uint[] Z1Squared = Z1.x;
+            if (!Z1IsOne)
+            {
+                Z1Squared = t2;
+                SecP128R1Field.Square(Z1.x, Z1Squared);
+            }
+
+            SecP128R1Field.Subtract(X1.x, Z1Squared, t1);
+
+            uint[] M = t2;
+            SecP128R1Field.Add(X1.x, Z1Squared, M);
+            SecP128R1Field.Multiply(M, t1, M);
+            c = Nat128.AddBothTo(M, M, M);
+            SecP128R1Field.Reduce32(c, M);
+
+            uint[] S = Y1Squared;
+            SecP128R1Field.Multiply(Y1Squared, X1.x, S);
+            c = Nat.ShiftUpBits(4, S, 2, 0);
+            SecP128R1Field.Reduce32(c, S);
+
+            c = Nat.ShiftUpBits(4, T, 3, 0, t1);
+            SecP128R1Field.Reduce32(c, t1);
+
+            SecP128R1FieldElement X3 = new SecP128R1FieldElement(T);
+            SecP128R1Field.Square(M, X3.x);
+            SecP128R1Field.Subtract(X3.x, S, X3.x);
+            SecP128R1Field.Subtract(X3.x, S, X3.x);
+
+            SecP128R1FieldElement Y3 = new SecP128R1FieldElement(S);
+            SecP128R1Field.Subtract(S, X3.x, Y3.x);
+            SecP128R1Field.Multiply(Y3.x, M, Y3.x);
+            SecP128R1Field.Subtract(Y3.x, t1, Y3.x);
+
+            SecP128R1FieldElement Z3 = new SecP128R1FieldElement(M);
+            SecP128R1Field.Twice(Y1.x, Z3.x);
+            if (!Z1IsOne)
+            {
+                SecP128R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SecP128R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between twicePlus and threeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SecP128R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs
new file mode 100644
index 000000000..7d45c6227
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs
@@ -0,0 +1,74 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP160K1Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = SecP160R2Curve.q;
+
+        private const int SECP160K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SecP160K1Point m_infinity;
+
+        public SecP160K1Curve()
+            : base(q)
+        {
+            this.m_infinity = new SecP160K1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.Zero);
+            this.m_b = FromBigInteger(BigInteger.ValueOf(7));
+            this.m_order = new BigInteger(1, Hex.Decode("0100000000000000000001B8FA16DFAB9ACA16B6B3"));
+            this.m_cofactor = BigInteger.One;
+            this.m_coord = SECP160K1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecP160K1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_JACOBIAN:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecP160R2FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecP160K1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecP160K1Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160K1Point.cs b/crypto/src/math/ec/custom/sec/SecP160K1Point.cs
new file mode 100644
index 000000000..1bcbadb33
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160K1Point.cs
@@ -0,0 +1,269 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP160K1Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.CreatePoint to construct points
+         */
+        public SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(bool)}
+         */
+        public SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+            bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecP160K1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        // B.3 pg 62
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SecP160R2FieldElement X1 = (SecP160R2FieldElement)this.RawXCoord, Y1 = (SecP160R2FieldElement)this.RawYCoord;
+            SecP160R2FieldElement X2 = (SecP160R2FieldElement)b.RawXCoord, Y2 = (SecP160R2FieldElement)b.RawYCoord;
+
+            SecP160R2FieldElement Z1 = (SecP160R2FieldElement)this.RawZCoords[0];
+            SecP160R2FieldElement Z2 = (SecP160R2FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat160.CreateExt();
+            uint[] t2 = Nat160.Create();
+            uint[] t3 = Nat160.Create();
+            uint[] t4 = Nat160.Create();
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SecP160R2Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                SecP160R2Field.Multiply(S2, X2.x, U2);
+
+                SecP160R2Field.Multiply(S2, Z1.x, S2);
+                SecP160R2Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SecP160R2Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                SecP160R2Field.Multiply(S1, X1.x, U1);
+
+                SecP160R2Field.Multiply(S1, Z2.x, S1);
+                SecP160R2Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat160.Create();
+            SecP160R2Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            SecP160R2Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat160.IsZero(H))
+            {
+                if (Nat160.IsZero(R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SecP160R2Field.Square(H, HSquared);
+
+            uint[] G = Nat160.Create();
+            SecP160R2Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SecP160R2Field.Multiply(HSquared, U1, V);
+
+            SecP160R2Field.Negate(G, G);
+            Nat160.Mul(S1, G, tt1);
+
+            c = Nat160.AddBothTo(V, V, G);
+            SecP160R2Field.Reduce32(c, G);
+
+            SecP160R2FieldElement X3 = new SecP160R2FieldElement(t4);
+            SecP160R2Field.Square(R, X3.x);
+            SecP160R2Field.Subtract(X3.x, G, X3.x);
+
+            SecP160R2FieldElement Y3 = new SecP160R2FieldElement(G);
+            SecP160R2Field.Subtract(V, X3.x, Y3.x);
+            SecP160R2Field.MultiplyAddToExt(Y3.x, R, tt1);
+            SecP160R2Field.Reduce(tt1, Y3.x);
+
+            SecP160R2FieldElement Z3 = new SecP160R2FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SecP160R2Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SecP160R2Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+            return new SecP160K1Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        // B.3 pg 62
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SecP160R2FieldElement Y1 = (SecP160R2FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SecP160R2FieldElement X1 = (SecP160R2FieldElement)this.RawXCoord, Z1 = (SecP160R2FieldElement)this.RawZCoords[0];
+
+            uint c;
+
+            uint[] Y1Squared = Nat160.Create();
+            SecP160R2Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat160.Create();
+            SecP160R2Field.Square(Y1Squared, T);
+
+            uint[] M = Nat160.Create();
+            SecP160R2Field.Square(X1.x, M);
+            c = Nat160.AddBothTo(M, M, M);
+            SecP160R2Field.Reduce32(c, M);
+
+            uint[] S = Y1Squared;
+            SecP160R2Field.Multiply(Y1Squared, X1.x, S);
+            c = Nat.ShiftUpBits(5, S, 2, 0);
+            SecP160R2Field.Reduce32(c, S);
+
+            uint[] t1 = Nat160.Create();
+            c = Nat.ShiftUpBits(5, T, 3, 0, t1);
+            SecP160R2Field.Reduce32(c, t1);
+
+            SecP160R2FieldElement X3 = new SecP160R2FieldElement(T);
+            SecP160R2Field.Square(M, X3.x);
+            SecP160R2Field.Subtract(X3.x, S, X3.x);
+            SecP160R2Field.Subtract(X3.x, S, X3.x);
+
+            SecP160R2FieldElement Y3 = new SecP160R2FieldElement(S);
+            SecP160R2Field.Subtract(S, X3.x, Y3.x);
+            SecP160R2Field.Multiply(Y3.x, M, Y3.x);
+            SecP160R2Field.Subtract(Y3.x, t1, Y3.x);
+
+            SecP160R2FieldElement Z3 = new SecP160R2FieldElement(M);
+            SecP160R2Field.Twice(Y1.x, Z3.x);
+            if (!Z1.IsOne)
+            {
+                SecP160R2Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SecP160K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between TwicePlus and threeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SecP160K1Point(Curve, this.RawXCoord, this.RawYCoord.Negate(), this.RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs
new file mode 100644
index 000000000..87389af36
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP160R1Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = new BigInteger(1,
+            Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF"));
+
+        private const int SecP160R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SecP160R1Point m_infinity;
+
+        public SecP160R1Curve()
+            : base(q)
+        {
+            this.m_infinity = new SecP160R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1,
+                Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC")));
+            this.m_b = FromBigInteger(new BigInteger(1,
+                Hex.Decode("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45")));
+            this.m_order = new BigInteger(1, Hex.Decode("0100000000000000000001F4C8F927AED3CA752257"));
+            this.m_cofactor = BigInteger.One;
+
+            this.m_coord = SecP160R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecP160R1Curve();
+        }
+
+        public override  bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_JACOBIAN:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecP160R1FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecP160R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecP160R1Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R1Field.cs b/crypto/src/math/ec/custom/sec/SecP160R1Field.cs
new file mode 100644
index 000000000..6a5a2ef64
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R1Field.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP160R1Field
+    {
+        // 2^160 - 2^31 - 1
+        internal static readonly uint[] P = new uint[] { 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
+        internal static readonly uint[] PExt = new uint[] { 0x00000001, 0x40000001, 0x00000000, 0x00000000, 0x00000000,
+            0xFFFFFFFE, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+        private static readonly uint[] PExtInv = new uint[]{ 0xFFFFFFFF, 0xBFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+            0xFFFFFFFF, 0x00000001, 0x00000001 };
+        private const uint P4 = 0xFFFFFFFF;
+        private const uint PExt9 = 0xFFFFFFFF;
+        private const uint PInv = 0x80000001;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            uint c = Nat160.Add(x, y, z);
+            if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+            {
+                Nat.AddWordTo(5, PInv, z);
+            }
+        }
+
+        public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            uint c = Nat.Add(10, xx, yy, zz);
+            if (c != 0 || (zz[9] == PExt9 && Nat.Gte(10, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(10, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            uint c = Nat.Inc(5, x, z);
+            if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+            {
+                Nat.AddWordTo(5, PInv, z);
+            }
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat160.FromBigInteger(x);
+            if (z[4] == P4 && Nat160.Gte(z, P))
+            {
+                Nat160.SubFrom(P, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            if ((x[0] & 1) == 0)
+            {
+                Nat.ShiftDownBit(5, x, 0, z);
+            }
+            else
+            {
+                uint c = Nat160.Add(x, P, z);
+                Nat.ShiftDownBit(5, z, c);
+            }
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat160.CreateExt();
+            Nat160.Mul(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+        {
+            uint c = Nat160.MulAddTo(x, y, zz);
+            if (c != 0 || (zz[9] == PExt9 && Nat.Gte(10, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(10, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat160.IsZero(x))
+            {
+                Nat160.Zero(z);
+            }
+            else
+            {
+                Nat160.Sub(P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            ulong x5 = xx[5], x6 = xx[6], x7 = xx[7], x8 = xx[8], x9 = xx[9];
+
+            ulong c = 0;
+            c += (ulong)xx[0] + x5 + (x5 << 31);
+            z[0] = (uint)c; c >>= 32;
+            c += (ulong)xx[1] + x6 + (x6 << 31);
+            z[1] = (uint)c; c >>= 32;
+            c += (ulong)xx[2] + x7 + (x7 << 31);
+            z[2] = (uint)c; c >>= 32;
+            c += (ulong)xx[3] + x8 + (x8 << 31);
+            z[3] = (uint)c; c >>= 32;
+            c += (ulong)xx[4] + x9 + (x9 << 31);
+            z[4] = (uint)c; c >>= 32;
+
+            Debug.Assert(c >> 32 == 0);
+
+            Reduce32((uint)c, z);
+        }
+
+        public static void Reduce32(uint x, uint[] z)
+        {
+            if ((x != 0 && Nat160.MulWordsAdd(PInv, x, z, 0) != 0)
+                || (z[4] == P4 && Nat160.Gte(z, P)))
+            {
+                Nat.AddWordTo(5, PInv, z);
+            }
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat160.CreateExt();
+            Nat160.Square(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+
+            uint[] tt = Nat160.CreateExt();
+            Nat160.Square(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                Nat160.Square(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat160.Sub(x, y, z);
+            if (c != 0)
+            {
+                Nat.SubWordFrom(5, PInv, z);
+            }
+        }
+
+        public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            int c = Nat.Sub(10, xx, yy, zz);
+            if (c != 0)
+            {
+                if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.DecAt(10, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            uint c = Nat.ShiftUpBit(5, x, 0, z);
+            if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+            {
+                Nat.AddWordTo(5, PInv, z);
+            }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs
new file mode 100644
index 000000000..d1fc75644
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs
@@ -0,0 +1,203 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP160R1FieldElement
+        : ECFieldElement
+    {
+        public static readonly BigInteger Q = SecP160R1Curve.q;
+
+        protected internal readonly uint[] x;
+
+        public SecP160R1FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for SecP160R1FieldElement", "x");
+
+            this.x = SecP160R1Field.FromBigInteger(x);
+        }
+
+        public SecP160R1FieldElement()
+        {
+            this.x = Nat160.Create();
+        }
+
+        protected internal SecP160R1FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat160.IsZero(x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat160.IsOne(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat160.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat160.ToBigInteger(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecP160R1Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat160.Create();
+            SecP160R1Field.Add(x, ((SecP160R1FieldElement)b).x, z);
+            return new SecP160R1FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat160.Create();
+            SecP160R1Field.AddOne(x, z);
+            return new SecP160R1FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat160.Create();
+            SecP160R1Field.Subtract(x, ((SecP160R1FieldElement)b).x, z);
+            return new SecP160R1FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat160.Create();
+            SecP160R1Field.Multiply(x, ((SecP160R1FieldElement)b).x, z);
+            return new SecP160R1FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+    //        return multiply(b.invert());
+            uint[] z = Nat160.Create();
+            Mod.Invert(SecP160R1Field.P, ((SecP160R1FieldElement)b).x, z);
+            SecP160R1Field.Multiply(z, x, z);
+            return new SecP160R1FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat160.Create();
+            SecP160R1Field.Negate(x, z);
+            return new SecP160R1FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat160.Create();
+            SecP160R1Field.Square(x, z);
+            return new SecP160R1FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+    //        return new SecP160R1FieldElement(ToBigInteger().modInverse(Q));
+            uint[] z = Nat160.Create();
+            Mod.Invert(SecP160R1Field.P, x, z);
+            return new SecP160R1FieldElement(z);
+        }
+
+        // D.1.4 91
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            /*
+             * Raise this element to the exponent 2^158 - 2^29
+             * 
+             * Breaking up the exponent's binary representation into "repunits", we get:
+             *     { 129 1s } { 29 0s }
+             * 
+             * Therefore we need an addition chain containing 129 (the length of the repunit) We use:
+             *     1, 2, 4, 8, 16, 32, 64, 128, [129]
+             */
+
+            uint[] x1 = this.x;
+            if (Nat160.IsZero(x1) || Nat160.IsOne(x1))
+            {
+                return this;
+            }
+
+            uint[] x2 = Nat160.Create();
+            SecP160R1Field.Square(x1, x2);
+            SecP160R1Field.Multiply(x2, x1, x2);
+            uint[] x4 = Nat160.Create();
+            SecP160R1Field.SquareN(x2, 2, x4);
+            SecP160R1Field.Multiply(x4, x2, x4);
+            uint[] x8 = x2;
+            SecP160R1Field.SquareN(x4, 4, x8);
+            SecP160R1Field.Multiply(x8, x4, x8);
+            uint[] x16 = x4;
+            SecP160R1Field.SquareN(x8, 8, x16);
+            SecP160R1Field.Multiply(x16, x8, x16);
+            uint[] x32 = x8;
+            SecP160R1Field.SquareN(x16, 16, x32);
+            SecP160R1Field.Multiply(x32, x16, x32);
+            uint[] x64 = x16;
+            SecP160R1Field.SquareN(x32, 32, x64);
+            SecP160R1Field.Multiply(x64, x32, x64);
+            uint[] x128 = x32;
+            SecP160R1Field.SquareN(x64, 64, x128);
+            SecP160R1Field.Multiply(x128, x64, x128);
+            uint[] x129 = x64;
+            SecP160R1Field.Square(x128, x129);
+            SecP160R1Field.Multiply(x129, x1, x129);
+
+            uint[] t1 = x129;
+            SecP160R1Field.SquareN(t1, 29, t1);
+
+            uint[] t2 = x128;
+            SecP160R1Field.Square(t1, t2);
+
+            return Nat160.Eq(x1, t2) ? new SecP160R1FieldElement(t1) : null;        
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecP160R1FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecP160R1FieldElement);
+        }
+
+        public virtual bool Equals(SecP160R1FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat160.Eq(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 5);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R1Point.cs b/crypto/src/math/ec/custom/sec/SecP160R1Point.cs
new file mode 100644
index 000000000..f9f065de6
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R1Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP160R1Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.CreatePoint to construct points
+         */
+        public SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(bool)}
+         */
+        public SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecP160R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SecP160R1FieldElement X1 = (SecP160R1FieldElement)this.RawXCoord, Y1 = (SecP160R1FieldElement)this.RawYCoord;
+            SecP160R1FieldElement X2 = (SecP160R1FieldElement)b.RawXCoord, Y2 = (SecP160R1FieldElement)b.RawYCoord;
+
+            SecP160R1FieldElement Z1 = (SecP160R1FieldElement)this.RawZCoords[0];
+            SecP160R1FieldElement Z2 = (SecP160R1FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat160.CreateExt();
+            uint[] t2 = Nat160.Create();
+            uint[] t3 = Nat160.Create();
+            uint[] t4 = Nat160.Create();
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SecP160R1Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                SecP160R1Field.Multiply(S2, X2.x, U2);
+
+                SecP160R1Field.Multiply(S2, Z1.x, S2);
+                SecP160R1Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SecP160R1Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                SecP160R1Field.Multiply(S1, X1.x, U1);
+
+                SecP160R1Field.Multiply(S1, Z2.x, S1);
+                SecP160R1Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat160.Create();
+            SecP160R1Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            SecP160R1Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat160.IsZero(H))
+            {
+                if (Nat160.IsZero(R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SecP160R1Field.Square(H, HSquared);
+
+            uint[] G = Nat160.Create();
+            SecP160R1Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SecP160R1Field.Multiply(HSquared, U1, V);
+
+            SecP160R1Field.Negate(G, G);
+            Nat160.Mul(S1, G, tt1);
+
+            c = Nat160.AddBothTo(V, V, G);
+            SecP160R1Field.Reduce32(c, G);
+
+            SecP160R1FieldElement X3 = new SecP160R1FieldElement(t4);
+            SecP160R1Field.Square(R, X3.x);
+            SecP160R1Field.Subtract(X3.x, G, X3.x);
+
+            SecP160R1FieldElement Y3 = new SecP160R1FieldElement(G);
+            SecP160R1Field.Subtract(V, X3.x, Y3.x);
+            SecP160R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+            SecP160R1Field.Reduce(tt1, Y3.x);
+
+            SecP160R1FieldElement Z3 = new SecP160R1FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SecP160R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SecP160R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+            return new SecP160R1Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SecP160R1FieldElement Y1 = (SecP160R1FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SecP160R1FieldElement X1 = (SecP160R1FieldElement)this.RawXCoord, Z1 = (SecP160R1FieldElement)this.RawZCoords[0];
+
+            uint c;
+            uint[] t1 = Nat160.Create();
+            uint[] t2 = Nat160.Create();
+
+            uint[] Y1Squared = Nat160.Create();
+            SecP160R1Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat160.Create();
+            SecP160R1Field.Square(Y1Squared, T);
+
+            bool Z1IsOne = Z1.IsOne;
+
+            uint[] Z1Squared = Z1.x;
+            if (!Z1IsOne)
+            {
+                Z1Squared = t2;
+                SecP160R1Field.Square(Z1.x, Z1Squared);
+            }
+
+            SecP160R1Field.Subtract(X1.x, Z1Squared, t1);
+
+            uint[] M = t2;
+            SecP160R1Field.Add(X1.x, Z1Squared, M);
+            SecP160R1Field.Multiply(M, t1, M);
+            c = Nat160.AddBothTo(M, M, M);
+            SecP160R1Field.Reduce32(c, M);
+
+            uint[] S = Y1Squared;
+            SecP160R1Field.Multiply(Y1Squared, X1.x, S);
+            c = Nat.ShiftUpBits(5, S, 2, 0);
+            SecP160R1Field.Reduce32(c, S);
+
+            c = Nat.ShiftUpBits(5, T, 3, 0, t1);
+            SecP160R1Field.Reduce32(c, t1);
+
+            SecP160R1FieldElement X3 = new SecP160R1FieldElement(T);
+            SecP160R1Field.Square(M, X3.x);
+            SecP160R1Field.Subtract(X3.x, S, X3.x);
+            SecP160R1Field.Subtract(X3.x, S, X3.x);
+
+            SecP160R1FieldElement Y3 = new SecP160R1FieldElement(S);
+            SecP160R1Field.Subtract(S, X3.x, Y3.x);
+            SecP160R1Field.Multiply(Y3.x, M, Y3.x);
+            SecP160R1Field.Subtract(Y3.x, t1, Y3.x);
+
+            SecP160R1FieldElement Z3 = new SecP160R1FieldElement(M);
+            SecP160R1Field.Twice(Y1.x, Z3.x);
+            if (!Z1IsOne)
+            {
+                SecP160R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SecP160R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SecP160R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs b/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs
new file mode 100644
index 000000000..100561453
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP160R2Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = new BigInteger(1,
+            Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73"));
+
+        private const int SecP160R2_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SecP160R2Point m_infinity;
+
+        public SecP160R2Curve()
+            : base(q)
+        {
+            this.m_infinity = new SecP160R2Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1,
+                Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70")));
+            this.m_b = FromBigInteger(new BigInteger(1,
+                Hex.Decode("B4E134D3FB59EB8BAB57274904664D5AF50388BA")));
+            this.m_order = new BigInteger(1, Hex.Decode("0100000000000000000000351EE786A818F3A1A16B"));
+            this.m_cofactor = BigInteger.One;
+
+            this.m_coord = SecP160R2_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecP160R2Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_JACOBIAN:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecP160R2FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecP160R2Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecP160R2Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R2Field.cs b/crypto/src/math/ec/custom/sec/SecP160R2Field.cs
new file mode 100644
index 000000000..1bef32eea
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R2Field.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP160R2Field
+    {
+        // 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+        internal static readonly uint[] P = new uint[]{ 0xFFFFAC73, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+        internal static readonly uint[] PExt = new uint[]{ 0x1B44BBA9, 0x0000A71A, 0x00000001, 0x00000000, 0x00000000,
+            0xFFFF58E6, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+        private static readonly uint[] PExtInv = new uint[]{ 0xE4BB4457, 0xFFFF58E5, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+            0x0000A719, 0x00000002 };
+        private const uint P4 = 0xFFFFFFFF;
+        private const uint PExt9 = 0xFFFFFFFF;
+        private const uint PInv33 = 0x538D;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            uint c = Nat160.Add(x, y, z);
+            if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+            {
+                Nat.Add33To(5, PInv33, z);
+            }
+        }
+
+        public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            uint c = Nat.Add(10, xx, yy, zz);
+            if (c != 0 || (zz[9] == PExt9 && Nat.Gte(10, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(10, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            uint c = Nat.Inc(5, x, z);
+            if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+            {
+                Nat.Add33To(5, PInv33, z);
+            }
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat160.FromBigInteger(x);
+            if (z[4] == P4 && Nat160.Gte(z, P))
+            {
+                Nat160.SubFrom(P, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            if ((x[0] & 1) == 0)
+            {
+                Nat.ShiftDownBit(5, x, 0, z);
+            }
+            else
+            {
+                uint c = Nat160.Add(x, P, z);
+                Nat.ShiftDownBit(5, z, c);
+            }
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat160.CreateExt();
+            Nat160.Mul(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+        {
+            uint c = Nat160.MulAddTo(x, y, zz);
+            if (c != 0 || (zz[9] == PExt9 && Nat.Gte(10, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(10, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat160.IsZero(x))
+            {
+                Nat160.Zero(z);
+            }
+            else
+            {
+                Nat160.Sub(P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            ulong cc = Nat160.Mul33Add(PInv33, xx, 5, xx, 0, z, 0);
+            uint c = Nat160.Mul33DWordAdd(PInv33, cc, z, 0);
+
+            Debug.Assert(c == 0 || c == 1);
+
+            if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+            {
+                Nat.Add33To(5, PInv33, z);
+            }
+        }
+
+        public static void Reduce32(uint x, uint[] z)
+        {
+            if ((x != 0 && Nat160.Mul33WordAdd(PInv33, x, z, 0) != 0)
+                || (z[4] == P4 && Nat160.Gte(z, P)))
+            {
+                Nat.Add33To(5, PInv33, z);
+            }
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat160.CreateExt();
+            Nat160.Square(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+
+            uint[] tt = Nat160.CreateExt();
+            Nat160.Square(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                Nat160.Square(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat160.Sub(x, y, z);
+            if (c != 0)
+            {
+                Nat.Sub33From(5, PInv33, z);
+            }
+        }
+
+        public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            int c = Nat.Sub(10, xx, yy, zz);
+            if (c != 0)
+            {
+                if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.DecAt(10, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            uint c = Nat.ShiftUpBit(5, x, 0, z);
+            if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+            {
+                Nat.Add33To(5, PInv33, z);
+            }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs
new file mode 100644
index 000000000..bdb5245b2
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs
@@ -0,0 +1,218 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP160R2FieldElement
+        : ECFieldElement
+    {
+        public static readonly BigInteger Q = SecP160R2Curve.q;
+
+        protected internal readonly uint[] x;
+
+        public SecP160R2FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for SecP160R2FieldElement", "x");
+
+            this.x = SecP160R2Field.FromBigInteger(x);
+        }
+
+        public SecP160R2FieldElement()
+        {
+            this.x = Nat160.Create();
+        }
+
+        protected internal SecP160R2FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat160.IsZero(x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat160.IsOne(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat160.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat160.ToBigInteger(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecP160R2Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat160.Create();
+            SecP160R2Field.Add(x, ((SecP160R2FieldElement)b).x, z);
+            return new SecP160R2FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat160.Create();
+            SecP160R2Field.AddOne(x, z);
+            return new SecP160R2FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat160.Create();
+            SecP160R2Field.Subtract(x, ((SecP160R2FieldElement)b).x, z);
+            return new SecP160R2FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat160.Create();
+            SecP160R2Field.Multiply(x, ((SecP160R2FieldElement)b).x, z);
+            return new SecP160R2FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+    //        return Multiply(b.invert());
+            uint[] z = Nat160.Create();
+            Mod.Invert(SecP160R2Field.P, ((SecP160R2FieldElement)b).x, z);
+            SecP160R2Field.Multiply(z, x, z);
+            return new SecP160R2FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat160.Create();
+            SecP160R2Field.Negate(x, z);
+            return new SecP160R2FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat160.Create();
+            SecP160R2Field.Square(x, z);
+            return new SecP160R2FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+    //        return new SecP160R2FieldElement(ToBigInteger().modInverse(Q));
+            uint[] z = Nat160.Create();
+            Mod.Invert(SecP160R2Field.P, x, z);
+            return new SecP160R2FieldElement(z);
+        }
+
+        // D.1.4 91
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            /*
+             * Raise this element to the exponent 2^158 - 2^30 - 2^12 - 2^10 - 2^7 - 2^6 - 2^5 - 2^1 - 2^0
+             * 
+             * Breaking up the exponent's binary representation into "repunits", we get: { 127 1s } { 1
+             * 0s } { 17 1s } { 1 0s } { 1 1s } { 1 0s } { 2 1s } { 3 0s } { 3 1s } { 1 0s } { 1 1s }
+             * 
+             * Therefore we need an Addition chain containing 1, 2, 3, 17, 127 (the lengths of the repunits)
+             * We use: [1], [2], [3], 4, 7, 14, [17], 31, 62, 124, [127]
+             */
+
+            uint[] x1 = this.x;
+            if (Nat160.IsZero(x1) || Nat160.IsOne(x1))
+            {
+                return this;
+            }
+
+            uint[] x2 = Nat160.Create();
+            SecP160R2Field.Square(x1, x2);
+            SecP160R2Field.Multiply(x2, x1, x2);
+            uint[] x3 = Nat160.Create();
+            SecP160R2Field.Square(x2, x3);
+            SecP160R2Field.Multiply(x3, x1, x3);
+            uint[] x4 = Nat160.Create();
+            SecP160R2Field.Square(x3, x4);
+            SecP160R2Field.Multiply(x4, x1, x4);
+            uint[] x7 = Nat160.Create();
+            SecP160R2Field.SquareN(x4, 3, x7);
+            SecP160R2Field.Multiply(x7, x3, x7);
+            uint[] x14 = x4;
+            SecP160R2Field.SquareN(x7, 7, x14);
+            SecP160R2Field.Multiply(x14, x7, x14);
+            uint[] x17 = x7;
+            SecP160R2Field.SquareN(x14, 3, x17);
+            SecP160R2Field.Multiply(x17, x3, x17);
+            uint[] x31 = Nat160.Create();
+            SecP160R2Field.SquareN(x17, 14, x31);
+            SecP160R2Field.Multiply(x31, x14, x31);
+            uint[] x62 = x14;
+            SecP160R2Field.SquareN(x31, 31, x62);
+            SecP160R2Field.Multiply(x62, x31, x62);
+            uint[] x124 = x31;
+            SecP160R2Field.SquareN(x62, 62, x124);
+            SecP160R2Field.Multiply(x124, x62, x124);
+            uint[] x127 = x62;
+            SecP160R2Field.SquareN(x124, 3, x127);
+            SecP160R2Field.Multiply(x127, x3, x127);
+
+            uint[] t1 = x127;
+            SecP160R2Field.SquareN(t1, 18, t1);
+            SecP160R2Field.Multiply(t1, x17, t1);
+            SecP160R2Field.SquareN(t1, 2, t1);
+            SecP160R2Field.Multiply(t1, x1, t1);
+            SecP160R2Field.SquareN(t1, 3, t1);
+            SecP160R2Field.Multiply(t1, x2, t1);
+            SecP160R2Field.SquareN(t1, 6, t1);
+            SecP160R2Field.Multiply(t1, x3, t1);
+            SecP160R2Field.SquareN(t1, 2, t1);
+            SecP160R2Field.Multiply(t1, x1, t1);
+
+            uint[] t2 = x2;
+            SecP160R2Field.Square(t1, t2);
+
+            return Nat160.Eq(x1, t2) ? new SecP160R2FieldElement(t1) : null;        
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecP160R2FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecP160R2FieldElement);
+        }
+
+        public virtual bool Equals(SecP160R2FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat160.Eq(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 5);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP160R2Point.cs b/crypto/src/math/ec/custom/sec/SecP160R2Point.cs
new file mode 100644
index 000000000..343cf8c16
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP160R2Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP160R2Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.CreatePoint to construct points
+         */
+        public SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(bool)}
+         */
+        public SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecP160R2Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SecP160R2FieldElement X1 = (SecP160R2FieldElement)this.RawXCoord, Y1 = (SecP160R2FieldElement)this.RawYCoord;
+            SecP160R2FieldElement X2 = (SecP160R2FieldElement)b.RawXCoord, Y2 = (SecP160R2FieldElement)b.RawYCoord;
+
+            SecP160R2FieldElement Z1 = (SecP160R2FieldElement)this.RawZCoords[0];
+            SecP160R2FieldElement Z2 = (SecP160R2FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat160.CreateExt();
+            uint[] t2 = Nat160.Create();
+            uint[] t3 = Nat160.Create();
+            uint[] t4 = Nat160.Create();
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SecP160R2Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                SecP160R2Field.Multiply(S2, X2.x, U2);
+
+                SecP160R2Field.Multiply(S2, Z1.x, S2);
+                SecP160R2Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SecP160R2Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                SecP160R2Field.Multiply(S1, X1.x, U1);
+
+                SecP160R2Field.Multiply(S1, Z2.x, S1);
+                SecP160R2Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat160.Create();
+            SecP160R2Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            SecP160R2Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat160.IsZero(H))
+            {
+                if (Nat160.IsZero(R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SecP160R2Field.Square(H, HSquared);
+
+            uint[] G = Nat160.Create();
+            SecP160R2Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SecP160R2Field.Multiply(HSquared, U1, V);
+
+            SecP160R2Field.Negate(G, G);
+            Nat160.Mul(S1, G, tt1);
+
+            c = Nat160.AddBothTo(V, V, G);
+            SecP160R2Field.Reduce32(c, G);
+
+            SecP160R2FieldElement X3 = new SecP160R2FieldElement(t4);
+            SecP160R2Field.Square(R, X3.x);
+            SecP160R2Field.Subtract(X3.x, G, X3.x);
+
+            SecP160R2FieldElement Y3 = new SecP160R2FieldElement(G);
+            SecP160R2Field.Subtract(V, X3.x, Y3.x);
+            SecP160R2Field.MultiplyAddToExt(Y3.x, R, tt1);
+            SecP160R2Field.Reduce(tt1, Y3.x);
+
+            SecP160R2FieldElement Z3 = new SecP160R2FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SecP160R2Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SecP160R2Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+            return new SecP160R2Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SecP160R2FieldElement Y1 = (SecP160R2FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SecP160R2FieldElement X1 = (SecP160R2FieldElement)this.RawXCoord, Z1 = (SecP160R2FieldElement)this.RawZCoords[0];
+
+            uint c;
+            uint[] t1 = Nat160.Create();
+            uint[] t2 = Nat160.Create();
+
+            uint[] Y1Squared = Nat160.Create();
+            SecP160R2Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat160.Create();
+            SecP160R2Field.Square(Y1Squared, T);
+
+            bool Z1IsOne = Z1.IsOne;
+
+            uint[] Z1Squared = Z1.x;
+            if (!Z1IsOne)
+            {
+                Z1Squared = t2;
+                SecP160R2Field.Square(Z1.x, Z1Squared);
+            }
+
+            SecP160R2Field.Subtract(X1.x, Z1Squared, t1);
+
+            uint[] M = t2;
+            SecP160R2Field.Add(X1.x, Z1Squared, M);
+            SecP160R2Field.Multiply(M, t1, M);
+            c = Nat160.AddBothTo(M, M, M);
+            SecP160R2Field.Reduce32(c, M);
+
+            uint[] S = Y1Squared;
+            SecP160R2Field.Multiply(Y1Squared, X1.x, S);
+            c = Nat.ShiftUpBits(5, S, 2, 0);
+            SecP160R2Field.Reduce32(c, S);
+
+            c = Nat.ShiftUpBits(5, T, 3, 0, t1);
+            SecP160R2Field.Reduce32(c, t1);
+
+            SecP160R2FieldElement X3 = new SecP160R2FieldElement(T);
+            SecP160R2Field.Square(M, X3.x);
+            SecP160R2Field.Subtract(X3.x, S, X3.x);
+            SecP160R2Field.Subtract(X3.x, S, X3.x);
+
+            SecP160R2FieldElement Y3 = new SecP160R2FieldElement(S);
+            SecP160R2Field.Subtract(S, X3.x, Y3.x);
+            SecP160R2Field.Multiply(Y3.x, M, Y3.x);
+            SecP160R2Field.Subtract(Y3.x, t1, Y3.x);
+
+            SecP160R2FieldElement Z3 = new SecP160R2FieldElement(M);
+            SecP160R2Field.Twice(Y1.x, Z3.x);
+            if (!Z1IsOne)
+            {
+                SecP160R2Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SecP160R2Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SecP160R2Point(Curve, this.RawXCoord, this.RawYCoord.Negate(), this.RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1Field.cs b/crypto/src/math/ec/custom/sec/SecP192K1Field.cs
index d5ca903d1..a00360360 100644
--- a/crypto/src/math/ec/custom/sec/SecP192K1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192K1Field.cs
@@ -1,6 +1,8 @@
 using System;
 using System.Diagnostics;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP192K1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
index 78886dd8c..dce377035 100644
--- a/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Diagnostics;
 
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1Point.cs b/crypto/src/math/ec/custom/sec/SecP192K1Point.cs
index 648aca502..58eb09102 100644
--- a/crypto/src/math/ec/custom/sec/SecP192K1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192K1Point.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP192K1Point
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1Field.cs b/crypto/src/math/ec/custom/sec/SecP192R1Field.cs
index 85e3a0394..096c2b51f 100644
--- a/crypto/src/math/ec/custom/sec/SecP192R1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192R1Field.cs
@@ -1,6 +1,8 @@
 using System;
 using System.Diagnostics;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP192R1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
index 020c5cdbb..45bcb00f0 100644
--- a/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1Point.cs b/crypto/src/math/ec/custom/sec/SecP192R1Point.cs
index 797a8de35..3b53e341e 100644
--- a/crypto/src/math/ec/custom/sec/SecP192R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192R1Point.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP192R1Point
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1Field.cs b/crypto/src/math/ec/custom/sec/SecP224K1Field.cs
index a55810c6d..98cf777a5 100644
--- a/crypto/src/math/ec/custom/sec/SecP224K1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224K1Field.cs
@@ -1,6 +1,8 @@
 using System;
 using System.Diagnostics;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP224K1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
index 72ff4b099..fec07436a 100644
--- a/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Diagnostics;
 
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1Point.cs b/crypto/src/math/ec/custom/sec/SecP224K1Point.cs
index 8cbd29699..98cb29274 100644
--- a/crypto/src/math/ec/custom/sec/SecP224K1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224K1Point.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP224K1Point
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1Field.cs b/crypto/src/math/ec/custom/sec/SecP224R1Field.cs
index 559593c66..4f5c3bbda 100644
--- a/crypto/src/math/ec/custom/sec/SecP224R1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224R1Field.cs
@@ -1,6 +1,8 @@
 using System;
 using System.Diagnostics;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP224R1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
index 06f47cded..2b9a06564 100644
--- a/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1Point.cs b/crypto/src/math/ec/custom/sec/SecP224R1Point.cs
index c3f4efb59..73c4f1948 100644
--- a/crypto/src/math/ec/custom/sec/SecP224R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224R1Point.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP224R1Point
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1Field.cs b/crypto/src/math/ec/custom/sec/SecP256K1Field.cs
index ba3a070a9..b0646e93f 100644
--- a/crypto/src/math/ec/custom/sec/SecP256K1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256K1Field.cs
@@ -1,6 +1,8 @@
 using System;
 using System.Diagnostics;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP256K1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
index d9a039a4f..473113d0f 100644
--- a/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Diagnostics;
 
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1Point.cs b/crypto/src/math/ec/custom/sec/SecP256K1Point.cs
index 3165682fa..072a0b969 100644
--- a/crypto/src/math/ec/custom/sec/SecP256K1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256K1Point.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP256K1Point
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1Field.cs b/crypto/src/math/ec/custom/sec/SecP256R1Field.cs
index 9ed9dcd41..11594b2ba 100644
--- a/crypto/src/math/ec/custom/sec/SecP256R1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256R1Field.cs
@@ -1,6 +1,8 @@
 using System;
 using System.Diagnostics;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP256R1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
index b22763cfa..d7838aead 100644
--- a/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1Point.cs b/crypto/src/math/ec/custom/sec/SecP256R1Point.cs
index 1de4a0b4a..83320824d 100644
--- a/crypto/src/math/ec/custom/sec/SecP256R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256R1Point.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP256R1Point
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1Field.cs b/crypto/src/math/ec/custom/sec/SecP384R1Field.cs
index 508b01e3c..7820775ee 100644
--- a/crypto/src/math/ec/custom/sec/SecP384R1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP384R1Field.cs
@@ -1,6 +1,8 @@
 using System;
 using System.Diagnostics;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP384R1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
index 40086978d..18d48a57d 100644
--- a/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1Point.cs b/crypto/src/math/ec/custom/sec/SecP384R1Point.cs
index 68c601611..83159ce61 100644
--- a/crypto/src/math/ec/custom/sec/SecP384R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP384R1Point.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP384R1Point
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1Field.cs b/crypto/src/math/ec/custom/sec/SecP521R1Field.cs
index 3568156d8..b7f8eb146 100644
--- a/crypto/src/math/ec/custom/sec/SecP521R1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP521R1Field.cs
@@ -1,6 +1,8 @@
 using System;
 using System.Diagnostics;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP521R1Field
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
index 83a615928..6f02a7eb5 100644
--- a/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1Point.cs b/crypto/src/math/ec/custom/sec/SecP521R1Point.cs
index fb1996cfd..7ad97f76f 100644
--- a/crypto/src/math/ec/custom/sec/SecP521R1Point.cs
+++ b/crypto/src/math/ec/custom/sec/SecP521R1Point.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Math.Raw;
+
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP521R1Point
diff --git a/crypto/src/math/ec/custom/sec/SecT113Field.cs b/crypto/src/math/ec/custom/sec/SecT113Field.cs
new file mode 100644
index 000000000..dbb645e6f
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113Field.cs
@@ -0,0 +1,180 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT113Field
+    {
+        private const ulong M49 = ulong.MaxValue >> 15;
+        private const ulong M57 = ulong.MaxValue >> 7;
+
+        public static void Add(ulong[] x, ulong[] y, ulong[] z)
+        {
+            z[0] = x[0] ^ y[0];
+            z[1] = x[1] ^ y[1];
+        }
+
+        public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+        {
+            zz[0] = xx[0] ^ yy[0];
+            zz[1] = xx[1] ^ yy[1];
+            zz[2] = xx[2] ^ yy[2];
+            zz[3] = xx[3] ^ yy[3];
+        }
+
+        public static void AddOne(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0] ^ 1UL;
+            z[1] = x[1];
+        }
+
+        public static ulong[] FromBigInteger(BigInteger x)
+        {
+            ulong[] z = Nat128.FromBigInteger64(x);
+            Reduce15(z, 0);
+            return z;
+        }
+
+        public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+        {
+            ulong[] tt = Nat128.CreateExt64();
+            ImplMultiply(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            ulong[] tt = Nat128.CreateExt64();
+            ImplMultiply(x, y, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void Reduce(ulong[] xx, ulong[] z)
+        {
+            ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3];
+
+            x1 ^= (x3 << 15) ^ (x3 << 24);
+            x2 ^= (x3 >> 49) ^ (x3 >> 40);
+
+            x0 ^= (x2 << 15) ^ (x2 << 24);
+            x1 ^= (x2 >> 49) ^ (x2 >> 40);
+
+            ulong t = x1 >> 49;
+            z[0]    = x0 ^ t ^ (t << 9);
+            z[1]    = x1 & M49;
+        }
+
+        public static void Reduce15(ulong[] z, int zOff)
+        {
+            ulong z1     = z[zOff + 1], t = z1 >> 49;
+            z[zOff    ] ^= t ^ (t << 9);
+            z[zOff + 1]  = z1 & M49;
+        }
+
+        public static void Square(ulong[] x, ulong[] z)
+        {
+            ulong[] tt = Nat128.CreateExt64();
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareAddToExt(ulong[] x, ulong[] zz)
+        {
+            ulong[] tt = Nat128.CreateExt64();
+            ImplSquare(x, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void SquareN(ulong[] x, int n, ulong[] z)
+        {
+            Debug.Assert(n > 0);
+
+            ulong[] tt = Nat128.CreateExt64();
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                ImplSquare(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            /*
+             * "Three-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+             */
+
+            ulong f0 = x[0], f1 = x[1];
+            f1  = ((f0 >> 57) ^ (f1 << 7)) & M57;
+            f0 &= M57;
+
+            ulong g0 = y[0], g1 = y[1];
+            g1  = ((g0 >> 57) ^ (g1 << 7)) & M57;
+            g0 &= M57;
+
+            ulong[] H = new ulong[6];
+
+            ImplMulw(f0, g0, H, 0);               // H(0)       57/56 bits                                
+            ImplMulw(f1, g1, H, 2);               // H(INF)     57/54 bits                                
+            ImplMulw(f0 ^ f1, g0 ^ g1, H, 4);     // H(1)       57/56 bits
+
+            ulong r  = H[1] ^ H[2];
+            ulong z0 = H[0],
+                  z3 = H[3],
+                  z1 = H[4] ^ z0 ^ r,
+                  z2 = H[5] ^ z3 ^ r;
+
+            zz[0] =  z0        ^ (z1 << 57);
+            zz[1] = (z1 >>  7) ^ (z2 << 50);
+            zz[2] = (z2 >> 14) ^ (z3 << 43);
+            zz[3] = (z3 >> 21);
+        }
+
+        protected static void ImplMulw(ulong x, ulong y, ulong[] z, int zOff)
+        {
+            Debug.Assert(x >> 57 == 0);
+            Debug.Assert(y >> 57 == 0);
+
+            ulong[] u = new ulong[8];
+            //u[0] = 0;
+            u[1] = y;
+            u[2] = u[1] << 1;
+            u[3] = u[2] ^ y;
+            u[4] = u[2] << 1;
+            u[5] = u[4] ^ y;
+            u[6] = u[3] << 1;
+            u[7] = u[6] ^ y;
+
+            uint j = (uint)x;
+            ulong g, h = 0, l = u[j & 7];
+            int k = 48;
+            do
+            {
+                j  = (uint)(x >> k);
+                g  = u[j & 7]
+                   ^ u[(j >> 3) & 7] << 3
+                   ^ u[(j >> 6) & 7] << 6;
+                l ^= (g << k);
+                h ^= (g >> -k);
+            }
+            while ((k -= 9) > 0);
+
+            h ^= ((x & 0x0100804020100800UL) & (ulong)(((long)y << 7) >> 63)) >> 8;
+
+            Debug.Assert(h >> 49 == 0);
+
+            z[zOff    ] = l & M57;
+            z[zOff + 1] = (l >> 57) ^ (h << 7);
+        }
+
+        protected static void ImplSquare(ulong[] x, ulong[] zz)
+        {
+            Interleave.Expand64To128(x[0], zz, 0);
+            Interleave.Expand64To128(x[1], zz, 2);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
new file mode 100644
index 000000000..7e9d53e44
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
@@ -0,0 +1,213 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT113FieldElement
+        : ECFieldElement
+    {
+        protected internal readonly ulong[] x;
+
+        public SecT113FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0)
+                throw new ArgumentException("value invalid for SecT113FieldElement", "x");
+
+            this.x = SecT113Field.FromBigInteger(x);
+        }
+
+        public SecT113FieldElement()
+        {
+            this.x = Nat128.Create64();
+        }
+
+        protected internal SecT113FieldElement(ulong[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat128.IsOne64(x); }
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat128.IsZero64(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return (x[0] & 1L) != 0L;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat128.ToBigInteger64(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecT113Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 113; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            ulong[] z = Nat128.Create64();
+            SecT113Field.Add(x, ((SecT113FieldElement)b).x, z);
+            return new SecT113FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            ulong[] z = Nat128.Create64();
+            SecT113Field.AddOne(x, z);
+            return new SecT113FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            // Addition and Subtraction are the same in F2m
+            return Add(b);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            ulong[] z = Nat128.Create64();
+            SecT113Field.Multiply(x, ((SecT113FieldElement)b).x, z);
+            return new SecT113FieldElement(z);
+        }
+
+        public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            return MultiplyPlusProduct(b, x, y);
+        }
+
+        public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x, bx = ((SecT113FieldElement)b).x;
+            ulong[] xx = ((SecT113FieldElement)x).x, yx = ((SecT113FieldElement)y).x;
+
+            ulong[] tt = Nat128.CreateExt64();
+            SecT113Field.MultiplyAddToExt(ax, bx, tt);
+            SecT113Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat128.Create64();
+            SecT113Field.Reduce(tt, z);
+            return new SecT113FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            return Multiply(b.Invert());
+        }
+
+        public override ECFieldElement Negate()
+        {
+            return this;
+        }
+
+        public override ECFieldElement Square()
+        {
+            ulong[] z = Nat128.Create64();
+            SecT113Field.Square(x, z);
+            return new SecT113FieldElement(z);
+        }
+
+        public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            return SquarePlusProduct(x, y);
+        }
+
+        public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x;
+            ulong[] xx = ((SecT113FieldElement)x).x, yx = ((SecT113FieldElement)y).x;
+
+            ulong[] tt = Nat128.CreateExt64();
+            SecT113Field.SquareAddToExt(ax, tt);
+            SecT113Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat128.Create64();
+            SecT113Field.Reduce(tt, z);
+            return new SecT113FieldElement(z);
+        }
+
+        public override ECFieldElement SquarePow(int pow)
+        {
+            if (pow < 1)
+                return this;
+
+            ulong[] z = Nat128.Create64();
+            SecT113Field.SquareN(x, pow, z);
+            return new SecT113FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            return new SecT113FieldElement(
+                AbstractF2mCurve.Inverse(113, new int[]{ 9 }, ToBigInteger()));
+        }
+
+        public override ECFieldElement Sqrt()
+        {
+            return SquarePow(M - 1);
+        }
+
+        public virtual int Representation
+        {
+            get { return F2mFieldElement.Tpb; }
+        }
+
+        public virtual int M
+        {
+            get { return 113; }
+        }
+
+        public virtual int K1
+        {
+            get { return 9; }
+        }
+
+        public virtual int K2
+        {
+            get { return 0; }
+        }
+
+        public virtual int K3
+        {
+            get { return 0; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecT113FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecT113FieldElement);
+        }
+
+        public virtual bool Equals(SecT113FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat128.Eq64(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return 113009 ^ Arrays.GetHashCode(x, 0, 2);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
new file mode 100644
index 000000000..04e69e2a8
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
@@ -0,0 +1,188 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT113R1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT113R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT113R1Point m_infinity;
+
+        public SecT113R1Curve()
+            : base(113, 9, 0, 0)
+        {
+            this.m_infinity = new SecT113R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("003088250CA6E7C7FE649CE85820F7")));
+            this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("00E8BEE4D3E2260744188BE0E9C723")));
+            this.m_order = new BigInteger(1, Hex.Decode("0100000000000000D9CCEC8A39E56F"));
+            this.m_cofactor = BigInteger.Two;
+
+            this.m_coord = SecT113R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT113R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 113; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT113FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT113R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT113R1Point(this, x, y, zs, withCompression);
+        }
+
+       public override bool IsKoblitz
+        {
+            get { return false; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+                return beta;
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(113, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 113; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 113; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return true; }
+        }
+
+        public virtual int K1
+        {
+            get { return 9; }
+        }
+
+        public virtual int K2
+        {
+            get { return 0; }
+        }
+
+        public virtual int K3
+        {
+            get { return 0; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT113R1Point.cs b/crypto/src/math/ec/custom/sec/SecT113R1Point.cs
new file mode 100644
index 000000000..6ecc8b01a
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113R1Point.cs
@@ -0,0 +1,281 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT113R1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT113R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                if (X3.IsZero)
+                {
+                    return new SecT113R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    return new SecT113R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity) 
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero) 
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement a = curve.A;
+            ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+            ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+            if (T.IsZero)
+            {
+                return new SecT113R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+            ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+            return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity) 
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero) 
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                return new SecT113R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT113R1Point(Curve, X, L.Add(Z), new ECFieldElement[]{ Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
new file mode 100644
index 000000000..a02db6b25
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
@@ -0,0 +1,190 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT113R2Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT113R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT113R2Point m_infinity;
+
+        public SecT113R2Curve()
+            : base(113, 9, 0, 0)
+        {
+            this.m_infinity = new SecT113R2Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("00689918DBEC7E5A0DD6DFC0AA55C7")));
+            this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0095E9A9EC9B297BD4BF36E059184F")));
+            this.m_order = new BigInteger(1, Hex.Decode("010000000000000108789B2496AF93"));
+            this.m_cofactor = BigInteger.Two;
+
+            this.m_coord = SecT113R2_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT113R2Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 113; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT113FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT113R2Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT113R2Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return false; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+            {
+                return beta;
+            }
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(113, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 113; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 113; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return true; }
+        }
+
+        public virtual int K1
+        {
+            get { return 9; }
+        }
+
+        public virtual int K2
+        {
+            get { return 0; }
+        }
+
+        public virtual int K3
+        {
+            get { return 0; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT113R2Point.cs b/crypto/src/math/ec/custom/sec/SecT113R2Point.cs
new file mode 100644
index 000000000..1453d78c3
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT113R2Point.cs
@@ -0,0 +1,291 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT113R2Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT113R2Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+            {
+                return b;
+            }
+            if (b.IsInfinity)
+            {
+                return this;
+            }
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                if (X3.IsZero)
+                {
+                    return new SecT113R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    return new SecT113R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity) 
+            {
+                return this;
+            }
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero) 
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement a = curve.A;
+            ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+            ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+            if (T.IsZero)
+            {
+                return new SecT113R2Point(curve, T, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+            ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+            return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity) 
+            {
+                return b;
+            }
+            if (b.IsInfinity)
+            {
+                return Twice();
+            }
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero) 
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                return new SecT113R2Point(curve, A, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT113R2Point(Curve, X, L.Add(Z), new ECFieldElement[]{ Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT131Field.cs b/crypto/src/math/ec/custom/sec/SecT131Field.cs
new file mode 100644
index 000000000..df75dfcd7
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131Field.cs
@@ -0,0 +1,274 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT131Field
+    {
+        private const ulong M03 = ulong.MaxValue >> 61;
+        private const ulong M44 = ulong.MaxValue >> 20;
+
+        public static void Add(ulong[] x, ulong[] y, ulong[] z)
+        {
+            z[0] = x[0] ^ y[0];
+            z[1] = x[1] ^ y[1];
+            z[2] = x[2] ^ y[2];
+        }
+
+        public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+        {
+            zz[0] = xx[0] ^ yy[0];
+            zz[1] = xx[1] ^ yy[1];
+            zz[2] = xx[2] ^ yy[2];
+            zz[3] = xx[3] ^ yy[3];
+            zz[4] = xx[4] ^ yy[4];
+        }
+
+        public static void AddOne(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0] ^ 1UL;
+            z[1] = x[1];
+            z[2] = x[2];
+        }
+
+        public static ulong[] FromBigInteger(BigInteger x)
+        {
+            ulong[] z = Nat192.FromBigInteger64(x);
+            Reduce61(z, 0);
+            return z;
+        }
+
+        public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+        {
+            ulong[] tt = Nat192.CreateExt64();
+            ImplMultiply(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            ulong[] tt = Nat192.CreateExt64();
+            ImplMultiply(x, y, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void Reduce(ulong[] xx, ulong[] z)
+        {
+            ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3], x4 = xx[4];
+
+            x1 ^= (x4 << 61) ^ (x4 << 63);
+            x2 ^= (x4 >>  3) ^ (x4 >>  1) ^ x4 ^ (x4 <<  5);
+            x3 ^=                                (x4 >> 59);
+
+            x0 ^= (x3 << 61) ^ (x3 << 63);
+            x1 ^= (x3 >>  3) ^ (x3 >>  1) ^ x3 ^ (x3 <<  5);
+            x2 ^=                                (x3 >> 59);
+
+            ulong t = x2 >> 3;
+            z[0]    = x0 ^ t ^ (t << 2) ^ (t << 3) ^ (t <<  8);
+            z[1]    = x1                           ^ (t >> 56);
+            z[2]    = x2 & M03;
+        }
+
+        public static void Reduce61(ulong[] z, int zOff)
+        {
+            ulong z2     = z[zOff + 2], t = z2 >> 3;
+            z[zOff    ] ^= t ^ (t << 2) ^ (t << 3) ^ (t <<  8);
+            z[zOff + 1] ^=                           (t >> 56);
+            z[zOff + 2]  = z2 & M03;
+        }
+
+        public static void Square(ulong[] x, ulong[] z)
+        {
+            ulong[] tt = Nat.Create64(5);
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareAddToExt(ulong[] x, ulong[] zz)
+        {
+            ulong[] tt = Nat.Create64(5);
+            ImplSquare(x, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void SquareN(ulong[] x, int n, ulong[] z)
+        {
+            Debug.Assert(n > 0);
+
+            ulong[] tt = Nat.Create64(5);
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                ImplSquare(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        protected static void ImplCompactExt(ulong[] zz)
+        {
+            ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5];
+            zz[0] =  z0        ^ (z1 << 44);
+            zz[1] = (z1 >> 20) ^ (z2 << 24);
+            zz[2] = (z2 >> 40) ^ (z3 <<  4)
+                               ^ (z4 << 48);
+            zz[3] = (z3 >> 60) ^ (z5 << 28)
+                  ^ (z4 >> 16);
+            zz[4] = (z5 >> 36);
+            zz[5] = 0;
+        }
+
+        protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            /*
+             * "Five-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+             */
+
+            ulong f0 = x[0], f1 = x[1], f2 = x[2];
+            f2  = ((f1 >> 24) ^ (f2 << 40)) & M44;
+            f1  = ((f0 >> 44) ^ (f1 << 20)) & M44;
+            f0 &= M44;
+
+            ulong g0 = y[0], g1 = y[1], g2 = y[2];
+            g2  = ((g1 >> 24) ^ (g2 << 40)) & M44;
+            g1  = ((g0 >> 44) ^ (g1 << 20)) & M44;
+            g0 &= M44;
+
+            ulong[] H = new ulong[10];
+
+            ImplMulw(f0, g0, H, 0);               // H(0)       44/43 bits
+            ImplMulw(f2, g2, H, 2);               // H(INF)     44/41 bits
+
+            ulong t0 = f0 ^ f1 ^ f2;
+            ulong t1 = g0 ^ g1 ^ g2;
+
+            ImplMulw(t0, t1, H, 4);               // H(1)       44/43 bits
+        
+            ulong t2 = (f1 << 1) ^ (f2 << 2);
+            ulong t3 = (g1 << 1) ^ (g2 << 2);
+
+            ImplMulw(f0 ^ t2, g0 ^ t3, H, 6);     // H(t)       44/45 bits
+            ImplMulw(t0 ^ t2, t1 ^ t3, H, 8);     // H(t + 1)   44/45 bits
+
+            ulong t4 = H[6] ^ H[8];
+            ulong t5 = H[7] ^ H[9];
+
+            Debug.Assert(t5 >> 44 == 0);
+
+            // Calculate V
+            ulong v0 =      (t4 << 1) ^ H[6];
+            ulong v1 = t4 ^ (t5 << 1) ^ H[7];
+            ulong v2 = t5;
+
+            // Calculate U
+            ulong u0 = H[0];
+            ulong u1 = H[1] ^ H[0] ^ H[4];
+            ulong u2 =        H[1] ^ H[5];
+        
+            // Calculate W
+            ulong w0 = u0 ^ v0 ^ (H[2] << 4) ^ (H[2] << 1);
+            ulong w1 = u1 ^ v1 ^ (H[3] << 4) ^ (H[3] << 1);
+            ulong w2 = u2 ^ v2;
+
+            // Propagate carries
+            w1 ^= (w0 >> 44); w0 &= M44;
+            w2 ^= (w1 >> 44); w1 &= M44;
+
+            Debug.Assert((w0 & 1UL) == 0);
+
+            // Divide W by t
+
+            w0 = (w0 >> 1) ^ ((w1 & 1UL) << 43);
+            w1 = (w1 >> 1) ^ ((w2 & 1UL) << 43);
+            w2 = (w2 >> 1);
+
+            // Divide W by (t + 1)
+
+            w0 ^= (w0 << 1);
+            w0 ^= (w0 << 2);
+            w0 ^= (w0 << 4);
+            w0 ^= (w0 << 8);
+            w0 ^= (w0 << 16);
+            w0 ^= (w0 << 32);
+
+            w0 &= M44; w1 ^= (w0 >> 43);
+
+            w1 ^= (w1 << 1);
+            w1 ^= (w1 << 2);
+            w1 ^= (w1 << 4);
+            w1 ^= (w1 << 8);
+            w1 ^= (w1 << 16);
+            w1 ^= (w1 << 32);
+
+            w1 &= M44; w2 ^= (w1 >> 43);
+
+            w2 ^= (w2 << 1);
+            w2 ^= (w2 << 2);
+            w2 ^= (w2 << 4);
+            w2 ^= (w2 << 8);
+            w2 ^= (w2 << 16);
+            w2 ^= (w2 << 32);
+
+            Debug.Assert(w2 >> 42 == 0);
+
+            zz[0] = u0; 
+            zz[1] = u1 ^ w0      ^ H[2]; 
+            zz[2] = u2 ^ w1 ^ w0 ^ H[3]; 
+            zz[3] =      w2 ^ w1; 
+            zz[4] =           w2 ^ H[2]; 
+            zz[5] =                H[3]; 
+
+            ImplCompactExt(zz);
+        }
+
+        protected static void ImplMulw(ulong x, ulong y, ulong[] z, int zOff)
+        {
+            Debug.Assert(x >> 45 == 0);
+            Debug.Assert(y >> 45 == 0);
+
+            ulong[] u = new ulong[8];
+    //      u[0] = 0;
+            u[1] = y;
+            u[2] = u[1] << 1;
+            u[3] = u[2] ^  y;
+            u[4] = u[2] << 1;
+            u[5] = u[4] ^  y;
+            u[6] = u[3] << 1;
+            u[7] = u[6] ^  y;
+
+            uint j = (uint)x;
+            ulong g, h = 0, l = u[j & 7]
+                              ^ u[(j >> 3) & 7] << 3
+                              ^ u[(j >> 6) & 7] << 6;
+            int k = 33;
+            do
+            {
+                j = (uint)(x >> k);
+                g  = u[j & 7]
+                   ^ u[(j >> 3) & 7] << 3
+                   ^ u[(j >> 6) & 7] << 6
+                   ^ u[(j >> 9) & 7] << 9;
+                l ^= (g <<  k);
+                h ^= (g >> -k);
+            }
+            while ((k -= 12) > 0);
+
+            Debug.Assert(h >> 25 == 0);
+
+            z[zOff    ] = l & M44;
+            z[zOff + 1] = (l >> 44) ^ (h << 20);
+        }
+
+        protected static void ImplSquare(ulong[] x, ulong[] zz)
+        {
+            Interleave.Expand64To128(x[0], zz, 0);
+            Interleave.Expand64To128(x[1], zz, 2);
+
+            zz[4] = Interleave.Expand8to16((uint)x[2]);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
new file mode 100644
index 000000000..d60c7ed7d
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
@@ -0,0 +1,213 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT131FieldElement
+        : ECFieldElement
+    {
+        protected readonly ulong[] x;
+
+        public SecT131FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0)
+                throw new ArgumentException("value invalid for SecT131FieldElement", "x");
+
+            this.x = SecT131Field.FromBigInteger(x);
+        }
+
+        public SecT131FieldElement()
+        {
+            this.x = Nat192.Create64();
+        }
+
+        protected internal SecT131FieldElement(ulong[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat192.IsOne64(x); }
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat192.IsZero64(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return (x[0] & 1UL) != 0UL;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat192.ToBigInteger64(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecT131Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 131; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            ulong[] z = Nat192.Create64();
+            SecT131Field.Add(x, ((SecT131FieldElement)b).x, z);
+            return new SecT131FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            ulong[] z = Nat192.Create64();
+            SecT131Field.AddOne(x, z);
+            return new SecT131FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            // Addition and Subtraction are the same in F2m
+            return Add(b);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            ulong[] z = Nat192.Create64();
+            SecT131Field.Multiply(x, ((SecT131FieldElement)b).x, z);
+            return new SecT131FieldElement(z);
+        }
+
+        public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            return MultiplyPlusProduct(b, x, y);
+        }
+
+        public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x, bx = ((SecT131FieldElement)b).x;
+            ulong[] xx = ((SecT131FieldElement)x).x, yx = ((SecT131FieldElement)y).x;
+
+            ulong[] tt = Nat.Create64(5);
+            SecT131Field.MultiplyAddToExt(ax, bx, tt);
+            SecT131Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat192.Create64();
+            SecT131Field.Reduce(tt, z);
+            return new SecT131FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            return Multiply(b.Invert());
+        }
+
+        public override ECFieldElement Negate()
+        {
+            return this;
+        }
+
+        public override ECFieldElement Square()
+        {
+            ulong[] z = Nat192.Create64();
+            SecT131Field.Square(x, z);
+            return new SecT131FieldElement(z);
+        }
+
+        public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            return SquarePlusProduct(x, y);
+        }
+
+        public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x;
+            ulong[] xx = ((SecT131FieldElement)x).x, yx = ((SecT131FieldElement)y).x;
+
+            ulong[] tt = Nat.Create64(5);
+            SecT131Field.SquareAddToExt(ax, tt);
+            SecT131Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat192.Create64();
+            SecT131Field.Reduce(tt, z);
+            return new SecT131FieldElement(z);
+        }
+
+        public override ECFieldElement SquarePow(int pow)
+        {
+            if (pow < 1)
+                return this;
+
+            ulong[] z = Nat192.Create64();
+            SecT131Field.SquareN(x, pow, z);
+            return new SecT131FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            return new SecT131FieldElement(
+                AbstractF2mCurve.Inverse(131, new int[] { 2, 3, 8 }, ToBigInteger()));
+        }
+
+        public override ECFieldElement Sqrt()
+        {
+            return SquarePow(M - 1);
+        }
+
+        public virtual int Representation
+        {
+            get { return F2mFieldElement.Ppb; }
+        }
+
+        public virtual int M
+        {
+            get { return 131; }
+        }
+
+        public virtual int K1
+        {
+            get { return 2; }
+        }
+
+        public virtual int K2
+        {
+            get { return 3; }
+        }
+
+        public virtual int K3
+        {
+            get { return 8; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecT131FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecT131FieldElement);
+        }
+
+        public virtual bool Equals(SecT131FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat192.Eq64(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return 131832 ^ Arrays.GetHashCode(x, 0, 3);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
new file mode 100644
index 000000000..789e3c0c3
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
@@ -0,0 +1,188 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT131R1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT131R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT131R1Point m_infinity;
+
+        public SecT131R1Curve()
+            : base(131, 2, 3, 8)
+        {
+            this.m_infinity = new SecT131R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("07A11B09A76B562144418FF3FF8C2570B8")));
+            this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0217C05610884B63B9C6C7291678F9D341")));
+            this.m_order = new BigInteger(1, Hex.Decode("0400000000000000023123953A9464B54D"));
+            this.m_cofactor = BigInteger.Two;
+
+            this.m_coord = SecT131R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT131R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 131; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT131FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT131R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT131R1Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return false; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+                return beta;
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(131, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 131; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 131; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return false; }
+        }
+
+        public virtual int K1
+        {
+            get { return 2; }
+        }
+
+        public virtual int K2
+        {
+            get { return 3; }
+        }
+
+        public virtual int K3
+        {
+            get { return 8; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT131R1Point.cs b/crypto/src/math/ec/custom/sec/SecT131R1Point.cs
new file mode 100644
index 000000000..7afdad89c
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131R1Point.cs
@@ -0,0 +1,287 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT131R1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT131R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                if (X3.IsZero)
+                {
+                    return new SecT131R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    return new SecT131R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT131R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+            {
+                return this;
+            }
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement a = curve.A;
+            ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+            ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+            if (T.IsZero)
+            {
+                return new SecT131R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+            ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+            return new SecT131R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+            {
+                return b;
+            }
+            if (b.IsInfinity)
+            {
+                return Twice();
+            }
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                return new SecT131R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT131R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT131R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
new file mode 100644
index 000000000..2004f84ca
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
@@ -0,0 +1,190 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT131R2Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT131R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT131R2Point m_infinity;
+
+        public SecT131R2Curve()
+            : base(131, 2, 3, 8)
+        {
+            this.m_infinity = new SecT131R2Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("03E5A88919D7CAFCBF415F07C2176573B2")));
+            this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("04B8266A46C55657AC734CE38F018F2192")));
+            this.m_order = new BigInteger(1, Hex.Decode("0400000000000000016954A233049BA98F"));
+            this.m_cofactor = BigInteger.Two;
+
+            this.m_coord = SecT131R2_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT131R2Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public override int FieldSize
+        {
+            get { return 131; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT131FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT131R2Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT131R2Point(this, x, y, zs, withCompression);
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return false; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+            {
+                return beta;
+            }
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(131, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 131; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 131; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return false; }
+        }
+
+        public virtual int K1
+        {
+            get { return 2; }
+        }
+
+        public virtual int K2
+        {
+            get { return 3; }
+        }
+
+        public virtual int K3
+        {
+            get { return 8; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT131R2Point.cs b/crypto/src/math/ec/custom/sec/SecT131R2Point.cs
new file mode 100644
index 000000000..be61561da
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT131R2Point.cs
@@ -0,0 +1,283 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT131R2Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT131R2Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                if (X3.IsZero)
+                {
+                    return new SecT131R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    return new SecT131R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT131R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+            {
+                return this;
+            }
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement a = curve.A;
+            ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+            ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+            if (T.IsZero)
+            {
+                return new SecT131R2Point(curve, T, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+            ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+            return new SecT131R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                return new SecT131R2Point(curve, A, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT131R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT131R2Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163Field.cs b/crypto/src/math/ec/custom/sec/SecT163Field.cs
new file mode 100644
index 000000000..2a775e20d
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163Field.cs
@@ -0,0 +1,272 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT163Field
+    {
+        private const ulong M35 = ulong.MaxValue >> 29;
+        private const ulong M55 = ulong.MaxValue >> 9;
+
+        public static void Add(ulong[] x, ulong[] y, ulong[] z)
+        {
+            z[0] = x[0] ^ y[0];
+            z[1] = x[1] ^ y[1];
+            z[2] = x[2] ^ y[2];
+        }
+
+        public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+        {
+            zz[0] = xx[0] ^ yy[0];
+            zz[1] = xx[1] ^ yy[1];
+            zz[2] = xx[2] ^ yy[2];
+            zz[3] = xx[3] ^ yy[3];
+            zz[4] = xx[4] ^ yy[4];
+            zz[5] = xx[5] ^ yy[5];
+        }
+
+        public static void AddOne(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0] ^ 1UL;
+            z[1] = x[1];
+            z[2] = x[2];
+        }
+
+        public static ulong[] FromBigInteger(BigInteger x)
+        {
+            ulong[] z = Nat192.FromBigInteger64(x);
+            Reduce29(z, 0);
+            return z;
+        }
+
+        public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+        {
+            ulong[] tt = Nat192.CreateExt64();
+            ImplMultiply(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            ulong[] tt = Nat192.CreateExt64();
+            ImplMultiply(x, y, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void Reduce(ulong[] xx, ulong[] z)
+        {
+            ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3], x4 = xx[4], x5 = xx[5];
+
+            x2 ^= (x5 << 29) ^ (x5 << 32) ^ (x5 << 35) ^ (x5 << 36);
+            x3 ^= (x5 >> 35) ^ (x5 >> 32) ^ (x5 >> 29) ^ (x5 >> 28);
+
+            x1 ^= (x4 << 29) ^ (x4 << 32) ^ (x4 << 35) ^ (x4 << 36);
+            x2 ^= (x4 >> 35) ^ (x4 >> 32) ^ (x4 >> 29) ^ (x4 >> 28);
+
+            x0 ^= (x3 << 29) ^ (x3 << 32) ^ (x3 << 35) ^ (x3 << 36);
+            x1 ^= (x3 >> 35) ^ (x3 >> 32) ^ (x3 >> 29) ^ (x3 >> 28);
+
+            ulong t = x2 >> 35;
+            z[0]    = x0 ^ t ^ (t << 3) ^ (t << 6) ^ (t << 7);
+            z[1]    = x1;
+            z[2]    = x2 & M35;
+        }
+
+        public static void Reduce29(ulong[] z, int zOff)
+        {
+            ulong z2     = z[zOff + 2], t = z2 >> 35;
+            z[zOff    ] ^= t ^ (t << 3) ^ (t << 6) ^ (t << 7);
+            z[zOff + 2]  = z2 & M35;
+        }
+
+        public static void Square(ulong[] x, ulong[] z)
+        {
+            ulong[] tt = Nat192.CreateExt64();
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareAddToExt(ulong[] x, ulong[] zz)
+        {
+            ulong[] tt = Nat192.CreateExt64();
+            ImplSquare(x, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void SquareN(ulong[] x, int n, ulong[] z)
+        {
+            Debug.Assert(n > 0);
+
+            ulong[] tt = Nat192.CreateExt64();
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                ImplSquare(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        protected static void ImplCompactExt(ulong[] zz)
+        {
+            ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5];
+            zz[0] =  z0        ^ (z1 << 55);
+            zz[1] = (z1 >>  9) ^ (z2 << 46);
+            zz[2] = (z2 >> 18) ^ (z3 << 37);
+            zz[3] = (z3 >> 27) ^ (z4 << 28);
+            zz[4] = (z4 >> 36) ^ (z5 << 19);
+            zz[5] = (z5 >> 45);
+        }
+
+        protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            /*
+             * "Five-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+             */
+
+            ulong f0 = x[0], f1 = x[1], f2 = x[2];
+            f2  = ((f1 >> 46) ^ (f2 << 18));
+            f1  = ((f0 >> 55) ^ (f1 <<  9)) & M55;
+            f0 &= M55;
+
+            ulong g0 = y[0], g1 = y[1], g2 = y[2];
+            g2  = ((g1 >> 46) ^ (g2 << 18));
+            g1  = ((g0 >> 55) ^ (g1 <<  9)) & M55;
+            g0 &= M55;
+
+            ulong[] H = new ulong[10];
+
+            ImplMulw(f0, g0, H, 0);               // H(0)       55/54 bits
+            ImplMulw(f2, g2, H, 2);               // H(INF)     55/50 bits
+
+            ulong t0 = f0 ^ f1 ^ f2;
+            ulong t1 = g0 ^ g1 ^ g2;
+
+            ImplMulw(t0, t1, H, 4);               // H(1)       55/54 bits
+        
+            ulong t2 = (f1 << 1) ^ (f2 << 2);
+            ulong t3 = (g1 << 1) ^ (g2 << 2);
+
+            ImplMulw(f0 ^ t2, g0 ^ t3, H, 6);     // H(t)       55/56 bits
+            ImplMulw(t0 ^ t2, t1 ^ t3, H, 8);     // H(t + 1)   55/56 bits
+
+            ulong t4 = H[6] ^ H[8];
+            ulong t5 = H[7] ^ H[9];
+
+            Debug.Assert(t5 >> 55 == 0);
+
+            // Calculate V
+            ulong v0 =      (t4 << 1) ^ H[6];
+            ulong v1 = t4 ^ (t5 << 1) ^ H[7];
+            ulong v2 = t5;
+
+            // Calculate U
+            ulong u0 = H[0];
+            ulong u1 = H[1] ^ H[0] ^ H[4];
+            ulong u2 =        H[1] ^ H[5];
+        
+            // Calculate W
+            ulong w0 = u0 ^ v0 ^ (H[2] << 4) ^ (H[2] << 1);
+            ulong w1 = u1 ^ v1 ^ (H[3] << 4) ^ (H[3] << 1);
+            ulong w2 = u2 ^ v2;
+
+            // Propagate carries
+            w1 ^= (w0 >> 55); w0 &= M55;
+            w2 ^= (w1 >> 55); w1 &= M55;
+
+            Debug.Assert((w0 & 1UL) == 0UL);
+
+            // Divide W by t
+
+            w0 = (w0 >> 1) ^ ((w1 & 1UL) << 54);
+            w1 = (w1 >> 1) ^ ((w2 & 1UL) << 54);
+            w2 = (w2 >> 1);
+
+            // Divide W by (t + 1)
+
+            w0 ^= (w0 << 1);
+            w0 ^= (w0 << 2);
+            w0 ^= (w0 << 4);
+            w0 ^= (w0 << 8);
+            w0 ^= (w0 << 16);
+            w0 ^= (w0 << 32);
+
+            w0 &= M55; w1 ^= (w0 >> 54);
+
+            w1 ^= (w1 << 1);
+            w1 ^= (w1 << 2);
+            w1 ^= (w1 << 4);
+            w1 ^= (w1 << 8);
+            w1 ^= (w1 << 16);
+            w1 ^= (w1 << 32);
+
+            w1 &= M55; w2 ^= (w1 >> 54);
+
+            w2 ^= (w2 << 1);
+            w2 ^= (w2 << 2);
+            w2 ^= (w2 << 4);
+            w2 ^= (w2 << 8);
+            w2 ^= (w2 << 16);
+            w2 ^= (w2 << 32);
+
+            Debug.Assert(w2 >> 52 == 0);
+
+            zz[0] = u0; 
+            zz[1] = u1 ^ w0      ^ H[2]; 
+            zz[2] = u2 ^ w1 ^ w0 ^ H[3]; 
+            zz[3] =      w2 ^ w1; 
+            zz[4] =           w2 ^ H[2]; 
+            zz[5] =                H[3]; 
+
+            ImplCompactExt(zz);
+        }
+
+        protected static void ImplMulw(ulong x, ulong y, ulong[] z, int zOff)
+        {
+            Debug.Assert(x >> 56 == 0);
+            Debug.Assert(y >> 56 == 0);
+
+            ulong[] u = new ulong[8];
+    //      u[0] = 0;
+            u[1] = y;
+            u[2] = u[1] << 1;
+            u[3] = u[2] ^  y;
+            u[4] = u[2] << 1;
+            u[5] = u[4] ^  y;
+            u[6] = u[3] << 1;
+            u[7] = u[6] ^  y;
+
+            uint j = (uint)x;
+            ulong g, h = 0, l = u[j & 3];
+            int k = 47;
+            do
+            {
+                j = (uint)(x >> k);
+                g  = u[j & 7]
+                   ^ u[(j >> 3) & 7] << 3
+                   ^ u[(j >> 6) & 7] << 6;
+                l ^= (g <<  k);
+                h ^= (g >> -k);
+            }
+            while ((k -= 9) > 0);
+
+            Debug.Assert(h >> 47 == 0);
+
+            z[zOff    ] = l & M55;
+            z[zOff + 1] = (l >> 55) ^ (h << 9);
+        }
+
+        protected static void ImplSquare(ulong[] x, ulong[] zz)
+        {
+            Interleave.Expand64To128(x[0], zz, 0);
+            Interleave.Expand64To128(x[1], zz, 2);
+
+            ulong x2 = x[2];
+            zz[4] = Interleave.Expand32to64((uint)x2);
+            zz[5] = Interleave.Expand8to16((uint)(x2 >> 32));
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
new file mode 100644
index 000000000..0ef421c71
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
@@ -0,0 +1,213 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT163FieldElement
+        : ECFieldElement
+    {
+        protected readonly ulong[] x;
+
+        public SecT163FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0)
+                throw new ArgumentException("value invalid for SecT163FieldElement", "x");
+
+            this.x = SecT163Field.FromBigInteger(x);
+        }
+
+        public SecT163FieldElement()
+        {
+            this.x = Nat192.Create64();
+        }
+
+        protected internal SecT163FieldElement(ulong[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat192.IsOne64(x); }
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat192.IsZero64(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return (x[0] & 1L) != 0L;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat192.ToBigInteger64(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecT163Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 163; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            ulong[] z = Nat192.Create64();
+            SecT163Field.Add(x, ((SecT163FieldElement)b).x, z);
+            return new SecT163FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            ulong[] z = Nat192.Create64();
+            SecT163Field.AddOne(x, z);
+            return new SecT163FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            // Addition and subtraction are the same in F2m
+            return Add(b);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            ulong[] z = Nat192.Create64();
+            SecT163Field.Multiply(x, ((SecT163FieldElement)b).x, z);
+            return new SecT163FieldElement(z);
+        }
+
+        public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            return MultiplyPlusProduct(b, x, y);
+        }
+
+        public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x, bx = ((SecT163FieldElement)b).x;
+            ulong[] xx = ((SecT163FieldElement)x).x, yx = ((SecT163FieldElement)y).x;
+
+            ulong[] tt = Nat192.CreateExt64();
+            SecT163Field.MultiplyAddToExt(ax, bx, tt);
+            SecT163Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat192.Create64();
+            SecT163Field.Reduce(tt, z);
+            return new SecT163FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            return Multiply(b.Invert());
+        }
+
+        public override ECFieldElement Negate()
+        {
+            return this;
+        }
+
+        public override ECFieldElement Square()
+        {
+            ulong[] z = Nat192.Create64();
+            SecT163Field.Square(x, z);
+            return new SecT163FieldElement(z);
+        }
+
+        public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            return SquarePlusProduct(x, y);
+        }
+
+        public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x;
+            ulong[] xx = ((SecT163FieldElement)x).x, yx = ((SecT163FieldElement)y).x;
+
+            ulong[] tt = Nat192.CreateExt64();
+            SecT163Field.SquareAddToExt(ax, tt);
+            SecT163Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat192.Create64();
+            SecT163Field.Reduce(tt, z);
+            return new SecT163FieldElement(z);
+        }
+
+        public override ECFieldElement SquarePow(int pow)
+        {
+            if (pow < 1)
+                return this;
+
+            ulong[] z = Nat192.Create64();
+            SecT163Field.SquareN(x, pow, z);
+            return new SecT163FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            return new SecT163FieldElement(
+                AbstractF2mCurve.Inverse(163, new int[] { 3, 6, 7 }, ToBigInteger()));
+        }
+
+        public override ECFieldElement Sqrt()
+        {
+            return SquarePow(M - 1);
+        }
+
+        public virtual int Representation
+        {
+            get { return F2mFieldElement.Ppb; }
+        }
+
+        public virtual int M
+        {
+            get { return 163; }
+        }
+
+        public virtual int K1
+        {
+            get { return 3; }
+        }
+
+        public virtual int K2
+        {
+            get { return 6; }
+        }
+
+        public virtual int K3
+        {
+            get { return 7; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecT163FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecT163FieldElement);
+        }
+
+        public virtual bool Equals(SecT163FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat192.Eq64(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return 163763 ^ Arrays.GetHashCode(x, 0, 3);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
new file mode 100644
index 000000000..1cfd09e1c
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
@@ -0,0 +1,194 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT163K1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT163K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT163K1Point m_infinity;
+
+        public SecT163K1Curve()
+            : base(163, 3, 6, 7)
+        {
+            this.m_infinity = new SecT163K1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.One);
+            this.m_b = this.m_a;
+            this.m_order = new BigInteger(1, Hex.Decode("04000000000000000000020108A2E0CC0D99F8A5EF"));
+            this.m_cofactor = BigInteger.Two;
+
+            this.m_coord = SecT163K1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT163K1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        protected override ECMultiplier CreateDefaultMultiplier()
+        {
+            return new WTauNafMultiplier();
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 163; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT163FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT163K1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT163K1Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return true; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+                return beta;
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(163, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 163; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 163; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return false; }
+        }
+
+        public virtual int K1
+        {
+            get { return 3; }
+        }
+
+        public virtual int K2
+        {
+            get { return 6; }
+        }
+
+        public virtual int K3
+        {
+            get { return 7; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163K1Point.cs b/crypto/src/math/ec/custom/sec/SecT163K1Point.cs
new file mode 100644
index 000000000..2e3ba57d0
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163K1Point.cs
@@ -0,0 +1,289 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT163K1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT163K1Point(null, this.AffineXCoord, this.AffineYCoord);
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                //X3 = L.Square().Add(L).Add(X1).Add(curve.getA());
+                X3 = L.Square().Add(L).Add(X1).AddOne();
+                if (X3.IsZero)
+                {
+                    //return new SecT163K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT163K1Point(curve, X3, curve.B, IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    //return new SecT163K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT163K1Point(curve, X3, curve.B, IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT163K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+            {
+                return this;
+            }
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+            if (T.IsZero)
+            {
+                //return new SecT163K1Point(curve, T, curve.B.sqrt(), withCompression);
+                return new SecT163K1Point(curve, T, curve.B, IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement t1 = L1.Add(X1).Square();
+            ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(X3);
+
+            return new SecT163K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            // NOTE: TwicePlus() only optimized for lambda-affine argument
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            //ECFieldElement T = curve.getA().Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            //ECFieldElement A = curve.getA().Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                //return new SecT163K1Point(curve, A, curve.B.sqrt(), withCompression);
+                return new SecT163K1Point(curve, A, curve.B, IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT163K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT163K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
new file mode 100644
index 000000000..fc18e1094
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
@@ -0,0 +1,190 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT163R1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT163R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT163R1Point m_infinity;
+
+        public SecT163R1Curve()
+            : base(163, 3, 6, 7)
+        {
+            this.m_infinity = new SecT163R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2")));
+            this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9")));
+            this.m_order = new BigInteger(1, Hex.Decode("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B"));
+            this.m_cofactor = BigInteger.Two;
+
+            this.m_coord = SecT163R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT163R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 163; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT163FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT163R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT163R1Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return false; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+            {
+                return beta;
+            }
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(163, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 163; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 163; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return false; }
+        }
+
+        public virtual int K1
+        {
+            get { return 3; }
+        }
+
+        public virtual int K2
+        {
+            get { return 6; }
+        }
+
+        public virtual int K3
+        {
+            get { return 7; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163R1Point.cs b/crypto/src/math/ec/custom/sec/SecT163R1Point.cs
new file mode 100644
index 000000000..811a09f14
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163R1Point.cs
@@ -0,0 +1,283 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT163R1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT163R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                if (X3.IsZero)
+                {
+                    return new SecT163R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    return new SecT163R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT163R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+            {
+                return this;
+            }
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement a = curve.A;
+            ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+            ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+            if (T.IsZero)
+            {
+                return new SecT163R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+            ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+            return new SecT163R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                return new SecT163R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT163R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT163R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
new file mode 100644
index 000000000..9efe11c3e
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
@@ -0,0 +1,188 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT163R2Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT163R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT163R2Point m_infinity;
+
+        public SecT163R2Curve()
+            : base(163, 3, 6, 7)
+        {
+            this.m_infinity = new SecT163R2Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.One);
+            this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("020A601907B8C953CA1481EB10512F78744A3205FD")));
+            this.m_order = new BigInteger(1, Hex.Decode("040000000000000000000292FE77E70C12A4234C33"));
+            this.m_cofactor = BigInteger.Two;
+
+            this.m_coord = SecT163R2_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT163R2Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 163; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT163FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT163R2Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT163R2Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return false; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+                return beta;
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(163, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 163; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 163; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return false; }
+        }
+
+        public virtual int K1
+        {
+            get { return 3; }
+        }
+
+        public virtual int K2
+        {
+            get { return 6; }
+        }
+
+        public virtual int K3
+        {
+            get { return 7; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT163R2Point.cs b/crypto/src/math/ec/custom/sec/SecT163R2Point.cs
new file mode 100644
index 000000000..07b3f1fd9
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT163R2Point.cs
@@ -0,0 +1,290 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT163R2Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT163R2Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                {
+                    return Twice();
+                }
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                X3 = L.Square().Add(L).Add(X1).AddOne();
+                if (X3.IsZero)
+                {
+                    return new SecT163R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    return new SecT163R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT163R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+            {
+                return this;
+            }
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+            if (T.IsZero)
+            {
+                return new SecT163R2Point(curve, T, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+            ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+            return new SecT163R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+            {
+                return b;
+            }
+            if (b.IsInfinity)
+            {
+                return Twice();
+            }
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                return new SecT163R2Point(curve, A, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT163R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT163R2Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT233Field.cs b/crypto/src/math/ec/custom/sec/SecT233Field.cs
new file mode 100644
index 000000000..165fadbf3
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233Field.cs
@@ -0,0 +1,243 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT233Field
+    {
+        private const ulong M41 = ulong.MaxValue >> 23;
+        private const ulong M59 = ulong.MaxValue >> 5;
+
+        public static void Add(ulong[] x, ulong[] y, ulong[] z)
+        {
+            z[0] = x[0] ^ y[0];
+            z[1] = x[1] ^ y[1];
+            z[2] = x[2] ^ y[2];
+            z[3] = x[3] ^ y[3];
+        }
+
+        public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+        {
+            zz[0] = xx[0] ^ yy[0];
+            zz[1] = xx[1] ^ yy[1];
+            zz[2] = xx[2] ^ yy[2];
+            zz[3] = xx[3] ^ yy[3];
+            zz[4] = xx[4] ^ yy[4];
+            zz[5] = xx[5] ^ yy[5];
+            zz[6] = xx[6] ^ yy[6];
+            zz[7] = xx[7] ^ yy[7];
+        }
+
+        public static void AddOne(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0] ^ 1UL;
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+        }
+
+        public static ulong[] FromBigInteger(BigInteger x)
+        {
+            ulong[] z = Nat256.FromBigInteger64(x);
+            Reduce23(z, 0);
+            return z;
+        }
+
+        public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+        {
+            ulong[] tt = Nat256.CreateExt64();
+            ImplMultiply(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            ulong[] tt = Nat256.CreateExt64();
+            ImplMultiply(x, y, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void Reduce(ulong[] xx, ulong[] z)
+        {
+            ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3];
+            ulong x4 = xx[4], x5 = xx[5], x6 = xx[6], x7 = xx[7];
+
+            x3 ^= (x7 << 23);
+            x4 ^= (x7 >> 41) ^ (x7 << 33);
+            x5 ^= (x7 >> 31);
+
+            x2 ^= (x6 << 23);
+            x3 ^= (x6 >> 41) ^ (x6 << 33);
+            x4 ^= (x6 >> 31);
+
+            x1 ^= (x5 << 23);
+            x2 ^= (x5 >> 41) ^ (x5 << 33);
+            x3 ^= (x5 >> 31);
+
+            x0 ^= (x4 << 23);
+            x1 ^= (x4 >> 41) ^ (x4 << 33);
+            x2 ^= (x4 >> 31);
+
+            ulong t = x3 >> 41;
+            z[0]    = x0 ^ t;
+            z[1]    = x1 ^ (t << 10);
+            z[2]    = x2;
+            z[3]    = x3 & M41;
+        }
+
+        public static void Reduce23(ulong[] z, int zOff)
+        {
+            ulong z3     = z[zOff + 3], t = z3 >> 41;
+            z[zOff    ] ^= t;
+            z[zOff + 1] ^= (t << 10);
+            z[zOff + 3]  = z3 & M41;
+        }
+
+        public static void Square(ulong[] x, ulong[] z)
+        {
+            ulong[] tt = Nat256.CreateExt64();
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareAddToExt(ulong[] x, ulong[] zz)
+        {
+            ulong[] tt = Nat256.CreateExt64();
+            ImplSquare(x, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void SquareN(ulong[] x, int n, ulong[] z)
+        {
+            Debug.Assert(n > 0);
+
+            ulong[] tt = Nat256.CreateExt64();
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                ImplSquare(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        protected static void ImplCompactExt(ulong[] zz)
+        {
+            ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5], z6 = zz[6], z7 = zz[7];
+            zz[0] =  z0         ^ (z1 << 59);
+            zz[1] = (z1 >>  5) ^ (z2 << 54);
+            zz[2] = (z2 >> 10) ^ (z3 << 49);
+            zz[3] = (z3 >> 15) ^ (z4 << 44);
+            zz[4] = (z4 >> 20) ^ (z5 << 39);
+            zz[5] = (z5 >> 25) ^ (z6 << 34);
+            zz[6] = (z6 >> 30) ^ (z7 << 29);
+            zz[7] = (z7 >> 35);
+        }
+
+        protected static void ImplExpand(ulong[] x, ulong[] z)
+        {
+            ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+            z[0] = x0 & M59;
+            z[1] = ((x0 >> 59) ^ (x1 <<  5)) & M59;
+            z[2] = ((x1 >> 54) ^ (x2 << 10)) & M59;
+            z[3] = ((x2 >> 49) ^ (x3 << 15));
+        }
+
+        protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            /*
+             * "Two-level seven-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+             */
+
+            ulong[] f = new ulong[4], g = new ulong[4];
+            ImplExpand(x, f);
+            ImplExpand(y, g);
+
+            ImplMulwAcc(f[0], g[0], zz, 0);
+            ImplMulwAcc(f[1], g[1], zz, 1);
+            ImplMulwAcc(f[2], g[2], zz, 2);
+            ImplMulwAcc(f[3], g[3], zz, 3);
+
+            // U *= (1 - t^n)
+            for (int i = 5; i > 0; --i)
+            {
+                zz[i] ^= zz[i - 1];
+            }
+
+            ImplMulwAcc(f[0] ^ f[1], g[0] ^ g[1], zz, 1);
+            ImplMulwAcc(f[2] ^ f[3], g[2] ^ g[3], zz, 3);
+
+            // V *= (1 - t^2n)
+            for (int i = 7; i > 1; --i)
+            {
+                zz[i] ^= zz[i - 2];
+            }
+
+            // Double-length recursion
+            {
+                ulong c0 = f[0] ^ f[2], c1 = f[1] ^ f[3];
+                ulong d0 = g[0] ^ g[2], d1 = g[1] ^ g[3];
+                ImplMulwAcc(c0 ^ c1, d0 ^ d1, zz, 3);
+                ulong[] t = new ulong[3];
+                ImplMulwAcc(c0, d0, t, 0);
+                ImplMulwAcc(c1, d1, t, 1);
+                ulong t0 = t[0], t1 = t[1], t2 = t[2];
+                zz[2] ^= t0;
+                zz[3] ^= t0 ^ t1;
+                zz[4] ^= t2 ^ t1;
+                zz[5] ^= t2;
+            }
+
+            ImplCompactExt(zz);
+        }
+
+        protected static void ImplMulwAcc(ulong x, ulong y, ulong[] z, int zOff)
+        {
+            Debug.Assert(x >> 59 == 0);
+            Debug.Assert(y >> 59 == 0);
+
+            ulong[] u = new ulong[8];
+    //      u[0] = 0;
+            u[1] = y;
+            u[2] = u[1] << 1;
+            u[3] = u[2] ^  y;
+            u[4] = u[2] << 1;
+            u[5] = u[4] ^  y;
+            u[6] = u[3] << 1;
+            u[7] = u[6] ^  y;
+
+            uint j = (uint)x;
+            ulong g, h = 0, l = u[j & 7]
+                              ^ (u[(j >> 3) & 7] << 3);
+            int k = 54;
+            do
+            {
+                j = (uint)(x >> k);
+                g  = u[j & 7]
+                   ^ u[(j >> 3) & 7] << 3;
+                l ^= (g <<  k);
+                h ^= (g >> -k);
+            }
+            while ((k -= 6) > 0);
+
+            Debug.Assert(h >> 53 == 0);
+
+            z[zOff    ] ^= l & M59;
+            z[zOff + 1] ^= (l >> 59) ^ (h << 5);
+        }
+
+        protected static void ImplSquare(ulong[] x, ulong[] zz)
+        {
+            Interleave.Expand64To128(x[0], zz, 0);
+            Interleave.Expand64To128(x[1], zz, 2);
+            Interleave.Expand64To128(x[2], zz, 4);
+
+            ulong x3 = x[3];
+            zz[6] = Interleave.Expand32to64((uint)x3);
+            zz[7] = Interleave.Expand16to32((uint)(x3 >> 32));
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
new file mode 100644
index 000000000..439c41d37
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
@@ -0,0 +1,213 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT233FieldElement
+        : ECFieldElement
+    {
+        protected readonly ulong[] x;
+
+        public SecT233FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0)
+                throw new ArgumentException("value invalid for SecT233FieldElement", "x");
+
+            this.x = SecT233Field.FromBigInteger(x);
+        }
+
+        public SecT233FieldElement()
+        {
+            this.x = Nat256.Create64();
+        }
+
+        protected internal SecT233FieldElement(ulong[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat256.IsOne64(x); }
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat256.IsZero64(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return (x[0] & 1UL) != 0UL;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat256.ToBigInteger64(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecT233Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 233; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            ulong[] z = Nat256.Create64();
+            SecT233Field.Add(x, ((SecT233FieldElement)b).x, z);
+            return new SecT233FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            ulong[] z = Nat256.Create64();
+            SecT233Field.AddOne(x, z);
+            return new SecT233FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            // Addition and Subtraction are the same in F2m
+            return Add(b);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            ulong[] z = Nat256.Create64();
+            SecT233Field.Multiply(x, ((SecT233FieldElement)b).x, z);
+            return new SecT233FieldElement(z);
+        }
+
+        public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            return MultiplyPlusProduct(b, x, y);
+        }
+
+        public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x, bx = ((SecT233FieldElement)b).x;
+            ulong[] xx = ((SecT233FieldElement)x).x, yx = ((SecT233FieldElement)y).x;
+
+            ulong[] tt = Nat256.CreateExt64();
+            SecT233Field.MultiplyAddToExt(ax, bx, tt);
+            SecT233Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat256.Create64();
+            SecT233Field.Reduce(tt, z);
+            return new SecT233FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            return Multiply(b.Invert());
+        }
+
+        public override ECFieldElement Negate()
+        {
+            return this;
+        }
+
+        public override ECFieldElement Square()
+        {
+            ulong[] z = Nat256.Create64();
+            SecT233Field.Square(x, z);
+            return new SecT233FieldElement(z);
+        }
+
+        public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            return SquarePlusProduct(x, y);
+        }
+
+        public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x;
+            ulong[] xx = ((SecT233FieldElement)x).x, yx = ((SecT233FieldElement)y).x;
+
+            ulong[] tt = Nat256.CreateExt64();
+            SecT233Field.SquareAddToExt(ax, tt);
+            SecT233Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat256.Create64();
+            SecT233Field.Reduce(tt, z);
+            return new SecT233FieldElement(z);
+        }
+
+        public override ECFieldElement SquarePow(int pow)
+        {
+            if (pow < 1)
+                return this;
+
+            ulong[] z = Nat256.Create64();
+            SecT233Field.SquareN(x, pow, z);
+            return new SecT233FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            return new SecT233FieldElement(
+                AbstractF2mCurve.Inverse(233, new int[] { 74 }, ToBigInteger()));
+        }
+
+        public override ECFieldElement Sqrt()
+        {
+            return SquarePow(M - 1);
+        }
+
+        public virtual int Representation
+        {
+            get { return F2mFieldElement.Tpb; }
+        }
+
+        public virtual int M
+        {
+            get { return 233; }
+        }
+
+        public virtual int K1
+        {
+            get { return 74; }
+        }
+
+        public virtual int K2
+        {
+            get { return 0; }
+        }
+
+        public virtual int K3
+        {
+            get { return 0; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecT233FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecT233FieldElement);
+        }
+
+        public virtual bool Equals(SecT233FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat256.Eq64(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return 2330074 ^ Arrays.GetHashCode(x, 0, 4);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
new file mode 100644
index 000000000..8768eaa81
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
@@ -0,0 +1,196 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT233K1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT233K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT233K1Point m_infinity;
+
+        public SecT233K1Curve()
+            : base(233, 74, 0, 0)
+        {
+            this.m_infinity = new SecT233K1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.Zero);
+            this.m_b = FromBigInteger(BigInteger.One);
+            this.m_order = new BigInteger(1, Hex.Decode("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF"));
+            this.m_cofactor = BigInteger.ValueOf(4);
+
+            this.m_coord = SecT233K1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT233K1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        protected override ECMultiplier CreateDefaultMultiplier()
+        {
+            return new WTauNafMultiplier();
+        }
+
+        public override int FieldSize
+        {
+            get { return 233; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT233FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT233K1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT233K1Point(this, x, y, zs, withCompression);
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return true; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+            {
+                return beta;
+            }
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(233, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 233; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 233; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return true; }
+        }
+
+        public virtual int K1
+        {
+            get { return 74; }
+        }
+
+        public virtual int K2
+        {
+            get { return 0; }
+        }
+
+        public virtual int K3
+        {
+            get { return 0; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT233K1Point.cs b/crypto/src/math/ec/custom/sec/SecT233K1Point.cs
new file mode 100644
index 000000000..7e7ee8f0b
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233K1Point.cs
@@ -0,0 +1,302 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT233K1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT233K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                {
+                    return curve.Infinity;
+                }
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                X3 = L.Square().Add(L).Add(X1);
+                if (X3.IsZero)
+                {
+                    //return new SecT233K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT233K1Point(curve, X3, curve.B, IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    //return new SecT233K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT233K1Point(curve, X3, curve.B, IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT233K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+            {
+                return this;
+            }
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement T;
+            if (Z1IsOne)
+            {
+                T = L1.Square().Add(L1);
+            }
+            else
+            {
+                T = L1.Add(Z1).Multiply(L1);
+            }
+
+            if (T.IsZero)
+            {
+                //return new SecT233K1Point(curve, T, curve.B.sqrt(), withCompression);
+                return new SecT233K1Point(curve, T, curve.B, IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement t1 = L1.Add(X1).Square();
+            ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+            ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+            return new SecT233K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            // NOTE: TwicePlus() only optimized for lambda-affine argument
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement T = L1Sq.Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                {
+                    return b.Twice();
+                }
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                //return new SecT233K1Point(curve, A, curve.B.sqrt(), withCompression);
+                return new SecT233K1Point(curve, A, curve.B, IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT233K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT233K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
new file mode 100644
index 000000000..92795b8a7
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
@@ -0,0 +1,188 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT233R1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT233R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT233R1Point m_infinity;
+
+        public SecT233R1Curve()
+            : base(233, 74, 0, 0)
+        {
+            this.m_infinity = new SecT233R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.One);
+            this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD")));
+            this.m_order = new BigInteger(1, Hex.Decode("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7"));
+            this.m_cofactor = BigInteger.Two;
+
+            this.m_coord = SecT233R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT233R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 233; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT233FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT233R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT233R1Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return false; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+                return beta;
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(233, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 233; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 233; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return true; }
+        }
+
+        public virtual int K1
+        {
+            get { return 74; }
+        }
+
+        public virtual int K2
+        {
+            get { return 0; }
+        }
+
+        public virtual int K3
+        {
+            get { return 0; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT233R1Point.cs b/crypto/src/math/ec/custom/sec/SecT233R1Point.cs
new file mode 100644
index 000000000..ffac89d15
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT233R1Point.cs
@@ -0,0 +1,282 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT233R1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT233R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                X3 = L.Square().Add(L).Add(X1).AddOne();
+                if (X3.IsZero)
+                {
+                    return new SecT233R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    return new SecT233R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT233R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+            if (T.IsZero)
+            {
+                return new SecT233R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+            ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+            return new SecT233R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                return new SecT233R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT233R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT233R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT239Field.cs b/crypto/src/math/ec/custom/sec/SecT239Field.cs
new file mode 100644
index 000000000..1e0824af9
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT239Field.cs
@@ -0,0 +1,249 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT239Field
+    {
+        private const ulong M47 = ulong.MaxValue >> 17;
+        private const ulong M60 = ulong.MaxValue >> 4;
+
+        public static void Add(ulong[] x, ulong[] y, ulong[] z)
+        {
+            z[0] = x[0] ^ y[0];
+            z[1] = x[1] ^ y[1];
+            z[2] = x[2] ^ y[2];
+            z[3] = x[3] ^ y[3];
+        }
+
+        public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+        {
+            zz[0] = xx[0] ^ yy[0];
+            zz[1] = xx[1] ^ yy[1];
+            zz[2] = xx[2] ^ yy[2];
+            zz[3] = xx[3] ^ yy[3];
+            zz[4] = xx[4] ^ yy[4];
+            zz[5] = xx[5] ^ yy[5];
+            zz[6] = xx[6] ^ yy[6];
+            zz[7] = xx[7] ^ yy[7];
+        }
+
+        public static void AddOne(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0] ^ 1UL;
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+        }
+
+        public static ulong[] FromBigInteger(BigInteger x)
+        {
+            ulong[] z = Nat256.FromBigInteger64(x);
+            Reduce17(z, 0);
+            return z;
+        }
+
+        public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+        {
+            ulong[] tt = Nat256.CreateExt64();
+            ImplMultiply(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            ulong[] tt = Nat256.CreateExt64();
+            ImplMultiply(x, y, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void Reduce(ulong[] xx, ulong[] z)
+        {
+            ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3];
+            ulong x4 = xx[4], x5 = xx[5], x6 = xx[6], x7 = xx[7];
+
+            x3 ^= (x7 << 17);
+            x4 ^= (x7 >> 47);
+            x5 ^= (x7 << 47);
+            x6 ^= (x7 >> 17);
+
+            x2 ^= (x6 << 17);
+            x3 ^= (x6 >> 47);
+            x4 ^= (x6 << 47);
+            x5 ^= (x6 >> 17);
+
+            x1 ^= (x5 << 17);
+            x2 ^= (x5 >> 47);
+            x3 ^= (x5 << 47);
+            x4 ^= (x5 >> 17);
+
+            x0 ^= (x4 << 17);
+            x1 ^= (x4 >> 47);
+            x2 ^= (x4 << 47);
+            x3 ^= (x4 >> 17);
+
+            ulong t = x3 >> 47;
+            z[0]    = x0 ^ t;
+            z[1]    = x1;
+            z[2]    = x2 ^ (t << 30);
+            z[3]    = x3 & M47;
+        }
+
+        public static void Reduce17(ulong[] z, int zOff)
+        {
+            ulong z3     = z[zOff + 3], t = z3 >> 47;
+            z[zOff    ] ^= t;
+            z[zOff + 2] ^= (t << 30);
+            z[zOff + 3]  = z3 & M47;
+        }
+
+        public static void Square(ulong[] x, ulong[] z)
+        {
+            ulong[] tt = Nat256.CreateExt64();
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareAddToExt(ulong[] x, ulong[] zz)
+        {
+            ulong[] tt = Nat256.CreateExt64();
+            ImplSquare(x, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void SquareN(ulong[] x, int n, ulong[] z)
+        {
+            Debug.Assert(n > 0);
+
+            ulong[] tt = Nat256.CreateExt64();
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                ImplSquare(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        protected static void ImplCompactExt(ulong[] zz)
+        {
+            ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5], z6 = zz[6], z7 = zz[7];
+            zz[0] =  z0        ^ (z1 << 60);
+            zz[1] = (z1 >>  4) ^ (z2 << 56);
+            zz[2] = (z2 >>  8) ^ (z3 << 52);
+            zz[3] = (z3 >> 12) ^ (z4 << 48);
+            zz[4] = (z4 >> 16) ^ (z5 << 44);
+            zz[5] = (z5 >> 20) ^ (z6 << 40);
+            zz[6] = (z6 >> 24) ^ (z7 << 36);
+            zz[7] = (z7 >> 28);
+        }
+
+        protected static void ImplExpand(ulong[] x, ulong[] z)
+        {
+            ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+            z[0] = x0 & M60;
+            z[1] = ((x0 >> 60) ^ (x1 <<  4)) & M60;
+            z[2] = ((x1 >> 56) ^ (x2 <<  8)) & M60;
+            z[3] = ((x2 >> 52) ^ (x3 << 12));
+        }
+
+        protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            /*
+             * "Two-level seven-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+             */
+
+            ulong[] f = new ulong[4], g = new ulong[4];
+            ImplExpand(x, f);
+            ImplExpand(y, g);
+
+            ImplMulwAcc(f[0], g[0], zz, 0);
+            ImplMulwAcc(f[1], g[1], zz, 1);
+            ImplMulwAcc(f[2], g[2], zz, 2);
+            ImplMulwAcc(f[3], g[3], zz, 3);
+
+            // U *= (1 - t^n)
+            for (int i = 5; i > 0; --i)
+            {
+                zz[i] ^= zz[i - 1];
+            }
+
+            ImplMulwAcc(f[0] ^ f[1], g[0] ^ g[1], zz, 1);
+            ImplMulwAcc(f[2] ^ f[3], g[2] ^ g[3], zz, 3);
+
+            // V *= (1 - t^2n)
+            for (int i = 7; i > 1; --i)
+            {
+                zz[i] ^= zz[i - 2];
+            }
+
+            // Double-length recursion
+            {
+                ulong c0 = f[0] ^ f[2], c1 = f[1] ^ f[3];
+                ulong d0 = g[0] ^ g[2], d1 = g[1] ^ g[3];
+                ImplMulwAcc(c0 ^ c1, d0 ^ d1, zz, 3);
+                ulong[] t = new ulong[3];
+                ImplMulwAcc(c0, d0, t, 0);
+                ImplMulwAcc(c1, d1, t, 1);
+                ulong t0 = t[0], t1 = t[1], t2 = t[2];
+                zz[2] ^= t0;
+                zz[3] ^= t0 ^ t1;
+                zz[4] ^= t2 ^ t1;
+                zz[5] ^= t2;
+            }
+
+            ImplCompactExt(zz);
+        }
+
+        protected static void ImplMulwAcc(ulong x, ulong y, ulong[] z, int zOff)
+        {
+            Debug.Assert(x >> 60 == 0);
+            Debug.Assert(y >> 60 == 0);
+
+            ulong[] u = new ulong[8];
+    //      u[0] = 0;
+            u[1] = y;
+            u[2] = u[1] << 1;
+            u[3] = u[2] ^  y;
+            u[4] = u[2] << 1;
+            u[5] = u[4] ^  y;
+            u[6] = u[3] << 1;
+            u[7] = u[6] ^  y;
+
+            uint j = (uint)x;
+            ulong g, h = 0, l = u[j & 7]
+                              ^ (u[(j >> 3) & 7] << 3);
+            int k = 54;
+            do
+            {
+                j = (uint)(x >> k);
+                g  = u[j & 7]
+                   ^ u[(j >> 3) & 7] << 3;
+                l ^= (g <<  k);
+                h ^= (g >> -k);
+            }
+            while ((k -= 6) > 0);
+
+            h ^= ((x & 0x0820820820820820L) & (ulong)(((long)y << 4) >> 63)) >> 5;
+
+            Debug.Assert(h >> 55 == 0);
+
+            z[zOff    ] ^= l & M60;
+            z[zOff + 1] ^= (l >> 60) ^ (h << 4);
+        }
+
+        protected static void ImplSquare(ulong[] x, ulong[] zz)
+        {
+            Interleave.Expand64To128(x[0], zz, 0);
+            Interleave.Expand64To128(x[1], zz, 2);
+            Interleave.Expand64To128(x[2], zz, 4);
+
+            ulong x3 = x[3];
+            zz[6] = Interleave.Expand32to64((uint)x3);
+            zz[7] = Interleave.Expand16to32((uint)(x3 >> 32));
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
new file mode 100644
index 000000000..c89b484b1
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
@@ -0,0 +1,213 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT239FieldElement
+        : ECFieldElement
+    {
+        protected ulong[] x;
+
+        public SecT239FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0)
+                throw new ArgumentException("value invalid for SecT239FieldElement", "x");
+
+            this.x = SecT239Field.FromBigInteger(x);
+        }
+
+        public SecT239FieldElement()
+        {
+            this.x = Nat256.Create64();
+        }
+
+        protected internal SecT239FieldElement(ulong[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat256.IsOne64(x); }
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat256.IsZero64(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return (x[0] & 1L) != 0L;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat256.ToBigInteger64(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecT239Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 239; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            ulong[] z = Nat256.Create64();
+            SecT239Field.Add(x, ((SecT239FieldElement)b).x, z);
+            return new SecT239FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            ulong[] z = Nat256.Create64();
+            SecT239Field.AddOne(x, z);
+            return new SecT239FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            // Addition and Subtraction are the same in F2m
+            return Add(b);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            ulong[] z = Nat256.Create64();
+            SecT239Field.Multiply(x, ((SecT239FieldElement)b).x, z);
+            return new SecT239FieldElement(z);
+        }
+
+        public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            return MultiplyPlusProduct(b, x, y);
+        }
+
+        public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x, bx = ((SecT239FieldElement)b).x;
+            ulong[] xx = ((SecT239FieldElement)x).x, yx = ((SecT239FieldElement)y).x;
+
+            ulong[] tt = Nat256.CreateExt64();
+            SecT239Field.MultiplyAddToExt(ax, bx, tt);
+            SecT239Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat256.Create64();
+            SecT239Field.Reduce(tt, z);
+            return new SecT239FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            return Multiply(b.Invert());
+        }
+
+        public override ECFieldElement Negate()
+        {
+            return this;
+        }
+
+        public override ECFieldElement Square()
+        {
+            ulong[] z = Nat256.Create64();
+            SecT239Field.Square(x, z);
+            return new SecT239FieldElement(z);
+        }
+
+        public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            return SquarePlusProduct(x, y);
+        }
+
+        public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x;
+            ulong[] xx = ((SecT239FieldElement)x).x, yx = ((SecT239FieldElement)y).x;
+
+            ulong[] tt = Nat256.CreateExt64();
+            SecT239Field.SquareAddToExt(ax, tt);
+            SecT239Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat256.Create64();
+            SecT239Field.Reduce(tt, z);
+            return new SecT239FieldElement(z);
+        }
+
+        public override ECFieldElement SquarePow(int pow)
+        {
+            if (pow < 1)
+                return this;
+
+            ulong[] z = Nat256.Create64();
+            SecT239Field.SquareN(x, pow, z);
+            return new SecT239FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            return new SecT239FieldElement(
+                AbstractF2mCurve.Inverse(239, new int[] { 158 }, ToBigInteger()));
+        }
+
+        public override ECFieldElement Sqrt()
+        {
+            return SquarePow(M - 1);
+        }
+
+        public virtual int Representation
+        {
+            get { return F2mFieldElement.Tpb; }
+        }
+
+        public virtual int M
+        {
+            get { return 239; }
+        }
+
+        public virtual int K1
+        {
+            get { return 158; }
+        }
+
+        public virtual int K2
+        {
+            get { return 0; }
+        }
+
+        public virtual int K3
+        {
+            get { return 0; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecT239FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecT239FieldElement);
+        }
+
+        public virtual bool Equals(SecT239FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat256.Eq64(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return 23900158 ^ Arrays.GetHashCode(x, 0, 4);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
new file mode 100644
index 000000000..2c73d941f
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
@@ -0,0 +1,194 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT239K1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT239K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT239K1Point m_infinity;
+
+        public SecT239K1Curve()
+            : base(239, 158, 0, 0)
+        {
+            this.m_infinity = new SecT239K1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.Zero);
+            this.m_b = FromBigInteger(BigInteger.One);
+            this.m_order = new BigInteger(1, Hex.Decode("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5"));
+            this.m_cofactor = BigInteger.ValueOf(4);
+
+            this.m_coord = SecT239K1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT239K1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        protected override ECMultiplier CreateDefaultMultiplier()
+        {
+            return new WTauNafMultiplier();
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 239; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT239FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT239K1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT239K1Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return true; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+                return beta;
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(239, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 239; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 239; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return true; }
+        }
+
+        public virtual int K1
+        {
+            get { return 158; }
+        }
+
+        public virtual int K2
+        {
+            get { return 0; }
+        }
+
+        public virtual int K3
+        {
+            get { return 0; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT239K1Point.cs b/crypto/src/math/ec/custom/sec/SecT239K1Point.cs
new file mode 100644
index 000000000..ac079ad1e
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT239K1Point.cs
@@ -0,0 +1,297 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT239K1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT239K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                //            X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                X3 = L.Square().Add(L).Add(X1);
+                if (X3.IsZero)
+                {
+                    //return new SecT239K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT239K1Point(curve, X3, curve.B, IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    //return new SecT239K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT239K1Point(curve, X3, curve.B, IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT239K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement T;
+            if (Z1IsOne)
+            {
+                T = L1.Square().Add(L1);
+            }
+            else
+            {
+                T = L1.Add(Z1).Multiply(L1);
+            }
+
+            if (T.IsZero)
+            {
+                //return new SecT239K1Point(curve, T, curve.B.sqrt(), withCompression);
+                return new SecT239K1Point(curve, T, curve.B, IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement t1 = L1.Add(X1).Square();
+            ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+            ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+            return new SecT239K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            // NOTE: TwicePlus() only optimized for lambda-affine argument
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement T = L1Sq.Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                //return new SecT239K1Point(curve, A, curve.B.sqrt(), withCompression);
+                return new SecT239K1Point(curve, A, curve.B, IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT239K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT239K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT283Field.cs b/crypto/src/math/ec/custom/sec/SecT283Field.cs
new file mode 100644
index 000000000..9afb27461
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283Field.cs
@@ -0,0 +1,335 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT283Field
+    {
+        private const ulong M27 = ulong.MaxValue >> 37;
+        private const ulong M57 = ulong.MaxValue >> 7;
+
+        public static void Add(ulong[] x, ulong[] y, ulong[] z)
+        {
+            z[0] = x[0] ^ y[0];
+            z[1] = x[1] ^ y[1];
+            z[2] = x[2] ^ y[2];
+            z[3] = x[3] ^ y[3];
+            z[4] = x[4] ^ y[4];
+        }
+
+        public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+        {
+            zz[0] = xx[0] ^ yy[0];
+            zz[1] = xx[1] ^ yy[1];
+            zz[2] = xx[2] ^ yy[2];
+            zz[3] = xx[3] ^ yy[3];
+            zz[4] = xx[4] ^ yy[4];
+            zz[5] = xx[5] ^ yy[5];
+            zz[6] = xx[6] ^ yy[6];
+            zz[7] = xx[7] ^ yy[7];
+            zz[8] = xx[8] ^ yy[8];
+        }
+
+        public static void AddOne(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0] ^ 1UL;
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+            z[4] = x[4];
+        }
+
+        public static ulong[] FromBigInteger(BigInteger x)
+        {
+            ulong[] z = Nat320.FromBigInteger64(x);
+            Reduce37(z, 0);
+            return z;
+        }
+
+        public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+        {
+            ulong[] tt = Nat320.CreateExt64();
+            ImplMultiply(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            ulong[] tt = Nat320.CreateExt64();
+            ImplMultiply(x, y, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void Reduce(ulong[] xx, ulong[] z)
+        {
+            ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3], x4 = xx[4];
+            ulong x5 = xx[5], x6 = xx[6], x7 = xx[7], x8 = xx[8];
+
+            x3 ^= (x8 << 37) ^ (x8 << 42) ^ (x8 << 44) ^ (x8 << 49);
+            x4 ^= (x8 >> 27) ^ (x8 >> 22) ^ (x8 >> 20) ^ (x8 >> 15);
+
+            x2 ^= (x7 << 37) ^ (x7 << 42) ^ (x7 << 44) ^ (x7 << 49);
+            x3 ^= (x7 >> 27) ^ (x7 >> 22) ^ (x7 >> 20) ^ (x7 >> 15);
+
+            x1 ^= (x6 << 37) ^ (x6 << 42) ^ (x6 << 44) ^ (x6 << 49);
+            x2 ^= (x6 >> 27) ^ (x6 >> 22) ^ (x6 >> 20) ^ (x6 >> 15);
+
+            x0 ^= (x5 << 37) ^ (x5 << 42) ^ (x5 << 44) ^ (x5 << 49);
+            x1 ^= (x5 >> 27) ^ (x5 >> 22) ^ (x5 >> 20) ^ (x5 >> 15);
+
+            ulong t = x4 >> 27;
+            z[0]    = x0 ^ t ^ (t << 5) ^ (t << 7) ^ (t << 12);
+            z[1]    = x1; 
+            z[2]    = x2; 
+            z[3]    = x3; 
+            z[4]    = x4 & M27; 
+        }
+
+        public static void Reduce37(ulong[] z, int zOff)
+        {
+            ulong z4     = z[zOff + 4], t = z4 >> 27;
+            z[zOff    ] ^= t ^ (t << 5) ^ (t << 7) ^ (t << 12);
+            z[zOff + 4]  = z4 & M27;
+        }
+
+        public static void Square(ulong[] x, ulong[] z)
+        {
+            ulong[] tt = Nat.Create64(9);
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareAddToExt(ulong[] x, ulong[] zz)
+        {
+            ulong[] tt = Nat.Create64(9);
+            ImplSquare(x, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void SquareN(ulong[] x, int n, ulong[] z)
+        {
+            Debug.Assert(n > 0);
+
+            ulong[] tt = Nat.Create64(9);
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                ImplSquare(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        protected static void ImplCompactExt(ulong[] zz)
+        {
+            ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4];
+            ulong z5 = zz[5], z6 = zz[6], z7 = zz[7], z8 = zz[8], z9 = zz[9];
+            zz[0] =  z0        ^ (z1 << 57);
+            zz[1] = (z1 >>  7) ^ (z2 << 50);
+            zz[2] = (z2 >> 14) ^ (z3 << 43);
+            zz[3] = (z3 >> 21) ^ (z4 << 36);
+            zz[4] = (z4 >> 28) ^ (z5 << 29);
+            zz[5] = (z5 >> 35) ^ (z6 << 22);
+            zz[6] = (z6 >> 42) ^ (z7 << 15);
+            zz[7] = (z7 >> 49) ^ (z8 <<  8);
+            zz[8] = (z8 >> 56) ^ (z9 <<  1);
+            zz[9] = (z9 >> 63); // Zero!
+        }
+
+        protected static void ImplExpand(ulong[] x, ulong[] z)
+        {
+            ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4];
+            z[0] = x0 & M57;
+            z[1] = ((x0 >> 57) ^ (x1 <<  7)) & M57;
+            z[2] = ((x1 >> 50) ^ (x2 << 14)) & M57;
+            z[3] = ((x2 >> 43) ^ (x3 << 21)) & M57;
+            z[4] = ((x3 >> 36) ^ (x4 << 28));
+        }
+
+        //protected static void AddMs(ulong[] zz, int zOff, ulong[] p, params int[] ms)
+        //{
+        //    ulong t0 = 0, t1 = 0;
+        //    foreach (int m in ms)
+        //    {
+        //        int i = (m - 1) << 1;
+        //        t0 ^= p[i    ];
+        //        t1 ^= p[i + 1];
+        //    }
+        //    zz[zOff    ] ^= t0;
+        //    zz[zOff + 1] ^= t1;
+        //}
+
+        protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            /*
+             * Formula (17) from "Some New Results on Binary Polynomial Multiplication",
+             * Murat Cenk and M. Anwar Hasan.
+             * 
+             * The formula as given contained an error in the term t25, as noted below
+             */
+            ulong[] a = new ulong[5], b = new ulong[5];
+            ImplExpand(x, a);
+            ImplExpand(y, b);
+
+            ulong[] p = new ulong[26];
+
+            ImplMulw(a[0], b[0], p, 0);                                 // m1
+            ImplMulw(a[1], b[1], p, 2);                                 // m2
+            ImplMulw(a[2], b[2], p, 4);                                 // m3
+            ImplMulw(a[3], b[3], p, 6);                                 // m4
+            ImplMulw(a[4], b[4], p, 8);                                 // m5
+
+            ulong u0 = a[0] ^ a[1], v0 = b[0] ^ b[1];
+            ulong u1 = a[0] ^ a[2], v1 = b[0] ^ b[2];
+            ulong u2 = a[2] ^ a[4], v2 = b[2] ^ b[4];
+            ulong u3 = a[3] ^ a[4], v3 = b[3] ^ b[4];
+
+            ImplMulw(u1 ^ a[3], v1 ^ b[3], p, 18);                      // m10
+            ImplMulw(u2 ^ a[1], v2 ^ b[1], p, 20);                      // m11
+
+            ulong A4 = u0 ^ u3  , B4 = v0 ^ v3;
+            ulong A5 = A4 ^ a[2], B5 = B4 ^ b[2];
+
+            ImplMulw(A4, B4, p, 22);                                    // m12
+            ImplMulw(A5, B5, p, 24);                                    // m13
+
+            ImplMulw(u0, v0, p, 10);                                    // m6
+            ImplMulw(u1, v1, p, 12);                                    // m7
+            ImplMulw(u2, v2, p, 14);                                    // m8
+            ImplMulw(u3, v3, p, 16);                                    // m9
+
+
+            // Original method, corresponding to formula (16)
+            //AddMs(zz, 0, p, 1);
+            //AddMs(zz, 1, p, 1, 2, 6);
+            //AddMs(zz, 2, p, 1, 2, 3, 7);
+            //AddMs(zz, 3, p, 1, 3, 4, 5, 8, 10, 12, 13);
+            //AddMs(zz, 4, p, 1, 2, 4, 5, 6, 9, 10, 11, 13);
+            //AddMs(zz, 5, p, 1, 2, 3, 5, 7, 11, 12, 13);
+            //AddMs(zz, 6, p, 3, 4, 5, 8);
+            //AddMs(zz, 7, p, 4, 5, 9);
+            //AddMs(zz, 8, p, 5);
+
+            // Improved method factors out common single-word terms
+            // NOTE: p1,...,p26 in the paper maps to p[0],...,p[25] here
+
+            zz[0]     = p[ 0];
+            zz[9]     = p[ 9];
+
+            ulong t1  = p[ 0] ^ p[ 1];
+            ulong t2  = t1    ^ p[ 2];
+            ulong t3  = t2    ^ p[10];
+        
+            zz[1]     = t3;
+
+            ulong t4  = p[ 3] ^ p[ 4];
+            ulong t5  = p[11] ^ p[12];
+            ulong t6  = t4    ^ t5;
+            ulong t7  = t2    ^ t6;
+
+            zz[2]     = t7;
+
+            ulong t8  = t1    ^ t4;
+            ulong t9  = p[ 5] ^ p[ 6];
+            ulong t10 = t8    ^ t9;
+            ulong t11 = t10   ^ p[ 8];
+            ulong t12 = p[13] ^ p[14];
+            ulong t13 = t11   ^ t12;
+            ulong t14 = p[18] ^ p[22];
+            ulong t15 = t14   ^ p[24];
+            ulong t16 = t13   ^ t15;
+
+            zz[3]     = t16;
+
+            ulong t17 = p[ 7] ^ p[ 8];
+            ulong t18 = t17   ^ p[ 9];
+            ulong t19 = t18   ^ p[17];
+
+            zz[8]     = t19;
+
+            ulong t20 = t18   ^ t9;
+            ulong t21 = p[15] ^ p[16];
+            ulong t22 = t20   ^ t21;
+
+            zz[7]     = t22;
+
+            ulong t23 = t22   ^ t3;
+            ulong t24 = p[19] ^ p[20];
+    //      ulong t25 = p[23] ^ p[24];
+            ulong t25 = p[25] ^ p[24];       // Fixes an error in the paper: p[23] -> p{25]
+            ulong t26 = p[18] ^ p[23];
+            ulong t27 = t24   ^ t25;
+            ulong t28 = t27   ^ t26;
+            ulong t29 = t28   ^ t23;
+
+            zz[4]     = t29;
+        
+            ulong t30 = t7    ^ t19;
+            ulong t31 = t27   ^ t30;
+            ulong t32 = p[21] ^ p[22];
+            ulong t33 = t31   ^ t32;
+
+            zz[5]     = t33;
+
+            ulong t34 = t11   ^ p[0];
+            ulong t35 = t34   ^ p[9];
+            ulong t36 = t35   ^ t12;
+            ulong t37 = t36   ^ p[21];
+            ulong t38 = t37   ^ p[23];
+            ulong t39 = t38   ^ p[25];
+
+            zz[6]     = t39;
+
+            ImplCompactExt(zz);
+        }
+
+        protected static void ImplMulw(ulong x, ulong y, ulong[] z, int zOff)
+        {
+            Debug.Assert(x >> 57 == 0);
+            Debug.Assert(y >> 57 == 0);
+
+            ulong[] u = new ulong[8];
+    //      u[0] = 0;
+            u[1] = y;
+            u[2] = u[1] << 1;
+            u[3] = u[2] ^  y;
+            u[4] = u[2] << 1;
+            u[5] = u[4] ^  y;
+            u[6] = u[3] << 1;
+            u[7] = u[6] ^  y;
+
+            uint j = (uint)x;
+            ulong g, h = 0, l = u[j & 7];
+            int k = 48;
+            do
+            {
+                j = (uint)(x >> k);
+                g  = u[j & 7]
+                   ^ u[(j >> 3) & 7] << 3
+                   ^ u[(j >> 6) & 7] << 6;
+                l ^= (g <<  k);
+                h ^= (g >> -k);
+            }
+            while ((k -= 9) > 0);
+
+            h ^= ((x & 0x0100804020100800L) & (ulong)(((long)y << 7) >> 63)) >> 8;
+
+            Debug.Assert(h >> 49 == 0);
+
+            z[zOff    ] = l & M57;
+            z[zOff + 1] = (l >> 57) ^ (h << 7);
+        }
+
+        protected static void ImplSquare(ulong[] x, ulong[] zz)
+        {
+            for (int i = 0; i < 4; ++i)
+            {
+                Interleave.Expand64To128(x[i], zz, i << 1);
+            }
+            zz[8] = Interleave.Expand32to64((uint)x[4]);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
new file mode 100644
index 000000000..09243e859
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
@@ -0,0 +1,213 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT283FieldElement
+        : ECFieldElement
+    {
+        protected readonly ulong[] x;
+
+        public SecT283FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0)
+                throw new ArgumentException("value invalid for SecT283FieldElement", "x");
+
+            this.x = SecT283Field.FromBigInteger(x);
+        }
+
+        public SecT283FieldElement()
+        {
+            this.x = Nat320.Create64();
+        }
+
+        protected internal SecT283FieldElement(ulong[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat320.IsOne64(x); }
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat320.IsZero64(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return (x[0] & 1UL) != 0UL;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat320.ToBigInteger64(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecT283Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 283; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            ulong[] z = Nat320.Create64();
+            SecT283Field.Add(x, ((SecT283FieldElement)b).x, z);
+            return new SecT283FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            ulong[] z = Nat320.Create64();
+            SecT283Field.AddOne(x, z);
+            return new SecT283FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            // Addition and subtraction are the same in F2m
+            return Add(b);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            ulong[] z = Nat320.Create64();
+            SecT283Field.Multiply(x, ((SecT283FieldElement)b).x, z);
+            return new SecT283FieldElement(z);
+        }
+
+        public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            return MultiplyPlusProduct(b, x, y);
+        }
+
+        public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x, bx = ((SecT283FieldElement)b).x;
+            ulong[] xx = ((SecT283FieldElement)x).x, yx = ((SecT283FieldElement)y).x;
+
+            ulong[] tt = Nat.Create64(9);
+            SecT283Field.MultiplyAddToExt(ax, bx, tt);
+            SecT283Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat320.Create64();
+            SecT283Field.Reduce(tt, z);
+            return new SecT283FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            return Multiply(b.Invert());
+        }
+
+        public override ECFieldElement Negate()
+        {
+            return this;
+        }
+
+        public override ECFieldElement Square()
+        {
+            ulong[] z = Nat320.Create64();
+            SecT283Field.Square(x, z);
+            return new SecT283FieldElement(z);
+        }
+
+        public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            return SquarePlusProduct(x, y);
+        }
+
+        public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x;
+            ulong[] xx = ((SecT283FieldElement)x).x, yx = ((SecT283FieldElement)y).x;
+
+            ulong[] tt = Nat.Create64(9);
+            SecT283Field.SquareAddToExt(ax, tt);
+            SecT283Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat320.Create64();
+            SecT283Field.Reduce(tt, z);
+            return new SecT283FieldElement(z);
+        }
+
+        public override ECFieldElement SquarePow(int pow)
+        {
+            if (pow < 1)
+                return this;
+
+            ulong[] z = Nat320.Create64();
+            SecT283Field.SquareN(x, pow, z);
+            return new SecT283FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            return new SecT283FieldElement(
+                AbstractF2mCurve.Inverse(283, new int[] { 5, 7, 12 }, ToBigInteger()));
+        }
+
+        public override ECFieldElement Sqrt()
+        {
+            return SquarePow(M - 1);
+        }
+
+        public virtual int Representation
+        {
+            get { return F2mFieldElement.Ppb; }
+        }
+
+        public virtual int M
+        {
+            get { return 283; }
+        }
+
+        public virtual int K1
+        {
+            get { return 5; }
+        }
+
+        public virtual int K2
+        {
+            get { return 7; }
+        }
+
+        public virtual int K3
+        {
+            get { return 12; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecT283FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecT283FieldElement);
+        }
+
+        public virtual bool Equals(SecT283FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat320.Eq64(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return 2831275 ^ Arrays.GetHashCode(x, 0, 5);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
new file mode 100644
index 000000000..42414401f
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
@@ -0,0 +1,194 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT283K1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT283K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT283K1Point m_infinity;
+
+        public SecT283K1Curve()
+            : base(283, 5, 7, 12)
+        {
+            this.m_infinity = new SecT283K1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.Zero);
+            this.m_b = FromBigInteger(BigInteger.One);
+            this.m_order = new BigInteger(1, Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61"));
+            this.m_cofactor = BigInteger.ValueOf(4);
+
+            this.m_coord = SecT283K1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT283K1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        protected override ECMultiplier CreateDefaultMultiplier()
+        {
+            return new WTauNafMultiplier();
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 283; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT283FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT283K1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT283K1Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return true; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+                return beta;
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(283, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 283; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 283; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return false; }
+        }
+
+        public virtual int K1
+        {
+            get { return 5; }
+        }
+
+        public virtual int K2
+        {
+            get { return 7; }
+        }
+
+        public virtual int K3
+        {
+            get { return 12; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT283K1Point.cs b/crypto/src/math/ec/custom/sec/SecT283K1Point.cs
new file mode 100644
index 000000000..f85706c63
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283K1Point.cs
@@ -0,0 +1,296 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT283K1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT283K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                X3 = L.Square().Add(L).Add(X1);
+                if (X3.IsZero)
+                {
+                    //return new SecT283K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT283K1Point(curve, X3, curve.B, IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    //return new SecT283K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT283K1Point(curve, X3, curve.B, IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT283K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement T;
+            if (Z1IsOne)
+            {
+                T = L1.Square().Add(L1);
+            }
+            else
+            {
+                T = L1.Add(Z1).Multiply(L1);
+            }
+
+            if (T.IsZero)
+            {
+                //return new SecT283K1Point(curve, T, curve.B.sqrt(), withCompression);
+                return new SecT283K1Point(curve, T, curve.B, IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement t1 = L1.Add(X1).Square();
+            ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+            ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+            return new SecT283K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            // NOTE: TwicePlus() only optimized for lambda-affine argument
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement T = L1Sq.Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                //return new SecT283K1Point(curve, A, curve.B.sqrt(), withCompression);
+                return new SecT283K1Point(curve, A, curve.B, IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT283K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT283K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
new file mode 100644
index 000000000..d8c462eeb
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
@@ -0,0 +1,188 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT283R1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT283R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT283R1Point m_infinity;
+
+        public SecT283R1Curve()
+            : base(283, 5, 7, 12)
+        {
+            this.m_infinity = new SecT283R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.One);
+            this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5")));
+            this.m_order = new BigInteger(1, Hex.Decode("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307"));
+            this.m_cofactor = BigInteger.Two;
+
+            this.m_coord = SecT283R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT283R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 283; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT283FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT283R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT283R1Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return false; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+                return beta;
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(283, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 283; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 283; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return false; }
+        }
+
+        public virtual int K1
+        {
+            get { return 5; }
+        }
+
+        public virtual int K2
+        {
+            get { return 7; }
+        }
+
+        public virtual int K3
+        {
+            get { return 12; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT283R1Point.cs b/crypto/src/math/ec/custom/sec/SecT283R1Point.cs
new file mode 100644
index 000000000..340bbdae6
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT283R1Point.cs
@@ -0,0 +1,282 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT283R1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT283R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                X3 = L.Square().Add(L).Add(X1).AddOne();
+                if (X3.IsZero)
+                {
+                    return new SecT283R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    return new SecT283R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT283R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+            if (T.IsZero)
+            {
+                return new SecT283R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+            ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+            return new SecT283R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                return new SecT283R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT283R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT283R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT409Field.cs b/crypto/src/math/ec/custom/sec/SecT409Field.cs
new file mode 100644
index 000000000..d71f5b5f9
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409Field.cs
@@ -0,0 +1,244 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT409Field
+    {
+        private const ulong M25 = ulong.MaxValue >> 39;
+        private const ulong M59 = ulong.MaxValue >> 5;
+
+        public static void Add(ulong[] x, ulong[] y, ulong[] z)
+        {
+            z[0] = x[0] ^ y[0];
+            z[1] = x[1] ^ y[1];
+            z[2] = x[2] ^ y[2];
+            z[3] = x[3] ^ y[3];
+            z[4] = x[4] ^ y[4];
+            z[5] = x[5] ^ y[5];
+            z[6] = x[6] ^ y[6];
+        }
+
+        public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+        {
+            for (int i = 0; i < 13; ++i)
+            {
+                zz[i] = xx[i] ^ yy[i]; 
+            }
+        }
+
+        public static void AddOne(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0] ^ 1UL;
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+            z[4] = x[4];
+            z[5] = x[5];
+            z[6] = x[6];
+        }
+
+        public static ulong[] FromBigInteger(BigInteger x)
+        {
+            ulong[] z = Nat448.FromBigInteger64(x);
+            Reduce39(z, 0);
+            return z;
+        }
+
+        public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+        {
+            ulong[] tt = Nat448.CreateExt64();
+            ImplMultiply(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            ulong[] tt = Nat448.CreateExt64();
+            ImplMultiply(x, y, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void Reduce(ulong[] xx, ulong[] z)
+        {
+            ulong x00 = xx[0], x01 = xx[1], x02 = xx[2], x03 = xx[3];
+            ulong x04 = xx[4], x05 = xx[5], x06 = xx[6], x07 = xx[7];
+
+            ulong u = xx[12];
+            x05 ^= (u << 39);
+            x06 ^= (u >> 25) ^ (u << 62);
+            x07 ^= (u >>  2);
+
+            u = xx[11];
+            x04 ^= (u << 39);
+            x05 ^= (u >> 25) ^ (u << 62);
+            x06 ^= (u >>  2);
+
+            u = xx[10];
+            x03 ^= (u << 39);
+            x04 ^= (u >> 25) ^ (u << 62);
+            x05 ^= (u >>  2);
+
+            u = xx[9];
+            x02 ^= (u << 39);
+            x03 ^= (u >> 25) ^ (u << 62);
+            x04 ^= (u >>  2);
+
+            u = xx[8];
+            x01 ^= (u << 39);
+            x02 ^= (u >> 25) ^ (u << 62);
+            x03 ^= (u >>  2);
+
+            u = x07;
+            x00 ^= (u << 39);
+            x01 ^= (u >> 25) ^ (u << 62);
+            x02 ^= (u >>  2);
+
+            ulong t = x06 >> 25;
+            z[0]    = x00 ^ t;
+            z[1]    = x01 ^ (t << 23);
+            z[2]    = x02;
+            z[3]    = x03;
+            z[4]    = x04;
+            z[5]    = x05;
+            z[6]    = x06 & M25;
+        }
+
+        public static void Reduce39(ulong[] z, int zOff)
+        {
+            ulong z6 = z[zOff + 6], t = z6 >> 25;
+            z[zOff    ] ^= t; 
+            z[zOff + 1] ^= (t << 23);
+            z[zOff + 6]  = z6 & M25;
+        }
+
+        public static void Square(ulong[] x, ulong[] z)
+        {
+            ulong[] tt = Nat.Create64(13);
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareAddToExt(ulong[] x, ulong[] zz)
+        {
+            ulong[] tt = Nat.Create64(13);
+            ImplSquare(x, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void SquareN(ulong[] x, int n, ulong[] z)
+        {
+            Debug.Assert(n > 0);
+
+            ulong[] tt = Nat.Create64(13);
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                ImplSquare(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        protected static void ImplCompactExt(ulong[] zz)
+        {
+            ulong z00 = zz[ 0], z01 = zz[ 1], z02 = zz[ 2], z03 = zz[ 3], z04 = zz[ 4], z05 = zz[ 5], z06 = zz[ 6];
+            ulong z07 = zz[ 7], z08 = zz[ 8], z09 = zz[ 9], z10 = zz[10], z11 = zz[11], z12 = zz[12], z13 = zz[13];
+            zz[ 0] =  z00        ^ (z01 << 59);
+            zz[ 1] = (z01 >>  5) ^ (z02 << 54);
+            zz[ 2] = (z02 >> 10) ^ (z03 << 49);
+            zz[ 3] = (z03 >> 15) ^ (z04 << 44);
+            zz[ 4] = (z04 >> 20) ^ (z05 << 39);
+            zz[ 5] = (z05 >> 25) ^ (z06 << 34);
+            zz[ 6] = (z06 >> 30) ^ (z07 << 29);
+            zz[ 7] = (z07 >> 35) ^ (z08 << 24);
+            zz[ 8] = (z08 >> 40) ^ (z09 << 19);
+            zz[ 9] = (z09 >> 45) ^ (z10 << 14);
+            zz[10] = (z10 >> 50) ^ (z11 <<  9);
+            zz[11] = (z11 >> 55) ^ (z12 <<  4)
+                                 ^ (z13 << 63);
+            zz[12] = (z12 >> 60)
+                   ^ (z13 >> 1);
+            zz[13] = 0;
+        }
+
+        protected static void ImplExpand(ulong[] x, ulong[] z)
+        {
+            ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6];
+            z[0] = x0 & M59;
+            z[1] = ((x0 >> 59) ^ (x1 <<  5)) & M59;
+            z[2] = ((x1 >> 54) ^ (x2 << 10)) & M59;
+            z[3] = ((x2 >> 49) ^ (x3 << 15)) & M59;
+            z[4] = ((x3 >> 44) ^ (x4 << 20)) & M59;
+            z[5] = ((x4 >> 39) ^ (x5 << 25)) & M59;
+            z[6] = ((x5 >> 34) ^ (x6 << 30));
+        }
+
+        protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            ulong[] a = new ulong[7], b = new ulong[7];
+            ImplExpand(x, a);
+            ImplExpand(y, b);
+
+            for (int i = 0; i < 7; ++i)
+            {
+                ImplMulwAcc(a, b[i], zz, i);
+            }
+
+            ImplCompactExt(zz);
+        }
+
+        protected static void ImplMulwAcc(ulong[] xs, ulong y, ulong[] z, int zOff)
+        {
+            Debug.Assert(y >> 59 == 0);
+
+            ulong[] u = new ulong[8];
+    //      u[0] = 0;
+            u[1] = y;
+            u[2] = u[1] << 1;
+            u[3] = u[2] ^  y;
+            u[4] = u[2] << 1;
+            u[5] = u[4] ^  y;
+            u[6] = u[3] << 1;
+            u[7] = u[6] ^  y;
+
+            for (int i = 0; i < 7; ++i)
+            {
+                ulong x = xs[i];
+
+                Debug.Assert(x >> 59 == 0);
+
+                uint j = (uint)x;
+                ulong g, h = 0, l = u[j & 7]
+                                  ^ (u[(j >> 3) & 7] << 3);
+                int k = 54;
+                do
+                {
+                    j  = (uint)(x >> k);
+                    g  = u[j & 7]
+                       ^ u[(j >> 3) & 7] << 3;
+                    l ^= (g <<  k);
+                    h ^= (g >> -k);
+                }
+                while ((k -= 6) > 0);
+
+                Debug.Assert(h >> 53 == 0);
+
+                z[zOff + i    ] ^= l & M59;
+                z[zOff + i + 1] ^= (l >> 59) ^ (h << 5);
+            }
+        }
+
+        protected static void ImplSquare(ulong[] x, ulong[] zz)
+        {
+            for (int i = 0; i < 6; ++i)
+            {
+                Interleave.Expand64To128(x[i], zz, i << 1);
+            }
+            zz[12] = Interleave.Expand32to64((uint)x[6]);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
new file mode 100644
index 000000000..6dabf6a7a
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
@@ -0,0 +1,213 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT409FieldElement
+        : ECFieldElement
+    {
+        protected ulong[] x;
+
+        public SecT409FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0)
+                throw new ArgumentException("value invalid for SecT409FieldElement", "x");
+
+            this.x = SecT409Field.FromBigInteger(x);
+        }
+
+        public SecT409FieldElement()
+        {
+            this.x = Nat448.Create64();
+        }
+
+        protected internal SecT409FieldElement(ulong[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat448.IsOne64(x); }
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat448.IsZero64(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return (x[0] & 1UL) != 0UL;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat448.ToBigInteger64(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecT409Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 409; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            ulong[] z = Nat448.Create64();
+            SecT409Field.Add(x, ((SecT409FieldElement)b).x, z);
+            return new SecT409FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            ulong[] z = Nat448.Create64();
+            SecT409Field.AddOne(x, z);
+            return new SecT409FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            // Addition and subtraction are the same in F2m
+            return Add(b);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            ulong[] z = Nat448.Create64();
+            SecT409Field.Multiply(x, ((SecT409FieldElement)b).x, z);
+            return new SecT409FieldElement(z);
+        }
+
+        public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            return MultiplyPlusProduct(b, x, y);
+        }
+
+        public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x, bx = ((SecT409FieldElement)b).x;
+            ulong[] xx = ((SecT409FieldElement)x).x, yx = ((SecT409FieldElement)y).x;
+
+            ulong[] tt = Nat.Create64(13);
+            SecT409Field.MultiplyAddToExt(ax, bx, tt);
+            SecT409Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat448.Create64();
+            SecT409Field.Reduce(tt, z);
+            return new SecT409FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            return Multiply(b.Invert());
+        }
+
+        public override ECFieldElement Negate()
+        {
+            return this;
+        }
+
+        public override ECFieldElement Square()
+        {
+            ulong[] z = Nat448.Create64();
+            SecT409Field.Square(x, z);
+            return new SecT409FieldElement(z);
+        }
+
+        public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            return SquarePlusProduct(x, y);
+        }
+
+        public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x;
+            ulong[] xx = ((SecT409FieldElement)x).x, yx = ((SecT409FieldElement)y).x;
+
+            ulong[] tt = Nat.Create64(13);
+            SecT409Field.SquareAddToExt(ax, tt);
+            SecT409Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat448.Create64();
+            SecT409Field.Reduce(tt, z);
+            return new SecT409FieldElement(z);
+        }
+
+        public override ECFieldElement SquarePow(int pow)
+        {
+            if (pow < 1)
+                return this;
+
+            ulong[] z = Nat448.Create64();
+            SecT409Field.SquareN(x, pow, z);
+            return new SecT409FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            return new SecT409FieldElement(
+                AbstractF2mCurve.Inverse(409, new int[] { 87 }, ToBigInteger()));
+        }
+
+        public override ECFieldElement Sqrt()
+        {
+            return SquarePow(M - 1);
+        }
+
+        public virtual int Representation
+        {
+            get { return F2mFieldElement.Tpb; }
+        }
+
+        public virtual int M
+        {
+            get { return 409; }
+        }
+
+        public virtual int K1
+        {
+            get { return 87; }
+        }
+
+        public virtual int K2
+        {
+            get { return 0; }
+        }
+
+        public virtual int K3
+        {
+            get { return 0; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecT409FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecT409FieldElement);
+        }
+
+        public virtual bool Equals(SecT409FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat448.Eq64(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return 4090087 ^ Arrays.GetHashCode(x, 0, 7);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
new file mode 100644
index 000000000..edfe1a293
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
@@ -0,0 +1,194 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT409K1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT409K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT409K1Point m_infinity;
+
+        public SecT409K1Curve()
+            : base(409, 87, 0, 0)
+        {
+            this.m_infinity = new SecT409K1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.Zero);
+            this.m_b = FromBigInteger(BigInteger.One);
+            this.m_order = new BigInteger(1, Hex.Decode("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF"));
+            this.m_cofactor = BigInteger.ValueOf(4);
+
+            this.m_coord = SecT409K1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT409K1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        protected override ECMultiplier CreateDefaultMultiplier()
+        {
+            return new WTauNafMultiplier();
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 409; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT409FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT409K1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT409K1Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return true; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+                return beta;
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(409, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 409; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 409; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return true; }
+        }
+
+        public virtual int K1
+        {
+            get { return 87; }
+        }
+
+        public virtual int K2
+        {
+            get { return 0; }
+        }
+
+        public virtual int K3
+        {
+            get { return 0; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT409K1Point.cs b/crypto/src/math/ec/custom/sec/SecT409K1Point.cs
new file mode 100644
index 000000000..71adc7af2
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409K1Point.cs
@@ -0,0 +1,296 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT409K1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT409K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                X3 = L.Square().Add(L).Add(X1);
+                if (X3.IsZero)
+                {
+                    //return new SecT409K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT409K1Point(curve, X3, curve.B, IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    //return new SecT409K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT409K1Point(curve, X3, curve.B, IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT409K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement T;
+            if (Z1IsOne)
+            {
+                T = L1.Square().Add(L1);
+            }
+            else
+            {
+                T = L1.Add(Z1).Multiply(L1);
+            }
+
+            if (T.IsZero)
+            {
+                //return new SecT409K1Point(curve, T, curve.B.sqrt(), withCompression);
+                return new SecT409K1Point(curve, T, curve.B, IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement t1 = L1.Add(X1).Square();
+            ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+            ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+            return new SecT409K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            // NOTE: TwicePlus() only optimized for lambda-affine argument
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement T = L1Sq.Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                //return new SecT409K1Point(curve, A, curve.B.sqrt(), withCompression);
+                return new SecT409K1Point(curve, A, curve.B, IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT409K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT409K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
new file mode 100644
index 000000000..e679094ad
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
@@ -0,0 +1,188 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT409R1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT409R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT409R1Point m_infinity;
+
+        public SecT409R1Curve()
+            : base(409, 87, 0, 0)
+        {
+            this.m_infinity = new SecT409R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.One);
+            this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F")));
+            this.m_order = new BigInteger(1, Hex.Decode("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173"));
+            this.m_cofactor = BigInteger.Two;
+
+            this.m_coord = SecT409R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT409R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 409; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT409FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT409R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT409R1Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return false; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+                return beta;
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(409, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 409; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 409; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return true; }
+        }
+
+        public virtual int K1
+        {
+            get { return 87; }
+        }
+
+        public virtual int K2
+        {
+            get { return 0; }
+        }
+
+        public virtual int K3
+        {
+            get { return 0; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT409R1Point.cs b/crypto/src/math/ec/custom/sec/SecT409R1Point.cs
new file mode 100644
index 000000000..af69fe656
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT409R1Point.cs
@@ -0,0 +1,282 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT409R1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT409R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                X3 = L.Square().Add(L).Add(X1).AddOne();
+                if (X3.IsZero)
+                {
+                    return new SecT409R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    return new SecT409R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT409R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+            if (T.IsZero)
+            {
+                return new SecT409R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+            ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+            return new SecT409R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                return new SecT409R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT409R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT409R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT571Field.cs b/crypto/src/math/ec/custom/sec/SecT571Field.cs
new file mode 100644
index 000000000..0711ee4aa
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571Field.cs
@@ -0,0 +1,251 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT571Field
+    {
+        private const ulong M59 = ulong.MaxValue >> 5;
+
+        private const ulong RM = 0xEF7BDEF7BDEF7BDEUL;
+
+        public static void Add(ulong[] x, ulong[] y, ulong[] z)
+        {
+            for (int i = 0; i < 9; ++i)
+            {
+                z[i] = x[i] ^ y[i]; 
+            }
+        }
+
+        private static void Add(ulong[] x, int xOff, ulong[] y, int yOff, ulong[] z, int zOff)
+        {
+            for (int i = 0; i < 9; ++i)
+            {
+                z[zOff + i] = x[xOff + i] ^ y[yOff + i];
+            }
+        }
+
+        private static void AddBothTo(ulong[] x, int xOff, ulong[] y, int yOff, ulong[] z, int zOff)
+        {
+            for (int i = 0; i < 9; ++i)
+            {
+                z[zOff + i] ^= x[xOff + i] ^ y[yOff + i];
+            }
+        }
+
+        public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+        {
+            for (int i = 0; i < 18; ++i)
+            {
+                zz[i] = xx[i] ^ yy[i]; 
+            }
+        }
+
+        public static void AddOne(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0] ^ 1UL;
+            for (int i = 1; i < 9; ++i)
+            {
+                z[i] = x[i];
+            }
+        }
+
+        public static ulong[] FromBigInteger(BigInteger x)
+        {
+            ulong[] z = Nat576.FromBigInteger64(x);
+            Reduce5(z, 0);
+            return z;
+        }
+
+        public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+        {
+            ulong[] tt = Nat576.CreateExt64();
+            ImplMultiply(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            ulong[] tt = Nat576.CreateExt64();
+            ImplMultiply(x, y, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void Reduce(ulong[] xx, ulong[] z)
+        {
+            ulong xx09 = xx[9];
+            ulong u = xx[17], v = xx09;
+
+            xx09  = v ^ (u >> 59) ^ (u >> 57) ^ (u >> 54) ^ (u >> 49);
+            v = xx[8] ^ (u <<  5) ^ (u <<  7) ^ (u << 10) ^ (u << 15);
+
+            for (int i = 16; i >= 10; --i)
+            {
+                u = xx[i];
+                z[i - 8]  = v ^ (u >> 59) ^ (u >> 57) ^ (u >> 54) ^ (u >> 49);
+                v = xx[i - 9] ^ (u <<  5) ^ (u <<  7) ^ (u << 10) ^ (u << 15);
+            }
+
+            u = xx09;
+            z[1]  = v ^ (u >> 59) ^ (u >> 57) ^ (u >> 54) ^ (u >> 49);
+            v = xx[0] ^ (u <<  5) ^ (u <<  7) ^ (u << 10) ^ (u << 15);
+
+            ulong x08 = z[8];
+            ulong t   = x08 >> 59;
+            z[0]      = v ^ t ^ (t << 2) ^ (t << 5) ^ (t << 10);
+            z[8]      = x08 & M59;
+        }
+
+        public static void Reduce5(ulong[] z, int zOff)
+        {
+            ulong z8     = z[zOff + 8], t = z8 >> 59;
+            z[zOff    ] ^= t ^ (t << 2) ^ (t << 5) ^ (t << 10);
+            z[zOff + 8]  = z8 & M59;
+        }
+
+        public static void Square(ulong[] x, ulong[] z)
+        {
+            ulong[] tt = Nat576.CreateExt64();
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareAddToExt(ulong[] x, ulong[] zz)
+        {
+            ulong[] tt = Nat576.CreateExt64();
+            ImplSquare(x, tt);
+            AddExt(zz, tt, zz);
+        }
+
+        public static void SquareN(ulong[] x, int n, ulong[] z)
+        {
+            Debug.Assert(n > 0);
+
+            ulong[] tt = Nat576.CreateExt64();
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                ImplSquare(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+        {
+            //for (int i = 0; i < 9; ++i)
+            //{
+            //    ImplMulwAcc(x, y[i], zz, i);
+            //}
+
+            /*
+             * Precompute table of all 4-bit products of y
+             */
+            ulong[] T0 = new ulong[9 << 4];
+            Array.Copy(y, 0, T0, 9, 9);
+    //        Reduce5(T0, 9);
+            int tOff = 0;
+            for (int i = 7; i > 0; --i)
+            {
+                tOff += 18;
+                Nat.ShiftUpBit64(9, T0, tOff >> 1, 0UL, T0, tOff);
+                Reduce5(T0, tOff);
+                Add(T0, 9, T0, tOff, T0, tOff + 9);
+            }
+
+            /*
+             * Second table with all 4-bit products of B shifted 4 bits
+             */
+            ulong[] T1 = new ulong[T0.Length];
+            Nat.ShiftUpBits64(T0.Length, T0, 0, 4, 0L, T1, 0);
+
+            uint MASK = 0xF;
+
+            /*
+             * Lopez-Dahab algorithm
+             */
+
+            for (int k = 56; k >= 0; k -= 8)
+            {
+                for (int j = 1; j < 9; j += 2)
+                {
+                    uint aVal = (uint)(x[j] >> k);
+                    uint u = aVal & MASK;
+                    uint v = (aVal >> 4) & MASK;
+                    AddBothTo(T0, (int)(9 * u), T1, (int)(9 * v), zz, j - 1);
+                }
+                Nat.ShiftUpBits64(16, zz, 0, 8, 0L);
+            }
+
+            for (int k = 56; k >= 0; k -= 8)
+            {
+                for (int j = 0; j < 9; j += 2)
+                {
+                    uint aVal = (uint)(x[j] >> k);
+                    uint u = aVal & MASK;
+                    uint v = (aVal >> 4) & MASK;
+                    AddBothTo(T0, (int)(9 * u), T1, (int)(9 * v), zz, j);
+                }
+                if (k > 0)
+                {
+                    Nat.ShiftUpBits64(18, zz, 0, 8, 0L);
+                }
+            }
+        }
+
+        protected static void ImplMulwAcc(ulong[] xs, ulong y, ulong[] z, int zOff)
+        {
+            ulong[] u = new ulong[32];
+    //      u[0] = 0;
+            u[1] = y;
+            for (int i = 2; i < 32; i += 2)
+            {
+                u[i    ] = u[i >> 1] << 1;
+                u[i + 1] = u[i     ] ^  y;
+            }
+
+            ulong l = 0;
+            for (int i = 0; i < 9; ++i)
+            {
+                ulong x = xs[i];
+
+                uint j = (uint)x;
+
+                l ^= u[j & 31];
+
+                ulong g, h = 0;
+                int k = 60;
+                do
+                {
+                    j  = (uint)(x >> k);
+                    g  = u[j & 31];
+                    l ^= (g <<  k);
+                    h ^= (g >> -k);
+                }
+                while ((k -= 5) > 0);
+
+                for (int p = 0; p < 4; ++p)
+                {
+                    x = (x & RM) >> 1;
+                    h ^= x & (ulong)(((long)y << p) >> 63);
+                }
+
+                z[zOff + i] ^= l;
+
+                l = h;
+            }
+            z[zOff + 9] ^= l;
+        }
+
+        protected static void ImplSquare(ulong[] x, ulong[] zz)
+        {
+            for (int i = 0; i < 9; ++i)
+            {
+                Interleave.Expand64To128(x[i], zz, i << 1);
+            }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
new file mode 100644
index 000000000..8474c912e
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
@@ -0,0 +1,213 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT571FieldElement
+        : ECFieldElement
+    {
+        protected readonly ulong[] x;
+
+        public SecT571FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0)
+                throw new ArgumentException("value invalid for SecT571FieldElement", "x");
+
+            this.x = SecT571Field.FromBigInteger(x);
+        }
+
+        public SecT571FieldElement()
+        {
+            this.x = Nat576.Create64();
+        }
+
+        protected internal SecT571FieldElement(ulong[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat576.IsOne64(x); }
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat576.IsZero64(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return (x[0] & 1UL) != 0UL;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat576.ToBigInteger64(x);
+        }
+
+        public override String FieldName
+        {
+            get { return "SecT571Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 571; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            ulong[] z = Nat576.Create64();
+            SecT571Field.Add(x, ((SecT571FieldElement)b).x, z);
+            return new SecT571FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            ulong[] z = Nat576.Create64();
+            SecT571Field.AddOne(x, z);
+            return new SecT571FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            // Addition and subtraction are the same in F2m
+            return Add(b);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            ulong[] z = Nat576.Create64();
+            SecT571Field.Multiply(x, ((SecT571FieldElement)b).x, z);
+            return new SecT571FieldElement(z);
+        }
+
+        public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            return MultiplyPlusProduct(b, x, y);
+        }
+
+        public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x, bx = ((SecT571FieldElement)b).x;
+            ulong[] xx = ((SecT571FieldElement)x).x, yx = ((SecT571FieldElement)y).x;
+
+            ulong[] tt = Nat576.CreateExt64();
+            SecT571Field.MultiplyAddToExt(ax, bx, tt);
+            SecT571Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat576.Create64();
+            SecT571Field.Reduce(tt, z);
+            return new SecT571FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            return Multiply(b.Invert());
+        }
+
+        public override ECFieldElement Negate()
+        {
+            return this;
+        }
+
+        public override ECFieldElement Square()
+        {
+            ulong[] z = Nat576.Create64();
+            SecT571Field.Square(x, z);
+            return new SecT571FieldElement(z);
+        }
+
+        public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            return SquarePlusProduct(x, y);
+        }
+
+        public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            ulong[] ax = this.x;
+            ulong[] xx = ((SecT571FieldElement)x).x, yx = ((SecT571FieldElement)y).x;
+
+            ulong[] tt = Nat576.CreateExt64();
+            SecT571Field.SquareAddToExt(ax, tt);
+            SecT571Field.MultiplyAddToExt(xx, yx, tt);
+
+            ulong[] z = Nat576.Create64();
+            SecT571Field.Reduce(tt, z);
+            return new SecT571FieldElement(z);
+        }
+
+        public override ECFieldElement SquarePow(int pow)
+        {
+            if (pow < 1)
+                return this;
+
+            ulong[] z = Nat576.Create64();
+            SecT571Field.SquareN(x, pow, z);
+            return new SecT571FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            return new SecT571FieldElement(
+                AbstractF2mCurve.Inverse(571, new int[] { 2, 5, 10 }, ToBigInteger()));
+        }
+
+        public override ECFieldElement Sqrt()
+        {
+            return SquarePow(M - 1);
+        }
+
+        public virtual int Representation
+        {
+            get { return F2mFieldElement.Ppb; }
+        }
+
+        public virtual int M
+        {
+            get { return 571; }
+        }
+
+        public virtual int K1
+        {
+            get { return 2; }
+        }
+
+        public virtual int K2
+        {
+            get { return 5; }
+        }
+
+        public virtual int K3
+        {
+            get { return 10; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecT571FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecT571FieldElement);
+        }
+
+        public virtual bool Equals(SecT571FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat576.Eq64(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return 5711052 ^ Arrays.GetHashCode(x, 0, 9);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
new file mode 100644
index 000000000..fb136c967
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
@@ -0,0 +1,196 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT571K1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT571K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT571K1Point m_infinity;
+
+        public SecT571K1Curve()
+            : base(571, 2, 5, 10)
+        {
+            this.m_infinity = new SecT571K1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.Zero);
+            this.m_b = FromBigInteger(BigInteger.One);
+            this.m_order = new BigInteger(1, Hex.Decode("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001"));
+            this.m_cofactor = BigInteger.ValueOf(4);
+
+            this.m_coord = SecT571K1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT571K1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        protected override ECMultiplier CreateDefaultMultiplier()
+        {
+            return new WTauNafMultiplier();
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 571; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT571FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT571K1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT571K1Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return true; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+                y = B.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+            {
+                return beta;
+            }
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(571, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 571; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 571; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return false; }
+        }
+
+        public virtual int K1
+        {
+            get { return 2; }
+        }
+
+        public virtual int K2
+        {
+            get { return 5; }
+        }
+
+        public virtual int K3
+        {
+            get { return 10; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT571K1Point.cs b/crypto/src/math/ec/custom/sec/SecT571K1Point.cs
new file mode 100644
index 000000000..62ed7bda0
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571K1Point.cs
@@ -0,0 +1,296 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT571K1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT571K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                X3 = L.Square().Add(L).Add(X1).AddOne();
+                if (X3.IsZero)
+                {
+                    //return new SecT571K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT571K1Point(curve, X3, curve.B, IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    //return new SecT571K1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT571K1Point(curve, X3, curve.B, IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT571K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement T;
+            if (Z1IsOne)
+            {
+                T = L1.Square().Add(L1);
+            }
+            else
+            {
+                T = L1.Add(Z1).Multiply(L1);
+            }
+
+            if (T.IsZero)
+            {
+                //return new SecT571K1Point(curve, T, curve.B.sqrt(), withCompression);
+                return new SecT571K1Point(curve, T, curve.B, IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement t1 = L1.Add(X1).Square();
+            ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+            ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+            return new SecT571K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            // NOTE: TwicePlus() only optimized for lambda-affine argument
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement T = L1Sq.Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                //return new SecT571K1Point(curve, A, curve.B.sqrt(), withCompression);
+                return new SecT571K1Point(curve, A, curve.B, IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT571K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT571K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
new file mode 100644
index 000000000..05d58863e
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
@@ -0,0 +1,193 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT571R1Curve
+        : AbstractF2mCurve
+    {
+        private const int SecT571R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+        protected readonly SecT571R1Point m_infinity;
+
+        internal static readonly SecT571FieldElement SecT571R1_B = new SecT571FieldElement(
+            new BigInteger(1, Hex.Decode("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A")));
+        internal static readonly SecT571FieldElement SecT571R1_B_SQRT = (SecT571FieldElement)SecT571R1_B.Sqrt();
+
+        public SecT571R1Curve()
+            : base(571, 2, 5, 10)
+        {
+            this.m_infinity = new SecT571R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.One);
+            this.m_b = SecT571R1_B;
+            this.m_order = new BigInteger(1, Hex.Decode("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47"));
+            this.m_cofactor = BigInteger.Two;
+
+            this.m_coord = SecT571R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecT571R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_LAMBDA_PROJECTIVE:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return 571; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecT571FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecT571R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecT571R1Point(this, x, y, zs, withCompression);
+        }
+
+        public override bool IsKoblitz
+        {
+            get { return false; }
+        }
+
+        /**
+         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+         * 
+         * @param yTilde
+         *            ~yp, an indication bit for the decompression of yp.
+         * @param X1
+         *            The field element xp.
+         * @return the decompressed point.
+         */
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1), y = null;
+            if (x.IsZero)
+            {
+    //            y = B.Sqrt();
+                y = SecT571R1_B_SQRT;
+            }
+            else
+            {
+                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
+                ECFieldElement z = SolveQuadraticEquation(beta);
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                    case COORD_LAMBDA_AFFINE:
+                    case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        y = z.Add(x);
+                        break;
+                    }
+                    default:
+                    {
+                        y = z.Multiply(x);
+                        break;
+                    }
+                    }
+                }
+            }
+
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return this.CreateRawPoint(x, y, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         * 
+         * @param beta
+         *            The value to solve the quadratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+                return beta;
+
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
+
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
+
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(571, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < 571; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                    return null;
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
+        }
+
+        public virtual int M
+        {
+            get { return 571; }
+        }
+
+        public virtual bool IsTrinomial
+        {
+            get { return false; }
+        }
+
+        public virtual int K1
+        {
+            get { return 2; }
+        }
+
+        public virtual int K2
+        {
+            get { return 5; }
+        }
+
+        public virtual int K3
+        {
+            get { return 10; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecT571R1Point.cs b/crypto/src/math/ec/custom/sec/SecT571R1Point.cs
new file mode 100644
index 000000000..0cbc98cf3
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecT571R1Point.cs
@@ -0,0 +1,286 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecT571R1Point
+        : AbstractF2mPoint
+    {
+        /**
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecT571R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                if (this.IsInfinity || X.IsZero)
+                    return L;
+
+                // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                ECFieldElement Y = L.Add(X).Multiply(X);
+
+                ECFieldElement Z = RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    Y = Y.Divide(Z);
+                }
+
+                return Y;
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                    return false;
+
+                ECFieldElement Y = this.RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                return Y.TestBitZero() != X.TestBitZero();
+            }
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            if (X1.IsZero)
+            {
+                if (X2.IsZero)
+                    return curve.Infinity;
+
+                return b.Add(this);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement U2 = X2, S2 = L2;
+            if (!Z1IsOne)
+            {
+                U2 = U2.Multiply(Z1);
+                S2 = S2.Multiply(Z1);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            ECFieldElement U1 = X1, S1 = L1;
+            if (!Z2IsOne)
+            {
+                U1 = U1.Multiply(Z2);
+                S1 = S1.Multiply(Z2);
+            }
+
+            ECFieldElement A = S1.Add(S2);
+            ECFieldElement B = U1.Add(U2);
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return Twice();
+
+                return curve.Infinity;
+            }
+
+            ECFieldElement X3, L3, Z3;
+            if (X2.IsZero)
+            {
+                // TODO This can probably be optimized quite a bit
+                ECPoint p = this.Normalize();
+                X1 = p.XCoord;
+                ECFieldElement Y1 = p.YCoord;
+
+                ECFieldElement Y2 = L2;
+                ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                //X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                X3 = L.Square().Add(L).Add(X1).AddOne();
+                if (X3.IsZero)
+                {
+                    //return new SecT571R1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT571R1Point(curve, X3, SecT571R1Curve.SecT571R1_B_SQRT, IsCompressed);
+                }
+
+                ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                L3 = Y3.Divide(X3).Add(X3);
+                Z3 = curve.FromBigInteger(BigInteger.One);
+            }
+            else
+            {
+                B = B.Square();
+
+                ECFieldElement AU1 = A.Multiply(U1);
+                ECFieldElement AU2 = A.Multiply(U2);
+
+                X3 = AU1.Multiply(AU2);
+                if (X3.IsZero)
+                {
+                    //return new SecT571R1Point(curve, X3, curve.B.sqrt(), IsCompressed);
+                    return new SecT571R1Point(curve, X3, SecT571R1Curve.SecT571R1_B_SQRT, IsCompressed);
+                }
+
+                ECFieldElement ABZ2 = A.Multiply(B);
+                if (!Z2IsOne)
+                {
+                    ABZ2 = ABZ2.Multiply(Z2);
+                }
+
+                L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                Z3 = ABZ2;
+                if (!Z1IsOne)
+                {
+                    Z3 = Z3.Multiply(Z1);
+                }
+            }
+
+            return new SecT571R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return curve.Infinity;
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+            bool Z1IsOne = Z1.IsOne;
+            ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+            ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+            ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+            if (T.IsZero)
+            {
+                //return new SecT571R1Point(curve, T, curve.B.sqrt(), withCompression);
+                return new SecT571R1Point(curve, T, SecT571R1Curve.SecT571R1_B_SQRT, IsCompressed);
+            }
+
+            ECFieldElement X3 = T.Square();
+            ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+            ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+            ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+            return new SecT571R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own Additive inverse
+                return b;
+            }
+
+            ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+            if (X2.IsZero || !Z2.IsOne)
+            {
+                return Twice().Add(b);
+            }
+
+            ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+            ECFieldElement L2 = b.RawYCoord;
+
+            ECFieldElement X1Sq = X1.Square();
+            ECFieldElement L1Sq = L1.Square();
+            ECFieldElement Z1Sq = Z1.Square();
+            ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+            //ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+            ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+            ECFieldElement L2plus1 = L2.AddOne();
+            //ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+            ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+            ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+            if (B.IsZero)
+            {
+                if (A.IsZero)
+                    return b.Twice();
+
+                return curve.Infinity;
+            }
+
+            if (A.IsZero)
+            {
+                //return new SecT571R1Point(curve, A, curve.B.sqrt(), withCompression);
+                return new SecT571R1Point(curve, A, SecT571R1Curve.SecT571R1_B_SQRT, IsCompressed);
+            }
+
+            ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+            ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+            ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+            return new SecT571R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            // L is actually Lambda (X + Y/X) here
+            ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+            return new SecT571R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs b/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
index dda778eea..1e7ddae91 100644
--- a/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
+++ b/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
@@ -15,23 +15,23 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
         internal static readonly string PRECOMP_NAME = "bc_wtnaf";
 
         /**
-        * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+        * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
         * by <code>k</code> using the reduced <code>&#964;</code>-adic NAF (RTNAF)
         * method.
-        * @param p The F2mPoint to multiply.
+        * @param p The AbstractF2mPoint to multiply.
         * @param k The integer by which to multiply <code>k</code>.
         * @return <code>p</code> multiplied by <code>k</code>.
         */
         protected override ECPoint MultiplyPositive(ECPoint point, BigInteger k)
         {
-            if (!(point is F2mPoint))
-                throw new ArgumentException("Only F2mPoint can be used in WTauNafMultiplier");
-
-            F2mPoint p = (F2mPoint)point;
-            F2mCurve curve = (F2mCurve)p.Curve;
-            int m = curve.M;
-            sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
-            sbyte mu = curve.GetMu();
+            if (!(point is AbstractF2mPoint))
+                throw new ArgumentException("Only AbstractF2mPoint can be used in WTauNafMultiplier");
+
+            AbstractF2mPoint p = (AbstractF2mPoint)point;
+            AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
+            int m = curve.FieldSize;
+            sbyte a = (sbyte)curve.A.ToBigInteger().IntValue;
+            sbyte mu = Tnaf.GetMu(a);
             BigInteger[] s = curve.GetSi();
 
             ZTauElement rho = Tnaf.PartModReduction(k, m, a, s, mu, (sbyte)10);
@@ -40,16 +40,16 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
         }
 
         /**
-        * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+        * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
         * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code> using
         * the <code>&#964;</code>-adic NAF (TNAF) method.
-        * @param p The F2mPoint to multiply.
+        * @param p The AbstractF2mPoint to multiply.
         * @param lambda The element <code>&#955;</code> of
         * <code><b>Z</b>[&#964;]</code> of which to compute the
         * <code>[&#964;]</code>-adic NAF.
         * @return <code>p</code> multiplied by <code>&#955;</code>.
         */
-        private F2mPoint MultiplyWTnaf(F2mPoint p, ZTauElement lambda,
+        private AbstractF2mPoint MultiplyWTnaf(AbstractF2mPoint p, ZTauElement lambda,
             PreCompInfo preCompInfo, sbyte a, sbyte mu)
         {
             ZTauElement[] alpha = (a == 0) ? Tnaf.Alpha0 : Tnaf.Alpha1;
@@ -63,20 +63,20 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
         }
         
         /**
-        * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+        * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
         * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>
         * using the window <code>&#964;</code>-adic NAF (TNAF) method, given the
         * WTNAF of <code>&#955;</code>.
-        * @param p The F2mPoint to multiply.
+        * @param p The AbstractF2mPoint to multiply.
         * @param u The the WTNAF of <code>&#955;</code>..
         * @return <code>&#955; * p</code>
         */
-        private static F2mPoint MultiplyFromWTnaf(F2mPoint p, sbyte[] u, PreCompInfo preCompInfo)
+        private static AbstractF2mPoint MultiplyFromWTnaf(AbstractF2mPoint p, sbyte[] u, PreCompInfo preCompInfo)
         {
-            F2mCurve curve = (F2mCurve)p.Curve;
+            AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
             sbyte a = (sbyte)curve.A.ToBigInteger().IntValue;
 
-            F2mPoint[] pu;
+            AbstractF2mPoint[] pu;
             if ((preCompInfo == null) || !(preCompInfo is WTauNafPreCompInfo))
             {
                 pu = Tnaf.GetPreComp(p, a);
@@ -90,26 +90,35 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
                 pu = ((WTauNafPreCompInfo)preCompInfo).PreComp;
             }
 
+            // TODO Include negations in precomp (optionally) and use from here
+            AbstractF2mPoint[] puNeg = new AbstractF2mPoint[pu.Length];
+            for (int i = 0; i < pu.Length; ++i)
+            {
+                puNeg[i] = (AbstractF2mPoint)pu[i].Negate();
+            }
+
+            
             // q = infinity
-            F2mPoint q = (F2mPoint)curve.Infinity;
+            AbstractF2mPoint q = (AbstractF2mPoint) p.Curve.Infinity;
+
+            int tauCount = 0;
             for (int i = u.Length - 1; i >= 0; i--)
             {
-                q = Tnaf.Tau(q);
-                sbyte ui = u[i];
+                ++tauCount;
+                int ui = u[i];
                 if (ui != 0)
                 {
-                    if (ui > 0)
-                    {
-                        q = q.AddSimple(pu[ui]);
-                    }
-                    else
-                    {
-                        // u[i] < 0
-                        q = q.SubtractSimple(pu[-ui]);
-                    }
+                    q = q.TauPow(tauCount);
+                    tauCount = 0;
+
+                    ECPoint x = ui > 0 ? pu[ui >> 1] : puNeg[(-ui) >> 1];
+                    q = (AbstractF2mPoint)q.Add(x);
                 }
             }
-
+            if (tauCount > 0)
+            {
+                q = q.TauPow(tauCount);
+            }
             return q;
         }
     }
diff --git a/crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs b/crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
index 3c18404c0..72659b3ec 100644
--- a/crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
+++ b/crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
@@ -8,14 +8,14 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
         : PreCompInfo
     {
         /**
-         * Array holding the precomputed <code>F2mPoint</code>s used for the
+         * Array holding the precomputed <code>AbstractF2mPoint</code>s used for the
          * WTNAF multiplication in <code>
          * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
          * WTauNafMultiplier.multiply()}</code>.
          */
-        protected F2mPoint[] m_preComp;
+        protected AbstractF2mPoint[] m_preComp;
 
-        public virtual F2mPoint[] PreComp
+        public virtual AbstractF2mPoint[] PreComp
         {
             get { return m_preComp; }
             set { this.m_preComp = value; }
diff --git a/crypto/src/math/raw/Interleave.cs b/crypto/src/math/raw/Interleave.cs
new file mode 100644
index 000000000..9755c9d6f
--- /dev/null
+++ b/crypto/src/math/raw/Interleave.cs
@@ -0,0 +1,70 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+    internal abstract class Interleave
+    {
+        /*
+         * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits.
+         * In a binary field, this operation is the same as squaring an 8 bit number.
+         */
+        private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[]
+        {
+            0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+            0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+            0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+            0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+            0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+            0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+            0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+            0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+            0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+            0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+            0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+            0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+            0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+            0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+            0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+            0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+            0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+            0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+            0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+            0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+            0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+            0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+            0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+            0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+            0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+            0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+            0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+            0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+            0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+            0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+            0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+            0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
+        };
+
+        internal static uint Expand8to16(uint x)
+        {
+            return INTERLEAVE2_TABLE[x & 0xFF];
+        }
+
+        internal static uint Expand16to32(uint x)
+        {
+            return (uint)(INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >> 8) & 0xFF] << 16);
+        }
+
+        internal static ulong Expand32to64(uint x)
+        {
+            uint r00 = (uint)(INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >> 8) & 0xFF] << 16);
+            uint r32 = (uint)(INTERLEAVE2_TABLE[(x >> 16) & 0xFF] | INTERLEAVE2_TABLE[x >> 24] << 16);
+            return (ulong)r32 << 32 | (ulong)r00;
+        }
+
+        internal static void Expand64To128(ulong x, ulong[] z, int zOff)
+        {
+            z[zOff    ] = Expand32to64((uint)x);
+            z[zOff + 1] = Expand32to64((uint)(x >> 32));
+        }
+    }
+}
diff --git a/crypto/src/math/ec/Mod.cs b/crypto/src/math/raw/Mod.cs
index 80534ca9f..63467e668 100644
--- a/crypto/src/math/ec/Mod.cs
+++ b/crypto/src/math/raw/Mod.cs
@@ -4,7 +4,7 @@ using System.Diagnostics;
 using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 
-namespace Org.BouncyCastle.Math.EC
+namespace Org.BouncyCastle.Math.Raw
 {
     internal abstract class Mod
     {
diff --git a/crypto/src/math/ec/Nat.cs b/crypto/src/math/raw/Nat.cs
index 17b632f26..1f9ab00ec 100644
--- a/crypto/src/math/ec/Nat.cs
+++ b/crypto/src/math/raw/Nat.cs
@@ -3,7 +3,7 @@ using System.Diagnostics;
 
 using Org.BouncyCastle.Crypto.Utilities;
 
-namespace Org.BouncyCastle.Math.EC
+namespace Org.BouncyCastle.Math.Raw
 {
     internal abstract class Nat
     {
@@ -212,6 +212,11 @@ namespace Org.BouncyCastle.Math.EC
             return new uint[len];
         }
 
+        public static ulong[] Create64(int len)
+        {
+            return new ulong[len];
+        }
+
         public static int Dec(int len, uint[] z)
         {
             for (int i = 0; i < len; ++i)
@@ -666,6 +671,17 @@ namespace Org.BouncyCastle.Math.EC
             return c >> 31;
         }
 
+        public static ulong ShiftUpBit64(int len, ulong[] x, int xOff, ulong c, ulong[] z, int zOff)
+        {
+            for (int i = 0; i < len; ++i)
+            {
+                ulong next = x[xOff + i];
+                z[zOff + i] = (next << 1) | (c >> 63);
+                c = next;
+            }
+            return c >> 63;
+        }
+
         public static uint ShiftUpBits(int len, uint[] z, int bits, uint c)
         {
             Debug.Assert(bits > 0 && bits < 32);
@@ -690,6 +706,18 @@ namespace Org.BouncyCastle.Math.EC
             return c >> -bits;
         }
 
+        public static ulong ShiftUpBits64(int len, ulong[] z, int zOff, int bits, ulong c)
+        {
+            Debug.Assert(bits > 0 && bits < 64);
+            for (int i = 0; i < len; ++i)
+            {
+                ulong next = z[zOff + i];
+                z[zOff + i] = (next << bits) | (c >> -bits);
+                c = next;
+            }
+            return c >> -bits;
+        }
+
         public static uint ShiftUpBits(int len, uint[] x, int bits, uint c, uint[] z)
         {
             Debug.Assert(bits > 0 && bits < 32);
@@ -714,6 +742,18 @@ namespace Org.BouncyCastle.Math.EC
             return c >> -bits;
         }
 
+        public static ulong ShiftUpBits64(int len, ulong[] x, int xOff, int bits, ulong c, ulong[] z, int zOff)
+        {
+            Debug.Assert(bits > 0 && bits < 64);
+            for (int i = 0; i < len; ++i)
+            {
+                ulong next = x[xOff + i];
+                z[zOff + i] = (next << bits) | (c >> -bits);
+                c = next;
+            }
+            return c >> -bits;
+        }
+
         public static void Square(int len, uint[] x, uint[] zz)
         {
             int extLen = len << 1;
diff --git a/crypto/src/math/raw/Nat128.cs b/crypto/src/math/raw/Nat128.cs
new file mode 100644
index 000000000..819c52062
--- /dev/null
+++ b/crypto/src/math/raw/Nat128.cs
@@ -0,0 +1,856 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+    internal abstract class Nat128
+    {
+        private const ulong M = 0xFFFFFFFFUL;
+
+        public static uint Add(uint[] x, uint[] y, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddBothTo(uint[] x, uint[] y, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + y[0] + z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + y[1] + z[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + y[2] + z[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + y[3] + z[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddTo(uint[] x, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + z[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + z[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + z[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddTo(uint[] x, int xOff, uint[] z, int zOff, uint cIn)
+        {
+            ulong c = cIn;
+            c += (ulong)x[xOff + 0] + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 1] + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 2] + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 3] + z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddToEachOther(uint[] u, int uOff, uint[] v, int vOff)
+        {
+            ulong c = 0;
+            c += (ulong)u[uOff + 0] + v[vOff + 0];
+            u[uOff + 0] = (uint)c;
+            v[vOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 1] + v[vOff + 1];
+            u[uOff + 1] = (uint)c;
+            v[vOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 2] + v[vOff + 2];
+            u[uOff + 2] = (uint)c;
+            v[vOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 3] + v[vOff + 3];
+            u[uOff + 3] = (uint)c;
+            v[vOff + 3] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static void Copy(uint[] x, uint[] z)
+        {
+            z[0] = x[0];
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+        }
+
+        public static void Copy64(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0];
+            z[1] = x[1];
+        }
+
+        public static uint[] Create()
+        {
+            return new uint[4];
+        }
+
+        public static ulong[] Create64()
+        {
+            return new ulong[2];
+        }
+
+        public static uint[] CreateExt()
+        {
+            return new uint[8];
+        }
+
+        public static ulong[] CreateExt64()
+        {
+            return new ulong[4];
+        }
+
+        public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            bool pos = Gte(x, xOff, y, yOff);
+            if (pos)
+            {
+                Sub(x, xOff, y, yOff, z, zOff);
+            }
+            else
+            {
+                Sub(y, yOff, x, xOff, z, zOff);
+            }
+            return pos;
+        }
+
+        public static bool Eq(uint[] x, uint[] y)
+        {
+            for (int i = 3; i >= 0; --i)
+            {
+                if (x[i] != y[i])
+                    return false;
+            }
+            return true;
+        }
+
+        public static bool Eq64(ulong[] x, ulong[] y)
+        {
+            for (int i = 1; i >= 0; --i)
+            {
+                if (x[i] != y[i])
+                    return false;
+            }
+            return true;
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            if (x.SignValue < 0 || x.BitLength > 128)
+                throw new ArgumentException();
+
+            uint[] z = Create();
+            int i = 0;
+            while (x.SignValue != 0)
+            {
+                z[i++] = (uint)x.IntValue;
+                x = x.ShiftRight(32);
+            }
+            return z;
+        }
+
+        public static ulong[] FromBigInteger64(BigInteger x)
+        {
+            if (x.SignValue < 0 || x.BitLength > 128)
+                throw new ArgumentException();
+
+            ulong[] z = Create64();
+            int i = 0;
+            while (x.SignValue != 0)
+            {
+                z[i++] = (ulong)x.LongValue;
+                x = x.ShiftRight(64);
+            }
+            return z;
+        }
+
+        public static uint GetBit(uint[] x, int bit)
+        {
+            if (bit == 0)
+            {
+                return x[0] & 1;
+            }
+            if ((bit & 127) != bit)
+            {
+                return 0;
+            }
+            int w = bit >> 5;
+            int b = bit & 31;
+            return (x[w] >> b) & 1;
+        }
+
+        public static bool Gte(uint[] x, uint[] y)
+        {
+            for (int i = 3; i >= 0; --i)
+            {
+                uint x_i = x[i], y_i = y[i];
+                if (x_i < y_i)
+                    return false;
+                if (x_i > y_i)
+                    return true;
+            }
+            return true;
+        }
+
+        public static bool Gte(uint[] x, int xOff, uint[] y, int yOff)
+        {
+            for (int i = 3; i >= 0; --i)
+            {
+                uint x_i = x[xOff + i], y_i = y[yOff + i];
+                if (x_i < y_i)
+                    return false;
+                if (x_i > y_i)
+                    return true;
+            }
+            return true;
+        }
+
+        public static bool IsOne(uint[] x)
+        {
+            if (x[0] != 1)
+            {
+                return false;
+            }
+            for (int i = 1; i < 4; ++i)
+            {
+                if (x[i] != 0)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static bool IsOne64(ulong[] x)
+        {
+            if (x[0] != 1UL)
+            {
+                return false;
+            }
+            for (int i = 1; i < 2; ++i)
+            {
+                if (x[i] != 0UL)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static bool IsZero(uint[] x)
+        {
+            for (int i = 0; i < 4; ++i)
+            {
+                if (x[i] != 0)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static bool IsZero64(ulong[] x)
+        {
+            for (int i = 0; i < 2; ++i)
+            {
+                if (x[i] != 0UL)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static void Mul(uint[] x, uint[] y, uint[] zz)
+        {
+            ulong y_0 = y[0];
+            ulong y_1 = y[1];
+            ulong y_2 = y[2];
+            ulong y_3 = y[3];
+
+            {
+                ulong c = 0, x_0 = x[0];
+                c += x_0 * y_0;
+                zz[0] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_1;
+                zz[1] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_2;
+                zz[2] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_3;
+                zz[3] = (uint)c;
+                c >>= 32;
+                zz[4] = (uint)c;
+            }
+
+            for (int i = 1; i < 4; ++i)
+            {
+                ulong c = 0, x_i = x[i];
+                c += x_i * y_0 + zz[i + 0];
+                zz[i + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[i + 1];
+                zz[i + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[i + 2];
+                zz[i + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[i + 3];
+                zz[i + 3] = (uint)c;
+                c >>= 32;
+                zz[i + 4] = (uint)c;
+            }
+        }
+
+        public static void Mul(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+        {
+            ulong y_0 = y[yOff + 0];
+            ulong y_1 = y[yOff + 1];
+            ulong y_2 = y[yOff + 2];
+            ulong y_3 = y[yOff + 3];
+
+            {
+                ulong c = 0, x_0 = x[xOff + 0];
+                c += x_0 * y_0;
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_1;
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_2;
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_3;
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                zz[zzOff + 4] = (uint)c;
+            }
+
+            for (int i = 1; i < 4; ++i)
+            {
+                ++zzOff;
+                ulong c = 0, x_i = x[xOff + i];
+                c += x_i * y_0 + zz[zzOff + 0];
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[zzOff + 1];
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[zzOff + 2];
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[zzOff + 3];
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                zz[zzOff + 4] = (uint)c;
+            }
+        }
+
+        public static uint MulAddTo(uint[] x, uint[] y, uint[] zz)
+        {
+            ulong y_0 = y[0];
+            ulong y_1 = y[1];
+            ulong y_2 = y[2];
+            ulong y_3 = y[3];
+
+            ulong zc = 0;
+            for (int i = 0; i < 4; ++i)
+            {
+                ulong c = 0, x_i = x[i];
+                c += x_i * y_0 + zz[i + 0];
+                zz[i + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[i + 1];
+                zz[i + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[i + 2];
+                zz[i + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[i + 3];
+                zz[i + 3] = (uint)c;
+                c >>= 32;
+                c += zc + zz[i + 4];
+                zz[i + 4] = (uint)c;
+                zc = c >> 32;
+            }
+            return (uint)zc;
+        }
+
+        public static uint MulAddTo(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+        {
+            ulong y_0 = y[yOff + 0];
+            ulong y_1 = y[yOff + 1];
+            ulong y_2 = y[yOff + 2];
+            ulong y_3 = y[yOff + 3];
+
+            ulong zc = 0;
+            for (int i = 0; i < 4; ++i)
+            {
+                ulong c = 0, x_i = x[xOff + i];
+                c += x_i * y_0 + zz[zzOff + 0];
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[zzOff + 1];
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[zzOff + 2];
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[zzOff + 3];
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += zc + zz[zzOff + 4];
+                zz[zzOff + 4] = (uint)c;
+                zc = c >> 32;
+                ++zzOff;
+            }
+            return (uint)zc;
+        }
+
+        public static ulong Mul33Add(uint w, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            Debug.Assert(w >> 31 == 0);
+
+            ulong c = 0, wVal = w;
+            ulong x0 = x[xOff + 0];
+            c += wVal * x0 + y[yOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            ulong x1 = x[xOff + 1];
+            c += wVal * x1 + x0 + y[yOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            ulong x2 = x[xOff + 2];
+            c += wVal * x2 + x1 + y[yOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            ulong x3 = x[xOff + 3];
+            c += wVal * x3 + x2 + y[yOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += x3;
+            return c;
+        }
+
+        public static uint MulWordAddExt(uint x, uint[] yy, int yyOff, uint[] zz, int zzOff)
+        {
+            Debug.Assert(yyOff <= 4);
+            Debug.Assert(zzOff <= 4);
+
+            ulong c = 0, xVal = x;
+            c += xVal * yy[yyOff + 0] + zz[zzOff + 0];
+            zz[zzOff + 0] = (uint)c;
+            c >>= 32;
+            c += xVal * yy[yyOff + 1] + zz[zzOff + 1];
+            zz[zzOff + 1] = (uint)c;
+            c >>= 32;
+            c += xVal * yy[yyOff + 2] + zz[zzOff + 2];
+            zz[zzOff + 2] = (uint)c;
+            c >>= 32;
+            c += xVal * yy[yyOff + 3] + zz[zzOff + 3];
+            zz[zzOff + 3] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint Mul33DWordAdd(uint x, ulong y, uint[] z, int zOff)
+        {
+            Debug.Assert(x >> 31 == 0);
+            Debug.Assert(zOff <= 0);
+            ulong c = 0, xVal = x;
+            ulong y00 = y & M;
+            c += xVal * y00 + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            ulong y01 = y >> 32;
+            c += xVal * y01 + y00 + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += y01 + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint Mul33WordAdd(uint x, uint y, uint[] z, int zOff)
+        {
+            Debug.Assert(x >> 31 == 0);
+            Debug.Assert(zOff <= 1);
+            ulong c = 0, yVal = y;
+            c += yVal * x + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += yVal + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(4, z, zOff, 3);
+        }
+
+        public static uint MulWordDwordAdd(uint x, ulong y, uint[] z, int zOff)
+        {
+            Debug.Assert(zOff <= 1);
+            ulong c = 0, xVal = x;
+            c += xVal * y + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += xVal * (y >> 32) + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(4, z, zOff, 3);
+        }
+
+        public static uint MulWordsAdd(uint x, uint y, uint[] z, int zOff)
+        {
+            Debug.Assert(zOff <= 2);
+
+            ulong c = 0, xVal = x, yVal = y;
+            c += yVal * xVal + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(4, z, zOff, 2);
+        }
+
+        public static uint MulWord(uint x, uint[] y, uint[] z, int zOff)
+        {
+            ulong c = 0, xVal = x;
+            int i = 0;
+            do
+            {
+                c += xVal * y[i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            while (++i < 4);
+            return (uint)c;
+        }
+
+        public static void Square(uint[] x, uint[] zz)
+        {
+            ulong x_0 = x[0];
+            ulong zz_1;
+
+            uint c = 0, w;
+            {
+                int i = 3, j = 8;
+                do
+                {
+                    ulong xVal = x[i--];
+                    ulong p = xVal * xVal;
+                    zz[--j] = (c << 31) | (uint)(p >> 33);
+                    zz[--j] = (uint)(p >> 1);
+                    c = (uint)p;
+                }
+                while (i > 0);
+
+                {
+                    ulong p = x_0 * x_0;
+                    zz_1 = (ulong)(c << 31) | (p >> 33);
+                    zz[0] = (uint)p;
+                    c = (uint)(p >> 32) & 1;
+                }
+            }
+
+            ulong x_1 = x[1];
+            ulong zz_2 = zz[2];
+
+            {
+                zz_1 += x_1 * x_0;
+                w = (uint)zz_1;
+                zz[1] = (w << 1) | c;
+                c = w >> 31;
+                zz_2 += zz_1 >> 32;
+            }
+
+            ulong x_2 = x[2];
+            ulong zz_3 = zz[3];
+            ulong zz_4 = zz[4];
+            {
+                zz_2 += x_2 * x_0;
+                w = (uint)zz_2;
+                zz[2] = (w << 1) | c;
+                c = w >> 31;
+                zz_3 += (zz_2 >> 32) + x_2 * x_1;
+                zz_4 += zz_3 >> 32;
+                zz_3 &= M;
+            }
+
+            ulong x_3 = x[3];
+            ulong zz_5 = zz[5];
+            ulong zz_6 = zz[6];
+            {
+                zz_3 += x_3 * x_0;
+                w = (uint)zz_3;
+                zz[3] = (w << 1) | c;
+                c = w >> 31;
+                zz_4 += (zz_3 >> 32) + x_3 * x_1;
+                zz_5 += (zz_4 >> 32) + x_3 * x_2;
+                zz_6 += zz_5 >> 32;
+            }
+
+            w = (uint)zz_4;
+            zz[4] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_5;
+            zz[5] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_6;
+            zz[6] = (w << 1) | c;
+            c = w >> 31;
+            w = zz[7] + (uint)(zz_6 >> 32);
+            zz[7] = (w << 1) | c;
+        }
+
+        public static void Square(uint[] x, int xOff, uint[] zz, int zzOff)
+        {
+            ulong x_0 = x[xOff + 0];
+            ulong zz_1;
+
+            uint c = 0, w;
+            {
+                int i = 3, j = 8;
+                do
+                {
+                    ulong xVal = x[xOff + i--];
+                    ulong p = xVal * xVal;
+                    zz[zzOff + --j] = (c << 31) | (uint)(p >> 33);
+                    zz[zzOff + --j] = (uint)(p >> 1);
+                    c = (uint)p;
+                }
+                while (i > 0);
+
+                {
+                    ulong p = x_0 * x_0;
+                    zz_1 = (ulong)(c << 31) | (p >> 33);
+                    zz[zzOff + 0] = (uint)p;
+                    c = (uint)(p >> 32) & 1;
+                }
+            }
+
+            ulong x_1 = x[xOff + 1];
+            ulong zz_2 = zz[zzOff + 2];
+
+            {
+                zz_1 += x_1 * x_0;
+                w = (uint)zz_1;
+                zz[zzOff + 1] = (w << 1) | c;
+                c = w >> 31;
+                zz_2 += zz_1 >> 32;
+            }
+
+            ulong x_2 = x[xOff + 2];
+            ulong zz_3 = zz[zzOff + 3];
+            ulong zz_4 = zz[zzOff + 4];
+            {
+                zz_2 += x_2 * x_0;
+                w = (uint)zz_2;
+                zz[zzOff + 2] = (w << 1) | c;
+                c = w >> 31;
+                zz_3 += (zz_2 >> 32) + x_2 * x_1;
+                zz_4 += zz_3 >> 32;
+                zz_3 &= M;
+            }
+
+            ulong x_3 = x[xOff + 3];
+            ulong zz_5 = zz[zzOff + 5];
+            ulong zz_6 = zz[zzOff + 6];
+            {
+                zz_3 += x_3 * x_0;
+                w = (uint)zz_3;
+                zz[zzOff + 3] = (w << 1) | c;
+                c = w >> 31;
+                zz_4 += (zz_3 >> 32) + x_3 * x_1;
+                zz_5 += (zz_4 >> 32) + x_3 * x_2;
+                zz_6 += zz_5 >> 32;
+            }
+
+            w = (uint)zz_4;
+            zz[zzOff + 4] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_5;
+            zz[zzOff + 5] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_6;
+            zz[zzOff + 6] = (w << 1) | c;
+            c = w >> 31;
+            w = zz[zzOff + 7] + (uint)(zz_6 >> 32);
+            zz[zzOff + 7] = (w << 1) | c;
+        }
+
+        public static int Sub(uint[] x, uint[] y, uint[] z)
+        {
+            long c = 0;
+            c += (long)x[0] - y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)x[1] - y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)x[2] - y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)x[3] - y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int Sub(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            c += (long)x[xOff + 0] - y[yOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 1] - y[yOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 2] - y[yOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 3] - y[yOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubBothFrom(uint[] x, uint[] y, uint[] z)
+        {
+            long c = 0;
+            c += (long)z[0] - x[0] - y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - x[1] - y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)z[2] - x[2] - y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)z[3] - x[3] - y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubFrom(uint[] x, uint[] z)
+        {
+            long c = 0;
+            c += (long)z[0] - x[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - x[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)z[2] - x[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)z[3] - x[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubFrom(uint[] x, int xOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            c += (long)z[zOff + 0] - x[xOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 1] - x[xOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 2] - x[xOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 3] - x[xOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static BigInteger ToBigInteger(uint[] x)
+        {
+            byte[] bs = new byte[16];
+            for (int i = 0; i < 4; ++i)
+            {
+                uint x_i = x[i];
+                if (x_i != 0)
+                {
+                    Pack.UInt32_To_BE(x_i, bs, (3 - i) << 2);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+
+        public static BigInteger ToBigInteger64(ulong[] x)
+        {
+            byte[] bs = new byte[16];
+            for (int i = 0; i < 2; ++i)
+            {
+                ulong x_i = x[i];
+                if (x_i != 0UL)
+                {
+                    Pack.UInt64_To_BE(x_i, bs, (1 - i) << 3);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+
+        public static void Zero(uint[] z)
+        {
+            z[0] = 0;
+            z[1] = 0;
+            z[2] = 0;
+            z[3] = 0;
+        }
+    }
+}
diff --git a/crypto/src/math/raw/Nat160.cs b/crypto/src/math/raw/Nat160.cs
new file mode 100644
index 000000000..153ac0a43
--- /dev/null
+++ b/crypto/src/math/raw/Nat160.cs
@@ -0,0 +1,874 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+    internal abstract class Nat160
+    {
+        private const ulong M = 0xFFFFFFFFUL;
+
+        public static uint Add(uint[] x, uint[] y, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[4] + y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddBothTo(uint[] x, uint[] y, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + y[0] + z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + y[1] + z[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + y[2] + z[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + y[3] + z[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[4] + y[4] + z[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddTo(uint[] x, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + z[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + z[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + z[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[4] + z[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddTo(uint[] x, int xOff, uint[] z, int zOff, uint cIn)
+        {
+            ulong c = cIn;
+            c += (ulong)x[xOff + 0] + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 1] + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 2] + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 3] + z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 4] + z[zOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 5] + z[zOff + 5];
+            return (uint)c;
+        }
+
+        public static uint AddToEachOther(uint[] u, int uOff, uint[] v, int vOff)
+        {
+            ulong c = 0;
+            c += (ulong)u[uOff + 0] + v[vOff + 0];
+            u[uOff + 0] = (uint)c;
+            v[vOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 1] + v[vOff + 1];
+            u[uOff + 1] = (uint)c;
+            v[vOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 2] + v[vOff + 2];
+            u[uOff + 2] = (uint)c;
+            v[vOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 3] + v[vOff + 3];
+            u[uOff + 3] = (uint)c;
+            v[vOff + 3] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 4] + v[vOff + 4];
+            u[uOff + 4] = (uint)c;
+            v[vOff + 4] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static void Copy(uint[] x, uint[] z)
+        {
+            z[0] = x[0];
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+            z[4] = x[4];
+        }
+
+        public static uint[] Create()
+        {
+            return new uint[5];
+        }
+
+        public static uint[] CreateExt()
+        {
+            return new uint[10];
+        }
+
+        public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            bool pos = Gte(x, xOff, y, yOff);
+            if (pos)
+            {
+                Sub(x, xOff, y, yOff, z, zOff);
+            }
+            else
+            {
+                Sub(y, yOff, x, xOff, z, zOff);
+            }
+            return pos;
+        }
+
+        public static bool Eq(uint[] x, uint[] y)
+        {
+            for (int i = 4; i >= 0; --i)
+            {
+                if (x[i] != y[i])
+                    return false;
+            }
+            return true;
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            if (x.SignValue < 0 || x.BitLength > 160)
+                throw new ArgumentException();
+
+            uint[] z = Create();
+            int i = 0;
+            while (x.SignValue != 0)
+            {
+                z[i++] = (uint)x.IntValue;
+                x = x.ShiftRight(32);
+            }
+            return z;
+        }
+
+        public static uint GetBit(uint[] x, int bit)
+        {
+            if (bit == 0)
+            {
+                return x[0] & 1;
+            }
+            int w = bit >> 5;
+            if (w < 0 || w >= 5)
+            {
+                return 0;
+            }
+            int b = bit & 31;
+            return (x[w] >> b) & 1;
+        }
+
+        public static bool Gte(uint[] x, uint[] y)
+        {
+            for (int i = 4; i >= 0; --i)
+            {
+                uint x_i = x[i], y_i = y[i];
+                if (x_i < y_i)
+                    return false;
+                if (x_i > y_i)
+                    return true;
+            }
+            return true;
+        }
+
+        public static bool Gte(uint[] x, int xOff, uint[] y, int yOff)
+        {
+            for (int i = 4; i >= 0; --i)
+            {
+                uint x_i = x[xOff + i], y_i = y[yOff + i];
+                if (x_i < y_i)
+                    return false;
+                if (x_i > y_i)
+                    return true;
+            }
+            return true;
+        }
+
+        public static bool IsOne(uint[] x)
+        {
+            if (x[0] != 1)
+            {
+                return false;
+            }
+            for (int i = 1; i < 5; ++i)
+            {
+                if (x[i] != 0)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static bool IsZero(uint[] x)
+        {
+            for (int i = 0; i < 5; ++i)
+            {
+                if (x[i] != 0)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static void Mul(uint[] x, uint[] y, uint[] zz)
+        {
+            ulong y_0 = y[0];
+            ulong y_1 = y[1];
+            ulong y_2 = y[2];
+            ulong y_3 = y[3];
+            ulong y_4 = y[4];
+
+            {
+                ulong c = 0, x_0 = x[0];
+                c += x_0 * y_0;
+                zz[0] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_1;
+                zz[1] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_2;
+                zz[2] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_3;
+                zz[3] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_4;
+                zz[4] = (uint)c;
+                c >>= 32;
+                zz[5] = (uint)c;
+            }
+
+            for (int i = 1; i < 5; ++i)
+            {
+                ulong c = 0, x_i = x[i];
+                c += x_i * y_0 + zz[i + 0];
+                zz[i + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[i + 1];
+                zz[i + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[i + 2];
+                zz[i + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[i + 3];
+                zz[i + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[i + 4];
+                zz[i + 4] = (uint)c;
+                c >>= 32;
+                zz[i + 5] = (uint)c;
+            }
+        }
+
+        public static void Mul(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+        {
+            ulong y_0 = y[yOff + 0];
+            ulong y_1 = y[yOff + 1];
+            ulong y_2 = y[yOff + 2];
+            ulong y_3 = y[yOff + 3];
+            ulong y_4 = y[yOff + 4];
+
+            {
+                ulong c = 0, x_0 = x[xOff + 0];
+                c += x_0 * y_0;
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_1;
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_2;
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_3;
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_4;
+                zz[zzOff + 4] = (uint)c;
+                c >>= 32;
+                zz[zzOff + 5] = (uint)c;
+            }
+
+            for (int i = 1; i < 5; ++i)
+            {
+                ++zzOff;
+                ulong c = 0, x_i = x[xOff + i];
+                c += x_i * y_0 + zz[zzOff + 0];
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[zzOff + 1];
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[zzOff + 2];
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[zzOff + 3];
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[zzOff + 4];
+                zz[zzOff + 4] = (uint)c;
+                c >>= 32;
+                zz[zzOff + 5] = (uint)c;
+            }
+        }
+
+        public static uint MulAddTo(uint[] x, uint[] y, uint[] zz)
+        {
+            ulong y_0 = y[0];
+            ulong y_1 = y[1];
+            ulong y_2 = y[2];
+            ulong y_3 = y[3];
+            ulong y_4 = y[4];
+
+            ulong zc = 0;
+            for (int i = 0; i < 5; ++i)
+            {
+                ulong c = 0, x_i = x[i];
+                c += x_i * y_0 + zz[i + 0];
+                zz[i + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[i + 1];
+                zz[i + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[i + 2];
+                zz[i + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[i + 3];
+                zz[i + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[i + 4];
+                zz[i + 4] = (uint)c;
+                c >>= 32;
+                c += zc + zz[i + 5];
+                zz[i + 5] = (uint)c;
+                zc = c >> 32;
+            }
+            return (uint)zc;
+        }
+
+        public static uint MulAddTo(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+        {
+            ulong y_0 = y[yOff + 0];
+            ulong y_1 = y[yOff + 1];
+            ulong y_2 = y[yOff + 2];
+            ulong y_3 = y[yOff + 3];
+            ulong y_4 = y[yOff + 4];
+
+            ulong zc = 0;
+            for (int i = 0; i < 5; ++i)
+            {
+                ulong c = 0, x_i = x[xOff + i];
+                c += x_i * y_0 + zz[zzOff + 0];
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[zzOff + 1];
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[zzOff + 2];
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[zzOff + 3];
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[zzOff + 4];
+                zz[zzOff + 4] = (uint)c;
+                c >>= 32;
+                c += zc + zz[zzOff + 5];
+                zz[zzOff + 5] = (uint)c;
+                zc = c >> 32;
+                ++zzOff;
+            }
+            return (uint)zc;
+        }
+
+        public static ulong Mul33Add(uint w, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            Debug.Assert(w >> 31 == 0);
+
+            ulong c = 0, wVal = w;
+            ulong x0 = x[xOff + 0];
+            c += wVal * x0 + y[yOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            ulong x1 = x[xOff + 1];
+            c += wVal * x1 + x0 + y[yOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            ulong x2 = x[xOff + 2];
+            c += wVal * x2 + x1 + y[yOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            ulong x3 = x[xOff + 3];
+            c += wVal * x3 + x2 + y[yOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            ulong x4 = x[xOff + 4];
+            c += wVal * x4 + x3 + y[yOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += x4;
+            return c;
+        }
+
+        public static uint MulWordAddExt(uint x, uint[] yy, int yyOff, uint[] zz, int zzOff)
+        {
+            Debug.Assert(yyOff <= 5);
+            Debug.Assert(zzOff <= 5);
+
+            ulong c = 0, xVal = x;
+            c += xVal * yy[yyOff + 0] + zz[zzOff + 0];
+            zz[zzOff + 0] = (uint)c;
+            c >>= 32;
+            c += xVal * yy[yyOff + 1] + zz[zzOff + 1];
+            zz[zzOff + 1] = (uint)c;
+            c >>= 32;
+            c += xVal * yy[yyOff + 2] + zz[zzOff + 2];
+            zz[zzOff + 2] = (uint)c;
+            c >>= 32;
+            c += xVal * yy[yyOff + 3] + zz[zzOff + 3];
+            zz[zzOff + 3] = (uint)c;
+            c >>= 32;
+            c += xVal * yy[yyOff + 4] + zz[zzOff + 4];
+            zz[zzOff + 4] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint Mul33DWordAdd(uint x, ulong y, uint[] z, int zOff)
+        {
+            Debug.Assert(x >> 31 == 0);
+            Debug.Assert(zOff <= 1);
+            ulong c = 0, xVal = x;
+            ulong y00 = y & M;
+            c += xVal * y00 + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            ulong y01 = y >> 32;
+            c += xVal * y01 + y00 + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += y01 + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(5, z, zOff, 4);
+        }
+
+        public static uint Mul33WordAdd(uint x, uint y, uint[] z, int zOff)
+        {
+            Debug.Assert(x >> 31 == 0);
+            Debug.Assert(zOff <= 2);
+            ulong c = 0, yVal = y;
+            c += yVal * x + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += yVal + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(5, z, zOff, 3);
+        }
+
+        public static uint MulWordDwordAdd(uint x, ulong y, uint[] z, int zOff)
+        {
+            Debug.Assert(zOff <= 2);
+            ulong c = 0, xVal = x;
+            c += xVal * y + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += xVal * (y >> 32) + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(5, z, zOff, 3);
+        }
+
+        public static uint MulWordsAdd(uint x, uint y, uint[] z, int zOff)
+        {
+            Debug.Assert(zOff <= 3);
+
+            ulong c = 0, xVal = x, yVal = y;
+            c += yVal * xVal + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(5, z, zOff, 2);
+        }
+
+        public static uint MulWord(uint x, uint[] y, uint[] z, int zOff)
+        {
+            ulong c = 0, xVal = x;
+            int i = 0;
+            do
+            {
+                c += xVal * y[i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            while (++i < 5);
+            return (uint)c;
+        }
+
+        public static void Square(uint[] x, uint[] zz)
+        {
+            ulong x_0 = x[0];
+            ulong zz_1;
+
+            uint c = 0, w;
+            {
+                int i = 4, j = 10;
+                do
+                {
+                    ulong xVal = x[i--];
+                    ulong p = xVal * xVal;
+                    zz[--j] = (c << 31) | (uint)(p >> 33);
+                    zz[--j] = (uint)(p >> 1);
+                    c = (uint)p;
+                }
+                while (i > 0);
+
+                {
+                    ulong p = x_0 * x_0;
+                    zz_1 = (ulong)(c << 31) | (p >> 33);
+                    zz[0] = (uint)p;
+                    c = (uint)(p >> 32) & 1;
+                }
+            }
+
+            ulong x_1 = x[1];
+            ulong zz_2 = zz[2];
+
+            {
+                zz_1 += x_1 * x_0;
+                w = (uint)zz_1;
+                zz[1] = (w << 1) | c;
+                c = w >> 31;
+                zz_2 += zz_1 >> 32;
+            }
+
+            ulong x_2 = x[2];
+            ulong zz_3 = zz[3];
+            ulong zz_4 = zz[4];
+            {
+                zz_2 += x_2 * x_0;
+                w = (uint)zz_2;
+                zz[2] = (w << 1) | c;
+                c = w >> 31;
+                zz_3 += (zz_2 >> 32) + x_2 * x_1;
+                zz_4 += zz_3 >> 32;
+                zz_3 &= M;
+            }
+
+            ulong x_3 = x[3];
+            ulong zz_5 = zz[5];
+            ulong zz_6 = zz[6];
+            {
+                zz_3 += x_3 * x_0;
+                w = (uint)zz_3;
+                zz[3] = (w << 1) | c;
+                c = w >> 31;
+                zz_4 += (zz_3 >> 32) + x_3 * x_1;
+                zz_5 += (zz_4 >> 32) + x_3 * x_2;
+                zz_4 &= M;
+                zz_6 += zz_5 >> 32;
+                zz_5 &= M;
+            }
+
+            ulong x_4 = x[4];
+            ulong zz_7 = zz[7];
+            ulong zz_8 = zz[8];
+            {
+                zz_4 += x_4 * x_0;
+                w = (uint)zz_4;
+                zz[4] = (w << 1) | c;
+                c = w >> 31;
+                zz_5 += (zz_4 >> 32) + x_4 * x_1;
+                zz_6 += (zz_5 >> 32) + x_4 * x_2;
+                zz_7 += (zz_6 >> 32) + x_4 * x_3;
+                zz_8 += zz_7 >> 32;
+            }
+
+            w = (uint)zz_5;
+            zz[5] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_6;
+            zz[6] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_7;
+            zz[7] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_8;
+            zz[8] = (w << 1) | c;
+            c = w >> 31;
+            w = zz[9] + (uint)(zz_8 >> 32);
+            zz[9] = (w << 1) | c;
+        }
+
+        public static void Square(uint[] x, int xOff, uint[] zz, int zzOff)
+        {
+            ulong x_0 = x[xOff + 0];
+            ulong zz_1;
+
+            uint c = 0, w;
+            {
+                int i = 4, j = 10;
+                do
+                {
+                    ulong xVal = x[xOff + i--];
+                    ulong p = xVal * xVal;
+                    zz[zzOff + --j] = (c << 31) | (uint)(p >> 33);
+                    zz[zzOff + --j] = (uint)(p >> 1);
+                    c = (uint)p;
+                }
+                while (i > 0);
+
+                {
+                    ulong p = x_0 * x_0;
+                    zz_1 = (ulong)(c << 31) | (p >> 33);
+                    zz[zzOff + 0] = (uint)p;
+                    c = (uint)(p >> 32) & 1;
+                }
+            }
+
+            ulong x_1 = x[xOff + 1];
+            ulong zz_2 = zz[zzOff + 2];
+
+            {
+                zz_1 += x_1 * x_0;
+                w = (uint)zz_1;
+                zz[zzOff + 1] = (w << 1) | c;
+                c = w >> 31;
+                zz_2 += zz_1 >> 32;
+            }
+
+            ulong x_2 = x[xOff + 2];
+            ulong zz_3 = zz[zzOff + 3];
+            ulong zz_4 = zz[zzOff + 4];
+            {
+                zz_2 += x_2 * x_0;
+                w = (uint)zz_2;
+                zz[zzOff + 2] = (w << 1) | c;
+                c = w >> 31;
+                zz_3 += (zz_2 >> 32) + x_2 * x_1;
+                zz_4 += zz_3 >> 32;
+                zz_3 &= M;
+            }
+
+            ulong x_3 = x[xOff + 3];
+            ulong zz_5 = zz[zzOff + 5];
+            ulong zz_6 = zz[zzOff + 6];
+            {
+                zz_3 += x_3 * x_0;
+                w = (uint)zz_3;
+                zz[zzOff + 3] = (w << 1) | c;
+                c = w >> 31;
+                zz_4 += (zz_3 >> 32) + x_3 * x_1;
+                zz_5 += (zz_4 >> 32) + x_3 * x_2;
+                zz_4 &= M;
+                zz_6 += zz_5 >> 32;
+                zz_5 &= M;
+            }
+
+            ulong x_4 = x[xOff + 4];
+            ulong zz_7 = zz[zzOff + 7];
+            ulong zz_8 = zz[zzOff + 8];
+            {
+                zz_4 += x_4 * x_0;
+                w = (uint)zz_4;
+                zz[zzOff + 4] = (w << 1) | c;
+                c = w >> 31;
+                zz_5 += (zz_4 >> 32) + x_4 * x_1;
+                zz_6 += (zz_5 >> 32) + x_4 * x_2;
+                zz_7 += (zz_6 >> 32) + x_4 * x_3;
+                zz_8 += zz_7 >> 32;
+            }
+
+            w = (uint)zz_5;
+            zz[zzOff + 5] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_6;
+            zz[zzOff + 6] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_7;
+            zz[zzOff + 7] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_8;
+            zz[zzOff + 8] = (w << 1) | c;
+            c = w >> 31;
+            w = zz[zzOff + 9] + (uint)(zz_8 >> 32);
+            zz[zzOff + 9] = (w << 1) | c;
+        }
+
+        public static int Sub(uint[] x, uint[] y, uint[] z)
+        {
+            long c = 0;
+            c += (long)x[0] - y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)x[1] - y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)x[2] - y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)x[3] - y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)x[4] - y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int Sub(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            c += (long)x[xOff + 0] - y[yOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 1] - y[yOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 2] - y[yOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 3] - y[yOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 4] - y[yOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubBothFrom(uint[] x, uint[] y, uint[] z)
+        {
+            long c = 0;
+            c += (long)z[0] - x[0] - y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - x[1] - y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)z[2] - x[2] - y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)z[3] - x[3] - y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)z[4] - x[4] - y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubFrom(uint[] x, uint[] z)
+        {
+            long c = 0;
+            c += (long)z[0] - x[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - x[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)z[2] - x[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)z[3] - x[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)z[4] - x[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubFrom(uint[] x, int xOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            c += (long)z[zOff + 0] - x[xOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 1] - x[xOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 2] - x[xOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 3] - x[xOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 4] - x[xOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static BigInteger ToBigInteger(uint[] x)
+        {
+            byte[] bs = new byte[20];
+            for (int i = 0; i < 5; ++i)
+            {
+                uint x_i = x[i];
+                if (x_i != 0)
+                {
+                    Pack.UInt32_To_BE(x_i, bs, (4 - i) << 2);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+
+        public static void Zero(uint[] z)
+        {
+            z[0] = 0;
+            z[1] = 0;
+            z[2] = 0;
+            z[3] = 0;
+            z[4] = 0;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/Nat192.cs b/crypto/src/math/raw/Nat192.cs
index 94d7ed17c..4797609ee 100644
--- a/crypto/src/math/ec/custom/sec/Nat192.cs
+++ b/crypto/src/math/raw/Nat192.cs
@@ -3,7 +3,7 @@ using System.Diagnostics;
 
 using Org.BouncyCastle.Crypto.Utilities;
 
-namespace Org.BouncyCastle.Math.EC.Custom.Sec
+namespace Org.BouncyCastle.Math.Raw
 {
     internal abstract class Nat192
     {
@@ -145,16 +145,33 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             z[5] = x[5];
         }
 
+        public static void Copy64(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0];
+            z[1] = x[1];
+            z[2] = x[2];
+        }
+
         public static uint[] Create()
         {
             return new uint[6];
         }
 
+        public static ulong[] Create64()
+        {
+            return new ulong[3];
+        }
+
         public static uint[] CreateExt()
         {
             return new uint[12];
         }
 
+        public static ulong[] CreateExt64()
+        {
+            return new ulong[6];
+        }
+
         public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
         {
             bool pos = Gte(x, xOff, y, yOff);
@@ -179,6 +196,18 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return true;
         }
 
+        public static bool Eq64(ulong[] x, ulong[] y)
+        {
+            for (int i = 2; i >= 0; --i)
+            {
+                if (x[i] != y[i])
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         public static uint[] FromBigInteger(BigInteger x)
         {
             if (x.SignValue < 0 || x.BitLength > 192)
@@ -194,6 +223,21 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static ulong[] FromBigInteger64(BigInteger x)
+        {
+            if (x.SignValue < 0 || x.BitLength > 192)
+                throw new ArgumentException();
+
+            ulong[] z = Create64();
+            int i = 0;
+            while (x.SignValue != 0)
+            {
+                z[i++] = (ulong)x.LongValue;
+                x = x.ShiftRight(64);
+            }
+            return z;
+        }
+
         public static uint GetBit(uint[] x, int bit)
         {
             if (bit == 0)
@@ -251,6 +295,22 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return true;
         }
 
+        public static bool IsOne64(ulong[] x)
+        {
+            if (x[0] != 1UL)
+            {
+                return false;
+            }
+            for (int i = 1; i < 3; ++i)
+            {
+                if (x[i] != 0UL)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         public static bool IsZero(uint[] x)
         {
             for (int i = 0; i < 6; ++i)
@@ -263,6 +323,18 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return true;
         }
 
+        public static bool IsZero64(ulong[] x)
+        {
+            for (int i = 0; i < 3; ++i)
+            {
+                if (x[i] != 0UL)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         public static void Mul(uint[] x, uint[] y, uint[] zz)
         {
             ulong y_0 = y[0];
@@ -949,6 +1021,20 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return new BigInteger(1, bs);
         }
 
+        public static BigInteger ToBigInteger64(ulong[] x)
+        {
+            byte[] bs = new byte[24];
+            for (int i = 0; i < 3; ++i)
+            {
+                ulong x_i = x[i];
+                if (x_i != 0L)
+                {
+                    Pack.UInt64_To_BE(x_i, bs, (2 - i) << 3);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+
         public static void Zero(uint[] z)
         {
             z[0] = 0;
diff --git a/crypto/src/math/ec/custom/sec/Nat224.cs b/crypto/src/math/raw/Nat224.cs
index d5b916a54..940e930ac 100644
--- a/crypto/src/math/ec/custom/sec/Nat224.cs
+++ b/crypto/src/math/raw/Nat224.cs
@@ -3,7 +3,7 @@ using System.Diagnostics;
 
 using Org.BouncyCastle.Crypto.Utilities;
 
-namespace Org.BouncyCastle.Math.EC.Custom.Sec
+namespace Org.BouncyCastle.Math.Raw
 {
     internal abstract class Nat224
     {
diff --git a/crypto/src/math/ec/custom/sec/Nat256.cs b/crypto/src/math/raw/Nat256.cs
index bd2d6da47..19455031a 100644
--- a/crypto/src/math/ec/custom/sec/Nat256.cs
+++ b/crypto/src/math/raw/Nat256.cs
@@ -3,7 +3,7 @@ using System.Diagnostics;
 
 using Org.BouncyCastle.Crypto.Utilities;
 
-namespace Org.BouncyCastle.Math.EC.Custom.Sec
+namespace Org.BouncyCastle.Math.Raw
 {
     internal abstract class Nat256
     {
@@ -239,16 +239,34 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             z[7] = x[7];
         }
 
+        public static void Copy64(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0];
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+        }
+
         public static uint[] Create()
         {
             return new uint[8];
         }
 
+        public static ulong[] Create64()
+        {
+            return new ulong[4];
+        }
+
         public static uint[] CreateExt()
         {
             return new uint[16];
         }
 
+        public static ulong[] CreateExt64()
+        {
+            return new ulong[8];
+        }
+
         public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
         {
             bool pos = Gte(x, xOff, y, yOff);
@@ -273,6 +291,18 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return true;
         }
 
+        public static bool Eq64(ulong[] x, ulong[] y)
+        {
+            for (int i = 3; i >= 0; --i)
+            {
+                if (x[i] != y[i])
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         public static uint[] FromBigInteger(BigInteger x)
         {
             if (x.SignValue < 0 || x.BitLength > 256)
@@ -288,6 +318,21 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static ulong[] FromBigInteger64(BigInteger x)
+        {
+            if (x.SignValue < 0 || x.BitLength > 256)
+                throw new ArgumentException();
+
+            ulong[] z = Create64();
+            int i = 0;
+            while (x.SignValue != 0)
+            {
+                z[i++] = (ulong)x.LongValue;
+                x = x.ShiftRight(64);
+            }
+            return z;
+        }
+
         public static uint GetBit(uint[] x, int bit)
         {
             if (bit == 0)
@@ -345,6 +390,22 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return true;
         }
 
+        public static bool IsOne64(ulong[] x)
+        {
+            if (x[0] != 1UL)
+            {
+                return false;
+            }
+            for (int i = 1; i < 4; ++i)
+            {
+                if (x[i] != 0UL)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         public static bool IsZero(uint[] x)
         {
             for (int i = 0; i < 8; ++i)
@@ -357,6 +418,18 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return true;
         }
 
+        public static bool IsZero64(ulong[] x)
+        {
+            for (int i = 0; i < 4; ++i)
+            {
+                if (x[i] != 0UL)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
         public static void Mul(uint[] x, uint[] y, uint[] zz)
         {
             ulong y_0 = y[0];
@@ -1285,6 +1358,20 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return new BigInteger(1, bs);
         }
 
+        public static BigInteger ToBigInteger64(ulong[] x)
+        {
+            byte[] bs = new byte[32];
+            for (int i = 0; i < 4; ++i)
+            {
+                ulong x_i = x[i];
+                if (x_i != 0L)
+                {
+                    Pack.UInt64_To_BE(x_i, bs, (3 - i) << 3);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+
         public static void Zero(uint[] z)
         {
             z[0] = 0;
diff --git a/crypto/src/math/raw/Nat320.cs b/crypto/src/math/raw/Nat320.cs
new file mode 100644
index 000000000..c7daa71e2
--- /dev/null
+++ b/crypto/src/math/raw/Nat320.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+    internal abstract class Nat320
+    {
+        public static void Copy64(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0];
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+            z[4] = x[4];
+        }
+
+        public static ulong[] Create64()
+        {
+            return new ulong[5];
+        }
+
+        public static ulong[] CreateExt64()
+        {
+            return new ulong[10];
+        }
+
+        public static bool Eq64(ulong[] x, ulong[] y)
+        {
+            for (int i = 4; i >= 0; --i)
+            {
+                if (x[i] != y[i])
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static ulong[] FromBigInteger64(BigInteger x)
+        {
+            if (x.SignValue < 0 || x.BitLength > 320)
+                throw new ArgumentException();
+
+            ulong[] z = Create64();
+            int i = 0;
+            while (x.SignValue != 0)
+            {
+                z[i++] = (ulong)x.LongValue;
+                x = x.ShiftRight(64);
+            }
+            return z;
+        }
+
+        public static bool IsOne64(ulong[] x)
+        {
+            if (x[0] != 1UL)
+            {
+                return false;
+            }
+            for (int i = 1; i < 5; ++i)
+            {
+                if (x[i] != 0UL)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static bool IsZero64(ulong[] x)
+        {
+            for (int i = 0; i < 5; ++i)
+            {
+                if (x[i] != 0UL)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static BigInteger ToBigInteger64(ulong[] x)
+        {
+            byte[] bs = new byte[40];
+            for (int i = 0; i < 5; ++i)
+            {
+                ulong x_i = x[i];
+                if (x_i != 0L)
+                {
+                    Pack.UInt64_To_BE(x_i, bs, (4 - i) << 3);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/Nat384.cs b/crypto/src/math/raw/Nat384.cs
index dd93e68b6..ed1c47e8c 100644
--- a/crypto/src/math/ec/custom/sec/Nat384.cs
+++ b/crypto/src/math/raw/Nat384.cs
@@ -1,7 +1,7 @@
 using System;
 using System.Diagnostics;
 
-namespace Org.BouncyCastle.Math.EC.Custom.Sec
+namespace Org.BouncyCastle.Math.Raw
 {
     internal abstract class Nat384
     {
diff --git a/crypto/src/math/raw/Nat448.cs b/crypto/src/math/raw/Nat448.cs
new file mode 100644
index 000000000..52a253f1b
--- /dev/null
+++ b/crypto/src/math/raw/Nat448.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+    internal abstract class Nat448
+    {
+        public static void Copy64(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0];
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+            z[4] = x[4];
+            z[5] = x[5];
+            z[6] = x[6];
+        }
+
+        public static ulong[] Create64()
+        {
+            return new ulong[7];
+        }
+
+        public static ulong[] CreateExt64()
+        {
+            return new ulong[14];
+        }
+
+        public static bool Eq64(ulong[] x, ulong[] y)
+        {
+            for (int i = 6; i >= 0; --i)
+            {
+                if (x[i] != y[i])
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static ulong[] FromBigInteger64(BigInteger x)
+        {
+            if (x.SignValue < 0 || x.BitLength > 448)
+                throw new ArgumentException();
+
+            ulong[] z = Create64();
+            int i = 0;
+            while (x.SignValue != 0)
+            {
+                z[i++] = (ulong)x.LongValue;
+                x = x.ShiftRight(64);
+            }
+            return z;
+        }
+
+        public static bool IsOne64(ulong[] x)
+        {
+            if (x[0] != 1UL)
+            {
+                return false;
+            }
+            for (int i = 1; i < 7; ++i)
+            {
+                if (x[i] != 0UL)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static bool IsZero64(ulong[] x)
+        {
+            for (int i = 0; i < 7; ++i)
+            {
+                if (x[i] != 0UL)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static BigInteger ToBigInteger64(ulong[] x)
+        {
+            byte[] bs = new byte[56];
+            for (int i = 0; i < 7; ++i)
+            {
+                ulong x_i = x[i];
+                if (x_i != 0L)
+                {
+                    Pack.UInt64_To_BE(x_i, bs, (6 - i) << 3);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/Nat512.cs b/crypto/src/math/raw/Nat512.cs
index 46e10f995..a9ef2b3b6 100644
--- a/crypto/src/math/ec/custom/sec/Nat512.cs
+++ b/crypto/src/math/raw/Nat512.cs
@@ -1,7 +1,7 @@
 using System;
 using System.Diagnostics;
 
-namespace Org.BouncyCastle.Math.EC.Custom.Sec
+namespace Org.BouncyCastle.Math.Raw
 {
     internal abstract class Nat512
     {
diff --git a/crypto/src/math/raw/Nat576.cs b/crypto/src/math/raw/Nat576.cs
new file mode 100644
index 000000000..813fb86be
--- /dev/null
+++ b/crypto/src/math/raw/Nat576.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+    internal abstract class Nat576
+    {
+        public static void Copy64(ulong[] x, ulong[] z)
+        {
+            z[0] = x[0];
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+            z[4] = x[4];
+            z[5] = x[5];
+            z[6] = x[6];
+            z[7] = x[7];
+            z[8] = x[8];
+        }
+
+        public static ulong[] Create64()
+        {
+            return new ulong[9];
+        }
+
+        public static ulong[] CreateExt64()
+        {
+            return new ulong[18];
+        }
+
+        public static bool Eq64(ulong[] x, ulong[] y)
+        {
+            for (int i = 8; i >= 0; --i)
+            {
+                if (x[i] != y[i])
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static ulong[] FromBigInteger64(BigInteger x)
+        {
+            if (x.SignValue < 0 || x.BitLength > 576)
+                throw new ArgumentException();
+
+            ulong[] z = Create64();
+            int i = 0;
+            while (x.SignValue != 0)
+            {
+                z[i++] = (ulong)x.LongValue;
+                x = x.ShiftRight(64);
+            }
+            return z;
+        }
+
+        public static bool IsOne64(ulong[] x)
+        {
+            if (x[0] != 1UL)
+            {
+                return false;
+            }
+            for (int i = 1; i < 9; ++i)
+            {
+                if (x[i] != 0UL)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static bool IsZero64(ulong[] x)
+        {
+            for (int i = 0; i < 9; ++i)
+            {
+                if (x[i] != 0UL)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static BigInteger ToBigInteger64(ulong[] x)
+        {
+            byte[] bs = new byte[72];
+            for (int i = 0; i < 9; ++i)
+            {
+                ulong x_i = x[i];
+                if (x_i != 0L)
+                {
+                    Pack.UInt64_To_BE(x_i, bs, (8 - i) << 3);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+    }
+}
diff --git a/crypto/src/security/DotNetUtilities.cs b/crypto/src/security/DotNetUtilities.cs
index d50e17d39..732b5e075 100644
--- a/crypto/src/security/DotNetUtilities.cs
+++ b/crypto/src/security/DotNetUtilities.cs
@@ -233,7 +233,9 @@ namespace Org.BouncyCastle.Security
 
         private static RSA CreateRSAProvider(RSAParameters rp)
         {
-            RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider();
+            CspParameters csp = new CspParameters();
+            csp.KeyContainerName = string.Format("BouncyCastle-{0}", Guid.NewGuid());
+            RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider(csp);
             rsaCsp.ImportParameters(rp);
             return rsaCsp;
         }
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index 8614baead..1f9711555 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -311,6 +311,48 @@ namespace Org.BouncyCastle.Utilities
             return hc;
         }
 
+        [CLSCompliantAttribute(false)]
+        public static int GetHashCode(ulong[] data)
+        {
+            if (data == null)
+                return 0;
+
+            int i = data.Length;
+            int hc = i + 1;
+
+            while (--i >= 0)
+            {
+                ulong di = data[i];
+                hc *= 257;
+                hc ^= (int)di;
+                hc *= 257;
+                hc ^= (int)(di >> 32);
+            }
+
+            return hc;
+        }
+
+        [CLSCompliantAttribute(false)]
+        public static int GetHashCode(ulong[] data, int off, int len)
+        {
+            if (data == null)
+                return 0;
+
+            int i = len;
+            int hc = i + 1;
+
+            while (--i >= 0)
+            {
+                ulong di = data[off + i];
+                hc *= 257;
+                hc ^= (int)di;
+                hc *= 257;
+                hc ^= (int)(di >> 32);
+            }
+
+            return hc;
+        }
+
         public static byte[] Clone(
             byte[] data)
         {
@@ -613,5 +655,21 @@ namespace Org.BouncyCastle.Utilities
 
             return result;
         }
+
+        public static int[] Reverse(int[] a)
+        {
+            if (a == null)
+                return null;
+
+            int p1 = 0, p2 = a.Length;
+            int[] result = new int[p2];
+
+            while (--p2 >= 0)
+            {
+                result[p2] = a[p1++];
+            }
+
+            return result;
+        }
     }
 }