Example #1
0
    def test_signature(self):

        ec = secp256k1
        q, Q = dsa.gen_keys(0x1)
        msg = "Satoshi Nakamoto"
        sig = dsa.sign(msg, q)
        self.assertEqual(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
        self.assertEqual(sig[0], exp_sig[0])
        self.assertIn(sig[1], (exp_sig[1], secp256k1.n - exp_sig[1]))

        self.assertTrue(dsa.verify(msg, Q, sig))

        # malleability
        malleated_sig = (r, secp256k1.n - s)
        self.assertTrue(dsa.verify(msg, Q, malleated_sig))

        keys = dsa.recover_pubkeys(msg, sig)
        self.assertTrue(len(keys) == 2)
        self.assertIn(Q, keys)

        fmsg = "Craig Wright"
        self.assertFalse(dsa.verify(fmsg, Q, sig))

        fdsasig = (sig[0], sig[1], sig[1])
        self.assertFalse(dsa.verify(msg, Q, fdsasig))
        self.assertRaises(ValueError, dsa._verify, msg, Q, fdsasig, ec, hf)

        _, fQ = dsa.gen_keys()
        self.assertFalse(dsa.verify(msg, fQ, sig))

        # r not in [1, n-1]
        invalid_dassig = 0, sig[1]
        self.assertFalse(dsa.verify(msg, Q, invalid_dassig))

        # s not in [1, n-1]
        invalid_dassig = sig[0], 0
        self.assertFalse(dsa.verify(msg, Q, invalid_dassig))

        # pubkey = INF
        self.assertRaises(ValueError, dsa._verify, msg, INF, sig, ec, hf)
        # dsa._verify(msg, INF, sig, ec, hf)

        # private key not in [1, n-1]
        self.assertRaises(ValueError, dsa.sign, msg, 0)
        # dsa.sign(msg, 0)

        # ephemeral key not in [1, n-1]
        self.assertRaises(ValueError, dsa.sign, msg, 1, 0)
Example #2
0
    def test_signature(self):
        q, Q = dsa.gen_keys(0x1)
        msg = 'Satoshi Nakamoto'
        sig = dsa.sign(msg, q)
        self.assertEqual(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
        self.assertEqual(sig[0], exp_sig[0])
        self.assertIn(sig[1], (exp_sig[1], secp256k1.n - exp_sig[1]))

        self.assertTrue(dsa.verify(msg, Q, sig))

        # malleability
        malleated_sig = (r, secp256k1.n - s)
        self.assertTrue(dsa.verify(msg, Q, malleated_sig))

        keys = dsa.recover_pubkeys(msg, sig)
        self.assertTrue(len(keys) == 2)
        self.assertIn(Q, keys)

        fmsg = 'Craig Wright'
        self.assertFalse(dsa.verify(fmsg, Q, sig))

        fdsasig = (sig[0], sig[1], sig[1])
        self.assertFalse(dsa.verify(msg, Q, fdsasig))
        self.assertRaises(ValueError, dsa._verify, msg, Q, fdsasig, ec, hf)

        fq, fQ = dsa.gen_keys()
        self.assertFalse(dsa.verify(msg, fQ, sig))

        # r not in [1, n-1]
        invalid_dassig = 0, sig[1]
        self.assertFalse(dsa.verify(msg, Q, invalid_dassig))

        # s not in [1, n-1]
        invalid_dassig = sig[0], 0
        self.assertFalse(dsa.verify(msg, Q, invalid_dassig))

        # pubkey = INF
        self.assertRaises(ValueError, dsa._verify, msg, INF, sig, ec, hf)
        #dsa._verify(msg, INF, sig, ec, hf)

        # private key not in [1, n-1]
        self.assertRaises(ValueError, dsa.sign, msg, 0)
        #dsa.sign(msg, 0)

        # ephemeral key not in [1, n-1]
        self.assertRaises(ValueError, dsa.sign, msg, 1, 0)
Example #3
0
def test_sign_to_contract_dsa() -> None:
    m = sha256(b"to be signed").digest()
    c = sha256(b"to be committed").digest()

    prvkey, pubkey = dsa.gen_keys()
    dsa_sig, dsa_receipt = ecdsa_commit_sign(c, m, prvkey)
    dsa._assert_as_valid(m, pubkey, dsa_sig, ec, sha256)
    assert verify_commit(c, dsa_receipt)

    k = 1 + secrets.randbelow(ec.n - 1)
    dsa_sig, dsa_receipt = ecdsa_commit_sign(c, m, prvkey, k)
    dsa._assert_as_valid(m, pubkey, dsa_sig, ec, sha256)
    assert verify_commit(c, dsa_receipt)
Example #4
0
def test_ecdh() -> None:
    ec = CURVES["secp256k1"]
    hf = sha256

    a, A = dsa.gen_keys()  # Alice
    b, B = dsa.gen_keys()  # Bob

    # Alice computes the shared secret using Bob's public key
    shared_secret_a = mult(a, B)

    # Bob computes the shared secret using Alice's public key
    shared_secret_b = mult(b, A)

    assert shared_secret_a == shared_secret_b
    assert shared_secret_a == mult(a * b, ec.G)

    # hash the shared secret to remove weak bits
    shared_secret_field_element = shared_secret_a[0]
    z = shared_secret_field_element.to_bytes(ec.psize, "big")

    shared_info = b"deadbeef"

    hsize = hf().digest_size
    for size in (hsize - 1, hsize, hsize + 1):
        shared_key = ansi_x9_63_kdf(z, size, hf, None)
        assert len(shared_key) == size
        assert shared_key == diffie_hellman(a, B, size, None, ec, hf)
        assert shared_key == diffie_hellman(b, A, size, None, ec, hf)
        shared_key = ansi_x9_63_kdf(z, size, hf, shared_info)
        assert len(shared_key) == size
        assert shared_key == diffie_hellman(a, B, size, shared_info, ec, hf)
        assert shared_key == diffie_hellman(b, A, size, shared_info, ec, hf)

    max_size = hsize * (2 ** 32 - 1)
    size = max_size + 1
    with pytest.raises(BTClibValueError, match="cannot derive a key larger than "):
        ansi_x9_63_kdf(z, size, hf, None)
Example #5
0
def test_signtocontract():
    m = b"to be signed"
    c = b"to be committed"

    prv, pub = dsa.gen_keys()
    dsa_sig, dsa_receipt = ecdsa_commit_sign(c, m, prv, None)
    dsa.assert_as_valid(m, pub, dsa_sig, ec, sha256)
    assert verify_commit(c, dsa_receipt)

    # 32 bytes message for ECSSA
    m = sha256(m).digest()
    prv, pub = ssa.gen_keys()
    ssa_sig, ssa_receipt = ecssa_commit_sign(c, m, prv, None)
    ssa.assert_as_valid(m, pub, ssa_sig, ec, sha256)
    assert verify_commit(c, ssa_receipt)
Example #6
0
    def test_signtocontract(self):
        m = b"to be signed"
        c = b"to be committed"

        prv, pub = dsa.gen_keys()
        dsa_sig, dsa_receipt = ecdsa_commit_sign(c, m, prv, None)
        self.assertIsNone(dsa._verify(m, pub, dsa_sig, ec, sha256))
        self.assertTrue(verify_commit(c, dsa_receipt))

        # 32 bytes message for ECSSA
        m = sha256(m).digest()
        prv, pub = ssa.gen_keys()
        ssa_sig, ssa_receipt = ecssa_commit_sign(c, m, prv, None)
        self.assertIsNone(ssa._verify(m, pub, ssa_sig, ec, sha256))
        self.assertTrue(verify_commit(c, ssa_receipt))
Example #7
0
    def test_borromean(self):
        nring = 4  # FIXME randomize; minimum number of rings?
        ring_sizes = [1 + secrets.randbelow(7) for _ in range(nring)]
        sign_key_idx = [secrets.randbelow(size) for size in ring_sizes]

        pubk_rings: Dict[int, List[Point]] = defaultdict(list)
        sign_keys: List[int] = []
        for i in range(nring):
            for j in range(ring_sizes[i]):
                priv_key, pub_key = dsa.gen_keys()
                pubk_rings[i].append(pub_key)
                if j == sign_key_idx[i]:
                    sign_keys.append(priv_key)

        msg = "Borromean ring signature"
        sig = borromean.sign(msg, list(range(1, 5)), sign_key_idx, sign_keys,
                             pubk_rings)

        borromean.assert_as_valid(msg.encode(), sig[0], sig[1], pubk_rings)
        self.assertTrue(borromean.verify(msg, sig[0], sig[1], pubk_rings))
        self.assertFalse(borromean.verify(0, sig[0], sig[1], pubk_rings))
Example #8
0
def test_signtocontract() -> None:
    m = sha256(b"to be signed").digest()
    c = sha256(b"to be committed").digest()

    prv, Pub = dsa.gen_keys()
    dsa_sig, dsa_receipt = ecdsa_commit_sign(c, m, prv)
    dsa._assert_as_valid(m, Pub, dsa_sig, ec, sha256)
    assert verify_commit(c, dsa_receipt)

    k = 1 + secrets.randbelow(ec.n - 1)
    dsa_sig, dsa_receipt = ecdsa_commit_sign(c, m, prv, k)
    dsa._assert_as_valid(m, Pub, dsa_sig, ec, sha256)
    assert verify_commit(c, dsa_receipt)

    prv, pub = ssa.gen_keys()
    ssa_sig, ssa_receipt = ecssa_commit_sign(c, m, prv)
    ssa._assert_as_valid(m, pub, ssa_sig, ec, sha256)
    assert verify_commit(c, ssa_receipt)

    k = 1 + secrets.randbelow(ec.n - 1)
    ssa_sig, ssa_receipt = ecssa_commit_sign(c, m, prv, k)
    ssa._assert_as_valid(m, pub, ssa_sig, ec, sha256)
    assert verify_commit(c, ssa_receipt)
Example #9
0
from btclib import bms, dsa, ssa

msg = "Hello, I'm Alice!"
print("\n", msg)

# ECDSA
print("\n ECDSA")

dsa_prv, dsa_pub = dsa.gen_keys()
print("prv", hex(dsa_prv))
print("pub", hex(dsa_pub[0]), hex(dsa_pub[1]))

dsa_sig = dsa.sign(msg, dsa_prv)
print("r:", hex(dsa_sig[0]))
print("s:", hex(dsa_sig[1]))

dsa_valid = dsa.verify(msg, dsa_pub, dsa_sig)
print("valid ECDSA sig:", dsa_valid)

# ECSSA
print("\n ECSSA")

ssa_prv, ssa_pub = ssa.gen_keys()
print("prv", hex(ssa_prv))
print("pub", hex(ssa_pub))

ssa_sig = ssa.sign(msg, ssa_prv)
print("r:", hex(ssa_sig[0]))
print("s:", hex(ssa_sig[1]))

ssa_valid = ssa.verify(msg, ssa_pub, ssa_sig)
Example #10
0
from hashlib import sha256 as hf

from btclib import dsa
from btclib.ecc.curve import mult
from btclib.ecc.curve import secp256k1 as ec
from btclib.dh import ansi_x9_63_kdf

# Diffie-Hellman
print("\n Diffie-Hellman")

a, A = dsa.gen_keys()  # Alice
b, B = dsa.gen_keys()  # Bob

# Alice calculates the shared secret using Bob's public key
shared_secret_a = mult(a, B)

# Bob calculates the shared secret using Alice's public key
shared_secret_b = mult(b, A)

print("same shared secret:", shared_secret_a == shared_secret_b)
print("as expected:", shared_secret_a == mult(a * b, ec.G))

# hash the shared secret to remove weak bits
shared_secret_field_element = shared_secret_a[0]
z = shared_secret_field_element.to_bytes(ec.psize, "big")
shared_info = None
shared_key = ansi_x9_63_kdf(z, 32, hf, shared_info)
print("shared key:", shared_key.hex())
Example #11
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)
Example #12
0
def test_signature():

    ec = secp256k1
    q, Q = dsa.gen_keys(0x1)
    msg = "Satoshi Nakamoto"
    sig = dsa.sign(msg, q)
    dsa.assert_as_valid(msg, Q, sig, ec, hf)
    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], secp256k1.n - exp_sig[1])

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

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

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

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

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

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

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

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

    err_msg = "private key not in 1..n-1: "
    with pytest.raises(ValueError, 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(ValueError, match=err_msg):
        dsa.sign(msg, 1, 0)
Example #13
0
def test_exceptions() -> None:
    # from creator example
    psbt_encoded = "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAAAAAA="

    psbt = Psbt.decode(psbt_encoded)
    psbt.outputs[0].redeem_script = "bad script"  # type: ignore
    with pytest.raises(BTClibValueError, match="invalid redeem script"):
        psbt.serialize()

    psbt = Psbt.decode(psbt_encoded)
    psbt.inputs[0].witness_script = "bad script"  # type: ignore
    with pytest.raises(BTClibValueError, match="invalid witness script"):
        psbt.serialize()

    psbt = Psbt.decode(psbt_encoded)
    psbt.outputs[0].unknown = {"bad key": b""}  # type: ignore
    with pytest.raises(BTClibValueError, match="invalid key in unknown"):
        psbt.serialize()

    psbt = Psbt.decode(psbt_encoded)
    psbt.outputs[0].unknown = {b"deadbeef": "bad value"}  # type: ignore
    with pytest.raises(BTClibValueError, match="invalid value in unknown"):
        psbt.serialize()

    psbt = Psbt.decode(psbt_encoded)
    psbt.inputs[0].sighash = 101
    with pytest.raises(BTClibValueError, match="invalid sighash: "):
        psbt.serialize()

    psbt = Psbt.decode(psbt_encoded)
    psbt.inputs[0].final_script_sig = "bad script"  # type: ignore
    with pytest.raises(BTClibValueError, match="invalid final script_sig"):
        psbt.serialize()

    psbt = Psbt.decode(psbt_encoded)
    psbt.inputs[0].final_script_witness = "bad script"  # type: ignore
    with pytest.raises(BTClibValueError, match="invalid final script witness"):
        psbt.serialize()

    psbt = Psbt.decode(psbt_encoded)
    psbt.inputs[0].final_script_witness = [b"", ""]  # type: ignore
    with pytest.raises(BTClibValueError, match="invalid final script witness"):
        psbt.serialize()

    psbt = Psbt.decode(psbt_encoded)
    _, Q = dsa.gen_keys()
    pubkey = secpoint.bytes_from_point(Q)
    r = s = int.from_bytes(bytes.fromhex("FF" * 32), "big")
    sig_bytes = der._serialize_scalar(r)
    sig_bytes += der._serialize_scalar(s)
    sig_bytes = b"\x30" + len(sig_bytes).to_bytes(1,
                                                  byteorder="big") + sig_bytes
    psbt.inputs[0].partial_signatures = {pubkey: sig_bytes}
    with pytest.raises(BTClibValueError, match="invalid partial signature: "):
        psbt.serialize()

    pubkey = bytes.fromhex("02" + 31 * "00" + "07")
    psbt.inputs[0].partial_signatures = {pubkey: sig_bytes}
    with pytest.raises(BTClibValueError,
                       match="invalid partial signature pubkey: "):
        psbt.serialize()

    psbt = Psbt.decode(psbt_encoded)
    err_msg = "invalid version: "
    psbt.version = -1
    with pytest.raises(BTClibValueError, match=err_msg):
        psbt.serialize()
    psbt.version = 0xFFFFFFFF + 1
    with pytest.raises(BTClibValueError, match=err_msg):
        psbt.serialize()
    psbt.version = 1
    # TODO: add to test vectors
    with pytest.raises(BTClibValueError, match="invalid non-zero version: "):
        psbt.serialize()

    psbt = Psbt.decode(psbt_encoded)
    psbt_bin = psbt.serialize()
    psbt_bin = psbt_bin.replace(PSBT_SEPARATOR, PSBT_DELIMITER)
    # TODO: add to test vectors
    with pytest.raises(BTClibValueError,
                       match="malformed psbt: missing separator"):
        Psbt.deserialize(psbt_bin)

    psbt = Psbt.decode(psbt_encoded)
    psbt.inputs.pop()
    err_msg = "mismatched number of tx.vin and psbt_in"
    # TODO: add to test vectors
    with pytest.raises(BTClibValueError, match=err_msg):
        psbt.serialize()

    psbt = Psbt.decode(psbt_encoded)
    psbt.tx.vin[0].txinwitness = [b""]
    err_msg = "non empty txinwitness"
    # TODO: add to test vectors
    with pytest.raises(BTClibValueError, match=err_msg):
        psbt.serialize()

    psbt = Psbt.decode(psbt_encoded)
    psbt.outputs.pop()
    err_msg = "mismatched number of tx.vout and psbt_out"
    # TODO: add to test vectors
    with pytest.raises(BTClibValueError, match=err_msg):
        psbt.serialize()