def test_forge_hash_sig(self):
        """forging valid hash signatures"""

        ec = secp256k1
        # see https://twitter.com/pwuille/status/1063582706288586752
        # Satoshi's key
        P = point_from_octets(
            secp256k1,
            "0311db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c"
        )

        u1 = 1
        u2 = 2  # pick them at will
        R = double_mult(ec, u1, ec.G, u2, P)
        r = R[0] % ec.n
        u2inv = mod_inv(u2, ec.n)
        s = r * u2inv % ec.n
        sig = r, s
        e = s * u1 % ec.n
        dsa._verhlp(ec, e, P, sig)

        u1 = 1234567890
        u2 = 987654321  # pick them at will
        R = double_mult(ec, u1, ec.G, u2, P)
        r = R[0] % ec.n
        u2inv = mod_inv(u2, ec.n)
        s = r * u2inv % ec.n
        sig = r, s
        e = s * u1 % ec.n
        dsa._verhlp(ec, e, P, sig)
Exemplo n.º 2
0
def _pubkey_recovery(ec: Curve, c: int, sig: ECDS) -> Sequence[Point]:
    """Private function provided for testing purposes only."""
    # ECDSA public key recovery operation according to SEC 1
    # http://www.secg.org/sec1-v2.pdf
    # See SEC 1 v.2 section 4.1.6

    r, s = _to_sig(ec, sig)

    # precomputations
    r1 = mod_inv(r, ec.n)
    r1s = r1 * s
    r1e = -r1 * c
    keys: Sequence[Point] = list()
    for j in range(ec.h):  # 1
        x = r + j * ec.n  # 1.1
        try:  #TODO: check test reporting 1, 2, 3, or 4 keys
            x %= ec._p
            R = x, ec.y_odd(x, 1)  # 1.2, 1.3, and 1.4
            # skip 1.5: in this function, c is an input
            Q = double_mult(ec, r1s, R, r1e, ec.G)  # 1.6.1
            if Q[1] != 0 and _verhlp(ec, c, Q, sig):  # 1.6.2
                keys.append(Q)
            R = ec.opposite(R)  # 1.6.3
            Q = double_mult(ec, r1s, R, r1e, ec.G)
            if Q[1] != 0 and _verhlp(ec, c, Q, sig):  # 1.6.2
                keys.append(Q)  # 1.6.2
        except Exception:  # R is not a curve point
            pass
    return keys
Exemplo n.º 3
0
def test_forge_hash_sig() -> None:
    """forging valid hash signatures"""

    ec = CURVES["secp256k1"]

    # see https://twitter.com/pwuille/status/1063582706288586752
    # Satoshi's key
    key = "03 11db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c"
    Q = point_from_octets(key, ec)

    # pick u1 and u2 at will
    u1 = 1
    u2 = 2
    R = double_mult(u2, Q, u1, ec.G, ec)
    r = R[0] % ec.n
    u2inv = mod_inv(u2, ec.n)
    s = r * u2inv % ec.n
    e = s * u1 % ec.n
    dsa.__assert_as_valid(e, (Q[0], Q[1], 1), r, s, ec)

    # pick u1 and u2 at will
    u1 = 1234567890
    u2 = 987654321
    R = double_mult(u2, Q, u1, ec.G, ec)
    r = R[0] % ec.n
    u2inv = mod_inv(u2, ec.n)
    s = r * u2inv % ec.n
    e = s * u1 % ec.n
    dsa.__assert_as_valid(e, (Q[0], Q[1], 1), r, s, ec)
