summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2018-07-10 23:21:16 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2018-07-10 23:21:16 +0700
commitaca10f3c38a70188b4caa29b1ca32b2dd04e16bc (patch)
treeefb31e973b61e1c32e49f1b9d7a6bc7f4067dcf9
parentMake members private (diff)
downloadBouncyCastle.NET-ed25519-aca10f3c38a70188b4caa29b1ca32b2dd04e16bc.tar.xz
EC-related updates from bc-java
-rw-r--r--crypto/BouncyCastle.Android.csproj2
-rw-r--r--crypto/BouncyCastle.csproj2
-rw-r--r--crypto/BouncyCastle.iOS.csproj2
-rw-r--r--crypto/crypto.csproj10
-rw-r--r--crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs45
-rw-r--r--crypto/src/asn1/x9/X962NamedCurves.cs6
-rw-r--r--crypto/src/asn1/x9/X9Curve.cs76
-rw-r--r--crypto/src/asn1/x9/X9ECParameters.cs27
-rw-r--r--crypto/src/asn1/x9/X9FieldElement.cs2
-rw-r--r--crypto/src/crypto/agreement/ECDHBasicAgreement.cs20
-rw-r--r--crypto/src/crypto/agreement/ECDHCBasicAgreement.cs14
-rw-r--r--crypto/src/crypto/agreement/ECMqvBasicAgreement.cs13
-rw-r--r--crypto/src/crypto/agreement/SM2KeyExchange.cs6
-rw-r--r--crypto/src/crypto/parameters/ECDomainParameters.cs41
-rw-r--r--crypto/src/crypto/parameters/ECPublicKeyParameters.cs21
-rw-r--r--crypto/src/math/ec/ECAlgorithms.cs31
-rw-r--r--crypto/src/math/ec/ECCurve.cs73
-rw-r--r--crypto/src/math/ec/ECFieldElement.cs94
-rw-r--r--crypto/src/math/ec/ECPoint.cs170
-rw-r--r--crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113FieldElement.cs7
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131FieldElement.cs7
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163FieldElement.cs7
-rw-r--r--crypto/src/math/ec/custom/sec/SecT193FieldElement.cs7
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233FieldElement.cs7
-rw-r--r--crypto/src/math/ec/custom/sec/SecT239FieldElement.cs7
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283FieldElement.cs7
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409FieldElement.cs7
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571FieldElement.cs7
-rw-r--r--crypto/src/math/ec/multiplier/AbstractECMultiplier.cs7
-rw-r--r--crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs6
-rw-r--r--crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs14
-rw-r--r--crypto/src/math/ec/multiplier/FixedPointUtilities.cs63
-rw-r--r--crypto/src/math/ec/multiplier/IPreCompCallback.cs9
-rw-r--r--crypto/src/math/ec/multiplier/ValidityPreCompInfo.cs44
-rw-r--r--crypto/src/math/ec/multiplier/WNafUtilities.cs311
-rw-r--r--crypto/src/math/ec/multiplier/WTauNafMultiplier.cs47
-rw-r--r--crypto/test/src/crypto/test/ECGOST3410Test.cs10
-rw-r--r--crypto/test/src/crypto/test/ECIESTest.cs12
-rw-r--r--crypto/test/src/crypto/test/ECNRTest.cs2
-rw-r--r--crypto/test/src/crypto/test/ECTest.cs55
-rw-r--r--crypto/test/src/crypto/test/SM2EngineTest.cs7
-rw-r--r--crypto/test/src/crypto/test/SM2KeyExchangeTest.cs7
-rw-r--r--crypto/test/src/crypto/test/SM2SignerTest.cs6
-rw-r--r--crypto/test/src/math/ec/test/ECPointTest.cs18
-rw-r--r--crypto/test/src/security/test/TestEncodings.cs31
-rw-r--r--crypto/test/src/security/test/TestSignerUtil.cs16
-rw-r--r--crypto/test/src/test/CertTest.cs25
-rw-r--r--crypto/test/src/test/DHTest.cs33
-rw-r--r--crypto/test/src/test/DSATest.cs66
-rw-r--r--crypto/test/src/test/GOST3410Test.cs20
-rw-r--r--crypto/test/src/test/IESTest.cs11
-rw-r--r--crypto/test/src/test/MqvTest.cs21
-rw-r--r--crypto/test/src/test/PKCS10CertRequestTest.cs25
-rw-r--r--crypto/test/src/x509/test/TestCertificateGen.cs21
67 files changed, 959 insertions, 672 deletions
diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj
index d6f9b737c..a9ddae8d8 100644
--- a/crypto/BouncyCastle.Android.csproj
+++ b/crypto/BouncyCastle.Android.csproj
@@ -1259,12 +1259,14 @@
     <Compile Include="src\math\ec\multiplier\FixedPointPreCompInfo.cs" />
     <Compile Include="src\math\ec\multiplier\FixedPointUtilities.cs" />
     <Compile Include="src\math\ec\multiplier\GlvMultiplier.cs" />
+    <Compile Include="src\math\ec\multiplier\IPreCompCallback.cs" />
     <Compile Include="src\math\ec\multiplier\MixedNafR2LMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\MontgomeryLadderMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\NafL2RMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\NafR2LMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\PreCompInfo.cs" />
     <Compile Include="src\math\ec\multiplier\ReferenceMultiplier.cs" />
+    <Compile Include="src\math\ec\multiplier\ValidityPreCompInfo.cs" />
     <Compile Include="src\math\ec\multiplier\WNafL2RMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\WNafPreCompInfo.cs" />
     <Compile Include="src\math\ec\multiplier\WNafUtilities.cs" />
diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj
index 679e226d0..981cefbe6 100644
--- a/crypto/BouncyCastle.csproj
+++ b/crypto/BouncyCastle.csproj
@@ -1253,12 +1253,14 @@
     <Compile Include="src\math\ec\multiplier\FixedPointPreCompInfo.cs" />
     <Compile Include="src\math\ec\multiplier\FixedPointUtilities.cs" />
     <Compile Include="src\math\ec\multiplier\GlvMultiplier.cs" />
+    <Compile Include="src\math\ec\multiplier\IPreCompCallback.cs" />
     <Compile Include="src\math\ec\multiplier\MixedNafR2LMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\MontgomeryLadderMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\NafL2RMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\NafR2LMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\PreCompInfo.cs" />
     <Compile Include="src\math\ec\multiplier\ReferenceMultiplier.cs" />
+    <Compile Include="src\math\ec\multiplier\ValidityPreCompInfo.cs" />
     <Compile Include="src\math\ec\multiplier\WNafL2RMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\WNafPreCompInfo.cs" />
     <Compile Include="src\math\ec\multiplier\WNafUtilities.cs" />
diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj
index 1d3616d05..c97d9bf65 100644
--- a/crypto/BouncyCastle.iOS.csproj
+++ b/crypto/BouncyCastle.iOS.csproj
@@ -1254,12 +1254,14 @@
     <Compile Include="src\math\ec\multiplier\FixedPointPreCompInfo.cs" />
     <Compile Include="src\math\ec\multiplier\FixedPointUtilities.cs" />
     <Compile Include="src\math\ec\multiplier\GlvMultiplier.cs" />
+    <Compile Include="src\math\ec\multiplier\IPreCompCallback.cs" />
     <Compile Include="src\math\ec\multiplier\MixedNafR2LMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\MontgomeryLadderMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\NafL2RMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\NafR2LMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\PreCompInfo.cs" />
     <Compile Include="src\math\ec\multiplier\ReferenceMultiplier.cs" />
+    <Compile Include="src\math\ec\multiplier\ValidityPreCompInfo.cs" />
     <Compile Include="src\math\ec\multiplier\WNafL2RMultiplier.cs" />
     <Compile Include="src\math\ec\multiplier\WNafPreCompInfo.cs" />
     <Compile Include="src\math\ec\multiplier\WNafUtilities.cs" />
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index e6f092c1e..7cd8de821 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -6154,6 +6154,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\math\ec\multiplier\IPreCompCallback.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\math\ec\multiplier\MixedNafR2LMultiplier.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -6184,6 +6189,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\math\ec\multiplier\ValidityPreCompInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\math\ec\multiplier\WNafL2RMultiplier.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
index 9c366503d..b61da6b57 100644
--- a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
+++ b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
@@ -32,15 +32,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                 mod_p, // p
                 new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a
                 new BigInteger("166"), // b
-                mod_q,
-                BigInteger.One);
+                mod_q, BigInteger.One);
 
             ECDomainParameters ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("1"), // x
                     new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y
-                mod_q);
+                mod_q, BigInteger.One);
 
             parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = ecParams;
 
@@ -51,15 +50,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                 mod_p, // p
                 new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"),
                 new BigInteger("166"),
-                mod_q,
-                BigInteger.One);
+                mod_q, BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("1"), // x
                     new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y
-                mod_q);
+                mod_q, BigInteger.One);
 
             parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA] = ecParams;
 
@@ -70,15 +68,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                 mod_p, // p
                 new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a
                 new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595"), // b
-                mod_q,
-                BigInteger.One);
+                mod_q, BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("1"), // x
                     new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124")), // y
-                mod_q); // q
+                mod_q, BigInteger.One);
 
             parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProB] = ecParams;
 
@@ -89,15 +86,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                 mod_p, // p
                 new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"),
                 new BigInteger("32858"),
-                mod_q,
-                BigInteger.One);
+                mod_q, BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("0"),
                     new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")),
-                mod_q);
+                mod_q, BigInteger.One);
 
             parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB] = ecParams;
 
@@ -107,15 +103,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                 mod_p, // p
                 new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a
                 new BigInteger("32858"), // b
-                mod_q,
-                BigInteger.One);
+                mod_q, BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("0"), // x
                     new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")), // y
-                mod_q); // q
+                mod_q, BigInteger.One);
 
             parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = ecParams;
 
@@ -126,15 +121,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                 mod_p, // p
                 new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a
                 new BigInteger("166"), // b
-                mod_q,
-                BigInteger.One);
+                mod_q, BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("1"), // x
                     new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y
-                mod_q); // q
+                mod_q, BigInteger.One);
 
             parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetA] = ecParams;
 
@@ -144,15 +138,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                 mod_p, // p
                 new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4",16), // a
                 new BigInteger("E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760",16), // b
-                mod_q,
-                BigInteger.One);
+                mod_q, BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003"), // x
                     new BigInteger("7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4",16)), // y
-                mod_q); // q
+                mod_q, BigInteger.One);
 
             parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetA] = ecParams;
 
@@ -162,15 +155,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                 mod_p, // p
                 new BigInteger("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C",16), // a
                 new BigInteger("687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116",16), // b
-                mod_q,
-                BigInteger.One);
+                mod_q, BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"), // x
                     new BigInteger("1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD",16)), // y
-                mod_q); // q
+                mod_q, BigInteger.One);
 
             parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetB] = ecParams;
 
@@ -180,15 +172,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
                 mod_p, // p
                 new BigInteger("DC9203E514A721875485A529D2C722FB187BC8980EB866644DE41C68E143064546E861C0E2C9EDD92ADE71F46FCF50FF2AD97F951FDA9F2A2EB6546F39689BD3",16), // a
                 new BigInteger("B4C4EE28CEBC6C2C8AC12952CF37F16AC7EFB6A9F69F4B57FFDA2E4F0DE5ADE038CBC2FFF719D2C18DE0284B8BFEF3B52B8CC7A5F5BF0A3C8D2319A5312557E1",16), // b
-                mod_q,
-                BigInteger.One);
+                mod_q, BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("E2E31EDFC23DE7BDEBE241CE593EF5DE2295B7A9CBAEF021D385F7074CEA043AA27272A7AE602BF2A7B9033DB9ED3610C6FB85487EAE97AAC5BC7928C1950148", 16), // x
                     new BigInteger("F5CE40D95B5EB899ABBCCFF5911CB8577939804D6527378B8C108C3D2090FF9BE18E2D33E3021ED2EF32D85822423B6304F726AA854BAE07D0396E9A9ADDC40F",16)), // y
-                mod_q); // q
+                mod_q, BigInteger.One);
 
             parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetC] = ecParams;
 
diff --git a/crypto/src/asn1/x9/X962NamedCurves.cs b/crypto/src/asn1/x9/X962NamedCurves.cs
index 14f7f818a..1609774f1 100644
--- a/crypto/src/asn1/x9/X962NamedCurves.cs
+++ b/crypto/src/asn1/x9/X962NamedCurves.cs
@@ -31,7 +31,7 @@ namespace Org.BouncyCastle.Asn1.X9
                 BigInteger h = BigInteger.One;
 
                 ECCurve cFp192v1 = new FpCurve(
-                    new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+                    new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16),
                     new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
                     new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16),
                     n, h);
@@ -58,7 +58,7 @@ namespace Org.BouncyCastle.Asn1.X9
                 BigInteger h = BigInteger.One;
 
                 ECCurve cFp192v2 = new FpCurve(
-                    new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+                    new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16),
                     new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
                     new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16),
                     n, h);
@@ -85,7 +85,7 @@ namespace Org.BouncyCastle.Asn1.X9
                 BigInteger h = BigInteger.One;
 
                 ECCurve cFp192v3 = new FpCurve(
-                    new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+                    new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", 16),
                     new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
                     new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16),
                     n, h);
diff --git a/crypto/src/asn1/x9/X9Curve.cs b/crypto/src/asn1/x9/X9Curve.cs
index f05a946c2..eab94def8 100644
--- a/crypto/src/asn1/x9/X9Curve.cs
+++ b/crypto/src/asn1/x9/X9Curve.cs
@@ -47,9 +47,19 @@ namespace Org.BouncyCastle.Asn1.X9
             }
         }
 
+        [Obsolete("Use constructor including order/cofactor")]
         public X9Curve(
             X9FieldID		fieldID,
             Asn1Sequence	seq)
