Exemple #1
0
def test_crack_prvkey() -> None:

    ec = CURVES["secp256k1"]

    q = 0x19E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725
    x_Q = mult(q)[0]

    msg1_str = "Paolo is afraid of ephemeral random numbers"
    msg1 = hf(msg1_str.encode()).digest()
    k, _ = ssa._det_nonce(msg1, q)
    sig1 = ssa._sign(msg1, q, k)

    msg2_str = "and Paolo is right to be afraid"
    msg2 = hf(msg2_str.encode()).digest()
    # reuse same k
    sig2 = ssa._sign(msg2, q, k)

    qc, kc = ssa._crack_prvkey(msg1, sig1, msg2, sig2, x_Q)
    assert q in (qc, ec.n - qc)
    assert k in (kc, ec.n - kc)

    with pytest.raises(ValueError, match="not the same r in signatures"):
        ssa._crack_prvkey(msg1, sig1, msg2, (16, sig1[1]), x_Q)

    with pytest.raises(ValueError, match="identical signatures"):
        ssa._crack_prvkey(msg1, sig1, msg1, sig1, x_Q)
Exemple #2
0
    def test_crack_prvkey(self):
        q = 0x6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725DEADBEEF
        x_Q = mult(q)[0]
        k = 1010101010101010101

        msg1 = "Paolo is afraid of ephemeral random numbers"
        msg1 = hf(msg1.encode()).digest()
        sig1 = ssa.sign(msg1, q, k)
        # print(f'\nmsg1: {msg1.hex().upper()}')
        # print(f'  r1: {hex(sig1[0]).upper()}')
        # print(f'  s1: {hex(sig1[1]).upper()}')

        msg2 = "and Paolo is right to be afraid"
        msg2 = hf(msg2.encode()).digest()
        sig2 = ssa.sign(msg2, q, k)
        # print(f'\nmsg2: {msg2.hex().upper()}')
        # print(f'  r2: {hex(sig2[0]).upper()}')
        # print(f'  s2: {hex(sig2[1]).upper()}')

        qc, kc = ssa.crack_prvkey(msg1, sig1, msg2, sig2, x_Q)
        self.assertIn(q, (qc, ec.n - qc))
        self.assertIn(k, (kc, ec.n - kc))

        self.assertRaises(ValueError, ssa.crack_prvkey, msg1, sig1, msg2,
                          (16, sig1[1]), x_Q)
        self.assertRaises(ValueError, ssa.crack_prvkey, msg1, sig1, msg1, sig1,
                          x_Q)
Exemple #3
0
    def test_ecssa(self):
        """Basic tests"""
        ec = secp256k1
        q = 0x1
        Q = mult(ec, q, ec.G)
        msg = hf('Satoshi Nakamoto'.encode()).digest()
        sig = ssa.sign(ec, hf, msg, q, None)
        # no source for the following... but
        # https://bitcointalk.org/index.php?topic=285142.40
        # same r because of rfc6979
        exp_sig = (
            0x934B1EA10A4B3C1757E2B0C017D0B6143CE3C9A7E6A4A49860D7A6AB210EE3D8,
            0x2DF2423F70563E3C4BD0E00BDEF658081613858F110ECF937A2ED9190BF4A01A)
        self.assertEqual(sig[0], exp_sig[0])
        self.assertEqual(sig[1], exp_sig[1])

        ssa._verify(ec, hf, msg, Q, sig)
        self.assertTrue(ssa.verify(ec, hf, msg, Q, sig))
        self.assertTrue(ssa._verify(ec, hf, msg, Q, sig))

        fmsg = hf('Craig Wright'.encode()).digest()
        self.assertFalse(ssa.verify(ec, hf, fmsg, Q, sig))
        self.assertFalse(ssa._verify(ec, hf, fmsg, Q, sig))

        fssasig = (sig[0], sig[1], sig[1])
        self.assertFalse(ssa.verify(ec, hf, msg, Q, fssasig))
        self.assertRaises(TypeError, ssa._verify, ec, hf, msg, Q, fssasig)

        # y(sG - eP) is not a quadratic residue
        fq = 0x2
        fQ = mult(ec, fq, ec.G)
        self.assertFalse(ssa.verify(ec, hf, msg, fQ, sig))
        self.assertRaises(ValueError, ssa._verify, ec, hf, msg, fQ, sig)

        fq = 0x4
        fQ = mult(ec, fq, ec.G)
        self.assertFalse(ssa.verify(ec, hf, msg, fQ, sig))
        self.assertFalse(ssa._verify(ec, hf, msg, fQ, sig))

        # not ec.pIsThreeModFour
        self.assertFalse(ssa.verify(secp224k1, hf, msg, Q, sig))
        self.assertRaises(ValueError, ssa._verify, secp224k1, hf, msg, Q, sig)

        # verify: message of wrong size
        wrongmsg = msg[:-1]
        self.assertFalse(ssa.verify(ec, hf, wrongmsg, Q, sig))
        self.assertRaises(ValueError, ssa._verify, ec, hf, wrongmsg, Q, sig)
        #ssa._verify(ec, hf, wrongmsg, Q, sig)

        # sign: message of wrong size
        self.assertRaises(ValueError, ssa.sign, ec, hf, wrongmsg, q, None)
        #ssa.sign(ec, hf, wrongmsg, q, None)

        # invalid (zero) challenge e
        self.assertRaises(ValueError, ssa._pubkey_recovery, ec, hf, 0, sig)
