Example #1
0
def test_double_mult():
    H = (
        0x50929B74C1A04954B78B4B6035E97A5E078A5A0F28EC96D547BFEE9ACE803AC0,
        0x31D3C6863973926E049E637CB1B5F40A36DAC28AF1766968C30C2313F3A38904,
    )
    G = secp256k1.G

    # 0*G + 1*H
    T = double_mult(1, H, 0, G)
    assert T == H

    # 0*G + 2*H
    T = double_mult(2, H, 0, G)
    assert T == mult(2, H)

    # 0*G + 3*H
    T = double_mult(3, H, 0, G)
    assert T == mult(3, H)

    # 1*G + 0*H
    T = double_mult(0, H, 1, G)
    assert T == G

    # 2*G + 0*H
    T = double_mult(0, H, 2, G)
    assert T == mult(2, G)

    # 3*G + 0*H
    T = double_mult(0, H, 3, G)
    assert T == mult(3, G)

    # 0*G + 5*H
    T = double_mult(5, H, 0, G)
    assert T == mult(5, H)

    # 0*G - 5*H
    T = double_mult(-5, H, 0, G)
    assert T == mult(-5, H)

    # 1*G - 5*H
    U = double_mult(-5, H, 1, G)
    assert U == secp256k1.add(G, T)
def ckd(xparentkey: octets, index: Union[octets, int]) -> bytes:
    """Child Key Derivation (CDK)

    Key derivation is normal if the extended parent key is public or
    child_index is less than 0x80000000.

    Key derivation is hardened if the extended parent key is private and
    child_index is not less than 0x80000000.
    """

    if isinstance(index, int):
        index = index.to_bytes(4, 'big')
    elif isinstance(index, str):  # hex string
        index = bytes.fromhex(index)

    if len(index) != 4:
        raise ValueError(f"a 4 bytes int is required, not {len(index)}")

    xparent = base58.decode_check(xparentkey, 78)

    version = xparent[:4]

    # serialization data
    xkey = version  # version
    xkey += (xparent[4] + 1).to_bytes(1, 'big')  # (increased) depth

    if (version in PUB):
        if xparent[45] not in (2, 3):  # not a compressed public key
            raise ValueError("version/key mismatch in extended parent key")
        Parent_bytes = xparent[45:]
        Parent = point_from_octets(ec, Parent_bytes)
        xkey += _h160(Parent_bytes)[:4]  # parent pubkey fingerprint
        if index[0] >= 0x80:
            raise ValueError("no private/hardened derivation from pubkey")
        xkey += index  # child index
        parent_chain_code = xparent[13:45]  # normal derivation
        # actual extended key (key + chain code) derivation
        h = HMAC(parent_chain_code, Parent_bytes + index, sha512).digest()
        offset = int.from_bytes(h[:32], 'big')
        Offset = mult(ec, offset, ec.G)
        Child = ec.add(Parent, Offset)
        Child_bytes = octets_from_point(ec, Child, True)
        xkey += h[32:]  # chain code
        xkey += Child_bytes  # public key
    elif (version in PRV):
        if xparent[45] != 0:  # not a private key
            raise ValueError("version/key mismatch in extended parent key")
        parent = int.from_bytes(xparent[46:], 'big')
        Parent = mult(ec, parent, ec.G)
        Parent_bytes = octets_from_point(ec, Parent, True)
        xkey += _h160(Parent_bytes)[:4]  # parent pubkey fingerprint
        xkey += index  # child index
        # actual extended key (key + chain code) derivation
        parent_chain_code = xparent[13:45]
        if (index[0] < 0x80):  # normal derivation
            h = HMAC(parent_chain_code, Parent_bytes + index, sha512).digest()
        else:  # hardened derivation
            h = HMAC(parent_chain_code, xparent[45:] + index, sha512).digest()
        offset = int.from_bytes(h[:32], 'big')
        child = (parent + offset) % ec.n
        child_bytes = b'\x00' + child.to_bytes(32, 'big')
        xkey += h[32:]  # chain code
        xkey += child_bytes  # private key
    else:
        raise ValueError("invalid extended key version")

    return base58.encode_check(xkey)
Example #3
0
def test_mult_double_mult():
    H = second_generator(secp256k1)
    G = secp256k1.G

    # 0*G + 1*H
    T = double_mult(1, H, 0, G)
    assert T == H
    T = multi_mult([1, 0], [H, G])
    assert T == H

    # 0*G + 2*H
    exp = mult(2, H)
    T = double_mult(2, H, 0, G)
    assert T == exp
    T = multi_mult([2, 0], [H, G])
    assert T == exp

    # 0*G + 3*H
    exp = mult(3, H)
    T = double_mult(3, H, 0, G)
    assert T == exp
    T = multi_mult([3, 0], [H, G])
    assert T == exp

    # 1*G + 0*H
    T = double_mult(0, H, 1, G)
    assert T == G
    T = multi_mult([0, 1], [H, G])
    assert T == G

    # 2*G + 0*H
    exp = mult(2, G)
    T = double_mult(0, H, 2, G)
    assert T == exp
    T = multi_mult([0, 2], [H, G])
    assert T == exp

    # 3*G + 0*H
    exp = mult(3, G)
    T = double_mult(0, H, 3, G)
    assert T == exp
    T = multi_mult([0, 3], [H, G])
    assert T == exp

    # 0*G + 5*H
    exp = mult(5, H)
    T = double_mult(5, H, 0, G)
    assert T == exp
    T = multi_mult([5, 0], [H, G])
    assert T == exp

    # 0*G - 5*H
    exp = mult(-5, H)
    T = double_mult(-5, H, 0, G)
    assert T == exp
    T = multi_mult([-5, 0], [H, G])
    assert T == exp

    # 1*G - 5*H
    exp = secp256k1.add(G, T)
    T = double_mult(-5, H, 1, G)
    assert T == exp