+            : this(fieldID, null, null, seq)
+        {
+        }
+
+        public X9Curve(
+            X9FieldID		fieldID,
+            BigInteger      order,
+            BigInteger      cofactor,
+            Asn1Sequence	seq)
         {
             if (fieldID == null)
                 throw new ArgumentNullException("fieldID");
@@ -60,47 +70,47 @@ namespace Org.BouncyCastle.Asn1.X9
 
             if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField))
             {
-                BigInteger q = ((DerInteger) fieldID.Parameters).Value;
-                X9FieldElement x9A = new X9FieldElement(q, (Asn1OctetString) seq[0]);
-                X9FieldElement x9B = new X9FieldElement(q, (Asn1OctetString) seq[1]);
-                curve = new FpCurve(q, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger());
+                BigInteger p = ((DerInteger)fieldID.Parameters).Value;
+                BigInteger A = new BigInteger(1, Asn1OctetString.GetInstance(seq[0]).GetOctets());
+                BigInteger B = new BigInteger(1, Asn1OctetString.GetInstance(seq[1]).GetOctets());
+                curve = new FpCurve(p, A, B, order, cofactor);
             }
-            else
+            else if (fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) 
             {
-                if (fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) 
+                // Characteristic two field
+                DerSequence parameters = (DerSequence)fieldID.Parameters;
+                int m = ((DerInteger)parameters[0]).Value.IntValue;
+                DerObjectIdentifier representation
+                    = (DerObjectIdentifier)parameters[1];
+
+                int k1 = 0;
+                int k2 = 0;
+                int k3 = 0;
+                if (representation.Equals(X9ObjectIdentifiers.TPBasis)) 
                 {
-                    // Characteristic two field
-                    DerSequence parameters = (DerSequence)fieldID.Parameters;
-                    int m = ((DerInteger)parameters[0]).Value.IntValue;
-                    DerObjectIdentifier representation
-                        = (DerObjectIdentifier)parameters[1];
-
-                    int k1 = 0;
-                    int k2 = 0;
-                    int k3 = 0;
-                    if (representation.Equals(X9ObjectIdentifiers.TPBasis)) 
-                    {
-                        // Trinomial basis representation
-                        k1 = ((DerInteger)parameters[2]).Value.IntValue;
-                    }
-                    else 
-                    {
-                        // Pentanomial basis representation
-                        DerSequence pentanomial = (DerSequence) parameters[2];
-                        k1 = ((DerInteger) pentanomial[0]).Value.IntValue;
-                        k2 = ((DerInteger) pentanomial[1]).Value.IntValue;
-                        k3 = ((DerInteger) pentanomial[2]).Value.IntValue;
-                    }
-                    X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[0]);
-                    X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[1]);
-                    // TODO Is it possible to get the order (n) and cofactor(h) too?
-                    curve = new F2mCurve(m, k1, k2, k3, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger());
+                    // Trinomial basis representation
+                    k1 = ((DerInteger)parameters[2]).Value.IntValue;
                 }
+                else 
+                {
+                    // Pentanomial basis representation
+                    DerSequence pentanomial = (DerSequence) parameters[2];
+                    k1 = ((DerInteger) pentanomial[0]).Value.IntValue;
+                    k2 = ((DerInteger) pentanomial[1]).Value.IntValue;
+                    k3 = ((DerInteger) pentanomial[2]).Value.IntValue;
+                }
+                BigInteger A = new BigInteger(1, Asn1OctetString.GetInstance(seq[0]).GetOctets());
+                BigInteger B = new BigInteger(1, Asn1OctetString.GetInstance(seq[1]).GetOctets());
+                curve = new F2mCurve(m, k1, k2, k3, A, B, order, cofactor);
+            }
+            else
+            {
+                throw new ArgumentException("This type of ECCurve is not implemented");
             }
 
             if (seq.Count == 3)
             {
-                seed = ((DerBitString) seq[2]).GetBytes();
+                seed = ((DerBitString)seq[2]).GetBytes();
             }
         }
 
diff --git a/crypto/src/asn1/x9/X9ECParameters.cs b/crypto/src/asn1/x9/X9ECParameters.cs
index 0fa343768..e1b29ca13 100644
--- a/crypto/src/asn1/x9/X9ECParameters.cs
+++ b/crypto/src/asn1/x9/X9ECParameters.cs
@@ -23,29 +23,32 @@ namespace Org.BouncyCastle.Asn1.X9
 		public static X9ECParameters GetInstance(Object obj)
 		{
 			if (obj is X9ECParameters)
-			{
 				return (X9ECParameters)obj;
-			}
 
-			if (obj != null)
-			{
+            if (obj != null)
 				return new X9ECParameters(Asn1Sequence.GetInstance(obj));
-			}
 
-			return null;
+            return null;
 		}
 
         public X9ECParameters(
             Asn1Sequence seq)
         {
             if (!(seq[0] is DerInteger)
-               || !((DerInteger) seq[0]).Value.Equals(BigInteger.One))
+                || !((DerInteger)seq[0]).Value.Equals(BigInteger.One))
             {
                 throw new ArgumentException("bad version in X9ECParameters");
             }
 
+            this.n = ((DerInteger)seq[4]).Value;
+
+            if (seq.Count == 6)
+            {
+                this.h = ((DerInteger)seq[5]).Value;
+            }
+
             X9Curve x9c = new X9Curve(
-                X9FieldID.GetInstance(seq[1]),
+                X9FieldID.GetInstance(seq[1]), n, h,
                 Asn1Sequence.GetInstance(seq[2]));
 
             this.curve = x9c.Curve;
@@ -53,20 +56,14 @@ namespace Org.BouncyCastle.Asn1.X9
 
             if (p is X9ECPoint)
             {
-                this.g = ((X9ECPoint)p);
+                this.g = (X9ECPoint)p;
             }
             else
             {
                 this.g = new X9ECPoint(curve, (Asn1OctetString)p);
             }
 
-            this.n = ((DerInteger)seq[4]).Value;
             this.seed = x9c.GetSeed();
-
-            if (seq.Count == 6)
-            {
-                this.h = ((DerInteger)seq[5]).Value;
-            }
         }
 
         public X9ECParameters(
diff --git a/crypto/src/asn1/x9/X9FieldElement.cs b/crypto/src/asn1/x9/X9FieldElement.cs
index 94bd96b24..222b4cfc8 100644
--- a/crypto/src/asn1/x9/X9FieldElement.cs
+++ b/crypto/src/asn1/x9/X9FieldElement.cs
@@ -19,6 +19,7 @@ namespace Org.BouncyCastle.Asn1.X9
             this.f = f;
         }
 
+        [Obsolete("Will be removed")]
         public X9FieldElement(
             BigInteger		p,
             Asn1OctetString	s)
@@ -26,6 +27,7 @@ namespace Org.BouncyCastle.Asn1.X9
         {
         }
 
+        [Obsolete("Will be removed")]
         public X9FieldElement(
             int				m,
             int				k1,
diff --git a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
index ca7b3fa3f..1358db0cf 100644
--- a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
@@ -45,12 +45,26 @@ namespace Org.BouncyCastle.Crypto.Agreement
         public virtual BigInteger CalculateAgreement(
             ICipherParameters pubKey)
         {
-            ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
-            if (!pub.Parameters.Equals(privKey.Parameters))
+            ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey;
+            ECDomainParameters dp = privKey.Parameters;
+            if (!dp.Equals(pub.Parameters))
                 throw new InvalidOperationException("ECDH public key has wrong domain parameters");
 
-            ECPoint P = pub.Q.Multiply(privKey.D).Normalize();
+            BigInteger d = privKey.D;
 
+            // Always perform calculations on the exact curve specified by our private key's parameters
+            ECPoint Q = ECAlgorithms.CleanPoint(dp.Curve, pub.Q);
+            if (Q.IsInfinity)
+                throw new InvalidOperationException("Infinity is not a valid public key for ECDH");
+
+            BigInteger h = dp.H;
+            if (!h.Equals(BigInteger.One))
+            {
+                d = dp.HInv.Multiply(d).Mod(dp.N);
+                Q = ECAlgorithms.ReferenceMultiply(Q, h);
+            }
+
+            ECPoint P = Q.Multiply(d).Normalize();
             if (P.IsInfinity)
                 throw new InvalidOperationException("Infinity is not a valid agreement value for ECDH");
 
diff --git a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
index 1c9ae45f9..f0b5d1e02 100644
--- a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
@@ -50,15 +50,19 @@ namespace Org.BouncyCastle.Crypto.Agreement
         public virtual BigInteger CalculateAgreement(
             ICipherParameters pubKey)
         {
-            ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
-            ECDomainParameters parameters = pub.Parameters;
-            if (!parameters.Equals(privKey.Parameters))
+            ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey;
+            ECDomainParameters dp = privKey.Parameters;
+            if (!dp.Equals(pub.Parameters))
                 throw new InvalidOperationException("ECDHC public key has wrong domain parameters");
 
-            BigInteger hd = parameters.H.Multiply(privKey.D).Mod(parameters.N);
+            BigInteger hd = dp.H.Multiply(privKey.D).Mod(dp.N);
 
-            ECPoint P = pub.Q.Multiply(hd).Normalize();
+            // Always perform calculations on the exact curve specified by our private key's parameters
+            ECPoint pubPoint = ECAlgorithms.CleanPoint(dp.Curve, pub.Q);
+            if (pubPoint.IsInfinity)
+                throw new InvalidOperationException("Infinity is not a valid public key for ECDHC");
 
+            ECPoint P = pubPoint.Multiply(hd).Normalize();
             if (P.IsInfinity)
                 throw new InvalidOperationException("Infinity is not a valid agreement value for ECDHC");
 
diff --git a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
index 8d5cebb13..b71f5a7d2 100644
--- a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
@@ -64,16 +64,9 @@ namespace Org.BouncyCastle.Crypto.Agreement
 
             ECCurve curve = parameters.Curve;
 
-            ECPoint[] points = new ECPoint[]{
-                // The Q2U public key is optional - but will be calculated for us if it wasn't present
-                ECAlgorithms.ImportPoint(curve, Q2U.Q),
-                ECAlgorithms.ImportPoint(curve, Q1V.Q),
-                ECAlgorithms.ImportPoint(curve, Q2V.Q)
-            };
-
-            curve.NormalizeAll(points);
-
-            ECPoint q2u = points[0], q1v = points[1], q2v = points[2];
+            ECPoint q2u = ECAlgorithms.CleanPoint(curve, Q2U.Q);
+            ECPoint q1v = ECAlgorithms.CleanPoint(curve, Q1V.Q);
+            ECPoint q2v = ECAlgorithms.CleanPoint(curve, Q2V.Q);
 
             BigInteger x = q2u.AffineXCoord.ToBigInteger();
             BigInteger xBar = x.Mod(powE);
diff --git a/crypto/src/crypto/agreement/SM2KeyExchange.cs b/crypto/src/crypto/agreement/SM2KeyExchange.cs
index 1cfcd6a3a..986d98421 100644
--- a/crypto/src/crypto/agreement/SM2KeyExchange.cs
+++ b/crypto/src/crypto/agreement/SM2KeyExchange.cs
@@ -144,8 +144,10 @@ namespace Org.BouncyCastle.Crypto.Agreement
 
         protected virtual ECPoint CalculateU(SM2KeyExchangePublicParameters otherPub)
         {
-            ECPoint p1 = otherPub.StaticPublicKey.Q;
-            ECPoint p2 = otherPub.EphemeralPublicKey.Q;
+            ECDomainParameters dp = mStaticKey.Parameters;
+
+            ECPoint p1 = ECAlgorithms.CleanPoint(dp.Curve, otherPub.StaticPublicKey.Q);
+            ECPoint p2 = ECAlgorithms.CleanPoint(dp.Curve, otherPub.EphemeralPublicKey.Q);
 
             BigInteger x1 = Reduce(mEphemeralPubPoint.AffineXCoord.ToBigInteger());
             BigInteger x2 = Reduce(p2.AffineXCoord.ToBigInteger());
diff --git a/crypto/src/crypto/parameters/ECDomainParameters.cs b/crypto/src/crypto/parameters/ECDomainParameters.cs
index 732fbdfa4..e377f7760 100644
--- a/crypto/src/crypto/parameters/ECDomainParameters.cs
+++ b/crypto/src/crypto/parameters/ECDomainParameters.cs
@@ -13,12 +13,13 @@ namespace Org.BouncyCastle.Crypto.Parameters
         internal ECPoint     g;
         internal BigInteger  n;
         internal BigInteger  h;
+        internal BigInteger  hInv;
 
         public ECDomainParameters(
             ECCurve     curve,
             ECPoint     g,
             BigInteger  n)
-            : this(curve, g, n, BigInteger.One)
+            : this(curve, g, n, BigInteger.One, null)
         {
         }
 
@@ -44,11 +45,10 @@ namespace Org.BouncyCastle.Crypto.Parameters
                 throw new ArgumentNullException("g");
             if (n == null)
                 throw new ArgumentNullException("n");
-            if (h == null)
-                throw new ArgumentNullException("h");
+            // we can't check for h == null here as h is optional in X9.62 as it is not required for ECDSA
 
             this.curve = curve;
-            this.g = g.Normalize();
+            this.g = Validate(curve, g);
             this.n = n;
             this.h = h;
             this.seed = Arrays.Clone(seed);
@@ -74,6 +74,21 @@ namespace Org.BouncyCastle.Crypto.Parameters
             get { return h; }
         }
 
+        public BigInteger HInv
+        {
+            get
+            {
+                lock (this)
+                {
+                    if (hInv == null)
+                    {
+                        hInv = h.ModInverse(n);
+                    }
+                    return hInv;
+                }
+            }
+        }
+
         public byte[] GetSeed()
         {
             return Arrays.Clone(seed);
@@ -99,7 +114,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             return curve.Equals(other.curve)
                 &&	g.Equals(other.g)
                 &&	n.Equals(other.n)
-                &&	h.Equals(other.h);
+                &&  h.Equals(other.h);
         }
 
         public override int GetHashCode()
@@ -113,5 +128,21 @@ namespace Org.BouncyCastle.Crypto.Parameters
             hc ^= h.GetHashCode();
             return hc;
         }
+
+        internal static ECPoint Validate(ECCurve c, ECPoint q)
+        {
+            if (q == null)
+                throw new ArgumentException("Point has null value", "q");
+
+            q = ECAlgorithms.ImportPoint(c, q).Normalize();
+
+            if (q.IsInfinity)
+                throw new ArgumentException("Point at infinity", "q");
+
+            if (!q.IsValid())
+                throw new ArgumentException("Point not on curve", "q");
+
+            return q;
+        }
     }
 }
