예제 #1
0
파일: VarArray.cs 프로젝트: zutobg/Meadow
        public override object ParseFromStorage(StorageManager storageManager, StorageLocation storageLocation, IJsonRpcClient rpcClient = null)
        {
            // Obtain our storage value for our given storage location.
            Memory <byte> storageData  = storageManager.ReadStorageSlot(storageLocation.SlotKey, storageLocation.DataOffset, SizeBytes);
            BigInteger    storageValue = BigIntegerConverter.GetBigInteger(storageData.Span, false, SizeBytes);

            // Define our element slot location to iterate over.
            StorageLocation elementLocation = new StorageLocation(storageLocation.SlotKey, 0);

            // If this is a dynamic sized type, our element's storage key will be the defining
            // array's key hashed, and all consecutive element items will have consecutive storage keys.

            // In any case, we'll want to grab our array length, which is either statically defined, or
            // is defined in the storage data obtained earlier from the given location.
            int length = 0;

            if (ArraySize.HasValue)
            {
                length = ArraySize.Value;
            }
            else
            {
                elementLocation.SlotKey = KeccakHash.ComputeHashBytes(elementLocation.SlotKey.Span);
                length = (int)storageValue;
            }

            // Create our resulting object array
            object[] arrayElements = new object[length];

            // Loop for every item.
            for (int i = 0; i < arrayElements.Length; i++)
            {
                // Decode our element at this index
                arrayElements[i] = ElementObject.ParseFromStorage(storageManager, elementLocation, rpcClient);

                // Determine how to iterate, dependent on if the array is dynamically sized or not, as described earlier,
                // (since it could compact multiple elements into a single storage slot).
                if (ElementObject.StorageEntryCount == 1 && storageLocation.DataOffset + ElementObject.SizeBytes <= UInt256.SIZE)
                {
                    // It was compacted with other data (or elligible to), so we advance data offset.
                    elementLocation.DataOffset += ElementObject.SizeBytes;

                    // If our data offset exceeded the size of a slot, we advance the slot.
                    if (elementLocation.DataOffset + ElementObject.SizeBytes > UInt256.SIZE)
                    {
                        elementLocation.SlotKeyInteger++;
                        elementLocation.DataOffset = 0;
                    }
                }
                else
                {
                    // We are not compacting our storage, so we advance for each element individually.
                    elementLocation.SlotKeyInteger += ElementObject.StorageEntryCount;
                    elementLocation.DataOffset      = 0;
                }
            }

            // Return our obtained array elements
            return(arrayElements);
        }
예제 #2
0
파일: MiningPoW.cs 프로젝트: zutobg/Meadow
        /// <summary>
        /// Given a block header, checks if the proof of work is valid on the block header. That is, if the header values, nonce, mix hash and difficulty are all suitable.
        /// </summary>
        /// <param name="blockNumber">The number of the block which we wish to validate.</param>
        /// <param name="headerHash">Hash of a portion of the block header which is used with the nonce to generate a seed for the proof.</param>
        /// <param name="mixHash">The resulting mix hash for the provided nonce after running the hashimoto algorithm.</param>
        /// <param name="nonce">The nonce which, along with the other provided values, will calculate the mix hash to be verified.</param>
        /// <param name="difficulty">The difficulty controls filtering for a plausible solution to the block which we wish to mine.</param>
        /// <returns>Returns true if the proof of work is valid, returns false is the proof is invalid.</returns>
        public static bool CheckProof(BigInteger blockNumber, byte[] headerHash, byte[] mixHash, byte[] nonce, BigInteger difficulty)
        {
            // Verify the length of our hashes and nonce
            if (headerHash.Length != KeccakHash.HASH_SIZE || mixHash.Length != KeccakHash.HASH_SIZE || nonce.Length != 8)
            {
                return(false);
            }

            // Flip endianness if we need to (should be little endian).
            byte[] nonceFlipped = (byte[])nonce.Clone();
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(nonceFlipped);
            }

            // Obtain our cache
            Memory <byte> cache = Ethash.MakeCache(blockNumber); // TODO: Make a helper function for this to cache x results.

            // Hash our block with the given nonce and etc.
            var result = Ethash.HashimotoLight(cache, blockNumber, headerHash, nonceFlipped);

            // Verify our mix hash matches
            if (!result.MixHash.ValuesEqual(mixHash))
            {
                return(false);
            }

            // Convert the result to a big integer.
            BigInteger upperBoundInclusive = BigInteger.Pow(2, EVMDefinitions.WORD_SIZE_BITS) / BigInteger.Max(difficulty, 1);
            BigInteger resultInteger       = BigIntegerConverter.GetBigInteger(result.Result);

            return(resultInteger <= upperBoundInclusive);
        }
