summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crypto/crypto.csproj35
-rw-r--r--crypto/src/asn1/sec/SECNamedCurves.cs69
-rw-r--r--crypto/src/crypto/ec/CustomNamedCurves.cs48
-rw-r--r--crypto/src/math/ec/ECAlgorithms.cs48
-rw-r--r--crypto/src/math/ec/ECCurve.cs26
-rw-r--r--crypto/src/math/ec/ECPointMap.cs9
-rw-r--r--crypto/src/math/ec/ScaleXPointMap.cs20
-rw-r--r--crypto/src/math/ec/ScaleYPointMap.cs20
-rw-r--r--crypto/src/math/ec/endo/ECEndomorphism.cs11
-rw-r--r--crypto/src/math/ec/endo/GlvEndomorphism.cs10
-rw-r--r--crypto/src/math/ec/endo/GlvTypeBEndomorphism.cs55
-rw-r--r--crypto/src/math/ec/endo/GlvTypeBParameters.cs60
-rw-r--r--crypto/src/math/ec/multiplier/WNafUtilities.cs46
13 files changed, 439 insertions, 18 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index a4d6c7068..195d69a23 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -4649,6 +4649,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\math\ec\ECPointMap.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\math\ec\LongArray.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4664,6 +4669,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\math\ec\ScaleXPointMap.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\ScaleYPointMap.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\math\ec\abc\SimpleBigDecimal.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -4869,6 +4884,26 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\math\ec\endo\ECEndomorphism.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\endo\GlvEndomorphism.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\endo\GlvTypeBEndomorphism.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\endo\GlvTypeBParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\math\ec\multiplier\AbstractECMultiplier.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/asn1/sec/SECNamedCurves.cs b/crypto/src/asn1/sec/SECNamedCurves.cs
index 52e8ed36d..7e2afbe6e 100644
--- a/crypto/src/asn1/sec/SECNamedCurves.cs
+++ b/crypto/src/asn1/sec/SECNamedCurves.cs
@@ -5,6 +5,7 @@ using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Endo;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
 using Org.BouncyCastle.Utilities.Encoders;
@@ -22,8 +23,12 @@ namespace Org.BouncyCastle.Asn1.Sec
             return curve;
         }
 
-        private static BigInteger FromHex(
-            string hex)
+        private static ECCurve ConfigureCurveGlv(ECCurve c, GlvTypeBParameters p)
+        {
+            return c.Configure().SetEndomorphism(new GlvTypeBEndomorphism(c, p)).Create();
+        }
+
+        private static BigInteger FromHex(string hex)
         {
             return new BigInteger(1, Hex.Decode(hex));
         }
@@ -172,7 +177,20 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3");
                 BigInteger h = BigInteger.One;
 
