/// <summary> /// Concats all the event metadata signatures and type names and hashes them. /// </summary> public static byte[] GetHash(List <GeneratedEventMetadata> items) { int bufferSize = 0; for (var i = 0; i < items.Count; i++) { bufferSize += items[i].ClrTypeFullName.Length + items[i].EventSignatureHash.Length + 2; } Span <char> inputData = stackalloc char[bufferSize]; Span <char> inputDataCursor = inputData; for (var i = 0; i < items.Count; i++) { items[i].ClrTypeFullName.AsSpan().CopyTo(inputDataCursor); inputDataCursor = inputDataCursor.Slice(items[i].ClrTypeFullName.Length); items[i].EventSignatureHash.AsSpan().CopyTo(inputDataCursor); inputDataCursor = inputDataCursor.Slice(items[i].EventSignatureHash.Length); items[i].IndexedArgsCounts.ToString("00", CultureInfo.InvariantCulture).AsSpan().CopyTo(inputDataCursor); inputDataCursor = inputDataCursor.Slice(2); } var hashBuffer = new byte[32]; KeccakHash.ComputeHash(MemoryMarshal.AsBytes(inputData), hashBuffer); return(hashBuffer); }
/// <summary> /// Given a key, deletes the key-value entry from the trie. /// </summary> /// <param name="key">The key for which we'd like to remove the key-value entry.</param> public override void Remove(Memory <byte> key) { // Use the hash of our provided key as a key. Memory <byte> hash = new byte[KeccakHash.HASH_SIZE]; KeccakHash.ComputeHash(key.Span, hash.Span); base.Remove(hash); }
/// <summary> /// Creates the 4 byte function selector from a function signature string /// </summary> /// <param name="functionSignature">Function signature, ex: "baz(uint32,bool)"</param> /// <param name="hexPrefix">True to prepend the hex string with "0x"</param> /// <returns>8 character lowercase hex string (from first 4 bytes of the sha3 hash of utf8 encoded function signature)</returns> public static string GetMethodIDHex(string functionSignature, bool hexPrefix = false) { var bytes = UTF8.GetBytes(functionSignature); var hash = KeccakHash.ComputeHash(bytes).Slice(0, 4); string funcSignature = HexUtil.GetHexFromBytes(hash, hexPrefix: hexPrefix); return(funcSignature); }
public static string GetSignatureHash(this Abi abi, bool hexPrefix = false) { string str = GetFullSignature(abi); var bytes = UTF8.GetBytes(str); var hash = KeccakHash.ComputeHash(bytes).ToHexString(hexPrefix); return(hash); }
public static ReadOnlyMemory <byte> GetMethodID(string functionSignature) { var bytes = UTF8.GetBytes(functionSignature); var mem = new Memory <byte>(new byte[4]); KeccakHash.ComputeHash(bytes).Slice(0, 4).CopyTo(mem.Span); return(mem); }
public static Address MakeContractAddress(Address sender, BigInteger nonce) { // Create an RLP list with the address and nonce RLPList list = new RLPList(RLP.FromInteger(sender, ADDRESS_SIZE), RLP.FromInteger(nonce)); var hash = KeccakHash.ComputeHash(RLP.Encode(list)).Slice(EVMDefinitions.WORD_SIZE - ADDRESS_SIZE); return(new Address(hash)); }
/// <summary> /// Given a key, sets the corresponding value in our trie. /// </summary> /// <param name="key">The key for which to set the corresponding value for.</param> /// <param name="value">The value to store in the trie for the provided key.</param> public override void Set(Memory <byte> key, byte[] value) { // Use the hash of our provided key as a key. Memory <byte> hash = new byte[KeccakHash.HASH_SIZE]; KeccakHash.ComputeHash(key.Span, hash.Span); base.Set(hash, value); // Set our hash->key lookup in the database Database.Set(hash.ToArray(), key.ToArray()); }
/// <summary> /// Returns a Keccak256 hash of the given message, using the prefix from eth_sign: "\u0019Ethereum Signed Message:\n{message.Length}". /// </summary> public static byte[] HashPersonalMessage(Span <byte> messageBytes) { const string PREFIX = "\u0019Ethereum Signed Message:\n"; string prefixedMessage = PREFIX + messageBytes.Length.ToString(CultureInfo.InvariantCulture); byte[] buffer = new byte[StringUtil.UTF8.GetByteCount(prefixedMessage) + messageBytes.Length]; StringUtil.UTF8.GetBytes(prefixedMessage, 0, prefixedMessage.Length, buffer, 0); messageBytes.CopyTo(buffer.AsSpan(prefixedMessage.Length)); var resultBuffer = new byte[KeccakHash.HASH_SIZE]; KeccakHash.ComputeHash(buffer, resultBuffer); return(resultBuffer); }
private void AssertHash512(string expectedHash, byte[] data, bool matches = true) { byte[] hash = new byte[64]; KeccakHash.ComputeHash(data, hash); string hashString = hash.ToHexString(); if (matches) { Assert.Equal(expectedHash, hashString, true); } else { Assert.NotEqual <string>(expectedHash, hashString, StringComparer.InvariantCultureIgnoreCase); } }
/// <summary> /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md /// </summary> public string ToStringWithChecksum() { Span <uint> buffer = stackalloc uint[10]; buffer[0] = _p1; buffer[1] = _p2; buffer[2] = _p3; buffer[3] = _p4; buffer[4] = _p5; Span <byte> addrBytes = MemoryMarshal.AsBytes(buffer); Span <char> addrHexBytesPrefixed = stackalloc char[42]; addrHexBytesPrefixed[0] = '0'; addrHexBytesPrefixed[1] = 'x'; Span <char> addrHexChars = addrHexBytesPrefixed.Slice(2); HexUtil.WriteBytesIntoHexString(addrBytes.Slice(0, 20), addrHexChars); for (var i = 0; i < 40; i++) { addrBytes[i] = (byte)addrHexChars[i]; } KeccakHash.ComputeHash(addrBytes.Slice(0, 40), addrBytes.Slice(0, 32)); for (var i = 0; i < 40; i++) { char inspectChar = addrHexChars[i]; // skip check if character is a number if (inspectChar > 64) { // get character casing flag var c = i % 2 == 0 ? addrBytes[i / 2] >> 4 : addrBytes[i / 2] & 0x0F; bool upperFlag = c >= 8; if (upperFlag) { addrHexChars[i] = (char)(inspectChar - 32); } } } return(addrHexBytesPrefixed.ToString()); }
private static void Keccak512(Span <byte> message, Span <byte> output) { KeccakHash.ComputeHash(message, output); }
/// <summary> /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md /// </summary> public static bool ValidChecksum(string addressHexStr) { bool foundUpper = false, foundLower = false; foreach (var c in addressHexStr) { foundUpper |= c > 64 && c < 71; foundLower |= c > 96 && c < 103; if (foundUpper && foundLower) { break; } } if (!(foundUpper && foundLower)) { return(true); } // get lowercase utf16 buffer Span <byte> addr = stackalloc byte[80]; var addrSpan = addressHexStr.AsSpan(); if (addrSpan[0] == '0' && addrSpan[1] == 'x') { addrSpan = addrSpan.Slice(2); } if (addrSpan.Length != 40) { throw new ArgumentException("Address hex string should be 40 chars long, or 42 with a 0x prefix, was given " + addressHexStr.Length, nameof(addressHexStr)); } addrSpan.ToLowerInvariant(MemoryMarshal.Cast <byte, char>(addr)); // inline buffer conversion from utf16 to ascii for (var i = 0; i < 40; i++) { addr[i] = addr[i * 2]; } // get hash of ascii hex KeccakHash.ComputeHash(addr.Slice(0, 40), addr.Slice(0, 32)); for (var i = 0; i < 40; i++) { char inspectChar = addrSpan[i]; // skip check if character is a number if (inspectChar > 64) { // get character casing flag var c = i % 2 == 0 ? addr[i / 2] >> 4 : addr[i / 2] & 0x0F; bool upperFlag = c >= 8; // verify character is uppercase, otherwise bad checksum if (upperFlag && inspectChar > 96) { return(false); } // verify character is lowercase else if (!upperFlag && inspectChar < 97) { return(false); } } } return(true); }
private static Span <byte> Keccak256(Span <byte> message) { return(KeccakHash.ComputeHash(message)); }
private static Span <byte> Keccak512(Span <byte> message) { byte[] output = new byte[0x40]; KeccakHash.ComputeHash(message, output); return(output); }
protected override string GenerateClassDef() { List <string> eventTypes = new List <string>(); foreach (var item in _contract.Abi) { if (item.Type == AbiType.Event) { eventTypes.Add($"typeof({_namespace}.{_contractName}.{item.Name})"); } } string eventTypesString = string.Empty; if (eventTypes.Any()) { eventTypesString = ", " + string.Join(", ", eventTypes); } string bytecodeHash = KeccakHash.ComputeHash(_contract.Evm.Bytecode.ObjectBytes).ToHexString(); string bytecodeDeployedHash = KeccakHash.ComputeHash(_contract.Evm.DeployedBytecode.ObjectBytes).ToHexString(); string devDocJson = JsonConvert.SerializeObject(_contract.Devdoc).Replace("\"", "\"\"", StringComparison.Ordinal); string userDocJson = JsonConvert.SerializeObject(_contract.Userdoc).Replace("\"", "\"\"", StringComparison.Ordinal); string extraSummaryDoc = GetContractSummaryXmlDoc(); return($@" /// <summary>{extraSummaryDoc}</summary> [{typeof(SolidityContractAttribute).FullName}(typeof({_contractName}), CONTRACT_SOL_FILE, CONTRACT_NAME, CONTRACT_BYTECODE_HASH, CONTRACT_BYTECODE_DEPLOYED_HASH)] public class {_contractName} : {typeof(BaseContract).FullName} {{ public static Lazy<byte[]> BYTECODE_BYTES = new Lazy<byte[]>(() => {typeof(HexUtil).FullName}.HexToBytes(GeneratedSolcData<{_contractName}>.Default.GetSolcBytecodeInfo(CONTRACT_SOL_FILE, CONTRACT_NAME).Bytecode)); public const string CONTRACT_SOL_FILE = ""{_contractSolFileName}""; public const string CONTRACT_NAME = ""{_contractName}""; public const string CONTRACT_BYTECODE_HASH = ""{bytecodeHash}""; public const string CONTRACT_BYTECODE_DEPLOYED_HASH = ""{bytecodeDeployedHash}""; protected override string ContractSolFilePath => CONTRACT_SOL_FILE; protected override string ContractName => CONTRACT_NAME; protected override string ContractBytecodeHash => CONTRACT_BYTECODE_HASH; protected override string ContractBytecodeDeployedHash => CONTRACT_BYTECODE_DEPLOYED_HASH; private {_contractName}({JsonRpcClientType} rpcClient, {typeof(Address).FullName} address, {typeof(Address).FullName} defaultFromAccount) : base(rpcClient, address, defaultFromAccount) {{ {typeof(EventLogUtil).FullName}.{nameof(EventLogUtil.RegisterDeployedContractEventTypes)}( address.GetHexString(hexPrefix: true) {eventTypesString} ); }} public static async Task<{_contractName}> At({JsonRpcClientType} rpcClient, {typeof(Address).FullName} address, {typeof(Address).FullName}? defaultFromAccount = null) {{ defaultFromAccount = defaultFromAccount ?? (await rpcClient.Accounts())[0]; return new {_contractName}(rpcClient, address, defaultFromAccount.Value); }} {GenerateClassMembers()} }} "); }
public void SigningTest() { using (var secp256k1 = new Secp256k1()) { Span <byte> signature = new byte[Secp256k1.UNSERIALIZED_SIGNATURE_SIZE]; Span <byte> messageHash = 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 }; Span <byte> secretKey = "e815acba8fcf085a0b4141060c13b8017a08da37f2eb1d6a5416adbb621560ef".HexToBytes(); bool result = secp256k1.SignRecoverable(signature, messageHash, secretKey); Assert.True(result); // Recover the public key Span <byte> publicKeyOutput = new byte[Secp256k1.PUBKEY_LENGTH]; result = secp256k1.Recover(publicKeyOutput, signature, messageHash); Assert.True(result); // Serialize the public key Span <byte> serializedKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH]; result = secp256k1.PublicKeySerialize(serializedKey, publicKeyOutput); Assert.True(result); // Slice off any prefix. serializedKey = serializedKey.Slice(serializedKey.Length - Secp256k1.PUBKEY_LENGTH); Assert.Equal("0x3a2361270fb1bdd220a2fa0f187cc6f85079043a56fb6a968dfad7d7032b07b01213e80ecd4fb41f1500f94698b1117bc9f3335bde5efbb1330271afc6e85e92", serializedKey.ToHexString(true), true); // Verify we could obtain the correct sender from the signature. Span <byte> senderAddress = KeccakHash.ComputeHash(serializedKey).Slice(KeccakHash.HASH_SIZE - Address.ADDRESS_SIZE); Assert.Equal("0x75c8aa4b12bc52c1f1860bc4e8af981d6542cccd", senderAddress.ToArray().ToHexString(true), true); // Verify it works with variables generated from our managed code. BigInteger ecdsa_r = BigInteger.Parse("68932463183462156574914988273446447389145511361487771160486080715355143414637", CultureInfo.InvariantCulture); BigInteger ecdsa_s = BigInteger.Parse("47416572686988136438359045243120473513988610648720291068939984598262749281683", CultureInfo.InvariantCulture); byte recoveryId = 1; byte[] ecdsa_r_bytes = BigIntegerConverter.GetBytes(ecdsa_r); byte[] ecdsa_s_bytes = BigIntegerConverter.GetBytes(ecdsa_s); signature = ecdsa_r_bytes.Concat(ecdsa_s_bytes); // Allocate memory for the signature and create a serialized-format signature to deserialize into our native format (platform dependent, hence why we do this). Span <byte> serializedSignature = ecdsa_r_bytes.Concat(ecdsa_s_bytes); signature = new byte[Secp256k1.UNSERIALIZED_SIGNATURE_SIZE]; result = secp256k1.RecoverableSignatureParseCompact(signature, serializedSignature, recoveryId); if (!result) { throw new Exception("Unmanaged EC library failed to parse serialized signature."); } // Recover the public key publicKeyOutput = new byte[Secp256k1.PUBKEY_LENGTH]; result = secp256k1.Recover(publicKeyOutput, signature, messageHash); Assert.True(result); // Serialize the public key serializedKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH]; result = secp256k1.PublicKeySerialize(serializedKey, publicKeyOutput); Assert.True(result); // Slice off any prefix. serializedKey = serializedKey.Slice(serializedKey.Length - Secp256k1.PUBKEY_LENGTH); // Assert our key Assert.Equal("0x3a2361270fb1bdd220a2fa0f187cc6f85079043a56fb6a968dfad7d7032b07b01213e80ecd4fb41f1500f94698b1117bc9f3335bde5efbb1330271afc6e85e92", serializedKey.ToHexString(true), true); //senderAddress = EthereumEcdsa.Recover(messageHash.ToArray(), recoveryId, ecdsa_r, ecdsa_s).GetPublicKeyHash(); //senderAddress = senderAddress.Slice(KeccakHash.HASH_SIZE - Address.ADDRESS_SIZE); //Assert.Equal("0x75c8aa4b12bc52c1f1860bc4e8af981d6542cccd", senderAddress.ToArray().ToHexString(true), true); } }
private static void Keccak256(Span <byte> message, Span <byte> output) { KeccakHash.ComputeHash(message, output, 0x20); }
public static void GetMethodID(Span <byte> buffer, string functionSignature) { var bytes = UTF8.GetBytes(functionSignature); KeccakHash.ComputeHash(bytes).Slice(0, 4).CopyTo(buffer); }
static void KeccakHashString(string str, Span <byte> output) { var strBytes = StringUtil.UTF8.GetBytes(str); KeccakHash.ComputeHash(strBytes, output); }
/// <summary> /// Performs the NIST SP 800-56 Concatenation Key Derivation Function ("KDF") to derive a key of the specified desired length from a base key of arbitrary length. /// </summary> /// <param name="key">The base key to derive another key from.</param> /// <param name="desiredKeyLength">The desired key length of the resulting derived key.</param> /// <param name="hashType">The type of hash algorithm to use in the key derivation process.</param> /// <returns>Returns the key derived from the provided base key and hash algorithm.</returns> private static byte[] DeriveKeyKDF(byte[] key, int desiredKeyLength, KDFHashAlgorithm hashType = KDFHashAlgorithm.SHA256) { // References: // https://csrc.nist.gov/CSRC/media/Publications/sp/800-56a/archive/2006-05-03/documents/sp800-56-draft-jul2005.pdf // Define our block size and hash size int hashSize; if (hashType == KDFHashAlgorithm.SHA256) { hashSize = 32; } else if (hashType == KDFHashAlgorithm.Keccak256) { hashSize = KeccakHash.HASH_SIZE; } else { throw new NotImplementedException(); } // Determine the amount of hashes required to generate a key of the desired length (ceiling by adding one less bit than needed to round up 1) int hashRounds = (desiredKeyLength + (hashSize - 1)) / hashSize; // Create a memory space to store all hashes for each round. The final key will slice from the start of this for all bytes it needs. byte[] aggregateHashData = new byte[hashRounds * hashSize]; Span <byte> aggregateHashMemory = aggregateHashData; int aggregateHashOffset = 0; // Loop for each hash round to compute. for (int i = 0; i <= hashRounds; i++) { // Get the iteration count (starting from 1) byte[] counterData = BitConverter.GetBytes(i + 1); if (BitConverter.IsLittleEndian) { Array.Reverse(counterData); } // Get the data to hash in a single buffer byte[] dataToHash = counterData.Concat(key); // Determine what provider to use to hash the buffer. if (hashType == KDFHashAlgorithm.SHA256) { // Calculate the SHA256 hash for this round. byte[] hashResult = _sha256.ComputeHash(dataToHash); // Copy it into our all hashes buffer. hashResult.CopyTo(aggregateHashMemory.Slice(aggregateHashOffset, hashSize)); } else if (hashType == KDFHashAlgorithm.Keccak256) { // Calculate the Keccak256 hash for this round. KeccakHash.ComputeHash(dataToHash, aggregateHashMemory.Slice(aggregateHashOffset, hashSize)); } else { throw new NotImplementedException(); } // Advance our offset aggregateHashOffset += hashSize; // If our offset is passed our required key length, we can stop early if (aggregateHashOffset >= desiredKeyLength) { break; } } // Slice off only the desired data return(aggregateHashMemory.Slice(0, desiredKeyLength).ToArray()); }
public ResxWriter GenerateResx() { var resxWriter = new ResxWriter(); resxWriter.AddEntry("SolidityCompilerVersion", _solidityCompilerVersion); // Make paths relative var solSourceContent = _solSourceContent.ToDictionary(d => Util.GetRelativeFilePath(_solSourceDir, d.Key), d => d.Value); // Scan ast json for absolute paths and make them relative foreach (var absPathToken in _solcOutput.JObject["sources"].SelectTokens("$..absolutePath").OfType <JValue>()) { var absPath = Util.GetRelativeFilePath(_solSourceDir, absPathToken.Value <string>()); absPathToken.Value = absPath; } var solcSourceInfos = new List <SolcSourceInfo>(); foreach (JProperty item in _solcOutput.JObject["sources"]) { var fileName = Util.GetRelativeFilePath(_solSourceDir, item.Name); var id = item.Value.Value <int>("id"); var astObj = (JObject)item.Value["ast"]; var sourceContent = solSourceContent[fileName]; var sourceInfo = new SolcSourceInfo { AstJson = astObj, FileName = fileName, ID = id, SourceCode = sourceContent }; solcSourceInfos.Add(sourceInfo); } var solcSourceInfosJson = JsonConvert.SerializeObject(solcSourceInfos, Formatting.Indented); resxWriter.AddEntry("SourcesList", solcSourceInfosJson); var solcBytecodeInfos = new List <SolcBytecodeInfo>(); foreach (JProperty solFile in _solcOutput.JObject["contracts"]) { foreach (JProperty solContract in solFile.Value) { var fileName = Util.GetRelativeFilePath(_solSourceDir, solFile.Name); var contractName = solContract.Name; var bytecodeObj = solContract.Value["evm"]["bytecode"]; var deployedBytecodeObj = solContract.Value["evm"]["deployedBytecode"]; var sourceMap = bytecodeObj.Value <string>("sourceMap"); var sourceMapDeployed = deployedBytecodeObj.Value <string>("sourceMap"); var opcodes = bytecodeObj.Value <string>("opcodes"); var opcodesDeployed = deployedBytecodeObj.Value <string>("opcodes"); var bytecode = bytecodeObj.Value <string>("object"); var bytecodeDeployed = deployedBytecodeObj.Value <string>("object"); var bytecodeHash = KeccakHash.ComputeHash(HexUtil.HexToBytes(bytecode)).ToHexString(); var bytecodeDeployedHash = KeccakHash.ComputeHash(HexUtil.HexToBytes(bytecodeDeployed)).ToHexString(); solcBytecodeInfos.Add(new SolcBytecodeInfo { FilePath = fileName, ContractName = contractName, SourceMap = sourceMap, Opcodes = opcodes, SourceMapDeployed = sourceMapDeployed, OpcodesDeployed = opcodesDeployed, Bytecode = bytecode, BytecodeDeployed = bytecodeDeployed, BytecodeHash = bytecodeHash, BytecodeDeployedHash = bytecodeDeployedHash }); } } var solcBytecodeInfosJson = JsonConvert.SerializeObject(solcBytecodeInfos, Formatting.Indented); resxWriter.AddEntry("ByteCodeData", solcBytecodeInfosJson); var contractAbis = _solcOutput.ContractsFlattened.ToDictionary(c => c.SolFile + "/" + c.ContractName, c => c.Contract.Abi); var contractAbisJson = JsonConvert.SerializeObject(contractAbis, Formatting.Indented); resxWriter.AddEntry("ContractAbiJson", contractAbisJson); return(resxWriter); }