Example #4
0
import random
import time

from btclib.curvemult import double_mult, mult
from btclib.curves import secp256k1 as ec

random.seed(42)

# setup
k1 = []
k2 = []
Q = []
for _ in range(50):
    k1.append(random.getrandbits(ec.nlen) % ec.n)
    k2.append(random.getrandbits(ec.nlen) % ec.n)
    q = random.getrandbits(ec.nlen) % ec.n
    Q.append(mult(q, ec.G))

start = time.time()
for i in range(len(Q)):
    ec.add(mult(k1[i], ec.G), mult(k2[i], Q[i]))
elapsed1 = time.time() - start

start = time.time()
for i in range(len(Q)):
    double_mult(k1[i], ec.G, k2[i], Q[i])
elapsed2 = time.time() - start

print(elapsed2 / elapsed1)
Example #5
0
mprvkey = random.getrandbits(ec.nlen) % ec.n
print('\nmaster private key:', hex(mprvkey))

# Master Pubkey:
mpubkey = mult(mprvkey, ec.G)
print('Master Public Key:', hex(mpubkey[0]))
print('                  ', hex(mpubkey[1]))

# public random number
r = random.getrandbits(ec.nlen)
print('\npublic ephemeral key:', format(r, '#064x'))

q = []
hint = []
rbytes = r.to_bytes(ec.nsize, 'big')
nKeys = 3
for i in range(nKeys):
    ibytes = i.to_bytes(ec.nsize, 'big')
    hd = hf(ibytes + rbytes).digest()
    hint.append(int_from_bits(hd))
    q.append((mprvkey + hint[i]) % ec.n)
    Q = mult(q[i], ec.G)
    print('\nprvkey#', i, ':', hex(q[i]))
    print('Pubkey#', i, ':', hex(Q[0]))
    print('           ', hex(Q[1]))

# Pubkeys could be calculated without using prvkeys
for i in range(nKeys):
    Q = ec.add(mpubkey, mult(hint[i], ec.G))
    assert Q == mult(q[i], ec.G)
Example #6
0
s = (c + r * q) * mod_inv(k, ec.n) % ec.n
# if s == 0 (extremely unlikely for large ec.n) go back to a different k
assert s != 0

print("    r:", hex(r))
print("    s:", hex(s))

print("*** Verify Signature")
w = mod_inv(s, ec.n)
u = (c * w) % ec.n
v = (r * w) % ec.n
assert u != 0
assert v != 0
U = mult(ec, u, ec.G)
V = mult(ec, v, Q)
x, y = ec.add(U, V)
print(r == x % ec.n)

print("\n*** Malleated Signature")
sm = ec.n - s
print("    r:", hex(r))
print("   sm:", hex(sm))

print("*** Malleated Signature Verification")
w = mod_inv(sm, ec.n)
u = c * w % ec.n
v = r * w % ec.n
assert u != 0
assert v != 0
U = mult(ec, u, ec.G)
V = mult(ec, v, Q)
Example #7
0
    def test_musig(self):
        """testing 3-of-3 MuSig

            https://github.com/ElementsProject/secp256k1-zkp/blob/secp256k1-zkp/src/modules/musig/musig.md
            https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/
            https://eprint.iacr.org/2018/068
            https://blockstream.com/2018/01/23/musig-key-aggregation-schnorr-signatures.html
            https://medium.com/@snigirev.stepan/how-schnorr-signatures-may-improve-bitcoin-91655bcb4744
        """
        mhd = hf(b'message to sign').digest()

        # the signers private and public keys,
        # including both the curve Point and the BIP340-Schnorr public key
        q1, x_Q1 = ssa.gen_keys()
        x_Q1 = x_Q1.to_bytes(ec.psize, 'big')

        q2, x_Q2 = ssa.gen_keys()
        x_Q2 = x_Q2.to_bytes(ec.psize, 'big')

        q3, x_Q3 = ssa.gen_keys()
        x_Q3 = x_Q3.to_bytes(ec.psize, 'big')

        # (non interactive) key setup
        # this is MuSig core: the rest is just Schnorr signature additivity
        # 1. lexicographic sorting of public keys
        keys: List[bytes] = list()
        keys.append(x_Q1)
        keys.append(x_Q2)
        keys.append(x_Q3)
        keys.sort()
        # 2. coefficients
        prefix = b''.join(keys)
        a1 = int_from_bits(hf(prefix + x_Q1).digest(), ec.nlen) % ec.n
        a2 = int_from_bits(hf(prefix + x_Q2).digest(), ec.nlen) % ec.n
        a3 = int_from_bits(hf(prefix + x_Q3).digest(), ec.nlen) % ec.n
        # 3. aggregated public key
        Q1 = mult(q1)
        Q2 = mult(q2)
        Q3 = mult(q3)
        Q = ec.add(double_mult(a1, Q1, a2, Q2), mult(a3, Q3))
        if not ec.has_square_y(Q):
            # print("Q has been negated")
            a1 = ec.n - a1  # pragma: no cover
            a2 = ec.n - a2  # pragma: no cover
            a3 = ec.n - a3  # pragma: no cover

        # ready to sign: nonces and nonce commitments
        k1, _ = ssa.gen_keys()
        K1 = mult(k1)

        k2, _ = ssa.gen_keys()
        K2 = mult(k2)

        k3, _ = ssa.gen_keys()
        K3 = mult(k3)

        # exchange {K_i} (interactive)

        # computes s_i (non interactive)
        # WARNING: signers must exchange the nonces commitments {K_i}
        # before sharing {s_i}

        # same for all signers
        K = ec.add(ec.add(K1, K2), K3)
        if not ec.has_square_y(K):
            k1 = ec.n - k1  # pragma: no cover
            k2 = ec.n - k2  # pragma: no cover
            k3 = ec.n - k3  # pragma: no cover
        r = K[0]
        e = ssa._challenge(r, Q[0], mhd, ec, hf)
        s1 = (k1 + e * a1 * q1) % ec.n
        s2 = (k2 + e * a2 * q2) % ec.n
        s3 = (k3 + e * a3 * q3) % ec.n

        # exchange s_i (interactive)

        # finalize signature (non interactive)
        s = (s1 + s2 + s3) % ec.n
        sig = r, s
        # check signature is valid
        ssa._verify(mhd, Q, sig, ec, hf)
        self.assertTrue(ssa.verify(mhd, Q, sig))
