private static BigInteger _recoverFromSignature(int recId, ECSignature sig, byte[] msg, ECDomainParameters parameters) { BigInteger n = parameters.N; BigInteger i = new BigInteger((recId / 2).ToString()); BigInteger x = sig.r.Add(i.Multiply(n)); if (x.CompareTo(_prime) >= 0) { return(null); } ECPoint R = _decompressKey(x, (recId & 1) == 1, parameters.Curve); if (!(R.Multiply(n)).IsInfinity) { return(null); } BigInteger e = _bytesToInt(msg); BigInteger eInv = (BigInteger.Zero.Subtract(e)); eInv = n.DivideAndRemainder(eInv)[1]; BigInteger rInv = sig.r.ModInverse(n); BigInteger srInv = rInv.Multiply(sig.s).DivideAndRemainder(n)[1]; BigInteger eInvrInv = (rInv.Multiply(eInv)).DivideAndRemainder(n)[1]; ECPoint q = ((parameters.G).Multiply(eInvrInv)).Add(R.Multiply(srInv)); byte[] bytes = q.GetEncoded(false); byte[] retBytes = new byte[bytes.Length - 1]; Array.Copy(bytes, 1, retBytes, 0, bytes.Length - 1); return(_bytesToInt(retBytes)); }
/// Canonicalizes [signature]. /// This is necessary because if a message can be signed by (r, s), it can also be signed by (r, -s (mod N)). /// More details at /// https://github.com/web3j/web3j/blob/master/crypto/src/main/java/org/web3j/crypto/ECDSASignature.java#L27 static ECSignature _toCanonicalised(ECSignature signature) { X9ECParameters _params = ECNamedCurveTable.GetByName("secp256k1"); BigInteger _halfCurveOrder = _params.N.ShiftRight(1); if (signature.s.CompareTo(_halfCurveOrder) > 0) { BigInteger canonicalisedS = _params.N.Subtract(signature.s); signature = new ECSignature(signature.r, canonicalisedS); } return(signature); }
public override bool Equals(Object obj) { if (obj == null) { return(false); } if (!(obj is ECSignature)) { return(false); } ECSignature test = obj as ECSignature; return((test.r == this.r) && (test.s == this.s)); }
/// Signs the given [data] using the private key associated with this wallet, /// returning the signature bytes ASN.1 DER encoded. public byte[] sign(byte[] data) { ECDsaSigner ecdsaSigner = new ECDsaSigner(); ecdsaSigner.Init(true, new ParametersWithRandom(ecPrivateKey, getSecureRandom())); ECSignature ecSignatureWk = new ECSignature(ecdsaSigner.GenerateSignature(data)); // RC 20200507 - Canonicalize signature (is this necessary?) ECSignature ecSignature = _toCanonicalised(ecSignatureWk); // RC 20200507 - Create the array in the new way - no more ASN1 byte[] sigBytes = ecSignature.r.ToByteArray().Concat(ecSignature.s.ToByteArray()).ToArray(); // Black magic - by Marco Ruaro - 20201016 if (sigBytes.Length > 64) { sigBytes = sigBytes.Skip(1).ToArray(); } return(sigBytes); }
public static byte[] deriveFrom(byte[] message, ECPrivateKeyParameters privateKey, ECPublicKeyParameters publicKey) { // RC 20201018 - Rearrange Signature in order to use the same approach of wallet.sign X9ECParameters curve = ECNamedCurveTable.GetByName("secp256k1"); ECDomainParameters _params = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed()); BigInteger _halfCurveOrder = _params.N.ShiftRight(1); ECDsaSigner ecdsaSigner = new ECDsaSigner(new HMacDsaKCalculator(new Sha256Digest())); ecdsaSigner.Init(true, privateKey); ECSignature ecSignature = new ECSignature(ecdsaSigner.GenerateSignature(message)); // RC 20201018 - This approach is better, as it will generate randomized signatures - In case, TestTXSigner needs to be rearranged too //ECDsaSigner ecdsaSigner = new ECDsaSigner(); //ecdsaSigner.Init(true, new ParametersWithRandom(privateKey, Wallet.getSecureRandom())); //ECSignature ecSignature = new ECSignature(ecdsaSigner.GenerateSignature(message)); // Canonicalize Signature... if (ecSignature.s.CompareTo(_halfCurveOrder) > 0) { BigInteger canonicalS = _params.N.Subtract(ecSignature.s); ecSignature = new ECSignature(ecSignature.r, canonicalS); } // Create a signer to check signature ECDsaSigner ecdsaChecker = new ECDsaSigner(new HMacDsaKCalculator(new Sha256Digest())); ecdsaChecker.Init(false, publicKey); bool signatureOK = ecdsaChecker.VerifySignature(message, ecSignature.r, ecSignature.s); if (signatureOK == false) { System.ArgumentException argEx = new System.ArgumentException("TransactionSigner - Error in checking signature!"); throw argEx; } // RC 20201018 - Again Black Magic as in Wallet.sign byte[] sigBytes = ecSignature.r.ToByteArray().Concat(ecSignature.s.ToByteArray()).ToArray(); // Black magic - by Marco Ruaro - 20201016 if (sigBytes.Length > 64) { sigBytes = sigBytes.Skip(1).ToArray(); } return(sigBytes); // 20200223 Rick - The code to recover the signature is somewhat bugged, and it looks like it's no use. // I replaced it with a check for the correcness of the signature above. // This code is commented out at the moment. //byte[] wkPublicKeyBytes = publicKey.Q.GetEncoded(false); //byte[] publicKeyBytes = new byte[wkPublicKeyBytes.Length - 1]; //Array.Copy(wkPublicKeyBytes, 1, publicKeyBytes, 0, wkPublicKeyBytes.Length - 1); //BigInteger publicKeyBigInt = _bytesToInt(publicKeyBytes); //int recoveryID = -1; //for (int i = 0; i < 4; i++) //{ // BigInteger k = _recoverFromSignature(i, ecSignature, message, _params); // // Need to check for null here! // if (k != null) // { // if (k.CompareTo(publicKeyBigInt) == 0) // { // recoveryID = i; // break; // } // } // // 20200219 - Removed premature exit from loop // // else // // break; //} //Debug.WriteLine($"****** _recoverFromSignature: recoveryId = {recoveryID}"); //if (recoveryID == -1) //{ // System.ArgumentException argEx = new System.ArgumentException("Invalid recoverable key!"); // throw argEx; //} // RC 20201018 - Discarted against black magic above //// Final assembly //byte[] r = _intToBytes(ecSignature.r); //byte[] s = _intToBytes(ecSignature.s); //byte[] z = new byte[r.Length + s.Length]; //r.CopyTo(z, 0); //s.CopyTo(z, r.Length); //return z; }