def sign(msg: bytes,
                   k: List[int],
                   sign_key_idx: List[int],
                   sign_keys: List[int],
                   pubk_rings: Dict[int, List[Point]]) -> Tuple[bytes, Dict[int, List[int]]]:
    """ Borromean ring signature - signing algorithm

        https://github.com/ElementsProject/borromean-signatures-writeup
        https://github.com/Blockstream/borromean_paper/blob/master/borromean_draft_0.01_9ade1e49.pdf

        inputs:
        - msg: msg to be signed (bytes)
        - sign_key_idx: list of indexes representing each signing key per ring
        - sign_keys: list containing the whole set of signing keys (one per ring)
        - pubk_rings: dictionary of lists where internal lists represent single rings of pubkeys
    """

    s: Dict[int, List[int]] = defaultdict(list)
    e: Dict[int, List[int]] = defaultdict(list)
    m = _get_msg_format(msg, pubk_rings)
    e0bytes = m
    ring_size = len(pubk_rings)
    # step 1
    for i in range(ring_size):
        keys_size = len(pubk_rings[i])
        s[i] = [0]*keys_size
        e[i] = [0]*keys_size
        j_star = sign_key_idx[i]
        start_idx = (j_star + 1) % keys_size
        R = octets_from_point(ec, mult(ec, k[i], ec.G), True)
        if start_idx != 0:
            for j in range(start_idx, keys_size):
                s[i][j] = random.getrandbits(256)
                e[i][j] = int_from_bits(ec, _hash(m, R, i, j))
                assert 0 < e[i][j] < ec.n, "sign fail: how did you do that?!?"
                T = double_mult(ec, s[i][j], ec.G, -e[i][j], pubk_rings[i][j])
                R = octets_from_point(ec, T, True)
        e0bytes += R
    e0 = hf(e0bytes).digest()
    # step 2
    for i in range(ring_size):
        e[i][0] = int_from_bits(ec, _hash(m, e0, i, 0))
        assert 0 < e[i][0] < ec.n, "sign fail: how did you do that?!?"
        j_star = sign_key_idx[i]
        for j in range(1, j_star+1):
            s[i][j-1] = random.getrandbits(256)
            T = double_mult(ec, s[i][j-1], ec.G, -e[i][j-1], pubk_rings[i][j-1])
            R = octets_from_point(ec, T, True)
            e[i][j] = int_from_bits(ec, _hash(m, R, i, j))
            assert 0 < e[i][j] < ec.n, "sign fail: how did you do that?!?"
        s[i][j_star] = k[i] + sign_keys[i]*e[i][j_star]
    return e0, s
Exemplo n.º 5
0
def test_assorted_mult() -> None:
    ec = ec23_31
    H = second_generator(ec)
    for k1 in range(-ec.n + 1, ec.n):
        K1 = mult(k1, ec.G, ec)
        for k2 in range(ec.n):
            K2 = mult(k2, H, ec)

            shamir = double_mult(k1, ec.G, k2, ec.G, ec)
            assert shamir == mult(k1 + k2, ec.G, ec)

            shamir = double_mult(k1, INF, k2, H, ec)
            assert ec.is_on_curve(shamir)
            assert shamir == K2

            shamir = double_mult(k1, ec.G, k2, INF, ec)
            assert ec.is_on_curve(shamir)
            assert shamir == K1

            shamir = double_mult(k1, ec.G, k2, H, ec)
            assert ec.is_on_curve(shamir)
            K1K2 = ec.add(K1, K2)
            assert K1K2 == shamir

            k3 = 1 + secrets.randbelow(ec.n - 1)
            K3 = mult(k3, ec.G, ec)
            K1K2K3 = ec.add(K1K2, K3)
            assert ec.is_on_curve(K1K2K3)
            boscoster = multi_mult([k1, k2, k3], [ec.G, H, ec.G], ec)
            assert ec.is_on_curve(boscoster)
            assert K1K2K3 == boscoster, k3

            k4 = 1 + secrets.randbelow(ec.n - 1)
            K4 = mult(k4, H, ec)
            K1K2K3K4 = ec.add(K1K2K3, K4)
            assert ec.is_on_curve(K1K2K3K4)
            points = [ec.G, H, ec.G, H]
            boscoster = multi_mult([k1, k2, k3, k4], points, ec)
            assert ec.is_on_curve(boscoster)
            assert K1K2K3K4 == boscoster, k4
            assert K1K2K3 == multi_mult([k1, k2, k3, 0], points, ec)
            assert K1K2 == multi_mult([k1, k2, 0, 0], points, ec)
            assert K1 == multi_mult([k1, 0, 0, 0], points, ec)
            assert INF == multi_mult([0, 0, 0, 0], points, ec)

    err_msg = "mismatch between number of scalars and points: "
    with pytest.raises(ValueError, match=err_msg):
        multi_mult([k1, k2, k3, k4], [ec.G, H, ec.G], ec)
