"""Benchmark spec256k1 vs coincurve."""

import hashlib
import time

import coincurve
import spec256k1

SECRET = b"\x01" * 32
MSG = hashlib.sha256(b"benchmark").digest()
ROUNDS = 10_000


def bench(label, fn, rounds=ROUNDS):
    # warmup
    for _ in range(100):
        fn()
    start = time.perf_counter()
    for _ in range(rounds):
        fn()
    elapsed = time.perf_counter() - start
    us = elapsed / rounds * 1_000_000
    ops = rounds / elapsed
    print(f"  {label:40s} {us:8.1f} µs/op  ({ops:,.0f} ops/s)")
    return elapsed


def main():
    sk_cc = coincurve.PrivateKey(SECRET)
    sk_sp = spec256k1.PrivateKey(SECRET)

    sig_cc = sk_cc.sign_recoverable(MSG, hasher=None)
    sig_sp = sk_sp.sign_recoverable(MSG)

    pk_cc = sk_cc.public_key
    pk_sp = sk_sp.public_key

    print(f"Rounds: {ROUNDS:,}\n")

    print("sign_recoverable:")
    bench("coincurve", lambda: sk_cc.sign_recoverable(MSG, hasher=None))
    bench("spec256k1", lambda: sk_sp.sign_recoverable(MSG))

    print("\nfrom_signature_and_message (recover):")
    bench("coincurve", lambda: coincurve.PublicKey.from_signature_and_message(sig_cc, MSG, hasher=None))
    bench("spec256k1", lambda: spec256k1.PublicKey.from_signature_and_message(sig_sp, MSG))

    print("\nformat(compressed=True):")
    bench("coincurve", lambda: pk_cc.format(compressed=True))
    bench("spec256k1", lambda: pk_sp.format(compressed=True))

    print("\nformat(compressed=False):")
    bench("coincurve", lambda: pk_cc.format(compressed=False))
    bench("spec256k1", lambda: pk_sp.format(compressed=False))

    print("\nPublicKey(compressed_bytes):")
    comp = pk_cc.format(compressed=True)
    bench("coincurve", lambda: coincurve.PublicKey(comp))
    bench("spec256k1", lambda: spec256k1.PublicKey(comp))

    print("\nfull pattern: sign + recover + format:")
    def cc_full():
        sig = sk_cc.sign_recoverable(MSG, hasher=None)
        pk = coincurve.PublicKey.from_signature_and_message(sig, MSG, hasher=None)
        return pk.format(compressed=False)[1:]

    def sp_full():
        sig = sk_sp.sign_recoverable(MSG)
        pk = spec256k1.PublicKey.from_signature_and_message(sig, MSG)
        return pk.format(compressed=False)[1:]

    bench("coincurve", cc_full)
    bench("spec256k1", sp_full)


if __name__ == "__main__":
    main()
