Everything You Ever Wanted To Know About ECDSA , But Were Afraid To Ask

And, so, Satoshi Nakamoto selected the secp256k1 curve, and used a private key to produce an ECDSA signature, in order to validate a…

Photo by Shubham Dhage on Unsplash

Everything You Ever Wanted To Know About ECDSA , But Were Afraid To Ask

And, so, Satoshi Nakamoto selected the secp256k1 curve, and used a private key to produce an ECDSA (Elliptic Curve Digital Signature Algorithm) signature, in order to validate a transaction. Up to this point, the DSA and RSA methods were the main techniques used to create a signature. But, elliptic curves came along and provided a lighter-weight approach, where we had an easy method to check a signature from a public identifier.

With Elliptic Curve Cryptography (ECC) we can use a Weierstrass curve form of the form of =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. These are SECP256R1, SECP384R1, and SECP521R1, but also use SECP224R1 and SECP192R1. SECP256R1 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

Creating the signature

With an ECDSA signature, Bob takes a hash of the message, his private key, and a random nonce (k), and produces an ECDSA signature. In its core form, it is an r and an s value. Normally, we encode this with a DER format, in order to fully define the curve we are using. Alice then checks the (r,s) values with Bob’s public key, and verifies it.

An outline of the method is:

For the ECDSA signature, Bob signs a message with the following:

Alice will check with:

Coding

The code we can use is [here]:

from cryptography.hazmat.primitives import serialization as crypto_serialization
from cryptography.hazmat.primitives.asymmetric import ec,utils
from cryptography.hazmat.backends import default_backend as crypto_default_backend
from cryptography.hazmat.primitives import hashes
import binascii
import sys

curve=0
message="Hello 123"

if (len(sys.argv)>1):
message=sys.argv[1]
if (len(sys.argv)>2):
curve=int(sys.argv[2])



key=ec.generate_private_key(ec.SECP256K1())
if curve==1: key=ec.generate_private_key(ec.SECP256R1())
elif curve==2: key=ec.generate_private_key(ec.SECP384R1())
elif curve==3: key=ec.generate_private_key(ec.SECP521R1())
elif curve==4: key=ec.generate_private_key(ec.SECP224R1())
elif curve==5: key=ec.generate_private_key(ec.SECP192R1())

try:
private_key = key.private_bytes(crypto_serialization.Encoding.PEM,crypto_serialization.PrivateFormat.PKCS8,crypto_serialization.NoEncryption())
print(f"\nPrivate key:\n{private_key.decode()}")

public_key = key.public_key().public_bytes(crypto_serialization.Encoding.PEM,crypto_serialization.PublicFormat.SubjectPublicKeyInfo)


print(f"Public key:\n{public_key.decode()}")

signature = key.sign(message.encode(),ec.ECDSA(hashes.SHA256()))

sig_bytes=binascii.b2a_hex(signature).decode()

b=len(sig_bytes)//2
print(f"Signature (DER): {sig_bytes}")
print(f"r={utils.decode_dss_signature(signature)[0]}\ns={utils.decode_dss_signature(signature)[1]}")


rtn=key.public_key().verify(signature, message.encode(),ec.ECDSA(hashes.SHA256()))
if (rtn==None): print("Signature verified")
else: print("Signature failed")

print("\n== Key details ==")

public_key = key.public_key().public_numbers()
print(f"Public key: Name: {public_key.curve.name}\nKey size: {public_key.curve.key_size} ")
print(f"\nPrivate key: {key.private_numbers().private_value}")

print(f"Public key: ({public_key.x}, {public_key.y})")

except Exception as e:
print("Public key error: ",e)

When we create the signature, it is in a DER format, and so we convert with to an (r,s) format with the utils.decode_dss_signature() method [here]:

signature = key.sign(message.encode(),ec.ECDSA(hashes.SHA256()))

sig_bytes=binascii.b2a_hex(signature).decode()

b=len(sig_bytes)//2
print(f"Signature (DER): {sig_bytes}")
print(f"r={utils.decode_dss_signature(signature)[0]}\ns={utils.decode_dss_signature(signature)[1]}")