def _verify(msg: bytes,
                      e0: bytes,
                      s: Dict[int, List[int]],
                      pubk_rings: Dict[int, List[Point]]) -> bool:

    ring_size = len(pubk_rings)
    m = _get_msg_format(msg, pubk_rings)
    e: Dict[int, List[int]] = defaultdict(list)
    e0bytes = m
    for i in range(ring_size):
        keys_size = len(pubk_rings[i])
        e[i] = [0]*keys_size
        e[i][0] = int_from_bits(ec, _hash(m, e0, i, 0))
        assert e[i][0] != 0, "invalid sig: how did you do that?!?"
        R = b'\0x00'
        for j in range(keys_size):
            T = double_mult(ec, s[i][j], ec.G, -e[i][j], pubk_rings[i][j])
            R = octets_from_point(ec, T, True)
            if j != len(pubk_rings[i])-1:
                e[i][j+1] = int_from_bits(ec, _hash(m, R, i, j+1))
                assert e[i][j+1] != 0, "invalid sig: how did you do that?!?"
            else:
                e0bytes += R
    e0_prime = hf(e0bytes).digest()
    return e0_prime == e0
Exemplo n.º 7
0
 def test_shamir(self):
     ec = ec23_31
     for k1 in range(ec.n):
         for k2 in range(ec.n):
             shamir = double_mult(ec, k1, ec.G, k2, ec.G)
             std = ec.add(mult(ec, k1, ec.G),
                          mult(ec, k2, ec.G))
             self.assertEqual(shamir, std)
             shamir = double_mult(ec, k1, Inf, k2, ec.G)
             std = ec.add(mult(ec, k1, Inf),
                          mult(ec, k2, ec.G))
             self.assertEqual(shamir, std)
             shamir = double_mult(ec, k1, ec.G, k2, Inf)
             std = ec.add(mult(ec, k1, ec.G),
                          mult(ec, k2, Inf))
             self.assertEqual(shamir, std)
def _pubkey_recovery(ec: Curve, hf, e: int, sig: ECSS) -> Point:
    # Private function provided for testing purposes only.

    r, s = _to_sig(ec, sig)

    K = r, ec.y_quadratic_residue(r, True)
    # FIXME y_quadratic_residue in Jacobian coordinates?

    if e == 0:
        raise ValueError("invalid (zero) challenge e")
    e1 = mod_inv(e, ec.n)
    P = double_mult(ec, e1 * s, ec.G, -e1, K)
    assert P[1] != 0, "how did you do that?!?"
    return P
