Ejemplo n.º 1
0
def test_libsecp256k1() -> None:
    msg = "Satoshi Nakamoto".encode()

    q, _ = dsa.gen_keys(0x1)
    sig = dsa.sign(msg, q)

    msg_hash = reduce_to_hlen(msg)
    secret = q.to_bytes(32, "big")

    c_sig = ffi.new("secp256k1_ecdsa_signature *")
    if not lib.secp256k1_ecdsa_sign(GLOBAL_CTX, c_sig, msg_hash, secret,
                                    ffi.NULL, ffi.NULL):
        raise RuntimeError("libsecp256k1 signature failed")

    output = ffi.new("unsigned char[%d]" % CDATA_SIG_LENGTH)
    if not lib.secp256k1_ecdsa_signature_serialize_compact(
            GLOBAL_CTX, output, c_sig):
        raise RuntimeError("libsecp256k1 signature serialization failed")

    c_sig_bytes = bytes(ffi.buffer(output, CDATA_SIG_LENGTH))

    r = c_sig_bytes[:32]
    s = c_sig_bytes[32:]

    assert r.hex() == sig.r.to_bytes(32, "big").hex()
    assert s.hex() == sig.s.to_bytes(32, "big").hex()
Ejemplo n.º 2
0
def test_pub_key_recovery() -> None:

    ec = CURVES["secp112r2"]

    q = 0x10
    Q = mult(q, ec.G, ec)

    msg = "Satoshi Nakamoto".encode()
    sig = dsa.sign(msg, q, ec=ec)
    dsa.assert_as_valid(msg, Q, sig)
    assert dsa.verify(msg, Q, sig)

    keys = dsa.recover_pub_keys(msg, sig)
    assert len(keys) == 4
    assert Q in keys
    for Q in keys:
        assert dsa.verify(msg, Q, sig)
Ejemplo n.º 3
0
def sign(msg: Octets, prv_key: PrvKey, addr: Optional[String] = None) -> Sig:
    "Generate address-based compact signature for the provided message."

    # first sign the message
    magic_msg = magic_message(msg)
    q, network, compressed = prv_keyinfo_from_prv_key(prv_key)
    dsa_sig = dsa.sign(magic_msg, q)

    # now calculate the key_id
    # TODO do the match in Jacobian coordinates avoiding mod_inv
    pub_keys = dsa.recover_pub_keys(magic_msg, dsa_sig)
    Q = mult(q)
    # key_id is in [0, 3]
    # first two bits in rf are reserved for it
    key_id = pub_keys.index(Q)
    pub_key = bytes_from_point(Q, compressed=compressed)

    if isinstance(addr, str):
        addr = addr.strip()
    elif isinstance(addr, bytes):
        addr = addr.decode("ascii")

    # finally, calculate the recovery flag
    if addr is None or addr == p2pkh(pub_key, network, compressed):
        rf = key_id + 27
        # third bit in rf is reserved for the 'compressed' boolean
        rf += 4 if compressed else 0
    # BIP137
    elif addr == p2wpkh_p2sh(pub_key, network):
        rf = key_id + 35
    elif addr == p2wpkh(pub_key, network):
        rf = key_id + 39
    else:
        raise BTClibValueError("mismatch between private key and address")

    return Sig(rf, dsa_sig)
Ejemplo n.º 4
0
print("\n*** EC:")
print(ec)

print("0. Key generation")
q = 0x18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725
q %= ec.n
Q = mult(q, ec.G)
print(f"prvkey:    {hex(q).upper()}")
print(f"PubKey: {'02' if Q[1] % 2 == 0 else '03'} {hex(Q[0]).upper()}")

print("\n1. Message to be signed")
msg1 = "Paolo is afraid of ephemeral random numbers".encode()
print(msg1.decode())

print("2. Sign message")
sig1 = sign(msg1, q)
print(f"    r1:    {hex(sig1.r).upper()}")
print(f"    s1:    {hex(sig1.s).upper()}")

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()}")
Ejemplo n.º 5
0
def test_signature() -> None:
    msg = "Satoshi Nakamoto".encode()

    q, Q = dsa.gen_keys(0x1)
    sig = dsa.sign(msg, q)
    dsa.assert_as_valid(msg, Q, sig)
    assert dsa.verify(msg, Q, sig)
    assert sig == dsa.Sig.parse(sig.serialize())
    assert sig == dsa.Sig.parse(sig.serialize().hex())

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

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

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

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

    msg_fake = "Craig Wright".encode()
    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_invalid = dsa.Sig(sig.ec.p, sig.s, check_validity=False)
    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 = dsa.Sig(sig.r, sig.ec.p, check_validity=False)
    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, sig.ec.n)
Ejemplo n.º 6
0
def test_sign_input_type() -> None:
    msg = "Satoshi Nakamoto".encode()
    q, Q = dsa.gen_keys(0x1)
    sig = dsa.sign(msg, q)
    dsa.assert_as_valid(msg, Q, sig)
    dsa.assert_as_valid(msg, Q, sig.serialize())
Ejemplo n.º 7
0
from btclib.ecc import bms, dsa, ssa

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

# 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.r))
print("s:", hex(dsa_sig.s))

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.r))
print("s:", hex(ssa_sig.s))

ssa_valid = ssa.verify(msg, ssa_pub, ssa_sig)