예제 #3
0
        public override void Execute()
        {
            // Obtain the current block number, and the block number for the block we want the hash for.
            BigInteger currentBlockNumber  = EVM.State.CurrentBlock.Header.BlockNumber;
            BigInteger targetBlockNumber   = Stack.Pop();
            BigInteger previousHeaderIndex = currentBlockNumber - targetBlockNumber - 1;

            // We only cache a finite amount of block headers, currently this is 256.
            // NOTE: Although it's defined in our configuration, we hard code it here as some official Ethereum implementations do,
            // instead of being dependent on configuration. This way, if it were to change with a fork, we still remain backward compatible here
            // and can simply just add a case.
            if (previousHeaderIndex < 0 || previousHeaderIndex > 255)
            {
                // We couldn't obtain the block hash, we return zero.
                Stack.Push(0);
            }
            else
            {
                // Obtain the hash of this previous block and push it.
                Stack.Push(BigIntegerConverter.GetBigInteger(EVM.State.PreviousHeaders[(int)previousHeaderIndex].GetHash()));

                // Verify there was not some error with block numbers mismatches on the previous header we obtained.
                if (targetBlockNumber != EVM.State.PreviousHeaders[(int)previousHeaderIndex].BlockNumber)
                {
                    throw new Exception($"BlockNumber mismatch when performing a {Opcode.ToString()} instruction in the EVM!");
                }
            }
        }
예제 #4
0
        public override void Execute()
        {
            // Obtain our offset into call data we want to start copying at.
            BigInteger offset = Stack.Pop();

            // Read our data (if our offset is wrong or we hit the end of the array, the rest should be zeroes).
            byte[] data   = new byte[EVMDefinitions.WORD_SIZE];
            int    length = data.Length;

            if (offset > Message.Data.Length)
            {
                offset = 0;
                length = 0;
            }
            else if (offset + length > Message.Data.Length)
            {
                length = Message.Data.Length - (int)offset;
            }

            // Copy however much data we were able to out of our 32-byte desired count.
            Array.Copy(Message.Data, (int)offset, data, 0, length);

            // Convert it to a big integer and push it.
            Stack.Push(BigIntegerConverter.GetBigInteger(data));
        }
예제 #5
0
        public override object ParseFromStack(Data[] stack, int stackIndex, Memory <byte> memory, StorageManager storageManager)
        {
            // If we exceeded our stack size
            if (stack.Length <= stackIndex)
            {
                throw new VarResolvingException("Could not parse variable from stack using reference type method because the stack is not populated up to the target index.");
            }

            // Obtain our pointer data from the stack.
            Memory <byte> stackEntryData = stack[stackIndex].GetBytes();

            // Switch on our location
            switch (VariableLocation)
            {
            case VarLocation.Memory:
                // Parse our pointer from the bytes.
                BigInteger pointer = BigIntegerConverter.GetBigInteger(stackEntryData.Span, false, UInt256.SIZE);

                // Parse our dereferenced value from memory. (Using our stack data as a data offset)
                return(ParseDereferencedFromMemory(memory, (int)pointer));

            case VarLocation.Storage:
                // Parse our stack data as a storage key
                StorageLocation storageLocation = new StorageLocation(stackEntryData, 0);

                // Parse our value from storage. (Using our stack data as a storage key)
                return(ParseFromStorage(storageManager, storageLocation));

            default:
                throw new VarResolvingException("Could not parse variable from stack using reference type because the provided underlying location is invalid.");
            }
        }
