def add(p: tuple, q: tuple) -> tuple or None:
    """Returns the result of p + q according to the group law."""
    assert on_curve(p)
    assert on_curve(q)
    if p is None:
        # 0 + q = q
        return q
    if q is None:
        # p + 0 = p
        return p
    #
    # p == -q
    #
    if p == negative(q):
        return None
    #
    # p != -q
    #
    x1, y1 = p
    x2, y2 = q
    if p == q:
        m = (3 * x1 * x1 + curve.a) * modular_multiplicative_inverse(
            2 * y1, curve.p)
    else:
        m = (y1 - y2) * modular_multiplicative_inverse(x1 - x2, curve.p)
    x = m * m - x1 - x2
    y = y1 + m * (x - x1)
    result = (x % curve.p, -y % curve.p)
    assert on_curve(result)
    return result
 def invss(self, a_shares: list, debug: bool = False) -> list:
     """Returns shares of modular multiplicative inverse of a, with shares of a, without knowing a"""
     assert len(a_shares) == self.group_size
     if debug:
         print('------------ invss ------------')
         print(ThresholdSignature.inspect(a_shares))
     b, _ = self.jvrss(debug)
     u = self.pross(a_shares, b, debug)
     mod_inv_u = modular_multiplicative_inverse(u, curve.n)
     inverse_shares = [(mod_inv_u * bi) % curve.n for bi in b]
     if debug:
         print(f'u = {u}')
         print(f'mod_inv_u = {mod_inv_u}')
         print(
             f'inverse shares = {ThresholdSignature.inspect(inverse_shares)}'
         )
         random_points = random.sample(
             ThresholdSignature.shares_to_points(inverse_shares),
             2 * self.polynomial_order + 1)
         print(
             f'points picked = {ThresholdSignature.inspect(random_points)}')
         secret_inverse = Polynomial.interpolate_evaluate(random_points, 0)
         print(f'inverse secret = {secret_inverse}')
         print('-------------------------------')
     return inverse_shares
예제 #3
0
def verify_signature(public_key: tuple, message: bytes,
                     signature: tuple) -> bool:
    """Verify signature with public key and message"""
    e = hash_to_int(message)
    r, s = signature
    w = modular_multiplicative_inverse(s, curve.n)
    u1 = (w * e) % curve.n
    u2 = (w * r) % curve.n
    x, _ = add(scalar_multiply(u1, curve.g), scalar_multiply(u2, public_key))
    return r == (x % curve.n)
예제 #4
0
def sign(private_key: int, message: bytes) -> tuple:
    """Create ECDSA signature (r, s)"""
    e = hash_to_int(message)
    r, s = 0, 0
    while not r or not s:
        k = random.randrange(1, curve.n)
        k_x, _ = scalar_multiply(k, curve.g)
        r = k_x % curve.n
        s = ((e + r * private_key) *
             modular_multiplicative_inverse(k, curve.n)) % curve.n
    return r, s
예제 #5
0
def sign_recoverable(private_key: int, message: bytes) -> tuple:
    """Create recoverable ECDSA signature, aka compact signature, (recovery_id, r, s)"""
    e = hash_to_int(message)
    recovery_id, r, s = 0, 0, 0
    while not r or not s:
        k = random.randrange(1, curve.n)
        k_x, k_y = scalar_multiply(k, curve.g)
        # r
        r = k_x % curve.n
        recovery_id = 0 | 2 if k_x > curve.n else 0 | k_y % 2
        # s
        s = ((e + r * private_key) *
             modular_multiplicative_inverse(k, curve.n)) % curve.n
    return recovery_id, r, s
def verify_message(p2pkh_address: str, plain_text: str,
                   signature: str) -> bool:
    """Verify serialized compact signature with p2pkh address and plain text"""
    sig_bytes = b64decode(signature)
    if len(sig_bytes) != 65:
        return False
    prefix, r, s = sig_bytes[0], int.from_bytes(
        sig_bytes[1:33], byteorder='big'), int.from_bytes(sig_bytes[33:],
                                                          byteorder='big')
    # Calculate recovery_id
    compressed = False
    if prefix < 27 or prefix >= 35:
        return False
    if prefix >= 31:
        compressed = True
        prefix -= 4
    recovery_id = prefix - 27
    # Recover point kG, k is the ephemeral private key
    x = r + (curve.n if recovery_id >= 2 else 0)
    y_squared = (x * x * x + curve.a * x + curve.b) % curve.p
    y = pow(y_squared, (curve.p + 1) // 4, curve.p)
    if (y + recovery_id) % 2 != 0:
        y = -y % curve.p
    point_k = (x, y)
    # Calculate point aG, a is the private key
    d = message_digest(plain_text)
    e = hash_to_int(d)
    mod_inv_r = modular_multiplicative_inverse(r, curve.n)
    public_key = add(scalar_multiply(mod_inv_r * s, point_k),
                     scalar_multiply(mod_inv_r * (-e % curve.n), curve.g))
    # Verify signature
    if not verify_signature(public_key, d, (r, s)):
        return False
    # Check public key hash
    if public_key_hash(
            public_key,
            compressed) != address_to_public_key_hash(p2pkh_address):
        return False
    # OK
    return True
 def jvrss(self, debug: bool = False) -> tuple:
     """Returns (shares_of_participants, group_shared_public_key)"""
     if debug:
         print('------------ jvrss ------------')
     # Random polynomials for each player
     polynomials = []
     for i in range(self.group_size):
         p = Polynomial.random(self.polynomial_order, debug)
         if debug:
             print(f'Player {i + 1} {p}')
         polynomials.append(p)
     # Calculate shares for each player
     shares = [0] * self.group_size
     for i in range(self.group_size):
         for j in range(self.group_size):
             fij = polynomials[i].evaluate(j + 1)
             shares[j] += fij
             if debug:
                 print(f'f{i + 1}({j + 1}) = {fij}', end='\t')
         if debug:
             print()
     for i in range(len(shares)):
         shares[i] %= curve.n
     # Calculate group shared public key
     public_key = None
     for i in range(self.group_size):
         public_key = add(
             public_key,
             scalar_multiply(polynomials[i].coefficients[0], curve.g))
     if debug:
         secret = sum([p.coefficients[0] for p in polynomials]) % curve.n
         mod_inv_secret = modular_multiplicative_inverse(secret, curve.n)
         print(f'secret = {secret}')
         print(f'mod_inv_secret = {mod_inv_secret}')
         print(f'public key = {public_key}')
         print(f'shares = {ThresholdSignature.inspect(shares)}')
         print('-------------------------------')
     return shares, public_key