private bool CheckPubkeys(Autarkysoft.Bitcoin.Cryptography.Asymmetric.EllipticCurve.Signature sig, byte[] toSign, string address, Address.AddressType addrType) { if (calc.TryRecoverPublicKeys(toSign, sig, out EllipticCurvePoint[] pubkeys))
/// <summary> /// Verifies if the given signature is a valid ECDSA signature based on Standards for Efficient Cryptography /// (SEC 1: Elliptic Curve Cryptography) 4.1.4 Verifying Operation (page 46). /// </summary> /// <param name="hash">Hash(m) used in signing</param> /// <param name="sig">Signature</param> /// <param name="pubK">Public key</param> /// <param name="lowS">If true s values bigger than <see cref="IECurveFp.N"/>/2 are rejected.</param> /// <returns>True if the signature was valid, otherwise false.</returns> public bool Verify(byte[] hash, Signature sig, PublicKey pubK, bool lowS = true) { return(Verify(hash, sig, pubK.ToPoint(), lowS)); }
/// <summary> /// Verifies if the given signature is a valid ECSDSA signature based on BIP-340. /// </summary> /// <param name="hash">Hash(m) used in signing</param> /// <param name="sig">Signature</param> /// <param name="pubK">Public key</param> /// <returns>True if the signature was valid, otherwise false.</returns> public bool VerifySchnorr(byte[] hash, Signature sig, PublicKey pubK) { return(VerifySchnorr(hash, sig, pubK.ToPoint())); }
// Note: in all the following methods, we assume inputs are valid hence skip checkking. // It is because all these methods are used internally by other classes that perform the checks. // for example Sign() is used by PrivateKey so the keyBytes and hash are both valid /// <summary> /// Creates a signature using ECDSA based on Standards for Efficient Cryptography (SEC 1: Elliptic Curve Cryptography) /// section 4.1.3 Signing Operation (page 44). /// Return value indicates success. /// </summary> /// <param name="hash">Hash(m) to use for signing</param> /// <param name="key">Private key bytes (must be padded to 32 bytes)</param> /// <param name="k"> /// The ephemeral elliptic curve key used for signing /// (k should be smaller than <see cref="IECurveFp.N"/>, it is always smaller if <see cref="Rfc6979"/> is used). /// </param> /// <param name="lowS">If true s values bigger than <see cref="IECurveFp.N"/>/2 will be converted.</param> /// <param name="lowR">If true the process fails if R.X had its highest bit set</param> /// <param name="sig">Signature (null if process fails)</param> /// <returns>True if successful, otherwise false.</returns> public bool TrySign(byte[] hash, byte[] key, BigInteger k, bool lowS, bool lowR, out Signature sig) { // TODO: research what happens if e value is zero. does it reveal private key? // https://bitcointalk.org/index.php?topic=260595.msg4928224#msg4928224 BigInteger e = hash.ToBigInt(true, true); EllipticCurvePoint rp = MultiplyChecked(k, curve.G); byte v = (byte)(((rp.X > curve.N) ? 2 : 0) | (rp.Y.IsEven ? 0 : 1)); BigInteger r = rp.X % curve.N; // Note about r: // R.X is at most 32 bytes, if the highest bit is set then in DER encoding 0 is appended to indicate // it is a positive integer. // Here if low r is requested, we only check the length and reject cases where R.X is 32 bytes and needs the // additional 0 and if R.X was smaller than 32 bytes it passes even if the higest bit was set. // In other words 0<31 bytes> or 0<30 byte>,... are accepted // TODO: when BigInteger is replaced by ModularUInt256 in the future, this should be replaced by a simple // test of the highest bit instead of ToByteArray and length check. if (r == 0 || (lowR && r.ToByteArray(isBigEndian: true).Length > 32)) { sig = null; return(false); } BigInteger s = k.ModInverse(curve.N) * (e + (r * key.ToBigInt(true, true))) % curve.N; if (s == 0) { sig = null; return(false); } if (lowS && s > curve.N / 2) { v ^= 1; s = curve.N - s; } sig = new Signature(r, s, v); return(true); }