Skip to content
Permalink
Tree: b036cf5cb3
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
160 lines (125 sloc) 3.94 KB
import hashlib
import hmac
import sys
if sys.version_info.major == 2:
safe_ord = ord
else:
def safe_ord(value):
if isinstance(value, int):
return value
else:
return ord(value)
# Elliptic curve parameters (secp256k1)
P = 2**256 - 2**32 - 977
N = 115792089237316195423570985008687907852837564279074904382605163141518161494337
A = 0
B = 7
Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240
Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424
G = (Gx, Gy)
def bytes_to_int(x):
o = 0
for b in x:
o = (o << 8) + safe_ord(b)
return o
# Extended Euclidean Algorithm
def inv(a, n):
if a == 0:
return 0
lm, hm = 1, 0
low, high = a % n, n
while low > 1:
r = high // low
nm, new = hm - lm * r, high - low * r
lm, low, hm, high = nm, new, lm, low
return lm % n
def to_jacobian(p):
o = (p[0], p[1], 1)
return o
def jacobian_double(p):
if not p[1]:
return (0, 0, 0)
ysq = (p[1] ** 2) % P
S = (4 * p[0] * ysq) % P
M = (3 * p[0] ** 2 + A * p[2] ** 4) % P
nx = (M**2 - 2 * S) % P
ny = (M * (S - nx) - 8 * ysq ** 2) % P
nz = (2 * p[1] * p[2]) % P
return (nx, ny, nz)
def jacobian_add(p, q):
if not p[1]:
return q
if not q[1]:
return p
U1 = (p[0] * q[2] ** 2) % P
U2 = (q[0] * p[2] ** 2) % P
S1 = (p[1] * q[2] ** 3) % P
S2 = (q[1] * p[2] ** 3) % P
if U1 == U2:
if S1 != S2:
return (0, 0, 1)
return jacobian_double(p)
H = U2 - U1
R = S2 - S1
H2 = (H * H) % P
H3 = (H * H2) % P
U1H2 = (U1 * H2) % P
nx = (R ** 2 - H3 - 2 * U1H2) % P
ny = (R * (U1H2 - nx) - S1 * H3) % P
nz = (H * p[2] * q[2]) % P
return (nx, ny, nz)
def from_jacobian(p):
z = inv(p[2], P)
return ((p[0] * z**2) % P, (p[1] * z**3) % P)
def jacobian_multiply(a, n):
if a[1] == 0 or n == 0:
return (0, 0, 1)
if n == 1:
return a
if n < 0 or n >= N:
return jacobian_multiply(a, n % N)
if (n % 2) == 0:
return jacobian_double(jacobian_multiply(a, n // 2))
if (n % 2) == 1:
return jacobian_add(jacobian_double(jacobian_multiply(a, n // 2)), a)
def multiply(a, n):
return from_jacobian(jacobian_multiply(to_jacobian(a), n))
def add(a, b):
return from_jacobian(jacobian_add(to_jacobian(a), to_jacobian(b)))
def privtopub(privkey):
return multiply(G, bytes_to_int(privkey))
def deterministic_generate_k(msghash, priv):
v = b'\x01' * 32
k = b'\x00' * 32
k = hmac.new(k, v + b'\x00' + priv + msghash, hashlib.sha256).digest()
v = hmac.new(k, v, hashlib.sha256).digest()
k = hmac.new(k, v + b'\x01' + priv + msghash, hashlib.sha256).digest()
v = hmac.new(k, v, hashlib.sha256).digest()
return bytes_to_int(hmac.new(k, v, hashlib.sha256).digest())
# bytes32, bytes32 -> v, r, s (as numbers)
def ecdsa_raw_sign(msghash, priv):
z = bytes_to_int(msghash)
k = deterministic_generate_k(msghash, priv)
r, y = multiply(G, k)
s = inv(k, N) * (z + r * bytes_to_int(priv)) % N
v, r, s = 27 + ((y % 2) ^ (0 if s * 2 < N else 1)), r, s if s * 2 < N else N - s
return v, r, s
def ecdsa_raw_recover(msghash, vrs):
v, r, s = vrs
if not (27 <= v <= 34):
raise ValueError("%d must in range 27-31" % v)
x = r
xcubedaxb = (x * x * x + A * x + B) % P
beta = pow(xcubedaxb, (P + 1) // 4, P)
y = beta if v % 2 ^ beta % 2 else (P - beta)
# If xcubedaxb is not a quadratic residue, then r cannot be the x coord
# for a point on the curve, and so the sig is invalid
if (xcubedaxb - y * y) % P != 0 or not (r % N) or not (s % N):
return False
z = bytes_to_int(msghash)
Gz = jacobian_multiply((Gx, Gy, 1), (N - z) % N)
XY = jacobian_multiply((x, y, 1), s)
Qr = jacobian_add(Gz, XY)
Q = jacobian_multiply(Qr, inv(r, N))
Q = from_jacobian(Q)
return Q
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.