예제 #6
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);
        }
예제 #7
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));
        }
예제 #8
0
        public override object ParseFromMemory(Memory <byte> memory, int offset)
        {
            // Read a pointer bytes (size of word) to dereference the value.
            Memory <byte> pointerData = memory.Slice(offset, UInt256.SIZE);

            // Parse our pointer from the bytes.
            BigInteger pointer = BigIntegerConverter.GetBigInteger(pointerData.Span, false, UInt256.SIZE);

            // Parse our dereferenced value.
            return(ParseDereferencedFromMemory(memory, (int)pointer));
        }
예제 #9
0
        public override object ParseDereferencedFromMemory(Memory <byte> memory, int offset)
        {
            // Dynamic memory is a WORD denoting length, followed by the length in bytes of data.

            // Read a length bytes (size of word) to dereference the value.
            Memory <byte> lengthData = memory.Slice(offset, UInt256.SIZE);
            BigInteger    length     = BigIntegerConverter.GetBigInteger(lengthData.Span, false, UInt256.SIZE);

            // Read our data
            return(memory.Slice(offset + UInt256.SIZE, (int)length));
        }
예제 #10
0
파일: RLP.cs 프로젝트: zutobg/Meadow
        public static BigInteger ToInteger(RLPByteArray rlpByteArray, int byteCount = 32, bool signed = false)
        {
            // If our data is null or empty, the result is 0.
            if (rlpByteArray.Data.Length == 0)
            {
                return(0);
            }

            // Obtain our integer
            return(BigIntegerConverter.GetBigInteger(rlpByteArray.Data.Span, signed, byteCount));
        }
예제 #11
0
        private static EVMExecutionResult Precompile_ECAdd(MeadowEVM evm)
        {
            // Verify we're past the byzantium fork
            if (evm.Version < EthereumRelease.Byzantium)
            {
                return(new EVMExecutionResult(evm, null, true));
            }

            // Charge the gas for the precompile operation before processing.
            BigInteger gasCharge = GasDefinitions.GAS_PRECOMPILE_ECADD_BASE;

            evm.GasState.Deduct(gasCharge);

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

            // Obtain our component data
            BigInteger x1 = BigIntegerConverter.GetBigInteger(messageData.Slice(0, EVMDefinitions.WORD_SIZE));
            BigInteger y1 = BigIntegerConverter.GetBigInteger(messageData.Slice(32, EVMDefinitions.WORD_SIZE));
            BigInteger x2 = BigIntegerConverter.GetBigInteger(messageData.Slice(64, EVMDefinitions.WORD_SIZE));
            BigInteger y2 = BigIntegerConverter.GetBigInteger(messageData.Slice(96, EVMDefinitions.WORD_SIZE));

            // Parse and verify our points.
            FpVector3 <Fp> point1 = ParsePoint(x1, y1);

            if (point1 == null)
            {
                throw new EVMException("ECAdd precompile failed because point 1 was deemed invalid when parsing.");
            }

            FpVector3 <Fp> point2 = ParsePoint(x2, y2);

            if (point1 == null)
            {
                throw new EVMException("ECAdd precompile failed because point 2 was deemed invalid when parsing.");
            }

            // Add the two points together
            FpVector3 <Fp> additionResult = point1.Add(point2);

            // Normalize the result into X/Y components.
            (Fp resultX, Fp resultY) = additionResult.Normalize();

            // Obtain the binary data for these results
            byte[] resultXData = BigIntegerConverter.GetBytes(resultX.N, EVMDefinitions.WORD_SIZE);
            byte[] resultYData = BigIntegerConverter.GetBytes(resultY.N, EVMDefinitions.WORD_SIZE);

            // Concat them to a singular result
            byte[] returnData = resultXData.Concat(resultYData);

            // Return our result
            return(new EVMExecutionResult(evm, returnData, true));
        }
