diff --git a/src/local_bip85/__init__.py b/src/local_bip85/__init__.py index 36da833..e1f44b1 100644 --- a/src/local_bip85/__init__.py +++ b/src/local_bip85/__init__.py @@ -6,10 +6,10 @@ logger = logging.getLogger(__name__) try: from .bip85 import BIP85 +except Exception as exc: + logger.error("Failed to import BIP85 module: %s", exc, exc_info=True) + raise ImportError( + "BIP85 dependencies are missing. Install 'bip_utils', 'cryptography', and 'colorama'." + ) from exc - logger.info("BIP85 module imported successfully.") -except Exception as e: - logger.error(f"Failed to import BIP85 module: {e}", exc_info=True) - BIP85 = None - -__all__ = ["BIP85"] if BIP85 is not None else [] +__all__ = ["BIP85"] diff --git a/src/local_bip85/bip85.py b/src/local_bip85/bip85.py index 665b5f3..52b270e 100644 --- a/src/local_bip85/bip85.py +++ b/src/local_bip85/bip85.py @@ -18,6 +18,8 @@ import hashlib import hmac import logging import os +from typing import Union + from colorama import Fore from bip_utils import Bip32Slip10Secp256k1, Bip39MnemonicGenerator, Bip39Languages @@ -37,13 +39,19 @@ class Bip85Error(Exception): class BIP85: - def __init__(self, seed_bytes: bytes | str): - """Initialize from BIP39 seed bytes or BIP32 xprv string.""" + def __init__(self, seed_or_xprv: Union[bytes, str]): + """Initialize from seed bytes or an ``xprv`` string. + + Parameters: + seed_or_xprv (Union[bytes, str]): Either raw BIP39 seed bytes + or a BIP32 extended private key (``xprv``) string. + """ + try: - if isinstance(seed_bytes, (bytes, bytearray)): - self.bip32_ctx = Bip32Slip10Secp256k1.FromSeed(seed_bytes) + if isinstance(seed_or_xprv, (bytes, bytearray)): + self.bip32_ctx = Bip32Slip10Secp256k1.FromSeed(seed_or_xprv) else: - self.bip32_ctx = Bip32Slip10Secp256k1.FromExtendedKey(seed_bytes) + self.bip32_ctx = Bip32Slip10Secp256k1.FromExtendedKey(seed_or_xprv) logging.debug("BIP32 context initialized successfully.") except Exception as e: logging.error(f"Error initializing BIP32 context: {e}", exc_info=True) diff --git a/src/tests/test_bip85_init.py b/src/tests/test_bip85_init.py new file mode 100644 index 0000000..5f12b37 --- /dev/null +++ b/src/tests/test_bip85_init.py @@ -0,0 +1,21 @@ +import sys +from pathlib import Path + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from bip_utils import Bip39SeedGenerator +from local_bip85.bip85 import BIP85 +from helpers import TEST_SEED + +MASTER_XPRV = "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb" + + +def test_init_with_seed_bytes(): + seed_bytes = Bip39SeedGenerator(TEST_SEED).Generate() + bip85 = BIP85(seed_bytes) + assert isinstance(bip85, BIP85) + + +def test_init_with_xprv(): + bip85 = BIP85(MASTER_XPRV) + assert isinstance(bip85, BIP85) diff --git a/src/utils/key_derivation.py b/src/utils/key_derivation.py index ca15423..aed72cf 100644 --- a/src/utils/key_derivation.py +++ b/src/utils/key_derivation.py @@ -23,7 +23,9 @@ import hmac import time from enum import Enum from typing import Optional, Union + from bip_utils import Bip39SeedGenerator +from local_bip85 import BIP85 from cryptography.hazmat.primitives.kdf.hkdf import HKDF from cryptography.hazmat.primitives import hashes @@ -213,8 +215,6 @@ def derive_index_key(seed: str) -> bytes: def derive_totp_secret(seed: str, index: int) -> str: """Derive a base32-encoded TOTP secret from a BIP39 seed.""" try: - from local_bip85 import BIP85 - # Initialize BIP85 from the BIP39 seed bytes seed_bytes = Bip39SeedGenerator(seed).Generate() bip85 = BIP85(seed_bytes)