Exemple #4
0
def assert_as_valid(msg: bytes, e0: bytes, s: SValues,
                    pubk_rings: PubkeyRing) -> bool:

    ring_size = len(pubk_rings)
    m = _get_msg_format(msg, pubk_rings)
    e: SValues = 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(_hash(m, e0, i, 0), ec.nlen) % ec.n
        # edge case that cannot be reproduced in the test suite
        assert e[i][0] != 0, "implausibile signature failure"
        R = b"\0x00"
        for j in range(keys_size):
            T = double_mult(-e[i][j], pubk_rings[i][j], s[i][j], ec.G)
            R = bytes_from_point(T, ec)
            if j != len(pubk_rings[i]) - 1:
                h = _hash(m, R, i, j + 1)
                e[i][j + 1] = int_from_bits(h, ec.nlen) % ec.n
                # edge case that cannot be reproduced in the test suite
                assert e[i][j + 1] != 0, "implausibile signature failure"
            else:
                e0bytes += R
    e0_prime = hf(e0bytes).digest()
    return e0_prime == e0
Exemple #5
0
def _get_msg_format(msg: bytes, pubk_rings: PubkeyRing) -> bytes:

    t = b"".join(
        b"".join(bytes_from_point(Q, ec) for Q in pubk_ring)
        for pubk_ring in pubk_rings.values()
    )
    return hf(msg + t).digest()
Exemple #6
0
def assert_as_valid(msg: Octets, e0: bytes, s: SValues, pubk_rings: PubkeyRing) -> bool:

    msg = bytes_from_octets(msg)
    m = _get_msg_format(msg, pubk_rings)

    ring_size = len(pubk_rings)
    e: SValues = 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(_hash(m, e0, i, 0), ec.nlen) % ec.n
        # edge case that cannot be reproduced in the test suite
        if e[i][0] == 0:
            err_msg = "implausibile signature failure"  # pragma: no cover
            raise BTClibRuntimeError(err_msg)  # pragma: no cover
        r = b"\0x00"
        for j in range(keys_size):
            t = double_mult(-e[i][j], pubk_rings[i][j], s[i][j], ec.G)
            r = bytes_from_point(t, ec)
            if j != len(pubk_rings[i]) - 1:
                h = _hash(m, r, i, j + 1)
                e[i][j + 1] = int_from_bits(h, ec.nlen) % ec.n
                # edge case that cannot be reproduced in the test suite
                if e[i][j + 1] == 0:
                    err_msg = "implausibile signature failure"  # pragma: no cover
                    raise BTClibRuntimeError(err_msg)  # pragma: no cover
            else:
                e0bytes += r
    e0_prime = hf(e0bytes).digest()
    return e0_prime == e0
