diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2017-06-03 20:44:45 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2017-06-03 20:44:45 +0700 |
commit | 9b3549d18ecc3e4f66488568594a626e7d6d8543 (patch) | |
tree | 9504d9265461ab4118bb0708fcd7f0c11ca9d9b6 /crypto/src | |
parent | Fix reductions for custom secp128r1 field (diff) | |
download | BouncyCastle.NET-ed25519-9b3549d18ecc3e4f66488568594a626e7d6d8543.tar.xz |
Initial implementation of SM2 elliptic curve
- includes custom curve code - add lots of OIDs from GM standard
Diffstat (limited to 'crypto/src')
-rw-r--r-- | crypto/src/asn1/gm/GMNamedCurves.cs | 157 | ||||
-rw-r--r-- | crypto/src/asn1/gm/GMObjectIdentifiers.cs | 85 | ||||
-rw-r--r-- | crypto/src/asn1/x9/ECNamedCurveTable.cs | 31 | ||||
-rw-r--r-- | crypto/src/crypto/ec/CustomNamedCurves.cs | 25 | ||||
-rw-r--r-- | crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs | 77 | ||||
-rw-r--r-- | crypto/src/math/ec/custom/gm/SM2P256V1Field.cs | 307 | ||||
-rw-r--r-- | crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs | 213 | ||||
-rw-r--r-- | crypto/src/math/ec/custom/gm/SM2P256V1Point.cs | 279 |
8 files changed, 1161 insertions, 13 deletions
diff --git a/crypto/src/asn1/gm/GMNamedCurves.cs b/crypto/src/asn1/gm/GMNamedCurves.cs new file mode 100644 index 000000000..e2ec6d854 --- /dev/null +++ b/crypto/src/asn1/gm/GMNamedCurves.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Math.EC.Endo; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Collections; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Asn1.GM +{ + public sealed class GMNamedCurves + { + private GMNamedCurves() + { + } + + private static ECCurve ConfigureCurve(ECCurve curve) + { + return curve; + } + + private static BigInteger FromHex(string hex) + { + return new BigInteger(1, Hex.Decode(hex)); + } + + /* + * sm2p256v1 + */ + internal class SM2P256V1Holder + : X9ECParametersHolder + { + private SM2P256V1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new SM2P256V1Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger p = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"); + BigInteger a = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"); + BigInteger b = FromHex("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"); + byte[] S = null; + BigInteger n = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"); + BigInteger h = BigInteger.One; + + ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" + + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * wapip192v1 + */ + internal class WapiP192V1Holder + : X9ECParametersHolder + { + private WapiP192V1Holder() { } + + internal static readonly X9ECParametersHolder Instance = new WapiP192V1Holder(); + + protected override X9ECParameters CreateParameters() + { + BigInteger p = FromHex("BDB6F4FE3E8B1D9E0DA8C0D46F4C318CEFE4AFE3B6B8551F"); + BigInteger a = FromHex("BB8E5E8FBC115E139FE6A814FE48AAA6F0ADA1AA5DF91985"); + BigInteger b = FromHex("1854BEBDC31B21B7AEFC80AB0ECD10D5B1B3308E6DBF11C1"); + byte[] S = null; + BigInteger n = FromHex("BDB6F4FE3E8B1D9E0DA8C0D40FC962195DFAE76F56564677"); + BigInteger h = BigInteger.One; + + ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h)); + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + + "4AD5F7048DE709AD51236DE6" + "5E4D4B482C836DC6E4106640" + + "02BB3A02D4AAADACAE24817A" + "4CA3A1B014B5270432DB27D2")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + + private static readonly IDictionary objIds = Platform.CreateHashtable(); + private static readonly IDictionary curves = Platform.CreateHashtable(); + private static readonly IDictionary names = Platform.CreateHashtable(); + + private static void DefineCurve( + string name, + DerObjectIdentifier oid, + X9ECParametersHolder holder) + { + objIds.Add(Platform.ToUpperInvariant(name), oid); + names.Add(oid, name); + curves.Add(oid, holder); + } + + static GMNamedCurves() + { + DefineCurve("wapip192v1", GMObjectIdentifiers.wapip192v1, WapiP192V1Holder.Instance); + DefineCurve("sm2p256v1", GMObjectIdentifiers.sm2p256v1, SM2P256V1Holder.Instance); + } + + public static X9ECParameters GetByName( + string name) + { + DerObjectIdentifier oid = GetOid(name); + return oid == null ? null : GetByOid(oid); + } + + /** + * return the X9ECParameters object for the named curve represented by + * the passed in object identifier. Null if the curve isn't present. + * + * @param oid an object identifier representing a named curve, if present. + */ + public static X9ECParameters GetByOid( + DerObjectIdentifier oid) + { + X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid]; + return holder == null ? null : holder.Parameters; + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static DerObjectIdentifier GetOid( + string name) + { + return (DerObjectIdentifier)objIds[Platform.ToUpperInvariant(name)]; + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static string GetName( + DerObjectIdentifier oid) + { + return (string)names[oid]; + } + + /** + * returns an enumeration containing the name strings for curves + * contained in this structure. + */ + public static IEnumerable Names + { + get { return new EnumerableProxy(names.Values); } + } + } +} diff --git a/crypto/src/asn1/gm/GMObjectIdentifiers.cs b/crypto/src/asn1/gm/GMObjectIdentifiers.cs new file mode 100644 index 000000000..edb3a41c5 --- /dev/null +++ b/crypto/src/asn1/gm/GMObjectIdentifiers.cs @@ -0,0 +1,85 @@ +using System; + +namespace Org.BouncyCastle.Asn1.GM +{ + public abstract class GMObjectIdentifiers + { + public static readonly DerObjectIdentifier sm_scheme = new DerObjectIdentifier("1.2.156.10197.1"); + + public static readonly DerObjectIdentifier sm6_ecb = sm_scheme.Branch("101.1"); + public static readonly DerObjectIdentifier sm6_cbc = sm_scheme.Branch("101.2"); + public static readonly DerObjectIdentifier sm6_ofb128 = sm_scheme.Branch("101.3"); + public static readonly DerObjectIdentifier sm6_cfb128 = sm_scheme.Branch("101.4"); + + public static readonly DerObjectIdentifier sm1_ecb = sm_scheme.Branch("102.1"); + public static readonly DerObjectIdentifier sm1_cbc = sm_scheme.Branch("102.2"); + public static readonly DerObjectIdentifier sm1_ofb128 = sm_scheme.Branch("102.3"); + public static readonly DerObjectIdentifier sm1_cfb128 = sm_scheme.Branch("102.4"); + public static readonly DerObjectIdentifier sm1_cfb1 = sm_scheme.Branch("102.5"); + public static readonly DerObjectIdentifier sm1_cfb8 = sm_scheme.Branch("102.6"); + + public static readonly DerObjectIdentifier ssf33_ecb = sm_scheme.Branch("103.1"); + public static readonly DerObjectIdentifier ssf33_cbc = sm_scheme.Branch("103.2"); + public static readonly DerObjectIdentifier ssf33_ofb128 = sm_scheme.Branch("103.3"); + public static readonly DerObjectIdentifier ssf33_cfb128 = sm_scheme.Branch("103.4"); + public static readonly DerObjectIdentifier ssf33_cfb1 = sm_scheme.Branch("103.5"); + public static readonly DerObjectIdentifier ssf33_cfb8 = sm_scheme.Branch("103.6"); + + public static readonly DerObjectIdentifier sms4_ecb = sm_scheme.Branch("104.1"); + public static readonly DerObjectIdentifier sms4_cbc = sm_scheme.Branch("104.2"); + public static readonly DerObjectIdentifier sms4_ofb128 = sm_scheme.Branch("104.3"); + public static readonly DerObjectIdentifier sms4_cfb128 = sm_scheme.Branch("104.4"); + public static readonly DerObjectIdentifier sms4_cfb1 = sm_scheme.Branch("104.5"); + public static readonly DerObjectIdentifier sms4_cfb8 = sm_scheme.Branch("104.6"); + public static readonly DerObjectIdentifier sms4_ctr = sm_scheme.Branch("104.7"); + public static readonly DerObjectIdentifier sms4_gcm = sm_scheme.Branch("104.8"); + public static readonly DerObjectIdentifier sms4_ccm = sm_scheme.Branch("104.9"); + public static readonly DerObjectIdentifier sms4_xts = sm_scheme.Branch("104.10"); + public static readonly DerObjectIdentifier sms4_wrap = sm_scheme.Branch("104.11"); + public static readonly DerObjectIdentifier sms4_wrap_pad = sm_scheme.Branch("104.12"); + public static readonly DerObjectIdentifier sms4_ocb = sm_scheme.Branch("104.100"); + + public static readonly DerObjectIdentifier sm5 = sm_scheme.Branch("201"); + + public static readonly DerObjectIdentifier sm2p256v1 = sm_scheme.Branch("301"); + public static readonly DerObjectIdentifier sm2sign = sm_scheme.Branch("301.1"); + public static readonly DerObjectIdentifier sm2exchange = sm_scheme.Branch("301.2"); + public static readonly DerObjectIdentifier sm2encrypt = sm_scheme.Branch("301.3"); + + public static readonly DerObjectIdentifier wapip192v1 = sm_scheme.Branch("301.101"); + + public static readonly DerObjectIdentifier sm2encrypt_recommendedParameters = sm2encrypt.Branch("1"); + public static readonly DerObjectIdentifier sm2encrypt_specifiedParameters = sm2encrypt.Branch("2"); + public static readonly DerObjectIdentifier sm2encrypt_with_sm3 = sm2encrypt.Branch("2.1"); + public static readonly DerObjectIdentifier sm2encrypt_with_sha1 = sm2encrypt.Branch("2.2"); + public static readonly DerObjectIdentifier sm2encrypt_with_sha224 = sm2encrypt.Branch("2.3"); + public static readonly DerObjectIdentifier sm2encrypt_with_sha256 = sm2encrypt.Branch("2.4"); + public static readonly DerObjectIdentifier sm2encrypt_with_sha384 = sm2encrypt.Branch("2.5"); + public static readonly DerObjectIdentifier sm2encrypt_with_sha512 = sm2encrypt.Branch("2.6"); + public static readonly DerObjectIdentifier sm2encrypt_with_rmd160 = sm2encrypt.Branch("2.7"); + public static readonly DerObjectIdentifier sm2encrypt_with_whirlpool = sm2encrypt.Branch("2.8"); + public static readonly DerObjectIdentifier sm2encrypt_with_blake2b512 = sm2encrypt.Branch("2.9"); + public static readonly DerObjectIdentifier sm2encrypt_with_blake2s256 = sm2encrypt.Branch("2.10"); + public static readonly DerObjectIdentifier sm2encrypt_with_md5 = sm2encrypt.Branch("2.11"); + + public static readonly DerObjectIdentifier id_sm9PublicKey = sm_scheme.Branch("302"); + public static readonly DerObjectIdentifier sm9sign = sm_scheme.Branch("302.1"); + public static readonly DerObjectIdentifier sm9keyagreement = sm_scheme.Branch("302.2"); + public static readonly DerObjectIdentifier sm9encrypt = sm_scheme.Branch("302.3"); + + public static readonly DerObjectIdentifier sm3 = sm_scheme.Branch("401"); + + public static readonly DerObjectIdentifier hmac_sm3 = sm3.Branch("2"); + + public static readonly DerObjectIdentifier sm2sign_with_sm3 = sm_scheme.Branch("501"); + public static readonly DerObjectIdentifier sm2sign_with_sha1 = sm_scheme.Branch("502"); + public static readonly DerObjectIdentifier sm2sign_with_sha256 = sm_scheme.Branch("503"); + public static readonly DerObjectIdentifier sm2sign_with_sha512 = sm_scheme.Branch("504"); + public static readonly DerObjectIdentifier sm2sign_with_sha224 = sm_scheme.Branch("505"); + public static readonly DerObjectIdentifier sm2sign_with_sha384 = sm_scheme.Branch("506"); + public static readonly DerObjectIdentifier sm2sign_with_rmd160 = sm_scheme.Branch("507"); + public static readonly DerObjectIdentifier sm2sign_with_whirlpool = sm_scheme.Branch("520"); + public static readonly DerObjectIdentifier sm2sign_with_blake2b512 = sm_scheme.Branch("521"); + public static readonly DerObjectIdentifier sm2sign_with_blake2s256 = sm_scheme.Branch("522"); + } +} \ No newline at end of file diff --git a/crypto/src/asn1/x9/ECNamedCurveTable.cs b/crypto/src/asn1/x9/ECNamedCurveTable.cs index 92d4393a8..317ef17b4 100644 --- a/crypto/src/asn1/x9/ECNamedCurveTable.cs +++ b/crypto/src/asn1/x9/ECNamedCurveTable.cs @@ -2,6 +2,7 @@ using System.Collections; using Org.BouncyCastle.Asn1.Anssi; +using Org.BouncyCastle.Asn1.GM; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Asn1.TeleTrust; @@ -25,27 +26,26 @@ namespace Org.BouncyCastle.Asn1.X9 public static X9ECParameters GetByName(string name) { X9ECParameters ecP = X962NamedCurves.GetByName(name); - if (ecP == null) { ecP = SecNamedCurves.GetByName(name); } - if (ecP == null) { ecP = NistNamedCurves.GetByName(name); } - if (ecP == null) { ecP = TeleTrusTNamedCurves.GetByName(name); } - if (ecP == null) { ecP = AnssiNamedCurves.GetByName(name); } - + if (ecP == null) + { + ecP = GMNamedCurves.GetByName(name); + } return ecP; } @@ -68,6 +68,10 @@ namespace Org.BouncyCastle.Asn1.X9 { name = AnssiNamedCurves.GetName(oid); } + if (name == null) + { + name = GMNamedCurves.GetName(oid); + } return name; } @@ -80,27 +84,26 @@ namespace Org.BouncyCastle.Asn1.X9 public static DerObjectIdentifier GetOid(string name) { DerObjectIdentifier oid = X962NamedCurves.GetOid(name); - if (oid == null) { oid = SecNamedCurves.GetOid(name); } - if (oid == null) { oid = NistNamedCurves.GetOid(name); } - if (oid == null) { oid = TeleTrusTNamedCurves.GetOid(name); } - if (oid == null) { oid = AnssiNamedCurves.GetOid(name); } - + if (oid == null) + { + oid = GMNamedCurves.GetOid(name); + } return oid; } @@ -114,7 +117,6 @@ namespace Org.BouncyCastle.Asn1.X9 public static X9ECParameters GetByOid(DerObjectIdentifier oid) { X9ECParameters ecP = X962NamedCurves.GetByOid(oid); - if (ecP == null) { ecP = SecNamedCurves.GetByOid(oid); @@ -126,12 +128,14 @@ namespace Org.BouncyCastle.Asn1.X9 { ecP = TeleTrusTNamedCurves.GetByOid(oid); } - if (ecP == null) { ecP = AnssiNamedCurves.GetByOid(oid); } - + if (ecP == null) + { + ecP = GMNamedCurves.GetByOid(oid); + } return ecP; } @@ -150,6 +154,7 @@ namespace Org.BouncyCastle.Asn1.X9 CollectionUtilities.AddRange(v, NistNamedCurves.Names); CollectionUtilities.AddRange(v, TeleTrusTNamedCurves.Names); CollectionUtilities.AddRange(v, AnssiNamedCurves.Names); + CollectionUtilities.AddRange(v, GMNamedCurves.Names); return v; } } diff --git a/crypto/src/crypto/ec/CustomNamedCurves.cs b/crypto/src/crypto/ec/CustomNamedCurves.cs index 8a0c50a47..4b7600e09 100644 --- a/crypto/src/crypto/ec/CustomNamedCurves.cs +++ b/crypto/src/crypto/ec/CustomNamedCurves.cs @@ -2,11 +2,13 @@ using System; using System.Collections; using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.GM; using Org.BouncyCastle.Asn1.Sec; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Math; using Org.BouncyCastle.Math.EC; using Org.BouncyCastle.Math.EC.Custom.Djb; +using Org.BouncyCastle.Math.EC.Custom.GM; using Org.BouncyCastle.Math.EC.Custom.Sec; using Org.BouncyCastle.Math.EC.Endo; using Org.BouncyCastle.Utilities; @@ -746,6 +748,27 @@ namespace Org.BouncyCastle.Crypto.EC } }; + /* + * sm2p256v1 + */ + internal class SM2P256V1Holder + : X9ECParametersHolder + { + private SM2P256V1Holder() { } + + internal static readonly X9ECParametersHolder Instance = new SM2P256V1Holder(); + + protected override X9ECParameters CreateParameters() + { + byte[] S = null; + ECCurve curve = ConfigureCurve(new SM2P256V1Curve()); + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" + + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0")); + return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S); + } + } + private static readonly IDictionary nameToCurve = Platform.CreateHashtable(); private static readonly IDictionary nameToOid = Platform.CreateHashtable(); @@ -820,6 +843,8 @@ namespace Org.BouncyCastle.Crypto.EC DefineCurveWithOid("sect571k1", SecObjectIdentifiers.SecT571k1, SecT571K1Holder.Instance); DefineCurveWithOid("sect571r1", SecObjectIdentifiers.SecT571r1, SecT571R1Holder.Instance); + DefineCurveWithOid("sm2p256v1", GMObjectIdentifiers.sm2p256v1, SM2P256V1Holder.Instance); + DefineCurveAlias("B-163", SecObjectIdentifiers.SecT163r2); DefineCurveAlias("B-233", SecObjectIdentifiers.SecT233r1); DefineCurveAlias("B-283", SecObjectIdentifiers.SecT283r1); diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs b/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs new file mode 100644 index 000000000..70b1190c9 --- /dev/null +++ b/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs @@ -0,0 +1,77 @@ +using System; + +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Math.EC.Custom.GM +{ + internal class SM2P256V1Curve + : AbstractFpCurve + { + public static readonly BigInteger q = new BigInteger(1, + Hex.Decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF")); + + private const int SM2P256V1_DEFAULT_COORDS = COORD_JACOBIAN; + + protected readonly SM2P256V1Point m_infinity; + + public SM2P256V1Curve() + : base(q) + { + this.m_infinity = new SM2P256V1Point(this, null, null); + + this.m_a = FromBigInteger(new BigInteger(1, + Hex.Decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"))); + this.m_b = FromBigInteger(new BigInteger(1, + Hex.Decode("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"))); + this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123")); + this.m_cofactor = BigInteger.One; + this.m_coord = SM2P256V1_DEFAULT_COORDS; + } + + protected override ECCurve CloneCurve() + { + return new SM2P256V1Curve(); + } + + public override bool SupportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN: + return true; + default: + return false; + } + } + + public virtual BigInteger Q + { + get { return q; } + } + + public override ECPoint Infinity + { + get { return m_infinity; } + } + + public override int FieldSize + { + get { return q.BitLength; } + } + + public override ECFieldElement FromBigInteger(BigInteger x) + { + return new SM2P256V1FieldElement(x); + } + + protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression) + { + return new SM2P256V1Point(this, x, y, withCompression); + } + + protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) + { + return new SM2P256V1Point(this, x, y, zs, withCompression); + } + } +} diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1Field.cs b/crypto/src/math/ec/custom/gm/SM2P256V1Field.cs new file mode 100644 index 000000000..b1d232347 --- /dev/null +++ b/crypto/src/math/ec/custom/gm/SM2P256V1Field.cs @@ -0,0 +1,307 @@ +using System; +using System.Diagnostics; + +using Org.BouncyCastle.Math.Raw; + +namespace Org.BouncyCastle.Math.EC.Custom.GM +{ + internal class SM2P256V1Field + { + // 2^256 - 2^224 - 2^96 + 2^64 - 1 + internal static readonly uint[] P = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFE }; + internal static readonly uint[] PExt = new uint[]{ 00000001, 0x00000000, 0xFFFFFFFE, 0x00000001, 0x00000001, + 0xFFFFFFFE, 0x00000000, 0x00000002, 0xFFFFFFFE, 0xFFFFFFFD, 0x00000003, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0xFFFFFFFE }; + internal const uint P7 = 0xFFFFFFFE; + internal const uint PExt15 = 0xFFFFFFFE; + + public static void Add(uint[] x, uint[] y, uint[] z) + { + uint c = Nat256.Add(x, y, z); + if (c != 0 || (z[7] >= P7 && Nat256.Gte(z, P))) + { + AddPInvTo(z); + } + } + + public static void AddExt(uint[] xx, uint[] yy, uint[] zz) + { + uint c = Nat.Add(16, xx, yy, zz); + if (c != 0 || (zz[15] >= PExt15 && Nat.Gte(16, zz, PExt))) + { + Nat.SubFrom(16, PExt, zz); + } + } + + public static void AddOne(uint[] x, uint[] z) + { + uint c = Nat.Inc(8, x, z); + if (c != 0 || (z[7] >= P7 && Nat256.Gte(z, P))) + { + AddPInvTo(z); + } + } + + public static uint[] FromBigInteger(BigInteger x) + { + uint[] z = Nat256.FromBigInteger(x); + if (z[7] >= P7 && Nat256.Gte(z, P)) + { + Nat256.SubFrom(P, z); + } + return z; + } + + public static void Half(uint[] x, uint[] z) + { + if ((x[0] & 1) == 0) + { + Nat.ShiftDownBit(8, x, 0, z); + } + else + { + uint c = Nat256.Add(x, P, z); + Nat.ShiftDownBit(8, z, c); + } + } + + public static void Multiply(uint[] x, uint[] y, uint[] z) + { + uint[] tt = Nat256.CreateExt(); + Nat256.Mul(x, y, tt); + Reduce(tt, z); + } + + public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz) + { + uint c = Nat256.MulAddTo(x, y, zz); + if (c != 0 || (zz[15] >= PExt15 && Nat.Gte(16, zz, PExt))) + { + Nat.SubFrom(16, PExt, zz); + } + } + + public static void Negate(uint[] x, uint[] z) + { + if (Nat256.IsZero(x)) + { + Nat256.Zero(z); + } + else + { + Nat256.Sub(P, x, z); + } + } + + public static void Reduce(uint[] xx, uint[] z) + { + long xx08 = xx[8], xx09 = xx[9], xx10 = xx[10], xx11 = xx[11]; + long xx12 = xx[12], xx13 = xx[13], xx14 = xx[14], xx15 = xx[15]; + + long t0 = xx08 + xx09; + long t1 = xx10 + xx11; + long t2 = xx12 + xx15; + long t3 = xx13 + xx14; + long t4 = t3 + (xx15 << 1); + + long ts = t0 + t3; + long tt = t1 + t2 + ts; + + long cc = 0; + cc += (long)xx[0] + tt + xx13 + xx14 + xx15; + z[0] = (uint)cc; + cc >>= 32; + cc += (long)xx[1] + tt - xx08 + xx14 + xx15; + z[1] = (uint)cc; + cc >>= 32; + cc += (long)xx[2] - ts; + z[2] = (uint)cc; + cc >>= 32; + cc += (long)xx[3] + tt - xx09 - xx10 + xx13; + z[3] = (uint)cc; + cc >>= 32; + cc += (long)xx[4] + tt - t1 - xx08 + xx14; + z[4] = (uint)cc; + cc >>= 32; + cc += (long)xx[5] + t4 + xx10; + z[5] = (uint)cc; + cc >>= 32; + cc += (long)xx[6] + xx11 + xx14 + xx15; + z[6] = (uint)cc; + cc >>= 32; + cc += (long)xx[7] + tt + t4 + xx12; + z[7] = (uint)cc; + cc >>= 32; + + Debug.Assert(cc >= 0); + + Reduce32((uint)cc, z); + } + + public static void Reduce32(uint x, uint[] z) + { + long cc = 0; + + if (x != 0) + { + long xx08 = x; + + cc += (long)z[0] + xx08; + z[0] = (uint)cc; + cc >>= 32; + if (cc != 0) + { + cc += (long)z[1]; + z[1] = (uint)cc; + cc >>= 32; + } + cc += (long)z[2] - xx08; + z[2] = (uint)cc; + cc >>= 32; + cc += (long)z[3] + xx08; + z[3] = (uint)cc; + cc >>= 32; + if (cc != 0) + { + cc += (long)z[4]; + z[4] = (uint)cc; + cc >>= 32; + cc += (long)z[5]; + z[5] = (uint)cc; + cc >>= 32; + cc += (long)z[6]; + z[6] = (uint)cc; + cc >>= 32; + } + cc += (long)z[7] + xx08; + z[7] = (uint)cc; + cc >>= 32; + + Debug.Assert(cc == 0 || cc == 1); + } + + if (cc != 0 || (z[7] >= P7 && Nat256.Gte(z, P))) + { + AddPInvTo(z); + } + } + + public static void Square(uint[] x, uint[] z) + { + uint[] tt = Nat256.CreateExt(); + Nat256.Square(x, tt); + Reduce(tt, z); + } + + public static void SquareN(uint[] x, int n, uint[] z) + { + Debug.Assert(n > 0); + + uint[] tt = Nat256.CreateExt(); + Nat256.Square(x, tt); + Reduce(tt, z); + + while (--n > 0) + { + Nat256.Square(z, tt); + Reduce(tt, z); + } + } + + public static void Subtract(uint[] x, uint[] y, uint[] z) + { + int c = Nat256.Sub(x, y, z); + if (c != 0) + { + SubPInvFrom(z); + } + } + + public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz) + { + int c = Nat.Sub(16, xx, yy, zz); + if (c != 0) + { + Nat.AddTo(16, PExt, zz); + } + } + + public static void Twice(uint[] x, uint[] z) + { + uint c = Nat.ShiftUpBit(8, x, 0, z); + if (c != 0 || (z[7] >= P7 && Nat256.Gte(z, P))) + { + AddPInvTo(z); + } + } + + private static void AddPInvTo(uint[] z) + { + long c = (long)z[0] + 1; + z[0] = (uint)c; + c >>= 32; + if (c != 0) + { + c += (long)z[1]; + z[1] = (uint)c; + c >>= 32; + } + c += (long)z[2] - 1; + z[2] = (uint)c; + c >>= 32; + c += (long)z[3] + 1; + z[3] = (uint)c; + c >>= 32; + if (c != 0) + { + c += (long)z[4]; + z[4] = (uint)c; + c >>= 32; + c += (long)z[5]; + z[5] = (uint)c; + c >>= 32; + c += (long)z[6]; + z[6] = (uint)c; + c >>= 32; + } + c += (long)z[7] + 1; + z[7] = (uint)c; + //c >>= 32; + } + + private static void SubPInvFrom(uint[] z) + { + long c = (long)z[0] - 1; + z[0] = (uint)c; + c >>= 32; + if (c != 0) + { + c += (long)z[1]; + z[1] = (uint)c; + c >>= 32; + } + c += (long)z[2] + 1; + z[2] = (uint)c; + c >>= 32; + c += (long)z[3] - 1; + z[3] = (uint)c; + c >>= 32; + if (c != 0) + { + c += (long)z[4]; + z[4] = (uint)c; + c >>= 32; + c += (long)z[5]; + z[5] = (uint)c; + c >>= 32; + c += (long)z[6]; + z[6] = (uint)c; + c >>= 32; + } + c += (long)z[7] - 1; + z[7] = (uint)c; + //c >>= 32; + } + } +} diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs b/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs new file mode 100644 index 000000000..669c73bd2 --- /dev/null +++ b/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs @@ -0,0 +1,213 @@ +using System; + +using Org.BouncyCastle.Math.Raw; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Math.EC.Custom.GM +{ + internal class SM2P256V1FieldElement + : ECFieldElement + { + public static readonly BigInteger Q = SM2P256V1Curve.q; + + protected internal readonly uint[] x; + + public SM2P256V1FieldElement(BigInteger x) + { + if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0) + throw new ArgumentException("value invalid for SM2P256V1FieldElement", "x"); + + this.x = SM2P256V1Field.FromBigInteger(x); + } + + public SM2P256V1FieldElement() + { + this.x = Nat256.Create(); + } + + protected internal SM2P256V1FieldElement(uint[] x) + { + this.x = x; + } + + public override bool IsZero + { + get { return Nat256.IsZero(x); } + } + + public override bool IsOne + { + get { return Nat256.IsOne(x); } + } + + public override bool TestBitZero() + { + return Nat256.GetBit(x, 0) == 1; + } + + public override BigInteger ToBigInteger() + { + return Nat256.ToBigInteger(x); + } + + public override string FieldName + { + get { return "SM2P256V1Field"; } + } + + public override int FieldSize + { + get { return Q.BitLength; } + } + + public override ECFieldElement Add(ECFieldElement b) + { + uint[] z = Nat256.Create(); + SM2P256V1Field.Add(x, ((SM2P256V1FieldElement)b).x, z); + return new SM2P256V1FieldElement(z); + } + + public override ECFieldElement AddOne() + { + uint[] z = Nat256.Create(); + SM2P256V1Field.AddOne(x, z); + return new SM2P256V1FieldElement(z); + } + + public override ECFieldElement Subtract(ECFieldElement b) + { + uint[] z = Nat256.Create(); + SM2P256V1Field.Subtract(x, ((SM2P256V1FieldElement)b).x, z); + return new SM2P256V1FieldElement(z); + } + + public override ECFieldElement Multiply(ECFieldElement b) + { + uint[] z = Nat256.Create(); + SM2P256V1Field.Multiply(x, ((SM2P256V1FieldElement)b).x, z); + return new SM2P256V1FieldElement(z); + } + + public override ECFieldElement Divide(ECFieldElement b) + { + //return Multiply(b.Invert()); + uint[] z = Nat256.Create(); + Mod.Invert(SM2P256V1Field.P, ((SM2P256V1FieldElement)b).x, z); + SM2P256V1Field.Multiply(z, x, z); + return new SM2P256V1FieldElement(z); + } + + public override ECFieldElement Negate() + { + uint[] z = Nat256.Create(); + SM2P256V1Field.Negate(x, z); + return new SM2P256V1FieldElement(z); + } + + public override ECFieldElement Square() + { + uint[] z = Nat256.Create(); + SM2P256V1Field.Square(x, z); + return new SM2P256V1FieldElement(z); + } + + public override ECFieldElement Invert() + { + //return new SM2P256V1FieldElement(ToBigInteger().ModInverse(Q)); + uint[] z = Nat256.Create(); + Mod.Invert(SM2P256V1Field.P, x, z); + return new SM2P256V1FieldElement(z); + } + + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public override ECFieldElement Sqrt() + { + /* + * Raise this element to the exponent 2^254 - 2^222 - 2^94 + 2^62 + * + * Breaking up the exponent's binary representation into "repunits", we get: + * { 31 1s } { 1 0s } { 128 1s } { 31 0s } { 1 1s } { 62 0s} + * + * We use an addition chain for the beginning: [1], 2, 3, 6, 12, [24], 30, [31] + */ + + uint[] x1 = this.x; + if (Nat256.IsZero(x1) || Nat256.IsOne(x1)) + { + return this; + } + + uint[] x2 = Nat256.Create(); + SM2P256V1Field.Square(x1, x2); + SM2P256V1Field.Multiply(x2, x1, x2); + uint[] x3 = x2; + SM2P256V1Field.Square(x2, x3); + SM2P256V1Field.Multiply(x3, x1, x3); + uint[] x6 = Nat256.Create(); + SM2P256V1Field.SquareN(x3, 3, x6); + SM2P256V1Field.Multiply(x6, x3, x6); + uint[] x12 = x3; + SM2P256V1Field.SquareN(x6, 6, x12); + SM2P256V1Field.Multiply(x12, x6, x12); + uint[] x24 = Nat256.Create(); + SM2P256V1Field.SquareN(x12, 12, x24); + SM2P256V1Field.Multiply(x24, x12, x24); + uint[] x30 = x12; + SM2P256V1Field.SquareN(x24, 6, x30); + SM2P256V1Field.Multiply(x30, x6, x30); + uint[] x31 = x6; + SM2P256V1Field.Square(x30, x31); + SM2P256V1Field.Multiply(x31, x1, x31); + + uint[] t1 = x31; + SM2P256V1Field.Square(x31, t1); + + uint[] x32 = x12; + SM2P256V1Field.Multiply(t1, x1, x32); + + SM2P256V1Field.SquareN(t1, 32, t1); + SM2P256V1Field.Multiply(t1, x32, t1); + + uint[] t2 = x24; + SM2P256V1Field.SquareN(t1, 32, t2); + SM2P256V1Field.Multiply(t2, x1, t2); + SM2P256V1Field.SquareN(t2, 32, t2); + SM2P256V1Field.Multiply(t2, t1, t2); + SM2P256V1Field.SquareN(t2, 32, t2); + SM2P256V1Field.Multiply(t2, x32, t2); + SM2P256V1Field.SquareN(t2, 32, t2); + SM2P256V1Field.Multiply(t2, x1, t2); + SM2P256V1Field.SquareN(t2, 62, t1); + SM2P256V1Field.Square(t1, t2); + + return Nat256.Eq(x1, t2) ? new SM2P256V1FieldElement(t1) : null; + } + + public override bool Equals(object obj) + { + return Equals(obj as SM2P256V1FieldElement); + } + + public override bool Equals(ECFieldElement other) + { + return Equals(other as SM2P256V1FieldElement); + } + + public virtual bool Equals(SM2P256V1FieldElement other) + { + if (this == other) + return true; + if (null == other) + return false; + return Nat256.Eq(x, other.x); + } + + public override int GetHashCode() + { + return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 8); + } + } +} diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1Point.cs b/crypto/src/math/ec/custom/gm/SM2P256V1Point.cs new file mode 100644 index 000000000..916c90633 --- /dev/null +++ b/crypto/src/math/ec/custom/gm/SM2P256V1Point.cs @@ -0,0 +1,279 @@ +using System; + +using Org.BouncyCastle.Math.Raw; + +namespace Org.BouncyCastle.Math.EC.Custom.GM +{ + internal class SM2P256V1Point + : AbstractFpPoint + { + /** + * Create a point which encodes with point compression. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + : this(curve, x, y, false) + { + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * @param withCompression + * if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer + * {@link #getEncoded(bool)} + */ + public SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) + : base(curve, x, y, withCompression) + { + if ((x == null) != (y == null)) + throw new ArgumentException("Exactly one of the field elements is null"); + } + + internal SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) + : base(curve, x, y, zs, withCompression) + { + } + + protected override ECPoint Detach() + { + return new SM2P256V1Point(null, AffineXCoord, AffineYCoord); + } + + public override ECPoint Add(ECPoint b) + { + if (this.IsInfinity) + return b; + if (b.IsInfinity) + return this; + if (this == b) + return Twice(); + + ECCurve curve = this.Curve; + + SM2P256V1FieldElement X1 = (SM2P256V1FieldElement)this.RawXCoord, Y1 = (SM2P256V1FieldElement)this.RawYCoord; + SM2P256V1FieldElement X2 = (SM2P256V1FieldElement)b.RawXCoord, Y2 = (SM2P256V1FieldElement)b.RawYCoord; + + SM2P256V1FieldElement Z1 = (SM2P256V1FieldElement)this.RawZCoords[0]; + SM2P256V1FieldElement Z2 = (SM2P256V1FieldElement)b.RawZCoords[0]; + + uint c; + uint[] tt1 = Nat256.CreateExt(); + uint[] t2 = Nat256.Create(); + uint[] t3 = Nat256.Create(); + uint[] t4 = Nat256.Create(); + + bool Z1IsOne = Z1.IsOne; + uint[] U2, S2; + if (Z1IsOne) + { + U2 = X2.x; + S2 = Y2.x; + } + else + { + S2 = t3; + SM2P256V1Field.Square(Z1.x, S2); + + U2 = t2; + SM2P256V1Field.Multiply(S2, X2.x, U2); + + SM2P256V1Field.Multiply(S2, Z1.x, S2); + SM2P256V1Field.Multiply(S2, Y2.x, S2); + } + + bool Z2IsOne = Z2.IsOne; + uint[] U1, S1; + if (Z2IsOne) + { + U1 = X1.x; + S1 = Y1.x; + } + else + { + S1 = t4; + SM2P256V1Field.Square(Z2.x, S1); + + U1 = tt1; + SM2P256V1Field.Multiply(S1, X1.x, U1); + + SM2P256V1Field.Multiply(S1, Z2.x, S1); + SM2P256V1Field.Multiply(S1, Y1.x, S1); + } + + uint[] H = Nat256.Create(); + SM2P256V1Field.Subtract(U1, U2, H); + + uint[] R = t2; + SM2P256V1Field.Subtract(S1, S2, R); + + // Check if b == this or b == -this + if (Nat256.IsZero(H)) + { + if (Nat256.IsZero(R)) + { + // this == b, i.e. this must be doubled + return this.Twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.Infinity; + } + + uint[] HSquared = t3; + SM2P256V1Field.Square(H, HSquared); + + uint[] G = Nat256.Create(); + SM2P256V1Field.Multiply(HSquared, H, G); + + uint[] V = t3; + SM2P256V1Field.Multiply(HSquared, U1, V); + + SM2P256V1Field.Negate(G, G); + Nat256.Mul(S1, G, tt1); + + c = Nat256.AddBothTo(V, V, G); + SM2P256V1Field.Reduce32(c, G); + + SM2P256V1FieldElement X3 = new SM2P256V1FieldElement(t4); + SM2P256V1Field.Square(R, X3.x); + SM2P256V1Field.Subtract(X3.x, G, X3.x); + + SM2P256V1FieldElement Y3 = new SM2P256V1FieldElement(G); + SM2P256V1Field.Subtract(V, X3.x, Y3.x); + SM2P256V1Field.MultiplyAddToExt(Y3.x, R, tt1); + SM2P256V1Field.Reduce(tt1, Y3.x); + + SM2P256V1FieldElement Z3 = new SM2P256V1FieldElement(H); + if (!Z1IsOne) + { + SM2P256V1Field.Multiply(Z3.x, Z1.x, Z3.x); + } + if (!Z2IsOne) + { + SM2P256V1Field.Multiply(Z3.x, Z2.x, Z3.x); + } + + ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; + + return new SM2P256V1Point(curve, X3, Y3, zs, IsCompressed); + } + + public override ECPoint Twice() + { + if (this.IsInfinity) + return this; + + ECCurve curve = this.Curve; + + SM2P256V1FieldElement Y1 = (SM2P256V1FieldElement)this.RawYCoord; + if (Y1.IsZero) + return curve.Infinity; + + SM2P256V1FieldElement X1 = (SM2P256V1FieldElement)this.RawXCoord, Z1 = (SM2P256V1FieldElement)this.RawZCoords[0]; + + uint c; + uint[] t1 = Nat256.Create(); + uint[] t2 = Nat256.Create(); + + uint[] Y1Squared = Nat256.Create(); + SM2P256V1Field.Square(Y1.x, Y1Squared); + + uint[] T = Nat256.Create(); + SM2P256V1Field.Square(Y1Squared, T); + + bool Z1IsOne = Z1.IsOne; + + uint[] Z1Squared = Z1.x; + if (!Z1IsOne) + { + Z1Squared = t2; + SM2P256V1Field.Square(Z1.x, Z1Squared); + } + + SM2P256V1Field.Subtract(X1.x, Z1Squared, t1); + + uint[] M = t2; + SM2P256V1Field.Add(X1.x, Z1Squared, M); + SM2P256V1Field.Multiply(M, t1, M); + c = Nat256.AddBothTo(M, M, M); + SM2P256V1Field.Reduce32(c, M); + + uint[] S = Y1Squared; + SM2P256V1Field.Multiply(Y1Squared, X1.x, S); + c = Nat.ShiftUpBits(8, S, 2, 0); + SM2P256V1Field.Reduce32(c, S); + + c = Nat.ShiftUpBits(8, T, 3, 0, t1); + SM2P256V1Field.Reduce32(c, t1); + + SM2P256V1FieldElement X3 = new SM2P256V1FieldElement(T); + SM2P256V1Field.Square(M, X3.x); + SM2P256V1Field.Subtract(X3.x, S, X3.x); + SM2P256V1Field.Subtract(X3.x, S, X3.x); + + SM2P256V1FieldElement Y3 = new SM2P256V1FieldElement(S); + SM2P256V1Field.Subtract(S, X3.x, Y3.x); + SM2P256V1Field.Multiply(Y3.x, M, Y3.x); + SM2P256V1Field.Subtract(Y3.x, t1, Y3.x); + + SM2P256V1FieldElement Z3 = new SM2P256V1FieldElement(M); + SM2P256V1Field.Twice(Y1.x, Z3.x); + if (!Z1IsOne) + { + SM2P256V1Field.Multiply(Z3.x, Z1.x, Z3.x); + } + + return new SM2P256V1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed); + } + + public override ECPoint TwicePlus(ECPoint b) + { + if (this == b) + return ThreeTimes(); + if (this.IsInfinity) + return b; + if (b.IsInfinity) + return Twice(); + + ECFieldElement Y1 = this.RawYCoord; + if (Y1.IsZero) + return b; + + return Twice().Add(b); + } + + public override ECPoint ThreeTimes() + { + if (this.IsInfinity || this.RawYCoord.IsZero) + return this; + + // NOTE: Be careful about recursions between TwicePlus and ThreeTimes + return Twice().Add(this); + } + + public override ECPoint Negate() + { + if (IsInfinity) + return this; + + return new SM2P256V1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed); + } + } +} |