diff --git a/crypto/src/crypto/parameters/ECPublicKeyParameters.cs b/crypto/src/crypto/parameters/ECPublicKeyParameters.cs
index 474e5d82c..69916e525 100644
--- a/crypto/src/crypto/parameters/ECPublicKeyParameters.cs
+++ b/crypto/src/crypto/parameters/ECPublicKeyParameters.cs
@@ -9,21 +9,6 @@ namespace Org.BouncyCastle.Crypto.Parameters
     public class ECPublicKeyParameters
         : ECKeyParameters
     {
-        private static ECPoint Validate(ECPoint q)
-        {
-            if (q == null)
-                throw new ArgumentNullException("q");
-            if (q.IsInfinity)
-                throw new ArgumentException("point at infinity", "q");
-
-            q = q.Normalize();
-
-            if (!q.IsValid())
-                throw new ArgumentException("point not on curve", "q");
-
-            return q;
-        }
-
         private readonly ECPoint q;
 
         public ECPublicKeyParameters(
@@ -42,7 +27,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             if (q == null)
                 throw new ArgumentNullException("q");
 
-            this.q = Validate(q);
+            this.q = ECDomainParameters.Validate(Parameters.Curve, q);
         }
 
         public ECPublicKeyParameters(
@@ -54,7 +39,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             if (q == null)
                 throw new ArgumentNullException("q");
 
-            this.q = Validate(q);
+            this.q = ECDomainParameters.Validate(Parameters.Curve, q);
         }
 
         public ECPublicKeyParameters(
@@ -66,7 +51,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             if (q == null)
                 throw new ArgumentNullException("q");
 
-            this.q = Validate(q);
+            this.q = ECDomainParameters.Validate(Parameters.Curve, q);
         }
 
         public ECPoint Q
diff --git a/crypto/src/math/ec/ECAlgorithms.cs b/crypto/src/math/ec/ECAlgorithms.cs
index 5d60de40f..b05c0201a 100644
--- a/crypto/src/math/ec/ECAlgorithms.cs
+++ b/crypto/src/math/ec/ECAlgorithms.cs
@@ -58,10 +58,10 @@ namespace Org.BouncyCastle.Math.EC
             GlvEndomorphism glvEndomorphism = c.GetEndomorphism() as GlvEndomorphism;
             if (glvEndomorphism != null)
             {
-                return ValidatePoint(ImplSumOfMultipliesGlv(imported, ks, glvEndomorphism));
+                return ImplCheckResult(ImplSumOfMultipliesGlv(imported, ks, glvEndomorphism));
             }
 
-            return ValidatePoint(ImplSumOfMultiplies(imported, ks));
+            return ImplCheckResult(ImplSumOfMultiplies(imported, ks));
         }
 
         public static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger a, ECPoint Q, BigInteger b)
@@ -74,18 +74,18 @@ namespace Org.BouncyCastle.Math.EC
                 AbstractF2mCurve f2mCurve = cp as AbstractF2mCurve;
                 if (f2mCurve != null && f2mCurve.IsKoblitz)
                 {
-                    return ValidatePoint(P.Multiply(a).Add(Q.Multiply(b)));
+                    return ImplCheckResult(P.Multiply(a).Add(Q.Multiply(b)));
                 }
             }
 
             GlvEndomorphism glvEndomorphism = cp.GetEndomorphism() as GlvEndomorphism;
             if (glvEndomorphism != null)
             {
-                return ValidatePoint(
+                return ImplCheckResult(
                     ImplSumOfMultipliesGlv(new ECPoint[] { P, Q }, new BigInteger[] { a, b }, glvEndomorphism));
             }
 
-            return ValidatePoint(ImplShamirsTrickWNaf(P, a, Q, b));
+            return ImplCheckResult(ImplShamirsTrickWNaf(P, a, Q, b));
         }
 
         /*
@@ -111,7 +111,7 @@ namespace Org.BouncyCastle.Math.EC
             ECCurve cp = P.Curve;
             Q = ImportPoint(cp, Q);
 
-            return ValidatePoint(ImplShamirsTrickJsf(P, k, Q, l));
+            return ImplCheckResult(ImplShamirsTrickJsf(P, k, Q, l));
         }
 
         public static ECPoint ImportPoint(ECCurve c, ECPoint p)
@@ -202,7 +202,24 @@ namespace Org.BouncyCastle.Math.EC
         public static ECPoint ValidatePoint(ECPoint p)
         {
             if (!p.IsValid())
-                throw new ArgumentException("Invalid point", "p");
+                throw new InvalidOperationException("Invalid point");
+
+            return p;
+        }
+
+        public static ECPoint CleanPoint(ECCurve c, ECPoint p)
+        {
+            ECCurve cp = p.Curve;
+            if (!c.Equals(cp))
+                throw new ArgumentException("Point must be on the same curve", "p");
+
+            return c.DecodePoint(p.GetEncoded(false));
+        }
+
+        internal static ECPoint ImplCheckResult(ECPoint p)
+        {
+            if (!p.IsValidPartial())
+                throw new InvalidOperationException("Invalid result");
 
             return p;
         }
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index 6a9342722..993b69149 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -161,15 +161,24 @@ namespace Org.BouncyCastle.Math.EC
         public virtual PreCompInfo GetPreCompInfo(ECPoint point, string name)
         {
             CheckPoint(point);
+
+            IDictionary table;
             lock (point)
             {
-                IDictionary table = point.m_preCompTable;
-                return table == null ? null : (PreCompInfo)table[name];
+                table = point.m_preCompTable;
+            }
+
+            if (null == table)
+                return null;
+
+            lock (table)
+            {
+                return (PreCompInfo)table[name];
             }
         }
 
         /**
-         * Adds <code>PreCompInfo</code> for a point on this curve, under a given name. Used by
+         * Compute a <code>PreCompInfo</code> for a point on this curve, under a given name. Used by
          * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use
          * by subsequent multiplication.
          * 
@@ -177,20 +186,34 @@ namespace Org.BouncyCastle.Math.EC
          *            The <code>ECPoint</code> to store precomputations for.
          * @param name
          *            A <code>String</code> used to index precomputations of different types.
-         * @param preCompInfo
-         *            The values precomputed by the <code>ECMultiplier</code>.
+         * @param callback
+         *            Called to calculate the <code>PreCompInfo</code>.
          */
-        public virtual void SetPreCompInfo(ECPoint point, string name, PreCompInfo preCompInfo)
+        public virtual PreCompInfo Precompute(ECPoint point, string name, IPreCompCallback callback)
         {
             CheckPoint(point);
+
+            IDictionary table;
             lock (point)
             {
-                IDictionary table = point.m_preCompTable;
+                table = point.m_preCompTable;
                 if (null == table)
                 {
                     point.m_preCompTable = table = Platform.CreateHashtable(4);
                 }
-                table[name] = preCompInfo;
+            }
+
+            lock (table)
+            {
+                PreCompInfo existing = (PreCompInfo)table[name];
+                PreCompInfo result = callback.Precompute(existing);
+
+                if (result != existing)
+                {
+                    table[name] = result;
+                }
+
+                return result;
             }
         }
 
@@ -208,7 +231,7 @@ namespace Org.BouncyCastle.Math.EC
             // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
             p = p.Normalize();
 
-            return ValidatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
+            return CreatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
         }
 
         /**
@@ -453,7 +476,7 @@ namespace Org.BouncyCastle.Math.EC
                     BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
 
                     p = DecompressPoint(yTilde, X);
-                    if (!p.SatisfiesCofactor())
+                    if (!p.ImplIsValid(true, true))
                         throw new ArgumentException("Invalid point");
 
                     break;
@@ -588,6 +611,7 @@ namespace Org.BouncyCastle.Math.EC
         protected readonly BigInteger m_q, m_r;
         protected readonly FpPoint m_infinity;
 
+        [Obsolete("Use constructor taking order/cofactor")]
         public FpCurve(BigInteger q, BigInteger a, BigInteger b)
             : this(q, a, b, null, null)
         {
@@ -598,7 +622,7 @@ namespace Org.BouncyCastle.Math.EC
         {
             this.m_q = q;
             this.m_r = FpFieldElement.CalculateResidue(q);
-            this.m_infinity = new FpPoint(this, null, null);
+            this.m_infinity = new FpPoint(this, null, null, false);
 
             this.m_a = FromBigInteger(a);
             this.m_b = FromBigInteger(b);
@@ -607,6 +631,7 @@ namespace Org.BouncyCastle.Math.EC
             this.m_coord = FP_DEFAULT_COORDS;
         }
 
+        [Obsolete("Use constructor taking order/cofactor")]
         protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)
             : this(q, r, a, b, null, null)
         {
@@ -617,7 +642,7 @@ namespace Org.BouncyCastle.Math.EC
         {
             this.m_q = q;
             this.m_r = r;
-            this.m_infinity = new FpPoint(this, null, null);
+            this.m_infinity = new FpPoint(this, null, null, false);
 
             this.m_a = a;
             this.m_b = b;
@@ -794,7 +819,7 @@ namespace Org.BouncyCastle.Math.EC
             else
             {
                 ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
-                ECFieldElement z = SolveQuadradicEquation(beta);
+                ECFieldElement z = SolveQuadraticEquation(beta);
 
                 if (z != null)
                 {
@@ -831,11 +856,11 @@ namespace Org.BouncyCastle.Math.EC
          * D.1.6) The other solution is <code>z + 1</code>.
          *
          * @param beta
-         *            The value to solve the qradratic equation for.
+         *            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 SolveQuadradicEquation(ECFieldElement beta)
+        internal ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
         {
             if (beta.IsZero)
                 return beta;
@@ -957,6 +982,7 @@ namespace Org.BouncyCastle.Math.EC
          * for non-supersingular elliptic curves over
          * <code>F<sub>2<sup>m</sup></sub></code>.
          */
+        [Obsolete("Use constructor taking order/cofactor")]
         public F2mCurve(
             int			m,
             int			k,
@@ -1014,6 +1040,7 @@ namespace Org.BouncyCastle.Math.EC
          * for non-supersingular elliptic curves over
          * <code>F<sub>2<sup>m</sup></sub></code>.
          */
+        [Obsolete("Use constructor taking order/cofactor")]
         public F2mCurve(
             int			m,
             int			k1,
@@ -1065,7 +1092,7 @@ namespace Org.BouncyCastle.Math.EC
             this.k3 = k3;
             this.m_order = order;
             this.m_cofactor = cofactor;
-            this.m_infinity = new F2mPoint(this, null, null);
+            this.m_infinity = new F2mPoint(this, null, null, false);
 
             if (k1 == 0)
                 throw new ArgumentException("k1 must be > 0");
@@ -1099,7 +1126,7 @@ namespace Org.BouncyCastle.Math.EC
             this.m_order = order;
             this.m_cofactor = cofactor;
 
-            this.m_infinity = new F2mPoint(this, null, null);
+            this.m_infinity = new F2mPoint(this, null, null, false);
             this.m_a = a;
             this.m_b = b;
             this.m_coord = F2M_DEFAULT_COORDS;
@@ -1188,18 +1215,6 @@ namespace Org.BouncyCastle.Math.EC
             get { return k3; }
         }
 
-        [Obsolete("Use 'Order' property instead")]
-        public BigInteger N
-        {
-            get { return m_order; }
-        }
-
-        [Obsolete("Use 'Cofactor' property instead")]
-        public BigInteger H
-        {
-            get { return m_cofactor; }
-        }
-
         public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len)
         {
             int FE_LONGS = (m + 63) / 64;
diff --git a/crypto/src/math/ec/ECFieldElement.cs b/crypto/src/math/ec/ECFieldElement.cs
index 3676c81b1..350e8c6d4 100644
--- a/crypto/src/math/ec/ECFieldElement.cs
+++ b/crypto/src/math/ec/ECFieldElement.cs
@@ -101,9 +101,14 @@ namespace Org.BouncyCastle.Math.EC
         }
     }
 
-    public class FpFieldElement
+    public abstract class AbstractFpFieldElement
         : ECFieldElement
     {
+    }
+
+    public class FpFieldElement
+        : AbstractFpFieldElement
+    {
         private readonly BigInteger q, r, x;
 
         internal static BigInteger CalculateResidue(BigInteger p)
@@ -536,6 +541,45 @@ namespace Org.BouncyCastle.Math.EC
         }
     }
 
+    public abstract class AbstractF2mFieldElement
+        :   ECFieldElement
+    {
+        public virtual ECFieldElement HalfTrace()
+        {
+            int m = FieldSize;
+            if ((m & 1) == 0)
+                throw new InvalidOperationException("Half-trace only defined for odd m");
+
+            ECFieldElement fe = this;
+            ECFieldElement ht = fe;
+            for (int i = 2; i < m; i += 2)
+            {
+                fe = fe.SquarePow(2);
+                ht = ht.Add(fe);
+            }
+
+            return ht;
+        }
+
+        public virtual int Trace()
+        {
+            int m = FieldSize;
+            ECFieldElement fe = this;
+            ECFieldElement tr = fe;
+            for (int i = 1; i < m; ++i)
+            {
+                fe = fe.Square();
+                tr = tr.Add(fe);
+            }
+            if (tr.IsZero)
+                return 0;
+            if (tr.IsOne)
+                return 1;
+
+            throw new InvalidOperationException("Internal error in trace calculation");
+        }
+    }
+
     /**
      * Class representing the Elements of the finite field
      * <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB)
@@ -544,7 +588,7 @@ namespace Org.BouncyCastle.Math.EC
      * representation is not supported.
      */
     public class F2mFieldElement