Exemple #7
0
def sign(
    msg: String,
    ks: Sequence[int],
    sign_key_idx: Sequence[int],
    sign_keys: Sequence[int],
    pubk_rings: PubkeyRing,
) -> Tuple[bytes, SValues]:
    """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: message 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 sequences representing single rings of pubkeys
    """

    if isinstance(msg, str):
        msg = msg.encode()
    m = _get_msg_format(msg, pubk_rings)

    e0bytes = m
    s: SValues = defaultdict(list)
    e: SValues = defaultdict(list)
    # step 1
    for i, (pubk_ring, j_star,
            k) in enumerate(zip(pubk_rings.values(), sign_key_idx, ks)):
        keys_size = len(pubk_ring)
        s[i] = [0] * keys_size
        e[i] = [0] * keys_size
        start_idx = (j_star + 1) % keys_size
        R = bytes_from_point(mult(k), ec)
        if start_idx != 0:
            for j in range(start_idx, keys_size):
                s[i][j] = secrets.randbits(256)
                e[i][j] = int_from_bits(_hash(m, R, i, j), ec.nlen) % ec.n
                # edge case that cannot be reproduced in the test suite
                assert 0 < e[i][j] < ec.n, "implausibile signature failure"
                T = double_mult(-e[i][j], pubk_ring[j], s[i][j], ec.G)
                R = bytes_from_point(T, ec)
        e0bytes += R
    e0 = hf(e0bytes).digest()
    # step 2
    for i, (j_star, k) in enumerate(zip(sign_key_idx, ks)):
        e[i][0] = int_from_bits(_hash(m, e0, i, 0), ec.nlen) % ec.n
        # edge case that cannot be reproduced in the test suite
        assert 0 < e[i][0] < ec.n, "implausibile signature failure"
        for j in range(1, j_star + 1):
            s[i][j - 1] = secrets.randbits(256)
            T = double_mult(-e[i][j - 1], pubk_rings[i][j - 1], s[i][j - 1],
                            ec.G)
            R = bytes_from_point(T, ec)
            e[i][j] = int_from_bits(_hash(m, R, i, j), ec.nlen) % ec.n
            # edge case that cannot be reproduced in the test suite
            assert 0 < e[i][j] < ec.n, "implausibile signature failure"
        s[i][j_star] = k + sign_keys[i] * e[i][j_star]
    return e0, s
Exemple #8
0
def _get_msg_format(msg: bytes, pubk_rings: PubkeyRing) -> bytes:
    m = msg
    rings = len(pubk_rings)
    for i in range(rings):
        for P in pubk_rings[i]:
            Pbytes = octets_from_point(P, True, ec)
            m += Pbytes
    return hf(m).digest()
Exemple #9
0
def test_batch_validation() -> None:

    ec = CURVES["secp256k1"]

    hsize = hf().digest_size
    hlen = hsize * 8

    ms = []
    Qs = []
    sigs = []
    ms.append(secrets.randbits(hlen).to_bytes(hsize, "big"))
    q = 1 + secrets.randbelow(ec.n - 1)
    # bytes version
    Qs.append(mult(q, ec.G, ec)[0])
    sigs.append(ssa._sign(ms[0], q, None, ec, hf))
    # test with only 1 sig
    ssa._batch_verify(ms, Qs, sigs, ec, hf)
    for _ in range(3):
        m = secrets.randbits(hlen).to_bytes(hsize, "big")
        ms.append(m)
        q = 1 + secrets.randbelow(ec.n - 1)
        # Point version
        Qs.append(mult(q, ec.G, ec)[0])
        sigs.append(ssa._sign(m, q, None, ec, hf))
    ssa._batch_verify(ms, Qs, sigs, ec, hf)
    assert ssa.batch_verify(ms, Qs, sigs, ec, hf)

    ms.append(ms[0])
    sigs.append(sigs[1])
    Qs.append(Qs[0])
    assert not ssa.batch_verify(ms, Qs, sigs, ec, hf)
    err_msg = "signature verification precondition failed"
    with pytest.raises(ValueError, match=err_msg):
        ssa._batch_verify(ms, Qs, sigs, ec, hf)
    sigs[-1] = sigs[0]  # valid again

    ms[-1] = ms[0][:-1]
    err_msg = "invalid size: 31 bytes instead of 32"
    with pytest.raises(ValueError, match=err_msg):
        ssa._batch_verify(ms, Qs, sigs, ec, hf)
    ms[-1] = ms[0]  # valid again

    ms.append(ms[0])  # add extra message
    err_msg = "mismatch between number of pubkeys "
    with pytest.raises(ValueError, match=err_msg):
        ssa._batch_verify(ms, Qs, sigs, ec, hf)
    ms.pop()  # valid again

    sigs.append(sigs[0])  # add extra sig
    err_msg = "mismatch between number of pubkeys "
    with pytest.raises(ValueError, match=err_msg):
        ssa._batch_verify(ms, Qs, sigs, ec, hf)
    sigs.pop()  # valid again

    err_msg = "field prime is not equal to 3 mod 4: "
    with pytest.raises(ValueError, match=err_msg):
        ssa._batch_verify(ms, Qs, sigs, CURVES["secp224k1"], hf)