예제 #12
0
        public override void Execute()
        {
            // Obtain the values for our call value, and call data memory.
            BigInteger value            = Stack.Pop();
            BigInteger inputMemoryStart = Stack.Pop();
            BigInteger inputMemorySize  = Stack.Pop();

            // We'll want to charge for memory expansion first
            Memory.ExpandStream(inputMemoryStart, inputMemorySize);

            // If we're in a static context, we can't self destruct
            if (Message.IsStatic)
            {
                throw new EVMException($"{Opcode.ToString()} instruction cannot execute in a static context!");
            }

            // Verify we have enough balance and call depth hasn't exceeded the maximum.
            if (EVM.State.GetBalance(Message.To) >= value && Message.Depth < EVMDefinitions.MAX_CALL_DEPTH)
            {
                // Obtain our call information.
                byte[]     callData     = Memory.ReadBytes((long)inputMemoryStart, (int)inputMemorySize);
                BigInteger innerCallGas = GasState.Gas;
                if (Version >= EthereumRelease.TangerineWhistle)
                {
                    innerCallGas = GasDefinitions.GetMaxCallGas(innerCallGas);
                }

                // Create our message
                EVMMessage         message       = new EVMMessage(Message.To, Address.ZERO_ADDRESS, value, innerCallGas, callData, Message.Depth + 1, Address.ZERO_ADDRESS, true, Message.IsStatic);
                EVMExecutionResult innerVMResult = MeadowEVM.CreateContract(EVM.State, message);
                if (innerVMResult.Succeeded)
                {
                    // Push our resulting address onto the stack.
                    Stack.Push(BigIntegerConverter.GetBigInteger(innerVMResult.ReturnData.ToArray()));
                    EVM.ExecutionState.LastCallResult = null;
                }
                else
                {
                    // We failed, push our fail value and put the last call data in place.
                    Stack.Push(0);
                    ExecutionState.LastCallResult = innerVMResult;
                }
            }
            else
            {
                // We didn't have a sufficient balance or call depth so we push nothing to the stack. We push 0 (fail)
                Stack.Push(0);

                // Set our last call result as null.
                ExecutionState.LastCallResult = null;
            }
        }
예제 #13
0
파일: EVMStack.cs 프로젝트: zutobg/Meadow
        public BigInteger Pop(bool signed = false)
        {
            // Verify we have items on the stack.
            if (_internalStack.Count == 0)
            {
                throw new EVMException("Tried to pop a value off of the stack when the stack was empty. This should not have happened.");
            }

            // Pop a value off the internal stack, convert it, and return it.
            byte[] data = _internalStack[_internalStack.Count - 1];
            _internalStack.RemoveAt(_internalStack.Count - 1);
            return(BigIntegerConverter.GetBigInteger(data, signed));
        }
예제 #14
0
파일: MiningPoW.cs 프로젝트: zutobg/Meadow
        /// <summary>
        /// Mines a given block starting from the provided nonce for the provided number of rounds.
        /// </summary>
        /// <param name="blockNumber">The number of the block which we are mining.</param>
        /// <param name="difficulty">The difficulty of the block which we are mining.</param>
        /// <param name="miningHash">The mining hash (partial header hash) of the block which we are mining.</param>
        /// <param name="startNonce">The starting nonce we will use and iterate through to try and find a suitable one for the reward.</param>
        /// <param name="rounds">The number of steps to take from our starting nonce before giving up. Use ulong.MaxValue to try all.</param>
        /// <returns>Returns the nonce and mixhash if block is successfully mined, otherwise both are null.</returns>
        public static (byte[] Nonce, byte[] MixHash) Mine(BigInteger blockNumber, BigInteger difficulty, byte[] miningHash, ulong startNonce, ulong rounds)
        {
            // Verify the length of our hashes and nonce
            if (miningHash == null || miningHash.Length != KeccakHash.HASH_SIZE)
            {
                return(null, null);
            }

            // Get our cache, set our start nonce and rounds remaining
            Memory <byte> cache           = Ethash.MakeCache(blockNumber);
            ulong         nonce           = startNonce;
            BigInteger    roundsRemaining = rounds;

            // Obtain our upper bound.
            BigInteger upperBoundInclusive = (BigInteger.Pow(2, EVMDefinitions.WORD_SIZE_BITS) / BigInteger.Max(difficulty, 1)) - 1;

            // Loop for each round.
            for (ulong i = 0; i <= rounds; i++)
            {
                // Increment our nonce.
                nonce++;

                // Obtain the bytes for it
                byte[] nonceData = BitConverter.GetBytes(nonce);

                // Flip endianness if we need to (should be little endian).
                if (!BitConverter.IsLittleEndian)
                {
                    Array.Reverse(nonceData);
                }

                // Obtain our mix hash with this nonce.
                var        result        = Ethash.HashimotoLight(cache, blockNumber, miningHash, nonceData);
                BigInteger resultInteger = BigIntegerConverter.GetBigInteger(result.Result);

                // If our result is below our difficulty bound.
                if (resultInteger <= upperBoundInclusive)
                {
                    // Flip endianness if we need to (returning nonce should be big endian).
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(nonceData);
                    }

                    // Return our nonce and mix hash.
                    return(nonceData, result.MixHash);
                }
            }

            return(null, null);
        }
