public static bool?VerifySignature(byte[] pkParameters, byte[] pkKey, byte[] hash, byte[] signature) { EllipticCurve curve = GetCurveFromParameters(pkParameters); if (curve == null) { return(null); } // We must decode the signature from DER format to raw format (to coordinates on the curve) int offset = 1; // Skip tag 0x30 Utils.GetASNLength(signature, ref offset); // P521 requires 2 bytes to specify the length offset += 1; // 0x02 int len1 = Utils.GetASNLength(signature, ref offset); var rBytes = new byte[len1]; for (var i = 0; i < len1; i++) { rBytes[i] = signature[offset + len1 - 1 - i]; } offset += len1; offset += 1; // 0x02 int len2 = Utils.GetASNLength(signature, ref offset); var sBytes = new byte[len2]; for (var i = 0; i < len2; i++) { sBytes[i] = signature[offset + len2 - 1 - i]; } var r = new BigInteger(rBytes); var s = new BigInteger(sBytes); // Verify that r, s are in [1, q - 1] and Qa lies on the curve if (r == 0 || s == 0) { return(false); } if (r >= curve.q || s >= curve.q) { return(false); } BigInt Qax = new BigInt(pkKey, 1, curve.curveByteLen), Qay = new BigInt(pkKey, 1 + curve.curveByteLen, curve.curveByteLen); BigInteger QaxBi = Qax.ExportToBigInteger(), QayBi = Qay.ExportToBigInteger(); var pBi = curve.p.ExportToBigInteger(); if (QaxBi >= pBi || QayBi >= pBi) { return(false); } if ((QaxBi * QaxBi * QaxBi - 3 * QaxBi + curve.b + pBi * 3) % pBi != QayBi * QayBi % pBi) { return(false); } // Data points are ok, now start verify the signature var hashLen = hash.Length; byte[] hash2 = null; if (hash[0] >= 128) { hash2 = new byte[hash.Length + 1]; hash2[hash.Length] = 0; for (var i = 0; i < hash.Length; i++) { hash2[i] = hash[hash.Length - 1 - i]; } } else { Array.Reverse(hash); hash2 = hash; } var z = new BigInteger(hash2); if (hashLen * 8 > curve.curveLen) // Should be compared to order length, but p length is the same for NIST curves { var excessBits = hashLen * 8 - curve.curveLen; z >>= excessBits; } var w = BigInteger.ModPow(s, curve.q - 2, curve.q); var u1 = z * w % curve.q; var u2 = r * w % curve.q; var mul = curve.EcTwinMult(new BigInt(u1, (curve.curveByteLen + 3) / 4), new Projective() { x = curve.xg, y = curve.yg, z = new BigInt(1, (curve.curveByteLen + 3) / 4) }, new BigInt(u2, (curve.curveByteLen + 3) / 4), new Projective() { x = Qax, y = Qay, z = new BigInt(1, (curve.curveByteLen + 3) / 4) }); var res = curve.EcAffinify(mul).x.ExportToBigInteger(); if (res >= curve.q) { res -= curve.q; } bool ok = res == r; return(ok); }