Exemple #10
0
    def test_signature(self):
        """Basic tests"""

        q, x_Q = ssa.gen_keys()
        mhd = hf(b'Satoshi Nakamoto').digest()
        sig = ssa.sign(mhd, q, None)
        self.assertEqual(sig, ssa.deserialize(sig))
        ssa._verify(mhd, x_Q, sig, ec, hf)
        self.assertTrue(ssa.verify(mhd, x_Q, sig))

        fmhd = hf(b'Craig Wright').digest()
        self.assertRaises(AssertionError, ssa._verify, fmhd, x_Q, sig, ec, hf)

        fssasig = (sig[0], sig[1], sig[1])
        self.assertRaises(ValueError, ssa._verify, mhd, x_Q, fssasig, ec, hf)

        # y(sG - eP) is not a quadratic residue
        _, fQ = ssa.gen_keys(0x2)
        self.assertRaises(AssertionError, ssa._verify, mhd, fQ, sig, ec, hf)

        _, fQ = ssa.gen_keys(0x4)
        self.assertRaises(AssertionError, ssa._verify, mhd, fQ, sig, ec, hf)

        # not ec.pIsThreeModFour
        self.assertRaises(ValueError, ssa._verify, mhd, x_Q, sig, secp224k1,
                          hf)

        # verify: message of wrong size
        wrongmhd = mhd[:-1]
        self.assertRaises(ValueError, ssa._verify, wrongmhd, x_Q, sig, ec, hf)
        # ssa._verify(wrongmhd, x_Q, sig)

        # sign: message of wrong size
        self.assertRaises(ValueError, ssa.sign, wrongmhd, q, None)
        # ssa.sign(wrongmhd, q, None)

        # invalid (zero) challenge e
        self.assertRaises(ValueError, ssa._recover_pubkeys, 0, sig[0], sig[1],
                          ec)
        # ssa._recover_pubkeys(0, sig)

        # not a BIP340 public key
        self.assertRaises(ValueError, ssa._to_bip340_point,
                          ["not", "a BIP340", "public key"])
Exemple #11
0
    def test_ecssa(self):
        """Basic tests"""
        q = 0x1
        Q = mult(q)
        mhd = hf(b'Satoshi Nakamoto').digest()
        sig = ssa.sign(mhd, q, None)
        ssa._verify(mhd, Q, sig, ec, hf)
        self.assertTrue(ssa.verify(mhd, Q, sig))

        fmhd = hf(b'Craig Wright').digest()
        self.assertRaises(AssertionError, ssa._verify, fmhd, Q, sig, ec, hf)

        fssasig = (sig[0], sig[1], sig[1])
        self.assertRaises(ValueError, ssa._verify, mhd, Q, fssasig, ec, hf)

        # y(sG - eP) is not a quadratic residue
        fq = 0x2
        fQ = mult(fq)
        self.assertRaises(ValueError, ssa._verify, mhd, fQ, sig, ec, hf)

        fq = 0x4
        fQ = mult(fq)
        self.assertRaises(AssertionError, ssa._verify, mhd, fQ, sig, ec, hf)

        # not ec.pIsThreeModFour
        self.assertRaises(ValueError, ssa._verify, mhd, Q, sig, secp224k1, hf)

        # verify: message of wrong size
        wrongmhd = mhd[:-1]
        self.assertRaises(ValueError, ssa._verify, wrongmhd, Q, sig, ec, hf)
        #ssa._verify(wrongmhd, Q, sig)

        # sign: message of wrong size
        self.assertRaises(ValueError, ssa.sign, wrongmhd, q, None)
        #ssa.sign(wrongmhd, q, None)

        # invalid (zero) challenge e
        self.assertRaises(ValueError, ssa._recover_pubkeys, 0, sig[0], sig[1],
                          ec)
        #ssa._recover_pubkeys(0, sig)

        # not a BIP340 public key
        self.assertRaises(ValueError, ssa.to_bip340_pubkey_tuple,
                          ["not", "a BIP340", "public key"])
Exemple #12
0
def _magic_hash(msg: str) -> bytes:
    # Electrum does strip leading and trailing spaces;
    # bitcoin core does not
    # msg = msg.strip()
    m = hf()
    prefix = b'\x18Bitcoin Signed Message:\n'
    m.update(prefix)
    message = chr(len(msg)) + msg
    m.update(message.encode())
    return m.digest()