-        : ECFieldElement
+        :   AbstractF2mFieldElement
     {
         /**
          * Indicates gaussian normal basis representation (GNB). Number chosen
@@ -582,20 +626,21 @@ namespace Org.BouncyCastle.Math.EC
         internal LongArray x;
 
         /**
-            * Constructor for Ppb.
-            * @param m  The exponent <code>m</code> of
-            * <code>F<sub>2<sup>m</sup></sub></code>.
-            * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
-            * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-            * represents the reduction polynomial <code>f(z)</code>.
-            * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
-            * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-            * represents the reduction polynomial <code>f(z)</code>.
-            * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
-            * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
-            * represents the reduction polynomial <code>f(z)</code>.
-            * @param x The BigInteger representing the value of the field element.
-            */
+         * Constructor for Ppb.
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         * @param x The BigInteger representing the value of the field element.
+         */
+        [Obsolete("Use ECCurve.FromBigInteger to construct field elements")]
         public F2mFieldElement(
             int			m,
             int			k1,
@@ -627,14 +672,15 @@ namespace Org.BouncyCastle.Math.EC
         }
 
         /**
-            * Constructor for Tpb.
-            * @param m  The exponent <code>m</code> of
-            * <code>F<sub>2<sup>m</sup></sub></code>.
-            * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
-            * x<sup>k</sup> + 1</code> represents the reduction
-            * polynomial <code>f(z)</code>.
-            * @param x The BigInteger representing the value of the field element.
-            */
+         * Constructor for Tpb.
+         * @param m  The exponent <code>m</code> of
+         * <code>F<sub>2<sup>m</sup></sub></code>.
+         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+         * x<sup>k</sup> + 1</code> represents the reduction
+         * polynomial <code>f(z)</code>.
+         * @param x The BigInteger representing the value of the field element.
+         */
+        [Obsolete("Use ECCurve.FromBigInteger to construct field elements")]
         public F2mFieldElement(
             int			m,
             int			k,
diff --git a/crypto/src/math/ec/ECPoint.cs b/crypto/src/math/ec/ECPoint.cs
index a5ba515c5..2acc9f5c0 100644
--- a/crypto/src/math/ec/ECPoint.cs
+++ b/crypto/src/math/ec/ECPoint.cs
@@ -67,13 +67,19 @@ namespace Org.BouncyCastle.Math.EC
             this.m_withCompression = withCompression;
         }
 
-        protected internal bool SatisfiesCofactor()
+        protected abstract bool SatisfiesCurveEquation();
+
+        protected virtual bool SatisfiesOrder()
         {
-            BigInteger h = Curve.Cofactor;
-            return h == null || h.Equals(BigInteger.One) || !ECAlgorithms.ReferenceMultiply(this, h).IsInfinity;
-        }
+            if (BigInteger.One.Equals(Curve.Cofactor))
+                return true;
 
-        protected abstract bool SatisfiesCurveEquation();
+            BigInteger n = Curve.Order;
+
+            // TODO Require order to be available for all curves
+
+            return n == null || ECAlgorithms.ReferenceMultiply(this, n).IsInfinity;
+        }
 
         public ECPoint GetDetachedPoint()
         {
@@ -97,30 +103,6 @@ namespace Org.BouncyCastle.Math.EC
         }
 
         /**
-         * Normalizes this point, and then returns the affine x-coordinate.
-         * 
-         * Note: normalization can be expensive, this method is deprecated in favour
-         * of caller-controlled normalization.
-         */
-        [Obsolete("Use AffineXCoord, or Normalize() and XCoord, instead")]
-        public virtual ECFieldElement X
-        {
-            get { return Normalize().XCoord; }
-        }
-
-        /**
-         * Normalizes this point, and then returns the affine y-coordinate.
-         * 
-         * Note: normalization can be expensive, this method is deprecated in favour
-         * of caller-controlled normalization.
-         */
-        [Obsolete("Use AffineYCoord, or Normalize() and YCoord, instead")]
-        public virtual ECFieldElement Y
-        {
-            get { return Normalize().YCoord; }
-        }
-
-        /**
          * Returns the affine x-coordinate after checking that this point is normalized.
          * 
          * @return The affine x-coordinate of this point
@@ -299,22 +281,22 @@ namespace Org.BouncyCastle.Math.EC
 
         public bool IsValid()
         {
-            if (IsInfinity)
-                return true;
-
-            // TODO Sanity-check the field elements
+            return ImplIsValid(false, true);
+        }
 
-            ECCurve curve = Curve;
-            if (curve != null)
-            {
-                if (!SatisfiesCurveEquation())
-                    return false;
+        internal bool IsValidPartial()
+        {
+            return ImplIsValid(false, false);
+        }
 
-                if (!SatisfiesCofactor())
-                    return false;
-            }
+        internal bool ImplIsValid(bool decompressed, bool checkOrder)
+        {
+            if (IsInfinity)
+                return true;
 
-            return true;
+            ValidityCallback callback = new ValidityCallback(this, decompressed, checkOrder);
+            ValidityPreCompInfo validity = (ValidityPreCompInfo)Curve.Precompute(this, ValidityPreCompInfo.PRECOMP_NAME, callback);
+            return !validity.HasFailed();
         }
 
         public virtual ECPoint ScaleX(ECFieldElement scale)
@@ -462,6 +444,52 @@ namespace Org.BouncyCastle.Math.EC
         {
             return TwicePlus(this);
         }
+
+        private class ValidityCallback
+            : IPreCompCallback
+        {
+            private readonly ECPoint m_outer;
+            private readonly bool m_decompressed, m_checkOrder;
+
+            internal ValidityCallback(ECPoint outer, bool decompressed, bool checkOrder)
+            {
+                this.m_outer = outer;
+                this.m_decompressed = decompressed;
+                this.m_checkOrder = checkOrder;
+            }
+
+            public PreCompInfo Precompute(PreCompInfo existing)
+            {
+                ValidityPreCompInfo info = existing as ValidityPreCompInfo;
+                if (info == null)
+                {
+                    info = new ValidityPreCompInfo();
+                }
+
+                if (info.HasFailed())
+                    return info;
+
+                if (!info.HasCurveEquationPassed())
+                {
+                    if (!m_decompressed && !m_outer.SatisfiesCurveEquation())
+                    {
+                        info.ReportFailed();
+                        return info;
+                    }
+                    info.ReportCurveEquationPassed();
+                }
+                if (m_checkOrder && !info.HasOrderPassed())
+                {
+                    if (!m_outer.SatisfiesOrder())
+                    {
+                        info.ReportFailed();
+                        return info;
+                    }
+                    info.ReportOrderPassed();
+                }
+                return info;
+            }
+        }
     }
 
     public abstract class ECPointBase
@@ -608,6 +636,7 @@ namespace Org.BouncyCastle.Math.EC
          * @param x affine x co-ordinate
          * @param y affine y co-ordinate
          */
