def verify_message(coin, message, v, signature, address, curve=secp256k1, hash_function=double_sha256): r, s = signature if v < 27 or v >= 35: return False if v >= 31: compressed = True v -= 4 else: compressed = False recid = v - 27 # Calculation is based on http://www.secg.org/sec1-v2.pdf # chapter 4.1.6 'Public Key Recovery Operation'. x = r + (recid // 2) * curve.n alpha = (x**3 + curve.a * x + curve.b) % curve.p beta = modular_sqrt(alpha, curve.p) y = beta if (beta - recid) % 2 == 0 else curve.p - beta R = Point(curve, x, y) h = hash_function(message).digest() e = int.from_bytes(h, byteorder='big') Q = modular_inverse(r, curve.n) * (s * R - e * curve.G) public_key = Q calculated_address = convert_public_key_to_address( public_key, coin['address_prefix_bytes'], compressed) if calculated_address == address: return True else: return False
def decode_point(encoded_point, curve=secp256k1): if isinstance(encoded_point, bytes): encoded_point = encoded_point.hex() if len(encoded_point) == 130: # uncompressed x = int(encoded_point[2:66], 16) y = int(encoded_point[66:130], 16) return Point(curve=curve, x=x, y=y) if len(encoded_point) == 66: # compressed x = int(encoded_point[2:66], 16) beta = modular_sqrt(x**3 + curve.a * x + curve.b, curve.p) if (beta + int(encoded_point[:2], 16)) % 2: y = curve.p - beta else: y = beta return Point(curve=curve, x=x, y=y) raise Exception('Unrecognized point format')
def test_modular_sqrt_no_existing(a, p): sqrt = modular_sqrt(a, p) assert sqrt == 0
def test_modular_sqrt_exists(a, p): sqrt = modular_sqrt(a, p) assert sqrt * sqrt % p == a, 'failure for a={}'.format(a)