Exemple #13
0
    def test_batch_validation(self):
        hsize = hf().digest_size
        hlen = hsize * 8

        ms = []
        Qs = []
        sigs = []
        ms.append(secrets.randbits(hlen).to_bytes(hsize, 'big'))
        q = 1 + secrets.randbelow(ec.n - 1)
        # bytes version
        Qs.append(mult(q, ec.G, ec)[0].to_bytes(ec.psize, 'big'))
        sigs.append(ssa.sign(ms[0], q, None, ec, hf))
        # test with only 1 sig
        ssa._batch_verify(ms, Qs, sigs, ec, hf)
        for _ in range(3):
            mhd = secrets.randbits(hlen).to_bytes(hsize, 'big')
            ms.append(mhd)
            q = 1 + secrets.randbelow(ec.n - 1)
            # Point version
            Qs.append(mult(q, ec.G, ec))
            sigs.append(ssa.sign(mhd, q, None, ec, hf))
        ssa._batch_verify(ms, Qs, sigs, ec, hf)
        self.assertTrue(ssa.batch_verify(ms, Qs, sigs, ec, hf))

        # invalid sig
        ms.append(ms[0])
        sigs.append(sigs[1])
        Qs.append(Qs[0])
        self.assertFalse(ssa.batch_verify(ms, Qs, sigs, ec, hf))
        self.assertRaises(AssertionError, ssa._batch_verify, ms, Qs, sigs, ec,
                          hf)
        # ssa._batch_verify(ms, Qs, sigs, ec, hf)
        sigs[-1] = sigs[0]  # valid again

        # Invalid size: 31 bytes instead of 32
        ms[-1] = ms[0][:-1]
        self.assertRaises(ValueError, ssa._batch_verify, ms, Qs, sigs, ec, hf)
        # ssa._batch_verify(ms, Qs, sigs, ec, hf)
        ms[-1] = ms[0]  # valid again

        # mismatch between number of pubkeys (5) and number of messages (6)
        ms.append(ms[0])  # add extra message
        self.assertRaises(ValueError, ssa._batch_verify, ms, Qs, sigs, ec, hf)
        # ssa._batch_verify(ms, Qs, sigs, ec, hf)
        ms.pop()  # valid again

        # mismatch between number of pubkeys (5) and number of signatures (6)
        sigs.append(sigs[0])  # add extra sig
        self.assertRaises(ValueError, ssa._batch_verify, ms, Qs, sigs, ec, hf)
        # ssa._batch_verify(ms, Qs, sigs, ec, hf)
        sigs.pop()  # valid again

        # field prime p is not equal to 3 (mod 4)
        self.assertRaises(ValueError, ssa._batch_verify, ms, Qs, sigs,
                          secp224k1, hf)
Exemple #14
0
def sign(msg: String, k: Sequence[int], sign_key_idx: Sequence[int],
         sign_keys: Sequence[int],
         pubk_rings: PubkeyRing) -> Tuple[bytes, SValues]:
    """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: message 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 sequences representing single rings of pubkeys
    """

    if isinstance(msg, str):
        msg = msg.encode()
    m = _get_msg_format(msg, pubk_rings)

    e0bytes = m
    s: SValues = defaultdict(list)
    e: SValues = defaultdict(list)
    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 = bytes_from_point(mult(k[i]), ec)
        if start_idx != 0:
            for j in range(start_idx, keys_size):
                s[i][j] = random.getrandbits(256)
                e[i][j] = int_from_bits(_hash(m, R, i, j), ec.nlen) % ec.n
                assert 0 < e[i][j] < ec.n, "sign fail: how did you do that?!?"
                T = double_mult(-e[i][j], pubk_rings[i][j], s[i][j], ec.G)
                R = bytes_from_point(T, ec)
        e0bytes += R
    e0 = hf(e0bytes).digest()
    # step 2
    for i in range(ring_size):
        e[i][0] = int_from_bits(_hash(m, e0, i, 0), ec.nlen) % ec.n
        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(-e[i][j - 1], pubk_rings[i][j - 1], s[i][j - 1],
                            ec.G)
            R = bytes_from_point(T, ec)
            e[i][j] = int_from_bits(_hash(m, R, i, j), ec.nlen) % ec.n
            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
Exemple #15
0
    def test_batch_validation(self):
        ec = secp256k1
        m = []
        sig = []
        Q = []

        hsize = hf().digest_size
        hlen = hsize * 8
        m.append(random.getrandbits(hlen).to_bytes(hsize, 'big'))
        q = (1 + random.getrandbits(ec.nlen)) % ec.n
        sig.append(ssa.sign(ec, hf, m[0], q))
        Q.append(mult(ec, q, ec.G))
        # test with only 1 sig
        self.assertTrue(ssa.batch_verify(ec, hf, m, Q, sig))
        for i in range(1, 4):
            m.append(random.getrandbits(hlen).to_bytes(hsize, 'big'))
            q = (1 + random.getrandbits(ec.nlen)) % ec.n
            sig.append(ssa.sign(ec, hf, m[i], q))
            Q.append(mult(ec, q, ec.G))
        self.assertTrue(ssa.batch_verify(ec, hf, m, Q, sig))

        # invalid sig
        m.append(m[0])
        sig.append(sig[1])
        Q.append(Q[0])
        self.assertFalse(ssa.batch_verify(ec, hf, m, Q, sig))
        #ssa._batch_verify(ec, hf, m, Q, sig)
        sig[-1] = sig[0]  # valid again

        # invalid 31 bytes message
        m[-1] = m[0][:-1]
        self.assertFalse(ssa.batch_verify(ec, hf, m, Q, sig))
        #ssa._batch_verify(ec, hf, m, Q, sig)
        m[-1] = m[0]  # valid again

        # mismatch between number of pubkeys and number of messages
        m.append(m[0])  # add extra message
        self.assertRaises(ValueError, ssa._batch_verify, ec, hf, m, Q, sig)
        #ssa._batch_verify(ec, hf, m, Q, sig)
        m.pop()  # valid again

        # mismatch between number of pubkeys and number of signatures
        sig.append(sig[0])  # add extra sig
        self.assertRaises(ValueError, ssa._batch_verify, ec, hf, m, Q, sig)
        #ssa._batch_verify(ec, hf, m, Q, sig)
        sig.pop()  # valid again

        # curve prime p must be equal to 3 (mod 4)
        ec = secp224k1
        self.assertRaises(ValueError, ssa._batch_verify, ec, hf, m, Q, sig)
Exemple #16
0
def HashDir(Dir, File):
    import os
    from datetime import datetime
    from hashlib import md5 as hf
    from HashFile import HashFile
    from GetDirSize import GetDirSize
    tfmt = '%Y-%m-%d %H:%M:%S'
    outfile = open(File, 'w')
    t1 = datetime.now()
    outfile.write('Begin ' + t1.strftime(tfmt) + '\n')
    outfile.write(Dir + '\n')
    str1 = 'Name\tSize\tmdate'
    str1 += '\tMD5'
    outfile.write(str1 + '\n')
    dirsize = GetDirSize(Dir)
    hashd = hf()
    dsize = 0
    fnum = 0
    for root, subdirs, files in os.walk(Dir):
        for file in files:
            filefullpath = os.path.join(root, file)
            print('\n' + filefullpath, end="  ")
            filerelpath = os.path.relpath(filefullpath, Dir)
            fst = os.stat(filefullpath)
            str_fsize = '{:,}'.format(fst.st_size)
            print(str_fsize, end="")
            dsize += fst.st_size
            fnum += 1
            ctime = datetime.fromtimestamp(fst.st_ctime)
            str_ctime = ctime.strftime(tfmt)
            mtime = datetime.fromtimestamp(fst.st_mtime)
            str_mtime = mtime.strftime(tfmt)
            hashf = HashFile(filefullpath)
            print(' %d' % (dsize / dirsize * 100.0) + '%')
            hashd.update(hashf.digest())
            outfile.write(filerelpath + '\t' + str_fsize + '\t' + str_mtime +
                          '\t' + hashf.hexdigest() + '\n')
    str_total = 'Total %d Files(\t' % (fnum) + '{:,}'.format(
        dsize) + '\t Bytes) \t' + hashd.hexdigest()
    print('\n\n' + str_total)
    outfile.write(str_total + '\n')
    t2 = datetime.now()
    outfile.write('Finished ' + t2.strftime(tfmt) + '\n')
    speed = dsize / ((t2 - t1).seconds + (t2 - t1).microseconds / 1e6)
    str_time = 'Total: ' + str(t2 - t1) + '  %.1fMB/s\n' % (speed / 2**20)
    print('\n' + str_time)
    outfile.write(str_time)
    outfile.close()
    print('Sum File: ' + File)
    def test_signtocontract(self):
        prv = 0x1
        pub = mult(ec, prv, ec.G)
        m = "to be signed".encode()
        c = "to be committed".encode()

        dsa_sig, dsa_receipt = ecdsa_commit_sign(c, ec, hf, m, prv, None)
        self.assertTrue(dsa.verify(ec, hf, m, pub, dsa_sig))
        self.assertTrue(verify_commit(c, ec, hf, dsa_receipt))

        # 32 bytes message for ECSSA
        m = hf(m).digest()
        ssa_sig, ssa_receipt = ecssa_commit_sign(c, ec, hf, m, prv, None)
        self.assertTrue(ssa.verify(ec, hf, m, pub, ssa_sig))
        self.assertTrue(verify_commit(c, ec, hf, ssa_receipt))
Exemple #18
0
def HashFile(filefullpath, block=2**20):
    f = open(filefullpath, 'rb')
    m = hf()
    i = 0
    while True:
        i += 1
        if i >= 10:
            sys.stdout.write('.')
            i = 0
        data = f.read(block)
        if not data:
            break
        m.update(data)
    f.close()
    return m
Exemple #19
0
def HashFile(filefullpath, block=2**20):
    from hashlib import md5 as hf
    import sys
    f = open(filefullpath, 'rb')
    h = hf()
    i = 0
    while True:
        i += 1
        if i >= 10:
            sys.stdout.write('.')
            i = 0
        data = f.read(block)
        if not data:
            break
        h.update(data)
    f.close()
    return h
Exemple #20
0
def HF1(ffp, block=2**20, Method='MD5'):
    from hashlib import md5 as hf
    import sys
    f = open(ffp, 'rb')
    h = hf()
    i = 0
    while True:
        i += 1
        if i >= 10:
            sys.stdout.write('.')
            i = 0
        data = f.read(block)
        if not data:
            break
        h.update(data)
    f.close()
    return h.hexdigest()
Exemple #21
0
    def test_low_cardinality(self):
        """test low-cardinality curves for all msg/key pairs."""
        # ec.n has to be prime to sign
        prime = [11, 13, 17, 19]

        # for dsa it is possible to directy iterate on all
        # possible values for e;
        # for ssa we have to iterate over all possible hash values
        hsize = hf().digest_size
        H = [i.to_bytes(hsize, 'big') for i in range(max(prime) * 4)]
        # only low card curves or it would take forever
        for ec in low_card_curves:
            if ec._p in prime:  # only few curves or it would take too long
                # BIP340 Schnorr only applies to curve whose prime p = 3 %4
                if not ec.pIsThreeModFour:
                    self.assertRaises(ValueError, ssa.sign, H[0], 1, None, ec)
                    continue
                for q in range(1, ec.n):  # all possible private keys
                    Q = mult(q, ec.G, ec)  # public key
                    if not ec.has_square_y(Q):
                        q = ec.n - q
                    for h in H:  # all possible hashed messages
                        k = ssa.k(h, q, ec, hf)
                        K = mult(k, ec.G, ec)
                        if not ec.has_square_y(K):
                            k = ec.n - k
                        x_K = K[0]

                        try:
                            c = ssa._challenge(x_K, Q[0], h, ec, hf)
                        except Exception:
                            pass
                        else:
                            s = (k + c * q) % ec.n
                            sig = ssa.sign(h, q, None, ec)
                            self.assertEqual((x_K, s), sig)
                            # valid signature must validate
                            self.assertIsNone(ssa._verify(h, Q, sig, ec, hf))

                            if c != 0:  # FIXME
                                x_Q = ssa._recover_pubkeys(c, x_K, s, ec)
                                self.assertEqual(Q[0], x_Q)
Exemple #22
0
def _verify(msg: bytes, e0: bytes, s: SValues, pubk_rings: PubkeyRing) -> bool:

    ring_size = len(pubk_rings)
    m = _get_msg_format(msg, pubk_rings)
    e: Dict[int, Sequence[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(_hash(m, e0, i, 0), ec)
        assert e[i][0] != 0, "invalid sig: how did you do that?!?"
        R = b'\0x00'
        for j in range(keys_size):
            T = double_mult(-e[i][j], pubk_rings[i][j], s[i][j])
            R = octets_from_point(T, True, ec)
            if j != len(pubk_rings[i])-1:
                e[i][j+1] = int_from_bits(_hash(m, R, i, j+1), ec)
                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
Exemple #23
0
def assert_as_valid(msg: bytes, e0: bytes, s: SValues, pubk_rings: PubkeyRing) -> bool:

    ring_size = len(pubk_rings)
    m = _get_msg_format(msg, pubk_rings)
    e: SValues = 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(_hash(m, e0, i, 0), ec.nlen) % ec.n
        assert e[i][0] != 0, "invalid sig: how did you do that?!?"
        R = b"\0x00"
        for j in range(keys_size):
            T = double_mult(-e[i][j], pubk_rings[i][j], s[i][j], ec.G)
            R = bytes_from_point(T, ec)
            if j != len(pubk_rings[i]) - 1:
                h = _hash(m, R, i, j + 1)
                e[i][j + 1] = int_from_bits(h, ec.nlen) % ec.n
                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
Exemple #24
0
    def test_batch_validation(self):
        ec = secp256k1
        m = []
        sig = []
        Q = []

        hsize = hf().digest_size
        hlen = hsize * 8
        for i in range(10):
            m.append(random.getrandbits(hlen).to_bytes(hsize, 'big'))
            q = random.getrandbits(ec.nlen) % ec.n
            sig.append(ssa.sign(ec, hf, m[i], q))
            Q.append(mult(ec, q, ec.G))
        self.assertTrue(ssa.batch_verify(ec, hf, m, Q, sig))

        m.append(m[0])
        sig.append(sig[1])  # invalid
        Q.append(Q[0])
        self.assertFalse(ssa.batch_verify(ec, hf, m, Q, sig))

        sig[-1] = sig[0]  # valid
        m[-1] = m[0][:-1]  # invalid 31 bytes message
        self.assertFalse(ssa.batch_verify(ec, hf, m, Q, sig))
Exemple #25
0
#
# This file is part of btclib. It is subject to the license terms in the
# LICENSE file found in the top-level directory of this distribution.
#
# No part of btclib including this file, may be copied, modified, propagated,
# or distributed except according to the terms contained in the LICENSE file.
""" Deterministic Wallet (Type-1)
"""

import random
from hashlib import sha256 as hf

from btclib.curve import mult
from btclib.curves import secp256k1 as ec
from btclib.utils import int_from_bits

# master prvkey
mprvkey = random.getrandbits(ec.nlen) % ec.n
print('\nmaster private key =', hex(mprvkey))

mprvkey_bytes = mprvkey.to_bytes(ec.nlen, 'big')
nKeys = 3
for i in range(nKeys):
    ibytes = i.to_bytes(ec.nlen, 'big')
    hd = hf(ibytes + mprvkey_bytes).digest()
    q = int_from_bits(ec, hd)
    Q = mult(ec, q, ec.G)
    print('\nprvkey#', i, ':', hex(q))
    print('Pubkey#', i, ':', hex(Q[0]))
    print('           ', hex(Q[1]))
Exemple #26
0
def _get_msg_format(msg: bytes, pubk_rings: PubkeyRing) -> bytes:
    rings = len(pubk_rings)
    for i in range(rings):
        for P in pubk_rings[i]:
            msg += bytes_from_point(P, ec)
    return hf(msg).digest()
Exemple #27
0
def _hash(m: bytes, R: bytes, i: int, j: int) -> bytes:
    temp = m + R
    temp += i.to_bytes(4, byteorder='big') + j.to_bytes(4, byteorder='big')
    return hf(temp).digest()
Exemple #28
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)
Exemple #29
0
mprvkey = 1 + secrets.randbelow(ec.n - 1)
print(f"\nmaster prvkey: {hex(mprvkey).upper()}")

# Master Pubkey:
mpubkey = mult(mprvkey, ec.G)
print(f"Master Pubkey: {hex(mpubkey[0]).upper()}")
print(f"               {hex(mpubkey[1]).upper()}")

r = secrets.randbits(ec.nlen)
print(f"\npublic random number: {hex(r).upper()}")

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()
    offset = int_from_bits(hd, ec.nlen) % ec.n
    q = (mprvkey + offset) % ec.n
    Q = mult(q, ec.G, ec)
    print(f"\nprvkey #{i}: {hex(q).upper()}")
    print(f"Pubkey #{i}: {hex(Q[0]).upper()}")
    print(f"           {hex(Q[1]).upper()}")

# Pubkeys could also be calculated without using prvkeys
for i in range(nKeys):
    ibytes = i.to_bytes(ec.nsize, "big")
    hd = hf(ibytes + rbytes).digest()
    offset = int_from_bits(hd, ec.nlen) % ec.n
    Q = ec.add(mpubkey, mult(offset, ec.G, ec))
    assert Q == mult((mprvkey + offset) % ec.n, ec.G, ec)
Exemple #30
0
print(ec)

q = 0x18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725
q = q % ec.n
print("\n*** Key Generation:")
print("prvkey:   ", hex(q))

Q = mult(ec, q, ec.G)
print("PubKey:", "02" if (Q[1] % 2 == 0) else "03", hex(Q[0]))

print("\n*** Message to be signed")
msg = "Paolo is afraid of ephemeral random numbers"
print(msg)

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

print("\n*** Sign Message")
# ephemeral key k must be kept secret and never reused !!!!!
# good choice: k = hf(q||c)
# different for each msg, private because of q
temp = q.to_bytes(32, 'big') + c.to_bytes(32, 'big')
k_bytes = hf(temp).digest()
k = int.from_bytes(k_bytes, 'big') % ec.n
assert 0 < k < ec.n, "Invalid ephemeral key"
print("eph k:", hex(k))