+        [Obsolete("Use ECCurve.CreatePoint to construct points")]
         public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
             : this(curve, x, y, false)
         {
@@ -621,6 +650,7 @@ namespace Org.BouncyCastle.Math.EC
          * @param y affine y co-ordinate
          * @param withCompression if true encode with point compression
          */
+        [Obsolete("Per-point compression property will be removed, see GetEncoded(bool)")]
         public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
             : base(curve, x, y, withCompression)
         {
@@ -635,7 +665,7 @@ namespace Org.BouncyCastle.Math.EC
 
         protected override ECPoint Detach()
         {
-            return new FpPoint(null, AffineXCoord, AffineYCoord);
+            return new FpPoint(null, AffineXCoord, AffineYCoord, false);
         }
 
         public override ECFieldElement GetZCoord(int index)
@@ -1384,6 +1414,46 @@ namespace Org.BouncyCastle.Math.EC
             return lhs.Equals(rhs);
         }
 
+        protected override bool SatisfiesOrder()
+        {
+            ECCurve curve = Curve;
+            BigInteger cofactor = curve.Cofactor;
+            if (BigInteger.Two.Equals(cofactor))
+            {
+                /*
+                 *  Check that the trace of (X + A) is 0, then there exists a solution to L^2 + L = X + A,
+                 *  and so a halving is possible, so this point is the double of another.  
+                 */
+                ECPoint N = this.Normalize();
+                ECFieldElement X = N.AffineXCoord;
+                ECFieldElement rhs = X.Add(curve.A);
+                return ((AbstractF2mFieldElement)rhs).Trace() == 0;
+            }
+            if (BigInteger.ValueOf(4).Equals(cofactor))
+            {
+                /*
+                 * Solve L^2 + L = X + A to find the half of this point, if it exists (fail if not).
+                 * Generate both possibilities for the square of the half-point's x-coordinate (w),
+                 * and check if Tr(w + A) == 0 for at least one; then a second halving is possible
+                 * (see comments for cofactor 2 above), so this point is four times another.
+                 * 
+                 * Note: Tr(x^2) == Tr(x). 
+                 */
+                ECPoint N = this.Normalize();
+                ECFieldElement X = N.AffineXCoord;
+                ECFieldElement lambda = ((AbstractF2mCurve)curve).SolveQuadraticEquation(X.Add(curve.A));
+                if (lambda == null)
+                    return false;
+
+                ECFieldElement w = X.Multiply(lambda).Add(N.AffineYCoord);
+                ECFieldElement t = w.Add(curve.A);
+                return ((AbstractF2mFieldElement)t).Trace() == 0
+                    || ((AbstractF2mFieldElement)(t.Add(X))).Trace() == 0;
+            }
+
+            return base.SatisfiesOrder();
+        }
+
         public override ECPoint ScaleX(ECFieldElement scale)
         {
             if (this.IsInfinity)
@@ -1529,6 +1599,7 @@ namespace Org.BouncyCastle.Math.EC
          * @param x x point
          * @param y y point
          */
+        [Obsolete("Use ECCurve.CreatePoint to construct points")]
         public F2mPoint(
             ECCurve			curve,
             ECFieldElement	x,
@@ -1543,6 +1614,7 @@ namespace Org.BouncyCastle.Math.EC
          * @param y y point
          * @param withCompression true if encode with point compression.
          */
+        [Obsolete("Per-point compression property will be removed, see GetEncoded(bool)")]
         public F2mPoint(
             ECCurve			curve,
             ECFieldElement	x,
@@ -1573,19 +1645,9 @@ namespace Org.BouncyCastle.Math.EC
         {
         }
 
-        /**
-         * Constructor for point at infinity
-         */
-        [Obsolete("Use ECCurve.Infinity property")]
-        public F2mPoint(
-            ECCurve curve)
-            : this(curve, null, null)
-        {
-        }
-
         protected override ECPoint Detach()
         {
-            return new F2mPoint(null, AffineXCoord, AffineYCoord);
+            return new F2mPoint(null, AffineXCoord, AffineYCoord, false);
         }
 
         public override ECFieldElement YCoord
diff --git a/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs b/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
index 732e9e468..37256a550 100644
--- a/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
+++ b/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Djb
 {
     internal class Curve25519FieldElement
-        :   ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = Curve25519.q;
 
diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs b/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs
index 4f6428f9e..087a040f2 100644
--- a/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs
+++ b/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.GM
 {
     internal class SM2P256V1FieldElement
-        : ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = SM2P256V1Curve.q;
 
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs
index fa7951d5d..5912a87e8 100644
--- a/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP128R1FieldElement
-        : ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = SecP128R1Curve.q;
 
diff --git a/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs
index d1fc75644..3ab11bdae 100644
--- a/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP160R1FieldElement
-        : ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = SecP160R1Curve.q;
 
diff --git a/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs
index bdb5245b2..9d8131857 100644
--- a/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP160R2FieldElement
-        : ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = SecP160R2Curve.q;
 
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
index dce377035..54b72573c 100644
--- a/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
@@ -7,7 +7,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP192K1FieldElement
-        : ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = SecP192K1Curve.q;
 
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
index 45bcb00f0..f3e12b542 100644
--- a/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP192R1FieldElement
-        : ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = SecP192R1Curve.q;
 
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
index fec07436a..ef53a88d6 100644
--- a/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
@@ -7,7 +7,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP224K1FieldElement
-        : ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = SecP224K1Curve.q;
 
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
index 2b9a06564..5780b7481 100644
--- a/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP224R1FieldElement
-        : ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = SecP224R1Curve.q;
 
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
index 473113d0f..9a604bdb7 100644
--- a/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
@@ -7,7 +7,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP256K1FieldElement
-        : ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = SecP256K1Curve.q;
 
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
index d7838aead..808e99ea6 100644
--- a/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP256R1FieldElement
-        : ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = SecP256R1Curve.q;
 
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
index 18d48a57d..7eedccae6 100644
--- a/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP384R1FieldElement
-        : ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = SecP384R1Curve.q;
 
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
index 6f02a7eb5..96658a8e5 100644
--- a/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecP521R1FieldElement
-        : ECFieldElement
+        : AbstractFpFieldElement
     {
         public static readonly BigInteger Q = SecP521R1Curve.q;
 
diff --git a/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
index 9ba25d987..bb87b00fc 100644
--- a/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecT113FieldElement
-        : ECFieldElement
+        : AbstractF2mFieldElement
     {
         protected internal readonly ulong[] x;
 
@@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return new SecT113FieldElement(z);
         }
 
+        public override int Trace()
+        {
+            return (int)SecT113Field.Trace(x);
+        }
+
         public override ECFieldElement Invert()
         {
             ulong[] z = Nat128.Create64();
diff --git a/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
index c38e8eb0a..f96c7ca39 100644
--- a/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecT131FieldElement
-        : ECFieldElement
+        : AbstractF2mFieldElement
     {
         protected internal readonly ulong[] x;
 
@@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return new SecT131FieldElement(z);
         }
 
+        public override int Trace()
+        {
+            return (int)SecT131Field.Trace(x);
+        }
+
         public override ECFieldElement Invert()
         {
             ulong[] z = Nat192.Create64();
diff --git a/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
index 07bd07652..903645999 100644
--- a/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecT163FieldElement
-        : ECFieldElement
+        : AbstractF2mFieldElement
     {
         protected internal readonly ulong[] x;
 
@@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return new SecT163FieldElement(z);
         }
 
+        public override int Trace()
+        {
+            return (int)SecT163Field.Trace(x);
+        }
+
         public override ECFieldElement Invert()
         {
             ulong[] z = Nat192.Create64();
diff --git a/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
index d04e68d3f..9813bcb01 100644
--- a/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecT193FieldElement
-        : ECFieldElement
+        : AbstractF2mFieldElement
     {
         protected internal readonly ulong[] x;
 
@@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return new SecT193FieldElement(z);
         }
 
+        public override int Trace()
+        {
+            return (int)SecT193Field.Trace(x);
+        }
+
         public override ECFieldElement Invert()
         {
             ulong[] z = Nat256.Create64();
diff --git a/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
index 64d09bd6d..fbfe35e13 100644
--- a/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecT233FieldElement
-        : ECFieldElement
+        : AbstractF2mFieldElement
     {
         protected internal readonly ulong[] x;
 
@@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return new SecT233FieldElement(z);
         }
 
+        public override int Trace()
+        {
+            return (int)SecT233Field.Trace(x);
+        }
+
         public override ECFieldElement Invert()
         {
             ulong[] z = Nat256.Create64();
diff --git a/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
index 18563f746..b1b58e89b 100644
--- a/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecT239FieldElement
-        : ECFieldElement
+        : AbstractF2mFieldElement
     {
         protected internal readonly ulong[] x;
 
@@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return new SecT239FieldElement(z);
         }
 
+        public override int Trace()
+        {
+            return (int)SecT239Field.Trace(x);
+        }
+
         public override ECFieldElement Invert()
         {
             ulong[] z = Nat256.Create64();
diff --git a/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
index b054bedfb..c1bb2e30c 100644
--- a/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecT283FieldElement
-        : ECFieldElement
+        : AbstractF2mFieldElement
     {
         protected internal readonly ulong[] x;
 
@@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return new SecT283FieldElement(z);
         }
 
+        public override int Trace()
+        {
+            return (int)SecT283Field.Trace(x);
+        }
+
         public override ECFieldElement Invert()
         {
             ulong[] z = Nat320.Create64();
diff --git a/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
index 7076905bb..68a63312d 100644
--- a/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecT409FieldElement
-        : ECFieldElement
+        : AbstractF2mFieldElement
     {
         protected internal readonly ulong[] x;
 
@@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return new SecT409FieldElement(z);
         }
 
+        public override int Trace()
+        {
+            return (int)SecT409Field.Trace(x);
+        }
+
         public override ECFieldElement Invert()
         {
             ulong[] z = Nat448.Create64();
diff --git a/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
index 5f28c01be..c9f3aa5c0 100644
--- a/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Math.EC.Custom.Sec
 {
     internal class SecT571FieldElement
-        : ECFieldElement
+        : AbstractF2mFieldElement
     {
         protected internal readonly ulong[] x;
 
@@ -150,6 +150,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return new SecT571FieldElement(z);
         }
 
+        public override int Trace()
+        {
+            return (int)SecT571Field.Trace(x);
+        }
+
         public override ECFieldElement Invert()
         {
             ulong[] z = Nat576.Create64();
diff --git a/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs b/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs
index 517881323..c2580c852 100644
--- a/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs
+++ b/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs
@@ -16,9 +16,14 @@
              * Although the various multipliers ought not to produce invalid output under normal
              * circumstances, a final check here is advised to guard against fault attacks.
              */
-            return ECAlgorithms.ValidatePoint(result);
+            return CheckResult(result);
         }
 
         protected abstract ECPoint MultiplyPositive(ECPoint p, BigInteger k);
+
+        protected virtual ECPoint CheckResult(ECPoint p)
+        {
+            return ECAlgorithms.ImplCheckResult(p);
+        }
     }
 }
diff --git a/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs b/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs
index adaedb809..505832442 100644
--- a/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs
+++ b/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs
@@ -52,11 +52,5 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
 
             return R.Add(info.Offset);
         }
-
-        [Obsolete("Is no longer used; remove any overrides in subclasses.")]
-        protected virtual int GetWidthForCombSize(int combSize)
-        {
-            return combSize > 257 ? 6 : 5;
-        }
     }
 }
diff --git a/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs b/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs
index 4c0b404df..5d6af9e5d 100644
--- a/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs
+++ b/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs
@@ -11,13 +11,6 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
         protected ECPoint m_offset = null;
 
         /**
-         * Array holding the precomputed <code>ECPoint</code>s used for a fixed
-         * point multiplication.
-         */
-        [Obsolete("Will be removed")]
-		protected ECPoint[] m_preComp = null;
-
-        /**
          * Lookup table for the precomputed <code>ECPoint</code>s used for a fixed point multiplication.
          */
         protected ECLookupTable m_lookupTable = null;
@@ -41,13 +34,6 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
 			set { this.m_offset = value; }
 		}
 
-        [Obsolete("Use 'LookupTable' property instead.")]
-        public virtual ECPoint[] PreComp
-        {
-            get { return m_preComp; }
-            set { this.m_preComp = value; }
-        }
-
         public virtual int Width
         {
             get { return m_width; }
diff --git a/crypto/src/math/ec/multiplier/FixedPointUtilities.cs b/crypto/src/math/ec/multiplier/FixedPointUtilities.cs
index cc7203314..88f178e24 100644
--- a/crypto/src/math/ec/multiplier/FixedPointUtilities.cs
+++ b/crypto/src/math/ec/multiplier/FixedPointUtilities.cs
@@ -14,36 +14,40 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
 
         public static FixedPointPreCompInfo GetFixedPointPreCompInfo(PreCompInfo preCompInfo)
         {
-            if ((preCompInfo != null) && (preCompInfo is FixedPointPreCompInfo))
-            {
-                return (FixedPointPreCompInfo)preCompInfo;
-            }
-
-            return new FixedPointPreCompInfo();
+            return preCompInfo as FixedPointPreCompInfo;
         }
 
-        [Obsolete("Use 'Precompute(ECPoint)' instead, as minWidth parameter is now ignored")]
-        public static FixedPointPreCompInfo Precompute(ECPoint p, int minWidth)
+        public static FixedPointPreCompInfo Precompute(ECPoint p)
         {
-            return Precompute(p);
+            return (FixedPointPreCompInfo)p.Curve.Precompute(p, PRECOMP_NAME, new FixedPointCallback(p));
         }
 
-        public static FixedPointPreCompInfo Precompute(ECPoint p)
+        private class FixedPointCallback
+            : IPreCompCallback
         {
-            ECCurve c = p.Curve;
-            int minWidth = GetCombSize(c) > 257 ? 6 : 5;
+            private readonly ECPoint m_p;
 
-            int n = 1 << minWidth;
-            FixedPointPreCompInfo info = GetFixedPointPreCompInfo(c.GetPreCompInfo(p, PRECOMP_NAME));
-            ECPoint[] lookupTable = info.PreComp;
+            internal FixedPointCallback(ECPoint p)
+            {
+                this.m_p = p;
+            }
 
-            if (lookupTable == null || lookupTable.Length < n)
+            public PreCompInfo Precompute(PreCompInfo existing)
             {
-                int bits = GetCombSize(c);
+                FixedPointPreCompInfo existingFP = (existing is FixedPointPreCompInfo) ? (FixedPointPreCompInfo)existing : null;
+
+                ECCurve c = m_p.Curve;
+                int bits = FixedPointUtilities.GetCombSize(c);
+                int minWidth = bits > 250 ? 6 : 5;
+                int n = 1 << minWidth;
+
+                if (CheckExisting(existingFP, n))
+                    return existingFP;
+
                 int d = (bits + minWidth - 1) / minWidth;
 
                 ECPoint[] pow2Table = new ECPoint[minWidth + 1];
-                pow2Table[0] = p;
+                pow2Table[0] = m_p;
                 for (int i = 1; i < minWidth; ++i)
                 {
                     pow2Table[i] = pow2Table[i - 1].TimesPow2(d);
@@ -53,8 +57,8 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
                 pow2Table[minWidth] = pow2Table[0].Subtract(pow2Table[1]);
 
                 c.NormalizeAll(pow2Table);
-    
-                lookupTable = new ECPoint[n];
+
+                ECPoint[] lookupTable = new ECPoint[n];
                 lookupTable[0] = pow2Table[0];
 
                 for (int bit = minWidth - 1; bit >= 0; --bit)
@@ -70,15 +74,22 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
 
                 c.NormalizeAll(lookupTable);
 
-                info.LookupTable = c.CreateCacheSafeLookupTable(lookupTable, 0, lookupTable.Length);
-                info.Offset = pow2Table[minWidth];
-                info.PreComp = lookupTable;
-                info.Width = minWidth;
+                FixedPointPreCompInfo result = new FixedPointPreCompInfo();
+                result.LookupTable = c.CreateCacheSafeLookupTable(lookupTable, 0, lookupTable.Length);
+                result.Offset = pow2Table[minWidth];
+                result.Width = minWidth;
+                return result;
+            }
 
-                c.SetPreCompInfo(p, PRECOMP_NAME, info);
+            private bool CheckExisting(FixedPointPreCompInfo existingFP, int n)
+            {
+                return existingFP != null && CheckTable(existingFP.LookupTable, n);
             }
 
-            return info;
+            private bool CheckTable(ECLookupTable table, int n)
+            {
+                return table != null && table.Size >= n;
+            }
         }
     }
 }
diff --git a/crypto/src/math/ec/multiplier/IPreCompCallback.cs b/crypto/src/math/ec/multiplier/IPreCompCallback.cs
new file mode 100644
index 000000000..e64ae834d
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/IPreCompCallback.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    public interface IPreCompCallback
+    {
+        PreCompInfo Precompute(PreCompInfo existing);
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/ValidityPreCompInfo.cs b/crypto/src/math/ec/multiplier/ValidityPreCompInfo.cs
new file mode 100644
index 000000000..7ec2cbb95
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/ValidityPreCompInfo.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    internal class ValidityPreCompInfo
+        : PreCompInfo
+    {
+        internal static readonly string PRECOMP_NAME = "bc_validity";
+
+        private bool failed = false;
+        private bool curveEquationPassed = false;
+        private bool orderPassed = false;
+
+        internal bool HasFailed()
+        {
+            return failed;
+        }
+
+        internal void ReportFailed()
+        {
+            failed = true;
+        }
+
+        internal bool HasCurveEquationPassed()
+        {
+            return curveEquationPassed;
+        }
+
+        internal void ReportCurveEquationPassed()
+        {
+            curveEquationPassed = true;
+        }
+
+        internal bool HasOrderPassed()
+        {
+            return orderPassed;
+        }
+
+        internal void ReportOrderPassed()
+        {
+            orderPassed = true;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/WNafUtilities.cs b/crypto/src/math/ec/multiplier/WNafUtilities.cs
index 7d565dfbd..e893abd49 100644
--- a/crypto/src/math/ec/multiplier/WNafUtilities.cs
+++ b/crypto/src/math/ec/multiplier/WNafUtilities.cs
@@ -287,12 +287,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
 
         public static WNafPreCompInfo GetWNafPreCompInfo(PreCompInfo preCompInfo)
         {
-            if ((preCompInfo != null) && (preCompInfo is WNafPreCompInfo))
-            {
-                return (WNafPreCompInfo)preCompInfo;
-            }
-
-            return new WNafPreCompInfo();
+            return preCompInfo as WNafPreCompInfo;
         }
 
         /**
@@ -333,106 +328,178 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
             WNafPreCompInfo wnafPreCompP = Precompute(p, width, includeNegated);
 
             ECPoint q = pointMap.Map(p);
-            WNafPreCompInfo wnafPreCompQ = GetWNafPreCompInfo(c.GetPreCompInfo(q, PRECOMP_NAME));
+            c.Precompute(q, PRECOMP_NAME, new MapPointCallback(wnafPreCompP, includeNegated, pointMap));
+            return q;
+        }
 
-            ECPoint twiceP = wnafPreCompP.Twice;
-            if (twiceP != null)
-            {
-                ECPoint twiceQ = pointMap.Map(twiceP);
-                wnafPreCompQ.Twice = twiceQ;
-            }
+        public static WNafPreCompInfo Precompute(ECPoint p, int width, bool includeNegated)
+        {
+            return (WNafPreCompInfo)p.Curve.Precompute(p, PRECOMP_NAME, new WNafCallback(p, width, includeNegated));
+        }
+
+        private static byte[] Trim(byte[] a, int length)
+        {
+            byte[] result = new byte[length];
+            Array.Copy(a, 0, result, 0, result.Length);
+            return result;
+        }
+
+        private static int[] Trim(int[] a, int length)
+        {
+            int[] result = new int[length];
+            Array.Copy(a, 0, result, 0, result.Length);
+            return result;
+        }
+
+        private static ECPoint[] ResizeTable(ECPoint[] a, int length)
+        {
+            ECPoint[] result = new ECPoint[length];
+            Array.Copy(a, 0, result, 0, a.Length);
+            return result;
+        }
+
+        private class MapPointCallback
+            : IPreCompCallback
+        {
+            private readonly WNafPreCompInfo m_wnafPreCompP;
+            private readonly bool m_includeNegated;
+            private readonly ECPointMap m_pointMap;
 
-            ECPoint[] preCompP = wnafPreCompP.PreComp;
-            ECPoint[] preCompQ = new ECPoint[preCompP.Length];
-            for (int i = 0; i < preCompP.Length; ++i)
+            internal MapPointCallback(WNafPreCompInfo wnafPreCompP, bool includeNegated, ECPointMap pointMap)
             {
-                preCompQ[i] = pointMap.Map(preCompP[i]);
+                this.m_wnafPreCompP = wnafPreCompP;
+                this.m_includeNegated = includeNegated;
+                this.m_pointMap = pointMap;
             }
-            wnafPreCompQ.PreComp = preCompQ;
 
-            if (includeNegated)
+            public PreCompInfo Precompute(PreCompInfo existing)
             {
-                ECPoint[] preCompNegQ = new ECPoint[preCompQ.Length];
-                for (int i = 0; i < preCompNegQ.Length; ++i)
+                WNafPreCompInfo result = new WNafPreCompInfo();
+
+                ECPoint twiceP = m_wnafPreCompP.Twice;
+                if (twiceP != null)
                 {
-                    preCompNegQ[i] = preCompQ[i].Negate();
+                    ECPoint twiceQ = m_pointMap.Map(twiceP);
+                    result.Twice = twiceQ;
                 }
-                wnafPreCompQ.PreCompNeg = preCompNegQ;
-            }
 
-            c.SetPreCompInfo(q, PRECOMP_NAME, wnafPreCompQ);
+                ECPoint[] preCompP = m_wnafPreCompP.PreComp;
+                ECPoint[] preCompQ = new ECPoint[preCompP.Length];
+                for (int i = 0; i < preCompP.Length; ++i)
+                {
+                    preCompQ[i] = m_pointMap.Map(preCompP[i]);
+                }
+                result.PreComp = preCompQ;
 
-            return q;
+                if (m_includeNegated)
+                {
+                    ECPoint[] preCompNegQ = new ECPoint[preCompQ.Length];
+                    for (int i = 0; i < preCompNegQ.Length; ++i)
+                    {
+                        preCompNegQ[i] = preCompQ[i].Negate();
+                    }
+                    result.PreCompNeg = preCompNegQ;
+                }
+
+                return result;
+            }
         }
 
-        public static WNafPreCompInfo Precompute(ECPoint p, int width, bool includeNegated)
+        private class WNafCallback
+            : IPreCompCallback
         {
-            ECCurve c = p.Curve;
-            WNafPreCompInfo wnafPreCompInfo = GetWNafPreCompInfo(c.GetPreCompInfo(p, PRECOMP_NAME));
+            private readonly ECPoint m_p;
+            private readonly int m_width;
+            private readonly bool m_includeNegated;
 
-            int iniPreCompLen = 0, reqPreCompLen = 1 << System.Math.Max(0, width - 2);
-
-            ECPoint[] preComp = wnafPreCompInfo.PreComp;
-            if (preComp == null)
+            internal WNafCallback(ECPoint p, int width, bool includeNegated)
             {
-                preComp = EMPTY_POINTS;
-            }
-            else
-            {
-                iniPreCompLen = preComp.Length;
+                this.m_p = p;
+                this.m_width = width;
+                this.m_includeNegated = includeNegated;
             }
 
-            if (iniPreCompLen < reqPreCompLen)
+            public PreCompInfo Precompute(PreCompInfo existing)
             {
-                preComp = ResizeTable(preComp, reqPreCompLen);
+                WNafPreCompInfo existingWNaf = existing as WNafPreCompInfo;
+
+                int reqPreCompLen = 1 << System.Math.Max(0, m_width - 2);
+
+                if (CheckExisting(existingWNaf, reqPreCompLen, m_includeNegated))
+                    return existingWNaf;
 
-                if (reqPreCompLen == 1)
+                ECCurve c = m_p.Curve;
+                ECPoint[] preComp = null, preCompNeg = null;
+                ECPoint twiceP = null;
+
+                if (existingWNaf != null)
+                {
+                    preComp = existingWNaf.PreComp;
+                    preCompNeg = existingWNaf.PreCompNeg;
+                    twiceP = existingWNaf.Twice;
+                }
+
+                int iniPreCompLen = 0;
+                if (preComp == null)
                 {
-                    preComp[0] = p.Normalize();
+                    preComp = EMPTY_POINTS;
                 }
                 else
                 {
-                    int curPreCompLen = iniPreCompLen;
-                    if (curPreCompLen == 0)
-                    {
-                        preComp[0] = p;
-                        curPreCompLen = 1;
-                    }
+                    iniPreCompLen = preComp.Length;
+                }
 
-                    ECFieldElement iso = null;
+                if (iniPreCompLen < reqPreCompLen)
+                {
+                    preComp = WNafUtilities.ResizeTable(preComp, reqPreCompLen);
 
-                    if (reqPreCompLen == 2)
+                    if (reqPreCompLen == 1)
                     {
-                        preComp[1] = p.ThreeTimes();
+                        preComp[0] = m_p.Normalize();
                     }
                     else
                     {
-                        ECPoint twiceP = wnafPreCompInfo.Twice, last = preComp[curPreCompLen - 1];
-                        if (twiceP == null)
+                        int curPreCompLen = iniPreCompLen;
+                        if (curPreCompLen == 0)
+                        {
+                            preComp[0] = m_p;
+                            curPreCompLen = 1;
+                        }
+
+                        ECFieldElement iso = null;
+
+                        if (reqPreCompLen == 2)
+                        {
+                            preComp[1] = m_p.ThreeTimes();
+                        }
+                        else
                         {
-                            twiceP = preComp[0].Twice();
-                            wnafPreCompInfo.Twice = twiceP;
-
-                            /*
-                             * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism
-                             * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This
-                             * also requires scaling the initial point's X, Y coordinates, and reversing the
-                             * isomorphism as part of the subsequent normalization.
-                             * 
-                             *  NOTE: The correctness of this optimization depends on:
-                             *      1) additions do not use the curve's A, B coefficients.
-                             *      2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ...
-                             */
-                            if (!twiceP.IsInfinity && ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64)
+                            ECPoint isoTwiceP = twiceP, last = preComp[curPreCompLen - 1];
+                            if (isoTwiceP == null)
                             {
-                                switch (c.CoordinateSystem)
+                                isoTwiceP = preComp[0].Twice();
+                                twiceP = isoTwiceP;
+
+                                /*
+                                 * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism
+                                 * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This
+                                 * also requires scaling the initial point's X, Y coordinates, and reversing the
+                                 * isomorphism as part of the subsequent normalization.
+                                 * 
+                                 *  NOTE: The correctness of this optimization depends on:
+                                 *      1) additions do not use the curve's A, B coefficients.
+                                 *      2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ...
+                                 */
+                                if (!twiceP.IsInfinity && ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64)
                                 {
+                                    switch (c.CoordinateSystem)
+                                    {
                                     case ECCurve.COORD_JACOBIAN:
                                     case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
                                     case ECCurve.COORD_JACOBIAN_MODIFIED:
                                     {
                                         iso = twiceP.GetZCoord(0);
-                                        twiceP = c.CreatePoint(twiceP.XCoord.ToBigInteger(),
+                                        isoTwiceP = c.CreatePoint(twiceP.XCoord.ToBigInteger(),
                                             twiceP.YCoord.ToBigInteger());
 
                                         ECFieldElement iso2 = iso.Square(), iso3 = iso2.Multiply(iso);
@@ -444,81 +511,69 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
                                         }
                                         break;
                                     }
+                                    }
                                 }
                             }
-                        }
 
-                        while (curPreCompLen < reqPreCompLen)
-                        {
-                            /*
-                             * Compute the new ECPoints for the precomputation array. The values 1, 3,
-                             * 5, ..., 2^(width-1)-1 times p are computed
-                             */
-                            preComp[curPreCompLen++] = last = last.Add(twiceP);
+                            while (curPreCompLen < reqPreCompLen)
+                            {
+                                /*
+                                 * Compute the new ECPoints for the precomputation array. The values 1, 3,
+                                 * 5, ..., 2^(width-1)-1 times p are computed
+                                 */
+                                preComp[curPreCompLen++] = last = last.Add(isoTwiceP);
+                            }
                         }
-                    }
 
-                    /*
-                     * Having oft-used operands in affine form makes operations faster.
-                     */
-                    c.NormalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso);
+                        /*
+                         * Having oft-used operands in affine form makes operations faster.
+                         */
+                        c.NormalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso);
+                    }
                 }
-            }
-
-            wnafPreCompInfo.PreComp = preComp;
-
-            if (includeNegated)
-            {
-                ECPoint[] preCompNeg = wnafPreCompInfo.PreCompNeg;
 
-                int pos;
-                if (preCompNeg == null)
-                {
-                    pos = 0;
-                    preCompNeg = new ECPoint[reqPreCompLen]; 
-                }
-                else
+                if (m_includeNegated)
                 {
-                    pos = preCompNeg.Length;
-                    if (pos < reqPreCompLen)
+                    int pos;
+                    if (preCompNeg == null)
                     {
-                        preCompNeg = ResizeTable(preCompNeg, reqPreCompLen);
+                        pos = 0;
+                        preCompNeg = new ECPoint[reqPreCompLen]; 
+                    }
+                    else
+                    {
+                        pos = preCompNeg.Length;
+                        if (pos < reqPreCompLen)
+                        {
+                            preCompNeg = WNafUtilities.ResizeTable(preCompNeg, reqPreCompLen);
+                        }
                     }
-                }
 
-                while (pos < reqPreCompLen)
-                {
-                    preCompNeg[pos] = preComp[pos].Negate();
-                    ++pos;
+                    while (pos < reqPreCompLen)
+                    {
+                        preCompNeg[pos] = preComp[pos].Negate();
+                        ++pos;
+                    }
                 }
 
-                wnafPreCompInfo.PreCompNeg = preCompNeg;
+                WNafPreCompInfo result = new WNafPreCompInfo();
+                result.PreComp = preComp;
+                result.PreCompNeg = preCompNeg;
+                result.Twice = twiceP;
+                return result;
             }
 
-            c.SetPreCompInfo(p, PRECOMP_NAME, wnafPreCompInfo);
-
-            return wnafPreCompInfo;
-        }
-
-        private static byte[] Trim(byte[] a, int length)
-        {
-            byte[] result = new byte[length];
-            Array.Copy(a, 0, result, 0, result.Length);
-            return result;
-        }
-
-        private static int[] Trim(int[] a, int length)
-        {
-            int[] result = new int[length];
-            Array.Copy(a, 0, result, 0, result.Length);
-            return result;
-        }
+            private bool CheckExisting(WNafPreCompInfo existingWNaf, int reqPreCompLen, bool includeNegated)
+            {
+                return existingWNaf != null
+                    && CheckTable(existingWNaf.PreComp, reqPreCompLen)
+                    && (!includeNegated || CheckTable(existingWNaf.PreCompNeg, reqPreCompLen));
+            }
 
-        private static ECPoint[] ResizeTable(ECPoint[] a, int length)
-        {
-            ECPoint[] result = new ECPoint[length];
-            Array.Copy(a, 0, result, 0, a.Length);
-            return result;
+            private bool CheckTable(ECPoint[] table, int reqLen)
+            {
+                return table != null && table.Length >= reqLen;
+            }
         }
     }
 }
diff --git a/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs b/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
index 1e7ddae91..4dce54440 100644
--- a/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
+++ b/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
@@ -36,7 +36,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
 
             ZTauElement rho = Tnaf.PartModReduction(k, m, a, s, mu, (sbyte)10);
 
-            return MultiplyWTnaf(p, rho, curve.GetPreCompInfo(p, PRECOMP_NAME), a, mu);
+            return MultiplyWTnaf(p, rho, a, mu);
         }
 
         /**
@@ -50,7 +50,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
         * @return <code>p</code> multiplied by <code>&#955;</code>.
         */
         private AbstractF2mPoint MultiplyWTnaf(AbstractF2mPoint p, ZTauElement lambda,
-            PreCompInfo preCompInfo, sbyte a, sbyte mu)
+            sbyte a, sbyte mu)
         {
             ZTauElement[] alpha = (a == 0) ? Tnaf.Alpha0 : Tnaf.Alpha1;
 
@@ -59,7 +59,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
             sbyte[]u = Tnaf.TauAdicWNaf(mu, lambda, Tnaf.Width,
                 BigInteger.ValueOf(Tnaf.Pow2Width), tw, alpha);
 
-            return MultiplyFromWTnaf(p, u, preCompInfo);
+            return MultiplyFromWTnaf(p, u);
         }
         
         /**
@@ -71,24 +71,14 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
         * @param u The the WTNAF of <code>&#955;</code>..
         * @return <code>&#955; * p</code>
         */
-        private static AbstractF2mPoint MultiplyFromWTnaf(AbstractF2mPoint p, sbyte[] u, PreCompInfo preCompInfo)
+        private static AbstractF2mPoint MultiplyFromWTnaf(AbstractF2mPoint p, sbyte[] u)
         {
             AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
             sbyte a = (sbyte)curve.A.ToBigInteger().IntValue;
 
-            AbstractF2mPoint[] pu;
-            if ((preCompInfo == null) || !(preCompInfo is WTauNafPreCompInfo))
-            {
-                pu = Tnaf.GetPreComp(p, a);
-
-                WTauNafPreCompInfo pre = new WTauNafPreCompInfo();
-                pre.PreComp = pu;
-                curve.SetPreCompInfo(p, PRECOMP_NAME, pre);
-            }
-            else
-            {
-                pu = ((WTauNafPreCompInfo)preCompInfo).PreComp;
-            }
+            WTauNafCallback callback = new WTauNafCallback(p, a);
+            WTauNafPreCompInfo preCompInfo = (WTauNafPreCompInfo)curve.Precompute(p, PRECOMP_NAME, callback);
+            AbstractF2mPoint[] pu = preCompInfo.PreComp;
 
             // TODO Include negations in precomp (optionally) and use from here
             AbstractF2mPoint[] puNeg = new AbstractF2mPoint[pu.Length];
@@ -121,5 +111,28 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
             }
             return q;
         }