Exemplo n.º 9
0
    def test_second_generator(self):
        """
        important remark on secp256-zkp prefix for compressed encoding of the second generator:
        https://github.com/garyyu/rust-secp256k1-zkp/wiki/Pedersen-Commitment
        """

        ec = secp256k1
        hf = sha256

        H = pedersen.second_generator(ec, hf)
        self.assertEqual(H, point_from_octets(ec, '0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0'))

        # 0*G + 1*H
        T = double_mult(ec, 1, H, 0)
        self.assertEqual(T, point_from_octets(ec, '0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0'))

        # 0*G + 2*H
        T = double_mult(ec, 2, H, 0)
        self.assertEqual(T, point_from_octets(ec, '03fad265e0a0178418d006e247204bcf42edb6b92188074c9134704c8686eed37a'))
        T = mult(ec, 2, H)
        self.assertEqual(T, point_from_octets(ec, '03fad265e0a0178418d006e247204bcf42edb6b92188074c9134704c8686eed37a'))

        # 0*G + 3*H
        T = double_mult(ec, 3, H, 0)
        self.assertEqual(T, point_from_octets(ec, '025ef47fcde840a435e831bbb711d466fc1ee160da3e15437c6c469a3a40daacaa'))
        T = mult(ec, 3, H)
        self.assertEqual(T, point_from_octets(ec, '025ef47fcde840a435e831bbb711d466fc1ee160da3e15437c6c469a3a40daacaa'))

        # 1*G+0*H
        T = double_mult(ec, 0, H, 1)
        self.assertEqual(T, point_from_octets(ec, '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'))
        T = mult(ec, 1)
        self.assertEqual(T, point_from_octets(ec, '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'))

        # 2*G+0*H
        T = double_mult(ec, 0, H, 2)
        self.assertEqual(T, point_from_octets(ec, '02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5'))
        T = mult(ec, 2)
        self.assertEqual(T, point_from_octets(ec, '02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5'))

        # 3*G+0*H
        T = double_mult(ec, 0, H, 3)
        self.assertEqual(T, point_from_octets(ec, '02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9'))
        T = mult(ec, 3)
        self.assertEqual(T, point_from_octets(ec, '02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9'))

        # 0*G+5*H
        T = double_mult(ec, 5, H, 0)
        self.assertEqual(T, point_from_octets(ec, '039e431be0851721f9ce35cc0f718fce7d6d970e3ddd796643d71294d7a09b554e'))
        T = mult(ec, 5, H)
        self.assertEqual(T, point_from_octets(ec, '039e431be0851721f9ce35cc0f718fce7d6d970e3ddd796643d71294d7a09b554e'))

        # 0*G-5*H
        T = double_mult(ec, -5, H, 0)
        self.assertEqual(T, point_from_octets(ec, '029e431be0851721f9ce35cc0f718fce7d6d970e3ddd796643d71294d7a09b554e'))
        T = mult(ec, -5, H)
        self.assertEqual(T, point_from_octets(ec, '029e431be0851721f9ce35cc0f718fce7d6d970e3ddd796643d71294d7a09b554e'))

        # 1*G-5*H
        U = double_mult(ec, -5, H, 1)
        self.assertEqual(U, point_from_octets(ec, '02b218ddacb34d827c71760e601b41d309bc888cf7e3ab7cc09ec082b645f77e5a'))
        U = ec.add(ec.G, T)  # reusing previous T value
        self.assertEqual(U, point_from_octets(ec, '02b218ddacb34d827c71760e601b41d309bc888cf7e3ab7cc09ec082b645f77e5a'))

        H = pedersen.second_generator(secp256r1, hf)
        H = pedersen.second_generator(secp384r1, sha384)
Exemplo n.º 10
0
def commit(r: int, v: int, ec: Curve, hf) -> Point:
    """Return rG + vH, with H being second (NUMS) generator of the curve"""
    H = second_generator(ec, hf)
    Q = double_mult(ec, r, ec.G, v, H)
    assert Q[1] != 0, "how did you do that?!?"
    return Q
Exemplo n.º 11
0
def test_threshold() -> None:
    "testing 2-of-3 threshold signature (Pedersen secret sharing)"

    ec = CURVES["secp256k1"]

    # parameters
    m = 2
    H = second_generator(ec)

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

    # 1.1 signer one acting as the dealer
    commits1: List[Point] = []
    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] = []
    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] = []
    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] = []
    A2: List[Point] = []
    A3: List[Point] = []
    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] = []
    for i in range(m):
        A.append(ec.add(A1[i], ec.add(A2[i], A3[i])))

    # aggregated public key
    Q = A[0]
    if Q[1] % 2:
        # 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

    msg = "message to sign"

    # 2.1 signer one acting as the dealer
    commits1 = []
    k1 = ssa.det_nonce(msg, q1, ec, hf)
    k1_prime = ssa.det_nonce(msg, 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 = []
    k3 = ssa.det_nonce(msg, q3, ec, hf)
    k3_prime = ssa.det_nonce(msg, 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] = []
    B3: List[Point] = []
    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] = []
    for i in range(m):
        B.append(ec.add(B1[i], B3[i]))

    # aggregated public nonce
    K = B[0]
    if K[1] % 2:
        # 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(msg, Q[0], K[0], 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

    assert ssa.verify(msg, Q[0], sig)

    # ADDITIONAL PHASE: reconstruction of the private key ###
    secret = (omega1 * alpha1 + omega3 * alpha3) % ec.n
    assert (q1 + q2 + q3) % ec.n in (secret, ec.n - secret)
