ECDSA and C#

Prof Bill Buchanan OBE FRSE
2 min readNov 6, 2023

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 =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)

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Prof Bill Buchanan OBE FRSE
Prof Bill Buchanan OBE FRSE

Written by Prof Bill Buchanan OBE FRSE

Professor of Cryptography. Serial innovator. Believer in fairness, justice & freedom. Based in Edinburgh. Old World Breaker. New World Creator. Building trust.

No responses yet

Write a response