+
+        private class WTauNafCallback
+            : IPreCompCallback
+        {
+            private readonly AbstractF2mPoint m_p;
+            private readonly sbyte m_a;
+
+            internal WTauNafCallback(AbstractF2mPoint p, sbyte a)
+            {
+                this.m_p = p;
+                this.m_a = a;
+            }
+
+            public PreCompInfo Precompute(PreCompInfo existing)
+            {
+                if (existing is WTauNafPreCompInfo)
+                    return existing;
+
+                WTauNafPreCompInfo result = new WTauNafPreCompInfo();
+                result.PreComp = Tnaf.GetPreComp(m_p, m_a);
+                return result;
+            }
+        }
     }
 }
diff --git a/crypto/test/src/crypto/test/ECGOST3410Test.cs b/crypto/test/src/crypto/test/ECGOST3410Test.cs
index 37cb23ecf..4c938378a 100644
--- a/crypto/test/src/crypto/test/ECGOST3410Test.cs
+++ b/crypto/test/src/crypto/test/ECGOST3410Test.cs
@@ -56,7 +56,7 @@ namespace Org.BouncyCastle.Crypto.Tests
                 curve.CreatePoint(
                     new BigInteger("2"), // x
                     new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y
-                mod_q);
+                mod_q, BigInteger.One);
 
             ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
                 "ECGOST3410",
@@ -127,7 +127,7 @@ namespace Org.BouncyCastle.Crypto.Tests
                 curve.CreatePoint(
                     new BigInteger("2"), // x
                     new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y
-                mod_q);
+                mod_q, BigInteger.One);
 
             ECKeyPairGenerator          pGen = new ECKeyPairGenerator();
             ECKeyGenerationParameters   genParam = new ECKeyGenerationParameters(
@@ -184,7 +184,7 @@ namespace Org.BouncyCastle.Crypto.Tests
                 curve.CreatePoint(
                     new BigInteger("1"), // x
                     new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y
-                mod_q);
+                mod_q, BigInteger.One);
 
             ECKeyPairGenerator pGen = new ECKeyPairGenerator("ECGOST3410");
             ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
@@ -234,7 +234,7 @@ namespace Org.BouncyCastle.Crypto.Tests
                 curve.CreatePoint(
                     new BigInteger("1"), // x
                     new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124")), // y
-                mod_q);
+                mod_q, BigInteger.One);
 
             ECKeyPairGenerator pGen = new ECKeyPairGenerator("ECGOST3410");
             ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