Example #8
0
    def test_threshold(self):
        """testing 2-of-3 threshold signature (Pedersen secret sharing)"""

        # parameters
        m = 2
        H = second_generator(ec, hf)
        mhd = hf(b'message to sign').digest()

        # FIRST PHASE: key pair generation ###################################

        # 1.1 signer one acting as the dealer
        commits1: List[Point] = list()
        q1, _ = ssa.gen_keys()
        q1_prime, _ = ssa.gen_keys()
        commits1.append(double_mult(q1_prime, H, q1, ec.G))
        # sharing polynomials
        f1 = [q1]
        f1_prime = [q1_prime]
        for i in range(1, m):
            f1.append(ssa.gen_keys()[0])
            f1_prime.append(ssa.gen_keys()[0])
            commits1.append(double_mult(f1_prime[i], H, f1[i], ec.G))
        # shares of the secret
        alpha12 = 0  # share of q1 belonging to signer two
        alpha12_prime = 0
        alpha13 = 0  # share of q1 belonging to signer three
        alpha13_prime = 0
        for i in range(m):
            alpha12 += (f1[i] * pow(2, i)) % ec.n
            alpha12_prime += (f1_prime[i] * pow(2, i)) % ec.n
            alpha13 += (f1[i] * pow(3, i)) % ec.n
            alpha13_prime += (f1_prime[i] * pow(3, i)) % ec.n
        # signer two verifies consistency of his share
        RHS = INF
        for i in range(m):
            RHS = ec.add(RHS, mult(pow(2, i), commits1[i]))
        t = double_mult(alpha12_prime, H, alpha12, ec.G)
        assert t == RHS, 'signer one is cheating'
        # signer three verifies consistency of his share
        RHS = INF
        for i in range(m):
            RHS = ec.add(RHS, mult(pow(3, i), commits1[i]))
        t = double_mult(alpha13_prime, H, alpha13, ec.G)
        assert t == RHS, 'signer one is cheating'

        # 1.2 signer two acting as the dealer
        commits2: List[Point] = list()
        q2, _ = ssa.gen_keys()
        q2_prime, _ = ssa.gen_keys()
        commits2.append(double_mult(q2_prime, H, q2, ec.G))
        # sharing polynomials
        f2 = [q2]
        f2_prime = [q2_prime]
        for i in range(1, m):
            f2.append(ssa.gen_keys()[0])
            f2_prime.append(ssa.gen_keys()[0])
            commits2.append(double_mult(f2_prime[i], H, f2[i], ec.G))
        # shares of the secret
        alpha21 = 0  # share of q2 belonging to signer one
        alpha21_prime = 0
        alpha23 = 0  # share of q2 belonging to signer three
        alpha23_prime = 0
        for i in range(m):
            alpha21 += (f2[i] * pow(1, i)) % ec.n
            alpha21_prime += (f2_prime[i] * pow(1, i)) % ec.n
            alpha23 += (f2[i] * pow(3, i)) % ec.n
            alpha23_prime += (f2_prime[i] * pow(3, i)) % ec.n
        # signer one verifies consistency of his share
        RHS = INF
        for i in range(m):
            RHS = ec.add(RHS, mult(pow(1, i), commits2[i]))
        t = double_mult(alpha21_prime, H, alpha21, ec.G)
        assert t == RHS, 'signer two is cheating'
        # signer three verifies consistency of his share
        RHS = INF
        for i in range(m):
            RHS = ec.add(RHS, mult(pow(3, i), commits2[i]))
        t = double_mult(alpha23_prime, H, alpha23, ec.G)
        assert t == RHS, 'signer two is cheating'

        # 1.3 signer three acting as the dealer
        commits3: List[Point] = list()
        q3, _ = ssa.gen_keys()
        q3_prime, _ = ssa.gen_keys()
        commits3.append(double_mult(q3_prime, H, q3, ec.G))
        # sharing polynomials
        f3 = [q3]
        f3_prime = [q3_prime]
        for i in range(1, m):
            f3.append(ssa.gen_keys()[0])
            f3_prime.append(ssa.gen_keys()[0])
            commits3.append(double_mult(f3_prime[i], H, f3[i], ec.G))
        # shares of the secret
        alpha31 = 0  # share of q3 belonging to signer one
        alpha31_prime = 0
        alpha32 = 0  # share of q3 belonging to signer two
        alpha32_prime = 0
        for i in range(m):
            alpha31 += (f3[i] * pow(1, i)) % ec.n
            alpha31_prime += (f3_prime[i] * pow(1, i)) % ec.n
            alpha32 += (f3[i] * pow(2, i)) % ec.n
            alpha32_prime += (f3_prime[i] * pow(2, i)) % ec.n
        # signer one verifies consistency of his share
        RHS = INF
        for i in range(m):
            RHS = ec.add(RHS, mult(pow(1, i), commits3[i]))
        t = double_mult(alpha31_prime, H, alpha31, ec.G)
        assert t == RHS, 'signer three is cheating'
        # signer two verifies consistency of his share
        RHS = INF
        for i in range(m):
            RHS = ec.add(RHS, mult(pow(2, i), commits3[i]))
        t = double_mult(alpha32_prime, H, alpha32, ec.G)
        assert t == RHS, 'signer three is cheating'
        # shares of the secret key q = q1 + q2 + q3
        alpha1 = (alpha21 + alpha31) % ec.n
        alpha2 = (alpha12 + alpha32) % ec.n
        alpha3 = (alpha13 + alpha23) % ec.n
        for i in range(m):
            alpha1 += (f1[i] * pow(1, i)) % ec.n
            alpha2 += (f2[i] * pow(2, i)) % ec.n
            alpha3 += (f3[i] * pow(3, i)) % ec.n

        # 1.4 it's time to recover the public key
        # each participant i = 1, 2, 3 shares Qi as follows
        # Q = Q1 + Q2 + Q3 = (q1 + q2 + q3) G
        A1: List[Point] = list()
        A2: List[Point] = list()
        A3: List[Point] = list()
        for i in range(m):
            A1.append(mult(f1[i]))
            A2.append(mult(f2[i]))
            A3.append(mult(f3[i]))
        # signer one checks others' values
        RHS2 = INF
        RHS3 = INF
        for i in range(m):
            RHS2 = ec.add(RHS2, mult(pow(1, i), A2[i]))
            RHS3 = ec.add(RHS3, mult(pow(1, i), A3[i]))
        assert mult(alpha21) == RHS2, 'signer two is cheating'
        assert mult(alpha31) == RHS3, 'signer three is cheating'
        # signer two checks others' values
        RHS1 = INF
        RHS3 = INF
        for i in range(m):
            RHS1 = ec.add(RHS1, mult(pow(2, i), A1[i]))
            RHS3 = ec.add(RHS3, mult(pow(2, i), A3[i]))
        assert mult(alpha12) == RHS1, 'signer one is cheating'
        assert mult(alpha32) == RHS3, 'signer three is cheating'
        # signer three checks others' values
        RHS1 = INF
        RHS2 = INF
        for i in range(m):
            RHS1 = ec.add(RHS1, mult(pow(3, i), A1[i]))
            RHS2 = ec.add(RHS2, mult(pow(3, i), A2[i]))
        assert mult(alpha13) == RHS1, 'signer one is cheating'
        assert mult(alpha23) == RHS2, 'signer two is cheating'
        # commitment at the global sharing polynomial
        A: List[Point] = list()
        for i in range(m):
            A.append(ec.add(A1[i], ec.add(A2[i], A3[i])))

        # aggregated public key
        Q = A[0]
        if not ec.has_square_y(Q):
            # print('Q has been negated')
            A[1] = ec.negate(A[1])  # pragma: no cover
            alpha1 = ec.n - alpha1  # pragma: no cover
            alpha2 = ec.n - alpha2  # pragma: no cover
            alpha3 = ec.n - alpha3  # pragma: no cover
            Q = ec.negate(Q)  # pragma: no cover

        # SECOND PHASE: generation of the nonces' pair  ######################
        # Assume signer one and three want to sign

        # 2.1 signer one acting as the dealer
        commits1: List[Point] = list()
        k1 = ssa.k(mhd, q1, ec, hf)
        k1_prime = ssa.k(mhd, q1_prime, ec, hf)
        commits1.append(double_mult(k1_prime, H, k1, ec.G))
        # sharing polynomials
        f1 = [k1]
        f1_prime = [k1_prime]
        for i in range(1, m):
            f1.append(ssa.gen_keys()[0])
            f1_prime.append(ssa.gen_keys()[0])
            commits1.append(double_mult(f1_prime[i], H, f1[i], ec.G))
        # shares of the secret
        beta13 = 0  # share of k1 belonging to signer three
        beta13_prime = 0
        for i in range(m):
            beta13 += (f1[i] * pow(3, i)) % ec.n
            beta13_prime += (f1_prime[i] * pow(3, i)) % ec.n
        # signer three verifies consistency of his share
        RHS = INF
        for i in range(m):
            RHS = ec.add(RHS, mult(pow(3, i), commits1[i]))
        t = double_mult(beta13_prime, H, beta13, ec.G)
        assert t == RHS, 'signer one is cheating'

        # 2.2 signer three acting as the dealer
        commits3: List[Point] = list()
        k3 = ssa.k(mhd, q3, ec, hf)
        k3_prime = ssa.k(mhd, q3_prime, ec, hf)
        commits3.append(double_mult(k3_prime, H, k3, ec.G))
        # sharing polynomials
        f3 = [k3]
        f3_prime = [k3_prime]
        for i in range(1, m):
            f3.append(ssa.gen_keys()[0])
            f3_prime.append(ssa.gen_keys()[0])
            commits3.append(double_mult(f3_prime[i], H, f3[i], ec.G))
        # shares of the secret
        beta31 = 0  # share of k3 belonging to signer one
        beta31_prime = 0
        for i in range(m):
            beta31 += (f3[i] * pow(1, i)) % ec.n
            beta31_prime += (f3_prime[i] * pow(1, i)) % ec.n
        # signer one verifies consistency of his share
        RHS = INF
        for i in range(m):
            RHS = ec.add(RHS, mult(pow(1, i), commits3[i]))
        t = double_mult(beta31_prime, H, beta31, ec.G)
        assert t == RHS, 'signer three is cheating'

        # 2.3 shares of the secret nonce
        beta1 = beta31 % ec.n
        beta3 = beta13 % ec.n
        for i in range(m):
            beta1 += (f1[i] * pow(1, i)) % ec.n
            beta3 += (f3[i] * pow(3, i)) % ec.n

        # 2.4 it's time to recover the public nonce
        # each participant i = 1, 3 shares Qi as follows
        B1: List[Point] = list()
        B3: List[Point] = list()
        for i in range(m):
            B1.append(mult(f1[i]))
            B3.append(mult(f3[i]))

        # signer one checks values from signer three
        RHS3 = INF
        for i in range(m):
            RHS3 = ec.add(RHS3, mult(pow(1, i), B3[i]))
        assert mult(beta31) == RHS3, 'signer three is cheating'

        # signer three checks values from signer one
        RHS1 = INF
        for i in range(m):
            RHS1 = ec.add(RHS1, mult(pow(3, i), B1[i]))
        assert mult(beta13) == RHS1, 'signer one is cheating'

        # commitment at the global sharing polynomial
        B: List[Point] = list()
        for i in range(m):
            B.append(ec.add(B1[i], B3[i]))

        # aggregated public nonce
        K = B[0]
        if not ec.has_square_y(K):
            # print('K has been negated')
            B[1] = ec.negate(B[1])  # pragma: no cover
            beta1 = ec.n - beta1  # pragma: no cover
            beta3 = ec.n - beta3  # pragma: no cover
            K = ec.negate(K)  # pragma: no cover

        # PHASE THREE: signature generation ###

        # partial signatures
        e = ssa._challenge(K[0], Q[0], mhd, ec, hf)
        gamma1 = (beta1 + e * alpha1) % ec.n
        gamma3 = (beta3 + e * alpha3) % ec.n

        # each participant verifies the other partial signatures

        # signer one
        RHS3 = ec.add(K, mult(e, Q))
        for i in range(1, m):
            temp = double_mult(pow(3, i), B[i], e * pow(3, i), A[i])
            RHS3 = ec.add(RHS3, temp)
        assert mult(gamma3) == RHS3, 'signer three is cheating'

        # signer three
        RHS1 = ec.add(K, mult(e, Q))
        for i in range(1, m):
            temp = double_mult(pow(1, i), B[i], e * pow(1, i), A[i])
            RHS1 = ec.add(RHS1, temp)
        assert mult(gamma1) == RHS1, 'signer one is cheating'

        # PHASE FOUR: aggregating the signature ###
        omega1 = 3 * mod_inv(3 - 1, ec.n) % ec.n
        omega3 = 1 * mod_inv(1 - 3, ec.n) % ec.n
        sigma = (gamma1 * omega1 + gamma3 * omega3) % ec.n

        sig = K[0], sigma

        self.assertTrue(ssa.verify(mhd, Q, sig))

        # ADDITIONAL PHASE: reconstruction of the private key ###
        secret = (omega1 * alpha1 + omega3 * alpha3) % ec.n
        self.assertIn((q1 + q2 + q3) % ec.n, (secret, ec.n - secret))
