ECDSA and C#
With ECDSA (Elliptic Curve Digital Signature), we use an elliptic curve to produce a digital signature. Overall, we take a hash of a message and then create a signature using a private key. The public key can then be used to verify the signature. In this case, we will use a range of curves, such as 192-bit, 256-bit, 384-bit and 521-bit curves, and create a range of hashing methods (such as MD5, SHA-1 and SHA-256).
With Elliptic Curve Cryptography (ECC) we can use a Weierstrass curve form of the form of y²=x³+ax+b (mod p). Bitcoin and Ethereum use secp256k1 and which has the form of y²=x³+7 (mod p). In most cases, though, we use the NIST-defined curves. SECP256k1 has 256-bit (x,y) points, and where the private key is a 256-bit scalar value (a) and which gives a public key point of:
a.G
and where G is a base point on the curve. An outline of ECDSA is:
We can code with [here]:
namespace ECDSA
{
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Parameters;
class Program
{
static void Main(string[] args)
{
try {
var msg="Hello";
var method="SHA-1withECDSA";
if (args.Length >0) msg=args[0];
if (args.Length >1) method=args[1];
var gen = new Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator("ECDSA");
var secureRandom = new SecureRandom();
var keyGenParam = new KeyGenerationParameters(secureRandom, 256);
gen.Init(keyGenParam);
var keyPair = gen.GenerateKeyPair();
ECPrivateKeyParameters privateKeyParam = (ECPrivateKeyParameters)keyPair.Private;
ECPublicKeyParameters publicKeyParam = (ECPublicKeyParameters)keyPair.Public;
var signer = SignerUtilities.GetSigner(method);
signer.Init(true,keyPair.Private);
signer.BlockUpdate(System.Text.Encoding.UTF8.GetBytes(msg), 0,System.Text.Encoding.UTF8.GetBytes(msg).Length);
byte[] signature = signer.GenerateSignature();
signer = SignerUtilities.GetSigner(method);
signer.Init(false,keyPair.Public);
signer.BlockUpdate(System.Text.Encoding.UTF8.GetBytes(msg), 0,System.Text.Encoding.UTF8.GetBytes(msg).Length);
var rtn=signer.VerifySignature(signature);
Console.WriteLine("Message: {0}",msg);
Console.WriteLine("\n=== Private key ===");
Console.WriteLine("D={0}",privateKeyParam.D.ToString());
Console.WriteLine("Method={0}",method);
Console.WriteLine("\n=== Public key ===");
Console.WriteLine("Gy={0}",publicKeyParam.Parameters.G.YCoord.ToString());
Console.WriteLine("Gx={0}",publicKeyParam.Parameters.G.XCoord.ToString());
Console.WriteLine("Curve={0}",publicKeyParam.Parameters.Curve.ToString());
Console.WriteLine("Order={0}",publicKeyParam.Parameters.N.ToString());
Console.WriteLine("Qx={0}",publicKeyParam.Q.XCoord.ToString());
Console.WriteLine("Qy={0}",publicKeyParam.Q.YCoord.ToString());
Console.WriteLine("\n=== Signature ===");
Console.WriteLine("\nSignature: r={0}",Convert.ToHexString(signature)[0..64]);
Console.WriteLine("\nVerified={0}",rtn);
} catch (Exception e) {
Console.WriteLine("Error: {0}",e.Message);
}
}
}
}
A sample run gives [here]:
Message: Post Quantum Crypto
=== Private key ===
D=121419095404849764515855012415047775391541554722394902556065690372269803511
Method=SHA-1withECDSA
=== Public key ===
Gy=4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
Gx=6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
Curve=Org.BouncyCastle.Math.EC.Custom.Sec.SecP256R1Curve
Order=115792089210356248762697446949407573529996955224135760342422259061068512044369
Qx=eb3472338fbfbb1510870bb820ad05f30b9d1330197cd8abf30e6de98abf9b64
Qy=4375cdefe245958f3a0358a723f7dbe2dc8847f7df180c1f2bc6ce691b2cbfb2
=== Signature ===
Signature=304502206DE460A0E46515B578A838CA71961E51FF3B6A76257E07744912EDC48F72AEF802210088753A7A3294DCD9808B87CDA1A7E668833FB57F79DBD696F6DABAB98771B18A
Verified=True
The signature is in a DER form, and we can then parse with [here] to get the r and s values:
DER: 304502206DE460A0E46515B578A838CA71961E51FF3B6A76257E07744912EDC48F72AEF802210088753A7A3294DCD9808B87CDA1A7E668833FB57F79DBD696F6DABAB98771B18A
[U] SEQUENCE (30)
[U] INTEGER (02): 49705608531639052973379532627260569791942375067203030641079606654887303229176
[U] INTEGER (02): 61721672109631760174112530506626131835392659902044938154054687780295991734666
-----BEGIN PUBLIC KEY-----
MEUCIG3kYKDkZRW1eKg4ynGWHlH/O2p2JX4HdEkS7cSPcq74AiEAiHU6ejKU3NmAi4fNoafmaIM/tX9529aW9tq6uYdxsYo=
-----END PUBLIC KEY-----
We thus have an (r,s) of 49705608531639052973379532627260569791942375067203030641079606654887303229176, 61721672109631760174112530506626131835392659902044938154054687780295991734666)