예제 #15
0
        public async Task ModExpTest()
        {
            // Test the modexp precompile.
            var modExpTestBytes = await _contract.testModExp(
                BigIntegerConverter.GetBytes(BigInteger.Parse("1212121323543453245345678346345737475734753745737774573475377734577", CultureInfo.InvariantCulture)),
                BigIntegerConverter.GetBytes(BigInteger.Parse("3", CultureInfo.InvariantCulture)),
                BigIntegerConverter.GetBytes(BigInteger.Parse("4345328123928357434573234217343477", CultureInfo.InvariantCulture)))
                                  .Call();

            // Convert the result into an integer.
            var modExpTest = BigIntegerConverter.GetBigInteger(modExpTestBytes, false, modExpTestBytes.Length);

            Assert.AreEqual("856753145937825219130387866259147", modExpTest.ToString(CultureInfo.InvariantCulture));
        }
예제 #16
0
        public void BouncyCastleBigIntegerTests()
        {
            // Run 100 rounds of conversion from bouncy castle to system.numerics
            Random random = new Random();

            for (int i = 0; i < 100; i++)
            {
                byte[] data = new byte[random.Next(1, 0x20 + 1)];
                random.NextBytes(data);
                BigInteger bigInteger = BigIntegerConverter.GetBigInteger(data);
                Org.BouncyCastle.Math.BigInteger bcInteger = bigInteger.ToBouncyCastleBigInteger();
                BigInteger bigInteger2 = bcInteger.ToNumericsBigInteger();
                Assert.Equal <BigInteger>(bigInteger, bigInteger2);
            }
        }
예제 #17
0
        public void ValuesUnchanged()
        {
            Random random = new Random();

            for (int i = 0; i < 100; i++)
            {
                byte[] data = new byte[random.Next(1, 0x20 + 1)];
                random.NextBytes(data);
                BigInteger bigInteger = BigIntegerConverter.GetBigInteger(data);
                byte[]     parsed     = BigIntegerConverter.GetBytes(bigInteger);
                for (int x = 0; x < Math.Min(data.Length, parsed.Length); x++)
                {
                    Assert.Equal(data[data.Length - x - 1], parsed[parsed.Length - x - 1]);
                }
            }
        }
예제 #18
0
        public override object ParseDereferencedFromMemory(Memory <byte> memory, int offset)
        {
            // Verify our bounds
            if (offset >= memory.Length)
            {
                return(Array.Empty <object>());
            }

            // Define our length.
            int length = 0;

            // If our array has a constant size, set it. Otherwise it's dynamic and lives in memory.
            int elementOffset = offset;

            if (ArraySize.HasValue)
            {
                length = ArraySize.Value;
            }
            else
            {
                // Obtain our length data from memory.
                Memory <byte> lengthData = memory.Slice(offset, UInt256.SIZE);

                // Obtain our length integer from the read memory.
                length = (int)BigIntegerConverter.GetBigInteger(lengthData.Span, false, UInt256.SIZE);

                // Advance our element offset since our offset position referred to the length ifrst
                elementOffset += UInt256.SIZE;
            }

            // Create our resulting object array
            object[] arrayElements = new object[length];

            // Obtain every element of our array
            for (int i = 0; i < arrayElements.Length; i++)
            {
                // Parse our array element
                arrayElements[i] = ElementObject.ParseFromMemory(memory, elementOffset);

                // Advance our offset
                elementOffset += UInt256.SIZE;
            }

            // Return our array elements.
            return(arrayElements);
        }