Exemplo n.º 12
0
def test_musig() -> None:
    """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
    """

    ec = CURVES["secp256k1"]

    m = 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_int = ssa.gen_keys()
    x_Q1 = x_Q1_int.to_bytes(ec.psize, "big")

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

    q3, x_Q3_int = ssa.gen_keys()
    x_Q3 = x_Q3_int.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] = []
    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 Q[1] % 2:
        # 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 K[1] % 2:
        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(m, Q[0], r, ec, hf)
    s_1 = (k1 + e * a1 * q1) % ec.n
    s_2 = (k2 + e * a2 * q2) % ec.n
    s3 = (k3 + e * a3 * q3) % ec.n

    # exchange s_i (interactive)

    # finalize signature (non interactive)
    s = (s_1 + s_2 + s3) % ec.n
    sig = r, s
    # check signature is valid
    ssa._assert_as_valid(m, Q[0], sig, ec, hf)
Exemplo n.º 13
0
k1 = int_from_bits(k1_bytes, ec.nlen) % ec.n
assert 0 < k1 < ec.n, "Invalid ephemeral key"
print(f"eph k: {hex(k1).upper()}")

K1 = mult(k1, ec.G)
c1 = _challenge(msg1, Q[0], K1[0], ec, sha256)
print(f"   c1: {hex(c1).upper()}")

print("2. Sign message")
r1 = K1[0]
s1 = (k1 + c1 * q) % ec.n
print(f"   r1: {hex(r1).upper()}")
print(f"   s1: {hex(s1).upper()}")

print("3. Verify signature")
K = double_mult(-c1, Q, s1, ec.G)
print(K[0] == r1)

print("\n0. Another message to sign")
orig_msg2 = "and Paolo is right to be afraid"
msg2 = sha256(orig_msg2.encode()).digest()
print(msg2.hex().upper())

print("\n*** Ephemeral key and challenge")
# ephemeral key k must be kept secret and never reused !!!!!
k2 = k1
print(f"eph k: {hex(k2).upper()}")

K2 = mult(k2, ec.G)
c2 = _challenge(msg2, Q[0], K2[0], ec, sha256)
print(f"   c2: {hex(c2).upper()}")
Exemplo n.º 14
0
import time

from btclib.curve import mult, double_mult
from btclib.curves import secp256k1

random.seed(42)

ec = secp256k1

# 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(ec, q, ec.G))

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

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

