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));
        }
Exemple #2
0
        /// 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);
        }
Exemple #3
0
        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));
        }
Exemple #4
0
        /// 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;
        }