예제 #19
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));
        }
예제 #20
0
        public async Task TestPrecompiles()
        {
            // Grab a list of accounts
            var accounts = await Client.Accounts();

            // Deploy our test contract
            var contract = await BasicContract.New($"TestName", true, 34, Client, new TransactionParams { From = accounts[0], Gas = 4712388 }, accounts[0]);

            // 1) This ECRecover test should yield 0x75c8aa4b12bc52c1f1860bc4e8af981d6542cccd. This test data is taken from SigningTests.cs
            var ecRecoverTest = await contract.testECRecover(
                new byte[] { 0xc9, 0xf1, 0xc7, 0x66, 0x85, 0x84, 0x5e, 0xa8, 0x1c, 0xac, 0x99, 0x25, 0xa7, 0x56, 0x58, 0x87, 0xb7, 0x77, 0x1b, 0x34, 0xb3, 0x5e, 0x64, 0x1c, 0xca, 0x85, 0xdb, 0x9f, 0xef, 0xd0, 0xe7, 0x1f },
                0x1c,
                BigIntegerConverter.GetBytes(BigInteger.Parse("68932463183462156574914988273446447389145511361487771160486080715355143414637", CultureInfo.InvariantCulture)),
                BigIntegerConverter.GetBytes(BigInteger.Parse("47416572686988136438359045243120473513988610648720291068939984598262749281683", CultureInfo.InvariantCulture)))
                                .Call();

            Assert.Equal("0x75c8aa4b12bc52c1f1860bc4e8af981d6542cccd", ecRecoverTest);

            // Precompile hash tests

            // 2) SHA-256
            var sha256HashTest = await contract.sha256str("hello world").Call(); // should be 0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9

            Assert.Equal("0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", sha256HashTest.ToHexString(hexPrefix: true));

            // 3) RIPEMD160
            var ripemd160HashTest = await contract.ripemd160str("hello world").Call(); // should be 0x98c615784ccb5fe5936fbc0cbe9dfdb408d92f0f

            Assert.Equal("0x98c615784ccb5fe5936fbc0cbe9dfdb408d92f0f", ripemd160HashTest.ToHexString(hexPrefix: true));

            // 4) IDENTITY + 5) MODEXP (this function uses both)
            var modExpTestBytes = await contract.testModExp(
                BigIntegerConverter.GetBytes(BigInteger.Parse("1212121323543453245345678346345737475734753745737774573475377734577", CultureInfo.InvariantCulture)),
                BigIntegerConverter.GetBytes(BigInteger.Parse("3", CultureInfo.InvariantCulture)),
                BigIntegerConverter.GetBytes(BigInteger.Parse("4345328123928357434573234217343477", CultureInfo.InvariantCulture)))
                                  .Call();

            var modExpTest = BigIntegerConverter.GetBigInteger(modExpTestBytes, false, modExpTestBytes.Length); // should be 0x856753145937825219130387866259147

            Assert.Equal(BigInteger.Parse("856753145937825219130387866259147", CultureInfo.InvariantCulture), modExpTest);

            // TODO: 6) Checking a pairing equation on bn128 curve
            // TODO: 7) Addition of bn128 curve
            // TODO: 8) Scalar multiplication of bn128 curve.
        }
예제 #21
0
        public override void Execute()
        {
            // Obtain the memory offset and size
            BigInteger offset = Stack.Pop();
            BigInteger size   = Stack.Pop();

            // Deduct our gas accordingly.
            GasState.Deduct(EVMDefinitions.GetWordCount(size) * GasDefinitions.GAS_SHA3_WORD);

            // Read our data to hash
            byte[] data = Memory.ReadBytes((long)offset, (int)size);

            // Hash our read data.
            byte[] hash = KeccakHash.ComputeHashBytes(data);

            // Push it onto our stack.
            Stack.Push(BigIntegerConverter.GetBigInteger(hash));
        }
