summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2019-08-09 17:08:48 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2019-08-09 17:08:48 +0700
commitac5ab976832d3d6e107502acd318f9fe3b12e547 (patch)
treed594b09d80bd74705d23e011a43f8fc8fda87904
parentASN.1 updates from bc-java (diff)
downloadBouncyCastle.NET-ed25519-ac5ab976832d3d6e107502acd318f9fe3b12e547.tar.xz
Add non-constant-time variant to ECLookupTable
-rw-r--r--crypto/BouncyCastle.Android.csproj1
-rw-r--r--crypto/BouncyCastle.csproj1
-rw-r--r--crypto/BouncyCastle.iOS.csproj1
-rw-r--r--crypto/crypto.csproj5
-rw-r--r--crypto/src/math/ec/AbstractECLookupTable.cs16
-rw-r--r--crypto/src/math/ec/ECAlgorithms.cs4
-rw-r--r--crypto/src/math/ec/ECCurve.cs58
-rw-r--r--crypto/src/math/ec/ECLookupTable.cs1
-rw-r--r--crypto/src/math/ec/SimpleLookupTable.cs11
-rw-r--r--crypto/src/math/ec/custom/djb/Curve25519.cs43
-rw-r--r--crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecP128R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160K1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R2Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192K1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224K1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256K1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecP384R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecP521R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113R2Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131R2Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163K1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163R2Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT193R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT193R2Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233K1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT239K1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283K1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409K1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409R1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571K1Curve.cs28
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571R1Curve.cs28
41 files changed, 860 insertions, 149 deletions
diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj
index c1c53fc52..f30b48433 100644
--- a/crypto/BouncyCastle.Android.csproj
+++ b/crypto/BouncyCastle.Android.csproj
@@ -1218,6 +1218,7 @@
     <Compile Include="src\crypto\util\Pack.cs" />
     <Compile Include="src\math\BigInteger.cs" />
     <Compile Include="src\math\Primes.cs" />
+    <Compile Include="src\math\ec\AbstractECLookupTable.cs" />
     <Compile Include="src\math\ec\ECAlgorithms.cs" />
     <Compile Include="src\math\ec\ECCurve.cs" />
     <Compile Include="src\math\ec\ECFieldElement.cs" />
diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj
index 3ba21ac66..be84564e2 100644
--- a/crypto/BouncyCastle.csproj
+++ b/crypto/BouncyCastle.csproj
@@ -1212,6 +1212,7 @@
     <Compile Include="src\crypto\util\Pack.cs" />
     <Compile Include="src\math\BigInteger.cs" />
     <Compile Include="src\math\Primes.cs" />
+    <Compile Include="src\math\ec\AbstractECLookupTable.cs" />
     <Compile Include="src\math\ec\ECAlgorithms.cs" />
     <Compile Include="src\math\ec\ECCurve.cs" />
     <Compile Include="src\math\ec\ECFieldElement.cs" />
diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj
index b6810009b..53e8a5b00 100644
--- a/crypto/BouncyCastle.iOS.csproj
+++ b/crypto/BouncyCastle.iOS.csproj
@@ -1213,6 +1213,7 @@
     <Compile Include="src\crypto\util\Pack.cs" />
     <Compile Include="src\math\BigInteger.cs" />
     <Compile Include="src\math\Primes.cs" />