A sample run for secp256r1 (NIST P256) is [here]:

Private key:
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg1/WMr6oUXGl1hijP
+u8jwEuAKsw2LPAvdPLyfSUSaNahRANCAASyJ4jRvy2/675n7A1anxaA6gUFCcsd
Hd0ieyIipIhLwhZZ57C5WhQBESwM5j8Xghi3bqJ3N6KKt8irRbhzJQvj
-----END PRIVATE KEY-----

Public key:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsieI0b8tv+u+Z+wNWp8WgOoFBQnL
HR3dInsiIqSIS8IWWeewuVoUAREsDOY/F4IYt26idzeiirfIq0W4cyUL4w==
-----END PUBLIC KEY-----

Signature (DER): 304502206b66916549f1fa8b9f2ae56a5acbfc88e30f8879ca2e337bfbc770642e188629022100b22c17256e27645326b83078311cb3b4d95b4d866fc013eff29e90eef7daa970
r=48578696682979138323841239336966833087059913739059954950567875251457003914793
s=80589588067956225877222590359913556297419631195495675214203673851061073521008
Signature verified

== Key details ==
Public key: Name: secp256r1
Key size: 256

Private key: 97681110956663660698023570645080160418079654958239874342586146225893087013078
Public key: (80581538375613259110382645040751327827229088365285399880658569756787922717634, 10109731125473688744975397858096091767732387706802026242652869573827719662563)

For secp521r1 [here]:

Private key:
-----BEGIN PRIVATE KEY-----
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBBFvswy9Qt1mKYBfy
tANEjARBG+9BGKKs3kf3ufGxcnfAw1a05/plXhGel047UKwLGZC5r6hytwB3+7Ac
Kiizfo2hgYkDgYYABAHlGg3qStsv/A0y1nVcgECXF91ycQrpnRPkO5KRv5tJRDjF
7JkHZ0olnJ/QmmUjUamTZ6YoX6Td9DqRTE/97yUdQgClRxfWdZkDD3WIE8RS2vAL
fCe+kqjQFRfigQ0KtxMVRs1C0YMu+HUM6RghwyS8sr0ppqeMDiR5qKOJeaswGsOH
tg==
-----END PRIVATE KEY-----

Public key:
-----BEGIN PUBLIC KEY-----
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB5RoN6krbL/wNMtZ1XIBAlxfdcnEK
6Z0T5DuSkb+bSUQ4xeyZB2dKJZyf0JplI1Gpk2emKF+k3fQ6kUxP/e8lHUIApUcX
1nWZAw91iBPEUtrwC3wnvpKo0BUX4oENCrcTFUbNQtGDLvh1DOkYIcMkvLK9Kaan
jA4keaijiXmrMBrDh7Y=
-----END PUBLIC KEY-----

Signature (DER): 308187024201d70a17895bdebf00f433afd1871c6963e06ef6cc142a07cebf6cb3ed1f7b7675daba5c24859315dc68ee8a99e8313edb3c2fa8e010139172bf1b89acc90e398fc502411bfad0a850c8ed15cde688ed75600bd547a647f6c346c48a012337df472fdb7564c576b8e41b880b56129533bcdd8192da219a17ed224d7aac36935c0d560b4b88
r=6315606092771985981675816777073871025533535685965415619681877735262154976141865195999710735842895685660425491922826211744427853666455615246297444053455310789
s=375147065130289034422735296529499637140700428942085621550486584979599009632621007362922100130642571123950584104642162500253809400661177401107949724136852360
Signature verified

== Key details ==
Public key: Name: secp521r1
Key size: 521

Private key: 3490844557007032590307378324673901236195920256627806290363707045243517267669111053311636297424454617120940146534511643423453782292068078937438239529643507341
Public key: (6504151423383820698811569074431024637218700646139367871020025492981128209725404760145406602271883736075202394444212944924295886984916204707081734163584589122, 2216011757059080428507096630121753476505305322973799098805588840810401842521999013682800354303429047478160206458108209657898967890882032166704333983502796726)

Conclusions

If you want to know more about ECDSA, try here:

https://asecuritysite.com/ecdsa