예제 #1
0
        /// <summary>
        /// Signs given data and returns the r and s components of the ECDSA signature, along with a recovery ID to recover the public key given the original signed message and the returned components.
        /// </summary>
        /// <param name="hash">The hash to be signed.</param>
        /// <returns>Returns r and s components of an ECDSA signature, along with a recovery ID to recover the signers public key given the original signed message and r, s.</returns>
        public override (byte RecoveryID, BigInteger r, BigInteger s) SignData(Span <byte> hash)
        {
            // Verify we have a private key.
            if (KeyType != EthereumEcdsaKeyType.Private)
            {
                throw _notPrivateKeyException;
            }

            // Initialize our crypto provider.
            ECDsaSigner signer = new ECDsaSigner();

            signer.Init(true, PrivateKey);

            // Obtain our signature, rs[0] ("r") and rs[1] ("s")
            Org.BouncyCastle.Math.BigInteger[] rs = signer.GenerateSignature(hash.ToArray());

            // We want to make sure we enforce a low S value
            rs[1] = Secp256k1Curve.EnforceLowS(rs[1]);

            // We need to return a valid recovery ID for this signature. We do this by trying all of our 4 possible recovery IDs to make sure the public key hash recovered is the same as ours.

            // We start by obtaining our current public key hash
            byte[] actualPublicKeyHash = GetPublicKeyHash();

            // Next we try of our potential recovery IDs until we can obtain the matching public key from the signature.
            // 2, 3 are usually not used and 0, 1 denote odd or even Y, which can be figured out.
            for (byte recoveryID = 0; recoveryID < 4; recoveryID++)
            {
                // We wrap this in a try in case, as we know one of these IDs will work.
                try
                {
                    EthereumEcdsa possibleMatch = Recover(hash, recoveryID, rs[0].ToNumericsBigInteger(), rs[1].ToNumericsBigInteger());
                    if (actualPublicKeyHash.ValuesEqual(possibleMatch.GetPublicKeyHash()))
                    {
                        return(recoveryID, rs[0].ToNumericsBigInteger(), rs[1].ToNumericsBigInteger());
예제 #2
0
        static EthereumEcdsaBouncyCastle GenerateSingle(uint accountIndex, IAccountDerivation accountFactory)
        {
            var privateKey = accountFactory.GeneratePrivateKey(accountIndex);
            var keyBigInt  = BigIntegerConverter.GetBigInteger(privateKey, signed: false, byteCount: PRIVATE_KEY_SIZE);

            keyBigInt = Secp256k1Curve.EnforceLowS(keyBigInt);

            // Return our private key instance.
            return(new EthereumEcdsaBouncyCastle(privateKey, EthereumEcdsaKeyType.Private));
        }
예제 #3
0
        static EthereumEcdsaNative Generate(uint accountIndex, Secp256k1 secp256k1, IAccountDerivation accountFactory)
        {
            var privateKey = accountFactory.GeneratePrivateKey(accountIndex);

            if (!secp256k1.SecretKeyVerify(privateKey))
            {
                var errMsg = "Unmanaged EC library failed to valid private key. ";
                if (IncludeKeyDataInExceptions)
                {
                    errMsg += $"Private key: {privateKey.ToHexString()}";
                }

                throw new Exception(errMsg);
            }

            var keyBigInt = BigIntegerConverter.GetBigInteger(privateKey, signed: false, byteCount: PRIVATE_KEY_SIZE);

            keyBigInt  = Secp256k1Curve.EnforceLowS(keyBigInt);
            privateKey = BigIntegerConverter.GetBytes(keyBigInt, PRIVATE_KEY_SIZE);

            return(new EthereumEcdsaNative(privateKey, EthereumEcdsaKeyType.Private));
        }