예제 #22
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;
            }

            using (AutoObjectPool <Secp256k1> .Get(out var secp256k1))
            {
                // Allocate memory for the signature and call our sign function.
                Span <byte> signature = new byte[Secp256k1.UNSERIALIZED_SIGNATURE_SIZE];
                if (!secp256k1.SignRecoverable(signature, hash, UnmanagedKey.Span))
                {
                    var errMsg = "Unmanaged EC library failed to sign data. ";
                    if (IncludeKeyDataInExceptions)
                    {
                        errMsg += $"MessageHash: {hash.ToHexString()}, SecretKey: {UnmanagedKey.Span.ToHexString()}";
                    }

                    throw new Exception(errMsg);
                }

                // Now we serialize our signature
                Span <byte> serializedSignature = new byte[Secp256k1.SERIALIZED_SIGNATURE_SIZE];
                if (!secp256k1.RecoverableSignatureSerializeCompact(serializedSignature, out var recoveryId, signature))
                {
                    var errMsg = "Unmanaged EC library failed to serialize signature. ";
                    if (IncludeKeyDataInExceptions)
                    {
                        errMsg += $"Signature: {signature.ToHexString()}";
                    }

                    throw new Exception(errMsg);
                }

                // Obtain our components.
                Span <byte> r = serializedSignature.Slice(0, 32);
                Span <byte> s = serializedSignature.Slice(32, 32);

                // Return them.
                return((byte)recoveryId, BigIntegerConverter.GetBigInteger(r), BigIntegerConverter.GetBigInteger(s));
            }
        }
예제 #23
0
        /// <summary>
        /// Our default constructor, reads the opcode/operand information from the provided stream.
        /// </summary>
        public InstructionPush(MeadowEVM evm) : base(evm)
        {
            // This class handles multiple push operations (various sizes).
            // The opcodes are linear, so we can calculate the size of the push based off opcode.
            PushSize = (uint)(Opcode - InstructionOpcode.PUSH1) + 1;

            // Assert we are not at the end of the code.
            if (EVM.Code.Length < (ExecutionState.PC + PushSize))
            {
                throw new EVMException($"Cannot read {OpcodeDescriptor.Mnemonic}'s operand because the end of the stream was reached, or the bytes to read were unavailable.");
            }

            // Read our push data.
            byte[] pushBytes = EVM.Code.Slice((int)ExecutionState.PC, (int)PushSize).ToArray();

            // Parse our push data as a uint256.
            PushData = BigIntegerConverter.GetBigInteger(pushBytes);

            // Advance our program counter
            ExecutionState.PC += PushSize;
        }
예제 #24
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));
        }
예제 #25
0
        public override object ParseData(Memory <byte> data)
        {
            // If there is no data, it can be a singly addressed value, so we return the first enum definition member.
            if (data.Length == 0)
            {
                return(EnumDefinition.Members.Length > 0 ? EnumDefinition.Members[0].Name : "");
            }
            else
            {
                // Otherwise we parse our enum value from this data.
                BigInteger index = BigIntegerConverter.GetBigInteger(data.Span, false, SizeBytes);

                // Verify our enum index
                if (index >= EnumDefinition.Members.Length)
                {
                    throw new VarResolvingException("Could not resolve enum because value exceeded enum member count.");
                }

                // Our enum index is valid, return our enum member name
                return(string.Join('.', EnumDefinition.CanonicalName, EnumDefinition.Members[(int)index].Name));
            }
        }
