Secp256k1.Net
1.2.0
dotnet add package Secp256k1.Net --version 1.2.0
NuGet\Install-Package Secp256k1.Net -Version 1.2.0
<PackageReference Include="Secp256k1.Net" Version="1.2.0" />
paket add Secp256k1.Net --version 1.2.0
#r "nuget: Secp256k1.Net, 1.2.0"
// Install Secp256k1.Net as a Cake Addin #addin nuget:?package=Secp256k1.Net&version=1.2.0 // Install Secp256k1.Net as a Cake Tool #tool nuget:?package=Secp256k1.Net&version=1.2.0
Secp256k1.Net
Cross platform C# wrapper for the native secp256k1 library.
The nuget package supports win-x64, win-x86, win-arm64, macOS-x64, macOS-arm64 (Apple Silcon), linux-x64, linux-x86, and linux-arm64 out of the box. The native libraries are bundled from the Secp256k1.Native package. This wrapper should work on any other platform that supports netstandard2.0 (.NET Core 2.0+, Mono 5.4+, etc) but requires that the native secp256k1 library be compiled from source.
Example Usage
Generate key pair
using var secp256k1 = new Secp256k1();
// Generate a private key
var privateKey = new byte[Secp256k1.PRIVKEY_LENGTH];
var rnd = System.Security.Cryptography.RandomNumberGenerator.Create();
do { rnd.GetBytes(privateKey); }
while (!secp256k1.SecretKeyVerify(privateKey));
// Derive public key bytes
var publicKey = new byte[Secp256k1.PUBKEY_LENGTH];
Assert.True(secp256k1.PublicKeyCreate(publicKey, privateKey));
// Serialize the public key to compressed format
var serializedCompressedPublicKey = new byte[Secp256k1.SERIALIZED_COMPRESSED_PUBKEY_LENGTH];
Assert.True(secp256k1.PublicKeySerialize(serializedCompressedPublicKey, publicKey, Flags.SECP256K1_EC_COMPRESSED));
// Serialize the public key to uncompressed format
var serializedUncompressedPublicKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH];
Assert.True(secp256k1.PublicKeySerialize(serializedUncompressedPublicKey, publicKey, Flags.SECP256K1_EC_UNCOMPRESSED));
// Parse public key from serialized compressed public key
var parsedPublicKey1 = new byte[Secp256k1.PUBKEY_LENGTH];
Assert.IsTrue(secp256k1.PublicKeyParse(parsedPublicKey1, serializedCompressedPublicKey));
Assert.AreEqual(Convert.ToHexString(publicKey), Convert.ToHexString(parsedPublicKey1));
// Parse public key from serialied uncompressed public key
var parsedPublicKey2 = new byte[Secp256k1.PUBKEY_LENGTH];
Assert.IsTrue(secp256k1.PublicKeyParse(parsedPublicKey2, serializedUncompressedPublicKey));
Assert.AreEqual(Convert.ToHexString(publicKey), Convert.ToHexString(parsedPublicKey2));
Sign and verify message
using var secp256k1 = new Secp256k1();
var keypair = new
{
PrivateKey = Convert.FromHexString("7ef7543476bf146020cb59f9968a25ec67c3c73dbebad8a0b53a3256170dcdfe"),
PublicKey = Convert.FromHexString("2208d5dc41d4f3ed555aff761e9bb0b99fbe6d1503b98711944be6a362242ebfa1c788c7a4e13f6aaa4099f9d2175fc031e5aa3ba08eb280e87dfb43bdae207f")
};
// Create message hash
var msgBytes = System.Text.Encoding.UTF8.GetBytes("Hello!!");
var msgHash = System.Security.Cryptography.SHA256.HashData(msgBytes);
Assert.Equal(Secp256k1.HASH_LENGTH, msgHash.Length);
// Sign then verify message hash
var signature = new byte[Secp256k1.SIGNATURE_LENGTH];
Assert.True(secp256k1.Sign(signature, msgHash, keypair.PrivateKey));
Assert.True(secp256k1.Verify(signature, msgHash, keypair.PublicKey));
Compute an ECDH (EC Diffie-Hellman) secret
using var secp256k1 = new Secp256k1();
var aliceKeyPair = new
{
PrivateKey = Convert.FromHexString("7ef7543476bf146020cb59f9968a25ec67c3c73dbebad8a0b53a3256170dcdfe"),
PublicKey = Convert.FromHexString("2208d5dc41d4f3ed555aff761e9bb0b99fbe6d1503b98711944be6a362242ebfa1c788c7a4e13f6aaa4099f9d2175fc031e5aa3ba08eb280e87dfb43bdae207f")
};
var bobKeyPair = new
{
PrivateKey = Convert.FromHexString("d8bdb07407bb011137ef7ba6a7f07c6a55c1e3600a6aa138e34ab5c16439ceda"),
PublicKey = Convert.FromHexString("62127c4563f711169b1d3e56a34f218302a2587c3725bd418b9388933373e095d45ec4d74ca734599598c89d7719bda5fb799afeec89c6940d569e05bd5a1bba")
};
// Create secret using Alice's public key and Bob's private key
var secret1 = new byte[Secp256k1.SECRET_LENGTH];
Assert.True(secp256k1.Ecdh(secret1, aliceKeyPair.PublicKey, bobKeyPair.PrivateKey));
// Create secret using Bob's public key and Alice's private key
var secret2 = new byte[Secp256k1.SECRET_LENGTH];
Assert.True(secp256k1.Ecdh(secret2, bobKeyPair.PublicKey, aliceKeyPair.PrivateKey));
// Validate secrets match
Assert.Equal(Convert.ToHexString(secret1), Convert.ToHexString(secret2));
Parsing and serializing DER signatures
using var secp256k1 = new Secp256k1();
// Parse DER signature
var signatureOutput = new byte[Secp256k1.SIGNATURE_LENGTH];
var derSignature = Convert.FromHexString("30440220484ECE2B365D2B2C2EAD34B518328BBFEF0F4409349EEEC9CB19837B5795A5F5022040C4F6901FE489F923C49D4104554FD08595EAF864137F87DADDD0E3619B0605");
Assert.True(secp256k1.SignatureParseDer(signatureOutput, derSignature));
// Serialize DER signature
Span<byte> derSignatureOutput = new byte[Secp256k1.SERIALIZED_DER_SIGNATURE_MAX_SIZE];
Assert.True(secp256k1.SignatureSerializeDer(derSignatureOutput, signatureOutput, out int signatureOutputLength));
derSignatureOutput = derSignatureOutput.Slice(0, signatureOutputLength);
// Validate signature is the same after round trip parse and serialize
Assert.Equal(Convert.ToHexString(derSignature), Convert.ToHexString(derSignatureOutput));
See the tests project for more examples.
Benchmarks
BenchmarkDotNet=v0.13.4, OS=macOS Monterey 12.6.2 (21G320) [Darwin 21.6.0]
Apple M1 Pro, 1 CPU, 10 logical and 10 physical cores
.NET SDK=7.0.102
[Host] : .NET 7.0.2 (7.0.222.60605), Arm64 RyuJIT AdvSIMD
DefaultJob : .NET 7.0.2 (7.0.222.60605), Arm64 RyuJIT AdvSIMD
Method | feature | Mean | Error | StdDev | Ratio | RatioSD |
---|---|---|---|---|---|---|
Secp256k1Net | SignOnly | 53.00 μs | 0.044 μs | 0.037 μs | 1.00 | 0.00 |
Nbitcoin | SignOnly | 186.25 μs | 0.255 μs | 0.226 μs | 3.51 | 0.01 |
Nethereum | SignOnly | 579.06 μs | 1.272 μs | 0.993 μs | 10.93 | 0.02 |
BouncyCastle | SignOnly | 582.83 μs | 6.968 μs | 5.818 μs | 11.00 | 0.11 |
Chainers | SignOnly | 778.34 μs | 15.176 μs | 14.905 μs | 14.72 | 0.30 |
StarkBank | SignOnly | 1,800.91 μs | 4.751 μs | 4.444 μs | 34.00 | 0.10 |
Secp256k1Net | SignAndVerify | 90.97 μs | 0.084 μs | 0.075 μs | 1.00 | 0.00 |
Nbitcoin | SignAndVerify | 373.22 μs | 1.822 μs | 1.521 μs | 4.10 | 0.02 |
Nethereum | SignAndVerify | 1,679.02 μs | 3.984 μs | 3.327 μs | 18.46 | 0.04 |
BouncyCastle | SignAndVerify | 1,701.31 μs | 18.157 μs | 16.985 μs | 18.72 | 0.18 |
StarkBank | SignAndVerify | 5,315.49 μs | 15.796 μs | 14.002 μs | 58.43 | 0.15 |
BenchmarkDotNet=v0.13.4, OS=macOS Monterey 12.6.3 (21G419) [Darwin 21.6.0]
Intel Xeon CPU E5-1650 v2 3.50GHz (Max: 3.34GHz), 1 CPU, 3 logical and 3 physical cores
.NET SDK=7.0.102
[Host] : .NET 7.0.2 (7.0.222.60605), X64 RyuJIT AVX
DefaultJob : .NET 7.0.2 (7.0.222.60605), X64 RyuJIT AVX
Method | feature | Mean | Error | StdDev | Median | Ratio | RatioSD |
---|---|---|---|---|---|---|---|
Secp256k1Net | SignOnly | 97.17 μs | 4.112 μs | 11.666 μs | 93.27 μs | 1.00 | 0.00 |
Nbitcoin | SignOnly | 362.74 μs | 15.863 μs | 45.769 μs | 357.29 μs | 3.79 | 0.65 |
Nethereum | SignOnly | 1,122.70 μs | 28.246 μs | 78.740 μs | 1,098.21 μs | 11.71 | 1.46 |
BouncyCastle | SignOnly | 1,079.60 μs | 21.453 μs | 43.823 μs | 1,067.88 μs | 11.18 | 1.36 |
Chainers | SignOnly | 1,300.33 μs | 23.165 μs | 30.121 μs | 1,301.86 μs | 12.49 | 1.65 |
StarkBank | SignOnly | 2,564.26 μs | 41.055 μs | 40.322 μs | 2,566.36 μs | 25.16 | 2.97 |
Secp256k1Net | SignAndVerify | 146.25 μs | 2.679 μs | 2.506 μs | 145.54 μs | 1.00 | 0.00 |
Nbitcoin | SignAndVerify | 724.20 μs | 7.401 μs | 6.561 μs | 723.84 μs | 4.95 | 0.09 |
Nethereum | SignAndVerify | 3,048.38 μs | 59.507 μs | 55.663 μs | 3,058.23 μs | 20.85 | 0.57 |
BouncyCastle | SignAndVerify | 2,997.17 μs | 51.521 μs | 45.672 μs | 2,999.00 μs | 20.48 | 0.41 |
StarkBank | SignAndVerify | 8,008.58 μs | 159.859 μs | 304.149 μs | 8,022.61 μs | 53.30 | 2.05 |
BenchmarkDotNet=v0.13.4, OS=ubuntu 22.04
Intel Xeon Platinum 8370C CPU 2.80GHz, 1 CPU, 2 logical and 2 physical cores
.NET SDK=7.0.102
[Host] : .NET 7.0.2 (7.0.222.60605), X64 RyuJIT AVX2
DefaultJob : .NET 7.0.2 (7.0.222.60605), X64 RyuJIT AVX2
Method | feature | Mean | Error | StdDev | Ratio | RatioSD |
---|---|---|---|---|---|---|
Secp256k1Net | SignOnly | 88.61 μs | 0.047 μs | 0.041 μs | 1.00 | 0.00 |
Nbitcoin | SignOnly | 303.01 μs | 0.478 μs | 0.447 μs | 3.42 | 0.01 |
Nethereum | SignOnly | 988.51 μs | 4.649 μs | 4.348 μs | 11.16 | 0.05 |
BouncyCastle | SignOnly | 1,005.06 μs | 4.370 μs | 4.087 μs | 11.35 | 0.05 |
Chainers | SignOnly | 1,545.85 μs | 29.765 μs | 29.233 μs | 17.42 | 0.35 |
StarkBank | SignOnly | 2,441.18 μs | 5.709 μs | 5.340 μs | 27.55 | 0.06 |
Secp256k1Net | SignAndVerify | 146.08 μs | 0.047 μs | 0.039 μs | 1.00 | 0.00 |
Nbitcoin | SignAndVerify | 631.46 μs | 0.782 μs | 0.693 μs | 4.32 | 0.01 |
Nethereum | SignAndVerify | 2,800.69 μs | 19.084 μs | 17.851 μs | 19.17 | 0.13 |
BouncyCastle | SignAndVerify | 2,878.09 μs | 16.666 μs | 14.774 μs | 19.71 | 0.10 |
StarkBank | SignAndVerify | 7,121.17 μs | 13.625 μs | 12.745 μs | 48.77 | 0.08 |
BenchmarkDotNet=v0.13.4, OS=Windows 10 (10.0.20348.1487), VM=Hyper-V
Intel Xeon CPU E5-2673 v4 2.30GHz, 1 CPU, 2 logical and 2 physical cores
.NET SDK=7.0.102
[Host] : .NET 7.0.2 (7.0.222.60605), X64 RyuJIT AVX2
DefaultJob : .NET 7.0.2 (7.0.222.60605), X64 RyuJIT AVX2
Method | feature | Mean | Error | StdDev | Ratio | RatioSD |
---|---|---|---|---|---|---|
Secp256k1Net | SignOnly | 165.8 μs | 3.28 μs | 3.07 μs | 1.00 | 0.00 |
Nbitcoin | SignOnly | 374.1 μs | 7.43 μs | 8.84 μs | 2.25 | 0.06 |
Nethereum | SignOnly | 1,206.2 μs | 20.57 μs | 20.21 μs | 7.28 | 0.21 |
BouncyCastle | SignOnly | 1,200.1 μs | 20.21 μs | 18.91 μs | 7.24 | 0.17 |
Chainers | SignOnly | 1,613.4 μs | 31.76 μs | 50.38 μs | 9.78 | 0.31 |
StarkBank | SignOnly | 3,341.0 μs | 63.47 μs | 73.09 μs | 20.17 | 0.57 |
Secp256k1Net | SignAndVerify | 274.4 μs | 5.30 μs | 7.26 μs | 1.00 | 0.00 |
Nbitcoin | SignAndVerify | 807.3 μs | 16.02 μs | 32.00 μs | 3.00 | 0.16 |
Nethereum | SignAndVerify | 3,490.7 μs | 68.01 μs | 101.79 μs | 12.74 | 0.47 |
BouncyCastle | SignAndVerify | 3,438.9 μs | 68.07 μs | 109.93 μs | 12.52 | 0.52 |
StarkBank | SignAndVerify | 9,331.1 μs | 184.57 μs | 318.37 μs | 34.38 | 1.49 |
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Memory (>= 4.5.5)
NuGet packages (10)
Showing the top 5 NuGet packages that depend on Secp256k1.Net:
Package | Downloads |
---|---|
AElf.Cryptography
Cryptographic primitives used in AElf. |
|
Meadow.Core
Package Description |
|
Meadow.EVM
Package Description |
|
Libplanet.Crypto.Secp256k1
Package Description |
|
Cosm.Net.Core
Package Description |
GitHub repositories (4)
Showing the top 4 popular GitHub repositories that depend on Secp256k1.Net:
Repository | Stars |
---|---|
AElfProject/AElf
An AI-enhanced cloud-native layer-1 blockchain network.
|
|
planetarium/libplanet
Blockchain in C#/.NET for on-chain, decentralized gaming
|
|
hcmlab/nova
NOVA is a tool for annotating and analyzing behaviours in social interactions. It supports Annotators using Machine Learning already during the coding process. Further it features both, discrete labels and continuous scores and a visuzalization of streams recorded with the SSI Framework.
|
|
MeadowSuite/Meadow
Integrated Ethereum implementation and tool suite focused on Solidity testing and development.
|
Version | Downloads | Last updated |
---|---|---|
1.2.0 | 69,648 | 6/17/2023 |
1.1.0 | 10,059 | 2/12/2023 |
1.0.1 | 337 | 2/4/2023 |
1.0.0 | 404 | 2/4/2023 |
1.0.0-alpha.3 | 124 | 2/4/2023 |
1.0.0-alpha.2 | 124 | 2/4/2023 |
1.0.0-alpha | 178,624 | 2/9/2022 |
0.1.55 | 191,319 | 1/28/2020 |
0.1.54 | 190,631 | 4/1/2019 |
0.1.52 | 15,022 | 10/25/2018 |
0.1.51 | 747 | 10/25/2018 |
0.1.48 | 108,606 | 9/6/2018 |
0.1.47 | 784 | 9/6/2018 |
0.1.46 | 821 | 9/6/2018 |
0.1.45 | 936 | 8/8/2018 |
0.1.44 | 832 | 7/30/2018 |
0.1.43 | 850 | 7/28/2018 |
0.1.42 | 832 | 7/27/2018 |
0.1.41 | 825 | 7/27/2018 |
0.1.40 | 827 | 7/27/2018 |
0.1.39 | 820 | 7/27/2018 |
0.1.38 | 835 | 7/27/2018 |
0.1.37 | 824 | 7/27/2018 |
0.1.36 | 1,026 | 7/13/2018 |
0.1.35 | 845 | 7/11/2018 |
0.1.34 | 919 | 7/8/2018 |
0.1.33 | 932 | 7/5/2018 |
0.1.31 | 857 | 7/3/2018 |
0.1.30 | 906 | 7/3/2018 |
0.1.29 | 854 | 7/2/2018 |
0.1.28 | 990 | 6/20/2018 |
0.1.23 | 556 | 1/28/2020 |
0.1.22 | 567 | 1/28/2020 |
0.1.16 | 861 | 6/20/2018 |
0.1.15 | 837 | 6/20/2018 |
0.1.14 | 849 | 6/20/2018 |
0.1.13 | 928 | 6/20/2018 |
0.1.12 | 946 | 6/20/2018 |
0.1.11 | 930 | 6/20/2018 |
0.1.10 | 926 | 6/20/2018 |
0.1.9 | 936 | 6/20/2018 |
0.1.8 | 910 | 6/20/2018 |
0.1.7 | 925 | 6/20/2018 |
0.1.6 | 926 | 6/20/2018 |
0.1.1 | 901 | 6/19/2018 |
0.1.0 | 2,695 | 1/28/2020 |