Example #9
0
    def test_musig(self):
        """testing 3-of-3 MuSig

            https://github.com/ElementsProject/secp256k1-zkp/blob/secp256k1-zkp/src/modules/musig/musig.md
            https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/
            https://eprint.iacr.org/2018/068
            https://blockstream.com/2018/01/23/musig-key-aggregation-schnorr-signatures.html
            https://medium.com/@snigirev.stepan/how-schnorr-signatures-may-improve-bitcoin-91655bcb4744
        """
        mhd = hf(b'message to sign').digest()

        # the signers private and public keys,
        # including both the curve Point and the BIP340-Schnorr public key
        q1 = 0x010101
        Q1 = mult(q1)
        Q1_x = Q1[0].to_bytes(ec.psize, 'big')
        q2 = 0x020202
        Q2 = mult(q2)
        Q2_x = Q2[0].to_bytes(ec.psize, 'big')
        q3 = 0x030303
        Q3 = mult(q3)
        Q3_x = Q3[0].to_bytes(ec.psize, 'big')

        # ready to sign: nonces and nonce commitments
        k1 = 1 + secrets.randbelow(ec.n - 1)
        K1 = mult(k1)
        k2 = 1 + secrets.randbelow(ec.n - 1)
        K2 = mult(k2)
        k3 = 1 + secrets.randbelow(ec.n - 1)
        K3 = mult(k3)

        #### (non interactive) key setup
        # this is MuSig core: the rest is just Schnorr signature additivity
        # 1. lexicographic sorting of public keys
        keys: List[bytes] = list()
        keys.append(Q1_x)
        keys.append(Q2_x)
        keys.append(Q3_x)
        keys.sort()
        # 2. coefficients
        prefix = b''.join(keys)
        a1 = int_from_bits(hf(prefix + Q1_x).digest(), ec.nlen) % ec.n
        a2 = int_from_bits(hf(prefix + Q2_x).digest(), ec.nlen) % ec.n
        a3 = int_from_bits(hf(prefix + Q3_x).digest(), ec.nlen) % ec.n
        # 3. aggregated public key
        Q = ec.add(double_mult(a1, Q1, a2, Q2), mult(a3, Q3))

        #### exchange {K_i} (interactive)

        #### computes s_i (non interactive)
        # WARNING:
        # the signers must exchange the nonces
        # commitments {K_i} before sharing {s_i}

        # same for all signers
        K = ec.add(ec.add(K1, K2), K3)
        r = K[0]
        e = ssa._challenge(r, Q[0], mhd, ec, hf)

        # first signer
        if not ec.has_square_y(K):
            k1 = ec.n - k1
        s1 = (k1 + e * a1 * q1) % ec.n

        # second signer
        if not ec.has_square_y(K):
            k2 = ec.n - k2
        s2 = (k2 + e * a2 * q2) % ec.n

        # third signer
        if not ec.has_square_y(K):
            k3 = ec.n - k3
        s3 = (k3 + e * a3 * q3) % ec.n

        #### exchange s_i (interactive)

        #### finalize signature (non interactive)
        s = (s1 + s2 + s3) % ec.n
        sig = r, s
        # check signature is valid
        self.assertTrue(ssa.verify(mhd, Q, sig))
