| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- """
- Functions lifted from https://github.com/vbuterin/pybitcointools
- """
- import hashlib
- import hmac
- from typing import (
- Any,
- Callable,
- Tuple,
- )
- from eth_utils import (
- big_endian_to_int,
- int_to_big_endian,
- )
- from eth_keys.constants import (
- SECPK1_A as A,
- SECPK1_B as B,
- SECPK1_G as G,
- SECPK1_N as N,
- SECPK1_P as P,
- SECPK1_Gx as Gx,
- SECPK1_Gy as Gy,
- )
- from eth_keys.exceptions import (
- BadSignature,
- )
- from eth_keys.utils.padding import (
- pad32,
- )
- from .jacobian import (
- fast_add,
- fast_multiply,
- from_jacobian,
- inv,
- is_identity,
- jacobian_add,
- jacobian_multiply,
- )
- def decode_public_key(public_key_bytes: bytes) -> Tuple[int, int]:
- left = big_endian_to_int(public_key_bytes[0:32])
- right = big_endian_to_int(public_key_bytes[32:64])
- return left, right
- def encode_raw_public_key(raw_public_key: Tuple[int, int]) -> bytes:
- left, right = raw_public_key
- return b"".join(
- (
- pad32(int_to_big_endian(left)),
- pad32(int_to_big_endian(right)),
- )
- )
- def private_key_to_public_key(private_key_bytes: bytes) -> bytes:
- private_key_as_num = big_endian_to_int(private_key_bytes)
- if private_key_as_num >= N:
- raise Exception("Invalid privkey")
- raw_public_key = fast_multiply(G, private_key_as_num)
- public_key_bytes = encode_raw_public_key(raw_public_key)
- return public_key_bytes
- def compress_public_key(uncompressed_public_key_bytes: bytes) -> bytes:
- x, y = decode_public_key(uncompressed_public_key_bytes)
- if y % 2 == 0:
- prefix = b"\x02"
- else:
- prefix = b"\x03"
- return prefix + pad32(int_to_big_endian(x))
- def decompress_public_key(compressed_public_key_bytes: bytes) -> bytes:
- if len(compressed_public_key_bytes) != 33:
- raise ValueError("Invalid compressed public key")
- prefix = compressed_public_key_bytes[0]
- if prefix not in (2, 3):
- raise ValueError("Invalid compressed public key")
- x = big_endian_to_int(compressed_public_key_bytes[1:])
- y_squared = (x**3 + A * x + B) % P
- y_abs = pow(y_squared, ((P + 1) // 4), P)
- if (prefix == 2 and y_abs & 1 == 1) or (prefix == 3 and y_abs & 1 == 0):
- y = (-y_abs) % P
- else:
- y = y_abs
- return encode_raw_public_key((x, y))
- def deterministic_generate_k(
- msg_hash: bytes,
- private_key_bytes: bytes,
- digest_fn: Callable[[], Any] = hashlib.sha256,
- ) -> int:
- v_0 = b"\x01" * 32
- k_0 = b"\x00" * 32
- k_1 = hmac.new(
- k_0, v_0 + b"\x00" + private_key_bytes + msg_hash, digest_fn
- ).digest()
- v_1 = hmac.new(k_1, v_0, digest_fn).digest()
- k_2 = hmac.new(
- k_1, v_1 + b"\x01" + private_key_bytes + msg_hash, digest_fn
- ).digest()
- v_2 = hmac.new(k_2, v_1, digest_fn).digest()
- kb = hmac.new(k_2, v_2, digest_fn).digest()
- k = big_endian_to_int(kb)
- return k
- def ecdsa_raw_sign(msg_hash: bytes, private_key_bytes: bytes) -> Tuple[int, int, int]:
- z = big_endian_to_int(msg_hash)
- msg_hash_mod_n = pad32(int_to_big_endian(z % N))
- k = deterministic_generate_k(msg_hash_mod_n, private_key_bytes)
- r, y = fast_multiply(G, k)
- s_raw = inv(k, N) * (z + r * big_endian_to_int(private_key_bytes)) % N
- v = 27 + ((y % 2) ^ (0 if s_raw * 2 < N else 1))
- s = s_raw if s_raw * 2 < N else N - s_raw
- return v - 27, r, s
- def ecdsa_raw_verify(
- msg_hash: bytes, rs: Tuple[int, int], public_key_bytes: bytes
- ) -> bool:
- raw_public_key = decode_public_key(public_key_bytes)
- r, s = rs
- w = inv(s, N)
- z = big_endian_to_int(msg_hash)
- u1, u2 = z * w % N, r * w % N
- x, y = fast_add(
- fast_multiply(G, u1),
- fast_multiply(raw_public_key, u2),
- )
- return bool(r == x and (r % N) and (s % N))
- def ecdsa_raw_recover(msg_hash: bytes, vrs: Tuple[int, int, int]) -> bytes:
- v, r, s = vrs
- if v not in (0, 1):
- raise BadSignature(f"value of v, aka y-parity, was {v}, must be either 0 or 1")
- v += 27
- 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):
- raise BadSignature("Invalid signature")
- z = big_endian_to_int(msg_hash)
- 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))
- if is_identity(Q):
- raise BadSignature("InvalidSignature")
- raw_public_key = from_jacobian(Q)
- return encode_raw_public_key(raw_public_key)
|