예제 #26
0
        private static EVMExecutionResult Precompile_ModExp(MeadowEVM evm)
        {
            // Verify we're past the byzantium fork
            if (evm.Version < EthereumRelease.Byzantium)
            {
                return(new EVMExecutionResult(evm, null, true));
            }

            // Source: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-198.md

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

            // Extract our base length, exponent length, and mod length (in bytes)
            BigInteger baseLength     = BigIntegerConverter.GetBigInteger(messageData.Slice(0, EVMDefinitions.WORD_SIZE));
            BigInteger exponentLength = BigIntegerConverter.GetBigInteger(messageData.Slice(32, EVMDefinitions.WORD_SIZE));
            BigInteger modLength      = BigIntegerConverter.GetBigInteger(messageData.Slice(64, EVMDefinitions.WORD_SIZE));

            // GAS CALCULATION START: Exponent is leading the word of data, so we obtain a numeric representation of the first bytes.
            BigInteger exponentHead = BigIntegerConverter.GetBigInteger(messageData.Slice(96 + (int)baseLength, EVMDefinitions.WORD_SIZE));

            // Shift our head so we only have relevant bytes (they're leading the word, so we want to cut the tail off by bitshifting).
            exponentHead >>= (8 * (int)BigInteger.Max(32 - exponentLength, 0));

            // Count our bits in our exponent head.
            int exponentHeadBitCount = -1;

            while (exponentHead > 0)
            {
                exponentHead >>= 1;
                exponentHeadBitCount++;
            }

            // Obtain our adjusted exponent length.
            // 1) If exponent length <= 32, and exponent bits are 0, this is 0.
            // 2) If exponent length <= 32, then return the index of the highest bit in exponent.
            // 3) If exponent length > 32, then we return (8 * (exponent-length - 32)) + the index of the highest bit in the exponent.
            BigInteger adjustedExponentLength = Math.Max(exponentHeadBitCount, 0) + (8 * BigInteger.Max(exponentLength - 32, 0));

            adjustedExponentLength = BigInteger.Max(adjustedExponentLength, 1);

            // GAS CALCULATION END: Calculate the final gas cost from the length of our biggest parameter, times the exponent length, divided by our divisor.
            BigInteger biggestLength = BigInteger.Max(modLength, baseLength);
            BigInteger gasCost       = (Estimate_karatsuba_difficulty(biggestLength) * adjustedExponentLength) / GasDefinitions.GAS_PRECOMPILE_MODEXP_QUAD_DIVISOR;

            // Deduct our gas cost.
            evm.GasState.Deduct(gasCost);

            // Verify our base length.
            if (baseLength == 0)
            {
                return(new EVMExecutionResult(evm, new byte[(int)modLength], true));
            }

            // Verify our mod length.
            if (modLength == 0)
            {
                return(new EVMExecutionResult(evm, null, true));
            }

            // Obtain our base, exponent and mod
            Span <byte> memBase     = messageData.Slice(96, (int)baseLength);
            BigInteger  numBase     = BigIntegerConverter.GetBigInteger(memBase, false, memBase.Length);
            Span <byte> memExponent = messageData.Slice(96 + (int)baseLength, (int)exponentLength);
            BigInteger  numExponent = BigIntegerConverter.GetBigInteger(memExponent, false, memExponent.Length);
            Span <byte> memMod      = messageData.Slice(96 + (int)baseLength + (int)exponentLength, (int)modLength);
            BigInteger  numMod      = BigIntegerConverter.GetBigInteger(memMod, false, memMod.Length);

            // Verify our divisor isn't 0.
            if (numMod == 0)
            {
                return(new EVMExecutionResult(evm, new byte[(int)modLength], true));
            }

            // Obtain our modexp result, which, by definition, we know won't be bigger than our divisor, so we bind our length to the modulo divisor length.
            BigInteger numResult = BigInteger.ModPow(numBase, numExponent, numMod);

            byte[] result = BigIntegerConverter.GetBytes(numResult, (int)modLength);

            // Return our result
            return(new EVMExecutionResult(evm, result, true));
        }
예제 #27
0
 public Address(string address)
 {
     SetAddress(BigIntegerConverter.GetBigInteger(address.HexToBytes()));
 }
예제 #28
0
 public Address(Span <byte> address)
 {
     SetAddress(BigIntegerConverter.GetBigInteger(address));
 }
예제 #29
0
 public Address(byte[] address)
 {
     SetAddress(BigIntegerConverter.GetBigInteger(address));
 }
예제 #30
0
 public override object ParseData(Memory <byte> data)
 {
     // Read an signed integer of the specified size
     return(BigIntegerConverter.GetBigInteger(data.Span, true, SizeBytes));
 }