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 verify(message, signature, public_key, curve=secp256k1, hash_function=sha256): hashed_message = hash_function(message).digest() int_hashed_message = int.from_bytes(hashed_message, byteorder='big') r, s = signature w = modular_inverse(s, curve.n) U1 = curve.G * ((int_hashed_message * w) % curve.n) U2 = public_key * ((r * w) % curve.n) V = U1 + U2 return r == V.x
def sign(message, private_key, curve=secp256k1, hash_function=sha256): hashed_message = hash_function(message).digest() int_hashed_message = int.from_bytes(hashed_message, byteorder='big') # generate a deterministic nonce according to RFC6979 rfc6979 = RFC6979(message, private_key, curve.n, hash_function) k = rfc6979.gen_nonce() rfc6979_point = curve.G * k r = rfc6979_point.x s = ((int_hashed_message + r * private_key) * modular_inverse(k, curve.n)) % curve.n return r, s
def __add__(self, other): if self == self.curve.identity_point: return other if other == self.curve.identity_point: return self if self.x == other.x: if self.y == other.y: # adding point to itself return self.double() else: # sum of vertical pair points gives identity point return self.curve.identity_point inverse_den = modular_inverse((self.x - other.x) % self.curve.p, self.curve.p) slope = ((self.y - other.y) * inverse_den) % self.curve.p return self.line_intersect(other, slope)
def test_modular_inverse(): n = secp256k1.n for i in range(100): a = randint(1, n) inv_a = modular_inverse(a, n) assert inv_a * a % n == 1
def tangent(self): inverse = modular_inverse(self.y * 2, self.curve.p) return ((self.x * self.x * 3 + self.curve.a) * inverse) % self.curve.p