print(elapsed2 / elapsed1)
Exemplo n.º 15
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
        """
        ec = secp256k1
        M = hf('message to sign'.encode()).digest()

        # key setup is not interactive

        # first signer
        q1 = int_from_octets(
            '0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d92ad1d')
        Q1 = mult(ec, q1, ec.G)
        k1 = rfc6979(ec, hf, M, q1)
        K1 = mult(ec, k1, ec.G)

        # second signer
        q2 = int_from_octets(
            '0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d')
        Q2 = mult(ec, q2, ec.G)
        k2 = rfc6979(ec, hf, M, q2)
        K2 = mult(ec, k2, ec.G)

        # third signer
        q3 = int_from_octets(
            '0c28fca386c7aff7600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d')
        Q3 = mult(ec, q3, ec.G)
        k3 = rfc6979(ec, hf, M, q3)
        K3 = mult(ec, k3, ec.G)

        # this is MuSig core: the rest is just Schnorr signature additivity
        L: List[Point] = list()  # multiset of public keys
        L.append(octets_from_point(ec, Q1, False))
        L.append(octets_from_point(ec, Q2, False))
        L.append(octets_from_point(ec, Q3, False))
        L.sort()  # using lexicographic ordering
        L_brackets = b''
        for i in range(len(L)):
            L_brackets += L[i]
        h1 = hf(L_brackets + octets_from_point(ec, Q1, False)).digest()
        a1 = int_from_bits(ec, h1)
        h2 = hf(L_brackets + octets_from_point(ec, Q2, False)).digest()
        a2 = int_from_bits(ec, h2)
        h3 = hf(L_brackets + octets_from_point(ec, Q3, False)).digest()
        a3 = int_from_bits(ec, h3)
        # aggregated public key
        Q = ec.add(double_mult(ec, a1, Q1, a2, Q2), mult(ec, a3, Q3))
        Q_bytes = octets_from_point(ec, Q, True)

        ########################
        # interactive signature: exchange K, compute s
        # WARNING: the signers should exchange commitments to the public
        #          nonces before sending the nonces themselves

        # first signer
        # K, r_bytes, and e as calculated by any signer
        # are the same as the ones by the other signers
        K = ec.add(ec.add(K1, K2), K3)
        r_bytes = K[0].to_bytes(32, byteorder="big")
        e = int_from_bits(ec, hf(r_bytes + Q_bytes + M).digest())
        if legendre_symbol(K[1], ec._p) != 1:
            # no need to actually change K[1], as it is not used anymore
            # let's fix k1 instead, as it is used later
            # note that all other signers will change their k too
            k1 = ec.n - k1
        s1 = (k1 + e * a1 * q1) % ec.n

        # second signer
        # K, r_bytes, and e as calculated by any signer
        # are the same as the ones by the other signers
        if legendre_symbol(K[1], ec._p) != 1:
            # no need to actually change K[1], as it is not used anymore
            # let's fix k2 instead, as it is used later
            # note that all other signers will change their k too
            k2 = ec.n - k2
        s2 = (k2 + e * a2 * q2) % ec.n

        # third signer
        # K, r_bytes, and e as calculated by any signer
        # are the same as the ones by the other signers
        if legendre_symbol(K[1], ec._p) != 1:
            # no need to actually change K[1], as it is not used anymore
            # let's fix k3 instead, as it is used later
            # note that all other signers will change their k too
            k3 = ec.n - k3
        s3 = (k3 + e * a3 * q3) % ec.n

        ############################################
        # interactive signature: exchange signatures
        # combine all (K[0], s) signatures into a single signature
        # anyone can do the following
        sig = K[0], (s1 + s2 + s3) % ec.n

        self.assertTrue(ssa.verify(ec, hf, M, Q, sig))
Exemplo n.º 16
0
    def test_threshold(self):
        """testing 2-of-3 threshold signature (Pedersen secret sharing)"""

        ec = secp256k1
        # parameters
        t = 2
        H = second_generator(ec, hf)
        msg = hf('message to sign'.encode()).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(ec, q1, ec.G, q1_prime, H))

        # 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(ec, f1[i], ec.G, f1_prime[i], H))

        # 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 = 1, 0
        for i in range(t):
            RHS = ec.add(RHS, mult(ec, pow(2, i), commits1[i]))
        assert double_mult(ec, alpha12, ec.G, alpha12_prime,
                           H) == RHS, 'player one is cheating'

        # player three verifies consistency of his share
        RHS = 1, 0
        for i in range(t):
            RHS = ec.add(RHS, mult(ec, pow(3, i), commits1[i]))
        assert double_mult(ec, alpha13, ec.G, alpha13_prime,
                           H) == 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(ec, q2, ec.G, q2_prime, H))

        # 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(ec, f2[i], ec.G, f2_prime[i], H))

        # 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 = 1, 0
        for i in range(t):
            RHS = ec.add(RHS, mult(ec, pow(1, i), commits2[i]))
        assert double_mult(ec, alpha21, ec.G, alpha21_prime,
                           H) == RHS, 'player two is cheating'

        # player three verifies consistency of his share
        RHS = 1, 0
        for i in range(t):
            RHS = ec.add(RHS, mult(ec, pow(3, i), commits2[i]))
        assert double_mult(ec, alpha23, ec.G, alpha23_prime,
                           H) == 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(ec, q3, ec.G, q3_prime, H))

        # 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(ec, f3[i], ec.G, f3_prime[i], H))

        # 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 = 1, 0
        for i in range(t):
            RHS = ec.add(RHS, mult(ec, pow(1, i), commits3[i]))
        assert double_mult(ec, alpha31, ec.G, alpha31_prime,
                           H) == RHS, 'player three is cheating'

        # player two verifies consistency of his share
        RHS = 1, 0
        for i in range(t):
            RHS = ec.add(RHS, mult(ec, pow(2, i), commits3[i]))
        assert double_mult(ec, alpha32, ec.G, alpha32_prime,
                           H) == 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(ec, f1[i], ec.G))
            A2.append(mult(ec, f2[i], ec.G))
            A3.append(mult(ec, f3[i], ec.G))

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

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

        # player three
        RHS1 = 1, 0
        RHS2 = 1, 0
        for i in range(t):
            RHS1 = ec.add(RHS1, mult(ec, pow(3, i), A1[i]))
            RHS2 = ec.add(RHS2, mult(ec, pow(3, i), A2[i]))
        assert mult(ec, alpha13, ec.G) == RHS1, 'player one is cheating'
        assert mult(ec, alpha23, ec.G) == 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(ec, k1, ec.G, k1_prime, H))

        # 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(ec, f1[i], ec.G, f1_prime[i], H))

        # 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 = 1, 0
        for i in range(t):
            RHS = ec.add(RHS, mult(ec, pow(3, i), commits1[i]))
        assert double_mult(ec, beta13, ec.G, beta13_prime,
                           H) == 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(ec, k3, ec.G, k3_prime, H))

        # 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(ec, f3[i], ec.G, f3_prime[i], H))

        # 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 = 1, 0
        for i in range(t):
            RHS = ec.add(RHS, mult(ec, pow(1, i), commits3[i]))
        assert double_mult(ec, beta31, ec.G, beta31_prime,
                           H) == 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(ec, f1[i], ec.G))
            B3.append(mult(ec, f3[i], ec.G))

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

        # player three
        RHS1 = 1, 0
        for i in range(t):
            RHS1 = ec.add(RHS1, mult(ec, pow(3, i), B1[i]))
        assert mult(ec, beta13, ec.G) == 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 legendre_symbol(K[1], ec._p) != 1:
            beta1 = ec.n - beta1
            beta3 = ec.n - beta3

        ### PHASE THREE: signature generation ###

        # partial signatures
        ebytes = K[0].to_bytes(32, byteorder="big")
        ebytes += octets_from_point(ec, Q, True)
        ebytes += msg
        e = int_from_bits(ec, hf(ebytes).digest())
        gamma1 = (beta1 + e * alpha1) % ec.n
        gamma3 = (beta3 + e * alpha3) % ec.n

        # each participant verifies the other partial signatures

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

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

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

        assert mult(ec, gamma1, ec.G) == 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(ec, hf, msg, Q, sig))

        ### ADDITIONAL PHASE: reconstruction of the private key ###
        secret = (omega1 * alpha1 + omega3 * alpha3) % ec.n
        self.assertEqual((q1 + q2 + q3) % ec.n, secret)
Exemplo n.º 17
0
def test_double_mult() -> None:
    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
Exemplo n.º 18
0
    def test_musig(self):
        """ testing 3-of-3 MuSig
        
            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
        """
        ec = secp256k1
        L: List[Point] = list()  # multiset of public keys
        M = hf('message to sign'.encode()).digest()

        # first signer
        q1 = int_from_octets(
            '0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d92ad1d')
        Q1 = mult(ec, q1, ec.G)
        L.append(octets_from_point(ec, Q1, False))

        # ephemeral private nonce
        k1 = 0x012a2a833eac4e67e06611aba01345b85cdd4f5ad44f72e369ef0dd640424dbb
        K1 = mult(ec, k1, ec.G)
        K1_x = K1[0]
        if legendre_symbol(K1[1], ec._p) != 1:
            k1 = ec.n - k1
            K1 = K1_x, ec.y_quadratic_residue(K1_x, True)
            #K1 = mult(ec, k1, ec.G)

        # second signer
        q2 = int_from_octets(
            '0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d')
        Q2 = mult(ec, q2, ec.G)
        L.append(octets_from_point(ec, Q2, False))

        k2 = 0x01a2a0d3eac4e67e06611aba01345b85cdd4f5ad44f72e369ef0dd640424dbdb
        K2 = mult(ec, k2, ec.G)
        K2_x = K2[0]
        if legendre_symbol(K2[1], ec._p) != 1:
            k2 = ec.n - k2
            K2 = K2_x, ec.y_quadratic_residue(K2_x, True)
            #K2 = mult(ec, k2, ec.G)

        # third signer
        q3 = random.getrandbits(ec.nlen) % ec.n
        Q3 = mult(ec, q3, ec.G)
        while Q3 == None:  # plausible only for small (test) cardinality groups
            q3 = random.getrandbits(ec.nlen) % ec.n
            Q3 = mult(ec, q3, ec.G)
        L.append(octets_from_point(ec, Q3, False))

        k3 = random.getrandbits(ec.nlen) % ec.n
        K3 = mult(ec, k3, ec.G)
        while K3 == None:  # plausible only for small (test) cardinality groups
            k3 = random.getrandbits(ec.nlen) % ec.n
            K3 = mult(ec, k3, ec.G)
        K3_x = K3[0]
        if legendre_symbol(K3[1], ec._p) != 1:
            k3 = ec.n - k3
            K3 = K3_x, ec.y_quadratic_residue(K3_x, True)
            #K3 = mult(ec, k3, ec.G)

        L.sort()  # using lexicographic ordering
        L_brackets = b''
        for i in range(len(L)):
            L_brackets += L[i]

        h1 = hf(L_brackets + octets_from_point(ec, Q1, False)).digest()
        a1 = int_from_bits(ec, h1)
        h2 = hf(L_brackets + octets_from_point(ec, Q2, False)).digest()
        a2 = int_from_bits(ec, h2)
        h3 = hf(L_brackets + octets_from_point(ec, Q3, False)).digest()
        a3 = int_from_bits(ec, h3)
        # aggregated public key
        Q_All = double_mult(ec, a1, Q1, a2, Q2)
        Q_All = ec.add(Q_All, mult(ec, a3, Q3))
        Q_All_bytes = octets_from_point(ec, Q_All, True)

        ########################
        # exchange K_x, compute s
        # WARNING: the signers should exchange commitments to the public
        #          nonces before sending the nonces themselves

        # first signer use K2_x and K3_x
        y = ec.y_quadratic_residue(K2_x, True)
        K2_recovered = (K2_x, y)
        y = ec.y_quadratic_residue(K3_x, True)
        K3_recovered = (K3_x, y)
        K1_All = ec.add(ec.add(K1, K2_recovered), K3_recovered)
        if legendre_symbol(K1_All[1], ec._p) != 1:
            # no need to actually change K1_All[1], as it is not used anymore
            # let's fix k1 instead, as it is used later
            k1 = ec.n - k1
        K1_All0_bytes = K1_All[0].to_bytes(32, byteorder="big")
        h1 = hf(K1_All0_bytes + Q_All_bytes + M).digest()
        c1 = int_from_bits(ec, h1)
        assert 0 < c1 and c1 < ec.n, "sign fail"
        s1 = (k1 + c1 * a1 * q1) % ec.n

        # second signer use K1_x and K3_x
        y = ec.y_quadratic_residue(K1_x, True)
        K1_recovered = (K1_x, y)
        y = ec.y_quadratic_residue(K3_x, True)
        K3_recovered = (K3_x, y)
        K2_All = ec.add(ec.add(K2, K1_recovered), K3_recovered)
        if legendre_symbol(K2_All[1], ec._p) != 1:
            # no need to actually change K2_All[1], as it is not used anymore
            # let's fix k2 instead, as it is used later
            k2 = ec.n - k2
        K2_All0_bytes = K2_All[0].to_bytes(32, byteorder="big")
        h2 = hf(K2_All0_bytes + Q_All_bytes + M).digest()
        c2 = int_from_bits(ec, h2)
        assert 0 < c2 and c2 < ec.n, "sign fail"
        s2 = (k2 + c2 * a2 * q2) % ec.n

        # third signer use K1_x and K2_x
        y = ec.y_quadratic_residue(K1_x, True)
        K1_recovered = (K1_x, y)
        y = ec.y_quadratic_residue(K2_x, True)
        K2_recovered = (K2_x, y)
        K3_All = ec.add(ec.add(K1_recovered, K2_recovered), K3)
        if legendre_symbol(K3_All[1], ec._p) != 1:
            # no need to actually change K3_All[1], as it is not used anymore
            # let's fix k3 instead, as it is used later
            k3 = ec.n - k3
        K3_All0_bytes = K3_All[0].to_bytes(32, byteorder="big")
        h3 = hf(K3_All0_bytes + Q_All_bytes + M).digest()
        c3 = int_from_bits(ec, h3)
        assert 0 < c3 and c3 < ec.n, "sign fail"
        s3 = (k3 + c3 * a3 * q3) % ec.n

        ############################################
        # combine signatures into a single signature

        # anyone can do the following
        assert K1_All[0] == K2_All[0], "sign fail"
        assert K2_All[0] == K3_All[0], "sign fail"
        s_All = (s1 + s2 + s3) % ec.n
        sig = (K1_All[0], s_All)

        self.assertTrue(ssa.verify(ec, hf, M, Q_All, sig))