-                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16),
+                    new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16),
+                    new BigInteger[]{
+                        new BigInteger("9162fbe73984472a0a9e", 16),
+                        new BigInteger("-96341f1138933bc2f505", 16) },
+                    new BigInteger[]{
+                        new BigInteger("127971af8721782ecffa3", 16),
+                        new BigInteger("9162fbe73984472a0a9e", 16) },
+                    new BigInteger("48b17df39cc22395054e8", 16),
+                    new BigInteger("4b1a0f889c499de17a820", 16),
+                    163);
+
+                ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
                 //ECPoint G = curve.DecodePoint(Hex.Decode("02"
                     //+ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"));
                 ECPoint G = curve.DecodePoint(Hex.Decode("04"
@@ -265,7 +283,20 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D");
                 BigInteger h = BigInteger.One;
 
-                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16),
+                    new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16),
+                    new BigInteger[]{
+                        new BigInteger("71169be7330b3038edb025f1", 16),
+                        new BigInteger("-b3fb3400dec5c4adceb8655c", 16) },
+                    new BigInteger[]{
+                        new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
+                        new BigInteger("71169be7330b3038edb025f1", 16) },
+                    new BigInteger("1c45a6f9ccc2cc0e3b6c097c7", 16),
+                    new BigInteger("2cfecd0037b1712b73ae19575", 16),
+                    194);
+
+                ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
                 //ECPoint G = curve.DecodePoint(Hex.Decode("03"
                 //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"));
                 ECPoint G = curve.DecodePoint(Hex.Decode("04"
@@ -327,7 +358,20 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
                 BigInteger h = BigInteger.One;
 
-                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16),
+                    new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16),
+                    new BigInteger[]{
+                        new BigInteger("6b8cf07d4ca75c88957d9d670591", 16),
+                        new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) },
+                    new BigInteger[]{
+                        new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
+                        new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
+                    new BigInteger("35c6783ea653ae444abeceb382c82", 16),
+                    new BigInteger("5c56f89bc5375b9a04fd364e31bdd", 16),
+                    227);
+
+                ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
                 //ECPoint G = curve.DecodePoint(Hex.Decode("03"
                 //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"));
                 ECPoint G = curve.DecodePoint(Hex.Decode("04"
@@ -389,7 +433,20 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
                 BigInteger h = BigInteger.One;
 
-                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16),
+                    new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16),
+                    new BigInteger[]{
+                        new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16),
+                        new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) },
+                    new BigInteger[]{
+                        new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
+                        new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
+                    new BigInteger("c21b48869f51af37a1b243924a13ac55", 16),
+                    new BigInteger("3910dfb58043a20a1bd51fea42aff9311", 16),
+                    258);
+
+                ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
                 //ECPoint G = curve.DecodePoint(Hex.Decode("02"
                 //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"));
                 ECPoint G = curve.DecodePoint(Hex.Decode("04"
diff --git a/crypto/src/crypto/ec/CustomNamedCurves.cs b/crypto/src/crypto/ec/CustomNamedCurves.cs
index a4b21ab3d..e58f83d25 100644
--- a/crypto/src/crypto/ec/CustomNamedCurves.cs
+++ b/crypto/src/crypto/ec/CustomNamedCurves.cs
@@ -7,6 +7,7 @@ using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
 using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Math.EC.Endo;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
 using Org.BouncyCastle.Utilities.Encoders;
@@ -29,6 +30,11 @@ namespace Org.BouncyCastle.Crypto.EC
             return curve;
         }
 
+        private static ECCurve ConfigureCurveGlv(ECCurve c, GlvTypeBParameters p)
+        {
+            return c.Configure().SetEndomorphism(new GlvTypeBEndomorphism(c, p)).Create();
+        }
+
         /*
          * secp192k1
          */
@@ -42,7 +48,19 @@ namespace Org.BouncyCastle.Crypto.EC
             protected override X9ECParameters CreateParameters()
             {
                 byte[] S = null;
-                ECCurve curve = ConfigureCurve(new SecP192K1Curve());
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16),
+                    new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16),
+                    new BigInteger[]{
+                        new BigInteger("71169be7330b3038edb025f1", 16),
+                        new BigInteger("-b3fb3400dec5c4adceb8655c", 16) },
+                    new BigInteger[]{
+                        new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
+                        new BigInteger("71169be7330b3038edb025f1", 16) },
+                    new BigInteger("1c45a6f9ccc2cc0e3b6c097c7", 16),
+                    new BigInteger("2cfecd0037b1712b73ae19575", 16),
+                    194);
+                ECCurve curve = ConfigureCurveGlv(new SecP192K1Curve(), glv);
                 ECPoint G = curve.DecodePoint(Hex.Decode("04"
                     + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
                     + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
@@ -84,7 +102,19 @@ namespace Org.BouncyCastle.Crypto.EC
             protected override X9ECParameters CreateParameters()
             {
                 byte[] S = null;
-                ECCurve curve = ConfigureCurve(new SecP224K1Curve());
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16),
+                    new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16),
+                    new BigInteger[]{
+                        new BigInteger("6b8cf07d4ca75c88957d9d670591", 16),
+                        new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) },
+                    new BigInteger[]{
+                        new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
+                        new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
+                    new BigInteger("35c6783ea653ae444abeceb382c82", 16),
+                    new BigInteger("5c56f89bc5375b9a04fd364e31bdd", 16),
+                    227);
+                ECCurve curve = ConfigureCurveGlv(new SecP224K1Curve(), glv);
                 ECPoint G = curve.DecodePoint(Hex.Decode("04"
                     + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
                     + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
@@ -126,7 +156,19 @@ namespace Org.BouncyCastle.Crypto.EC
             protected override X9ECParameters CreateParameters()
             {
                 byte[] S = null;
-                ECCurve curve = ConfigureCurve(new SecP256K1Curve());
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16),
+                    new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16),
+                    new BigInteger[]{
+                        new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16),
+                        new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) },
+                    new BigInteger[]{
+                        new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
+                        new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
+                    new BigInteger("c21b48869f51af37a1b243924a13ac55", 16),
+                    new BigInteger("3910dfb58043a20a1bd51fea42aff9311", 16),
+                    258);
+                ECCurve curve = ConfigureCurveGlv(new SecP256K1Curve(), glv);
                 ECPoint G = curve.DecodePoint(Hex.Decode("04"
                     + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
                     + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
diff --git a/crypto/src/math/ec/ECAlgorithms.cs b/crypto/src/math/ec/ECAlgorithms.cs
index 0b8836b6b..628680e24 100644
--- a/crypto/src/math/ec/ECAlgorithms.cs
+++ b/crypto/src/math/ec/ECAlgorithms.cs
@@ -168,25 +168,61 @@ namespace Org.BouncyCastle.Math.EC
             return R;
         }
 
-        internal static ECPoint ImplShamirsTrickWNaf(ECPoint P, BigInteger k, ECPoint Q, BigInteger l)
+        internal static ECPoint ImplShamirsTrickWNaf(ECPoint P, BigInteger k,
+            ECPoint Q, BigInteger l)
         {
+            bool negK = k.SignValue < 0, negL = l.SignValue < 0;
+
+            k = k.Abs();
+            l = l.Abs();
+
             int widthP = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(k.BitLength)));
             int widthQ = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(l.BitLength)));
 
             WNafPreCompInfo infoP = WNafUtilities.Precompute(P, widthP, true);
             WNafPreCompInfo infoQ = WNafUtilities.Precompute(Q, widthQ, true);
 
