![]() |
VOOZH | about |
dotnet add package Nethereum.Signer --version 6.1.0
NuGet\Install-Package Nethereum.Signer -Version 6.1.0
<PackageReference Include="Nethereum.Signer" Version="6.1.0" />
<PackageVersion Include="Nethereum.Signer" Version="6.1.0" />Directory.Packages.props
<PackageReference Include="Nethereum.Signer" />Project file
paket add Nethereum.Signer --version 6.1.0
#r "nuget: Nethereum.Signer, 6.1.0"
#:package Nethereum.Signer@6.1.0
#addin nuget:?package=Nethereum.Signer&version=6.1.0Install as a Cake Addin
#tool nuget:?package=Nethereum.Signer&version=6.1.0Install as a Cake Tool
Cryptographic signing library for Ethereum transactions, messages, and typed data using secp256k1 elliptic curve cryptography.
Nethereum.Signer is the core cryptographic engine for all signing operations in Nethereum. It provides secure key generation, transaction signing (Legacy, EIP-155, EIP-1559, EIP-7702), message signing, and signature recovery using the secp256k1 elliptic curve (same as Bitcoin and Ethereum).
Key Features:
dotnet add package Nethereum.Signer
Or via Package Manager Console:
Install-Package Nethereum.Signer
External:
Nethereum:
Ethereum uses the secp256k1 elliptic curve (same as Bitcoin) for public-key cryptography:
Ethereum signatures consist of three components:
Combined signature format: 0x + r (64 hex) + s (64 hex) + v (2 hex) = 132 hex characters
Ethereum messages are prefixed before signing to prevent signing malicious transactions:
"\x19Ethereum Signed Message:\n" + message.length + message
This prefix ensures that a signed message cannot be a valid transaction.
using Nethereum.Signer;
using Nethereum.Hex.HexConvertors.Extensions;
// Generate new key pair
var key = EthECKey.GenerateKey();
string privateKey = key.GetPrivateKey();
string address = key.GetPublicAddress();
Console.WriteLine($"Address: {address}");
Console.WriteLine($"Private Key: {privateKey}");
// Sign a message
var signer = new EthereumMessageSigner();
string message = "Hello Ethereum!";
string signature = signer.EncodeUTF8AndSign(message, key);
// Recover address from signature
string recoveredAddress = signer.EncodeUTF8AndEcRecover(message, signature);
Console.WriteLine($"Recovered: {recoveredAddress}");
using Nethereum.Signer;
using Nethereum.Hex.HexConvertors.Extensions;
// Generate new random key pair
var key = EthECKey.GenerateKey();
// Get private key (KEEP SECRET!)
string privateKeyHex = key.GetPrivateKey();
byte[] privateKeyBytes = key.GetPrivateKeyAsBytes();
// Get public key
byte[] publicKey = key.GetPubKey(); // Uncompressed (65 bytes with 0x04 prefix)
byte[] publicKeyCompressed = key.GetPubKeyCompressed(); // Compressed (33 bytes)
// Get Ethereum address
string address = key.GetPublicAddress();
Console.WriteLine($"Address: {address}"); // 0x...
// Recreate key from existing private key
var existingKey = new EthECKey("0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7");
Console.WriteLine($"Restored address: {existingKey.GetPublicAddress()}");
using Nethereum.Signer;
using Nethereum.Hex.HexConvertors.Extensions;
// Example from EthereumMessageSignerTests.cs
var privateKey = "0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7";
var address = "0x12890D2cce102216644c59daE5baed380d84830c";
var message = "Hello from Nethereum";
var signer = new EthereumMessageSigner();
var key = new EthECKey(privateKey);
// Sign message (automatically adds Ethereum prefix and hashes)
string signature = signer.EncodeUTF8AndSign(message, key);
// Expected signature from test
var expectedSignature = "0xe20e42c13fbf52a5d65229f4dd1dcd3255691166ce2852456631baf4836afd4630480609a76794ee3018c5514ee3a0592031cf2490e7356dffe4ed202606f5181c";
Console.WriteLine($"Signature: {signature}");
Console.WriteLine($"Match: {signature == expectedSignature}");
// Recover signer's address from signature
string recoveredAddress = signer.EncodeUTF8AndEcRecover(message, signature);
Console.WriteLine($"Recovered address: {recoveredAddress}");
Console.WriteLine($"Match original: {address.Equals(recoveredAddress, StringComparison.OrdinalIgnoreCase)}");
using Nethereum.Signer;
using Nethereum.Util;
// Verify signature from MyEtherWallet (from EthereumMessageSignerTests.cs)
var address = "0xe651c5051ce42241765bbb24655a791ff0ec8d13";
var message = "wee test message 18/09/2017 02:55PM";
var mewSignature = "0xf5ac62a395216a84bd595069f1bb79f1ee08a15f07bb9d9349b3b185e69b20c60061dbe5cdbe7b4ed8d8fea707972f03c21dda80d99efde3d96b42c91b2703211b";
var signer = new EthereumMessageSigner();
string recoveredAddress = signer.EncodeUTF8AndEcRecover(message, mewSignature);
bool isValid = address.IsTheSameAddress(recoveredAddress);
Console.WriteLine($"MEW signature valid: {isValid}");
Console.WriteLine($"Expected: {address}");
Console.WriteLine($"Recovered: {recoveredAddress}");
// This works with signatures from:
// - MetaMask
// - MyEtherWallet (MEW)
// - Ledger
// - Trezor
// - Any wallet following EIP-191 standard
using Nethereum.Signer;
using Nethereum.Model;
using Nethereum.RLP;
using Nethereum.Hex.HexConvertors.Extensions;
using System.Numerics;
// Example from Eip155SignerTests.cs
var privateKey = "4646464646464646464646464646464646464646464646464646464646464646";
var key = new EthECKey(privateKey);
// Create transaction with chain ID (EIP-155 for replay protection)
var nonce = 9.ToBytesForRLPEncoding();
var gasPrice = BigInteger.Parse("20000000000").ToBytesForRLPEncoding();
var gasLimit = 21000.ToBytesForRLPEncoding();
var to = "0x3535353535353535353535353535353535353535".HexToByteArray();
var value = BigInteger.Parse("1000000000000000000").ToBytesForRLPEncoding();
var data = "".HexToByteArray();
var chainId = 1.ToBytesForRLPEncoding(); // Mainnet
var tx = new LegacyTransactionChainId(nonce, gasPrice, gasLimit, to, value, data, chainId);
// Sign transaction
var signer = new LegacyTransactionSigner();
signer.SignTransaction(privateKey.HexToByteArray(), tx);
// V value includes chain ID: v = {0,1} + CHAIN_ID * 2 + 35
Console.WriteLine($"V value: {tx.Signature.V.ToIntFromRLPDecoded()}"); // 37 for mainnet
// Get signed transaction bytes (ready to broadcast)
byte[] signedTxBytes = tx.GetRLPEncoded();
string signedTxHex = signedTxBytes.ToHex(true);
Console.WriteLine($"Signed tx: {signedTxHex}");
// Recover signer from signed transaction
var recoveredTx = new LegacyTransactionChainId(signedTxBytes);
string recoveredAddress = recoveredTx.GetKey().GetPublicAddress();
Console.WriteLine($"Signer: {recoveredAddress}");
Console.WriteLine($"Match: {key.GetPublicAddress() == recoveredAddress}");
using Nethereum.Signer;
using Nethereum.Model;
using Nethereum.RLP;
using Nethereum.Hex.HexConvertors.Extensions;
using System.Numerics;
var privateKey = "0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7";
// EIP-1559 transaction with maxFeePerGas and maxPriorityFeePerGas
var chainId = new BigInteger(1); // Mainnet
var nonce = new BigInteger(5);
var maxPriorityFeePerGas = new BigInteger(2000000000); // 2 gwei
var maxFeePerGas = new BigInteger(100000000000); // 100 gwei
var gasLimit = new BigInteger(21000);
var to = "0x3535353535353535353535353535353535353535";
var value = new BigInteger(1000000000000000000); // 1 ETH
var data = "".HexToByteArray();
var tx = new Transaction1559(
chainId,
nonce,
maxPriorityFeePerGas,
maxFeePerGas,
gasLimit,
to,
value,
data,
null // access list
);
// Sign
var signer = new Transaction1559Signer();
signer.SignTransaction(privateKey.HexToByteArray(), tx);
// Transaction type 0x02 for EIP-1559
byte[] signedTx = tx.GetRLPEncoded();
Console.WriteLine($"Type: 0x{signedTx[0]:X2}"); // 0x02
// Recover signer
var recovered = new Transaction1559(signedTx);
Console.WriteLine($"Signer: {recovered.Key.GetPublicAddress()}");
using Nethereum.Signer;
using Nethereum.Util;
using Nethereum.Hex.HexConvertors.Extensions;
var privateKey = "0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7";
var key = new EthECKey(privateKey);
// Method 1: Sign with Ethereum prefix (most common)
var signer = new EthereumMessageSigner();
string message = "test";
string signature1 = signer.EncodeUTF8AndSign(message, key);
Console.WriteLine($"Ethereum signature: {signature1}");
// Method 2: Hash message yourself, then sign with prefix
var hasher = new Sha3Keccack();
byte[] messageHash = hasher.CalculateHash(message);
string signature2 = signer.Sign(messageHash, key);
Console.WriteLine($"Pre-hashed signature: {signature2}");
// Method 3: Sign raw hash WITHOUT Ethereum prefix (not recommended)
var rawSigner = new MessageSigner();
string signature3 = rawSigner.Sign(messageHash, key);
Console.WriteLine($"Raw signature: {signature3}");
// Verify: signature1 == signature2 (both use Ethereum prefix)
Console.WriteLine($"Ethereum signatures match: {signature1 == signature2}");
using Nethereum.Signer;
using Nethereum.Hex.HexConvertors.Extensions;
using System.Text;
// Generate deterministic key from seed (useful for testing)
byte[] seed = Encoding.UTF8.GetBytes("my-secret-seed-phrase");
var key1 = EthECKey.GenerateKey(seed);
var key2 = EthECKey.GenerateKey(seed);
// Same seed = same key
Console.WriteLine($"Key 1: {key1.GetPrivateKey()}");
Console.WriteLine($"Key 2: {key2.GetPrivateKey()}");
Console.WriteLine($"Match: {key1.GetPrivateKey() == key2.GetPrivateKey()}");
// Different seed = different key
byte[] differentSeed = Encoding.UTF8.GetBytes("different-seed");
var key3 = EthECKey.GenerateKey(differentSeed);
Console.WriteLine($"Key 3: {key3.GetPrivateKey()}");
Console.WriteLine($"Different: {key1.GetPrivateKey() != key3.GetPrivateKey()}");
// WARNING: For production, use truly random keys:
var randomKey = EthECKey.GenerateKey(); // Cryptographically secure random
using Nethereum.Signer;
using Nethereum.Signer.Crypto;
using Nethereum.Hex.HexConvertors.Extensions;
var privateKey = "0x4646464646464646464646464646464646464646464646464646464646464646";
var key = new EthECKey(privateKey);
var message = "test message".HexToByteArray();
// Sign message
var signer = new MessageSigner();
string signatureHex = signer.Sign(message, key);
byte[] signatureBytes = signatureHex.HexToByteArray();
// Parse signature
var signature = new EthECDSASignature(signatureBytes);
// Verify with low-S enforcement (prevents signature malleability)
bool isValid = key.VerifyAllowingOnlyLowS(message, signature);
Console.WriteLine($"Signature valid (low-S only): {isValid}");
// Without low-S enforcement (accepts both high and low S values)
bool isValidAny = key.Verify(message, signature);
Console.WriteLine($"Signature valid (any S): {isValidAny}");
// Why enforce low-S?
// ECDSA signatures have two valid S values (s and n-s)
// Bitcoin/Ethereum enforce low-S to prevent transaction malleability
// Always use VerifyAllowingOnlyLowS for security
using Nethereum.Signer;
using Nethereum.Hex.HexConvertors.Extensions;
// Alice generates key pair
var aliceKey = EthECKey.GenerateKey();
Console.WriteLine($"Alice address: {aliceKey.GetPublicAddress()}");
// Bob generates key pair
var bobKey = EthECKey.GenerateKey();
Console.WriteLine($"Bob address: {bobKey.GetPublicAddress()}");
// Alice calculates shared secret using Bob's public key
var bobPublicKey = new EthECKey(bobKey.GetPubKey(), false);
byte[] aliceSharedSecret = aliceKey.CalculateCommonSecret(bobPublicKey);
// Bob calculates shared secret using Alice's public key
var alicePublicKey = new EthECKey(aliceKey.GetPubKey(), false);
byte[] bobSharedSecret = bobKey.CalculateCommonSecret(alicePublicKey);
// Both shared secrets are identical
Console.WriteLine($"Alice secret: {aliceSharedSecret.ToHex(true)}");
Console.WriteLine($"Bob secret: {bobSharedSecret.ToHex(true)}");
Console.WriteLine($"Secrets match: {aliceSharedSecret.SequenceEqual(bobSharedSecret)}");
// Use shared secret for symmetric encryption (AES, etc.)
// This is the basis of ECIES (Elliptic Curve Integrated Encryption Scheme)
Ethereum elliptic curve key pair.
// Constructors
public EthECKey(string privateKeyHex);
public EthECKey(byte[] keyData, bool isPrivate);
// Static methods
public static EthECKey GenerateKey();
public static EthECKey GenerateKey(byte[] seed);
// Properties & Methods
public string GetPrivateKey(); // Hex string with 0x prefix
public byte[] GetPrivateKeyAsBytes();
public byte[] GetPubKey(); // Uncompressed (65 bytes)
public byte[] GetPubKeyCompressed(); // Compressed (33 bytes)
public string GetPublicAddress(); // Ethereum address (0x...)
// Signing & Verification
public EthECDSASignature Sign(byte[] hash);
public EthECDSASignature SignAndCalculateV(byte[] hash);
public bool Verify(byte[] hash, EthECDSASignature signature);
public bool VerifyAllowingOnlyLowS(byte[] hash, EthECDSASignature signature);
// ECDH
public byte[] CalculateCommonSecret(EthECKey publicKey);
Sign and verify Ethereum messages with standard prefix.
public class EthereumMessageSigner : MessageSigner
{
// Sign message (adds Ethereum prefix)
public string EncodeUTF8AndSign(string message, EthECKey key);
public override string Sign(byte[] message, EthECKey key);
public override string HashAndSign(byte[] message, EthECKey key);
// Recover signer address
public string EncodeUTF8AndEcRecover(string message, string signature);
public override string EcRecover(byte[] message, string signature);
public override string HashAndEcRecover(string message, string signature);
// Hash with Ethereum prefix
public byte[] HashPrefixedMessage(string message);
public byte[] HashPrefixedMessage(byte[] message);
}
Raw message signing (without Ethereum prefix).
public class MessageSigner
{
public virtual string Sign(byte[] message, EthECKey key);
public virtual string Sign(byte[] message, string privateKey);
public virtual string HashAndSign(byte[] plainMessage, EthECKey key);
public string HashAndSign(string plainMessage, string privateKey);
public string HashAndSign(byte[] plainMessage, string privateKey);
public virtual string EcRecover(byte[] hashMessage, string signature);
public virtual string HashAndEcRecover(string plainMessage, string signature);
public byte[] Hash(byte[] plainMessage);
}
// Legacy transactions
public class LegacyTransactionSigner
{
public void SignTransaction(byte[] privateKey, LegacyTransaction transaction);
public void SignTransaction(byte[] privateKey, LegacyTransactionChainId transaction);
}
// EIP-1559 transactions
public class Transaction1559Signer
{
public void SignTransaction(byte[] privateKey, Transaction1559 transaction);
}
// EIP-7702 transactions
public class Transaction7702Signer
{
public void SignTransaction(byte[] privateKey, Transaction7702 transaction);
}
// Authorization lists (EIP-7702)
public class Authorisation7702Signer
{
public void Sign(byte[] privateKey, Authorisation7702 authorisation);
}
ECDSA signature representation.
public class EthECDSASignature
{
public byte[] R { get; }
public byte[] S { get; }
public byte[] V { get; }
public EthECDSASignature(BigInteger r, BigInteger s, byte[] v);
public EthECDSASignature(ECDSASignature signature);
public EthECDSASignature(byte[] derSig);
public bool IsLowS { get; }
public byte[] ToDER();
public static EthECDSASignature FromDER(byte[] sig);
public static string CreateStringSignature(EthECDSASignature signature);
}
NEVER expose private keys in production code:
// ❌ WRONG - Hard-coded private key
var key = new EthECKey("0x1234567890abcdef...");
// ✅ CORRECT - Load from secure storage
string privateKey = Environment.GetEnvironmentVariable("PRIVATE_KEY");
var key = new EthECKey(privateKey);
// ✅ BETTER - Use hardware wallet or key vault
// See Nethereum.Signer.Ledger, Nethereum.Signer.AzureKeyVault
Always use VerifyAllowingOnlyLowS to prevent signature malleability:
// ❌ WRONG - Allows high-S signatures (malleable)
bool valid = key.Verify(hash, signature);
// ✅ CORRECT - Enforces low-S (prevents malleability)
bool valid = key.VerifyAllowingOnlyLowS(hash, signature);
Always specify chain ID for EIP-155+ transactions:
// ❌ WRONG - No replay protection
var tx = new LegacyTransaction(nonce, gasPrice, gasLimit, to, value, data);
// ✅ CORRECT - EIP-155 with chain ID
var chainId = 1; // Mainnet
var tx = new LegacyTransactionChainId(nonce, gasPrice, gasLimit, to, value, data, chainId.ToBytesForRLPEncoding());
Use EthereumMessageSigner (not MessageSigner) for user-facing messages:
// ❌ WRONG - No Ethereum prefix (could sign malicious transaction)
var signer = new MessageSigner();
string sig = signer.Sign(message, key);
// ✅ CORRECT - Adds Ethereum prefix (safe for user messages)
var signer = new EthereumMessageSigner();
string sig = signer.EncodeUTF8AndSign(message, key);
.NET 6+ uses NBitcoin.Secp256k1 for better performance:
#if NET6_0_OR_GREATER
// Enable recoverable signatures (uses NBitcoin.Secp256k1)
EthECKey.SignRecoverable = true;
#endif
This is faster and avoids post-signature recovery ID calculation.
EthECKey instances are not thread-safe. Don't share key instances across threads without synchronization.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 is compatible. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net451 net451 is compatible. net452 net452 was computed. net46 net46 was computed. net461 net461 is compatible. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 5 NuGet packages that depend on Nethereum.Signer:
| Package | Downloads |
|---|---|
|
Nethereum.Web3
Nethereum.Web3 Ethereum Web3 Class Library to interact via RPC with an Ethereum client, for example geth. Including contract interaction, deployment, transaction, encoding / decoding and event filters |
|
|
Nethereum.Accounts
Nethereum.Accounts Ethereum Accounts and Transaction Managers Class Library |
|
|
Nethereum.Signer.EIP712
Nethereum signer library to sign and encode messages according to EIP-712 |
|
|
Thirdweb
Best in class Web3 .NET SDK, powered by thirdweb. |
|
|
Nethereum
Package Description |
Showing the top 5 popular GitHub repositories that depend on Nethereum.Signer:
| Repository | Stars |
|---|---|
|
ChainSafe/web3.unity
🕹 Unity SDK for building games that interact with blockchains.
|
|
|
yc-l/yc.boilerplate
YC. Boilerplate is a set of loose coupling, flexible combination, complete functions, convenient development, and reduces the workload of development.
|
|
|
umacryptosoft/USDT-TRC20-Wallet
USDT Wallet -TRX Wallet - TRC20 Wallet, Transfer
|
|
|
WalletConnect/WalletConnectSharp
[Deprecated] A C# implementation of the WalletConnect protocol
|
|
|
biheBlockChain/MyLinkToken
开源链克口袋,玩客币钱包
|
| Version | Downloads | Last Updated |
|---|---|---|
| 6.1.0 | 69,150 | 3/25/2026 |
| 6.0.4 | 12,634 | 3/18/2026 |
| 6.0.3 | 1,907 | 3/18/2026 |
| 6.0.1 | 2,905 | 3/17/2026 |
| 6.0.0 | 4,219 | 3/16/2026 |
| 5.8.0 | 99,505 | 1/6/2026 |
| 5.0.0 | 447,462 | 5/28/2025 |
| 4.29.0 | 378,687 | 2/10/2025 |
| 4.28.0 | 97,535 | 1/7/2025 |
| 4.27.1 | 15,237 | 12/24/2024 |
| 4.27.0 | 8,743 | 12/24/2024 |
| 4.26.0 | 134,127 | 10/1/2024 |
| 4.25.0 | 35,245 | 9/19/2024 |
| 4.21.4 | 143,738 | 8/9/2024 |
| 4.21.3 | 16,774 | 7/22/2024 |
| 4.21.2 | 81,132 | 6/26/2024 |
| 4.21.1 | 4,123 | 6/26/2024 |
| 4.21.0 | 19,861 | 6/18/2024 |
| 4.20.0 | 441,465 | 3/28/2024 |
| 4.19.0 | 118,457 | 2/16/2024 |