+    <Compile Include="src\math\ec\AbstractECLookupTable.cs" />
     <Compile Include="src\math\ec\ECAlgorithms.cs" />
     <Compile Include="src\math\ec\ECCurve.cs" />
     <Compile Include="src\math\ec\ECFieldElement.cs" />
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 7789d1858..ca6dba5ff 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -5949,6 +5949,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\math\ec\AbstractECLookupTable.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\math\ec\ECAlgorithms.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/math/ec/AbstractECLookupTable.cs b/crypto/src/math/ec/AbstractECLookupTable.cs
new file mode 100644
index 000000000..fbd272d0c
--- /dev/null
+++ b/crypto/src/math/ec/AbstractECLookupTable.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC
+{
+    public abstract class AbstractECLookupTable
+        : ECLookupTable
+    {
+        public abstract ECPoint Lookup(int index);
+        public abstract int Size { get; }
+
+        public virtual ECPoint LookupVar(int index)
+        {
+            return Lookup(index);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/ECAlgorithms.cs b/crypto/src/math/ec/ECAlgorithms.cs
index 8b7184006..4976b73b0 100644
--- a/crypto/src/math/ec/ECAlgorithms.cs
+++ b/crypto/src/math/ec/ECAlgorithms.cs
@@ -586,8 +586,8 @@ namespace Org.BouncyCastle.Math.EC
                     secretIndexL ^= secretBitL;
                 }
 
-                ECPoint addP = lookupTableP.Lookup((int)secretIndexK);
-                ECPoint addQ = lookupTableQ.Lookup((int)secretIndexL);
+                ECPoint addP = lookupTableP.LookupVar((int)secretIndexK);
+                ECPoint addQ = lookupTableQ.LookupVar((int)secretIndexL);
 
                 ECPoint T = addP.Add(addQ);
 
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index 5b9b39c10..60fbc887a 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -521,7 +521,7 @@ namespace Org.BouncyCastle.Math.EC
         }
 
         private class DefaultLookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly ECCurve m_outer;
             private readonly byte[] m_table;
@@ -534,12 +534,12 @@ namespace Org.BouncyCastle.Math.EC
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 int FE_BYTES = (m_outer.FieldSize + 7) / 8;
                 byte[] x = new byte[FE_BYTES], y = new byte[FE_BYTES];
@@ -558,6 +558,26 @@ namespace Org.BouncyCastle.Math.EC
                     pos += (FE_BYTES * 2);
                 }
 
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                int FE_BYTES = (m_outer.FieldSize + 7) / 8;
+                byte[] x = new byte[FE_BYTES], y = new byte[FE_BYTES];
+                int pos = index * FE_BYTES * 2;
+
+                for (int j = 0; j < FE_BYTES; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + FE_BYTES + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(byte[] x, byte[] y)
+            {
                 ECFieldElement X = m_outer.FromBigInteger(new BigInteger(1, x));
                 ECFieldElement Y = m_outer.FromBigInteger(new BigInteger(1, y));
                 return m_outer.CreateRawPoint(X, Y, false);
@@ -1251,7 +1271,7 @@ namespace Org.BouncyCastle.Math.EC
         }
 
         private class DefaultF2mLookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly F2mCurve m_outer;
             private readonly long[] m_table;
@@ -1264,16 +1284,13 @@ namespace Org.BouncyCastle.Math.EC
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
-                int m = m_outer.m;
-                int[] ks = m_outer.IsTrinomial() ? new int[]{ m_outer.k1 } : new int[]{ m_outer.k1, m_outer.k2, m_outer.k3 }; 
-
                 int FE_LONGS = (m_outer.m + 63) / 64;
                 long[] x = new long[FE_LONGS], y = new long[FE_LONGS];
                 int pos = 0;
@@ -1291,6 +1308,29 @@ namespace Org.BouncyCastle.Math.EC
                     pos += (FE_LONGS * 2);
                 }
 
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                int FE_LONGS = (m_outer.m + 63) / 64;
+                long[] x = new long[FE_LONGS], y = new long[FE_LONGS];
+                int pos = index * FE_LONGS * 2;
+
+                for (int j = 0; j < FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(long[] x, long[] y)
+            {
+                int m = m_outer.m;
+                int[] ks = m_outer.IsTrinomial() ? new int[] { m_outer.k1 } : new int[] { m_outer.k1, m_outer.k2, m_outer.k3 }; 
+
                 ECFieldElement X = new F2mFieldElement(m, ks, new LongArray(x));
                 ECFieldElement Y = new F2mFieldElement(m, ks, new LongArray(y));
                 return m_outer.CreateRawPoint(X, Y, false);
diff --git a/crypto/src/math/ec/ECLookupTable.cs b/crypto/src/math/ec/ECLookupTable.cs
index 35995d426..c14087d3b 100644
--- a/crypto/src/math/ec/ECLookupTable.cs
+++ b/crypto/src/math/ec/ECLookupTable.cs
@@ -6,5 +6,6 @@ namespace Org.BouncyCastle.Math.EC
     {
         int Size { get; }
         ECPoint Lookup(int index);
+        ECPoint LookupVar(int index);
     }
 }
diff --git a/crypto/src/math/ec/SimpleLookupTable.cs b/crypto/src/math/ec/SimpleLookupTable.cs
index f1e32f215..ed300baaa 100644
--- a/crypto/src/math/ec/SimpleLookupTable.cs
+++ b/crypto/src/math/ec/SimpleLookupTable.cs
@@ -3,7 +3,7 @@
 namespace Org.BouncyCastle.Math.EC
 {
     public class SimpleLookupTable
-        : ECLookupTable
+        : AbstractECLookupTable
     {
         private static ECPoint[] Copy(ECPoint[] points, int off, int len)
         {
@@ -22,12 +22,17 @@ namespace Org.BouncyCastle.Math.EC
             this.points = Copy(points, off, len);
         }
 
-        public virtual int Size
+        public override int Size
         {
             get { return points.Length; }
         }
 
-        public virtual ECPoint Lookup(int index)
+        public override ECPoint Lookup(int index)
+        {
+            throw new NotSupportedException("Constant-time lookup not supported");
+        }
+
+        public override ECPoint LookupVar(int index)
         {
             return points[index];
         }
diff --git a/crypto/src/math/ec/custom/djb/Curve25519.cs b/crypto/src/math/ec/custom/djb/Curve25519.cs
index c0f911a9c..f64eed244 100644
--- a/crypto/src/math/ec/custom/djb/Curve25519.cs
+++ b/crypto/src/math/ec/custom/djb/Curve25519.cs
@@ -10,9 +10,13 @@ namespace Org.BouncyCastle.Math.EC.Custom.Djb
     {
         public static readonly BigInteger q = Nat256.ToBigInteger(Curve25519Field.P);
 
-        private const int Curve25519_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
-        private const int CURVE25519_FE_INTS = 8;
+        private static readonly BigInteger C_a = new BigInteger(1, Hex.Decode("2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA984914A144"));
+        private static readonly BigInteger C_b = new BigInteger(1, Hex.Decode("7B425ED097B425ED097B425ED097B425ED097B425ED097B4260B5E9C7710C864"));
 
+        private const int CURVE25519_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
+        private const int CURVE25519_FE_INTS = 8;
+        private static readonly ECFieldElement[] CURVE25519_AFFINE_ZS = new ECFieldElement[] {
+            new Curve25519FieldElement(BigInteger.One), new Curve25519FieldElement(C_a) }; 
         protected readonly Curve25519Point m_infinity;
 
         public Curve25519()
@@ -20,13 +24,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Djb
         {
             this.m_infinity = new Curve25519Point(this, null, null);
 
-            this.m_a = FromBigInteger(new BigInteger(1,
-                Hex.Decode("2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA984914A144")));
-            this.m_b = FromBigInteger(new BigInteger(1,
-                Hex.Decode("7B425ED097B425ED097B425ED097B425ED097B425ED097B4260B5E9C7710C864")));
+            this.m_a = FromBigInteger(C_a);
+            this.m_b = FromBigInteger(C_b);
             this.m_order = new BigInteger(1, Hex.Decode("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"));
             this.m_cofactor = BigInteger.ValueOf(8);
-            this.m_coord = Curve25519_DEFAULT_COORDS;
+            this.m_coord = CURVE25519_DEFAULT_COORDS;
         }
 
         protected override ECCurve CloneCurve()
@@ -92,7 +94,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Djb
         }
 
         private class Curve25519LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly Curve25519 m_outer;
             private readonly uint[] m_table;
@@ -105,12 +107,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Djb
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat256.Create(), y = Nat256.Create();
                 int pos = 0;
@@ -128,7 +130,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Djb
                     pos += (CURVE25519_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new Curve25519FieldElement(x), new Curve25519FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat256.Create(), y = Nat256.Create();
+                int pos = index * CURVE25519_FE_INTS * 2;
+
+                for (int j = 0; j < CURVE25519_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + CURVE25519_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new Curve25519FieldElement(x), new Curve25519FieldElement(y), CURVE25519_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs b/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs
index 2c5d8f3a3..86c8efaf7 100644
--- a/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs
+++ b/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs
@@ -13,6 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.GM
 
         private const int SM2P256V1_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SM2P256V1_FE_INTS = 8;
+        private static readonly ECFieldElement[] SM2P256V1_AFFINE_ZS = new ECFieldElement[] { new SM2P256V1FieldElement(BigInteger.One) }; 
 
         protected readonly SM2P256V1Point m_infinity;
 
@@ -93,7 +94,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.GM
         }
 
         private class SM2P256V1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SM2P256V1Curve m_outer;
             private readonly uint[] m_table;
@@ -106,12 +107,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.GM
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat256.Create(), y = Nat256.Create();
                 int pos = 0;
@@ -129,7 +130,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.GM
                     pos += (SM2P256V1_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SM2P256V1FieldElement(x), new SM2P256V1FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat256.Create(), y = Nat256.Create();
+                int pos = index * SM2P256V1_FE_INTS * 2;
+
+                for (int j = 0; j < SM2P256V1_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SM2P256V1_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SM2P256V1FieldElement(x), new SM2P256V1FieldElement(y), SM2P256V1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs
index cc50f50d2..ffe40581f 100644
--- a/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs
@@ -13,6 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private const int SECP128R1_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SECP128R1_FE_INTS = 4;
+        private static readonly ECFieldElement[] SECP128R1_AFFINE_ZS = new ECFieldElement[] { new SecP128R1FieldElement(BigInteger.One) }; 
 
         protected readonly SecP128R1Point m_infinity;
 
@@ -94,7 +95,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecP128R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecP128R1Curve m_outer;
             private readonly uint[] m_table;
@@ -107,12 +108,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat128.Create(), y = Nat128.Create();
                 int pos = 0;
@@ -130,7 +131,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECP128R1_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecP128R1FieldElement(x), new SecP128R1FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat128.Create(), y = Nat128.Create();
+                int pos = index * SECP128R1_FE_INTS * 2;
+
+                for (int j = 0; j < SECP128R1_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECP128R1_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SecP128R1FieldElement(x), new SecP128R1FieldElement(y), SECP128R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs
index 234c86b87..4bacd55c6 100644
--- a/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs
@@ -12,6 +12,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private const int SECP160K1_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SECP160K1_FE_INTS = 5;
+        private static readonly ECFieldElement[] SECP160K1_AFFINE_ZS = new ECFieldElement[] { new SecP160R2FieldElement(BigInteger.One) };
 
         protected readonly SecP160K1Point m_infinity;
 
@@ -90,7 +91,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecP160K1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecP160K1Curve m_outer;
             private readonly uint[] m_table;
@@ -103,12 +104,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat256.Create(), y = Nat256.Create();
                 int pos = 0;
@@ -126,7 +127,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECP160K1_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecP160R2FieldElement(x), new SecP160R2FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat256.Create(), y = Nat256.Create();
+                int pos = index * SECP160K1_FE_INTS * 2;
+
+                for (int j = 0; j < SECP160K1_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECP160K1_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SecP160R2FieldElement(x), new SecP160R2FieldElement(y), SECP160K1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs
index 958eb2765..c48edaf7c 100644
--- a/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs
@@ -13,6 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private const int SECP160R1_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SECP160R1_FE_INTS = 5;
+        private static readonly ECFieldElement[] SECP160R1_AFFINE_ZS = new ECFieldElement[] { new SecP160R1FieldElement(BigInteger.One) }; 
 
         protected readonly SecP160R1Point m_infinity;
 
@@ -94,7 +95,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecP160R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecP160R1Curve m_outer;
             private readonly uint[] m_table;
@@ -107,12 +108,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat160.Create(), y = Nat160.Create();
                 int pos = 0;
@@ -130,7 +131,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECP160R1_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecP160R1FieldElement(x), new SecP160R1FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat160.Create(), y = Nat160.Create();
+                int pos = index * SECP160R1_FE_INTS * 2;
+
+                for (int j = 0; j < SECP160R1_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECP160R1_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SecP160R1FieldElement(x), new SecP160R1FieldElement(y), SECP160R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs b/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs
index 252312e62..ecc836671 100644
--- a/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs
@@ -13,6 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private const int SECP160R2_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SECP160R2_FE_INTS = 5;
+        private static readonly ECFieldElement[] SECP160R2_AFFINE_ZS = new ECFieldElement[] { new SecP160R2FieldElement(BigInteger.One) };
 
         protected readonly SecP160R2Point m_infinity;
 
@@ -94,7 +95,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecP160R2LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecP160R2Curve m_outer;
             private readonly uint[] m_table;
@@ -107,12 +108,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat160.Create(), y = Nat160.Create();
                 int pos = 0;
@@ -130,7 +131,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECP160R2_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecP160R2FieldElement(x), new SecP160R2FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat160.Create(), y = Nat160.Create();
+                int pos = index * SECP160R2_FE_INTS * 2;
+
+                for (int j = 0; j < SECP160R2_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECP160R2_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SecP160R2FieldElement(x), new SecP160R2FieldElement(y), SECP160R2_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
index 518e0a131..62e253dc5 100644
--- a/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
@@ -13,6 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private const int SECP192K1_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SECP192K1_FE_INTS = 6;
+        private static readonly ECFieldElement[] SECP192K1_AFFINE_ZS = new ECFieldElement[] { new SecP192K1FieldElement(BigInteger.One) };
 
         protected readonly SecP192K1Point m_infinity;
 
@@ -91,7 +92,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecP192K1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecP192K1Curve m_outer;
             private readonly uint[] m_table;
@@ -104,12 +105,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat192.Create(), y = Nat192.Create();
                 int pos = 0;
@@ -127,7 +128,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECP192K1_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecP192K1FieldElement(x), new SecP192K1FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat192.Create(), y = Nat192.Create();
+                int pos = index * SECP192K1_FE_INTS * 2;
+
+                for (int j = 0; j < SECP192K1_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECP192K1_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SecP192K1FieldElement(x), new SecP192K1FieldElement(y), SECP192K1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
index 91d31932a..8b9042627 100644
--- a/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
@@ -13,6 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private const int SECP192R1_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SECP192R1_FE_INTS = 6;
+        private static readonly ECFieldElement[] SECP192R1_AFFINE_ZS = new ECFieldElement[] { new SecP192R1FieldElement(BigInteger.One) };
 
         protected readonly SecP192R1Point m_infinity;
 
@@ -94,7 +95,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecP192R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecP192R1Curve m_outer;
             private readonly uint[] m_table;
@@ -107,12 +108,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat192.Create(), y = Nat192.Create();
                 int pos = 0;
@@ -130,7 +131,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECP192R1_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecP192R1FieldElement(x), new SecP192R1FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat192.Create(), y = Nat192.Create();
+                int pos = index * SECP192R1_FE_INTS * 2;
+
+                for (int j = 0; j < SECP192R1_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECP192R1_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SecP192R1FieldElement(x), new SecP192R1FieldElement(y), SECP192R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
index a9c55090f..859cb8526 100644
--- a/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
@@ -13,6 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private const int SECP224K1_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SECP224K1_FE_INTS = 7;
+        private static readonly ECFieldElement[] SECP224K1_AFFINE_ZS = new ECFieldElement[] { new SecP224K1FieldElement(BigInteger.One) };
 
         protected readonly SecP224K1Point m_infinity;
 
@@ -91,7 +92,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecP224K1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecP224K1Curve m_outer;
             private readonly uint[] m_table;
@@ -104,12 +105,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat224.Create(), y = Nat224.Create();
                 int pos = 0;
@@ -127,7 +128,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECP224K1_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecP224K1FieldElement(x), new SecP224K1FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat224.Create(), y = Nat224.Create();
+                int pos = index * SECP224K1_FE_INTS * 2;
+
+                for (int j = 0; j < SECP224K1_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECP224K1_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SecP224K1FieldElement(x), new SecP224K1FieldElement(y), SECP224K1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
index ec34390aa..bb63ebf5e 100644
--- a/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
@@ -13,6 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private const int SECP224R1_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SECP224R1_FE_INTS = 7;
+        private static readonly ECFieldElement[] SECP224R1_AFFINE_ZS = new ECFieldElement[] { new SecP224R1FieldElement(BigInteger.One) };
 
         protected readonly SecP224R1Point m_infinity;
 
@@ -94,7 +95,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecP224R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecP224R1Curve m_outer;
             private readonly uint[] m_table;
@@ -107,12 +108,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat224.Create(), y = Nat224.Create();
                 int pos = 0;
@@ -130,7 +131,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECP224R1_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecP224R1FieldElement(x), new SecP224R1FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat224.Create(), y = Nat224.Create();
+                int pos = index * SECP224R1_FE_INTS * 2;
+
+                for (int j = 0; j < SECP224R1_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECP224R1_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SecP224R1FieldElement(x), new SecP224R1FieldElement(y), SECP224R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
index b3a5dd646..bdda5a1b9 100644
--- a/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
@@ -13,6 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private const int SECP256K1_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SECP256K1_FE_INTS = 8;
+        private static readonly ECFieldElement[] SECP256K1_AFFINE_ZS = new ECFieldElement[] { new SecP256K1FieldElement(BigInteger.One) };
 
         protected readonly SecP256K1Point m_infinity;
 
@@ -91,7 +92,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecP256K1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecP256K1Curve m_outer;
             private readonly uint[] m_table;
@@ -104,12 +105,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat256.Create(), y = Nat256.Create();
                 int pos = 0;
@@ -127,7 +128,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECP256K1_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecP256K1FieldElement(x), new SecP256K1FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat256.Create(), y = Nat256.Create();
+                int pos = index * SECP256K1_FE_INTS * 2;
+
+                for (int j = 0; j < SECP256K1_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECP256K1_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SecP256K1FieldElement(x), new SecP256K1FieldElement(y), SECP256K1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
index 2d9a88b72..24341e613 100644
--- a/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
@@ -13,6 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private const int SECP256R1_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SECP256R1_FE_INTS = 8;
+        private static readonly ECFieldElement[] SECP256R1_AFFINE_ZS = new ECFieldElement[] { new SecP256R1FieldElement(BigInteger.One) }; 
 
         protected readonly SecP256R1Point m_infinity;
 
@@ -93,7 +94,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecP256R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecP256R1Curve m_outer;
             private readonly uint[] m_table;
@@ -106,12 +107,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat256.Create(), y = Nat256.Create();
                 int pos = 0;
@@ -129,7 +130,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECP256R1_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecP256R1FieldElement(x), new SecP256R1FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat256.Create(), y = Nat256.Create();
+                int pos = index * SECP256R1_FE_INTS * 2;
+
+                for (int j = 0; j < SECP256R1_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECP256R1_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SecP256R1FieldElement(x), new SecP256R1FieldElement(y), SECP256R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
index 26b057198..ac1855945 100644
--- a/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
@@ -13,6 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private const int SECP384R1_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SECP384R1_FE_INTS = 12;
+        private static readonly ECFieldElement[] SECP384R1_AFFINE_ZS = new ECFieldElement[] { new SecP384R1FieldElement(BigInteger.One) };
 
         protected readonly SecP384R1Point m_infinity;
 
@@ -93,7 +94,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecP384R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecP384R1Curve m_outer;
             private readonly uint[] m_table;
@@ -106,12 +107,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat.Create(SECP384R1_FE_INTS), y = Nat.Create(SECP384R1_FE_INTS);
                 int pos = 0;
@@ -129,7 +130,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECP384R1_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecP384R1FieldElement(x), new SecP384R1FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat.Create(SECP384R1_FE_INTS), y = Nat.Create(SECP384R1_FE_INTS);
+                int pos = index * SECP384R1_FE_INTS * 2;
+
+                for (int j = 0; j < SECP384R1_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECP384R1_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SecP384R1FieldElement(x), new SecP384R1FieldElement(y), SECP384R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
index 810be85b5..0841fb8a5 100644
--- a/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
@@ -13,6 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private const int SECP521R1_DEFAULT_COORDS = COORD_JACOBIAN;
         private const int SECP521R1_FE_INTS = 17;
+        private static readonly ECFieldElement[] SECP521R1_AFFINE_ZS = new ECFieldElement[] { new SecP521R1FieldElement(BigInteger.One) };
 
         protected readonly SecP521R1Point m_infinity;
 
@@ -93,7 +94,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecP521R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecP521R1Curve m_outer;
             private readonly uint[] m_table;
@@ -106,12 +107,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 uint[] x = Nat.Create(SECP521R1_FE_INTS), y = Nat.Create(SECP521R1_FE_INTS);
                 int pos = 0;
@@ -129,7 +130,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECP521R1_FE_INTS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecP521R1FieldElement(x), new SecP521R1FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                uint[] x = Nat.Create(SECP521R1_FE_INTS), y = Nat.Create(SECP521R1_FE_INTS);
+                int pos = index * SECP521R1_FE_INTS * 2;
+
+                for (int j = 0; j < SECP521R1_FE_INTS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECP521R1_FE_INTS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(uint[] x, uint[] y)
+            {
+                return m_outer.CreateRawPoint(new SecP521R1FieldElement(x), new SecP521R1FieldElement(y), SECP521R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
index e85f68e60..ea9ea0b0c 100644
--- a/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT113R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT113R1_FE_LONGS = 2;
+        private static readonly ECFieldElement[] SECT113R1_AFFINE_ZS = new ECFieldElement[] { new SecT113FieldElement(BigInteger.One) };
 
         protected readonly SecT113R1Point m_infinity;
 
@@ -114,7 +115,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT113R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT113R1Curve m_outer;
             private readonly ulong[] m_table;
@@ -127,12 +128,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat128.Create64(), y = Nat128.Create64();
                 int pos = 0;
@@ -150,7 +151,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT113R1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT113FieldElement(x), new SecT113FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat128.Create64(), y = Nat128.Create64();
+                int pos = index * SECT113R1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT113R1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT113R1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT113FieldElement(x), new SecT113FieldElement(y), SECT113R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
index efe422806..84b20e026 100644
--- a/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT113R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT113R2_FE_LONGS = 2;
+        private static readonly ECFieldElement[] SECT113R2_AFFINE_ZS = new ECFieldElement[] { new SecT113FieldElement(BigInteger.One) };
 
         protected readonly SecT113R2Point m_infinity;
 
@@ -114,7 +115,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT113R2LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT113R2Curve m_outer;
             private readonly ulong[] m_table;
@@ -127,12 +128,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat128.Create64(), y = Nat128.Create64();
                 int pos = 0;
@@ -150,7 +151,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT113R2_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT113FieldElement(x), new SecT113FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat128.Create64(), y = Nat128.Create64();
+                int pos = index * SECT113R2_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT113R2_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT113R2_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT113FieldElement(x), new SecT113FieldElement(y), SECT113R2_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
index 06f0a79ae..1a8c01670 100644
--- a/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT131R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT131R1_FE_LONGS = 3;
+        private static readonly ECFieldElement[] SECT131R1_AFFINE_ZS = new ECFieldElement[] { new SecT131FieldElement(BigInteger.One) };
 
         protected readonly SecT131R1Point m_infinity;
 
@@ -114,7 +115,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT131R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT131R1Curve m_outer;
             private readonly ulong[] m_table;
@@ -127,12 +128,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat192.Create64(), y = Nat192.Create64();
                 int pos = 0;
@@ -150,7 +151,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT131R1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT131FieldElement(x), new SecT131FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat192.Create64(), y = Nat192.Create64();
+                int pos = index * SECT131R1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT131R1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT131R1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT131FieldElement(x), new SecT131FieldElement(y), SECT131R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
index 0120b3059..4a90a74f3 100644
--- a/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT131R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT131R2_FE_LONGS = 3;
+        private static readonly ECFieldElement[] SECT131R2_AFFINE_ZS = new ECFieldElement[] { new SecT131FieldElement(BigInteger.One) };
 
         protected readonly SecT131R2Point m_infinity;
 
@@ -114,7 +115,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT131R2LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT131R2Curve m_outer;
             private readonly ulong[] m_table;
@@ -127,12 +128,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat192.Create64(), y = Nat192.Create64();
                 int pos = 0;
@@ -150,7 +151,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT131R2_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT131FieldElement(x), new SecT131FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat192.Create64(), y = Nat192.Create64();
+                int pos = index * SECT131R2_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT131R2_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT131R2_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT131FieldElement(x), new SecT131FieldElement(y), SECT131R2_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
index 5e1431f46..6cdb7bdd6 100644
--- a/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
@@ -11,6 +11,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT163K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT163K1_FE_LONGS = 3;
+        private static readonly ECFieldElement[] SECT163K1_AFFINE_ZS = new ECFieldElement[] { new SecT163FieldElement(BigInteger.One) };
 
         protected readonly SecT163K1Point m_infinity;
 
@@ -120,7 +121,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT163K1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT163K1Curve m_outer;
             private readonly ulong[] m_table;
@@ -133,12 +134,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat192.Create64(), y = Nat192.Create64();
                 int pos = 0;
@@ -156,7 +157,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT163K1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat192.Create64(), y = Nat192.Create64();
+                int pos = index * SECT163K1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT163K1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT163K1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), SECT163K1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
index e212ad4ea..bee0d3c80 100644
--- a/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT163R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT163R1_FE_LONGS = 3;
+        private static readonly ECFieldElement[] SECT163R1_AFFINE_ZS = new ECFieldElement[] { new SecT163FieldElement(BigInteger.One) };
 
         protected readonly SecT163R1Point m_infinity;
 
@@ -114,7 +115,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT163R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT163R1Curve m_outer;
             private readonly ulong[] m_table;
@@ -127,12 +128,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat192.Create64(), y = Nat192.Create64();
                 int pos = 0;
@@ -150,7 +151,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT163R1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat192.Create64(), y = Nat192.Create64();
+                int pos = index * SECT163R1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT163R1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT163R1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), SECT163R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
index b0365388a..35e91ddf1 100644
--- a/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT163R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT163R2_FE_LONGS = 3;
+        private static readonly ECFieldElement[] SECT163R2_AFFINE_ZS = new ECFieldElement[] { new SecT163FieldElement(BigInteger.One) };
 
         protected readonly SecT163R2Point m_infinity;
 
@@ -114,7 +115,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT163R2LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT163R2Curve m_outer;
             private readonly ulong[] m_table;
@@ -127,12 +128,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat192.Create64(), y = Nat192.Create64();
                 int pos = 0;
@@ -150,7 +151,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT163R2_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat192.Create64(), y = Nat192.Create64();
+                int pos = index * SECT163R2_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT163R2_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT163R2_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), SECT163R2_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs
index e6cb3b4d8..8ba83689e 100644
--- a/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT193R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT193R1_FE_LONGS = 4;
+        private static readonly ECFieldElement[] SECT193R1_AFFINE_ZS = new ECFieldElement[] { new SecT193FieldElement(BigInteger.One) };
 
         protected readonly SecT193R1Point m_infinity;
 
@@ -114,7 +115,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT193R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT193R1Curve m_outer;
             private readonly ulong[] m_table;
@@ -127,12 +128,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat256.Create64(), y = Nat256.Create64();
                 int pos = 0;
@@ -150,7 +151,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT193R1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT193FieldElement(x), new SecT193FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat256.Create64(), y = Nat256.Create64();
+                int pos = index * SECT193R1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT193R1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT193R1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT193FieldElement(x), new SecT193FieldElement(y), SECT193R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs
index cfd690c65..46790e7e4 100644
--- a/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT193R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT193R2_FE_LONGS = 4;
+        private static readonly ECFieldElement[] SECT193R2_AFFINE_ZS = new ECFieldElement[] { new SecT193FieldElement(BigInteger.One) };
 
         protected readonly SecT193R2Point m_infinity;
 
@@ -114,7 +115,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT193R2LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT193R2Curve m_outer;
             private readonly ulong[] m_table;
@@ -127,12 +128,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat256.Create64(), y = Nat256.Create64();
                 int pos = 0;
@@ -150,7 +151,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT193R2_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT193FieldElement(x), new SecT193FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat256.Create64(), y = Nat256.Create64();
+                int pos = index * SECT193R2_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT193R2_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT193R2_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT193FieldElement(x), new SecT193FieldElement(y), SECT193R2_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
index 07eae1564..c01247446 100644
--- a/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
@@ -11,6 +11,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT233K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT233K1_FE_LONGS = 4;
+        private static readonly ECFieldElement[] SECT233K1_AFFINE_ZS = new ECFieldElement[] { new SecT233FieldElement(BigInteger.One) };
 
         protected readonly SecT233K1Point m_infinity;
 
@@ -120,7 +121,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT233K1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT233K1Curve m_outer;
             private readonly ulong[] m_table;
@@ -133,12 +134,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat256.Create64(), y = Nat256.Create64();
                 int pos = 0;
@@ -156,7 +157,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT233K1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT233FieldElement(x), new SecT233FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat256.Create64(), y = Nat256.Create64();
+                int pos = index * SECT233K1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT233K1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT233K1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT233FieldElement(x), new SecT233FieldElement(y), SECT233K1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
index 5e8dee875..a5d3b86fd 100644
--- a/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT233R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT233R1_FE_LONGS = 4;
+        private static readonly ECFieldElement[] SECT233R1_AFFINE_ZS = new ECFieldElement[] { new SecT233FieldElement(BigInteger.One) };
 
         protected readonly SecT233R1Point m_infinity;
 
@@ -114,7 +115,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT233R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT233R1Curve m_outer;
             private readonly ulong[] m_table;
@@ -127,12 +128,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat256.Create64(), y = Nat256.Create64();
                 int pos = 0;
@@ -150,7 +151,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT233R1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT233FieldElement(x), new SecT233FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat256.Create64(), y = Nat256.Create64();
+                int pos = index * SECT233R1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT233R1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT233R1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT233FieldElement(x), new SecT233FieldElement(y), SECT233R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
index 33792e631..5748942e2 100644
--- a/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
@@ -11,6 +11,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT239K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT239K1_FE_LONGS = 4;
+        private static readonly ECFieldElement[] SECT239K1_AFFINE_ZS = new ECFieldElement[] { new SecT239FieldElement(BigInteger.One) };
 
         protected readonly SecT239K1Point m_infinity;
 
@@ -120,7 +121,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT239K1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT239K1Curve m_outer;
             private readonly ulong[] m_table;
@@ -133,12 +134,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat256.Create64(), y = Nat256.Create64();
                 int pos = 0;
@@ -156,7 +157,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT239K1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT239FieldElement(x), new SecT239FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat256.Create64(), y = Nat256.Create64();
+                int pos = index * SECT239K1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT239K1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT239K1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT239FieldElement(x), new SecT239FieldElement(y), SECT239K1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
index 51725bc20..e97a0f01d 100644
--- a/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
@@ -11,6 +11,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT283K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT283K1_FE_LONGS = 5;
+        private static readonly ECFieldElement[] SECT283K1_AFFINE_ZS = new ECFieldElement[] { new SecT283FieldElement(BigInteger.One) };
 
         protected readonly SecT283K1Point m_infinity;
 
@@ -120,7 +121,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT283K1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT283K1Curve m_outer;
             private readonly ulong[] m_table;
@@ -133,12 +134,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat320.Create64(), y = Nat320.Create64();
                 int pos = 0;
@@ -156,7 +157,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT283K1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT283FieldElement(x), new SecT283FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat320.Create64(), y = Nat320.Create64();
+                int pos = index * SECT283K1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT283K1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT283K1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT283FieldElement(x), new SecT283FieldElement(y), SECT283K1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
index 567df7686..a8a50c22a 100644
--- a/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT283R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT283R1_FE_LONGS = 5;
+        private static readonly ECFieldElement[] SECT283R1_AFFINE_ZS = new ECFieldElement[] { new SecT283FieldElement(BigInteger.One) };
 
         protected readonly SecT283R1Point m_infinity;
 
@@ -114,7 +115,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT283R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT283R1Curve m_outer;
             private readonly ulong[] m_table;
@@ -127,12 +128,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat320.Create64(), y = Nat320.Create64();
                 int pos = 0;
@@ -150,7 +151,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT283R1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT283FieldElement(x), new SecT283FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat320.Create64(), y = Nat320.Create64();
+                int pos = index * SECT283R1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT283R1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT283R1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT283FieldElement(x), new SecT283FieldElement(y), SECT283R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
index 839ec8059..2f6503692 100644
--- a/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
@@ -11,6 +11,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT409K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT409K1_FE_LONGS = 7;
+        private static readonly ECFieldElement[] SECT409K1_AFFINE_ZS = new ECFieldElement[] { new SecT409FieldElement(BigInteger.One) };
 
         protected readonly SecT409K1Point m_infinity;
 
@@ -120,7 +121,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT409K1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT409K1Curve m_outer;
             private readonly ulong[] m_table;
@@ -133,12 +134,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat448.Create64(), y = Nat448.Create64();
                 int pos = 0;
@@ -156,7 +157,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT409K1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT409FieldElement(x), new SecT409FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat448.Create64(), y = Nat448.Create64();
+                int pos = index * SECT409K1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT409K1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT409K1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT409FieldElement(x), new SecT409FieldElement(y), SECT409K1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
index f70dd5f8e..0e767504b 100644
--- a/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT409R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT409R1_FE_LONGS = 7;
+        private static readonly ECFieldElement[] SECT409R1_AFFINE_ZS = new ECFieldElement[] { new SecT409FieldElement(BigInteger.One) };
 
         protected readonly SecT409R1Point m_infinity;
 
@@ -114,7 +115,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT409R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT409R1Curve m_outer;
             private readonly ulong[] m_table;
@@ -127,12 +128,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat448.Create64(), y = Nat448.Create64();
                 int pos = 0;
@@ -150,7 +151,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT409R1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT409FieldElement(x), new SecT409FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat448.Create64(), y = Nat448.Create64();
+                int pos = index * SECT409R1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT409R1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT409R1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT409FieldElement(x), new SecT409FieldElement(y), SECT409R1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
index 3d84797f7..1ab3b0941 100644
--- a/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
@@ -11,6 +11,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT571K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT571K1_FE_LONGS = 9;
+        private static readonly ECFieldElement[] SECT571K1_AFFINE_ZS = new ECFieldElement[] { new SecT571FieldElement(BigInteger.One) };
 
         protected readonly SecT571K1Point m_infinity;
 
@@ -120,7 +121,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT571K1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT571K1Curve m_outer;
             private readonly ulong[] m_table;
@@ -133,12 +134,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat576.Create64(), y = Nat576.Create64();
                 int pos = 0;
@@ -156,7 +157,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT571K1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT571FieldElement(x), new SecT571FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat576.Create64(), y = Nat576.Create64();
+                int pos = index * SECT571K1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT571K1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT571K1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT571FieldElement(x), new SecT571FieldElement(y), SECT571K1_AFFINE_ZS, false);
             }
         }
     }
diff --git a/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
index 7ebf90856..840c29638 100644
--- a/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
@@ -10,6 +10,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
     {
         private const int SECT571R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
         private const int SECT571R1_FE_LONGS = 9;
+        private static readonly ECFieldElement[] SECT571R1_AFFINE_ZS = new ECFieldElement[] { new SecT571FieldElement(BigInteger.One) };
 
         protected readonly SecT571R1Point m_infinity;
 
@@ -118,7 +119,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         }
 
         private class SecT571R1LookupTable
-            : ECLookupTable
+            : AbstractECLookupTable
         {
             private readonly SecT571R1Curve m_outer;
             private readonly ulong[] m_table;
@@ -131,12 +132,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                 this.m_size = size;
             }
 
-            public virtual int Size
+            public override int Size
             {
                 get { return m_size; }
             }
 
-            public virtual ECPoint Lookup(int index)
+            public override ECPoint Lookup(int index)
             {
                 ulong[] x = Nat576.Create64(), y = Nat576.Create64();
                 int pos = 0;
@@ -154,7 +155,26 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     pos += (SECT571R1_FE_LONGS * 2);
                 }
 
-                return m_outer.CreateRawPoint(new SecT571FieldElement(x), new SecT571FieldElement(y), false);
+                return CreatePoint(x, y);
+            }
+
+            public override ECPoint LookupVar(int index)
+            {
+                ulong[] x = Nat576.Create64(), y = Nat576.Create64();
+                int pos = index * SECT571R1_FE_LONGS * 2;
+
+                for (int j = 0; j < SECT571R1_FE_LONGS; ++j)
+                {
+                    x[j] = m_table[pos + j];
+                    y[j] = m_table[pos + SECT571R1_FE_LONGS + j];
+                }
+
+                return CreatePoint(x, y);
+            }
+
+            private ECPoint CreatePoint(ulong[] x, ulong[] y)
+            {
+                return m_outer.CreateRawPoint(new SecT571FieldElement(x), new SecT571FieldElement(y), SECT571R1_AFFINE_ZS, false);
             }
         }
     }