 Adjunct Professor @ University of Lausanne

# Blockchain and Distributed Ledgers

Last updated: September 18th, 2019
In :
from fastecdsa.curve import secp256k1 as curve

In :
# The generating point G
curve.G

Out:
X: 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
(On curve <secp256k1>)
In :
# The coefficient a in y^2 = x^3 + ax + b
curve.a

Out:
0
In :
# The coefficient b in y^2 = x^3 + ax + b
curve.b

Out:
7
In :
# The number of elments in the underlying Galois field
curve.p

Out:
115792089237316195423570985008687907853269984665640564039457584007908834671663
In :
# The number of solutions (including the neutral element at infinity)
curve.q

Out:
115792089237316195423570985008687907852837564279074904382605163141518161494337
In :
from fastecdsa.curve import secp256k1 as curve
import fastecdsa.keys as keys
from mod import Mod

# every message needs to be hashed into a number
def encrypt_string(hash_str):
return int(hashlib.sha256(hash_str.encode()).hexdigest(), 16)

# The private key is a random number from [1, p - 1] where
# p is the order of the underlying Galois field
private_key = keys.gen_private_key(curve)

# The public key is
public_key = curve.G*private_key

# There are n solutions on the elliptic curve
# including the point at "infinity"
n = curve.q

# We send the clear message...
message = "I love this lecture"

# nonce
i = keys.gen_private_key(curve)

# nonce on elliptic curve
P = curve.G*i

# compute the signature
r = Mod(P.x,n)
inv_i = Mod(i,n).inverse()
s = (inv_i*(encrypt_string(message)+r*private_key))._value
# The sender transmits (r,s), the clear message and his public key
# s depends on the private key and the hashcode of the message.
# However it is not possible to extract the private key from s

# The receiver can now check whether the message is consistent
# This simple test returns False if
# - the text of the message has been changed.
# - if the sent public_key is consistent with  the private key
#   of the sender, without ever revealing the private key

# check the signature
w = Mod(s,n).inverse()
u1 = encrypt_string(message)*w
u2 = r*w

# addition of two residue classes and multiplication with Point
(curve.G*u1 + public_key*u2).x == r

Out:
True
In :
# We can hide a lot of the complexity
from fastecdsa.curve import secp256k1 as curve
import fastecdsa.keys as keys
from hashlib import sha256

private_key = keys.gen_private_key(curve)
public_key = keys.get_public_key(private_key, curve)

# We send the clear message...
message = "I love this lecture"

# standard signature, returns two integers
r, s = ecdsa.sign(message, private_key, curve, hashfunc=sha256)

# should return True as the signature we just generated is valid.
valid = ecdsa.verify((r, s), message, public_key, curve, hashfunc=sha256)
assert valid

# output the signature
print(r)
print(s)
print(public_key)

92638279574439449367469751620279883526129614094420035354557226216594551995720
56150953375323829929699404540178501317383477984004211069133248276172762035017
X: 0xed9671d3d1e3b8ee77a887517a9a019829354474a8e080ca1524712f53153da1