public EcPoint(EcPoint p) { A = p.A; B = p.B; X = p.X; Y = p.Y; FieldChar = p.FieldChar; }
//умножение точки на число. public static EcPoint Multiply(EcPoint p, BigInteger c) { EcPoint res = p; c = c - 1; while (c != 0) { if (c % 2 != 0) { res = (res.X == p.X || res.Y == p.Y) ? Doubling(res) : res + p; c--; } c /= 2; p = Doubling(p); } return(res); }
//сложение пары точек. public static EcPoint operator +(EcPoint p1, EcPoint p2) { var res = new EcPoint { A = p1.A, B = p1.B, FieldChar = p1.FieldChar }; BigInteger dx = p2.X - p1.X; BigInteger dy = p2.Y - p1.Y; if (dx < 0) { dx += p1.FieldChar; } if (dy < 0) { dy += p1.FieldChar; } BigInteger t = (dy * dx.modInverse(p1.FieldChar)) % p1.FieldChar; if (t < 0) { t += p1.FieldChar; } res.X = (t * t - p1.X - p2.X) % p1.FieldChar; res.Y = (t * (p1.X - res.X) - p1.Y) % p1.FieldChar; if (res.X < 0) { res.X += p1.FieldChar; } if (res.Y < 0) { res.Y += p1.FieldChar; } return(res); }
//удвоение точки. public static EcPoint Doubling(EcPoint p) { var res = new EcPoint { A = p.A, B = p.B, FieldChar = p.FieldChar }; BigInteger dx = 2 * p.Y; BigInteger dy = 3 * p.X * p.X + p.A; if (dx < 0) { dx += p.FieldChar; } if (dy < 0) { dy += p.FieldChar; } BigInteger t = (dy * dx.modInverse(p.FieldChar)) % p.FieldChar; res.X = (t * t - p.X - p.X) % p.FieldChar; res.Y = (t * (p.X - res.X) - p.Y) % p.FieldChar; if (res.X < 0) { res.X += p.FieldChar; } if (res.Y < 0) { res.Y += p.FieldChar; } return(res); }
public (SM2DeriveBytes?Key, byte[] Verifier, byte[] PeerVerifier) DeriveKey( EcPoint peerPubKey, EcPoint peerR, ReadOnlySpan <byte> peerIdent) { if (!_ephemeralKey.Param.Curve.ValidatePoint(peerPubKey)) { throw new CryptographicException(); } if (!_ephemeralKey.Param.Curve.ValidatePoint(peerR)) { throw new CryptographicException(); } var pkBytes = (_ephemeralKey.Param.Curve.BitLength + 7) / 8; var zPeer = SM2.ZValue(_ephemeralKey.Param, _hash, peerIdent, peerPubKey); var w = _ephemeralKey.Param.BitLength; if (_ephemeralKey.Param.N.IsPowerOfTwo) { w -= 1; } w = (ushort)((w >> 1) + (w & 1) - 1); var w2 = (BigInteger)1 << w; var x2 = w2 + (_ephemeralKey.Q.X & (w2 - 1)); var t = (_privateKey + x2 * _ephemeralKey.D) % _ephemeralKey.Param.N; var x1 = w2 + (peerR.X & (w2 - 1)); var vi = _ephemeralKey.Param.Curve.MultiplyAndAdd(1, peerPubKey, x1, peerR, _rng); var v = _ephemeralKey.Param.Curve.ToAffine(_ephemeralKey.Param.Curve.Multiply(_ephemeralKey.Param.H * t, vi, _rng)); if (v.Inf) { return(null, null !, null !); } var za = _responder ? zPeer : _zValue; var zb = _responder ? _zValue : zPeer; var zl = za.Length + zb.Length; var key = new byte[pkBytes * 2 + zl]; var xv = v.X.ToByteArrayUBe(pkBytes); var yv = v.Y.ToByteArrayUBe(pkBytes); xv.CopyTo(key, 0); yv.CopyTo(key, pkBytes); za.CopyTo(key, pkBytes * 2); zb.CopyTo(key, pkBytes * 2 + za.Length); var kdf = new SM2DeriveBytes(key, _hash); var ra = _responder ? peerR : _ephemeralKey.Q; var rb = _responder ? _ephemeralKey.Q : peerR; #if NETSTANDARD2_0 || NETSTANDARD2_1 _hash.Initialize(); _hash.TransformBlock(xv, 0, pkBytes, null, 0); _hash.TransformBlock(za, 0, za.Length, null, 0); _hash.TransformBlock(zb, 0, zb.Length, null, 0); _hash.TransformBlock(ra.X.ToByteArrayUBe(pkBytes), 0, pkBytes, null, 0); _hash.TransformBlock(ra.Y.ToByteArrayUBe(pkBytes), 0, pkBytes, null, 0); _hash.TransformBlock(rb.X.ToByteArrayUBe(pkBytes), 0, pkBytes, null, 0); _hash.TransformFinalBlock(rb.Y.ToByteArrayUBe(pkBytes), 0, pkBytes); var si = _hash.Hash; _hash.Initialize(); key[0] = 2; _hash.TransformBlock(key, 0, 1, null, 0); _hash.TransformBlock(yv, 0, pkBytes, null, 0); _hash.TransformFinalBlock(si, 0, si.Length); var sb = _hash.Hash; _hash.Initialize(); key[0] = 3; _hash.TransformBlock(key, 0, 1, null, 0); _hash.TransformBlock(yv, 0, pkBytes, null, 0); _hash.TransformFinalBlock(si, 0, si.Length); var sa = _hash.Hash; #else var sib = ArrayPool <byte> .Shared.Rent(pkBytes * 5 + zl); xv.CopyTo(sib, 0); za.CopyTo(sib, pkBytes); zb.CopyTo(sib, pkBytes + za.Length); ra.X.ToByteArrayUBe(pkBytes).CopyTo(sib, zl + pkBytes); ra.Y.ToByteArrayUBe(pkBytes).CopyTo(sib, zl + pkBytes * 2); rb.X.ToByteArrayUBe(pkBytes).CopyTo(sib, zl + pkBytes * 3); rb.Y.ToByteArrayUBe(pkBytes).CopyTo(sib, zl + pkBytes * 4); var si = _hash.ComputeHash(sib, 0, pkBytes * 5 + zl); ArrayPool <byte> .Shared.Return(sib); var sbb = ArrayPool <byte> .Shared.Rent(pkBytes + si.Length + 1); yv.CopyTo(sbb, 1); si.CopyTo(sbb, pkBytes + 1); sbb[0] = 2; var sb = _hash.ComputeHash(sbb, 0, pkBytes + si.Length + 1); sbb[0] = 3; var sa = _hash.ComputeHash(sbb, 0, pkBytes + si.Length + 1); ArrayPool <byte> .Shared.Return(sbb); #endif return(kdf, _responder ? sb : sa, _responder ? sa : sb); }