diff --git a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
index fa587b234..c33f16f78 100644
--- a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
@@ -1,3 +1,5 @@
+using System;
+
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Crypto;
@@ -20,19 +22,19 @@ namespace Org.BouncyCastle.Crypto.Agreement
* Section 7.2.2).
*/
public class ECDHBasicAgreement
- : IBasicAgreement
+ : IBasicAgreement
{
protected internal ECPrivateKeyParameters privKey;
public virtual void Init(
- ICipherParameters parameters)
+ ICipherParameters parameters)
{
- if (parameters is ParametersWithRandom)
- {
- parameters = ((ParametersWithRandom)parameters).Parameters;
- }
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom)parameters).Parameters;
+ }
- this.privKey = (ECPrivateKeyParameters)parameters;
+ this.privKey = (ECPrivateKeyParameters)parameters;
}
public virtual int GetFieldSize()
@@ -44,11 +46,12 @@ namespace Org.BouncyCastle.Crypto.Agreement
ICipherParameters pubKey)
{
ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
- ECPoint P = pub.Q.Multiply(privKey.D);
+ ECPoint P = pub.Q.Multiply(privKey.D).Normalize();
- // if ( p.IsInfinity ) throw new Exception("d*Q == infinity");
+ if (P.IsInfinity)
+ throw new InvalidOperationException("Infinity is not a valid agreement value for ECDH");
- return P.X.ToBigInteger();
+ return P.AffineXCoord.ToBigInteger();
}
}
}
diff --git a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
index e1c572373..89be7061e 100644
--- a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
@@ -52,11 +52,15 @@ namespace Org.BouncyCastle.Crypto.Agreement
{
ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
ECDomainParameters parameters = pub.Parameters;
- ECPoint P = pub.Q.Multiply(parameters.H.Multiply(key.D));
- // if ( p.IsInfinity ) throw new Exception("Invalid public key");
+ BigInteger hd = parameters.H.Multiply(key.D).Mod(parameters.N);
- return P.X.ToBigInteger();
+ ECPoint P = pub.Q.Multiply(hd).Normalize();
+
+ if (P.IsInfinity)
+ throw new InvalidOperationException("Infinity is not a valid agreement value for ECDHC");
+
+ return P.AffineXCoord.ToBigInteger();
}
}
}
diff --git a/crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs
index 28437a268..1de80d1e5 100644
--- a/crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs
@@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Crypto.Agreement
DHKdfParameters dhKdfParams = new DHKdfParameters(
new DerObjectIdentifier(algorithm),
keySize,
- bigIntToBytes(result));
+ BigIntToBytes(result));
kdf.Init(dhKdfParams);
@@ -54,10 +54,9 @@ namespace Org.BouncyCastle.Crypto.Agreement
return new BigInteger(1, keyBytes);
}
- private byte[] bigIntToBytes(
- BigInteger r)
+ private byte[] BigIntToBytes(BigInteger r)
{
- int byteLength = X9IntegerConverter.GetByteLength(privKey.Parameters.G.X);
+ int byteLength = X9IntegerConverter.GetByteLength(privKey.Parameters.Curve);
return X9IntegerConverter.IntegerToBytes(r, byteLength);
}
}
diff --git a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
index 3559d3e81..f55ae46af 100644
--- a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
@@ -35,15 +35,18 @@ namespace Org.BouncyCastle.Crypto.Agreement
ECPrivateKeyParameters staticPrivateKey = privParams.StaticPrivateKey;
- ECPoint agreement = calculateMqvAgreement(staticPrivateKey.Parameters, staticPrivateKey,
+ ECPoint agreement = CalculateMqvAgreement(staticPrivateKey.Parameters, staticPrivateKey,
privParams.EphemeralPrivateKey, privParams.EphemeralPublicKey,
- pubParams.StaticPublicKey, pubParams.EphemeralPublicKey);
+ pubParams.StaticPublicKey, pubParams.EphemeralPublicKey).Normalize();
- return agreement.X.ToBigInteger();
+ if (agreement.IsInfinity)
+ throw new InvalidOperationException("Infinity is not a valid agreement value for MQV");
+
+ return agreement.AffineXCoord.ToBigInteger();
}
-
+
// The ECMQV Primitive as described in SEC-1, 3.4
- private static ECPoint calculateMqvAgreement(
+ private static ECPoint CalculateMqvAgreement(
ECDomainParameters parameters,
ECPrivateKeyParameters d1U,
ECPrivateKeyParameters d2U,
@@ -55,36 +58,32 @@ namespace Org.BouncyCastle.Crypto.Agreement
int e = (n.BitLength + 1) / 2;
BigInteger powE = BigInteger.One.ShiftLeft(e);
- // The Q2U public key is optional
- ECPoint q;
- if (Q2U == null)
- {
- q = parameters.G.Multiply(d2U.D);
- }
- else
- {
- q = Q2U.Q;
- }
+ ECCurve curve = parameters.Curve;
- BigInteger x = q.X.ToBigInteger();
+ ECPoint[] points = new ECPoint[]{
+ // The Q2U public key is optional
+ ECAlgorithms.ImportPoint(curve, Q2U == null ? parameters.G.Multiply(d2U.D) : Q2U.Q),
+ ECAlgorithms.ImportPoint(curve, Q1V.Q),
+ ECAlgorithms.ImportPoint(curve, Q2V.Q)
+ };
+
+ curve.NormalizeAll(points);
+
+ ECPoint q2u = points[0], q1v = points[1], q2v = points[2];
+
+ BigInteger x = q2u.AffineXCoord.ToBigInteger();
BigInteger xBar = x.Mod(powE);
BigInteger Q2UBar = xBar.SetBit(e);
- BigInteger s = d1U.D.Multiply(Q2UBar).Mod(n).Add(d2U.D).Mod(n);
+ BigInteger s = d1U.D.Multiply(Q2UBar).Add(d2U.D).Mod(n);
- BigInteger xPrime = Q2V.Q.X.ToBigInteger();
+ BigInteger xPrime = q2v.AffineXCoord.ToBigInteger();
BigInteger xPrimeBar = xPrime.Mod(powE);
BigInteger Q2VBar = xPrimeBar.SetBit(e);
BigInteger hs = parameters.H.Multiply(s).Mod(n);
- //ECPoint p = Q1V.Q.Multiply(Q2VBar).Add(Q2V.Q).Multiply(hs);
- ECPoint p = ECAlgorithms.SumOfTwoMultiplies(
- Q1V.Q, Q2VBar.Multiply(hs).Mod(n), Q2V.Q, hs);
-
- if (p.IsInfinity)
- throw new InvalidOperationException("Infinity is not a valid agreement value for MQV");
-
- return p;
+ return ECAlgorithms.SumOfTwoMultiplies(
+ q1v, Q2VBar.Multiply(hs).Mod(n), q2v, hs);
}
}
}
diff --git a/crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs b/crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs
index 093ce4056..7d79fc468 100644
--- a/crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs
@@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Crypto.Agreement
DHKdfParameters dhKdfParams = new DHKdfParameters(
new DerObjectIdentifier(algorithm),
keySize,
- bigIntToBytes(result));
+ BigIntToBytes(result));
kdf.Init(dhKdfParams);
@@ -54,10 +54,9 @@ namespace Org.BouncyCastle.Crypto.Agreement
return new BigInteger(1, keyBytes);
}
- private byte[] bigIntToBytes(
- BigInteger r)
+ private byte[] BigIntToBytes(BigInteger r)
{
- int byteLength = X9IntegerConverter.GetByteLength(privParams.StaticPrivateKey.Parameters.G.X);
+ int byteLength = X9IntegerConverter.GetByteLength(privParams.StaticPrivateKey.Parameters.Curve);
return X9IntegerConverter.IntegerToBytes(r, byteLength);
}
}
diff --git a/crypto/src/crypto/signers/ECDsaSigner.cs b/crypto/src/crypto/signers/ECDsaSigner.cs
index d602ec3bb..3b0b8ddf1 100644
--- a/crypto/src/crypto/signers/ECDsaSigner.cs
+++ b/crypto/src/crypto/signers/ECDsaSigner.cs
@@ -84,10 +84,10 @@ namespace Org.BouncyCastle.Crypto.Signers
}
while (k.SignValue == 0 || k.CompareTo(n) >= 0);
- ECPoint p = key.Parameters.G.Multiply(k);
+ ECPoint p = key.Parameters.G.Multiply(k).Normalize();
// 5.3.3
- BigInteger x = p.X.ToBigInteger();
+ BigInteger x = p.AffineXCoord.ToBigInteger();
r = x.Mod(n);
}
@@ -95,7 +95,7 @@ namespace Org.BouncyCastle.Crypto.Signers
BigInteger d = ((ECPrivateKeyParameters)key).D;
- s = k.ModInverse(n).Multiply(e.Add(d.Multiply(r).Mod(n))).Mod(n);
+ s = k.ModInverse(n).Multiply(e.Add(d.Multiply(r))).Mod(n);
}
while (s.SignValue == 0);
@@ -131,12 +131,12 @@ namespace Org.BouncyCastle.Crypto.Signers
ECPoint G = key.Parameters.G;
ECPoint Q = ((ECPublicKeyParameters) key).Q;
- ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2);
+ ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2).Normalize();
if (point.IsInfinity)
return false;
- BigInteger v = point.X.ToBigInteger().Mod(n);
+ BigInteger v = point.AffineXCoord.ToBigInteger().Mod(n);
return v.Equals(r);
}
diff --git a/crypto/src/crypto/signers/ECGOST3410Signer.cs b/crypto/src/crypto/signers/ECGOST3410Signer.cs
index 294d4791a..3d71ace04 100644
--- a/crypto/src/crypto/signers/ECGOST3410Signer.cs
+++ b/crypto/src/crypto/signers/ECGOST3410Signer.cs
@@ -88,9 +88,9 @@ namespace Org.BouncyCastle.Crypto.Signers
}
while (k.SignValue == 0);
- ECPoint p = key.Parameters.G.Multiply(k);
+ ECPoint p = key.Parameters.G.Multiply(k).Normalize();
- BigInteger x = p.X.ToBigInteger();
+ BigInteger x = p.AffineXCoord.ToBigInteger();
r = x.Mod(n);
}
@@ -144,12 +144,12 @@ namespace Org.BouncyCastle.Crypto.Signers
ECPoint G = key.Parameters.G; // P
ECPoint Q = ((ECPublicKeyParameters)key).Q;
- ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, z1, Q, z2);
+ ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, z1, Q, z2).Normalize();
if (point.IsInfinity)
return false;
- BigInteger R = point.X.ToBigInteger().Mod(n);
+ BigInteger R = point.AffineXCoord.ToBigInteger().Mod(n);
return R.Equals(r);
}
diff --git a/crypto/src/crypto/signers/ECNRSigner.cs b/crypto/src/crypto/signers/ECNRSigner.cs
index 1d9af3d13..ba953aca4 100644
--- a/crypto/src/crypto/signers/ECNRSigner.cs
+++ b/crypto/src/crypto/signers/ECNRSigner.cs
@@ -9,181 +9,181 @@ using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Signers
{
- /**
- * EC-NR as described in IEEE 1363-2000
- */
- public class ECNRSigner
- : IDsa
- {
- private bool forSigning;
- private ECKeyParameters key;
- private SecureRandom random;
-
- public string AlgorithmName
- {
- get { return "ECNR"; }
- }
-
- public void Init(
- bool forSigning,
- ICipherParameters parameters)
- {
- this.forSigning = forSigning;
-
- if (forSigning)
- {
- if (parameters is ParametersWithRandom)
- {
- ParametersWithRandom rParam = (ParametersWithRandom) parameters;
-
- this.random = rParam.Random;
- parameters = rParam.Parameters;
- }
- else
- {
- this.random = new SecureRandom();
- }
-
- if (!(parameters is ECPrivateKeyParameters))
- throw new InvalidKeyException("EC private key required for signing");
-
- this.key = (ECPrivateKeyParameters) parameters;
- }
- else
- {
- if (!(parameters is ECPublicKeyParameters))
- throw new InvalidKeyException("EC public key required for verification");
-
- this.key = (ECPublicKeyParameters) parameters;
- }
- }
-
- // Section 7.2.5 ECSP-NR, pg 34
- /**
- * generate a signature for the given message using the key we were
- * initialised with. Generally, the order of the curve should be at
- * least as long as the hash of the message of interest, and with
- * ECNR it *must* be at least as long.
- *
- * @param digest the digest to be signed.
- * @exception DataLengthException if the digest is longer than the key allows
- */
- public BigInteger[] GenerateSignature(
- byte[] message)
- {
- if (!this.forSigning)
- {
- // not properly initilaized... deal with it
- throw new InvalidOperationException("not initialised for signing");
- }
-
- BigInteger n = ((ECPrivateKeyParameters) this.key).Parameters.N;
- int nBitLength = n.BitLength;
-
- BigInteger e = new BigInteger(1, message);
- int eBitLength = e.BitLength;
-
- ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)key;
-
- if (eBitLength > nBitLength)
- {
- throw new DataLengthException("input too large for ECNR key.");
- }
-
- BigInteger r = null;
- BigInteger s = null;
-
- AsymmetricCipherKeyPair tempPair;
- do // generate r
- {
- // generate another, but very temporary, key pair using
- // the same EC parameters
- ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
-
- keyGen.Init(new ECKeyGenerationParameters(privKey.Parameters, this.random));
-
- tempPair = keyGen.GenerateKeyPair();
-
- // BigInteger Vx = tempPair.getPublic().getW().getAffineX();
- ECPublicKeyParameters V = (ECPublicKeyParameters) tempPair.Public; // get temp's public key
- BigInteger Vx = V.Q.X.ToBigInteger(); // get the point's x coordinate
-
- r = Vx.Add(e).Mod(n);
- }
- while (r.SignValue == 0);
-
- // generate s
- BigInteger x = privKey.D; // private key value
- BigInteger u = ((ECPrivateKeyParameters) tempPair.Private).D; // temp's private key value
- s = u.Subtract(r.Multiply(x)).Mod(n);
-
- return new BigInteger[]{ r, s };
- }
-
- // Section 7.2.6 ECVP-NR, pg 35
- /**
- * return true if the value r and s represent a signature for the
- * message passed in. Generally, the order of the curve should be at
- * least as long as the hash of the message of interest, and with
- * ECNR, it *must* be at least as long. But just in case the signer
- * applied mod(n) to the longer digest, this implementation will
- * apply mod(n) during verification.
- *
- * @param digest the digest to be verified.
- * @param r the r value of the signature.
- * @param s the s value of the signature.
- * @exception DataLengthException if the digest is longer than the key allows
- */
- public bool VerifySignature(
- byte[] message,
- BigInteger r,
- BigInteger s)
- {
- if (this.forSigning)
- {
- // not properly initilaized... deal with it
- throw new InvalidOperationException("not initialised for verifying");
- }
-
- ECPublicKeyParameters pubKey = (ECPublicKeyParameters)key;
- BigInteger n = pubKey.Parameters.N;
- int nBitLength = n.BitLength;
-
- BigInteger e = new BigInteger(1, message);
- int eBitLength = e.BitLength;
-
- if (eBitLength > nBitLength)
- {
- throw new DataLengthException("input too large for ECNR key.");
- }
-
- // r in the range [1,n-1]
- if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
- {
- return false;
- }
-
- // TODO So why is this different from the spec?
- // s in the range [0,n-1] NB: ECNR spec says 0
- if (s.CompareTo(BigInteger.Zero) < 0 || s.CompareTo(n) >= 0)
- {
- return false;
- }
-
- // compute P = sG + rW
-
- ECPoint G = pubKey.Parameters.G;
- ECPoint W = pubKey.Q;
- // calculate P using Bouncy math
- ECPoint P = ECAlgorithms.SumOfTwoMultiplies(G, s, W, r);
+ /**
+ * EC-NR as described in IEEE 1363-2000
+ */
+ public class ECNRSigner
+ : IDsa
+ {
+ private bool forSigning;
+ private ECKeyParameters key;
+ private SecureRandom random;
+
+ public string AlgorithmName
+ {
+ get { return "ECNR"; }
+ }
+
+ public void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom) parameters;
+
+ this.random = rParam.Random;
+ parameters = rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+
+ if (!(parameters is ECPrivateKeyParameters))
+ throw new InvalidKeyException("EC private key required for signing");
+
+ this.key = (ECPrivateKeyParameters) parameters;
+ }
+ else
+ {
+ if (!(parameters is ECPublicKeyParameters))
+ throw new InvalidKeyException("EC public key required for verification");
+
+ this.key = (ECPublicKeyParameters) parameters;
+ }
+ }
+
+ // Section 7.2.5 ECSP-NR, pg 34
+ /**
+ * generate a signature for the given message using the key we were
+ * initialised with. Generally, the order of the curve should be at
+ * least as long as the hash of the message of interest, and with
+ * ECNR it *must* be at least as long.
+ *
+ * @param digest the digest to be signed.
+ * @exception DataLengthException if the digest is longer than the key allows
+ */
+ public BigInteger[] GenerateSignature(
+ byte[] message)
+ {
+ if (!this.forSigning)
+ {
+ // not properly initilaized... deal with it
+ throw new InvalidOperationException("not initialised for signing");
+ }
+
+ BigInteger n = ((ECPrivateKeyParameters) this.key).Parameters.N;
+ int nBitLength = n.BitLength;
+
+ BigInteger e = new BigInteger(1, message);
+ int eBitLength = e.BitLength;
+
+ ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)key;
+
+ if (eBitLength > nBitLength)
+ {
+ throw new DataLengthException("input too large for ECNR key.");
+ }
+
+ BigInteger r = null;
+ BigInteger s = null;
+
+ AsymmetricCipherKeyPair tempPair;
+ do // generate r
+ {
+ // generate another, but very temporary, key pair using
+ // the same EC parameters
+ ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
+
+ keyGen.Init(new ECKeyGenerationParameters(privKey.Parameters, this.random));
+
+ tempPair = keyGen.GenerateKeyPair();
+
+ // BigInteger Vx = tempPair.getPublic().getW().getAffineX();
+ ECPublicKeyParameters V = (ECPublicKeyParameters) tempPair.Public; // get temp's public key
+ ECPoint vq = V.Q.Normalize();
+ BigInteger Vx = vq.AffineXCoord.ToBigInteger(); // get the point's x coordinate
+
+ r = Vx.Add(e).Mod(n);
+ }
+ while (r.SignValue == 0);
+
+ // generate s
+ BigInteger x = privKey.D; // private key value
+ BigInteger u = ((ECPrivateKeyParameters) tempPair.Private).D; // temp's private key value
+ s = u.Subtract(r.Multiply(x)).Mod(n);
+
+ return new BigInteger[]{ r, s };
+ }
+
+ // Section 7.2.6 ECVP-NR, pg 35
+ /**
+ * return true if the value r and s represent a signature for the
+ * message passed in. Generally, the order of the curve should be at
+ * least as long as the hash of the message of interest, and with
+ * ECNR, it *must* be at least as long. But just in case the signer
+ * applied mod(n) to the longer digest, this implementation will
+ * apply mod(n) during verification.
+ *
+ * @param digest the digest to be verified.
+ * @param r the r value of the signature.
+ * @param s the s value of the signature.
+ * @exception DataLengthException if the digest is longer than the key allows
+ */
+ public bool VerifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ if (this.forSigning)
+ {
+ // not properly initilaized... deal with it
+ throw new InvalidOperationException("not initialised for verifying");
+ }
+
+ ECPublicKeyParameters pubKey = (ECPublicKeyParameters)key;
+ BigInteger n = pubKey.Parameters.N;
+ int nBitLength = n.BitLength;
+
+ BigInteger e = new BigInteger(1, message);
+ int eBitLength = e.BitLength;
+
+ if (eBitLength > nBitLength)
+ {
+ throw new DataLengthException("input too large for ECNR key.");
+ }
+
+ // r in the range [1,n-1]
+ if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ // s in the range [0,n-1] NB: ECNR spec says 0
+ if (s.CompareTo(BigInteger.Zero) < 0 || s.CompareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ // compute P = sG + rW
+
+ ECPoint G = pubKey.Parameters.G;
+ ECPoint W = pubKey.Q;
+ // calculate P using Bouncy math
+ ECPoint P = ECAlgorithms.SumOfTwoMultiplies(G, s, W, r).Normalize();
if (P.IsInfinity)
return false;
- BigInteger x = P.X.ToBigInteger();
- BigInteger t = r.Subtract(x).Mod(n);
+ BigInteger x = P.AffineXCoord.ToBigInteger();
+ BigInteger t = r.Subtract(x).Mod(n);
- return t.Equals(e);
- }
- }
+ return t.Equals(e);
+ }
+ }
}
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index 38daa719c..d369cb2b7 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -99,6 +99,8 @@ namespace Org.BouncyCastle.Math.EC
protected abstract ECCurve CloneCurve();
+ protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression);
+
protected virtual ECMultiplier CreateDefaultMultiplier()
{
return new WNafMultiplier();
@@ -145,7 +147,7 @@ namespace Org.BouncyCastle.Math.EC
// TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
p = p.Normalize();
- return CreatePoint(p.X.ToBigInteger(), p.Y.ToBigInteger(), p.IsCompressed);
+ return CreatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
}
/**
@@ -375,6 +377,20 @@ namespace Org.BouncyCastle.Math.EC
return new FpCurve(m_q, m_r, m_a, m_b);
}
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_AFFINE:
+ case COORD_HOMOGENEOUS:
+ //case COORD_JACOBIAN:
+ //case COORD_JACOBIAN_MODIFIED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
public virtual BigInteger Q
{
get { return m_q; }
@@ -395,6 +411,11 @@ namespace Org.BouncyCastle.Math.EC
return new FpFieldElement(this.m_q, this.m_r, x);
}
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new FpPoint(this, x, y, withCompression);
+ }
+
public override ECPoint CreatePoint(
BigInteger X1,
BigInteger Y1,
@@ -710,6 +731,11 @@ namespace Org.BouncyCastle.Math.EC
return base.CreateDefaultMultiplier();
}
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new F2mPoint(this, x, y, withCompression);
+ }
+
public override ECPoint Infinity
{
get { return m_infinity; }
diff --git a/crypto/src/math/ec/ECPoint.cs b/crypto/src/math/ec/ECPoint.cs
index 7a4450ac1..86134f80c 100644
--- a/crypto/src/math/ec/ECPoint.cs
+++ b/crypto/src/math/ec/ECPoint.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Diagnostics;
+using System.Text;
using Org.BouncyCastle.Math.EC.Multiplier;
@@ -51,24 +52,18 @@ namespace Org.BouncyCastle.Math.EC
protected internal PreCompInfo m_preCompInfo = null;
- protected ECPoint(
- ECCurve curve,
- ECFieldElement x,
- ECFieldElement y,
- bool withCompression)
+ protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : this(curve, x, y, GetInitialZCoords(curve), withCompression)
{
- this.m_curve = curve;
- this.m_x = x;
- this.m_y = y;
- this.m_withCompression = withCompression;
}
- protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs)
+ internal ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
{
this.m_curve = curve;
this.m_x = x;
this.m_y = y;
this.m_zs = zs;
+ this.m_withCompression = withCompression;
}
public virtual ECCurve Curve
@@ -85,13 +80,85 @@ namespace Org.BouncyCastle.Math.EC
}
}
+ /**
+ * Normalizes this point, and then returns the affine x-coordinate.
+ *
+ * Note: normalization can be expensive, this method is deprecated in favour
+ * of caller-controlled normalization.
+ */
+ [Obsolete("Use AffineXCoord, or Normalize() and XCoord, instead")]
public virtual ECFieldElement X
{
- get { return m_x; }
+ get { return Normalize().XCoord; }
}
+ /**
+ * Normalizes this point, and then returns the affine y-coordinate.
+ *
+ * Note: normalization can be expensive, this method is deprecated in favour
+ * of caller-controlled normalization.
+ */
+ [Obsolete("Use AffineYCoord, or Normalize() and YCoord, instead")]
public virtual ECFieldElement Y
{
+ get { return Normalize().YCoord; }
+ }
+
+ /**
+ * Returns the affine x-coordinate after checking that this point is normalized.
+ *
+ * @return The affine x-coordinate of this point
+ * @throws IllegalStateException if the point is not normalized
+ */
+ public virtual ECFieldElement AffineXCoord
+ {
+ get
+ {
+ CheckNormalized();
+ return XCoord;
+ }
+ }
+
+ /**
+ * Returns the affine y-coordinate after checking that this point is normalized
+ *
+ * @return The affine y-coordinate of this point
+ * @throws IllegalStateException if the point is not normalized
+ */
+ public virtual ECFieldElement AffineYCoord
+ {
+ get
+ {
+ CheckNormalized();
+ return YCoord;
+ }
+ }
+
+ /**
+ * Returns the x-coordinate.
+ *
+ * Caution: depending on the curve's coordinate system, this may not be the same value as in an
+ * affine coordinate system; use Normalize() to get a point where the coordinates have their
+ * affine values, or use AffineXCoord if you expect the point to already have been normalized.
+ *
+ * @return the x-coordinate of this point
+ */
+ public virtual ECFieldElement XCoord
+ {
+ get { return m_x; }
+ }
+
+ /**
+ * Returns the y-coordinate.
+ *
+ * Caution: depending on the curve's coordinate system, this may not be the same value as in an
+ * affine coordinate system; use Normalize() to get a point where the coordinates have their
+ * affine values, or use AffineYCoord if you expect the point to already have been normalized.
+ *
+ * @return the y-coordinate of this point
+ */
+ public virtual ECFieldElement YCoord
+ {
get { return m_y; }
}
@@ -112,6 +179,16 @@ namespace Org.BouncyCastle.Math.EC
return copy;
}
+ protected virtual ECFieldElement RawXCoord
+ {
+ get { return m_x; }
+ }
+
+ protected virtual ECFieldElement RawYCoord
+ {
+ get { return m_y; }
+ }
+
protected virtual void CheckNormalized()
{
if (!IsNormalized())
@@ -124,8 +201,8 @@ namespace Org.BouncyCastle.Math.EC
return coord == ECCurve.COORD_AFFINE
|| coord == ECCurve.COORD_LAMBDA_AFFINE
- || IsInfinity;
- //|| zs[0].isOne();
+ || IsInfinity
+ || GetZCoord(0).IsOne;
}
/**
@@ -163,27 +240,30 @@ namespace Org.BouncyCastle.Math.EC
internal virtual ECPoint Normalize(ECFieldElement zInv)
{
- throw new InvalidOperationException("not a projective coordinate system");
-
- //switch (this.CurveCoordinateSystem)
- //{
- // case ECCurve.COORD_HOMOGENEOUS:
- // case ECCurve.COORD_LAMBDA_PROJECTIVE:
- // {
- // return CreateScaledPoint(zInv, zInv);
- // }
- // case ECCurve.COORD_JACOBIAN:
- // case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
- // case ECCurve.COORD_JACOBIAN_MODIFIED:
- // {
- // ECFieldElement zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv);
- // return CreateScaledPoint(zInv2, zInv3);
- // }
- // default:
- // {
- // throw new InvalidOperationException("not a projective coordinate system");
- // }
- //}
+ switch (this.CurveCoordinateSystem)
+ {
+ case ECCurve.COORD_HOMOGENEOUS:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ return CreateScaledPoint(zInv, zInv);
+ }
+ case ECCurve.COORD_JACOBIAN:
+ case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ {
+ ECFieldElement zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv);
+ return CreateScaledPoint(zInv2, zInv3);
+ }
+ default:
+ {
+ throw new InvalidOperationException("not a projective coordinate system");
+ }
+ }
+ }
+
+ protected virtual ECPoint CreateScaledPoint(ECFieldElement sx, ECFieldElement sy)
+ {
+ return Curve.CreateRawPoint(RawXCoord.Multiply(sx), RawYCoord.Multiply(sy), IsCompressed);
}
public bool IsInfinity
@@ -208,26 +288,87 @@ namespace Org.BouncyCastle.Math.EC
if (null == other)
return false;
+ ECCurve c1 = this.Curve, c2 = other.Curve;
+ bool n1 = (null == c1), n2 = (null == c2);
bool i1 = IsInfinity, i2 = other.IsInfinity;
+
if (i1 || i2)
{
- return i1 && i2;
+ return (i1 && i2) && (n1 || n2 || c1.Equals(c2));
+ }
+
+ ECPoint p1 = this, p2 = other;
+ if (n1 && n2)
+ {
+ // Points with null curve are in affine form, so already normalized
+ }
+ else if (n1)
+ {
+ p2 = p2.Normalize();
+ }
+ else if (n2)
+ {
+ p1 = p1.Normalize();
+ }
+ else if (!c1.Equals(c2))
+ {
+ return false;
+ }
+ else
+ {
+ // TODO Consider just requiring already normalized, to avoid silent performance degradation
+
+ ECPoint[] points = new ECPoint[] { this, c1.ImportPoint(p2) };
+
+ // TODO This is a little strong, really only requires coZNormalizeAll to get Zs equal
+ c1.NormalizeAll(points);
+
+ p1 = points[0];
+ p2 = points[1];
}
- return X.Equals(other.X) && Y.Equals(other.Y);
+ return p1.XCoord.Equals(p2.XCoord) && p1.YCoord.Equals(p2.YCoord);
}
public override int GetHashCode()
{
- int hc = 0;
- if (!IsInfinity)
+ ECCurve c = this.Curve;
+ int hc = (null == c) ? 0 : ~c.GetHashCode();
+
+ if (!this.IsInfinity)
{
- hc ^= X.GetHashCode() * 17;
- hc ^= Y.GetHashCode() * 257;
+ // TODO Consider just requiring already normalized, to avoid silent performance degradation
+
+ ECPoint p = Normalize();
+
+ hc ^= p.XCoord.GetHashCode() * 17;
+ hc ^= p.YCoord.GetHashCode() * 257;
}
+
return hc;
}
+ public override string ToString()
+ {
+ if (this.IsInfinity)
+ {
+ return "INF";
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.Append('(');
+ sb.Append(RawXCoord);
+ sb.Append(',');
+ sb.Append(RawYCoord);
+ for (int i = 0; i < m_zs.Length; ++i)
+ {
+ sb.Append(',');
+ sb.Append(m_zs[i]);
+ }
+ sb.Append(')');
+ return sb.ToString();
+ }
+
public virtual byte[] GetEncoded()
{
return GetEncoded(m_withCompression);
@@ -280,6 +421,11 @@ namespace Org.BouncyCastle.Math.EC
{
}
+ protected internal ECPointBase(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
/**
* return the field element encoded with point compression. (S 4.3.6)
*/
@@ -292,7 +438,7 @@ namespace Org.BouncyCastle.Math.EC
ECPoint normed = Normalize();
- byte[] X = normed.X.GetEncoded();
+ byte[] X = normed.XCoord.GetEncoded();
if (compressed)
{
@@ -302,7 +448,7 @@ namespace Org.BouncyCastle.Math.EC
return PO;
}
- byte[] Y = normed.Y.GetEncoded();
+ byte[] Y = normed.YCoord.GetEncoded();
{
byte[] PO = new byte[X.Length + Y.Length + 1];
@@ -374,9 +520,14 @@ namespace Org.BouncyCastle.Math.EC
throw new ArgumentException("Exactly one of the field elements is null");
}
+ internal FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
protected internal override bool CompressionYTilde
{
- get { return this.Y.TestBitZero(); }
+ get { return this.AffineYCoord.TestBitZero(); }
}
// B.3 pg 62
@@ -396,28 +547,84 @@ namespace Org.BouncyCastle.Math.EC
return Twice();
}
- ECFieldElement X1 = this.X, Y1 = this.Y;
- ECFieldElement X2 = b.X, Y2 = b.Y;
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
- ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);
+ ECFieldElement X1 = this.XCoord, Y1 = this.YCoord;
+ ECFieldElement X2 = b.XCoord, Y2 = b.YCoord;
- if (dx.IsZero)
+ switch (coord)
{
- if (dy.IsZero)
+ case ECCurve.COORD_AFFINE:
{
- // this == b, i.e. this must be doubled
- return Twice();
+ ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);
+
+ if (dx.IsZero)
+ {
+ if (dy.IsZero)
+ {
+ // this == b, i.e. this must be doubled
+ return Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return Curve.Infinity;
+ }
+
+ ECFieldElement gamma = dy.Divide(dx);
+ ECFieldElement X3 = gamma.Square().Subtract(X1).Subtract(X2);
+ ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
+
+ return new FpPoint(Curve, X3, Y3, IsCompressed);
}
- // this == -b, i.e. the result is the point at infinity
- return Curve.Infinity;
- }
+ case ECCurve.COORD_HOMOGENEOUS:
+ {
+ ECFieldElement Z1 = this.GetZCoord(0);
+ ECFieldElement Z2 = b.GetZCoord(0);
+
+ bool Z1IsOne = Z1.IsOne;
+ bool Z2IsOne = Z2.IsOne;
+
+ ECFieldElement u1 = Z1IsOne ? Y2 : Y2.Multiply(Z1);
+ ECFieldElement u2 = Z2IsOne ? Y1 : Y1.Multiply(Z2);
+ ECFieldElement u = u1.Subtract(u2);
+ ECFieldElement v1 = Z1IsOne ? X2 : X2.Multiply(Z1);
+ ECFieldElement v2 = Z2IsOne ? X1 : X1.Multiply(Z2);
+ ECFieldElement v = v1.Subtract(v2);
+
+ // Check if b == this or b == -this
+ if (v.IsZero)
+ {
+ if (u.IsZero)
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ // TODO Optimize for when w == 1
+ ECFieldElement w = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2);
+ ECFieldElement vSquared = v.Square();
+ ECFieldElement vCubed = vSquared.Multiply(v);
+ ECFieldElement vSquaredV2 = vSquared.Multiply(v2);
+ ECFieldElement A = u.Square().Multiply(w).Subtract(vCubed).Subtract(Two(vSquaredV2));
- ECFieldElement gamma = dy.Divide(dx);
- ECFieldElement X3 = gamma.Square().Subtract(X1).Subtract(X2);
- ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
+ ECFieldElement X3 = v.Multiply(A);
+ ECFieldElement Y3 = vSquaredV2.Subtract(A).Multiply(u).Subtract(vCubed.Multiply(u2));
+ ECFieldElement Z3 = vCubed.Multiply(w);
- return new FpPoint(Curve, X3, Y3, IsCompressed);
+ return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ default:
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
}
// B.3 pg 62
@@ -428,20 +635,65 @@ namespace Org.BouncyCastle.Math.EC
return this;
}
- ECFieldElement Y1 = this.Y;
+ ECCurve curve = this.Curve;
+
+ ECFieldElement Y1 = this.YCoord;
if (Y1.IsZero)
{
- return Curve.Infinity;
+ return curve.Infinity;
}
- ECFieldElement X1 = this.X;
+ int coord = curve.CoordinateSystem;
+
+ ECFieldElement X1 = this.XCoord;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ {
+ ECFieldElement X1Squared = X1.Square();
+ ECFieldElement gamma = Three(X1Squared).Add(this.Curve.A).Divide(Two(Y1));
+ ECFieldElement X3 = gamma.Square().Subtract(Two(X1));
+ ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
- ECFieldElement X1Squared = X1.Square();
- ECFieldElement gamma = Three(X1Squared).Add(this.Curve.A).Divide(Two(Y1));
- ECFieldElement X3 = gamma.Square().Subtract(Two(X1));
- ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
+ return new FpPoint(Curve, X3, Y3, IsCompressed);
+ }
+
+ case ECCurve.COORD_HOMOGENEOUS:
+ {
+ ECFieldElement Z1 = this.GetZCoord(0);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ // TODO Optimize for small negative a4 and -3
+ ECFieldElement w = curve.A;
+ if (!w.IsZero && !Z1IsOne)
+ {
+ w = w.Multiply(Z1.Square());
+ }
+ w = w.Add(Three(X1.Square()));
+
+ ECFieldElement s = Z1IsOne ? Y1 : Y1.Multiply(Z1);
+ ECFieldElement t = Z1IsOne ? Y1.Square() : s.Multiply(Y1);
+ ECFieldElement B = X1.Multiply(t);
+ ECFieldElement _4B = Four(B);
+ ECFieldElement h = w.Square().Subtract(Two(_4B));
+
+ ECFieldElement _2s = Two(s);
+ ECFieldElement X3 = h.Multiply(_2s);
+ ECFieldElement _2t = Two(t);
+ ECFieldElement Y3 = _4B.Subtract(h).Multiply(w).Subtract(Two(_2t.Square()));
+ ECFieldElement _4sSquared = Z1IsOne ? Two(_2t) : _2s.Square();
+ ECFieldElement Z3 = Two(_4sSquared).Multiply(s);
+
+ return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
- return new FpPoint(Curve, X3, Y3, IsCompressed);
+ default:
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
}
public override ECPoint TwicePlus(ECPoint b)
@@ -459,79 +711,106 @@ namespace Org.BouncyCastle.Math.EC
return Twice();
}
- ECFieldElement Y1 = this.Y;
+ ECFieldElement Y1 = this.YCoord;
if (Y1.IsZero)
{
return b;
}
- ECFieldElement X1 = this.X;
- ECFieldElement X2 = b.X, Y2 = b.Y;
-
- ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
- if (dx.IsZero)
+ switch (coord)
{
- if (dy.IsZero)
+ case ECCurve.COORD_AFFINE:
{
- // this == b i.e. the result is 3P
- return ThreeTimes();
- }
+ ECFieldElement X1 = this.XCoord;
+ ECFieldElement X2 = b.XCoord, Y2 = b.YCoord;
- // this == -b, i.e. the result is P
- return this;
- }
+ ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);
- /*
- * Optimized calculation of 2P + Q, as described in "Trading Inversions for
- * Multiplications in Elliptic Curve Cryptography", by Ciet, Joye, Lauter, Montgomery.
- */
+ if (dx.IsZero)
+ {
+ if (dy.IsZero)
+ {
+ // this == b i.e. the result is 3P
+ return ThreeTimes();
+ }
- ECFieldElement X = dx.Square(), Y = dy.Square();
- ECFieldElement d = X.Multiply(Two(X1).Add(X2)).Subtract(Y);
- if (d.IsZero)
- {
- return Curve.Infinity;
- }
+ // this == -b, i.e. the result is P
+ return this;
+ }
- ECFieldElement D = d.Multiply(dx);
- ECFieldElement I = D.Invert();
- ECFieldElement L1 = d.Multiply(I).Multiply(dy);
- ECFieldElement L2 = Two(Y1).Multiply(X).Multiply(dx).Multiply(I).Subtract(L1);
- ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X2);
- ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1);
+ /*
+ * Optimized calculation of 2P + Q, as described in "Trading Inversions for
+ * Multiplications in Elliptic Curve Cryptography", by Ciet, Joye, Lauter, Montgomery.
+ */
- return new FpPoint(Curve, X4, Y4, IsCompressed);
+ ECFieldElement X = dx.Square(), Y = dy.Square();
+ ECFieldElement d = X.Multiply(Two(X1).Add(X2)).Subtract(Y);
+ if (d.IsZero)
+ {
+ return Curve.Infinity;
+ }
+
+ ECFieldElement D = d.Multiply(dx);
+ ECFieldElement I = D.Invert();
+ ECFieldElement L1 = d.Multiply(I).Multiply(dy);
+ ECFieldElement L2 = Two(Y1).Multiply(X).Multiply(dx).Multiply(I).Subtract(L1);
+ ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X2);
+ ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1);
+
+ return new FpPoint(Curve, X4, Y4, IsCompressed);
+ }
+ default:
+ {
+ return Twice().Add(b);
+ }
+ }
}
public override ECPoint ThreeTimes()
{
- if (IsInfinity || this.Y.IsZero)
+ if (IsInfinity || this.YCoord.IsZero)
{
return this;
}
- ECFieldElement X1 = this.X, Y1 = this.Y;
-
- ECFieldElement _2Y1 = Two(Y1);
- ECFieldElement X = _2Y1.Square();
- ECFieldElement Z = Three(X1.Square()).Add(Curve.A);
- ECFieldElement Y = Z.Square();
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
- ECFieldElement d = Three(X1).Multiply(X).Subtract(Y);
- if (d.IsZero)
+ switch (coord)
{
- return Curve.Infinity;
- }
+ case ECCurve.COORD_AFFINE:
+ {
+ ECFieldElement X1 = this.XCoord, Y1 = this.YCoord;
- ECFieldElement D = d.Multiply(_2Y1);
- ECFieldElement I = D.Invert();
- ECFieldElement L1 = d.Multiply(I).Multiply(Z);
- ECFieldElement L2 = X.Square().Multiply(I).Subtract(L1);
+ ECFieldElement _2Y1 = Two(Y1);
+ ECFieldElement X = _2Y1.Square();
+ ECFieldElement Z = Three(X1.Square()).Add(Curve.A);
+ ECFieldElement Y = Z.Square();
- ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X1);
- ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1);
- return new FpPoint(Curve, X4, Y4, IsCompressed);
+ ECFieldElement d = Three(X1).Multiply(X).Subtract(Y);
+ if (d.IsZero)
+ {
+ return Curve.Infinity;
+ }
+
+ ECFieldElement D = d.Multiply(_2Y1);
+ ECFieldElement I = D.Invert();
+ ECFieldElement L1 = d.Multiply(I).Multiply(Z);
+ ECFieldElement L2 = X.Square().Multiply(I).Subtract(L1);
+
+ ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X1);
+ ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1);
+ return new FpPoint(Curve, X4, Y4, IsCompressed);
+ }
+ default:
+ {
+ // NOTE: Be careful about recursions between twicePlus and threeTimes
+ return Twice().Add(this);
+ }
+ }
}
protected virtual ECFieldElement Two(ECFieldElement x)
@@ -583,14 +862,14 @@ namespace Org.BouncyCastle.Math.EC
}
ECCurve curve = this.Curve;
- //int coord = curve.CoordinateSystem;
+ int coord = curve.CoordinateSystem;
- //if (ECCurve.COORD_AFFINE != coord)
- //{
- // return new FpPoint(curve, X, Y.Negate(), this.m_zs, IsCompressed);
- //}
+ if (ECCurve.COORD_AFFINE != coord)
+ {
+ return new FpPoint(curve, XCoord, YCoord.Negate(), this.m_zs, IsCompressed);
+ }
- return new FpPoint(curve, X, Y.Negate(), IsCompressed);
+ return new FpPoint(curve, XCoord, YCoord.Negate(), IsCompressed);
}
}
@@ -637,10 +916,18 @@ namespace Org.BouncyCastle.Math.EC
F2mFieldElement.CheckFieldElements(x, y);
// Check if x and a are elements of the same field
- F2mFieldElement.CheckFieldElements(x, curve.A);
+ if (curve != null)
+ {
+ F2mFieldElement.CheckFieldElements(x, curve.A);
+ }
}
}
+ internal F2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
/**
* Constructor for point at infinity
*/
@@ -655,10 +942,28 @@ namespace Org.BouncyCastle.Math.EC
{
get
{
- // X9.62 4.2.2 and 4.3.6:
- // if x = 0 then ypTilde := 0, else ypTilde is the rightmost
- // bit of y * x^(-1)
- return !this.X.IsZero && this.Y.Divide(this.X).TestBitZero();
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ {
+ return false;
+ }
+
+ ECFieldElement Y = this.RawYCoord;
+
+ switch (this.CurveCoordinateSystem)
+ {
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ // Y is actually Lambda (X + Y/X) here
+ return Y.Subtract(X).TestBitZero();
+ }
+ default:
+ {
+ return Y.Divide(X).TestBitZero();
+ }
+ }
+
}
}
@@ -706,30 +1011,30 @@ namespace Org.BouncyCastle.Math.EC
if (b.IsInfinity)
return this;
- F2mFieldElement x2 = (F2mFieldElement) b.X;
- F2mFieldElement y2 = (F2mFieldElement) b.Y;
+ F2mFieldElement x2 = (F2mFieldElement) b.XCoord;
+ F2mFieldElement y2 = (F2mFieldElement) b.YCoord;
// Check if b == this or b == -this
- if (this.X.Equals(x2))
+ if (this.XCoord.Equals(x2))
{
// this == b, i.e. this must be doubled
- if (this.Y.Equals(y2))
+ if (this.YCoord.Equals(y2))
return (F2mPoint) this.Twice();
// this = -other, i.e. the result is the point at infinity
return (F2mPoint) Curve.Infinity;
}
- ECFieldElement xSum = this.X.Add(x2);
+ ECFieldElement xSum = this.XCoord.Add(x2);
F2mFieldElement lambda
- = (F2mFieldElement)(this.Y.Add(y2)).Divide(xSum);
+ = (F2mFieldElement)(this.YCoord.Add(y2)).Divide(xSum);
F2mFieldElement x3
= (F2mFieldElement)lambda.Square().Add(lambda).Add(xSum).Add(Curve.A);
F2mFieldElement y3
- = (F2mFieldElement)lambda.Multiply(this.X.Add(x3)).Add(x3).Add(this.Y);
+ = (F2mFieldElement)lambda.Multiply(this.XCoord.Add(x3)).Add(x3).Add(this.YCoord);
return new F2mPoint(Curve, x3, y3, IsCompressed);
}
@@ -763,6 +1068,39 @@ namespace Org.BouncyCastle.Math.EC
return AddSimple((F2mPoint) b.Negate());
}
+ public virtual F2mPoint Tau()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
+
+ ECFieldElement X1 = this.XCoord;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ {
+ ECFieldElement Y1 = this.YCoord;
+ return new F2mPoint(curve, X1.Square(), Y1.Square(), IsCompressed);
+ }
+ case ECCurve.COORD_HOMOGENEOUS:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ ECFieldElement Y1 = this.YCoord, Z1 = this.GetZCoord(0);
+ return new F2mPoint(curve, X1.Square(), Y1.Square(), new ECFieldElement[] { Z1.Square() }, IsCompressed);
+ }
+ default:
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
+ }
+
/* (non-Javadoc)
* @see Org.BouncyCastle.Math.EC.ECPoint#twice()
*/
@@ -774,15 +1112,15 @@ namespace Org.BouncyCastle.Math.EC
// if x1 == 0, then (x1, y1) == (x1, x1 + y1)
// and hence this = -this and thus 2(x1, y1) == infinity
- if (this.X.IsZero)
+ if (this.XCoord.IsZero)
{
return Curve.Infinity;
}
- F2mFieldElement lambda = (F2mFieldElement) this.X.Add(this.Y.Divide(this.X));
+ F2mFieldElement lambda = (F2mFieldElement) this.XCoord.Add(this.YCoord.Divide(this.XCoord));
F2mFieldElement x2 = (F2mFieldElement)lambda.Square().Add(lambda).Add(Curve.A);
ECFieldElement ONE = Curve.FromBigInteger(BigInteger.One);
- F2mFieldElement y2 = (F2mFieldElement)this.X.Square().Add(
+ F2mFieldElement y2 = (F2mFieldElement)this.XCoord.Square().Add(
x2.Multiply(lambda.Add(ONE)));
return new F2mPoint(Curve, x2, y2, IsCompressed);
@@ -795,13 +1133,13 @@ namespace Org.BouncyCastle.Math.EC
return this;
}
- ECFieldElement X1 = this.X;
+ ECFieldElement X1 = this.XCoord;
if (X1.IsZero)
{
return this;
}
- return new F2mPoint(Curve, X1, X1.Add(this.Y), IsCompressed);
+ return new F2mPoint(Curve, X1, X1.Add(this.YCoord), IsCompressed);
}
}
}
diff --git a/crypto/src/math/ec/abc/Tnaf.cs b/crypto/src/math/ec/abc/Tnaf.cs
index 225fc3075..0ba414e68 100644
--- a/crypto/src/math/ec/abc/Tnaf.cs
+++ b/crypto/src/math/ec/abc/Tnaf.cs
@@ -2,833 +2,827 @@ using System;
namespace Org.BouncyCastle.Math.EC.Abc
{
- /**
- * Class holding methods for point multiplication based on the window
- * τ-adic nonadjacent form (WTNAF). The algorithms are based on the
- * paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves"
- * by Jerome A. Solinas. The paper first appeared in the Proceedings of
- * Crypto 1997.
- */
- internal class Tnaf
- {
- private static readonly BigInteger MinusOne = BigInteger.One.Negate();
- private static readonly BigInteger MinusTwo = BigInteger.Two.Negate();
- private static readonly BigInteger MinusThree = BigInteger.Three.Negate();
- private static readonly BigInteger Four = BigInteger.ValueOf(4);
-
- /**
- * The window width of WTNAF. The standard value of 4 is slightly less
- * than optimal for running time, but keeps space requirements for
- * precomputation low. For typical curves, a value of 5 or 6 results in
- * a better running time. When changing this value, the
- * <code>α<sub>u</sub></code>'s must be computed differently, see
- * e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson,
- * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004,
- * p. 121-122
- */
- public const sbyte Width = 4;
-
- /**
- * 2<sup>4</sup>
- */
- public const sbyte Pow2Width = 16;
-
- /**
- * The <code>α<sub>u</sub></code>'s for <code>a=0</code> as an array
- * of <code>ZTauElement</code>s.
- */
- public static readonly ZTauElement[] Alpha0 =
- {
- null,
- new ZTauElement(BigInteger.One, BigInteger.Zero), null,
- new ZTauElement(MinusThree, MinusOne), null,
- new ZTauElement(MinusOne, MinusOne), null,
- new ZTauElement(BigInteger.One, MinusOne), null
- };
-
- /**
- * The <code>α<sub>u</sub></code>'s for <code>a=0</code> as an array
- * of TNAFs.
- */
- public static readonly sbyte[][] Alpha0Tnaf =
- {
- null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, 1}
- };
-
- /**
- * The <code>α<sub>u</sub></code>'s for <code>a=1</code> as an array
- * of <code>ZTauElement</code>s.
- */
- public static readonly ZTauElement[] Alpha1 =
- {
- null,
- new ZTauElement(BigInteger.One, BigInteger.Zero), null,
- new ZTauElement(MinusThree, BigInteger.One), null,
- new ZTauElement(MinusOne, BigInteger.One), null,
- new ZTauElement(BigInteger.One, BigInteger.One), null
- };
-
- /**
- * The <code>α<sub>u</sub></code>'s for <code>a=1</code> as an array
- * of TNAFs.
- */
- public static readonly sbyte[][] Alpha1Tnaf =
- {
- null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, -1}
- };
-
- /**
- * Computes the norm of an element <code>λ</code> of
- * <code><b>Z</b>[τ]</code>.
- * @param mu The parameter <code>μ</code> of the elliptic curve.
- * @param lambda The element <code>λ</code> of
- * <code><b>Z</b>[τ]</code>.
- * @return The norm of <code>λ</code>.
- */
- public static BigInteger Norm(sbyte mu, ZTauElement lambda)
- {
- BigInteger norm;
-
- // s1 = u^2
- BigInteger s1 = lambda.u.Multiply(lambda.u);
-
- // s2 = u * v
- BigInteger s2 = lambda.u.Multiply(lambda.v);
-
- // s3 = 2 * v^2
- BigInteger s3 = lambda.v.Multiply(lambda.v).ShiftLeft(1);
-
- if (mu == 1)
- {
- norm = s1.Add(s2).Add(s3);
- }
- else if (mu == -1)
- {
- norm = s1.Subtract(s2).Add(s3);
- }
- else
- {
- throw new ArgumentException("mu must be 1 or -1");
- }
-
- return norm;
- }
-
- /**
- * Computes the norm of an element <code>λ</code> of
- * <code><b>R</b>[τ]</code>, where <code>λ = u + vτ</code>
- * and <code>u</code> and <code>u</code> are real numbers (elements of
- * <code><b>R</b></code>).
- * @param mu The parameter <code>μ</code> of the elliptic curve.
- * @param u The real part of the element <code>λ</code> of
- * <code><b>R</b>[τ]</code>.
- * @param v The <code>τ</code>-adic part of the element
- * <code>λ</code> of <code><b>R</b>[τ]</code>.
- * @return The norm of <code>λ</code>.
- */
- public static SimpleBigDecimal Norm(sbyte mu, SimpleBigDecimal u, SimpleBigDecimal v)
- {
- SimpleBigDecimal norm;
-
- // s1 = u^2
- SimpleBigDecimal s1 = u.Multiply(u);
-
- // s2 = u * v
- SimpleBigDecimal s2 = u.Multiply(v);
-
- // s3 = 2 * v^2
- SimpleBigDecimal s3 = v.Multiply(v).ShiftLeft(1);
-
- if (mu == 1)
- {
- norm = s1.Add(s2).Add(s3);
- }
- else if (mu == -1)
- {
- norm = s1.Subtract(s2).Add(s3);
- }
- else
- {
- throw new ArgumentException("mu must be 1 or -1");
- }
-
- return norm;
- }
-
- /**
- * Rounds an element <code>λ</code> of <code><b>R</b>[τ]</code>
- * to an element of <code><b>Z</b>[τ]</code>, such that their difference
- * has minimal norm. <code>λ</code> is given as
- * <code>λ = λ<sub>0</sub> + λ<sub>1</sub>τ</code>.
- * @param lambda0 The component <code>λ<sub>0</sub></code>.
- * @param lambda1 The component <code>λ<sub>1</sub></code>.
- * @param mu The parameter <code>μ</code> of the elliptic curve. Must
- * equal 1 or -1.
- * @return The rounded element of <code><b>Z</b>[τ]</code>.
- * @throws ArgumentException if <code>lambda0</code> and
- * <code>lambda1</code> do not have same scale.
- */
- public static ZTauElement Round(SimpleBigDecimal lambda0,
- SimpleBigDecimal lambda1, sbyte mu)
- {
- int scale = lambda0.Scale;
- if (lambda1.Scale != scale)
- throw new ArgumentException("lambda0 and lambda1 do not have same scale");
-
- if (!((mu == 1) || (mu == -1)))
- throw new ArgumentException("mu must be 1 or -1");
-
- BigInteger f0 = lambda0.Round();
- BigInteger f1 = lambda1.Round();
-
- SimpleBigDecimal eta0 = lambda0.Subtract(f0);
- SimpleBigDecimal eta1 = lambda1.Subtract(f1);
-
- // eta = 2*eta0 + mu*eta1
- SimpleBigDecimal eta = eta0.Add(eta0);
- if (mu == 1)
- {
- eta = eta.Add(eta1);
- }
- else
- {
- // mu == -1
- eta = eta.Subtract(eta1);
- }
-
- // check1 = eta0 - 3*mu*eta1
- // check2 = eta0 + 4*mu*eta1
- SimpleBigDecimal threeEta1 = eta1.Add(eta1).Add(eta1);
- SimpleBigDecimal fourEta1 = threeEta1.Add(eta1);
- SimpleBigDecimal check1;
- SimpleBigDecimal check2;
- if (mu == 1)
- {
- check1 = eta0.Subtract(threeEta1);
- check2 = eta0.Add(fourEta1);
- }
- else
- {
- // mu == -1
- check1 = eta0.Add(threeEta1);
- check2 = eta0.Subtract(fourEta1);
- }
-
- sbyte h0 = 0;
- sbyte h1 = 0;
-
- // if eta >= 1
- if (eta.CompareTo(BigInteger.One) >= 0)
- {
- if (check1.CompareTo(MinusOne) < 0)
- {
- h1 = mu;
- }
- else
- {
- h0 = 1;
- }
- }
- else
- {
- // eta < 1
- if (check2.CompareTo(BigInteger.Two) >= 0)
- {
- h1 = mu;
- }
- }
-
- // if eta < -1
- if (eta.CompareTo(MinusOne) < 0)
- {
- if (check1.CompareTo(BigInteger.One) >= 0)
- {
- h1 = (sbyte)-mu;
- }
- else
- {
- h0 = -1;
- }
- }
- else
- {
- // eta >= -1
- if (check2.CompareTo(MinusTwo) < 0)
- {
- h1 = (sbyte)-mu;
- }
- }
-
- BigInteger q0 = f0.Add(BigInteger.ValueOf(h0));
- BigInteger q1 = f1.Add(BigInteger.ValueOf(h1));
- return new ZTauElement(q0, q1);
- }
-
- /**
- * Approximate division by <code>n</code>. For an integer
- * <code>k</code>, the value <code>λ = s k / n</code> is
- * computed to <code>c</code> bits of accuracy.
- * @param k The parameter <code>k</code>.
- * @param s The curve parameter <code>s<sub>0</sub></code> or
- * <code>s<sub>1</sub></code>.
- * @param vm The Lucas Sequence element <code>V<sub>m</sub></code>.
- * @param a The parameter <code>a</code> of the elliptic curve.
- * @param m The bit length of the finite field
- * <code><b>F</b><sub>m</sub></code>.
- * @param c The number of bits of accuracy, i.e. the scale of the returned
- * <code>SimpleBigDecimal</code>.
- * @return The value <code>λ = s k / n</code> computed to
- * <code>c</code> bits of accuracy.
- */
- public static SimpleBigDecimal ApproximateDivisionByN(BigInteger k,
- BigInteger s, BigInteger vm, sbyte a, int m, int c)
- {
- int _k = (m + 5)/2 + c;
- BigInteger ns = k.ShiftRight(m - _k - 2 + a);
-
- BigInteger gs = s.Multiply(ns);
-
- BigInteger hs = gs.ShiftRight(m);
-
- BigInteger js = vm.Multiply(hs);
-
- BigInteger gsPlusJs = gs.Add(js);
- BigInteger ls = gsPlusJs.ShiftRight(_k-c);
- if (gsPlusJs.TestBit(_k-c-1))
- {
- // round up
- ls = ls.Add(BigInteger.One);
- }
-
- return new SimpleBigDecimal(ls, c);
- }
-
- /**
- * Computes the <code>τ</code>-adic NAF (non-adjacent form) of an
- * element <code>λ</code> of <code><b>Z</b>[τ]</code>.
- * @param mu The parameter <code>μ</code> of the elliptic curve.
- * @param lambda The element <code>λ</code> of
- * <code><b>Z</b>[τ]</code>.
- * @return The <code>τ</code>-adic NAF of <code>λ</code>.
- */
- public static sbyte[] TauAdicNaf(sbyte mu, ZTauElement lambda)
- {
- if (!((mu == 1) || (mu == -1)))
- throw new ArgumentException("mu must be 1 or -1");
-
- BigInteger norm = Norm(mu, lambda);
-
- // Ceiling of log2 of the norm
- int log2Norm = norm.BitLength;
-
- // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
- int maxLength = log2Norm > 30 ? log2Norm + 4 : 34;
-
- // The array holding the TNAF
- sbyte[] u = new sbyte[maxLength];
- int i = 0;
-
- // The actual length of the TNAF
- int length = 0;
-
- BigInteger r0 = lambda.u;
- BigInteger r1 = lambda.v;
-
- while(!((r0.Equals(BigInteger.Zero)) && (r1.Equals(BigInteger.Zero))))
- {
- // If r0 is odd
- if (r0.TestBit(0))
- {
- u[i] = (sbyte) BigInteger.Two.Subtract((r0.Subtract(r1.ShiftLeft(1))).Mod(Four)).IntValue;
-
- // r0 = r0 - u[i]
- if (u[i] == 1)
- {
- r0 = r0.ClearBit(0);
- }
- else
- {
- // u[i] == -1
- r0 = r0.Add(BigInteger.One);
- }
- length = i;
- }
- else
- {
- u[i] = 0;
- }
-
- BigInteger t = r0;
- BigInteger s = r0.ShiftRight(1);
- if (mu == 1)
- {
- r0 = r1.Add(s);
- }
- else
- {
- // mu == -1
- r0 = r1.Subtract(s);
- }
-
- r1 = t.ShiftRight(1).Negate();
- i++;
- }
-
- length++;
-
- // Reduce the TNAF array to its actual length
- sbyte[] tnaf = new sbyte[length];
- Array.Copy(u, 0, tnaf, 0, length);
- return tnaf;
- }
-
- /**
- * Applies the operation <code>τ()</code> to an
- * <code>F2mPoint</code>.
- * @param p The F2mPoint to which <code>τ()</code> is applied.
- * @return <code>τ(p)</code>
- */
- public static F2mPoint Tau(F2mPoint p)
- {
- if (p.IsInfinity)
- return p;
-
- ECFieldElement x = p.X;
- ECFieldElement y = p.Y;
-
- return new F2mPoint(p.Curve, x.Square(), y.Square(), p.IsCompressed);
- }
-
- /**
- * Returns the parameter <code>μ</code> of the elliptic curve.
- * @param curve The elliptic curve from which to obtain <code>μ</code>.
- * The curve must be a Koblitz curve, i.e. <code>a</code> Equals
- * <code>0</code> or <code>1</code> and <code>b</code> Equals
- * <code>1</code>.
- * @return <code>μ</code> of the elliptic curve.
- * @throws ArgumentException if the given ECCurve is not a Koblitz
- * curve.
- */
- public static sbyte GetMu(F2mCurve curve)
- {
- BigInteger a = curve.A.ToBigInteger();
-
- sbyte mu;
- if (a.SignValue == 0)
- {
- mu = -1;
- }
- else if (a.Equals(BigInteger.One))
- {
- mu = 1;
- }
- else
- {
- throw new ArgumentException("No Koblitz curve (ABC), TNAF multiplication not possible");
- }
- return mu;
- }
-
- /**
- * Calculates the Lucas Sequence elements <code>U<sub>k-1</sub></code> and
- * <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code> and
- * <code>V<sub>k</sub></code>.
- * @param mu The parameter <code>μ</code> of the elliptic curve.
- * @param k The index of the second element of the Lucas Sequence to be
- * returned.
- * @param doV If set to true, computes <code>V<sub>k-1</sub></code> and
- * <code>V<sub>k</sub></code>, otherwise <code>U<sub>k-1</sub></code> and
- * <code>U<sub>k</sub></code>.
- * @return An array with 2 elements, containing <code>U<sub>k-1</sub></code>
- * and <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code>
- * and <code>V<sub>k</sub></code>.
- */
- public static BigInteger[] GetLucas(sbyte mu, int k, bool doV)
- {
- if (!(mu == 1 || mu == -1))
- throw new ArgumentException("mu must be 1 or -1");
-
- BigInteger u0;
- BigInteger u1;
- BigInteger u2;
-
- if (doV)
- {
- u0 = BigInteger.Two;
- u1 = BigInteger.ValueOf(mu);
- }
- else
- {
- u0 = BigInteger.Zero;
- u1 = BigInteger.One;
- }
-
- for (int i = 1; i < k; i++)
- {
- // u2 = mu*u1 - 2*u0;
- BigInteger s = null;
- if (mu == 1)
- {
- s = u1;
- }
- else
- {
- // mu == -1
- s = u1.Negate();
- }
-
- u2 = s.Subtract(u0.ShiftLeft(1));
- u0 = u1;
- u1 = u2;
- // System.out.println(i + ": " + u2);
- // System.out.println();
- }
-
- BigInteger[] retVal = {u0, u1};
- return retVal;
- }
-
- /**
- * Computes the auxiliary value <code>t<sub>w</sub></code>. If the width is
- * 4, then for <code>mu = 1</code>, <code>t<sub>w</sub> = 6</code> and for
- * <code>mu = -1</code>, <code>t<sub>w</sub> = 10</code>
- * @param mu The parameter <code>μ</code> of the elliptic curve.
- * @param w The window width of the WTNAF.
- * @return the auxiliary value <code>t<sub>w</sub></code>
- */
- public static BigInteger GetTw(sbyte mu, int w)
- {
- if (w == 4)
- {
- if (mu == 1)
- {
- return BigInteger.ValueOf(6);
- }
- else
- {
- // mu == -1
- return BigInteger.ValueOf(10);
- }
- }
- else
- {
- // For w <> 4, the values must be computed
- BigInteger[] us = GetLucas(mu, w, false);
- BigInteger twoToW = BigInteger.Zero.SetBit(w);
- BigInteger u1invert = us[1].ModInverse(twoToW);
- BigInteger tw;
- tw = BigInteger.Two.Multiply(us[0]).Multiply(u1invert).Mod(twoToW);
- //System.out.println("mu = " + mu);
- //System.out.println("tw = " + tw);
- return tw;
- }
- }
-
- /**
- * Computes the auxiliary values <code>s<sub>0</sub></code> and
- * <code>s<sub>1</sub></code> used for partial modular reduction.
- * @param curve The elliptic curve for which to compute
- * <code>s<sub>0</sub></code> and <code>s<sub>1</sub></code>.
- * @throws ArgumentException if <code>curve</code> is not a
- * Koblitz curve (Anomalous Binary Curve, ABC).
- */
- public static BigInteger[] GetSi(F2mCurve curve)
- {
- if (!curve.IsKoblitz)
- throw new ArgumentException("si is defined for Koblitz curves only");
-
- int m = curve.M;
- int a = curve.A.ToBigInteger().IntValue;
- sbyte mu = curve.GetMu();
- int h = curve.H.IntValue;
- int index = m + 3 - a;
- BigInteger[] ui = GetLucas(mu, index, false);
-
- BigInteger dividend0;
- BigInteger dividend1;
- if (mu == 1)
- {
- dividend0 = BigInteger.One.Subtract(ui[1]);
- dividend1 = BigInteger.One.Subtract(ui[0]);
- }
- else if (mu == -1)
- {
- dividend0 = BigInteger.One.Add(ui[1]);
- dividend1 = BigInteger.One.Add(ui[0]);
- }
- else
- {
- throw new ArgumentException("mu must be 1 or -1");
- }
-
- BigInteger[] si = new BigInteger[2];
-
- if (h == 2)
- {
- si[0] = dividend0.ShiftRight(1);
- si[1] = dividend1.ShiftRight(1).Negate();
- }
- else if (h == 4)
- {
- si[0] = dividend0.ShiftRight(2);
- si[1] = dividend1.ShiftRight(2).Negate();
- }
- else
- {
- throw new ArgumentException("h (Cofactor) must be 2 or 4");
- }
-
- return si;
- }
-
- /**
- * Partial modular reduction modulo
- * <code>(τ<sup>m</sup> - 1)/(τ - 1)</code>.
- * @param k The integer to be reduced.
- * @param m The bitlength of the underlying finite field.
- * @param a The parameter <code>a</code> of the elliptic curve.
- * @param s The auxiliary values <code>s<sub>0</sub></code> and
- * <code>s<sub>1</sub></code>.
- * @param mu The parameter μ of the elliptic curve.
- * @param c The precision (number of bits of accuracy) of the partial
- * modular reduction.
- * @return <code>ρ := k partmod (τ<sup>m</sup> - 1)/(τ - 1)</code>
- */
- public static ZTauElement PartModReduction(BigInteger k, int m, sbyte a,
- BigInteger[] s, sbyte mu, sbyte c)
- {
- // d0 = s[0] + mu*s[1]; mu is either 1 or -1
- BigInteger d0;
- if (mu == 1)
- {
- d0 = s[0].Add(s[1]);
- }
- else
- {
- d0 = s[0].Subtract(s[1]);
- }
-
- BigInteger[] v = GetLucas(mu, m, true);
- BigInteger vm = v[1];
-
- SimpleBigDecimal lambda0 = ApproximateDivisionByN(
- k, s[0], vm, a, m, c);
-
- SimpleBigDecimal lambda1 = ApproximateDivisionByN(
- k, s[1], vm, a, m, c);
-
- ZTauElement q = Round(lambda0, lambda1, mu);
-
- // r0 = n - d0*q0 - 2*s1*q1
- BigInteger r0 = k.Subtract(d0.Multiply(q.u)).Subtract(
- BigInteger.ValueOf(2).Multiply(s[1]).Multiply(q.v));
-
- // r1 = s1*q0 - s0*q1
- BigInteger r1 = s[1].Multiply(q.u).Subtract(s[0].Multiply(q.v));
-
- return new ZTauElement(r0, r1);
- }
-
- /**
- * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
- * by a <code>BigInteger</code> using the reduced <code>τ</code>-adic
- * NAF (RTNAF) method.
- * @param p The F2mPoint to Multiply.
- * @param k The <code>BigInteger</code> by which to Multiply <code>p</code>.
- * @return <code>k * p</code>
- */
- public static F2mPoint MultiplyRTnaf(F2mPoint p, BigInteger k)
- {
- F2mCurve curve = (F2mCurve) p.Curve;
- int m = curve.M;
- sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
- sbyte mu = curve.GetMu();
- BigInteger[] s = curve.GetSi();
- ZTauElement rho = PartModReduction(k, m, a, s, mu, (sbyte)10);
-
- return MultiplyTnaf(p, rho);
- }
-
- /**
- * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
- * by an element <code>λ</code> of <code><b>Z</b>[τ]</code>
- * using the <code>τ</code>-adic NAF (TNAF) method.
- * @param p The F2mPoint to Multiply.
- * @param lambda The element <code>λ</code> of
- * <code><b>Z</b>[τ]</code>.
- * @return <code>λ * p</code>
- */
- public static F2mPoint MultiplyTnaf(F2mPoint p, ZTauElement lambda)
- {
- F2mCurve curve = (F2mCurve)p.Curve;
- sbyte mu = curve.GetMu();
- sbyte[] u = TauAdicNaf(mu, lambda);
-
- F2mPoint q = MultiplyFromTnaf(p, u);
-
- return q;
- }
-
- /**
- * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
- * by an element <code>λ</code> of <code><b>Z</b>[τ]</code>
- * using the <code>τ</code>-adic NAF (TNAF) method, given the TNAF
- * of <code>λ</code>.
- * @param p The F2mPoint to Multiply.
- * @param u The the TNAF of <code>λ</code>..
- * @return <code>λ * p</code>
- */
- public static F2mPoint MultiplyFromTnaf(F2mPoint p, sbyte[] u)
- {
- F2mCurve curve = (F2mCurve)p.Curve;
- F2mPoint q = (F2mPoint) curve.Infinity;
- for (int i = u.Length - 1; i >= 0; i--)
- {
- q = Tau(q);
- if (u[i] == 1)
- {
- q = (F2mPoint)q.AddSimple(p);
- }
- else if (u[i] == -1)
- {
- q = (F2mPoint)q.SubtractSimple(p);
- }
- }
- return q;
- }
-
- /**
- * Computes the <code>[τ]</code>-adic window NAF of an element
- * <code>λ</code> of <code><b>Z</b>[τ]</code>.
- * @param mu The parameter μ of the elliptic curve.
- * @param lambda The element <code>λ</code> of
- * <code><b>Z</b>[τ]</code> of which to compute the
- * <code>[τ]</code>-adic NAF.
- * @param width The window width of the resulting WNAF.
- * @param pow2w 2<sup>width</sup>.
- * @param tw The auxiliary value <code>t<sub>w</sub></code>.
- * @param alpha The <code>α<sub>u</sub></code>'s for the window width.
- * @return The <code>[τ]</code>-adic window NAF of
- * <code>λ</code>.
- */
- public static sbyte[] TauAdicWNaf(sbyte mu, ZTauElement lambda,
- sbyte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)
- {
- if (!((mu == 1) || (mu == -1)))
- throw new ArgumentException("mu must be 1 or -1");
-
- BigInteger norm = Norm(mu, lambda);
-
- // Ceiling of log2 of the norm
- int log2Norm = norm.BitLength;
-
- // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
- int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width;
-
- // The array holding the TNAF
- sbyte[] u = new sbyte[maxLength];
-
- // 2^(width - 1)
- BigInteger pow2wMin1 = pow2w.ShiftRight(1);
-
- // Split lambda into two BigIntegers to simplify calculations
- BigInteger r0 = lambda.u;
- BigInteger r1 = lambda.v;
- int i = 0;
-
- // while lambda <> (0, 0)
- while (!((r0.Equals(BigInteger.Zero))&&(r1.Equals(BigInteger.Zero))))
- {
- // if r0 is odd
- if (r0.TestBit(0))
- {
- // uUnMod = r0 + r1*tw Mod 2^width
- BigInteger uUnMod
- = r0.Add(r1.Multiply(tw)).Mod(pow2w);
-
- sbyte uLocal;
- // if uUnMod >= 2^(width - 1)
- if (uUnMod.CompareTo(pow2wMin1) >= 0)
- {
- uLocal = (sbyte) uUnMod.Subtract(pow2w).IntValue;
- }
- else
- {
- uLocal = (sbyte) uUnMod.IntValue;
- }
- // uLocal is now in [-2^(width-1), 2^(width-1)-1]
-
- u[i] = uLocal;
- bool s = true;
- if (uLocal < 0)
- {
- s = false;
- uLocal = (sbyte)-uLocal;
- }
- // uLocal is now >= 0
-
- if (s)
- {
- r0 = r0.Subtract(alpha[uLocal].u);
- r1 = r1.Subtract(alpha[uLocal].v);
- }
- else
- {
- r0 = r0.Add(alpha[uLocal].u);
- r1 = r1.Add(alpha[uLocal].v);
- }
- }
- else
- {
- u[i] = 0;
- }
-
- BigInteger t = r0;
-
- if (mu == 1)
- {
- r0 = r1.Add(r0.ShiftRight(1));
- }
- else
- {
- // mu == -1
- r0 = r1.Subtract(r0.ShiftRight(1));
- }
- r1 = t.ShiftRight(1).Negate();
- i++;
- }
- return u;
- }
-
- /**
- * Does the precomputation for WTNAF multiplication.
- * @param p The <code>ECPoint</code> for which to do the precomputation.
- * @param a The parameter <code>a</code> of the elliptic curve.
- * @return The precomputation array for <code>p</code>.
- */
- public static F2mPoint[] GetPreComp(F2mPoint p, sbyte a)
- {
- F2mPoint[] pu;
- pu = new F2mPoint[16];
- pu[1] = p;
- sbyte[][] alphaTnaf;
- if (a == 0)
- {
- alphaTnaf = Tnaf.Alpha0Tnaf;
- }
- else
- {
- // a == 1
- alphaTnaf = Tnaf.Alpha1Tnaf;
- }
-
- int precompLen = alphaTnaf.Length;
- for (int i = 3; i < precompLen; i = i + 2)
- {
- pu[i] = Tnaf.MultiplyFromTnaf(p, alphaTnaf[i]);
- }
-
- return pu;
- }
- }
+ /**
+ * Class holding methods for point multiplication based on the window
+ * τ-adic nonadjacent form (WTNAF). The algorithms are based on the
+ * paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves"
+ * by Jerome A. Solinas. The paper first appeared in the Proceedings of
+ * Crypto 1997.
+ */
+ internal class Tnaf
+ {
+ private static readonly BigInteger MinusOne = BigInteger.One.Negate();
+ private static readonly BigInteger MinusTwo = BigInteger.Two.Negate();
+ private static readonly BigInteger MinusThree = BigInteger.Three.Negate();
+ private static readonly BigInteger Four = BigInteger.ValueOf(4);
+
+ /**
+ * The window width of WTNAF. The standard value of 4 is slightly less
+ * than optimal for running time, but keeps space requirements for
+ * precomputation low. For typical curves, a value of 5 or 6 results in
+ * a better running time. When changing this value, the
+ * <code>α<sub>u</sub></code>'s must be computed differently, see
+ * e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson,
+ * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004,
+ * p. 121-122
+ */
+ public const sbyte Width = 4;
+
+ /**
+ * 2<sup>4</sup>
+ */
+ public const sbyte Pow2Width = 16;
+
+ /**
+ * The <code>α<sub>u</sub></code>'s for <code>a=0</code> as an array
+ * of <code>ZTauElement</code>s.
+ */
+ public static readonly ZTauElement[] Alpha0 =
+ {
+ null,
+ new ZTauElement(BigInteger.One, BigInteger.Zero), null,
+ new ZTauElement(MinusThree, MinusOne), null,
+ new ZTauElement(MinusOne, MinusOne), null,
+ new ZTauElement(BigInteger.One, MinusOne), null
+ };
+
+ /**
+ * The <code>α<sub>u</sub></code>'s for <code>a=0</code> as an array
+ * of TNAFs.
+ */
+ public static readonly sbyte[][] Alpha0Tnaf =
+ {
+ null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, 1}
+ };
+
+ /**
+ * The <code>α<sub>u</sub></code>'s for <code>a=1</code> as an array
+ * of <code>ZTauElement</code>s.
+ */
+ public static readonly ZTauElement[] Alpha1 =
+ {
+ null,
+ new ZTauElement(BigInteger.One, BigInteger.Zero), null,
+ new ZTauElement(MinusThree, BigInteger.One), null,
+ new ZTauElement(MinusOne, BigInteger.One), null,
+ new ZTauElement(BigInteger.One, BigInteger.One), null
+ };
+
+ /**
+ * The <code>α<sub>u</sub></code>'s for <code>a=1</code> as an array
+ * of TNAFs.
+ */
+ public static readonly sbyte[][] Alpha1Tnaf =
+ {
+ null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, -1}
+ };
+
+ /**
+ * Computes the norm of an element <code>λ</code> of
+ * <code><b>Z</b>[τ]</code>.
+ * @param mu The parameter <code>μ</code> of the elliptic curve.
+ * @param lambda The element <code>λ</code> of
+ * <code><b>Z</b>[τ]</code>.
+ * @return The norm of <code>λ</code>.
+ */
+ public static BigInteger Norm(sbyte mu, ZTauElement lambda)
+ {
+ BigInteger norm;
+
+ // s1 = u^2
+ BigInteger s1 = lambda.u.Multiply(lambda.u);
+
+ // s2 = u * v
+ BigInteger s2 = lambda.u.Multiply(lambda.v);
+
+ // s3 = 2 * v^2
+ BigInteger s3 = lambda.v.Multiply(lambda.v).ShiftLeft(1);
+
+ if (mu == 1)
+ {
+ norm = s1.Add(s2).Add(s3);
+ }
+ else if (mu == -1)
+ {
+ norm = s1.Subtract(s2).Add(s3);
+ }
+ else
+ {
+ throw new ArgumentException("mu must be 1 or -1");
+ }
+
+ return norm;
+ }
+
+ /**
+ * Computes the norm of an element <code>λ</code> of
+ * <code><b>R</b>[τ]</code>, where <code>λ = u + vτ</code>
+ * and <code>u</code> and <code>u</code> are real numbers (elements of
+ * <code><b>R</b></code>).
+ * @param mu The parameter <code>μ</code> of the elliptic curve.
+ * @param u The real part of the element <code>λ</code> of
+ * <code><b>R</b>[τ]</code>.
+ * @param v The <code>τ</code>-adic part of the element
+ * <code>λ</code> of <code><b>R</b>[τ]</code>.
+ * @return The norm of <code>λ</code>.
+ */
+ public static SimpleBigDecimal Norm(sbyte mu, SimpleBigDecimal u, SimpleBigDecimal v)
+ {
+ SimpleBigDecimal norm;
+
+ // s1 = u^2
+ SimpleBigDecimal s1 = u.Multiply(u);
+
+ // s2 = u * v
+ SimpleBigDecimal s2 = u.Multiply(v);
+
+ // s3 = 2 * v^2
+ SimpleBigDecimal s3 = v.Multiply(v).ShiftLeft(1);
+
+ if (mu == 1)
+ {
+ norm = s1.Add(s2).Add(s3);
+ }
+ else if (mu == -1)
+ {
+ norm = s1.Subtract(s2).Add(s3);
+ }
+ else
+ {
+ throw new ArgumentException("mu must be 1 or -1");
+ }
+
+ return norm;
+ }
+
+ /**
+ * Rounds an element <code>λ</code> of <code><b>R</b>[τ]</code>
+ * to an element of <code><b>Z</b>[τ]</code>, such that their difference
+ * has minimal norm. <code>λ</code> is given as
+ * <code>λ = λ<sub>0</sub> + λ<sub>1</sub>τ</code>.
+ * @param lambda0 The component <code>λ<sub>0</sub></code>.
+ * @param lambda1 The component <code>λ<sub>1</sub></code>.
+ * @param mu The parameter <code>μ</code> of the elliptic curve. Must
+ * equal 1 or -1.
+ * @return The rounded element of <code><b>Z</b>[τ]</code>.
+ * @throws ArgumentException if <code>lambda0</code> and
+ * <code>lambda1</code> do not have same scale.
+ */
+ public static ZTauElement Round(SimpleBigDecimal lambda0,
+ SimpleBigDecimal lambda1, sbyte mu)
+ {
+ int scale = lambda0.Scale;
+ if (lambda1.Scale != scale)
+ throw new ArgumentException("lambda0 and lambda1 do not have same scale");
+
+ if (!((mu == 1) || (mu == -1)))
+ throw new ArgumentException("mu must be 1 or -1");
+
+ BigInteger f0 = lambda0.Round();
+ BigInteger f1 = lambda1.Round();
+
+ SimpleBigDecimal eta0 = lambda0.Subtract(f0);
+ SimpleBigDecimal eta1 = lambda1.Subtract(f1);
+
+ // eta = 2*eta0 + mu*eta1
+ SimpleBigDecimal eta = eta0.Add(eta0);
+ if (mu == 1)
+ {
+ eta = eta.Add(eta1);
+ }
+ else
+ {
+ // mu == -1
+ eta = eta.Subtract(eta1);
+ }
+
+ // check1 = eta0 - 3*mu*eta1
+ // check2 = eta0 + 4*mu*eta1
+ SimpleBigDecimal threeEta1 = eta1.Add(eta1).Add(eta1);
+ SimpleBigDecimal fourEta1 = threeEta1.Add(eta1);
+ SimpleBigDecimal check1;
+ SimpleBigDecimal check2;
+ if (mu == 1)
+ {
+ check1 = eta0.Subtract(threeEta1);
+ check2 = eta0.Add(fourEta1);
+ }
+ else
+ {
+ // mu == -1
+ check1 = eta0.Add(threeEta1);
+ check2 = eta0.Subtract(fourEta1);
+ }
+
+ sbyte h0 = 0;
+ sbyte h1 = 0;
+
+ // if eta >= 1
+ if (eta.CompareTo(BigInteger.One) >= 0)
+ {
+ if (check1.CompareTo(MinusOne) < 0)
+ {
+ h1 = mu;
+ }
+ else
+ {
+ h0 = 1;
+ }
+ }
+ else
+ {
+ // eta < 1
+ if (check2.CompareTo(BigInteger.Two) >= 0)
+ {
+ h1 = mu;
+ }
+ }
+
+ // if eta < -1
+ if (eta.CompareTo(MinusOne) < 0)
+ {
+ if (check1.CompareTo(BigInteger.One) >= 0)
+ {
+ h1 = (sbyte)-mu;
+ }
+ else
+ {
+ h0 = -1;
+ }
+ }
+ else
+ {
+ // eta >= -1
+ if (check2.CompareTo(MinusTwo) < 0)
+ {
+ h1 = (sbyte)-mu;
+ }
+ }
+
+ BigInteger q0 = f0.Add(BigInteger.ValueOf(h0));
+ BigInteger q1 = f1.Add(BigInteger.ValueOf(h1));
+ return new ZTauElement(q0, q1);
+ }
+
+ /**
+ * Approximate division by <code>n</code>. For an integer
+ * <code>k</code>, the value <code>λ = s k / n</code> is
+ * computed to <code>c</code> bits of accuracy.
+ * @param k The parameter <code>k</code>.
+ * @param s The curve parameter <code>s<sub>0</sub></code> or
+ * <code>s<sub>1</sub></code>.
+ * @param vm The Lucas Sequence element <code>V<sub>m</sub></code>.
+ * @param a The parameter <code>a</code> of the elliptic curve.
+ * @param m The bit length of the finite field
+ * <code><b>F</b><sub>m</sub></code>.
+ * @param c The number of bits of accuracy, i.e. the scale of the returned
+ * <code>SimpleBigDecimal</code>.
+ * @return The value <code>λ = s k / n</code> computed to
+ * <code>c</code> bits of accuracy.
+ */
+ public static SimpleBigDecimal ApproximateDivisionByN(BigInteger k,
+ BigInteger s, BigInteger vm, sbyte a, int m, int c)
+ {
+ int _k = (m + 5)/2 + c;
+ BigInteger ns = k.ShiftRight(m - _k - 2 + a);
+
+ BigInteger gs = s.Multiply(ns);
+
+ BigInteger hs = gs.ShiftRight(m);
+
+ BigInteger js = vm.Multiply(hs);
+
+ BigInteger gsPlusJs = gs.Add(js);
+ BigInteger ls = gsPlusJs.ShiftRight(_k-c);
+ if (gsPlusJs.TestBit(_k-c-1))
+ {
+ // round up
+ ls = ls.Add(BigInteger.One);
+ }
+
+ return new SimpleBigDecimal(ls, c);
+ }
+
+ /**
+ * Computes the <code>τ</code>-adic NAF (non-adjacent form) of an
+ * element <code>λ</code> of <code><b>Z</b>[τ]</code>.
+ * @param mu The parameter <code>μ</code> of the elliptic curve.
+ * @param lambda The element <code>λ</code> of
+ * <code><b>Z</b>[τ]</code>.
+ * @return The <code>τ</code>-adic NAF of <code>λ</code>.
+ */
+ public static sbyte[] TauAdicNaf(sbyte mu, ZTauElement lambda)
+ {
+ if (!((mu == 1) || (mu == -1)))
+ throw new ArgumentException("mu must be 1 or -1");
+
+ BigInteger norm = Norm(mu, lambda);
+
+ // Ceiling of log2 of the norm
+ int log2Norm = norm.BitLength;
+
+ // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+ int maxLength = log2Norm > 30 ? log2Norm + 4 : 34;
+
+ // The array holding the TNAF
+ sbyte[] u = new sbyte[maxLength];
+ int i = 0;
+
+ // The actual length of the TNAF
+ int length = 0;
+
+ BigInteger r0 = lambda.u;
+ BigInteger r1 = lambda.v;
+
+ while(!((r0.Equals(BigInteger.Zero)) && (r1.Equals(BigInteger.Zero))))
+ {
+ // If r0 is odd
+ if (r0.TestBit(0))
+ {
+ u[i] = (sbyte) BigInteger.Two.Subtract((r0.Subtract(r1.ShiftLeft(1))).Mod(Four)).IntValue;
+
+ // r0 = r0 - u[i]
+ if (u[i] == 1)
+ {
+ r0 = r0.ClearBit(0);
+ }
+ else
+ {
+ // u[i] == -1
+ r0 = r0.Add(BigInteger.One);
+ }
+ length = i;
+ }
+ else
+ {
+ u[i] = 0;
+ }
+
+ BigInteger t = r0;
+ BigInteger s = r0.ShiftRight(1);
+ if (mu == 1)
+ {
+ r0 = r1.Add(s);
+ }
+ else
+ {
+ // mu == -1
+ r0 = r1.Subtract(s);
+ }
+
+ r1 = t.ShiftRight(1).Negate();
+ i++;
+ }
+
+ length++;
+
+ // Reduce the TNAF array to its actual length
+ sbyte[] tnaf = new sbyte[length];
+ Array.Copy(u, 0, tnaf, 0, length);
+ return tnaf;
+ }
+
+ /**
+ * Applies the operation <code>τ()</code> to an
+ * <code>F2mPoint</code>.
+ * @param p The F2mPoint to which <code>τ()</code> is applied.
+ * @return <code>τ(p)</code>
+ */
+ public static F2mPoint Tau(F2mPoint p)
+ {
+ return p.Tau();
+ }
+
+ /**
+ * Returns the parameter <code>μ</code> of the elliptic curve.
+ * @param curve The elliptic curve from which to obtain <code>μ</code>.
+ * The curve must be a Koblitz curve, i.e. <code>a</code> Equals
+ * <code>0</code> or <code>1</code> and <code>b</code> Equals
+ * <code>1</code>.
+ * @return <code>μ</code> of the elliptic curve.
+ * @throws ArgumentException if the given ECCurve is not a Koblitz
+ * curve.
+ */
+ public static sbyte GetMu(F2mCurve curve)
+ {
+ BigInteger a = curve.A.ToBigInteger();
+
+ sbyte mu;
+ if (a.SignValue == 0)
+ {
+ mu = -1;
+ }
+ else if (a.Equals(BigInteger.One))
+ {
+ mu = 1;
+ }
+ else
+ {
+ throw new ArgumentException("No Koblitz curve (ABC), TNAF multiplication not possible");
+ }
+ return mu;
+ }
+
+ /**
+ * Calculates the Lucas Sequence elements <code>U<sub>k-1</sub></code> and
+ * <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code> and
+ * <code>V<sub>k</sub></code>.
+ * @param mu The parameter <code>μ</code> of the elliptic curve.
+ * @param k The index of the second element of the Lucas Sequence to be
+ * returned.
+ * @param doV If set to true, computes <code>V<sub>k-1</sub></code> and
+ * <code>V<sub>k</sub></code>, otherwise <code>U<sub>k-1</sub></code> and
+ * <code>U<sub>k</sub></code>.
+ * @return An array with 2 elements, containing <code>U<sub>k-1</sub></code>
+ * and <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code>
+ * and <code>V<sub>k</sub></code>.
+ */
+ public static BigInteger[] GetLucas(sbyte mu, int k, bool doV)
+ {
+ if (!(mu == 1 || mu == -1))
+ throw new ArgumentException("mu must be 1 or -1");
+
+ BigInteger u0;
+ BigInteger u1;
+ BigInteger u2;
+
+ if (doV)
+ {
+ u0 = BigInteger.Two;
+ u1 = BigInteger.ValueOf(mu);
+ }
+ else
+ {
+ u0 = BigInteger.Zero;
+ u1 = BigInteger.One;
+ }
+
+ for (int i = 1; i < k; i++)
+ {
+ // u2 = mu*u1 - 2*u0;
+ BigInteger s = null;
+ if (mu == 1)
+ {
+ s = u1;
+ }
+ else
+ {
+ // mu == -1
+ s = u1.Negate();
+ }
+
+ u2 = s.Subtract(u0.ShiftLeft(1));
+ u0 = u1;
+ u1 = u2;
+ // System.out.println(i + ": " + u2);
+ // System.out.println();
+ }
+
+ BigInteger[] retVal = {u0, u1};
+ return retVal;
+ }
+
+ /**
+ * Computes the auxiliary value <code>t<sub>w</sub></code>. If the width is
+ * 4, then for <code>mu = 1</code>, <code>t<sub>w</sub> = 6</code> and for
+ * <code>mu = -1</code>, <code>t<sub>w</sub> = 10</code>
+ * @param mu The parameter <code>μ</code> of the elliptic curve.
+ * @param w The window width of the WTNAF.
+ * @return the auxiliary value <code>t<sub>w</sub></code>
+ */
+ public static BigInteger GetTw(sbyte mu, int w)
+ {
+ if (w == 4)
+ {
+ if (mu == 1)
+ {
+ return BigInteger.ValueOf(6);
+ }
+ else
+ {
+ // mu == -1
+ return BigInteger.ValueOf(10);
+ }
+ }
+ else
+ {
+ // For w <> 4, the values must be computed
+ BigInteger[] us = GetLucas(mu, w, false);
+ BigInteger twoToW = BigInteger.Zero.SetBit(w);
+ BigInteger u1invert = us[1].ModInverse(twoToW);
+ BigInteger tw;
+ tw = BigInteger.Two.Multiply(us[0]).Multiply(u1invert).Mod(twoToW);
+ //System.out.println("mu = " + mu);
+ //System.out.println("tw = " + tw);
+ return tw;
+ }
+ }
+
+ /**
+ * Computes the auxiliary values <code>s<sub>0</sub></code> and
+ * <code>s<sub>1</sub></code> used for partial modular reduction.
+ * @param curve The elliptic curve for which to compute
+ * <code>s<sub>0</sub></code> and <code>s<sub>1</sub></code>.
+ * @throws ArgumentException if <code>curve</code> is not a
+ * Koblitz curve (Anomalous Binary Curve, ABC).
+ */
+ public static BigInteger[] GetSi(F2mCurve curve)
+ {
+ if (!curve.IsKoblitz)
+ throw new ArgumentException("si is defined for Koblitz curves only");
+
+ int m = curve.M;
+ int a = curve.A.ToBigInteger().IntValue;
+ sbyte mu = curve.GetMu();
+ int h = curve.H.IntValue;
+ int index = m + 3 - a;
+ BigInteger[] ui = GetLucas(mu, index, false);
+
+ BigInteger dividend0;
+ BigInteger dividend1;
+ if (mu == 1)
+ {
+ dividend0 = BigInteger.One.Subtract(ui[1]);
+ dividend1 = BigInteger.One.Subtract(ui[0]);
+ }
+ else if (mu == -1)
+ {
+ dividend0 = BigInteger.One.Add(ui[1]);
+ dividend1 = BigInteger.One.Add(ui[0]);
+ }
+ else
+ {
+ throw new ArgumentException("mu must be 1 or -1");
+ }
+
+ BigInteger[] si = new BigInteger[2];
+
+ if (h == 2)
+ {
+ si[0] = dividend0.ShiftRight(1);
+ si[1] = dividend1.ShiftRight(1).Negate();
+ }
+ else if (h == 4)
+ {
+ si[0] = dividend0.ShiftRight(2);
+ si[1] = dividend1.ShiftRight(2).Negate();
+ }
+ else
+ {
+ throw new ArgumentException("h (Cofactor) must be 2 or 4");
+ }
+
+ return si;
+ }
+
+ /**
+ * Partial modular reduction modulo
+ * <code>(τ<sup>m</sup> - 1)/(τ - 1)</code>.
+ * @param k The integer to be reduced.
+ * @param m The bitlength of the underlying finite field.
+ * @param a The parameter <code>a</code> of the elliptic curve.
+ * @param s The auxiliary values <code>s<sub>0</sub></code> and
+ * <code>s<sub>1</sub></code>.
+ * @param mu The parameter μ of the elliptic curve.
+ * @param c The precision (number of bits of accuracy) of the partial
+ * modular reduction.
+ * @return <code>ρ := k partmod (τ<sup>m</sup> - 1)/(τ - 1)</code>
+ */
+ public static ZTauElement PartModReduction(BigInteger k, int m, sbyte a,
+ BigInteger[] s, sbyte mu, sbyte c)
+ {
+ // d0 = s[0] + mu*s[1]; mu is either 1 or -1
+ BigInteger d0;
+ if (mu == 1)
+ {
+ d0 = s[0].Add(s[1]);
+ }
+ else
+ {
+ d0 = s[0].Subtract(s[1]);
+ }
+
+ BigInteger[] v = GetLucas(mu, m, true);
+ BigInteger vm = v[1];
+
+ SimpleBigDecimal lambda0 = ApproximateDivisionByN(
+ k, s[0], vm, a, m, c);
+
+ SimpleBigDecimal lambda1 = ApproximateDivisionByN(
+ k, s[1], vm, a, m, c);
+
+ ZTauElement q = Round(lambda0, lambda1, mu);
+
+ // r0 = n - d0*q0 - 2*s1*q1
+ BigInteger r0 = k.Subtract(d0.Multiply(q.u)).Subtract(
+ BigInteger.ValueOf(2).Multiply(s[1]).Multiply(q.v));
+
+ // r1 = s1*q0 - s0*q1
+ BigInteger r1 = s[1].Multiply(q.u).Subtract(s[0].Multiply(q.v));
+
+ return new ZTauElement(r0, r1);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * by a <code>BigInteger</code> using the reduced <code>τ</code>-adic
+ * NAF (RTNAF) method.
+ * @param p The F2mPoint to Multiply.
+ * @param k The <code>BigInteger</code> by which to Multiply <code>p</code>.
+ * @return <code>k * p</code>
+ */
+ public static F2mPoint MultiplyRTnaf(F2mPoint p, BigInteger k)
+ {
+ F2mCurve curve = (F2mCurve) p.Curve;
+ int m = curve.M;
+ sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
+ sbyte mu = curve.GetMu();
+ BigInteger[] s = curve.GetSi();
+ ZTauElement rho = PartModReduction(k, m, a, s, mu, (sbyte)10);
+
+ return MultiplyTnaf(p, rho);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * by an element <code>λ</code> of <code><b>Z</b>[τ]</code>
+ * using the <code>τ</code>-adic NAF (TNAF) method.
+ * @param p The F2mPoint to Multiply.
+ * @param lambda The element <code>λ</code> of
+ * <code><b>Z</b>[τ]</code>.
+ * @return <code>λ * p</code>
+ */
+ public static F2mPoint MultiplyTnaf(F2mPoint p, ZTauElement lambda)
+ {
+ F2mCurve curve = (F2mCurve)p.Curve;
+ sbyte mu = curve.GetMu();
+ sbyte[] u = TauAdicNaf(mu, lambda);
+
+ F2mPoint q = MultiplyFromTnaf(p, u);
+
+ return q;
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+ * by an element <code>λ</code> of <code><b>Z</b>[τ]</code>
+ * using the <code>τ</code>-adic NAF (TNAF) method, given the TNAF
+ * of <code>λ</code>.
+ * @param p The F2mPoint to Multiply.
+ * @param u The the TNAF of <code>λ</code>..
+ * @return <code>λ * p</code>
+ */
+ public static F2mPoint MultiplyFromTnaf(F2mPoint p, sbyte[] u)
+ {
+ F2mCurve curve = (F2mCurve)p.Curve;
+ F2mPoint q = (F2mPoint) curve.Infinity;
+ for (int i = u.Length - 1; i >= 0; i--)
+ {
+ q = Tau(q);
+ if (u[i] == 1)
+ {
+ q = (F2mPoint)q.AddSimple(p);
+ }
+ else if (u[i] == -1)
+ {
+ q = (F2mPoint)q.SubtractSimple(p);
+ }
+ }
+ return q;
+ }
+
+ /**
+ * Computes the <code>[τ]</code>-adic window NAF of an element
+ * <code>λ</code> of <code><b>Z</b>[τ]</code>.
+ * @param mu The parameter μ of the elliptic curve.
+ * @param lambda The element <code>λ</code> of
+ * <code><b>Z</b>[τ]</code> of which to compute the
+ * <code>[τ]</code>-adic NAF.
+ * @param width The window width of the resulting WNAF.
+ * @param pow2w 2<sup>width</sup>.
+ * @param tw The auxiliary value <code>t<sub>w</sub></code>.
+ * @param alpha The <code>α<sub>u</sub></code>'s for the window width.
+ * @return The <code>[τ]</code>-adic window NAF of
+ * <code>λ</code>.
+ */
+ public static sbyte[] TauAdicWNaf(sbyte mu, ZTauElement lambda,
+ sbyte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)
+ {
+ if (!((mu == 1) || (mu == -1)))
+ throw new ArgumentException("mu must be 1 or -1");
+
+ BigInteger norm = Norm(mu, lambda);
+
+ // Ceiling of log2 of the norm
+ int log2Norm = norm.BitLength;
+
+ // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+ int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width;
+
+ // The array holding the TNAF
+ sbyte[] u = new sbyte[maxLength];
+
+ // 2^(width - 1)
+ BigInteger pow2wMin1 = pow2w.ShiftRight(1);
+
+ // Split lambda into two BigIntegers to simplify calculations
+ BigInteger r0 = lambda.u;
+ BigInteger r1 = lambda.v;
+ int i = 0;
+
+ // while lambda <> (0, 0)
+ while (!((r0.Equals(BigInteger.Zero))&&(r1.Equals(BigInteger.Zero))))
+ {
+ // if r0 is odd
+ if (r0.TestBit(0))
+ {
+ // uUnMod = r0 + r1*tw Mod 2^width
+ BigInteger uUnMod
+ = r0.Add(r1.Multiply(tw)).Mod(pow2w);
+
+ sbyte uLocal;
+ // if uUnMod >= 2^(width - 1)
+ if (uUnMod.CompareTo(pow2wMin1) >= 0)
+ {
+ uLocal = (sbyte) uUnMod.Subtract(pow2w).IntValue;
+ }
+ else
+ {
+ uLocal = (sbyte) uUnMod.IntValue;
+ }
+ // uLocal is now in [-2^(width-1), 2^(width-1)-1]
+
+ u[i] = uLocal;
+ bool s = true;
+ if (uLocal < 0)
+ {
+ s = false;
+ uLocal = (sbyte)-uLocal;
+ }
+ // uLocal is now >= 0
+
+ if (s)
+ {
+ r0 = r0.Subtract(alpha[uLocal].u);
+ r1 = r1.Subtract(alpha[uLocal].v);
+ }
+ else
+ {
+ r0 = r0.Add(alpha[uLocal].u);
+ r1 = r1.Add(alpha[uLocal].v);
+ }
+ }
+ else
+ {
+ u[i] = 0;
+ }
+
+ BigInteger t = r0;
+
+ if (mu == 1)
+ {
+ r0 = r1.Add(r0.ShiftRight(1));
+ }
+ else
+ {
+ // mu == -1
+ r0 = r1.Subtract(r0.ShiftRight(1));
+ }
+ r1 = t.ShiftRight(1).Negate();
+ i++;
+ }
+ return u;
+ }
+
+ /**
+ * Does the precomputation for WTNAF multiplication.
+ * @param p The <code>ECPoint</code> for which to do the precomputation.
+ * @param a The parameter <code>a</code> of the elliptic curve.
+ * @return The precomputation array for <code>p</code>.
+ */
+ public static F2mPoint[] GetPreComp(F2mPoint p, sbyte a)
+ {
+ F2mPoint[] pu;
+ pu = new F2mPoint[16];
+ pu[1] = p;
+ sbyte[][] alphaTnaf;
+ if (a == 0)
+ {
+ alphaTnaf = Tnaf.Alpha0Tnaf;
+ }
+ else
+ {
+ // a == 1
+ alphaTnaf = Tnaf.Alpha1Tnaf;
+ }
+
+ int precompLen = alphaTnaf.Length;
+ for (int i = 3; i < precompLen; i = i + 2)
+ {
+ pu[i] = Tnaf.MultiplyFromTnaf(p, alphaTnaf[i]);
+ }
+
+ return pu;
+ }
+ }
}
diff --git a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
index 54ca78090..bb6f37831 100644
--- a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
+++ b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
@@ -26,162 +26,162 @@ namespace Org.BouncyCastle.X509
{
}
- /// <summary>
+ /// <summary>
/// Create a Subject Public Key Info object for a given public key.
/// </summary>
/// <param name="key">One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters</param>
/// <returns>A subject public key info object.</returns>
/// <exception cref="Exception">Throw exception if object provided is not one of the above.</exception>
public static SubjectPublicKeyInfo CreateSubjectPublicKeyInfo(
- AsymmetricKeyParameter key)
+ AsymmetricKeyParameter key)
{
- if (key == null)
- throw new ArgumentNullException("key");
+ if (key == null)
+ throw new ArgumentNullException("key");
if (key.IsPrivate)
throw new ArgumentException("Private key passed - public key expected.", "key");
- if (key is ElGamalPublicKeyParameters)
+ if (key is ElGamalPublicKeyParameters)
{
- ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)key;
- ElGamalParameters kp = _key.Parameters;
+ ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)key;
+ ElGamalParameters kp = _key.Parameters;
- SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
- new AlgorithmIdentifier(
- OiwObjectIdentifiers.ElGamalAlgorithm,
- new ElGamalParameter(kp.P, kp.G).ToAsn1Object()),
- new DerInteger(_key.Y));
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(
+ OiwObjectIdentifiers.ElGamalAlgorithm,
+ new ElGamalParameter(kp.P, kp.G).ToAsn1Object()),
+ new DerInteger(_key.Y));
- return info;
+ return info;
}
- if (key is DsaPublicKeyParameters)
+ if (key is DsaPublicKeyParameters)
{
DsaPublicKeyParameters _key = (DsaPublicKeyParameters) key;
- DsaParameters kp = _key.Parameters;
- Asn1Encodable ae = kp == null
- ? null
- : new DsaParameter(kp.P, kp.Q, kp.G).ToAsn1Object();
+ DsaParameters kp = _key.Parameters;
+ Asn1Encodable ae = kp == null
+ ? null
+ : new DsaParameter(kp.P, kp.Q, kp.G).ToAsn1Object();
- return new SubjectPublicKeyInfo(
+ return new SubjectPublicKeyInfo(
new AlgorithmIdentifier(X9ObjectIdentifiers.IdDsa, ae),
- new DerInteger(_key.Y));
+ new DerInteger(_key.Y));
}
- if (key is DHPublicKeyParameters)
+ if (key is DHPublicKeyParameters)
{
DHPublicKeyParameters _key = (DHPublicKeyParameters) key;
- DHParameters kp = _key.Parameters;
+ DHParameters kp = _key.Parameters;
- SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
new AlgorithmIdentifier(
- _key.AlgorithmOid,
- new DHParameter(kp.P, kp.G, kp.L).ToAsn1Object()),
- new DerInteger(_key.Y));
+ _key.AlgorithmOid,
+ new DHParameter(kp.P, kp.G, kp.L).ToAsn1Object()),
+ new DerInteger(_key.Y));
- return info;
+ return info;
} // End of DH
if (key is RsaKeyParameters)
{
RsaKeyParameters _key = (RsaKeyParameters) key;
- SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
- new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance),
- new RsaPublicKeyStructure(_key.Modulus, _key.Exponent).ToAsn1Object());
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance),
+ new RsaPublicKeyStructure(_key.Modulus, _key.Exponent).ToAsn1Object());
- return info;
+ return info;
} // End of RSA.
- if (key is ECPublicKeyParameters)
+ if (key is ECPublicKeyParameters)
{
ECPublicKeyParameters _key = (ECPublicKeyParameters) key;
- if (_key.AlgorithmName == "ECGOST3410")
- {
- if (_key.PublicKeyParamSet == null)
- throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
-
- ECPoint q = _key.Q;
- BigInteger bX = q.X.ToBigInteger();
- BigInteger bY = q.Y.ToBigInteger();
-
- byte[] encKey = new byte[64];
- ExtractBytes(encKey, 0, bX);
- ExtractBytes(encKey, 32, bY);
-
- Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
- _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
-
- AlgorithmIdentifier algID = new AlgorithmIdentifier(
- CryptoProObjectIdentifiers.GostR3410x2001,
- gostParams.ToAsn1Object());
-
- return new SubjectPublicKeyInfo(algID, new DerOctetString(encKey));
- }
- else
- {
- X962Parameters x962;
- if (_key.PublicKeyParamSet == null)
- {
- ECDomainParameters kp = _key.Parameters;
- X9ECParameters ecP = new X9ECParameters(kp.Curve, kp.G, kp.N, kp.H, kp.GetSeed());
-
- x962 = new X962Parameters(ecP);
- }
- else
- {
- x962 = new X962Parameters(_key.PublicKeyParamSet);
- }
-
- Asn1OctetString p = (Asn1OctetString)(new X9ECPoint(_key.Q).ToAsn1Object());
-
- AlgorithmIdentifier algID = new AlgorithmIdentifier(
- X9ObjectIdentifiers.IdECPublicKey, x962.ToAsn1Object());
-
- return new SubjectPublicKeyInfo(algID, p.GetOctets());
- }
- } // End of EC
-
- if (key is Gost3410PublicKeyParameters)
- {
- Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) key;
-
- if (_key.PublicKeyParamSet == null)
- throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
-
- byte[] keyEnc = _key.Y.ToByteArrayUnsigned();
- byte[] keyBytes = new byte[keyEnc.Length];
-
- for (int i = 0; i != keyBytes.Length; i++)
- {
- keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian
- }
-
- Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
- _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
-
- AlgorithmIdentifier algID = new AlgorithmIdentifier(
- CryptoProObjectIdentifiers.GostR3410x94,
- algParams.ToAsn1Object());
-
- return new SubjectPublicKeyInfo(algID, new DerOctetString(keyBytes));
- }
-
- throw new ArgumentException("Class provided no convertible: " + key.GetType().FullName);
- }
-
- private static void ExtractBytes(
- byte[] encKey,
- int offset,
- BigInteger bI)
- {
- byte[] val = bI.ToByteArray();
- int n = (bI.BitLength + 7) / 8;
-
- for (int i = 0; i < n; ++i)
- {
- encKey[offset + i] = val[val.Length - 1 - i];
- }
- }
- }
+ if (_key.AlgorithmName == "ECGOST3410")
+ {
+ if (_key.PublicKeyParamSet == null)
+ throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+ ECPoint q = _key.Q.Normalize();
+ BigInteger bX = q.AffineXCoord.ToBigInteger();
+ BigInteger bY = q.AffineYCoord.ToBigInteger();
+
+ byte[] encKey = new byte[64];
+ ExtractBytes(encKey, 0, bX);
+ ExtractBytes(encKey, 32, bY);
+
+ Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+ _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ CryptoProObjectIdentifiers.GostR3410x2001,
+ gostParams.ToAsn1Object());
+
+ return new SubjectPublicKeyInfo(algID, new DerOctetString(encKey));
+ }
+ else
+ {
+ X962Parameters x962;
+ if (_key.PublicKeyParamSet == null)
+ {
+ ECDomainParameters kp = _key.Parameters;
+ X9ECParameters ecP = new X9ECParameters(kp.Curve, kp.G, kp.N, kp.H, kp.GetSeed());
+
+ x962 = new X962Parameters(ecP);
+ }
+ else
+ {
+ x962 = new X962Parameters(_key.PublicKeyParamSet);
+ }
+
+ Asn1OctetString p = (Asn1OctetString)(new X9ECPoint(_key.Q).ToAsn1Object());
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ X9ObjectIdentifiers.IdECPublicKey, x962.ToAsn1Object());
+
+ return new SubjectPublicKeyInfo(algID, p.GetOctets());
+ }
+ } // End of EC
+
+ if (key is Gost3410PublicKeyParameters)
+ {
+ Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) key;
+
+ if (_key.PublicKeyParamSet == null)
+ throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+ byte[] keyEnc = _key.Y.ToByteArrayUnsigned();
+ byte[] keyBytes = new byte[keyEnc.Length];
+
+ for (int i = 0; i != keyBytes.Length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian
+ }
+
+ Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
+ _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ CryptoProObjectIdentifiers.GostR3410x94,
+ algParams.ToAsn1Object());
+
+ return new SubjectPublicKeyInfo(algID, new DerOctetString(keyBytes));
+ }
+
+ throw new ArgumentException("Class provided no convertible: " + key.GetType().FullName);
+ }
+
+ private static void ExtractBytes(
+ byte[] encKey,
+ int offset,
+ BigInteger bI)
+ {
+ byte[] val = bI.ToByteArray();
+ int n = (bI.BitLength + 7) / 8;
+
+ for (int i = 0; i < n; ++i)
+ {
+ encKey[offset + i] = val[val.Length - 1 - i];
+ }
+ }
+ }
}
|