Пример #1
0
        /// <summary>
        /// Recovers the ephemeral key used to sign the transformed nonce in the authentication data.
        /// Throws an exception if the recovered key is invalid, or could not be recovered.
        /// </summary>
        /// <param name="receiverPrivateKey">The private key of the receiver used to generate the shared secret.</param>
        /// <returns>Returns the remote ephemeral public key for the keypair which signed this authentication data.</returns>
        public virtual (EthereumEcdsa remoteEphemeralPublicKey, uint?chainId) RecoverDataFromSignature(EthereumEcdsa receiverPrivateKey)
        {
            // Create an EC provider with the given public key.
            EthereumEcdsa publicKey = EthereumEcdsa.Create(PublicKey, EthereumEcdsaKeyType.Public);

            // Generate the shared secret using ECDH between our local private key and this remote public key
            byte[] ecdhKey = receiverPrivateKey.ComputeECDHKey(publicKey);

            // Obtain our transformed nonce data.
            byte[] transformedNonceData = GetTransformedNonce(ecdhKey);

            // We want our signature in r,s,v format.
            BigInteger ecdsa_r = BigIntegerConverter.GetBigInteger(R, false, 32);
            BigInteger ecdsa_s = BigIntegerConverter.GetBigInteger(S, false, 32);

            (byte recoveryId, uint?chainId) = EthereumEcdsa.GetRecoveryAndChainIDFromV(V);

            // Recover the public key from the data provided.
            EthereumEcdsa remoteEphemeralPublickey = EthereumEcdsa.Recover(transformedNonceData, recoveryId, ecdsa_r, ecdsa_s);

            // Verify the key is valid

            // Return the ephemeral key
            return(remoteEphemeralPublickey, chainId);
        }
Пример #2
0
        // Precompiles Below
        /// <summary>
        /// A precompiled contract which uses v,r,s + hash obtained from the message data to perform elliptic curve public key recovery to obtain a senders address.
        /// </summary>
        /// <param name="evm">The Ethereum Virtual Machine instance we are executing inside of.</param>
        private static EVMExecutionResult Precompile_ECRecover(MeadowEVM evm)
        {
            // Charge the gas for the precompile operation before processing.
            evm.GasState.Deduct(GasDefinitions.GAS_PRECOMPILE_ECRECOVER);

            // Obtain a memory representation of our data.
            Span <byte> messageData = new Span <byte>(evm.Message.Data);

            // We extract our signature information from message data (256-bit each)
            Span <byte> hash = messageData.Slice(0, EVMDefinitions.WORD_SIZE);
            BigInteger  v    = BigIntegerConverter.GetBigInteger(messageData.Slice(32, EVMDefinitions.WORD_SIZE));
            BigInteger  r    = BigIntegerConverter.GetBigInteger(messageData.Slice(64, EVMDefinitions.WORD_SIZE));
            BigInteger  s    = BigIntegerConverter.GetBigInteger(messageData.Slice(96, EVMDefinitions.WORD_SIZE));

            // Verify we have a low r, s, and a valid v.
            if (r >= Secp256k1Curve.N || s >= Secp256k1Curve.N || v < 27 || v > 28)
            {
                // We failed v,r,s verification, so we stop executing.
                return(new EVMExecutionResult(evm, null, true));
            }

            // Obtain our recovery id from v.
            byte recoveryID = EthereumEcdsa.GetRecoveryAndChainIDFromV((byte)v).recoveryId;

            // Try to get an address from this. If it fails, it will throw an exception.
            byte[] senderAddress = null;
            try
            {
                senderAddress = EthereumEcdsa.Recover(hash, recoveryID, r, s).GetPublicKeyHash();
            }
            catch
            {
                // Recovery failed, so we stop executing.
                return(new EVMExecutionResult(evm, null, true));
            }

            // The address portion is at the end, and we zero out the leading portion.
            for (int i = 0; i < senderAddress.Length - Address.ADDRESS_SIZE; i++)
            {
                senderAddress[i] = 0;
            }

            // Return the sender address
            return(new EVMExecutionResult(evm, senderAddress, true));
        }
Пример #3
0
        public void SignAndVerify(bool useBouncyCastle)
        {
            // Generate ECDSA keypair, compute a hash, sign it, then recover the public key from the signature and verify it matches.
            EthereumEcdsa provider;

            if (useBouncyCastle)
            {
                provider = EthereumEcdsaBouncyCastle.Generate(new SystemRandomAccountDerivation());
            }
            else
            {
                provider = EthereumEcdsaNative.Generate(new SystemRandomAccountDerivation());
            }

            byte[] hash = KeccakHash.ComputeHashBytes(new byte[] { 11, 22, 33, 44 });
            (byte RecoveryID, BigInteger r, BigInteger s)signature = provider.SignData(hash);
            EthereumEcdsa recovered = EthereumEcdsa.Recover(hash, signature.RecoveryID, signature.r, signature.s);

            Assert.True(provider.GetPublicKeyHash().ValuesEqual(recovered.GetPublicKeyHash()));
        }