@@ -284,7 +284,7 @@ namespace Org.BouncyCastle.Crypto.Tests
                 curve.CreatePoint(
                     new BigInteger("0"), // x
                     new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")), // y
-                mod_q);
+                mod_q, BigInteger.One);
 
             ECKeyPairGenerator pGen = new ECKeyPairGenerator("ECGOST3410");
             ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
diff --git a/crypto/test/src/crypto/test/ECIESTest.cs b/crypto/test/src/crypto/test/ECIESTest.cs
index e8cfd6df4..1e2e8f711 100644
--- a/crypto/test/src/crypto/test/ECIESTest.cs
+++ b/crypto/test/src/crypto/test/ECIESTest.cs
@@ -46,9 +46,9 @@ namespace Org.BouncyCastle.Crypto.Tests
                 n, BigInteger.One);
 
             ECDomainParameters parameters = new ECDomainParameters(
-                    curve,
-                    curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G
-                    n);
+                curve,
+                curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G
+                n, BigInteger.One);
 
             ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
                 "ECDH",
@@ -220,9 +220,9 @@ namespace Org.BouncyCastle.Crypto.Tests
                 n, BigInteger.One);
 
             ECDomainParameters parameters = new ECDomainParameters(
-                    curve,
-                    curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G
-                    n);
+                curve,
+                curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G
+                n, BigInteger.One);
 
             ECKeyPairGenerator eGen = new ECKeyPairGenerator();
             KeyGenerationParameters gParam = new ECKeyGenerationParameters(parameters, new SecureRandom());
diff --git a/crypto/test/src/crypto/test/ECNRTest.cs b/crypto/test/src/crypto/test/ECNRTest.cs
index 5eae9f097..1ab67546c 100644
--- a/crypto/test/src/crypto/test/ECNRTest.cs
+++ b/crypto/test/src/crypto/test/ECNRTest.cs
@@ -49,7 +49,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             ECDomainParameters parameters = new ECDomainParameters(
                 curve,
                 curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-                n);
+                n, BigInteger.One);
 
             ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
                 new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d
diff --git a/crypto/test/src/crypto/test/ECTest.cs b/crypto/test/src/crypto/test/ECTest.cs
index 5697f41eb..7dc847ebe 100644
--- a/crypto/test/src/crypto/test/ECTest.cs
+++ b/crypto/test/src/crypto/test/ECTest.cs
@@ -5,6 +5,7 @@ using NUnit.Framework;
 using Org.BouncyCastle.Asn1.Nist;
 using Org.BouncyCastle.Asn1.Sec;
 using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.EC;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
 using Org.BouncyCastle.Security;
@@ -52,7 +53,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             ECDomainParameters parameters = new ECDomainParameters(
                 curve,
                 curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G
-                n);
+                n, BigInteger.One);
 
             ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
                 "ECDSA",
@@ -98,12 +99,8 @@ namespace Org.BouncyCastle.Crypto.Tests
         [Test]
         public void TestDecode()
         {
-            FpCurve curve = new FpCurve(
-                new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q
-                new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a
-                new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b
-
-            ECPoint p = curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")).Normalize();
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("prime192v1");
+            ECPoint p = x9.G;
 
             if (!p.AffineXCoord.ToBigInteger().Equals(new BigInteger("188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", 16)))
             {
@@ -115,7 +112,7 @@ namespace Org.BouncyCastle.Crypto.Tests
                 Fail("y uncompressed incorrectly");
             }
 
-            byte[] encoding = p.GetEncoded();
+            byte[] encoding = p.GetEncoded(true);
 
             if (!AreEqual(encoding, Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")))
             {
@@ -149,7 +146,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             ECDomainParameters parameters = new ECDomainParameters(
                 curve,
                 curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-                n);
+                n, BigInteger.One);
 
             ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
                 "ECDSA",
@@ -651,7 +648,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             ECDomainParameters parameters = new ECDomainParameters(
                 curve,
                 curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-                n);
+                n, BigInteger.One);
 
             ECKeyPairGenerator pGen = new ECKeyPairGenerator();
             ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
@@ -683,7 +680,7 @@ namespace Org.BouncyCastle.Crypto.Tests
          * Basic Key Agreement Test
          */
         [Test]
-        public void TestECBasicAgreementTest()
+        public void TestECDHBasicAgreement()
         {
             SecureRandom random = new SecureRandom();
 
@@ -698,7 +695,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             ECDomainParameters parameters = new ECDomainParameters(
                 curve,
                 curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-                n);
+                n, BigInteger.One);
 
             ECKeyPairGenerator pGen = new ECKeyPairGenerator();
             ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(parameters, random);
@@ -744,6 +741,35 @@ namespace Org.BouncyCastle.Crypto.Tests
         }
 
         [Test]
+        public void TestECDHBasicAgreementCofactor()
+        {
+            SecureRandom random = new SecureRandom();
+
+            X9ECParameters x9 = CustomNamedCurves.GetByName("curve25519");
+            ECDomainParameters ec = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
+
+            ECKeyPairGenerator kpg = new ECKeyPairGenerator();
+            kpg.Init(new ECKeyGenerationParameters(ec, random));
+
+            AsymmetricCipherKeyPair p1 = kpg.GenerateKeyPair();
+            AsymmetricCipherKeyPair p2 = kpg.GenerateKeyPair();
+
+            IBasicAgreement e1 = new ECDHBasicAgreement();
+            IBasicAgreement e2 = new ECDHBasicAgreement();
+
+            e1.Init(p1.Private);
+            e2.Init(p2.Private);
+
+            BigInteger k1 = e1.CalculateAgreement(p2.Public);
+            BigInteger k2 = e2.CalculateAgreement(p1.Public);
+
+            if (!k1.Equals(k2))
+            {
+                Fail("calculated agreement test failed");
+            }
+        }
+
+        [Test]
         public void TestECMqvTestVector1()
         {
             // Test Vector from GEC-2
@@ -843,7 +869,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             ECDomainParameters parameters = new ECDomainParameters(
                 curve,
                 curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-                n);
+                n, BigInteger.One);
 
             ECKeyPairGenerator pGen = new ECKeyPairGenerator();
 
@@ -909,7 +935,8 @@ namespace Org.BouncyCastle.Crypto.Tests
             TestECDsa191bitBinary();
             TestECDsa239bitBinary();
             TestECDsaKeyGenTest();
-            TestECBasicAgreementTest();
+            TestECDHBasicAgreement();
+            TestECDHBasicAgreementCofactor();
 
             TestECDsaP224Sha224();
             TestECDsaP224OneByteOver();
diff --git a/crypto/test/src/crypto/test/SM2EngineTest.cs b/crypto/test/src/crypto/test/SM2EngineTest.cs
index 8a1987d52..1a2d1d13e 100644
--- a/crypto/test/src/crypto/test/SM2EngineTest.cs
+++ b/crypto/test/src/crypto/test/SM2EngineTest.cs
@@ -28,10 +28,11 @@ namespace Org.BouncyCastle.Crypto.Tests
             BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16);
             BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16);
             BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16);
+            BigInteger SM2_ECC_H = BigInteger.One;
             BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16);
             BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16);
 
-            ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B);
+            ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H);
 
             ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY);
             ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N);
@@ -104,11 +105,11 @@ namespace Org.BouncyCastle.Crypto.Tests
             BigInteger SM2_ECC_A = new BigInteger("00", 16);
             BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16);
             BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16);
+            BigInteger SM2_ECC_H = BigInteger.ValueOf(4);
             BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16);
             BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16);
-            BigInteger SM2_ECC_H = BigInteger.ValueOf(4);
 
-            ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B);
+            ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H);
 
             ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY);
             ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N, SM2_ECC_H);
diff --git a/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs b/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs
index d7a2650eb..39131f163 100644
--- a/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs
+++ b/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs
@@ -30,10 +30,11 @@ namespace Org.BouncyCastle.Crypto.Tests
             BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16);
             BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16);
             BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16);
+            BigInteger SM2_ECC_H = BigInteger.One;
             BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16);
             BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16);
 
-            ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B);
+            ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H);
 
             ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY);
             ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N);
@@ -119,11 +120,11 @@ namespace Org.BouncyCastle.Crypto.Tests
             BigInteger SM2_ECC_A = new BigInteger("00", 16);
             BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16);
             BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16);
+            BigInteger SM2_ECC_H = BigInteger.ValueOf(4);
             BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16);
             BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16);
-            BigInteger SM2_ECC_H = BigInteger.ValueOf(4);
 
-            ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B);
+            ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H);
 
             ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY);
             ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N, SM2_ECC_H);
diff --git a/crypto/test/src/crypto/test/SM2SignerTest.cs b/crypto/test/src/crypto/test/SM2SignerTest.cs
index 5904c95a7..e3c9c21ae 100644
--- a/crypto/test/src/crypto/test/SM2SignerTest.cs
+++ b/crypto/test/src/crypto/test/SM2SignerTest.cs
@@ -29,10 +29,11 @@ namespace Org.BouncyCastle.Crypto.Tests
             BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16);
             BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16);
             BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16);
+            BigInteger SM2_ECC_H = BigInteger.ValueOf(4);
             BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16);
             BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16);
 
-            ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B);
+            ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H);
 
             ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY);
             ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N);
@@ -76,10 +77,11 @@ namespace Org.BouncyCastle.Crypto.Tests
             BigInteger SM2_ECC_A = new BigInteger("00", 16);
             BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16);
             BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16);
+            BigInteger SM2_ECC_H = BigInteger.ValueOf(4);
             BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16);
             BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16);
 
-            ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B);
+            ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H);
 
             ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY);
             ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N);
diff --git a/crypto/test/src/math/ec/test/ECPointTest.cs b/crypto/test/src/math/ec/test/ECPointTest.cs
index 089fb88b3..a5ca083e2 100644
--- a/crypto/test/src/math/ec/test/ECPointTest.cs
+++ b/crypto/test/src/math/ec/test/ECPointTest.cs
@@ -442,6 +442,22 @@ namespace Org.BouncyCastle.Math.EC.Tests
             }
         }
 
+        private void ImplValidityTest(ECCurve c, ECPoint g)
+        {
+            Assert.IsTrue(g.IsValid());
+
+            BigInteger h = c.Cofactor;
+            if (h != null && h.CompareTo(BigInteger.One) > 0)
+            {
+                if (ECAlgorithms.IsF2mCurve(c))
+                {
+                    ECPoint order2 = c.CreatePoint(BigInteger.Zero, c.B.Sqrt().ToBigInteger());
+                    ECPoint bad = g.Add(order2);
+                    Assert.IsFalse(bad.IsValid());
+                }
+            }
+        }
+
         private void ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(X9ECParameters x9ECParameters)
         {
             BigInteger n = x9ECParameters.N;
@@ -470,6 +486,8 @@ namespace Org.BouncyCastle.Math.EC.Tests
                     ImplAddSubtractMultiplyTwiceEncodingTest(c, q, n);
 
                     ImplSqrtTest(c);
+
+                    ImplValidityTest(c, g);
                 }
             }
         }
diff --git a/crypto/test/src/security/test/TestEncodings.cs b/crypto/test/src/security/test/TestEncodings.cs
index 557d2dc51..a70d5b5b7 100644
--- a/crypto/test/src/security/test/TestEncodings.cs
+++ b/crypto/test/src/security/test/TestEncodings.cs
@@ -32,24 +32,19 @@ namespace Org.BouncyCastle.Security.Tests
 			BigInteger ECPubQY = new BigInteger(Base64.Decode("JrlJfxu3WGhqwtL/55BOs/wsUeiDFsvXcGhB8DGx"));
 			BigInteger ECPrivD = new BigInteger(Base64.Decode("GYQmd/NF1B+He1iMkWt3by2Az6Eu07t0ynJ4YCAo"));
 
