Nethereum.Util
NuGet:
Nethereum.Util| Source:src/Nethereum.Util/
Nethereum.Util
Core utilities for Ethereum development including Keccak-256 hashing, address checksum validation, and wei/ether unit conversions.
Overview
Nethereum.Util provides essential utility functions for Ethereum development. It includes the Keccak-256 (SHA-3) hashing implementation used throughout Ethereum, EIP-55 mixed-case checksum address handling, and comprehensive unit conversion between wei, gwei, ether, and other denominations.
Key Features
- Keccak-256 Hashing (SHA-3): Ethereum's primary cryptographic hash function
- Poseidon Hashing: ZK-proof-friendly hash function with Circom-compatible presets
- Hash Provider Abstraction:
IHashProviderinterface for pluggable hash implementations - Address Utilities: EIP-55 checksum address creation and validation
- Unit Conversion: Convert between wei, gwei, ether, and 20+ Ethereum unit denominations
- BigDecimal Support: High-precision decimal arithmetic for large value conversions
- Address Comparison: Case-insensitive address equality with checksum awareness
- Transaction Utilities: Helper methods for transaction handling
Installation
dotnet add package Nethereum.Util
Dependencies
- Nethereum.Hex - Hexadecimal encoding/decoding
- Nethereum.RLP - RLP (Recursive Length Prefix) encoding
Key Concepts
Keccak-256 (SHA-3)
Ethereum uses Keccak-256, the original SHA-3 submission before FIPS 202 standardization. This hash function is used for:
- Generating Ethereum addresses from public keys
- Creating function selectors for smart contracts
- Computing storage slot keys
- Generating message hashes for signing
EIP-55 Checksum Addresses
EIP-55 defines a backward-compatible mixed-case checksum format for Ethereum addresses:
- Uses Keccak-256 hash of the lowercase address
- Capitalizes hex digits at positions where the hash has a value ≥ 8
- Provides error detection without changing address format
- Example:
0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed
Unit Conversion
Ethereum uses wei as the smallest unit (10^-18 ether). Common denominations:
| Unit | Wei Value | Common Usage |
|---|---|---|
| Wei | 1 | Smart contract precision |
| Gwei | 10^9 | Gas prices |
| Ether | 10^18 | User-facing amounts |
The UnitConversion class handles conversions between 20+ denominations including wei, kwei, mwei, gwei, szabo, finney, ether, kether, and more.
Quick Start
using Nethereum.Util;
using System.Numerics;
// Keccak-256 hashing
var hasher = new Sha3Keccack();
string hash = hasher.CalculateHash("Hello, Ethereum!");
// Result: hex string of the keccak-256 hash
// Create checksum address
var addressUtil = new AddressUtil();
string checksumAddress = addressUtil.ConvertToChecksumAddress(
"0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed"
);
// Result: "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
// Convert ether to wei
var conversion = new UnitConversion();
BigInteger weiAmount = conversion.ToWei(1.5m, UnitConversion.EthUnit.Ether);
// Result: 1500000000000000000 wei
// Convert wei to ether
decimal etherAmount = conversion.FromWei(
BigInteger.Parse("1500000000000000000"),
UnitConversion.EthUnit.Ether
);
// Result: 1.5 ether
Usage Examples
Example 1: Keccak-256 Hashing
using Nethereum.Util;
using Nethereum.Hex.HexConvertors.Extensions;
var keccak = new Sha3Keccack();
// Hash a string (UTF-8 encoded)
string textHash = keccak.CalculateHash("Ethereum");
Console.WriteLine($"Hash: 0x{textHash}");
// Hash byte array
byte[] data = new byte[] { 0x01, 0x02, 0x03 };
byte[] hashBytes = keccak.CalculateHash(data);
string hashHex = hashBytes.ToHex();
// Hash from hex values (useful for contract data)
string combinedHash = keccak.CalculateHashFromHex(
"0x1234",
"0x5678",
"0xabcd"
);
// Hashes the concatenation: 0x12345678abcd
// Get hash as bytes (for further processing)
byte[] hashAsBytes = keccak.CalculateHashAsBytes("test");
Example 2: EIP-55 Checksum Addresses
using Nethereum.Util;
var addressUtil = new AddressUtil();
// Create checksum address from lowercase
string address1 = "0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed";
string checksum1 = addressUtil.ConvertToChecksumAddress(address1);
// Result: "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
// Create checksum address from uppercase
string address2 = "0xFB6916095CA1DF60BB79CE92CE3EA74C37C5D359";
string checksum2 = addressUtil.ConvertToChecksumAddress(address2);
// Result: "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"
// Verify if address is properly checksummed
bool isValid = addressUtil.IsChecksumAddress(
"0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
); // true
bool isInvalid = addressUtil.IsChecksumAddress(
"0x5aaeb6053F3E94C9b9A09f33669435E7Ef1BeAed" // wrong case
); // false
Example 3: Address Validation and Comparison
using Nethereum.Util;
var addressUtil = new AddressUtil();
// Validate address format (40 hex chars with 0x prefix)
bool valid = addressUtil.IsValidEthereumAddressHexFormat(
"0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
); // true
bool invalid = addressUtil.IsValidEthereumAddressHexFormat(
"0x5aAeb6053F3E" // too short
); // false
// Check address length
bool correctLength = addressUtil.IsValidAddressLength(
"0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
); // true
// Compare addresses (case-insensitive)
string addr1 = "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed";
string addr2 = "0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed";
bool same = addressUtil.AreAddressesTheSame(addr1, addr2); // true
// Using extension method
bool same2 = addr1.IsTheSameAddress(addr2); // true
Example 4: Empty Address Handling
using Nethereum.Util;
var addressUtil = new AddressUtil();
// Check if address is empty
bool isEmpty1 = addressUtil.IsAnEmptyAddress(null); // true
bool isEmpty2 = addressUtil.IsAnEmptyAddress(""); // true
bool isEmpty3 = addressUtil.IsAnEmptyAddress("0x0"); // true
bool isEmpty4 = addressUtil.IsAnEmptyAddress(" "); // true
// Get address or empty constant
string addr = null;
string result = addressUtil.AddressValueOrEmpty(addr);
// Result: "0x0" (AddressUtil.AddressEmptyAsHex)
// Check if not empty
bool notEmpty = addressUtil.IsNotAnEmptyAddress(
"0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
); // true
// Using extension methods
bool isEmpty = "0x0".IsAnEmptyAddress(); // true
bool notEmpty2 = "0x1234...".IsNotAnEmptyAddress(); // true
// Zero address constant
string zeroAddress = AddressUtil.ZERO_ADDRESS;
// "0x0000000000000000000000000000000000000000"
Example 5: Wei/Ether Conversions
From: Nethereum Playground Example 1014
using Nethereum.Util;
using System.Numerics;
var conversion = new UnitConversion();
// Convert ether to wei
BigInteger wei1 = conversion.ToWei(1m, UnitConversion.EthUnit.Ether);
// Result: 1000000000000000000
BigInteger wei2 = conversion.ToWei(0.001m, UnitConversion.EthUnit.Ether);
// Result: 1000000000000000 (0.001 ETH)
// Convert gwei to wei (for gas prices)
BigInteger gasWei = conversion.ToWei(
20,
UnitConversion.EthUnit.Gwei
);
// Result: 20000000000 (20 gwei)
// Convert wei to ether
decimal ether = conversion.FromWei(
BigInteger.Parse("1000000000000000000"),
UnitConversion.EthUnit.Ether
);
// Result: 1.0
// Convert wei to gwei
decimal gwei = conversion.FromWei(
BigInteger.Parse("20000000000"),
UnitConversion.EthUnit.Gwei
);
// Result: 20.0
// Using static accessor
BigInteger wei3 = UnitConversion.Convert.ToWei(
2.5m,
UnitConversion.EthUnit.Ether
);
// Result: 2500000000000000000
Example 6: High-Precision Conversions with BigDecimal
using Nethereum.Util;
using System.Numerics;
var conversion = new UnitConversion();
// Standard decimal has precision limits (29 digits)
// For very large or precise values, use BigDecimal
// Convert wei to BigDecimal (no precision loss)
BigDecimal precise = conversion.FromWeiToBigDecimal(
BigInteger.Parse("1111111111111111111111111111111"),
UnitConversion.EthUnit.Ether
);
// Result: 1111111111111.111111111111111111 (exact)
// Convert with more than 29 digits
BigDecimal veryLarge = conversion.FromWeiToBigDecimal(
BigInteger.Parse("1111111111111111111111111111111111111111111111111"),
UnitConversion.EthUnit.Tether
);
// Maintains full precision
// Convert BigDecimal back to wei
BigDecimal amount = new BigDecimal(1) / new BigDecimal(3);
BigInteger weiFromBigDecimal = conversion.ToWei(
amount,
UnitConversion.EthUnit.Ether
);
// Result: 333333333333333333 (1/3 ETH in wei)
Example 7: Working with Different Units
using Nethereum.Util;
using System.Numerics;
var conversion = new UnitConversion();
// Finney (milliether) - 0.001 ETH
BigInteger finneyWei = conversion.ToWei(
100,
UnitConversion.EthUnit.Finney
);
// Result: 100000000000000000 (0.1 ETH)
// Szabo (microether) - 0.000001 ETH
BigInteger szaboWei = conversion.ToWei(
1000000,
UnitConversion.EthUnit.Szabo
);
// Result: 1000000000000 (0.001 ETH)
// Kether (grand) - 1000 ETH
BigInteger ketherWei = conversion.ToWei(
1,
UnitConversion.EthUnit.Kether
);
// Result: 1000000000000000000000
// Convert using custom decimal places
BigInteger customWei = conversion.ToWei(
100m,
6 // USDC has 6 decimal places
);
// Result: 100000000
// Convert from custom decimal places
decimal customAmount = conversion.FromWei(
BigInteger.Parse("100000000"),
6 // USDC decimals
);
// Result: 100.0
Example 8: Unique Address Collections
using Nethereum.Util;
// UniqueAddressList uses case-insensitive address comparison
var addresses = new UniqueAddressList();
addresses.Add("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed");
addresses.Add("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed"); // Same address, different case
Console.WriteLine(addresses.Count); // 1 (duplicates ignored)
// Check if contains (case-insensitive)
bool contains = addresses.Contains(
"0x5AAEB6053F3E94C9B9A09F33669435E7EF1BEAED"
); // true
// Custom equality comparer for address dictionaries
var addressComparer = new AddressEqualityComparer();
var dict = new Dictionary<string, int>(addressComparer);
dict["0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"] = 100;
dict["0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed"] = 200; // Overwrites
Console.WriteLine(dict.Count); // 1
Example 9: Address Conversion and Padding
using Nethereum.Util;
var addressUtil = new AddressUtil();
// Convert short address to valid 20-byte address (pad with zeros)
string shortAddr = "0x1234";
string paddedAddr = addressUtil.ConvertToValid20ByteAddress(shortAddr);
// Result: "0x0000000000000000000000000000000000001234"
// Handle null addresses
string nullAddr = null;
string paddedNull = addressUtil.ConvertToValid20ByteAddress(nullAddr);
// Result: "0x0000000000000000000000000000000000000000"
// Convert byte array to checksum address
byte[] addressBytes = new byte[20] {
0x5a, 0xAe, 0xb6, 0x05, 0x3F, 0x3E, 0x94, 0xC9,
0xb9, 0xA0, 0x9f, 0x33, 0x66, 0x94, 0x35, 0xE7,
0xEf, 0x1B, 0xeA, 0xed
};
string checksumFromBytes = addressUtil.ConvertToChecksumAddress(addressBytes);
// Result: "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"
// Handles addresses longer than 20 bytes (takes last 20)
byte[] longAddress = new byte[32]; // e.g., from uint256 in Solidity
// ... populate longAddress ...
string fromLong = addressUtil.ConvertToChecksumAddress(longAddress);
// Uses last 20 bytes
API Reference
Sha3Keccack
Keccak-256 hashing implementation.
public class Sha3Keccack
{
public static Sha3Keccack Current { get; }
// Hash string (UTF-8)
public string CalculateHash(string value);
public byte[] CalculateHashAsBytes(string value);
// Hash bytes
public byte[] CalculateHash(byte[] value);
// Hash concatenated hex values
public string CalculateHashFromHex(params string[] hexValues);
}
AddressUtil
Ethereum address utilities and validation.
public class AddressUtil
{
public static AddressUtil Current { get; }
public const string AddressEmptyAsHex = "0x0";
public const string ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
// Checksum address creation
public string ConvertToChecksumAddress(string address);
public string ConvertToChecksumAddress(byte[] address);
// Validation
public bool IsValidEthereumAddressHexFormat(string address);
public bool IsValidAddressLength(string address);
public bool IsChecksumAddress(string address);
// Empty address checks
public bool IsAnEmptyAddress(string address);
public bool IsNotAnEmptyAddress(string address);
public string AddressValueOrEmpty(string address);
// Comparison
public bool AreAddressesTheSame(string address1, string address2);
public bool IsEmptyOrEqualsAddress(string address1, string candidate);
// Conversion
public string ConvertToValid20ByteAddress(string address);
}
UnitConversion
Convert between wei and various Ethereum denominations.
public class UnitConversion
{
public static UnitConversion Convert { get; }
public enum EthUnit
{
Wei, Kwei, Mwei, Gwei, Szabo, Finney, Ether,
Kether, Mether, Gether, Tether, /* and more */
}
// To Wei
public BigInteger ToWei(decimal amount, EthUnit fromUnit = EthUnit.Ether);
public BigInteger ToWei(BigDecimal amount, EthUnit fromUnit = EthUnit.Ether);
public BigInteger ToWei(decimal amount, int decimalPlacesFromUnit);
public BigInteger ToWeiFromUnit(BigDecimal amount, BigInteger fromUnit);
// From Wei (returns decimal, may lose precision > 29 digits)
public decimal FromWei(BigInteger value, EthUnit toUnit = EthUnit.Ether);
public decimal FromWei(BigInteger value, int decimalPlacesToUnit);
public decimal FromWei(BigInteger value, BigInteger toUnit);
// From Wei to BigDecimal (no precision loss)
public BigDecimal FromWeiToBigDecimal(BigInteger value, EthUnit toUnit = EthUnit.Ether);
public BigDecimal FromWeiToBigDecimal(BigInteger value, int decimalPlacesToUnit);
public BigDecimal FromWeiToBigDecimal(BigInteger value, BigInteger toUnit);
// Unit value helpers
public BigInteger GetEthUnitValue(EthUnit ethUnit);
public bool TryValidateUnitValue(BigInteger ethUnit);
}
Extension Methods
AddressExtensions
public static class AddressExtensions
{
// Address validation
public static bool IsValidEthereumAddressHexFormat(this string address);
public static bool IsChecksumAddress(this string address);
// Empty checks
public static bool IsAnEmptyAddress(this string address);
public static bool IsNotAnEmptyAddress(this string address);
public static string AddressValueOrEmpty(this string address);
// Comparison
public static bool IsTheSameAddress(this string address1, string address2);
// Conversion
public static string ConvertToEthereumChecksumAddress(this string address);
public static string ConvertToValid20ByteAddress(this string address);
}
BigDecimal
High-precision decimal arithmetic for large value conversions.
public class BigDecimal
{
public BigDecimal(BigInteger mantissa, int exponent);
public BigInteger Mantissa { get; }
public int Exponent { get; }
// Arithmetic operators
public static BigDecimal operator +(BigDecimal left, BigDecimal right);
public static BigDecimal operator -(BigDecimal left, BigDecimal right);
public static BigDecimal operator *(BigDecimal left, BigDecimal right);
public static BigDecimal operator /(BigDecimal left, BigDecimal right);
// Conversions
public static explicit operator decimal(BigDecimal value);
public static implicit operator BigDecimal(decimal value);
public BigInteger FloorToBigInteger();
}
PoseidonHasher
ZK-proof-friendly hash function with Circom-compatible parameter presets.
public class PoseidonHasher
{
public PoseidonHasher(); // Default (CircomT3)
public PoseidonHasher(PoseidonParameterPreset preset); // Specific preset
public PoseidonHasher(PoseidonParameters parameters); // Custom parameters
public BigInteger Hash(params BigInteger[] inputs); // Hash field elements
public byte[] HashToBytes(params BigInteger[] inputs); // Hash to 32 bytes
public BigInteger HashBytes(params byte[][] inputs); // Hash byte arrays
public BigInteger HashHex(params string[] hexInputs); // Hash hex strings
public byte[] HashBytesToBytes(params byte[][] inputs); // Bytes in, bytes out
}
public enum PoseidonParameterPreset
{
CircomT3, // State width 3, rate 2 (default)
CircomT6, // State width 6, rate 5
CircomT14, // State width 14, rate 13
CircomT16 // State width 16, rate 15
}
IHashProvider
Pluggable hash provider interface.
public interface IHashProvider
{
byte[] ComputeHash(byte[] data);
}
// Implementations:
// - Sha3KeccackHashProvider (Keccak-256)
// - PoseidonHashProvider (Poseidon with configurable preset)
Additional Utilities
DateTimeHelper
public static class DateTimeHelper
{
public static DateTime UnixTimeStampToDateTime(ulong unixTimeStamp);
public static ulong GetUnixTimeStampSeconds(DateTime dateTime);
}
ByteUtil
public static class ByteUtil
{
public static byte[] Merge(params byte[][] arrays);
public static bool AreEqual(byte[] a, byte[] b);
}
Poseidon Hashing (ZK-Proof Friendly)
Poseidon is a hash function designed for zero-knowledge proof circuits (zk-SNARKs). It operates over prime fields and is significantly more efficient inside circuits than Keccak-256.
using Nethereum.Util;
using System.Numerics;
// Default hasher (CircomT3 preset - 2 inputs)
var hasher = new PoseidonHasher();
// Hash field elements
BigInteger result = hasher.Hash(
BigInteger.Parse("1"),
BigInteger.Parse("2")
);
// Hash to bytes (32-byte big-endian output)
byte[] hashBytes = hasher.HashToBytes(
BigInteger.Parse("1"),
BigInteger.Parse("2")
);
// Hash raw byte arrays
byte[] input1 = new byte[] { 0x01, 0x02 };
byte[] input2 = new byte[] { 0x03, 0x04 };
BigInteger bytesResult = hasher.HashBytes(input1, input2);
// Hash hex strings
BigInteger hexResult = hasher.HashHex("0x1234", "0x5678");
// Use specific Circom preset
var hasherT6 = new PoseidonHasher(PoseidonParameterPreset.CircomT6); // up to 5 inputs
var hasherT14 = new PoseidonHasher(PoseidonParameterPreset.CircomT14); // up to 13 inputs
var hasherT16 = new PoseidonHasher(PoseidonParameterPreset.CircomT16); // up to 15 inputs
Available presets: CircomT3 (default, 2 inputs), CircomT6 (5 inputs), CircomT14 (13 inputs), CircomT16 (15 inputs).
Hash Provider Abstraction
IHashProvider provides a pluggable interface for different hash implementations:
using Nethereum.Util.HashProviders;
// Keccak-256 provider
IHashProvider keccakProvider = new Sha3KeccackHashProvider();
byte[] keccakHash = keccakProvider.ComputeHash(data);
// Poseidon provider
IHashProvider poseidonProvider = new PoseidonHashProvider();
byte[] poseidonHash = poseidonProvider.ComputeHash(data);
// Poseidon with specific preset
IHashProvider poseidonT6 = new PoseidonHashProvider(PoseidonParameterPreset.CircomT6);
Related Packages
Used By (Consumers)
Almost all Nethereum packages depend on Nethereum.Util:
- Nethereum.Signer - Uses Keccak for signing and address derivation
- Nethereum.RPC - Uses unit conversion for transaction values
- Nethereum.Contracts - Uses address validation and hashing
- Nethereum.Accounts - Uses address utilities and checksums
- Nethereum.Web3 - Uses all utility functions throughout
- Nethereum.ABI - Uses Keccak for function selector generation
Dependencies
- Nethereum.Hex - Hexadecimal encoding/decoding
- Nethereum.RLP - RLP encoding (for some utilities)
Important Notes
Decimal Precision Limits
When converting from wei to decimal using FromWei(), C# decimal type has a 29-digit limit. Values with more than 29 significant digits will be rounded:
// This rounds the least significant digits
decimal rounded = conversion.FromWei(
BigInteger.Parse("111111111111111111111111111111"), // 30 digits
18
);
// Use FromWeiToBigDecimal() for exact precision
For values requiring more than 29 digits of precision, use FromWeiToBigDecimal() which returns BigDecimal instead.
Keccak vs SHA3
Ethereum uses Keccak-256, which is different from the final NIST SHA-3 standard (FIPS 202). Do not use standard SHA-3 libraries for Ethereum - always use Nethereum's Sha3Keccack class.
Address Comparison Performance
Address comparison is case-insensitive and uses string comparison (not BigInteger). This is optimized for performance while maintaining correctness:
// Fast: string comparison
bool same = address1.IsTheSameAddress(address2);
// Both handle mixed-case addresses correctly
Unit Validation
Unit values must be powers of 10. The library validates this:
conversion.ToWeiFromUnit(100m, new BigInteger(10)); // OK
conversion.ToWeiFromUnit(100m, new BigInteger(7)); // Throws Exception