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)); }
static Converter() { BoolConverter.Initialize(); CharConverter.Initialize(); ByteConverter.Initialize(); SByteConverter.Initialize(); Int16Converter.Initialize(); UInt16Converter.Initialize(); Int32Converter.Initialize(); UInt32Converter.Initialize(); Int64Converter.Initialize(); UInt64Converter.Initialize(); SingleConverter.Initialize(); DoubleConverter.Initialize(); DecimalConverter.Initialize(); BigIntegerConverter.Initialize(); BytesConverter.Initialize(); CharsConverter.Initialize(); StringConverter.Initialize(); StringBuilderConverter.Initialize(); DateTimeConverter.Initialize(); TimeSpanConverter.Initialize(); GuidConverter.Initialize(); MemoryStreamConverter.Initialize(); StreamConverter.Initialize(); }
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."); } }
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); }
public override void Execute() { // Obtain our value and exponent BigInteger value = Stack.Pop(); BigInteger exponent = Stack.Pop(); // Calculate how much gas to deduct: the cost per exponent byte differs per Ethereum release byte[] exponentBytes = BigIntegerConverter.GetBytesWithoutLeadingZeros(exponent); BigInteger extraGasCost = exponentBytes.Length; if (Version < EthereumRelease.SpuriousDragon) { // Pre-Spurious Dragon extraGasCost *= GasDefinitions.GAS_EXP_BYTE; } else { // Spurious Dragon+ extraGasCost *= GasDefinitions.GAS_EXP_BYTE_SPURIOUS_DRAGON; } // Deduct our gas GasState.Deduct(extraGasCost); // Perform an exponent operation on the two unsigned words off of the top of the stack. BigInteger result = BigInteger.ModPow(value, exponent, EVMDefinitions.UINT256_MAX_VALUE + 1); // Push the result onto the stack. Stack.Push(result); }
/// <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); }
/// <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 UInt256(BigInteger value) : this(BigIntegerConverter.GetBytes(value).Reverse().ToArray()) { if (value < 0) { throw new ArgumentOutOfRangeException(); } }
public virtual void Sign(EthereumEcdsa localPrivateKey, EthereumEcdsa ephemeralPrivateKey, EthereumEcdsa receiverPublicKey, uint?chainID = null) { // Generate the shared secret using ECDH between our local private key and this remote public key byte[] ecdhKey = localPrivateKey.ComputeECDHKey(receiverPublicKey); // If our nonce is null, generate a new one Nonce = Nonce ?? RLPxSession.GenerateNonce(); // Verify the nonce is the correct length. if (Nonce.Length != RLPxSession.NONCE_SIZE) { // Throw an exception if an invalid nonce was provided. throw new ArgumentException($"Invalid size nonce provided for RLPx session when signing auth message. Should be {RLPxSession.NONCE_SIZE} bytes but was {Nonce?.Length}."); } // Obtain our transformed nonce data. byte[] transformedNonceData = GetTransformedNonce(ecdhKey); // Sign the transformed data. var signature = ephemeralPrivateKey.SignData(transformedNonceData); // We want our signature in r,s,v format. R = BigIntegerConverter.GetBytes(signature.r, 32); S = BigIntegerConverter.GetBytes(signature.s, 32); V = EthereumEcdsa.GetVFromRecoveryID(chainID, signature.RecoveryID); // Set our local public key and the public key hash. PublicKey = localPrivateKey.ToPublicKeyArray(false, true); }
private static byte[] HexToByteArray(string text) { if (text.Length % 2 != 0) { return(null); } return(BigIntegerConverter.ParseHex(text)); }
public void RoundTripMinValueTest() { var converter = new BigIntegerConverter(); var s = converter.ConvertToString((BigInteger)long.MinValue - 1, null, new MemberMapData(null)); var bi = converter.ConvertFromString(s, null, new MemberMapData(null)); Assert.AreEqual((BigInteger)long.MinValue - 1, bi); }
public void Test_roundtrip(NumberConversion numberConversion) { BigIntegerConverter converter = new BigIntegerConverter(numberConversion); TestConverter(int.MaxValue, (integer, bigInteger) => integer.Equals(bigInteger), converter); TestConverter(BigInteger.One, (integer, bigInteger) => integer.Equals(bigInteger), converter); TestConverter(BigInteger.Zero, (integer, bigInteger) => integer.Equals(bigInteger), converter); }
public void Unknown_not_supported(NumberConversion notSupportedConversion) { BigIntegerConverter converter = new BigIntegerConverter(notSupportedConversion); Assert.Throws <NotSupportedException>( () => TestConverter(int.MaxValue, (a, b) => a.Equals(b), converter)); Assert.Throws <NotSupportedException>( () => TestConverter(1L, (a, b) => a.Equals(b), converter)); }
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 void Regression_0xa00000() { BigIntegerConverter converter = new BigIntegerConverter(); JsonReader reader = new JsonTextReader(new StringReader("0xa00000")); reader.ReadAsString(); BigInteger result = converter.ReadJson(reader, typeof(BigInteger), BigInteger.Zero, false, JsonSerializer.CreateDefault()); Assert.AreEqual(BigInteger.Parse("10485760"), result); }
public void Push(BigInteger obj) { // Verify we aren't reaching our maximum stack size. if (Count >= MAX_STACK_SIZE) { throw new EVMException($"Stack has overflowed past the maximum size of {MAX_STACK_SIZE} entries."); } // Push the object to the top of the stack. _internalStack.Add(BigIntegerConverter.GetBytes(obj)); }
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 async Task ModExpTest() { // Test the modexp precompile. var gas = await _precompiles.testModExp( BigIntegerConverter.GetBytes(BigInteger.Parse("1212121323543453245345678346345737475734753745737774573475377734577", CultureInfo.InvariantCulture)), BigIntegerConverter.GetBytes(BigInteger.Parse("3", CultureInfo.InvariantCulture)), BigIntegerConverter.GetBytes(BigInteger.Parse("4345328123928357434573234217343477", CultureInfo.InvariantCulture))) .EstimateGas(); Assert.AreEqual(29900, gas); }
public async Task EcRecoverTest() { var gas = await _precompiles.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))) .EstimateGas(); Assert.AreEqual(32437, gas); }
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)); }
public async Task EcRecoverTest() { 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.AreEqual("0x75c8aa4b12bc52c1f1860bc4e8af981d6542cccd", ecRecoverTest.GetHexString(hexPrefix: true)); }
// Type handling public static RLPByteArray FromInteger(BigInteger bigInteger, int byteCount = 32, bool removeLeadingZeros = false) { if (!removeLeadingZeros) { return(new RLPByteArray(BigIntegerConverter.GetBytes(bigInteger, byteCount))); } else { return(new RLPByteArray(BigIntegerConverter.GetBytesWithoutLeadingZeros(bigInteger, byteCount))); } }
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)); }
// Test of signing and verifying using test vectors // http://ed25519.cr.yp.to/python/sign.input internal static void Test() { using (var reader = new System.IO.StreamReader(@"sign.input")) { int skip = 0; int count = 0; while (true) { string line = reader.ReadLine(); if (line == null) { break; } count++; if (count <= skip) { continue; } System.Diagnostics.Debug.WriteLine("Line {0}", count); string[] w = line.Split(':'); byte[][] b = w.Select(s => BigIntegerConverter.ParseHex(s)).ToArray(); byte[] privateKey = new byte[32]; Buffer.BlockCopy(b[0], 0, privateKey, 0, 32); byte[] publicKey = b[1]; byte[] message = b[2]; byte[] signature = new byte[64]; Buffer.BlockCopy(b[3], 0, signature, 0, 64); CurveEd25519 curve = new CurveEd25519(); byte[] sig; if (!curve.Sign(privateKey, message, out sig)) { throw new Exception("signing failed"); } if (sig.Length != signature.Length) { throw new Exception("invalid sign length"); } for (int i = 0; i < signature.Length; ++i) { if (sig[i] != signature[i]) { throw new Exception("signs doesn't match"); } } if (!curve.Verify(publicKey, signature, message)) { throw new Exception("verification failed"); } } } }
public void LeadingBytesNegative() { BigInteger bigInt = -1; byte[] result = BigIntegerConverter.GetBytes(bigInt); for (int i = 0; i < result.Length; i++) { Assert.Equal(0xFF, result[i]); } Assert.Equal(0x20, result.Length); }
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); }