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); }
/// <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); }
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!"); } } }
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)); }
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."); } }
/// <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); }
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)); }
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)); }
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)); }
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)); }
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)); }
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; } }
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)); }
/// <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); }
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)); }
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); } }
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]); } } }
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); }
// 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)); }
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. }
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)); }
/// <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)); } }
/// <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; }
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)); }
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)); } }
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)); }
public Address(string address) { SetAddress(BigIntegerConverter.GetBigInteger(address.HexToBytes())); }
public Address(Span <byte> address) { SetAddress(BigIntegerConverter.GetBigInteger(address)); }
public Address(byte[] address) { SetAddress(BigIntegerConverter.GetBigInteger(address)); }
public override object ParseData(Memory <byte> data) { // Read an signed integer of the specified size return(BigIntegerConverter.GetBigInteger(data.Span, true, SizeBytes)); }