Esempio n. 1
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)
Esempio n. 2
0
def test_signature():
    """Basic tests"""

    ec = secp256k1
    q, x_Q = ssa.gen_keys(0x1)
    mhd = hf(b"Satoshi Nakamoto").digest()
    sig = ssa.sign(mhd, q, None)
    ssa.assert_as_valid(mhd, x_Q, sig, ec, hf)
    assert ssa.verify(mhd, x_Q, sig)
    assert sig == ssa.deserialize(sig)

    fmhd = hf(b"Craig Wright").digest()
    assert not ssa.verify(fmhd, x_Q, sig, ec, hf)
    err_msg = "signature verification failed"
    with pytest.raises(AssertionError, match=err_msg):
        ssa.assert_as_valid(fmhd, x_Q, sig, ec, hf)

    _, x_fQ = ssa.gen_keys(0x2)
    assert not ssa.verify(mhd, x_fQ, sig, ec, hf)
    err_msg = "y_K is not a quadratic residue"
    with pytest.raises(RuntimeError, match=err_msg):
        ssa.assert_as_valid(mhd, x_fQ, sig, ec, hf)

    _, x_fQ = ssa.gen_keys(0x4)
    assert not ssa.verify(mhd, x_fQ, sig, ec, hf)
    err_msg = "signature verification failed"
    with pytest.raises(AssertionError, match=err_msg):
        ssa.assert_as_valid(mhd, x_fQ, sig, ec, hf)

    err_msg = "not a BIP340 public key"
    with pytest.raises(ValueError, match=err_msg):
        ssa.assert_as_valid(mhd, INF, sig, ec, hf)

    assert not ssa.verify(mhd, x_Q, sig, secp224k1, hf)
    err_msg = "field prime is not equal to 3 mod 4: "
    with pytest.raises(ValueError, match=err_msg):
        ssa.assert_as_valid(mhd, x_Q, sig, secp224k1, hf)

    wrongmhd = mhd[:-1]
    assert not ssa.verify(wrongmhd, x_Q, sig, ec, hf)
    err_msg = "invalid size: 31 bytes instead of 32"
    with pytest.raises(ValueError, match=err_msg):
        ssa.assert_as_valid(wrongmhd, x_Q, sig, ec, hf)

    fssasig = (sig[0], sig[1], sig[1])
    assert not ssa.verify(mhd, x_fQ, fssasig, ec, hf)
    err_msg = "too many values to unpack "
    with pytest.raises(ValueError, match=err_msg):
        ssa.assert_as_valid(mhd, x_Q, fssasig, ec, hf)

    invalid_sig = ec.p, sig[1]
    assert not ssa.verify(mhd, x_Q, invalid_sig)
    err_msg = "x-coordinate not in 0..p-1: "
    with pytest.raises(ValueError, match=err_msg):
        ssa.assert_as_valid(mhd, x_Q, invalid_sig, ec, hf)

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

    err_msg = "invalid size: 31 bytes instead of 32"
    with pytest.raises(ValueError, match=err_msg):
        ssa.sign(wrongmhd, q, None)

    err_msg = "private key not in 1..n-1: "
    with pytest.raises(ValueError, match=err_msg):
        ssa.sign(mhd, 0)

    # ephemeral key not in 1..n-1
    err_msg = "private key not in 1..n-1: "
    with pytest.raises(ValueError, match=err_msg):
        ssa.sign(mhd, 1, 0)

    err_msg = "invalid zero challenge"
    with pytest.raises(ValueError, match=err_msg):
        ssa._recover_pubkey(0, sig[0], sig[1], ec)

    err_msg = "not a BIP340 public key"
    with pytest.raises(ValueError, match=err_msg):
        ssa._to_bip340_point(["not", "a BIP340", "public key"])
Esempio n. 3
0
def test_signature() -> None:
    ec = CURVES["secp256k1"]
    msg = "Satoshi Nakamoto"

    q, x_Q = ssa.gen_keys(0x01)
    sig = ssa.sign(msg, q)
    ssa.assert_as_valid(msg, x_Q, sig)
    assert ssa.verify(msg, x_Q, sig)

    assert sig == ssa.deserialize(sig)

    ssa.assert_as_valid(msg, x_Q, sig)
    ssa.assert_as_valid(msg, x_Q, ssa.serialize(*sig))
    ssa.assert_as_valid(msg, x_Q, ssa.serialize(*sig).hex())

    msg_fake = "Craig Wright"
    assert not ssa.verify(msg_fake, x_Q, sig)
    err_msg = r"y_K is odd|signature verification failed"
    with pytest.raises(BTClibRuntimeError, match=err_msg):
        ssa.assert_as_valid(msg_fake, x_Q, sig)

    _, x_Q_fake = ssa.gen_keys(0x02)
    assert not ssa.verify(msg, x_Q_fake, sig)
    with pytest.raises(BTClibRuntimeError, match=err_msg):
        ssa.assert_as_valid(msg, x_Q_fake, sig)

    _, x_Q_fake = ssa.gen_keys(0x4)
    assert not ssa.verify(msg, x_Q_fake, sig)
    with pytest.raises(BTClibRuntimeError, match=err_msg):
        ssa.assert_as_valid(msg, x_Q_fake, sig)

    err_msg = "not a BIP340 public key"
    with pytest.raises(BTClibValueError, match=err_msg):
        ssa.assert_as_valid(msg, INF, sig)  # type: ignore
    with pytest.raises(BTClibValueError, match=err_msg):
        ssa.point_from_bip340pubkey(INF)  # type: ignore

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

    sig_invalid = ec.p, sig[1]
    assert not ssa.verify(msg, x_Q, sig_invalid)
    err_msg = "x-coordinate not in 0..p-1: "
    with pytest.raises(BTClibValueError, match=err_msg):
        ssa.assert_as_valid(msg, x_Q, sig_invalid)

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

    m_fake = b"\x00" * 31
    err_msg = "invalid size: 31 bytes instead of 32"
    with pytest.raises(BTClibValueError, match=err_msg):
        ssa._assert_as_valid(m_fake, x_Q, sig)

    with pytest.raises(BTClibValueError, match=err_msg):
        ssa._sign(m_fake, q)

    err_msg = "private key not in 1..n-1: "
    with pytest.raises(BTClibValueError, match=err_msg):
        ssa.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):
        ssa._sign(reduce_to_hlen(msg, hf), q, 0)
    with pytest.raises(BTClibValueError, match=err_msg):
        ssa._sign(reduce_to_hlen(msg, hf), q, ec.n)

    err_msg = "invalid zero challenge"
    with pytest.raises(BTClibValueError, match=err_msg):
        ssa.__recover_pubkey(0, sig[0], sig[1], ec)
Esempio n. 4
0
def test_musig():
    """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

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

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

    q3, x_Q3 = ssa.gen_keys()
    x_Q3 = x_Q3.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] = list()
    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 not ec.has_square_y(Q):
        # 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 not ec.has_square_y(K):
        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(r, Q[0], mhd, ec, hf)
    s1 = (k1 + e * a1 * q1) % ec.n
    s2 = (k2 + e * a2 * q2) % ec.n
    s3 = (k3 + e * a3 * q3) % ec.n

    # exchange s_i (interactive)

    # finalize signature (non interactive)
    s = (s1 + s2 + s3) % ec.n
    sig = r, s
    # check signature is valid
    ssa.assert_as_valid(mhd, Q, sig, ec, hf)
    assert ssa.verify(mhd, Q, sig)