-            ECPoint[] preCompP = infoP.PreComp;
-            ECPoint[] preCompQ = infoQ.PreComp;
-            ECPoint[] preCompNegP = infoP.PreCompNeg;
-            ECPoint[] preCompNegQ = infoQ.PreCompNeg;
+            ECPoint[] preCompP = negK ? infoP.PreCompNeg : infoP.PreComp;
+            ECPoint[] preCompQ = negL ? infoQ.PreCompNeg : infoQ.PreComp;
+            ECPoint[] preCompNegP = negK ? infoP.PreComp : infoP.PreCompNeg;
+            ECPoint[] preCompNegQ = negL ? infoQ.PreComp : infoQ.PreCompNeg;
 
             byte[] wnafP = WNafUtilities.GenerateWindowNaf(widthP, k);
             byte[] wnafQ = WNafUtilities.GenerateWindowNaf(widthQ, l);
 
+            return ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ);
+        }
+
+        internal static ECPoint ImplShamirsTrickWNaf(ECPoint P, BigInteger k, ECPointMap pointMapQ, BigInteger l)
+        {
+            bool negK = k.SignValue < 0, negL = l.SignValue < 0;
+
+            k = k.Abs();
+            l = l.Abs();
+
+            int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(System.Math.Max(k.BitLength, l.BitLength))));
+
+            ECPoint Q = WNafUtilities.MapPointWithPrecomp(P, width, true, pointMapQ);
+            WNafPreCompInfo infoP = WNafUtilities.GetWNafPreCompInfo(P);
+            WNafPreCompInfo infoQ = WNafUtilities.GetWNafPreCompInfo(Q);
+
+            ECPoint[] preCompP = negK ? infoP.PreCompNeg : infoP.PreComp;
+            ECPoint[] preCompQ = negL ? infoQ.PreCompNeg : infoQ.PreComp;
+            ECPoint[] preCompNegP = negK ? infoP.PreComp : infoP.PreCompNeg;
+            ECPoint[] preCompNegQ = negL ? infoQ.PreComp : infoQ.PreCompNeg;
+
+            byte[] wnafP = WNafUtilities.GenerateWindowNaf(width, k);
+            byte[] wnafQ = WNafUtilities.GenerateWindowNaf(width, l);
+
+            return ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ);
+        }
+
+        private static ECPoint ImplShamirsTrickWNaf(ECPoint[] preCompP, ECPoint[] preCompNegP, byte[] wnafP,
+            ECPoint[] preCompQ, ECPoint[] preCompNegQ, byte[] wnafQ)
+        {
             int len = System.Math.Max(wnafP.Length, wnafQ.Length);
 
-            ECCurve curve = P.Curve;
+            ECCurve curve = preCompP[0].Curve;
             ECPoint infinity = curve.Infinity;
 
             ECPoint R = infinity;
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index a84863ce6..50ff88e82 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -2,6 +2,7 @@ using System;
 using System.Collections;
 
 using Org.BouncyCastle.Math.EC.Abc;
+using Org.BouncyCastle.Math.EC.Endo;
 using Org.BouncyCastle.Math.EC.Multiplier;
 using Org.BouncyCastle.Math.Field;
 using Org.BouncyCastle.Utilities;
@@ -30,12 +31,14 @@ namespace Org.BouncyCastle.Math.EC
         {
             protected ECCurve outer;
             protected int coord;
+            protected ECEndomorphism endomorphism;
             protected ECMultiplier multiplier;
 
-            internal Config(ECCurve outer, int coord, ECMultiplier multiplier)
+            internal Config(ECCurve outer, int coord, ECEndomorphism endomorphism, ECMultiplier multiplier)
             {
                 this.outer = outer;
                 this.coord = coord;
+                this.endomorphism = endomorphism;
                 this.multiplier = multiplier;
             }
 
@@ -45,6 +48,12 @@ namespace Org.BouncyCastle.Math.EC
                 return this;
             }
 
+            public Config SetEndomorphism(ECEndomorphism endomorphism)
+            {
+                this.endomorphism = endomorphism;
+                return this;
+            }
+
             public Config SetMultiplier(ECMultiplier multiplier)
             {
                 this.multiplier = multiplier;
@@ -65,6 +74,7 @@ namespace Org.BouncyCastle.Math.EC
                 }
 
                 c.m_coord = coord;
+                c.m_endomorphism = endomorphism;
                 c.m_multiplier = multiplier;
 
                 return c;
@@ -76,6 +86,7 @@ namespace Org.BouncyCastle.Math.EC
         protected BigInteger m_order, m_cofactor;
 
         protected int m_coord = COORD_AFFINE;
+        protected ECEndomorphism m_endomorphism = null;
         protected ECMultiplier m_multiplier = null;
 
         protected ECCurve(IFiniteField field)
@@ -88,7 +99,7 @@ namespace Org.BouncyCastle.Math.EC
 
         public virtual Config Configure()
         {
-            return new Config(this, this.m_coord, this.m_multiplier);
+            return new Config(this, this.m_coord, this.m_endomorphism, this.m_multiplier);
         }
 
         public virtual ECPoint CreatePoint(BigInteger x, BigInteger y)
@@ -110,6 +121,12 @@ namespace Org.BouncyCastle.Math.EC
 
         protected virtual ECMultiplier CreateDefaultMultiplier()
         {
+            GlvEndomorphism glvEndomorphism = m_endomorphism as GlvEndomorphism;
+            if (glvEndomorphism != null)
+            {
+                return new GlvMultiplier(this, glvEndomorphism);
+            }
+
             return new WNafL2RMultiplier();
         }
 
@@ -296,6 +313,11 @@ namespace Org.BouncyCastle.Math.EC
 
         protected abstract ECPoint DecompressPoint(int yTilde, BigInteger X1);
 
+        public virtual ECEndomorphism GetEndomorphism()
+        {
+            return m_endomorphism;
+        }
+
         /**
          * Sets the default <code>ECMultiplier</code>, unless already set. 
          */
diff --git a/crypto/src/math/ec/ECPointMap.cs b/crypto/src/math/ec/ECPointMap.cs
new file mode 100644
index 000000000..e78c80065
--- /dev/null
+++ b/crypto/src/math/ec/ECPointMap.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC
+{
+    public interface ECPointMap
+    {
+        ECPoint Map(ECPoint p);
+    }
+}
diff --git a/crypto/src/math/ec/ScaleXPointMap.cs b/crypto/src/math/ec/ScaleXPointMap.cs
new file mode 100644
index 000000000..f8a363b24
--- /dev/null
+++ b/crypto/src/math/ec/ScaleXPointMap.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC
+{
+    public class ScaleXPointMap
+        : ECPointMap
+    {
+        protected readonly ECFieldElement scale;
+
+        public ScaleXPointMap(ECFieldElement scale)
+        {
+            this.scale = scale;
+        }
+
+        public virtual ECPoint Map(ECPoint p)
+        {
+            return p.ScaleX(scale);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/ScaleYPointMap.cs b/crypto/src/math/ec/ScaleYPointMap.cs
new file mode 100644
index 000000000..1c4795b70
--- /dev/null
+++ b/crypto/src/math/ec/ScaleYPointMap.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC
+{
+    public class ScaleYPointMap
+        : ECPointMap
+    {
+        protected readonly ECFieldElement scale;
+
+        public ScaleYPointMap(ECFieldElement scale)
+        {
+            this.scale = scale;
+        }
+
+        public virtual ECPoint Map(ECPoint p)
+        {
+            return p.ScaleY(scale);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/endo/ECEndomorphism.cs b/crypto/src/math/ec/endo/ECEndomorphism.cs
new file mode 100644
index 000000000..dfb321368
--- /dev/null
+++ b/crypto/src/math/ec/endo/ECEndomorphism.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Endo
+{
+    public interface ECEndomorphism
+    {
+        ECPointMap PointMap { get; }
+
+        bool HasEfficientPointMap { get; }
+    }
+}
diff --git a/crypto/src/math/ec/endo/GlvEndomorphism.cs b/crypto/src/math/ec/endo/GlvEndomorphism.cs
new file mode 100644
index 000000000..f65bdd613
--- /dev/null
+++ b/crypto/src/math/ec/endo/GlvEndomorphism.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Endo
+{
+    public interface GlvEndomorphism
+        :   ECEndomorphism
+    {
+        BigInteger[] DecomposeScalar(BigInteger k);
+    }
+}
diff --git a/crypto/src/math/ec/endo/GlvTypeBEndomorphism.cs b/crypto/src/math/ec/endo/GlvTypeBEndomorphism.cs
new file mode 100644
index 000000000..d234d88bf
--- /dev/null
+++ b/crypto/src/math/ec/endo/GlvTypeBEndomorphism.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Endo
+{
+    public class GlvTypeBEndomorphism
+        :   GlvEndomorphism
+    {
+        protected readonly ECCurve m_curve;
+        protected readonly GlvTypeBParameters m_parameters;
+        protected readonly ECPointMap m_pointMap;
+
+        public GlvTypeBEndomorphism(ECCurve curve, GlvTypeBParameters parameters)
+        {
+            this.m_curve = curve;
+            this.m_parameters = parameters;
+            this.m_pointMap = new ScaleXPointMap(curve.FromBigInteger(parameters.Beta));
+        }
+
+        public virtual BigInteger[] DecomposeScalar(BigInteger k)
+        {
+            int bits = m_parameters.Bits;
+            BigInteger b1 = CalculateB(k, m_parameters.G1, bits);
+            BigInteger b2 = CalculateB(k, m_parameters.G2, bits);
+
+            BigInteger[] v1 = m_parameters.V1, v2 = m_parameters.V2;
+            BigInteger a = k.Subtract((b1.Multiply(v1[0])).Add(b2.Multiply(v2[0])));
+            BigInteger b = (b1.Multiply(v1[1])).Add(b2.Multiply(v2[1])).Negate();
+
+            return new BigInteger[]{ a, b };
+        }
+
+        public virtual ECPointMap PointMap
+        {
+            get { return m_pointMap; }
+        }
+
+        public virtual bool HasEfficientPointMap
+        {
+            get { return true; }
+        }
+
+        protected virtual BigInteger CalculateB(BigInteger k, BigInteger g, int t)
+        {
+            bool negative = (g.SignValue < 0);
+            BigInteger b = k.Multiply(g.Abs());
+            bool extra = b.TestBit(t - 1);
+            b = b.ShiftRight(t);
+            if (extra)
+            {
+                b = b.Add(BigInteger.One);
+            }
+            return negative ? b.Negate() : b;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/endo/GlvTypeBParameters.cs b/crypto/src/math/ec/endo/GlvTypeBParameters.cs
new file mode 100644
index 000000000..f93dfaf2b
--- /dev/null
+++ b/crypto/src/math/ec/endo/GlvTypeBParameters.cs
@@ -0,0 +1,60 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Endo
+{
+    public class GlvTypeBParameters
+    {
+        protected readonly BigInteger m_beta;
+        protected readonly BigInteger m_lambda;
+        protected readonly BigInteger[] m_v1, m_v2;
+        protected readonly BigInteger m_g1, m_g2;
+        protected readonly int m_bits;
+
+        public GlvTypeBParameters(BigInteger beta, BigInteger lambda, BigInteger[] v1, BigInteger[] v2,
+            BigInteger g1, BigInteger g2, int bits)
+        {
+            this.m_beta = beta;
+            this.m_lambda = lambda;
+            this.m_v1 = v1;
+            this.m_v2 = v2;
+            this.m_g1 = g1;
+            this.m_g2 = g2;
+            this.m_bits = bits;
+        }
+
+        public virtual BigInteger Beta
+        {
+            get { return m_beta; }
+        }
+
+        public virtual BigInteger Lambda
+        {
+            get { return m_lambda; }
+        }
+
+        public virtual BigInteger[] V1
+        {
+            get { return m_v1; }
+        }
+
+        public virtual BigInteger[] V2
+        {
+            get { return m_v2; }
+        }
+
+        public virtual BigInteger G1
+        {
+            get { return m_g1; }
+        }
+
+        public virtual BigInteger G2
+        {
+            get { return m_g2; }
+        }
+
+        public virtual int Bits
+        {
+            get { return m_bits; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/WNafUtilities.cs b/crypto/src/math/ec/multiplier/WNafUtilities.cs
index 179d6d6eb..98e4f545f 100644
--- a/crypto/src/math/ec/multiplier/WNafUtilities.cs
+++ b/crypto/src/math/ec/multiplier/WNafUtilities.cs
@@ -268,6 +268,11 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
             return wnaf;
         }
 
+        public static WNafPreCompInfo GetWNafPreCompInfo(ECPoint p)
+        {
+            return GetWNafPreCompInfo(p.Curve.GetPreCompInfo(p, PRECOMP_NAME));
+        }
+
         public static WNafPreCompInfo GetWNafPreCompInfo(PreCompInfo preCompInfo)
         {
             if ((preCompInfo != null) && (preCompInfo is WNafPreCompInfo))
@@ -309,6 +314,45 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
             return w + 2;
         }
 
+        public static ECPoint MapPointWithPrecomp(ECPoint p, int width, bool includeNegated,
+            ECPointMap pointMap)
+        {
+            ECCurve c = p.Curve;
+            WNafPreCompInfo wnafPreCompP = Precompute(p, width, includeNegated);
+
+            ECPoint q = pointMap.Map(p);
+            WNafPreCompInfo wnafPreCompQ = GetWNafPreCompInfo(c.GetPreCompInfo(q, PRECOMP_NAME));
+
+            ECPoint twiceP = wnafPreCompP.Twice;
+            if (twiceP != null)
+            {
+                ECPoint twiceQ = pointMap.Map(twiceP);
+                wnafPreCompQ.Twice = twiceQ;
+            }
+
+            ECPoint[] preCompP = wnafPreCompP.PreComp;
+            ECPoint[] preCompQ = new ECPoint[preCompP.Length];
+            for (int i = 0; i < preCompP.Length; ++i)
+            {
+                preCompQ[i] = pointMap.Map(preCompP[i]);
+            }
+            wnafPreCompQ.PreComp = preCompQ;
+
+            if (includeNegated)
+            {
+                ECPoint[] preCompNegQ = new ECPoint[preCompQ.Length];
+                for (int i = 0; i < preCompNegQ.Length; ++i)
+                {
+                    preCompNegQ[i] = preCompQ[i].Negate();
+                }
+                wnafPreCompQ.PreCompNeg = preCompNegQ;
+            }
+
+            c.SetPreCompInfo(q, PRECOMP_NAME, wnafPreCompQ);
+
+            return q;
+        }
+
         public static WNafPreCompInfo Precompute(ECPoint p, int width, bool includeNegated)
         {
             ECCurve c = p.Curve;
@@ -335,7 +379,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
                     ECPoint twiceP = wnafPreCompInfo.Twice;
                     if (twiceP == null)
                     {
-                        twiceP = preComp[0].Twice().Normalize();
+                        twiceP = preComp[0].Twice();
                         wnafPreCompInfo.Twice = twiceP;
                     }