Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign up| 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 |