1import csv, hashlib, random, sys, pathlib2ROOT = pathlib.Path(__file__).resolve().parents[1]3sys.path.insert(0, str(ROOT / "src"))4from wp34 import secp256k1 as k1, sha256 as S, ecdsa as D, schnorr as B5from wp34.ec import Curve678def test_secp256k1_parameters():9 f = k1.verify_parameters()10 for key in ["p_is_prime", "n_is_prime", "G_on_curve", "nG_is_infinity", "beta_cubed_is_1_mod_p",11 "lambda_cubed_is_1_mod_n", "phi_G_equals_lambda_G", "glv_basis_v1", "glv_basis_v2",12 "glv_basis_det_is_n", "disc_is_minus3_times_square", "hasse_exact"]:13 assert f[key], key14 assert f["j_invariant"] == 0 and f["p_mod_3"] == 1 and not f["anomalous"]151617def test_sha256_matches_hashlib():18 rng = random.Random(7)19 for L in [0, 1, 55, 56, 63, 64, 65, 119, 120, 300]:20 m = bytes(rng.getrandbits(8) for _ in range(L))21 assert S.sha256(m) == hashlib.sha256(m).digest()222324def test_sha256_step_inverse():25 rng = random.Random(3)26 for _ in range(50):27 st = tuple(rng.getrandbits(32) for _ in range(8))28 k, w = rng.getrandbits(32), rng.getrandbits(32)29 assert S.step_inverse(S.step(st, k, w), k, w) == st303132def test_ecdsa_against_python_ecdsa_and_coincurve():33 import ecdsa as pyecdsa, coincurve34 rng = random.Random(11)35 for _ in range(5):36 d = rng.randrange(1, k1.n)37 msg = bytes(rng.getrandbits(8) for _ in range(40))38 h = hashlib.sha256(msg).digest()39 r, s = D.sign(d, h, low_s=False)40 sk = pyecdsa.SigningKey.from_secret_exponent(d, curve=pyecdsa.SECP256k1, hashfunc=hashlib.sha256)41 sig_ref = sk.sign_digest_deterministic(h, hashfunc=hashlib.sha256, sigencode=pyecdsa.util.sigencode_strings)42 assert (int.from_bytes(sig_ref[0], "big"), int.from_bytes(sig_ref[1], "big")) == (r, s)43 Q = D.pubkey(d)44 assert D.verify(Q, h, (r, s)) and D.verify_shamir(Q, h, (r, s))45 assert not D.verify(Q, h, (r, (s + 1) % k1.n))46 # coincurve (libsecp256k1) verifies our low-s signature in DER47 rl, sl = D.sign(d, h)48 der = coincurve.utils.der_encode if hasattr(coincurve.utils, "der_encode") else None49 pk = coincurve.PublicKey.from_secret(d.to_bytes(32, "big"))50 from coincurve.ecdsa import cdata_to_der, der_to_cdata # noqa51 import coincurve._libsecp256k1 as lib # noqa52 # use compact 64-byte form via coincurve's verify with hasher=None on the raw hash53 sig64 = rl.to_bytes(32, "big") + sl.to_bytes(32, "big")54 from coincurve.ecdsa import deserialize_compact, cdata_to_der55 assert pk.verify(cdata_to_der(deserialize_compact(sig64)), h, hasher=None)565758def test_bip340_vectors():59 rows = list(csv.DictReader(open(ROOT / "data/vectors/bip340_test_vectors.csv")))60 assert len(rows) == 1961 for row in rows:62 pk = bytes.fromhex(row["public key"]); msg = bytes.fromhex(row["message"]); sig = bytes.fromhex(row["signature"])63 expected = row["verification result"] == "TRUE"64 if row["secret key"]:65 sk = bytes.fromhex(row["secret key"]); aux = bytes.fromhex(row["aux_rand"])66 assert B.pubkey_gen(sk) == pk67 assert B.sign(msg, sk, aux) == sig68 assert B.verify(msg, pk, sig) == expected, row["index"]697071def test_bip340_batch():72 rng = random.Random(5)73 items = []74 for _ in range(4):75 sk = rng.randrange(1, k1.n).to_bytes(32, "big"); aux = bytes(rng.getrandbits(8) for _ in range(32))76 msg = bytes(rng.getrandbits(8) for _ in range(32))77 items.append((msg, B.pubkey_gen(sk), B.sign(msg, sk, aux)))78 assert B.batch_verify(items, random.Random(1))79 bad = list(items); m, pk, sig = bad[2]; bad[2] = (m, pk, sig[:63] + bytes([sig[63] ^ 1]))80 assert not B.batch_verify(bad, random.Random(1))818283def test_glv_decomposition_bounds():84 rng = random.Random(2)85 for _ in range(200):86 k = rng.randrange(1, k1.n)87 k1_, k2_ = k1.glv_decompose(k)88 assert (k1_ + k2_ * k1.lam - k) % k1.n == 089 assert abs(k1_) < 2**129 and abs(k2_) < 2**12990 E = k1.CURVE91 Q = E.mul(k, E.G)92 phi = lambda P: (k1.beta * P[0] % k1.p, P[1])93 assert E.add(E.mul(k1_, E.G), E.mul(k2_, phi(E.G))) == Q949596def test_small_curve_group_law():97 E = Curve(97, 2, 3)98 N = E.count_points_naive()99 rng = random.Random(1)100 for _ in range(20):101 P, Q = E.random_point(rng), E.random_point(rng)102 assert E.add(P, Q) == E.add(Q, P)103 assert E.mul(N, P) is None104 a, b = rng.randrange(1, 300), rng.randrange(1, 300)105 assert E.mul(a + b, P) == E.add(E.mul(a, P), E.mul(b, P))106 assert E.mul_wnaf(a, P) == E.mul(a, P)107