Files
easy-wallet/tests/test_single_wallet.py

260 lines
8.1 KiB
Python
Raw Normal View History

import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
import pytest
from src.single_wallet import encrypt_single_wallet, decrypt_single_wallet
from src.p2pkh import generate_legacy_address
from src.p2wpkh import generate_segwit_address
from src.p2tr import generate_p2tr_address
from src.p2pk import generate_p2pk
SECRETSCAN_URL = "https://secretscan.org/Bitcoin?address={}"
PASSWORD = "correct_horse_battery_staple"
# --- Fixtures ---
def _p2pkh():
return generate_legacy_address('mainnet')
def _p2wpkh():
return generate_segwit_address('mainnet')
def _p2tr():
return generate_p2tr_address('mainnet')
def _p2pk():
return generate_p2pk('mainnet', compressed=True)
# --- encrypt_single_wallet: output structure ---
def test_encrypt_sets_use_encryption_flag():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
assert encrypted['use_encryption'] is True
def test_encrypt_returns_dict():
wallet = _p2pkh()
result = encrypt_single_wallet(wallet, PASSWORD)
assert isinstance(result, dict)
# --- encrypt_single_wallet: sensitive fields are encrypted ---
def test_encrypt_private_key_hex_changes():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
assert encrypted['private_key_hex'] != wallet['private_key_hex']
def test_encrypt_private_key_wif_changes():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
assert encrypted['private_key_wif'] != wallet['private_key_wif']
# --- encrypt_single_wallet: public fields are preserved ---
def test_encrypt_preserves_address():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
assert encrypted['address'] == wallet['address']
def test_encrypt_preserves_public_key_hex():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
assert encrypted['public_key_hex'] == wallet['public_key_hex']
def test_encrypt_preserves_network():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
assert encrypted['network'] == wallet['network']
def test_encrypt_preserves_script_type():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
assert encrypted['script_type'] == wallet['script_type']
# --- encrypt_single_wallet: immutability ---
def test_encrypt_does_not_mutate_original_private_key_hex():
wallet = _p2pkh()
original_key = wallet['private_key_hex']
encrypt_single_wallet(wallet, PASSWORD)
assert wallet['private_key_hex'] == original_key
def test_encrypt_does_not_mutate_original_private_key_wif():
wallet = _p2pkh()
original_wif = wallet['private_key_wif']
encrypt_single_wallet(wallet, PASSWORD)
assert wallet['private_key_wif'] == original_wif
def test_encrypt_does_not_set_flag_on_original():
wallet = _p2pkh()
assert 'use_encryption' not in wallet
encrypt_single_wallet(wallet, PASSWORD)
assert 'use_encryption' not in wallet
# --- encrypt_single_wallet: error cases ---
def test_encrypt_empty_password_raises_value_error():
wallet = _p2pkh()
with pytest.raises(ValueError):
encrypt_single_wallet(wallet, "")
# --- decrypt_single_wallet: round-trips ---
def test_decrypt_round_trip_private_key_hex():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
decrypted = decrypt_single_wallet(encrypted, PASSWORD)
assert decrypted['private_key_hex'] == wallet['private_key_hex']
def test_decrypt_round_trip_private_key_wif():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
decrypted = decrypt_single_wallet(encrypted, PASSWORD)
assert decrypted['private_key_wif'] == wallet['private_key_wif']
def test_decrypt_clears_use_encryption_flag():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
decrypted = decrypt_single_wallet(encrypted, PASSWORD)
assert decrypted['use_encryption'] is False
def test_decrypt_preserves_address():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
decrypted = decrypt_single_wallet(encrypted, PASSWORD)
assert decrypted['address'] == wallet['address']
def test_decrypt_preserves_public_key():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
decrypted = decrypt_single_wallet(encrypted, PASSWORD)
assert decrypted['public_key_hex'] == wallet['public_key_hex']
# --- decrypt_single_wallet: unencrypted wallet is a no-op ---
def test_decrypt_unencrypted_wallet_noop():
wallet = _p2pkh()
result = decrypt_single_wallet(wallet, PASSWORD)
assert result['private_key_hex'] == wallet['private_key_hex']
def test_decrypt_unencrypted_wallet_returns_copy():
wallet = _p2pkh()
result = decrypt_single_wallet(wallet, PASSWORD)
assert result is not wallet
# --- decrypt_single_wallet: immutability ---
def test_decrypt_does_not_mutate_encrypted_wallet():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
original_enc_key = encrypted['private_key_hex']
decrypt_single_wallet(encrypted, PASSWORD)
assert encrypted['private_key_hex'] == original_enc_key
# --- decrypt_single_wallet: error cases ---
def test_decrypt_wrong_password_raises_value_error():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
with pytest.raises(ValueError):
decrypt_single_wallet(encrypted, "wrong_password")
def test_decrypt_empty_password_raises_value_error():
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
with pytest.raises(ValueError):
decrypt_single_wallet(encrypted, "")
# --- Works with all wallet types ---
def test_encrypt_decrypt_p2wpkh():
wallet = _p2wpkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
decrypted = decrypt_single_wallet(encrypted, PASSWORD)
assert decrypted['private_key_hex'] == wallet['private_key_hex']
assert decrypted['address'] == wallet['address']
def test_encrypt_decrypt_p2tr():
wallet = _p2tr()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
decrypted = decrypt_single_wallet(encrypted, PASSWORD)
assert decrypted['private_key_hex'] == wallet['private_key_hex']
assert decrypted['address'] == wallet['address']
def test_encrypt_decrypt_p2pk():
# P2PK has no 'address' field; only private keys are sensitive
wallet = _p2pk()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
decrypted = decrypt_single_wallet(encrypted, PASSWORD)
assert decrypted['private_key_hex'] == wallet['private_key_hex']
assert decrypted['private_key_wif'] == wallet['private_key_wif']
assert decrypted['public_key_hex'] == wallet['public_key_hex']
def test_encrypt_all_networks():
for network in ('mainnet', 'testnet', 'regtest'):
wallet = generate_legacy_address(network)
encrypted = encrypt_single_wallet(wallet, PASSWORD)
decrypted = decrypt_single_wallet(encrypted, PASSWORD)
assert decrypted['private_key_hex'] == wallet['private_key_hex']
# --- Two different passwords produce different ciphertext ---
def test_different_passwords_different_ciphertext():
wallet = _p2pkh()
enc1 = encrypt_single_wallet(wallet, "password_one")
enc2 = encrypt_single_wallet(wallet, "password_two")
assert enc1['private_key_hex'] != enc2['private_key_hex']
# --- SecretScan ---
def test_single_wallet_print_secretscan(capsys):
wallet = _p2pkh()
encrypted = encrypt_single_wallet(wallet, PASSWORD)
decrypted = decrypt_single_wallet(encrypted, PASSWORD)
url = SECRETSCAN_URL.format(wallet['address'])
print(f"\n[SingleWallet] P2PKH Address: {wallet['address']}")
print(f"[SingleWallet] Verify on SecretScan: {url}")
captured = capsys.readouterr()
assert 'secretscan.org' in captured.out
assert decrypted['private_key_hex'] == wallet['private_key_hex']
def test_single_wallet_p2wpkh_print_secretscan(capsys):
wallet = _p2wpkh()
url = SECRETSCAN_URL.format(wallet['address'])
print(f"\n[SingleWallet] P2WPKH Address: {wallet['address']}")
print(f"[SingleWallet] Verify on SecretScan: {url}")
captured = capsys.readouterr()
assert 'secretscan.org' in captured.out