-			FpCurve curve = new FpCurve(
-				new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
-				new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
-				new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
-
-			ECDomainParameters ecDomain =
-				new ECDomainParameters(
-					curve,
-					new FpPoint(curve,
-						curve.FromBigInteger(ECParraGX),
-						curve.FromBigInteger(ECParraGY)),
-				ECParraN);
-
-			ECPublicKeyParameters ecPub = new ECPublicKeyParameters(
-				new FpPoint(
-					curve,
-					curve.FromBigInteger(ECPubQX),
-					curve.FromBigInteger(ECPubQY)),
+            FpCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b
+                ECParraN, ECParraH);
+
+			ECDomainParameters ecDomain = new ECDomainParameters(
+				curve,
+                curve.ValidatePoint(ECParraGX, ECParraGY),
+                ECParraN, ECParraH);
+
+            ECPublicKeyParameters ecPub = new ECPublicKeyParameters(
+                curve.ValidatePoint(ECPubQX, ECPubQY),
 				ecDomain);
 
 			ECPrivateKeyParameters ecPriv = new ECPrivateKeyParameters(ECPrivD, ecDomain);
diff --git a/crypto/test/src/security/test/TestSignerUtil.cs b/crypto/test/src/security/test/TestSignerUtil.cs
index 18b856e3f..f2ee4b048 100644
--- a/crypto/test/src/security/test/TestSignerUtil.cs
+++ b/crypto/test/src/security/test/TestSignerUtil.cs
@@ -56,18 +56,16 @@ namespace Org.BouncyCastle.Security.Tests
             FpCurve curve = new FpCurve(
                 new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
                 new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
-                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b
+                ECParraN, ECParraH);
 
-            ECDomainParameters ecDomain = new ECDomainParameters(curve,
-                new FpPoint(curve,
-                    curve.FromBigInteger(ECParraGX),
-                    curve.FromBigInteger(ECParraGY)),
-                ECParraN);
+            ECDomainParameters ecDomain = new ECDomainParameters(
+                curve,
+                curve.ValidatePoint(ECParraGX, ECParraGY),
+                ECParraN, ECParraH);
 
             ECPublicKeyParameters ecPub = new ECPublicKeyParameters(
-                new FpPoint(curve,
-                    curve.FromBigInteger(ECPubQX),
-                    curve.FromBigInteger(ECPubQY)),
+                curve.ValidatePoint(ECPubQX, ECPubQY),
                 ecDomain);
 
             ECPrivateKeyParameters ecPriv = new ECPrivateKeyParameters(ECPrivD, ecDomain);
diff --git a/crypto/test/src/test/CertTest.cs b/crypto/test/src/test/CertTest.cs
index d9af06c82..46276a75b 100644
--- a/crypto/test/src/test/CertTest.cs
+++ b/crypto/test/src/test/CertTest.cs
@@ -1391,15 +1391,9 @@ namespace Org.BouncyCastle.Tests
          */
         internal void checkCreation3()
         {
-            ECCurve curve = new FpCurve(
-                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
-                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
-                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
-
-            ECDomainParameters spec = new ECDomainParameters(
-                curve,
-                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-                new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1");
+            ECCurve curve = x9.Curve;
+            ECDomainParameters spec = new ECDomainParameters(curve, x9.G, x9.N, x9.H);
 
             ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(
                 "ECDSA",
@@ -1533,16 +1527,9 @@ namespace Org.BouncyCastle.Tests
             string				algorithm,
             DerObjectIdentifier	algOid)
         {
-            FpCurve curve = new FpCurve(
-                new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p)
-                new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16),   // a
-                new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16));  // b
-
-            ECDomainParameters spec = new ECDomainParameters(
-                curve,
-//				curve.DecodePoint(Hex.Decode("02C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
-                curve.DecodePoint(Hex.Decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
-                new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("secp521r1");
+            ECCurve curve = x9.Curve;
+            ECDomainParameters spec = new ECDomainParameters(curve, x9.G, x9.N, x9.H);
 
             ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(
                 "ECDSA",
diff --git a/crypto/test/src/test/DHTest.cs b/crypto/test/src/test/DHTest.cs
index 1acc0d603..3ed79ca84 100644
--- a/crypto/test/src/test/DHTest.cs
+++ b/crypto/test/src/test/DHTest.cs
@@ -2,6 +2,7 @@ using System;
 
 using NUnit.Framework;
 
+using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
@@ -375,37 +376,22 @@ namespace Org.BouncyCastle.Tests
         [Test]
         public void TestECDH()
         {
-            doTestECDH("ECDH");
+            DoTestECDH("ECDH");
         }
 
         [Test]
         public void TestECDHC()
         {
-            doTestECDH("ECDHC");
+            DoTestECDH("ECDHC");
         }
 
-        private void doTestECDH(
-            string algorithm)
+        private void DoTestECDH(string algorithm)
         {
             IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator(algorithm);
 
-//			EllipticCurve curve = new EllipticCurve(
-//				new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q
-//				new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
-//				new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
-            ECCurve curve = new FpCurve(
-                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
-                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
-                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
-
-            ECDomainParameters ecSpec = new ECDomainParameters(
-                curve,
-//				ECPointUtil.DecodePoint(curve, Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-                new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
-                BigInteger.One); //1); // h
-
-//			g.initialize(ecSpec, new SecureRandom());
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1");
+            ECDomainParameters ecSpec = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H);
+
             g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
 
             //
@@ -429,11 +415,6 @@ namespace Org.BouncyCastle.Tests
             //
             // agreement
             //
-//			aKeyAgreeBasic.doPhase(bKeyPair.Public, true);
-//			bKeyAgreeBasic.doPhase(aKeyPair.Public, true);
-//
-//			BigInteger k1 = new BigInteger(aKeyAgreeBasic.generateSecret());
-//			BigInteger k2 = new BigInteger(bKeyAgreeBasic.generateSecret());
             BigInteger k1 = aKeyAgreeBasic.CalculateAgreement(bKeyPair.Public);
             BigInteger k2 = bKeyAgreeBasic.CalculateAgreement(aKeyPair.Public);
 
diff --git a/crypto/test/src/test/DSATest.cs b/crypto/test/src/test/DSATest.cs
index a8b8bec3b..9ed1109e2 100644
--- a/crypto/test/src/test/DSATest.cs
+++ b/crypto/test/src/test/DSATest.cs
@@ -252,15 +252,9 @@ namespace Org.BouncyCastle.Tests
 
             SecureRandom k = FixedSecureRandom.From(kData);
 
-            ECCurve curve = new FpCurve(
-                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
-                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
-                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
-
-            ECDomainParameters spec = new ECDomainParameters(
-                curve,
-                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-                new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1");
+            ECCurve curve = x9.Curve;
+            ECDomainParameters spec = new ECDomainParameters(curve, x9.G, x9.N, x9.H);
 
             ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
                 "ECDSA",
@@ -330,17 +324,9 @@ namespace Org.BouncyCastle.Tests
 
             SecureRandom k = FixedSecureRandom.From(kData);
 
-            ECCurve curve = new F2mCurve(
-                239, // m
-                36, // k
-                new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
-                new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b
-
-            ECDomainParameters parameters = new ECDomainParameters(
-                curve,
-                curve.DecodePoint(Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
-                new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n
-                BigInteger.ValueOf(4)); // h
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("c2tnb239v1");
+            ECCurve curve = x9.Curve;
+            ECDomainParameters parameters = new ECDomainParameters(curve, x9.G, x9.N, x9.H);
 
             ECPrivateKeyParameters sKey = new ECPrivateKeyParameters(
                 "ECDSA",
@@ -435,17 +421,9 @@ namespace Org.BouncyCastle.Tests
 
             SecureRandom k = FixedSecureRandom.From(kData);
 
-            ECCurve curve = new F2mCurve(
-                239, // m
-                36, // k
-                new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
-                new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b
-
-            ECDomainParameters parameters = new ECDomainParameters(
-                curve,
-                curve.DecodePoint(Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
-                new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n
-                BigInteger.ValueOf(4)); // h
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("c2tnb239v1");
+            ECCurve curve = x9.Curve;
+            ECDomainParameters parameters = new ECDomainParameters(curve, x9.G, x9.N, x9.H);
 
             ECPrivateKeyParameters sKey = new ECPrivateKeyParameters(
                 new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d
@@ -554,15 +532,9 @@ namespace Org.BouncyCastle.Tests
             //
             s = SignerUtilities.GetSigner("ECDSA");
 
-            ECCurve curve = new FpCurve(
-                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
-                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
-                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
-
-            ECDomainParameters ecSpec = new ECDomainParameters(
-                curve,
-                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-                new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1");
+            ECCurve curve = x9.Curve;
+            ECDomainParameters ecSpec = new ECDomainParameters(curve, x9.G, x9.N, x9.H);
 
             g = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
             g.Init(new ECKeyGenerationParameters(ecSpec, rand));
@@ -594,17 +566,9 @@ namespace Org.BouncyCastle.Tests
             //
             s = SignerUtilities.GetSigner("ECDSA");
 
-            curve = new F2mCurve(
-                    239, // m
-                    36, // k
-                    new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
-                    new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b
-
-            ecSpec = new ECDomainParameters(
-                curve,
-                curve.DecodePoint(Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
-                new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n
-                BigInteger.ValueOf(4)); // h
+            x9 = ECNamedCurveTable.GetByName("c2tnb239v1");
+            curve = x9.Curve;
+            ecSpec = new ECDomainParameters(curve, x9.G, x9.N, x9.H);
 
             g = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
             g.Init(new ECKeyGenerationParameters(ecSpec, rand));
diff --git a/crypto/test/src/test/GOST3410Test.cs b/crypto/test/src/test/GOST3410Test.cs
index db232c5a1..03dcf3144 100644
--- a/crypto/test/src/test/GOST3410Test.cs
+++ b/crypto/test/src/test/GOST3410Test.cs
@@ -29,19 +29,21 @@ namespace Org.BouncyCastle.Tests
 
             SecureRandom k = FixedSecureRandom.From(kData);
 
-            BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p
+            BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041");
+            BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619");
 
             ECCurve curve = new FpCurve(
-                mod_p, // p
+                mod_p,
                 new BigInteger("7"), // a
-                new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414")); // b
+                new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b
+                mod_q, BigInteger.One);
 
             ECDomainParameters spec = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("2"),
                     new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")),
-                new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619")); // q
+                mod_q, BigInteger.One);
 
             ECPrivateKeyParameters sKey = new ECPrivateKeyParameters(
                 "ECGOST3410",
@@ -193,19 +195,21 @@ namespace Org.BouncyCastle.Tests
             s = SignerUtilities.GetSigner("ECGOST3410");
             g = GeneratorUtilities.GetKeyPairGenerator("ECGOST3410");
 
-            BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p
+            BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041");
+            BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619");
 
             ECCurve curve = new FpCurve(
-                mod_p, // p
+                mod_p,
                 new BigInteger("7"), // a
-                new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414")); // b
+                new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b
+                mod_q, BigInteger.One);
 
             ECDomainParameters ecSpec = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("2"),
                     new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")),
-                new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619")); // q
+                mod_q, BigInteger.One);
 
             g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
 
diff --git a/crypto/test/src/test/IESTest.cs b/crypto/test/src/test/IESTest.cs
index 193fe1ae9..99aacc66d 100644
--- a/crypto/test/src/test/IESTest.cs
+++ b/crypto/test/src/test/IESTest.cs
@@ -32,15 +32,8 @@ namespace Org.BouncyCastle.Tests
 		{
 			IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECIES");
 
-			ECCurve curve = new FpCurve(
-				new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
-				new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
-				new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
-
-			ECDomainParameters ecSpec = new ECDomainParameters(
-				curve,
-				curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-				new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1");
+            ECDomainParameters ecSpec = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H);
 
 			g.Init(
 				new ECKeyGenerationParameters(
diff --git a/crypto/test/src/test/MqvTest.cs b/crypto/test/src/test/MqvTest.cs
index ef36e1a23..b26d5619b 100644
--- a/crypto/test/src/test/MqvTest.cs
+++ b/crypto/test/src/test/MqvTest.cs
@@ -2,6 +2,7 @@ using System;
 
 using NUnit.Framework;
 
+using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
@@ -31,24 +32,10 @@ namespace Org.BouncyCastle.Tests
 		{
 			IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECMQV");
 
-//			EllipticCurve curve = new EllipticCurve(
-//				new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q
-//				new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
-//				new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
-			ECCurve curve = new FpCurve(
-				new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
-				new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
-				new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1");
+            ECDomainParameters ecSpec = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H);
 
-			ECDomainParameters ecSpec = new ECDomainParameters(
-				curve,
-//				ECPointUtil.DecodePoint(curve, Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-				curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-				new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
-				BigInteger.One); //1); // h
-
-//			g.initialize(ecSpec, new SecureRandom());
-			g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
+            g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
 			
 			//
 			// U side
diff --git a/crypto/test/src/test/PKCS10CertRequestTest.cs b/crypto/test/src/test/PKCS10CertRequestTest.cs
index 9bad0a678..ea27d5111 100644
--- a/crypto/test/src/test/PKCS10CertRequestTest.cs
+++ b/crypto/test/src/test/PKCS10CertRequestTest.cs
@@ -126,16 +126,9 @@ namespace Org.BouncyCastle.Tests
             string				algorithm,
             DerObjectIdentifier	algOid)
         {
-            FpCurve curve = new FpCurve(
-                new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p)
-                new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16),   // a
-                new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16));  // b
-
-            ECDomainParameters spec = new ECDomainParameters(
-                curve,
-//				curve.DecodePoint(Hex.Decode("02C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
-                curve.DecodePoint(Hex.Decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
-                new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("secp521r1");
+            ECCurve curve = x9.Curve;
+            ECDomainParameters spec = new ECDomainParameters(curve, x9.G, x9.N, x9.H);
 
             ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(
                 new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d
@@ -413,15 +406,9 @@ namespace Org.BouncyCastle.Tests
             // elliptic curve openSSL
             IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
 
-            ECCurve curve = new FpCurve(
-                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
-                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
-                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
-
-            ECDomainParameters ecSpec = new ECDomainParameters(
-                curve,
-                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
-                new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1");
+            ECCurve curve = x9.Curve;
+            ECDomainParameters ecSpec = new ECDomainParameters(curve, x9.G, x9.N, x9.H);
 
 //			g.initialize(ecSpec, new SecureRandom());
             g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
diff --git a/crypto/test/src/x509/test/TestCertificateGen.cs b/crypto/test/src/x509/test/TestCertificateGen.cs
index e91a102f1..24dbdf08f 100644
--- a/crypto/test/src/x509/test/TestCertificateGen.cs
+++ b/crypto/test/src/x509/test/TestCertificateGen.cs
@@ -5,6 +5,7 @@ using System.Text;
 using NUnit.Framework;
 
 using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Signers;
@@ -222,20 +223,14 @@ namespace Org.BouncyCastle.X509.Tests
             BigInteger ECPubQX = new BigInteger(Base64.Decode("HWWi17Yb+Bm3PYr/DMjLOYNFhyOwX1QY7ZvqqM+l"));
             BigInteger ECPubQY = new BigInteger(Base64.Decode("JrlJfxu3WGhqwtL/55BOs/wsUeiDFsvXcGhB8DGx"));
             BigInteger ECPrivD = new BigInteger(Base64.Decode("GYQmd/NF1B+He1iMkWt3by2Az6Eu07t0ynJ4YCAo"));
-            FpCurve curve = new FpCurve(
-               new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
-                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
-                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
-            ECDomainParameters ecDomain =
-                new ECDomainParameters(curve, new FpPoint(curve, curve.FromBigInteger(ECParraGX), curve.FromBigInteger(ECParraGY)), ECParraN);
-            ECPublicKeyParameters ecPub = new ECPublicKeyParameters(
-				"ECDSA",
-				new FpPoint(curve,
-					curve.FromBigInteger(ECPubQX),
-					curve.FromBigInteger(ECPubQY)),
-				ecDomain);
-            ECPrivateKeyParameters ecPriv = new ECPrivateKeyParameters("ECDSA", ECPrivD, ecDomain);
 
+            X9ECParameters x9 = ECNamedCurveTable.GetByName("prime239v1");
+            ECCurve curve = x9.Curve;
+            ECDomainParameters ecDomain = new ECDomainParameters(curve, curve.ValidatePoint(ECParraGX, ECParraGY), ECParraN, ECParraH);
+
+            ECPublicKeyParameters ecPub = new ECPublicKeyParameters("ECDSA",
+                curve.ValidatePoint(ECPubQX, ECPubQY), ecDomain);
+            ECPrivateKeyParameters ecPriv = new ECPrivateKeyParameters("ECDSA", ECPrivD, ecDomain);
 
             IDictionary attrs = new Hashtable();
 			attrs[X509Name.C] = "AU";