コード例 #1
0
ファイル: dsa.py プロジェクト: btclib-org/btclib
def _sign_(c: int, q: int, nonce: int, lower_s: bool, ec: Curve) -> Sig:
    # Private function for testing purposes: it allows to explore all
    # possible value of the challenge c (for low-cardinality curves).
    # It assume that c is in [0, n-1], while q and nonce are in [1, n-1]

    # Steps numbering follows SEC 1 v.2 section 4.1.3

    KJ = _mult(nonce, ec.GJ, ec)  # 1

    # affine x_K-coordinate of K (field element)
    x_K = (KJ[0] * mod_inv(KJ[2] * KJ[2], ec.p)) % ec.p
    # mod n makes it a scalar
    r = x_K % ec.n  # 2, 3
    if r == 0:  # r≠0 required as it multiplies the public key
        raise BTClibRuntimeError("failed to sign: r = 0")

    s = mod_inv(nonce, ec.n) * (c + r * q) % ec.n  # 6
    if s == 0:  # s≠0 required as verify will need the inverse of s
        raise BTClibRuntimeError("failed to sign: s = 0")

    # bitcoin canonical 'low-s' encoding for ECDSA signatures
    # it removes signature malleability as cause of transaction malleability
    # see https://github.com/bitcoin/bitcoin/pull/6769
    if lower_s and s > ec.n / 2:
        s = ec.n - s  # s = - s % ec.n

    return Sig(r, s, ec)
コード例 #2
0
ファイル: test_der.py プロジェクト: btclib-org/btclib
def test_der_deserialize() -> None:

    err_msg = "non-hexadecimal number found "
    with pytest.raises(ValueError, match=err_msg):
        Sig.parse("not a sig")

    sig = Sig(2**255 - 4, 2**247 - 1)
    sig_bin = sig.serialize()
    r_size = sig_bin[3]

    bad_sig_bin = b"\x31" + sig_bin[1:]
    err_msg = "invalid compound header: "
    with pytest.raises(BTClibValueError, match=err_msg):
        Sig.parse(bad_sig_bin)

    bad_sig_bin = sig_bin[:1] + b"\x41" + sig_bin[2:]
    err_msg = "not enough binary data"
    with pytest.raises(BTClibRuntimeError, match=err_msg):
        Sig.parse(bad_sig_bin)

    # r and s scalars
    for offset in (4, 6 + r_size):
        bad_sig_bin = sig_bin[:offset - 2] + b"\x00" + sig_bin[offset - 1:]
        err_msg = "invalid value header: "
        with pytest.raises(BTClibValueError, match=err_msg):
            Sig.parse(bad_sig_bin)

        bad_sig_bin = sig_bin[:offset - 1] + b"\x00" + sig_bin[offset:]
        err_msg = "zero size"
        with pytest.raises(BTClibRuntimeError, match=err_msg):
            Sig.parse(bad_sig_bin)

        bad_sig_bin = sig_bin[:offset - 1] + b"\x80" + sig_bin[offset:]
        err_msg = "not enough binary data"
        with pytest.raises(BTClibRuntimeError, match=err_msg):
            Sig.parse(bad_sig_bin)

        bad_sig_bin = sig_bin[:offset] + b"\x80" + sig_bin[offset + 1:]
        err_msg = "invalid negative scalar"
        with pytest.raises(BTClibValueError, match=err_msg):
            Sig.parse(bad_sig_bin)

        bad_sig_bin = sig_bin[:offset] + b"\x00\x7f" + sig_bin[offset + 2:]
        err_msg = "invalid 'highest bit set' padding"
        with pytest.raises(BTClibValueError, match=err_msg):
            Sig.parse(bad_sig_bin)

    data_size = sig_bin[1]
    malleated_size = (data_size + 1).to_bytes(1, byteorder="big", signed=False)
    bad_sig_bin = sig_bin[:1] + malleated_size + sig_bin[2:] + b"\x01"
    err_msg = "invalid DER sequence length"
    with pytest.raises(BTClibValueError, match=err_msg):
        Sig.parse(bad_sig_bin)
コード例 #3
0
ファイル: test_der.py プロジェクト: btclib-org/btclib
def test_der_size() -> None:

    sig8 = 1, 1
    sig72 = ec.n - 2, ec.n - 1
    sig71 = 2**255 - 4, ec.n - 1
    sig70 = 2**255 - 4, 2**255 - 1
    sig70b = 2**255 - 4, 2**248 - 1
    sig69 = 2**255 - 4, 2**247 - 1
    sig68 = 2**247 - 1, 2**247 - 1
    sigs = [sig8, sig72, sig71, sig70, sig70b, sig69, sig68]
    lenghts = [8, 72, 71, 70, 70, 69, 68]

    for length, (r, s) in zip(lenghts, sigs):
        sig = Sig(r, s)
        assert r == sig.r
        assert s == sig.s
        assert ec == sig.ec
        sig_bin = sig.serialize()
        assert len(sig_bin) == length
        assert sig == Sig.parse(sig_bin)
コード例 #4
0
ファイル: test_der.py プロジェクト: btclib-org/btclib
def test_der_serialize() -> None:

    r = 2**247 - 1
    s = 2**247 - 1
    Sig(r, s)

    err_msg = "scalar r not in 1..n-1: "
    for bad_r in (0, ec.n):
        _ = Sig(bad_r, s, check_validity=False)
        with pytest.raises(BTClibValueError, match=err_msg):
            Sig(bad_r, s)

    err_msg = "scalar s not in 1..n-1: "
    for bad_s in (0, ec.n):
        _ = Sig(r, bad_s, check_validity=False)
        with pytest.raises(BTClibValueError, match=err_msg):
            Sig(r, bad_s)

    err_msg = r"r is not \(congruent to\) a valid x-coordinate: "
    with pytest.raises(BTClibValueError, match=err_msg):
        Sig(5, s)
コード例 #5
0
print("3. Verify signature")
print(verify(msg1, Q, sig1))

print("4. Recover keys")
keys = recover_pub_keys(msg1, sig1)
for i, key in enumerate(keys):
    print(
        f" key#{i}: {'02' if key[1] % 2 == 0 else '03'} {hex(key[0]).upper()}")

print("\n** Malleated signature")
sm = ec.n - sig1.s
print(f"    r1:    {hex(sig1.r).upper()}")
print(f"    sm:    {hex(sm).upper()}")

print("** Verify malleated signature")
print(verify(msg1, Q, Sig(sig1.r, sm)))
print(verify(msg1, Q, Sig(sig1.r, sm), False))

print("\n1. Another message to sign")
msg2 = "and Paolo is right to be afraid".encode()
print(msg2.decode())

print("2. Sign message")
sig2 = sign(msg2, q)
print(f"    r2:    {hex(sig2.r).upper()}")
print(f"    s2:    {hex(sig2.s).upper()}")

print("3. Verify signature")
print(verify(msg2, Q, sig2))

print("4. Recover keys")