From 86c52810c87606d052e914ec4e596349df4c5479 Mon Sep 17 00:00:00 2001 From: omipheo Date: Thu, 14 May 2026 10:54:21 +0200 Subject: [PATCH 1/2] BIP-0327: avoid using sys.path[0] to find current working directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `bip-0327/reference.py` and `bip-0327/gen_vectors_helper.py` both locate the test-vector JSON files via `os.path.join(sys.path[0], 'vectors', '.json')`. As Sebastian Falbesoner noted in 4e18ee6 ("BIP-374: avoid using sys.path[0] to find current working directory"), this pattern is incompatible with any future `sys.path.insert(0, ...)` extension — for example, the `sys.path.insert(0, str(Path(__file__).parent / "secp256k1lab/src"))` shim that bip-0352 and bip-0374 use to locate their vendored `secp256k1lab` copies. Should bip-0327 follow the same vendoring pattern, every test-vector load would silently miss its file. Switch both files to the `Path(__file__).parent / 'vectors' / '...'` pattern so the path is always resolved relative to the script itself, matching the BIP-374 precedent. `import os` and `import sys` are removed from `reference.py` (no remaining uses); `gen_vectors_helper.py` gets an explicit `from pathlib import Path` since it can no longer inherit those names through `from reference import *`. Verified that `python3 reference.py` and `python3 gen_vectors_helper.py` still exit 0 with all 8 (resp. 2) vector files loading correctly. No behavior change beyond the path-resolution robustness. --- bip-0327/gen_vectors_helper.py | 6 ++++-- bip-0327/reference.py | 19 +++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/bip-0327/gen_vectors_helper.py b/bip-0327/gen_vectors_helper.py index 03c2dbb2ac..ebd245f93a 100644 --- a/bip-0327/gen_vectors_helper.py +++ b/bip-0327/gen_vectors_helper.py @@ -1,3 +1,5 @@ +from pathlib import Path + from reference import * def gen_key_agg_vectors(): @@ -16,7 +18,7 @@ def gen_key_agg_vectors(): print(" tweak: ", tweak.hex().upper()) def check_sign_verify_vectors(): - with open(os.path.join(sys.path[0], 'vectors', 'sign_verify_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'sign_verify_vectors.json') as f: test_data = json.load(f) X = fromhex_all(test_data["pubkeys"]) pnonce = fromhex_all(test_data["pnonces"]) @@ -44,7 +46,7 @@ def check_sign_verify_vectors(): assert has_even_y(Q) and has_even_y(R) def check_tweak_vectors(): - with open(os.path.join(sys.path[0], 'vectors', 'tweak_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'tweak_vectors.json') as f: test_data = json.load(f) X = fromhex_all(test_data["pubkeys"]) diff --git a/bip-0327/reference.py b/bip-0327/reference.py index 5b8d114f65..a7d72481a6 100644 --- a/bip-0327/reference.py +++ b/bip-0327/reference.py @@ -462,8 +462,7 @@ def partial_sig_agg(psigs: List[bytes], session_ctx: SessionContext) -> bytes: # import json -import os -import sys +from pathlib import Path def fromhex_all(l): return [bytes.fromhex(l_i) for l_i in l] @@ -497,7 +496,7 @@ def get_error_details(test_case): return exception, except_fn def test_key_sort_vectors() -> None: - with open(os.path.join(sys.path[0], 'vectors', 'key_sort_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'key_sort_vectors.json') as f: test_data = json.load(f) X = fromhex_all(test_data["pubkeys"]) @@ -506,7 +505,7 @@ def test_key_sort_vectors() -> None: assert key_sort(X) == X_sorted def test_key_agg_vectors() -> None: - with open(os.path.join(sys.path[0], 'vectors', 'key_agg_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'key_agg_vectors.json') as f: test_data = json.load(f) X = fromhex_all(test_data["pubkeys"]) @@ -530,7 +529,7 @@ def test_key_agg_vectors() -> None: assert_raises(exception, lambda: key_agg_and_tweak(pubkeys, tweaks, is_xonly), except_fn) def test_nonce_gen_vectors() -> None: - with open(os.path.join(sys.path[0], 'vectors', 'nonce_gen_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'nonce_gen_vectors.json') as f: test_data = json.load(f) for test_case in test_data["test_cases"]: @@ -557,7 +556,7 @@ def get_value_maybe(key) -> Optional[bytes]: assert nonce_gen_internal(rand_, sk, pk, aggpk, msg, extra_in) == (expected_secnonce, expected_pubnonce) def test_nonce_agg_vectors() -> None: - with open(os.path.join(sys.path[0], 'vectors', 'nonce_agg_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'nonce_agg_vectors.json') as f: test_data = json.load(f) pnonce = fromhex_all(test_data["pnonces"]) @@ -575,7 +574,7 @@ def test_nonce_agg_vectors() -> None: assert_raises(exception, lambda: nonce_agg(pubnonces), except_fn) def test_sign_verify_vectors() -> None: - with open(os.path.join(sys.path[0], 'vectors', 'sign_verify_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'sign_verify_vectors.json') as f: test_data = json.load(f) sk = bytes.fromhex(test_data["sk"]) @@ -658,7 +657,7 @@ def test_sign_verify_vectors() -> None: assert_raises(exception, lambda: partial_sig_verify(sig, pubnonces, pubkeys, [], [], msg, signer_index), except_fn) def test_tweak_vectors() -> None: - with open(os.path.join(sys.path[0], 'vectors', 'tweak_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'tweak_vectors.json') as f: test_data = json.load(f) sk = bytes.fromhex(test_data["sk"]) @@ -715,7 +714,7 @@ def test_tweak_vectors() -> None: assert_raises(exception, lambda: sign(secnonce, sk, session_ctx), except_fn) def test_det_sign_vectors() -> None: - with open(os.path.join(sys.path[0], 'vectors', 'det_sign_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'det_sign_vectors.json') as f: test_data = json.load(f) sk = bytes.fromhex(test_data["sk"]) @@ -762,7 +761,7 @@ def test_det_sign_vectors() -> None: assert_raises(exception, try_fn, except_fn) def test_sig_agg_vectors() -> None: - with open(os.path.join(sys.path[0], 'vectors', 'sig_agg_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'sig_agg_vectors.json') as f: test_data = json.load(f) X = fromhex_all(test_data["pubkeys"]) From b39a896e28ba94f660cb0d1c2fb6e9200e81a6ba Mon Sep 17 00:00:00 2001 From: omipheo Date: Fri, 15 May 2026 01:45:05 +0200 Subject: [PATCH 2/2] BIPs 89, 328, 340: avoid using sys.path[0] to find current working directory Same fix as the previous commit on BIP-0327, applied to the remaining reference implementations that still use the `os.path.join(sys.path[0], ...)` pattern: bip-0089/reference.py (8 sites), bip-0328/reference.py (1 site), and bip-0340/reference.py (1 site). All resolve test-vector paths via `Path(__file__).parent / ...` so future `sys.path.insert(0, ...)` extensions for vendored deps won't silently miss the data files. `import os` and `import sys` are dropped from each file (no remaining uses). bip-0340/test-vectors.py imports `sys` itself for `sys.stdout` so its wildcard `from reference import *` is unaffected by the import cleanup in bip-0340/reference.py. Verified: `python3 reference.py` for each of bip-0089, bip-0328, bip-0340 still exits 0 with all test vectors loading; bip-0340's test-vectors.py importer also still exits 0. Per @jonatack's review note on PR #2158. --- bip-0089/reference.py | 19 +++++++++---------- bip-0328/reference.py | 5 ++--- bip-0340/reference.py | 5 ++--- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/bip-0089/reference.py b/bip-0089/reference.py index f81d5359a2..3ede724e90 100644 --- a/bip-0089/reference.py +++ b/bip-0089/reference.py @@ -7,9 +7,8 @@ from typing import Dict, Mapping, Optional, Sequence, Tuple, NewType, NamedTuple, List, Callable, Any, cast import hashlib import json -import os +from pathlib import Path import secrets -import sys from bip32 import ( CURVE_N, @@ -280,7 +279,7 @@ def build_session_ctx(obj): return (pk, a, e, R, tweaks, is_xonly) def test_blind_nonce_gen_vectors(): - with open(os.path.join(sys.path[0], 'vectors', 'blind_nonce_gen_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'blind_nonce_gen_vectors.json') as f: tv = json.load(f) for tc in tv["test_cases"]: @@ -311,7 +310,7 @@ def get_bytes_maybe(key) -> Optional[bytes]: assert len(expected_blindpubnonce) == 33 def test_blind_challenge_gen_vectors(): - with open(os.path.join(sys.path[0], 'vectors', 'blind_challenge_gen_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'blind_challenge_gen_vectors.json') as f: tv = json.load(f) # ---------- Valid cases ---------- @@ -388,7 +387,7 @@ def test_blind_challenge_gen_vectors(): assert raised, "Expected an exception but none was raised" def test_blind_sign_and_verify_vectors(): - with open(os.path.join(sys.path[0], 'vectors', 'blind_sign_and_verify_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'blind_sign_and_verify_vectors.json') as f: tv = json.load(f) # ------------------ Valid ------------------ @@ -479,7 +478,7 @@ def try_again(): assert_raises(exception, lambda: verify_blind_signature(pk, blindpubnonce, blindchallenge, blindsignature, pk_parity, nonce_parity), except_fn) def test_unblind_signature_vectors(): - with open(os.path.join(sys.path[0], 'vectors', 'unblind_signature_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'unblind_signature_vectors.json') as f: tv = json.load(f) # ---------- Valid ---------- @@ -619,7 +618,7 @@ def delegator_sign( return signature def test_compute_tweak_vectors() -> None: - with open(os.path.join(sys.path[0], 'vectors', 'compute_bip32_tweak_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'compute_bip32_tweak_vectors.json') as f: data = json.load(f) default_xpub_data = data.get("xpub") @@ -675,7 +674,7 @@ def test_compute_tweak_vectors() -> None: raise AssertionError("expected failure but case succeeded") def test_delegator_sign_vectors() -> None: - with open(os.path.join(sys.path[0], 'vectors', 'delegator_sign_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'delegator_sign_vectors.json') as f: data = json.load(f) for case in data.get("test_cases", []): @@ -706,7 +705,7 @@ def test_delegator_sign_vectors() -> None: def test_input_verification_vectors() -> None: - with open(os.path.join(sys.path[0], 'vectors', 'input_verification_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'input_verification_vectors.json') as f: data = json.load(f) @@ -729,7 +728,7 @@ def test_input_verification_vectors() -> None: ) def test_change_output_verification_vectors() -> None: - with open(os.path.join(sys.path[0], 'vectors', 'change_output_verification_vectors.json')) as f: + with open(Path(__file__).parent / 'vectors' / 'change_output_verification_vectors.json') as f: data = json.load(f) for case in data.get("test_cases", []): diff --git a/bip-0328/reference.py b/bip-0328/reference.py index d7e493e2ea..f114250815 100644 --- a/bip-0328/reference.py +++ b/bip-0328/reference.py @@ -1,8 +1,7 @@ #! /usr/bin/env python3 import json -import os -import sys +from pathlib import Path from _base58 import xpub_to_pub_hex from _bip327 import cbytes, key_agg @@ -14,7 +13,7 @@ def aggregate_to_xpub(aggregate: bytes) -> ExtendedKey: return ExtendedKey(ExtendedKey.MAINNET_PUBLIC, 0, b"\x00\x00\x00\x00", 0, CHAINCODE, None, aggregate) def test_aggregate_to_xpub(): - with open(os.path.join(sys.path[0], "vectors.json"), "r") as f: + with open(Path(__file__).parent / "vectors.json", "r") as f: test_data = json.load(f) for test_case in test_data: diff --git a/bip-0340/reference.py b/bip-0340/reference.py index bf8f16203a..f6d8af7bf5 100644 --- a/bip-0340/reference.py +++ b/bip-0340/reference.py @@ -140,12 +140,11 @@ def schnorr_verify(msg: bytes, pubkey: bytes, sig: bytes) -> bool: # The following code is only used to verify the test vectors. # import csv -import os -import sys +from pathlib import Path def test_vectors() -> bool: all_passed = True - with open(os.path.join(sys.path[0], 'test-vectors.csv'), newline='') as csvfile: + with open(Path(__file__).parent / 'test-vectors.csv', newline='') as csvfile: reader = csv.reader(csvfile) reader.__next__() for row in reader: