Esempio n. 1
0
def test_crack_prvkey() -> None:

    ec = CURVES["secp256k1"]

    # FIXME: make it random
    q = 0x17E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725

    msg1 = "Paolo is afraid of ephemeral random numbers"
    m_1 = reduce_to_hlen(msg1)
    k = _rfc6979(m_1, q)
    sig1 = dsa._sign(m_1, q, k)

    msg2 = "and Paolo is right to be afraid"
    m_2 = reduce_to_hlen(msg2)
    # reuse same k
    sig2 = dsa._sign(m_2, q, k)

    qc, kc = dsa.crack_prvkey(msg1, sig1, msg2, sig2)
    assert q in (qc, ec.n - qc)
    assert q == qc
    assert k in (kc, ec.n - kc)
    # assert k == kc

    with pytest.raises(BTClibValueError, match="not the same r in signatures"):
        dsa.crack_prvkey(msg1, sig1, msg2, (16, sig1[1]))

    with pytest.raises(BTClibValueError, match="identical signatures"):
        dsa.crack_prvkey(msg1, sig1, msg1, sig1)
Esempio n. 2
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 ec in low_card_curves:  # only low card or it would take forever
            if ec._p in prime:  # only few curves or it would take too long
                for q in range(1, ec.n):  # all possible private keys
                    PJ = _mult_jac(q, ec.GJ, ec)  # public key
                    for e in range(ec.n):  # all possible int from hash
                        for k in range(1, ec.n):  # all possible ephemeral keys
                            RJ = _mult_jac(k, ec.GJ, ec)
                            Rx = (RJ[0] *
                                  mod_inv(RJ[2] * RJ[2], ec._p)) % ec._p
                            r = Rx % ec.n
                            s = mod_inv(k, ec.n) * (e + q * r) % ec.n
                            # bitcoin canonical 'low-s' encoding for ECDSA
                            if s > ec.n / 2:
                                s = ec.n - s
                            if r == 0 or s == 0:
                                self.assertRaises(ValueError, dsa._sign, e, q,
                                                  k, ec)
                                continue

                            sig = dsa._sign(e, q, k, ec)
                            self.assertEqual((r, s), sig)
                            # valid signature must pass verification
                            self.assertIsNone(dsa._verhlp(e, PJ, r, s, ec))

                            JacobianKeys = dsa._recover_pubkeys(e, r, s, ec)
                            Qs = [
                                ec._aff_from_jac(key) for key in JacobianKeys
                            ]
                            self.assertIn(ec._aff_from_jac(PJ), Qs)
Esempio n. 3
0
def test_low_cardinality():
    """test low-cardinality curves for all msg/key pairs."""

    # ec.n has to be prime to sign
    test_curves = [
        low_card_curves["ec13_11"],
        # low_card_curves["ec13_19"],
        # low_card_curves["ec17_13"],
        low_card_curves["ec17_23"],
        low_card_curves["ec19_13"],
        # low_card_curves["ec19_23"],
        low_card_curves["ec23_19"],
        low_card_curves["ec23_31"],
    ]

    # only low cardinality test curves or it would take forever
    for ec in test_curves:
        for q in range(1, ec.n):  # all possible private keys
            QJ = _mult_jac(q, ec.GJ, ec)  # public key
            for k in range(1, ec.n):  # all possible ephemeral keys
                RJ = _mult_jac(k, ec.GJ, ec)
                r = ec._x_aff_from_jac(RJ) % ec.n
                k_inv = mod_inv(k, ec.n)
                for e in range(ec.n):  # all possible challenges
                    s = k_inv * (e + q * r) % ec.n
                    # bitcoin canonical 'low-s' encoding for ECDSA
                    if s > ec.n / 2:
                        s = ec.n - s
                    if r == 0 or s == 0:
                        err_msg = "failed to sign: "
                        with pytest.raises(RuntimeError, match=err_msg):
                            dsa._sign(e, q, k, ec)
                        continue

                    sig = dsa._sign(e, q, k, ec)
                    assert (r, s) == sig
                    # valid signature must pass verification
                    dsa._assert_as_valid(e, QJ, r, s, ec)

                    JacobianKeys = dsa._recover_pubkeys(e, r, s, ec)
                    # FIXME speed this up
                    Qs = [ec._aff_from_jac(key) for key in JacobianKeys]
                    assert ec._aff_from_jac(QJ) in Qs
                    assert len(JacobianKeys) in (2, 4)