Example #10
0
    def test_threshold(self):
        """testing 2-of-3 threshold signature (Pedersen secret sharing)"""

        # parameters
        t = 2
        H = second_generator(ec, hf)
        mhd = hf(b'message to sign').digest()

        ### FIRST PHASE: key pair generation ###

        # signer one acting as the dealer
        commits1: List[Point] = list()
        q1 = (1 + random.getrandbits(ec.nlen)) % ec.n
        q1_prime = (1 + random.getrandbits(ec.nlen)) % ec.n
        commits1.append(double_mult(q1_prime, H, q1))

        # sharing polynomials
        f1: List[int] = list()
        f1.append(q1)
        f1_prime: List[int] = list()
        f1_prime.append(q1_prime)
        for i in range(1, t):
            temp = (1 + random.getrandbits(ec.nlen)) % ec.n
            f1.append(temp)
            temp = (1 + random.getrandbits(ec.nlen)) % ec.n
            f1_prime.append(temp)
            commits1.append(double_mult(f1_prime[i], H, f1[i]))

        # shares of the secret
        alpha12 = 0  # share of q1 belonging to P2
        alpha12_prime = 0
        alpha13 = 0  # share of q1 belonging to P3
        alpha13_prime = 0
        for i in range(t):
            alpha12 += (f1[i] * pow(2, i)) % ec.n
            alpha12_prime += (f1_prime[i] * pow(2, i)) % ec.n

            alpha13 += (f1[i] * pow(3, i)) % ec.n
            alpha13_prime += (f1_prime[i] * pow(3, i)) % ec.n

        # player two verifies consistency of his share
        RHS = INF
        for i in range(t):
            RHS = ec.add(RHS, mult(pow(2, i), commits1[i]))
        assert double_mult(alpha12_prime, H,
                           alpha12) == RHS, 'player one is cheating'

        # player three verifies consistency of his share
        RHS = INF
        for i in range(t):
            RHS = ec.add(RHS, mult(pow(3, i), commits1[i]))
        assert double_mult(alpha13_prime, H,
                           alpha13) == RHS, 'player one is cheating'

        # signer two acting as the dealer
        commits2: List[Point] = list()
        q2 = (1 + random.getrandbits(ec.nlen)) % ec.n
        q2_prime = (1 + random.getrandbits(ec.nlen)) % ec.n
        commits2.append(double_mult(q2_prime, H, q2))

        # sharing polynomials
        f2: List[int] = list()
        f2.append(q2)
        f2_prime: List[int] = list()
        f2_prime.append(q2_prime)
        for i in range(1, t):
            temp = (1 + random.getrandbits(ec.nlen)) % ec.n
            f2.append(temp)
            temp = (1 + random.getrandbits(ec.nlen)) % ec.n
            f2_prime.append(temp)
            commits2.append(double_mult(f2_prime[i], H, f2[i]))

        # shares of the secret
        alpha21 = 0  # share of q2 belonging to P1
        alpha21_prime = 0
        alpha23 = 0  # share of q2 belonging to P3
        alpha23_prime = 0
        for i in range(t):
            alpha21 += (f2[i] * pow(1, i)) % ec.n
            alpha21_prime += (f2_prime[i] * pow(1, i)) % ec.n

            alpha23 += (f2[i] * pow(3, i)) % ec.n
            alpha23_prime += (f2_prime[i] * pow(3, i)) % ec.n

        # player one verifies consistency of his share
        RHS = INF
        for i in range(t):
            RHS = ec.add(RHS, mult(pow(1, i), commits2[i]))
        assert double_mult(alpha21_prime, H,
                           alpha21) == RHS, 'player two is cheating'

        # player three verifies consistency of his share
        RHS = INF
        for i in range(t):
            RHS = ec.add(RHS, mult(pow(3, i), commits2[i]))
        assert double_mult(alpha23_prime, H,
                           alpha23) == RHS, 'player two is cheating'

        # signer three acting as the dealer
        commits3: List[Point] = list()
        q3 = (1 + random.getrandbits(ec.nlen)) % ec.n
        q3_prime = (1 + random.getrandbits(ec.nlen)) % ec.n
        commits3.append(double_mult(q3_prime, H, q3))

        # sharing polynomials
        f3: List[int] = list()
        f3.append(q3)
        f3_prime: List[int] = list()
        f3_prime.append(q3_prime)
        for i in range(1, t):
            temp = (1 + random.getrandbits(ec.nlen)) % ec.n
            f3.append(temp)
            temp = (1 + random.getrandbits(ec.nlen)) % ec.n
            f3_prime.append(temp)
            commits3.append(double_mult(f3_prime[i], H, f3[i]))

        # shares of the secret
        alpha31 = 0  # share of q3 belonging to P1
        alpha31_prime = 0
        alpha32 = 0  # share of q3 belonging to P2
        alpha32_prime = 0
        for i in range(t):
            alpha31 += (f3[i] * pow(1, i)) % ec.n
            alpha31_prime += (f3_prime[i] * pow(1, i)) % ec.n

            alpha32 += (f3[i] * pow(2, i)) % ec.n
            alpha32_prime += (f3_prime[i] * pow(2, i)) % ec.n

        # player one verifies consistency of his share
        RHS = INF
        for i in range(t):
            RHS = ec.add(RHS, mult(pow(1, i), commits3[i]))
        assert double_mult(alpha31_prime, H,
                           alpha31) == RHS, 'player three is cheating'

        # player two verifies consistency of his share
        RHS = INF
        for i in range(t):
            RHS = ec.add(RHS, mult(pow(2, i), commits3[i]))
        assert double_mult(alpha32_prime, H,
                           alpha32) == RHS, 'player two is cheating'

        # shares of the secret key q = q1 + q2 + q3
        alpha1 = (alpha21 + alpha31) % ec.n
        alpha2 = (alpha12 + alpha32) % ec.n
        alpha3 = (alpha13 + alpha23) % ec.n
        for i in range(t):
            alpha1 += (f1[i] * pow(1, i)) % ec.n
            alpha2 += (f2[i] * pow(2, i)) % ec.n
            alpha3 += (f3[i] * pow(3, i)) % ec.n

        # it's time to recover the public key Q = Q1 + Q2 + Q3 = (q1 + q2 + q3)G
        A1: List[Point] = list()
        A2: List[Point] = list()
        A3: List[Point] = list()

        # each participant i = 1, 2, 3 shares Qi as follows

        # he broadcasts these values
        for i in range(t):
            A1.append(mult(f1[i]))
            A2.append(mult(f2[i]))
            A3.append(mult(f3[i]))

        # he checks the others' values
        # player one
        RHS2 = INF
        RHS3 = INF
        for i in range(t):
            RHS2 = ec.add(RHS2, mult(pow(1, i), A2[i]))
            RHS3 = ec.add(RHS3, mult(pow(1, i), A3[i]))
        assert mult(alpha21) == RHS2, 'player two is cheating'
        assert mult(alpha31) == RHS3, 'player three is cheating'

        # player two
        RHS1 = INF
        RHS3 = INF
        for i in range(t):
            RHS1 = ec.add(RHS1, mult(pow(2, i), A1[i]))
            RHS3 = ec.add(RHS3, mult(pow(2, i), A3[i]))
        assert mult(alpha12) == RHS1, 'player one is cheating'
        assert mult(alpha32) == RHS3, 'player three is cheating'

        # player three
        RHS1 = INF
        RHS2 = INF
        for i in range(t):
            RHS1 = ec.add(RHS1, mult(pow(3, i), A1[i]))
            RHS2 = ec.add(RHS2, mult(pow(3, i), A2[i]))
        assert mult(alpha13) == RHS1, 'player one is cheating'
        assert mult(alpha23) == RHS2, 'player two is cheating'

        A: List[Point] = list()  # commitment at the global sharing polynomial
        for i in range(t):
            A.append(ec.add(A1[i], ec.add(A2[i], A3[i])))

        Q = A[0]  # aggregated public key

        ### SECOND PHASE: generation of the nonces' pair ###
        # This phase follows exactly the key generation procedure
        # suppose that player one and three want to sign

        # signer one acting as the dealer
        commits1: List[Point] = list()
        k1 = (1 + random.getrandbits(ec.nlen)) % ec.n
        k1_prime = (1 + random.getrandbits(ec.nlen)) % ec.n
        commits1.append(double_mult(k1_prime, H, k1))

        # sharing polynomials
        f1: List[int] = list()
        f1.append(k1)
        f1_prime: List[int] = list()
        f1_prime.append(k1_prime)
        for i in range(1, t):
            temp = (1 + random.getrandbits(ec.nlen)) % ec.n
            f1.append(temp)
            temp = (1 + random.getrandbits(ec.nlen)) % ec.n
            f1_prime.append(temp)
            commits1.append(double_mult(f1_prime[i], H, f1[i]))

        # shares of the secret
        beta13 = 0  # share of k1 belonging to P3
        beta13_prime = 0
        for i in range(t):
            beta13 += (f1[i] * pow(3, i)) % ec.n
            beta13_prime += (f1_prime[i] * pow(3, i)) % ec.n

        # player three verifies consistency of his share
        RHS = INF
        for i in range(t):
            RHS = ec.add(RHS, mult(pow(3, i), commits1[i]))
        assert double_mult(beta13_prime, H,
                           beta13) == RHS, 'player one is cheating'

        # signer three acting as the dealer
        commits3: List[Point] = list()
        k3 = (1 + random.getrandbits(ec.nlen)) % ec.n
        k3_prime = (1 + random.getrandbits(ec.nlen)) % ec.n
        commits3.append(double_mult(k3_prime, H, k3))

        # sharing polynomials
        f3: List[int] = list()
        f3.append(k3)
        f3_prime: List[int] = list()
        f3_prime.append(k3_prime)
        for i in range(1, t):
            temp = (1 + random.getrandbits(ec.nlen)) % ec.n
            f3.append(temp)
            temp = (1 + random.getrandbits(ec.nlen)) % ec.n
            f3_prime.append(temp)
            commits3.append(double_mult(f3_prime[i], H, f3[i]))

        # shares of the secret
        beta31 = 0  # share of k3 belonging to P1
        beta31_prime = 0
        for i in range(t):
            beta31 += (f3[i] * pow(1, i)) % ec.n
            beta31_prime += (f3_prime[i] * pow(1, i)) % ec.n

        # player one verifies consistency of his share
        RHS = INF
        for i in range(t):
            RHS = ec.add(RHS, mult(pow(1, i), commits3[i]))
        assert double_mult(beta31_prime, H,
                           beta31) == RHS, 'player three is cheating'

        # shares of the secret nonce
        beta1 = beta31 % ec.n
        beta3 = beta13 % ec.n
        for i in range(t):
            beta1 += (f1[i] * pow(1, i)) % ec.n
            beta3 += (f3[i] * pow(3, i)) % ec.n

        # it's time to recover the public nonce
        B1: List[Point] = list()
        B3: List[Point] = list()

        # each participant i = 1, 3 shares Qi as follows

        # he broadcasts these values
        for i in range(t):
            B1.append(mult(f1[i]))
            B3.append(mult(f3[i]))

        # he checks the others' values
        # player one
        RHS3 = INF
        for i in range(t):
            RHS3 = ec.add(RHS3, mult(pow(1, i), B3[i]))
        assert mult(beta31) == RHS3, 'player three is cheating'

        # player three
        RHS1 = INF
        for i in range(t):
            RHS1 = ec.add(RHS1, mult(pow(3, i), B1[i]))
        assert mult(beta13) == RHS1, 'player one is cheating'

        B: List[Point] = list()  # commitment at the global sharing polynomial
        for i in range(t):
            B.append(ec.add(B1[i], B3[i]))

        K = B[0]  # aggregated public nonce
        if not ec.has_square_y(K):
            beta1 = ec.n - beta1
            beta3 = ec.n - beta3

        ### PHASE THREE: signature generation ###

        # partial signatures
        e = ssa._challenge(K[0], Q[0], mhd, ec, hf)
        gamma1 = (beta1 + e * alpha1) % ec.n
        gamma3 = (beta3 + e * alpha3) % ec.n

        # each participant verifies the other partial signatures

        # player one
        if ec.has_square_y(K):
            RHS3 = ec.add(K, mult(e, Q))
            for i in range(1, t):
                temp = double_mult(pow(3, i), B[i], e * pow(3, i), A[i])
                RHS3 = ec.add(RHS3, temp)
        else:
            RHS3 = ec.add(ec.opposite(K), mult(e, Q))
            for i in range(1, t):
                temp = double_mult(pow(3, i), ec.opposite(B[i]), e * pow(3, i),
                                   A[i])
                RHS3 = ec.add(RHS3, temp)

        assert mult(gamma3) == RHS3, 'player three is cheating'

        # player three
        if ec.has_square_y(K):
            RHS1 = ec.add(K, mult(e, Q))
            for i in range(1, t):
                temp = double_mult(pow(1, i), B[i], e * pow(1, i), A[i])
                RHS1 = ec.add(RHS1, temp)
        else:
            RHS1 = ec.add(ec.opposite(K), mult(e, Q))
            for i in range(1, t):
                temp = double_mult(pow(1, i), ec.opposite(B[i]), e * pow(1, i),
                                   A[i])
                RHS1 = ec.add(RHS1, temp)

        assert mult(gamma1) == RHS1, 'player two is cheating'

        ### PHASE FOUR: aggregating the signature ###
        omega1 = 3 * mod_inv(3 - 1, ec.n) % ec.n
        omega3 = 1 * mod_inv(1 - 3, ec.n) % ec.n
        sigma = (gamma1 * omega1 + gamma3 * omega3) % ec.n

        sig = K[0], sigma

        self.assertTrue(ssa.verify(mhd, Q, sig))

        ### ADDITIONAL PHASE: reconstruction of the private key ###
        secret = (omega1 * alpha1 + omega3 * alpha3) % ec.n
        self.assertEqual((q1 + q2 + q3) % ec.n, secret)
Example #11
0
k1 = int.from_bytes(k_bytes, 'big') % ec.n
assert k1 != 0

K1 = mult(k1, ec.G)

s1 = (k1 - h1 * q) % ec.n
# if s1 == 0 (extremely unlikely for large ec.n) go back to a different ephemeral key
assert s1 != 0

print("     r:", hex(K1[0]))
print("    s1:", hex(s1))

print("*** Signature Verification")
minush1 = -h1 % ec.n
V = mult(minush1, Q)
V = ec.add(K1, V)
print(V == mult(s1, ec.G))

print("\n*** Another message")
msg2 = "and Paolo is right to be afraid"
print(msg2)

print("*** Hash of the message")
h_bytes = hf(msg2.encode()).digest()
# hash(msg) must be transformed into an integer modulo ec.n:
h2 = int.from_bytes(h_bytes, 'big') % ec.n
assert h2 != 0
print("    h2:", hex(h2))

print("\n*** Signature")
k2 = k1  #very bad! Never reuse the same ephemeral key!!!