Esempio n. 4
0
def test_rfc6979_tv() -> None:

    fname = "rfc6979.json"
    filename = path.join(path.dirname(__file__), "test_data", fname)
    with open(filename, "r") as file_:
        test_dict = json.load(file_)

    for ec_name in test_dict:
        ec = CURVES[ec_name]
        test_vectors = test_dict[ec_name]
        for x, x_U, y_U, hf, msg, k, r, s in test_vectors:
            x = int(x, 16)
            m = reduce_to_hlen(msg, hf=getattr(hashlib, hf))
            # test RFC6979 implementation
            k2 = _rfc6979(m, x, ec, getattr(hashlib, hf))
            assert k == hex(k2)
            # test RFC6979 usage in DSA
            sig = dsa._sign(m,
                            x,
                            k2,
                            low_s=False,
                            ec=ec,
                            hf=getattr(hashlib, hf))
            assert r == hex(sig[0])
            assert s == hex(sig[1])
            # test that RFC6979 is the default nonce for DSA
            sig = dsa._sign(m,
                            x,
                            None,
                            low_s=False,
                            ec=ec,
                            hf=getattr(hashlib, hf))
            assert r == hex(sig[0])
            assert s == hex(sig[1])
            # test key-pair coherence
            U = mult(x, ec.G, ec)
            assert int(x_U, 16), int(y_U, 16) == U
            # test signature validity
            dsa.assert_as_valid(msg, U, sig, ec, getattr(hashlib, hf))
    def test_low_cardinality(self):
        """test all msg/key pairs of low cardinality elliptic curves"""

        # ec.n has to be prime to sign
        prime = [11, 13, 17, 19]

        for ec in low_card_curves:  # only low card or it would take forever
            if ec._p in prime:  # only few curves or it would take too long
                for d in range(ec.n):  # all possible private keys
                    if d == 0:  # invalid prvkey = 0
                        self.assertRaises(ValueError, dsa._sign, ec, 1, d, 1)
                        continue
                    P = mult(ec, d, ec.G)  # public key
                    for e in range(ec.n):  # all possible int from hash
                        for k in range(ec.n):  # all possible ephemeral keys

                            if k == 0:
                                self.assertRaises(ValueError, dsa._sign, ec, e,
                                                  d, k)
                                continue
                            R = mult(ec, k, ec.G)

                            r = R[0] % ec.n
                            if r == 0:
                                self.assertRaises(ValueError, dsa._sign, ec, e,
                                                  d, k)
                                continue

                            s = mod_inv(k, ec.n) * (e + d * r) % ec.n
                            if s == 0:
                                self.assertRaises(ValueError, dsa._sign, ec, e,
                                                  d, k)
                                continue

                            # bitcoin canonical 'low-s' encoding for ECDSA
                            if s > ec.n / 2:
                                s = ec.n - s

                            # valid signature
                            sig = dsa._sign(ec, e, d, k)
                            self.assertEqual((r, s), sig)
                            # valid signature must validate
                            self.assertTrue(dsa._verhlp(ec, e, P, sig))

                            keys = dsa._pubkey_recovery(ec, e, sig)
                            self.assertIn(P, keys)
                            for Q in keys:
                                self.assertTrue(dsa._verhlp(ec, e, Q, sig))
Esempio n. 6
0
def test_gec() -> None:
    """GEC 2: Test Vectors for SEC 1, section 2

    http://read.pudn.com/downloads168/doc/772358/TestVectorsforSEC%201-gec2.pdf
    """
    # 2.1.1 Scheme setup
    ec = CURVES["secp160r1"]
    hf = sha1

    # 2.1.2 Key Deployment for U
    dU = 971761939728640320549601132085879836204587084162
    assert format(dU,
                  str(ec.nsize) +
                  "x") == "aa374ffc3ce144e6b073307972cb6d57b2a4e982"

    QU = mult(dU, ec.G, ec)
    assert QU == (
        466448783855397898016055842232266600516272889280,
        1110706324081757720403272427311003102474457754220,
    )
    assert (bytes_from_point(
        QU, ec).hex() == "0251b4496fecc406ed0e75a24a3c03206251419dc0")

    # 2.1.3 Signing Operation for U
    msg = b"abc"
    k = 702232148019446860144825009548118511996283736794
    exp_sig = (
        0xCE2873E5BE449563391FEB47DDCBA2DC16379191,
        0x3480EC1371A091A464B31CE47DF0CB8AA2D98B54,
    )
    low_s = False
    sig = dsa._sign(reduce_to_hlen(msg, hf), dU, k, low_s, ec, hf)
    r, s = sig
    assert r == exp_sig[0]
    assert s == exp_sig[1]

    # 2.1.4 Verifying Operation for V
    assert dsa.verify(msg, QU, sig, ec, hf)
Esempio n. 7
0
def test_signature() -> None:
    ec = CURVES["secp256k1"]
    msg = "Satoshi Nakamoto"

    q, Q = dsa.gen_keys(0x1)
    sig = dsa.sign(msg, q)
    assert dsa.verify(msg, Q, sig)

    assert sig == dsa.deserialize(sig)

    # https://bitcointalk.org/index.php?topic=285142.40
    # Deterministic Usage of DSA and ECDSA (RFC 6979)
    exp_sig = (
        0x934B1EA10A4B3C1757E2B0C017D0B6143CE3C9A7E6A4A49860D7A6AB210EE3D8,
        0x2442CE9D2B916064108014783E923EC36B49743E2FFA1C4496F01A512AAFD9E5,
    )
    r, s = sig
    assert sig[0] == exp_sig[0]
    assert sig[1] in (exp_sig[1], ec.n - exp_sig[1])

    dsa.assert_as_valid(msg, Q, sig)
    dsa.assert_as_valid(msg, Q, dsa.serialize(*sig))
    dsa.assert_as_valid(msg, Q, dsa.serialize(*sig).hex())

    # malleability
    malleated_sig = (r, ec.n - s)
    assert dsa.verify(msg, Q, malleated_sig)

    keys = dsa.recover_pubkeys(msg, sig)
    assert len(keys) == 2
    assert Q in keys

    msg_fake = "Craig Wright"
    assert not dsa.verify(msg_fake, Q, sig)
    err_msg = "signature verification failed"
    with pytest.raises(BTClibRuntimeError, match=err_msg):
        dsa.assert_as_valid(msg_fake, Q, sig)

    _, Q_fake = dsa.gen_keys()
    assert not dsa.verify(msg, Q_fake, sig)
    err_msg = "signature verification failed"
    with pytest.raises(BTClibRuntimeError, match=err_msg):
        dsa.assert_as_valid(msg, Q_fake, sig)

    err_msg = "not a valid public key: "
    with pytest.raises(BTClibValueError, match=err_msg):
        dsa.assert_as_valid(msg, INF, sig)

    sig_fake = (sig[0], sig[1], sig[1])
    assert not dsa.verify(msg, Q, sig_fake)  # type: ignore
    err_msg = "too many values to unpack "
    with pytest.raises(ValueError, match=err_msg):
        dsa.assert_as_valid(msg, Q, sig_fake)  # type: ignore

    sig_invalid = ec.p, sig[1]
    assert not dsa.verify(msg, Q, sig_invalid)
    err_msg = "scalar r not in 1..n-1: "
    with pytest.raises(BTClibValueError, match=err_msg):
        dsa.assert_as_valid(msg, Q, sig_invalid)

    sig_invalid = sig[0], ec.p
    assert not dsa.verify(msg, Q, sig_invalid)
    err_msg = "scalar s not in 1..n-1: "
    with pytest.raises(BTClibValueError, match=err_msg):
        dsa.assert_as_valid(msg, Q, sig_invalid)

    err_msg = "private key not in 1..n-1: "
    with pytest.raises(BTClibValueError, match=err_msg):
        dsa.sign(msg, 0)

    # ephemeral key not in 1..n-1
    err_msg = "private key not in 1..n-1: "
    with pytest.raises(BTClibValueError, match=err_msg):
        dsa._sign(reduce_to_hlen(msg), q, 0)
    with pytest.raises(BTClibValueError, match=err_msg):
        dsa._sign(reduce_to_hlen(msg), q, ec.n)
Esempio n. 8
0
    return r == v  # 8


random.seed(42)

# setup
qs = []
es = []
Qs = []
sigs = []
for _ in range(5):
    q = random.getrandbits(ec.nlen) % ec.n
    qs.append(q)
    Qs.append(ec.mult(q, ec.G))
    e = random.getrandbits(ec.nlen) % ec.n
    es.append(e)
    k = _rfc6979(e, q)
    sigs.append(_sign(e, q, k))

start = time.time()
for i in range(len(qs)):
    assert _verhlp(ec, es[i], Qs[i], sigs[i], True)
elapsed1 = time.time() - start

start = time.time()
for i in range(len(qs)):
    assert _verhlp(ec, es[i], Qs[i], sigs[i], False)
elapsed2 = time.time() - start

print(elapsed2 / elapsed1)