import sys import os sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) from src.p2tr import generate_p2tr_address SECRETSCAN_URL = "https://secretscan.org/Bitcoin?address={}" NETWORKS = ['mainnet', 'testnet', 'regtest'] def test_p2tr_fields(): result = generate_p2tr_address('mainnet') assert set(result.keys()) == {'network', 'script_type', 'private_key_hex', 'private_key_wif', 'internal_pubkey_x_hex', 'address'} def test_p2tr_script_type(): result = generate_p2tr_address('mainnet') assert result['script_type'] == 'p2tr' def test_p2tr_address_mainnet(): result = generate_p2tr_address('mainnet') assert result['address'].startswith('bc1p') def test_p2tr_address_testnet(): result = generate_p2tr_address('testnet') assert result['address'].startswith('tb1p') def test_p2tr_address_regtest(): result = generate_p2tr_address('regtest') assert result['address'].startswith('bcrt1p') def test_p2tr_private_key_length(): result = generate_p2tr_address('mainnet') assert len(result['private_key_hex']) == 64 def test_p2tr_internal_pubkey_length(): result = generate_p2tr_address('mainnet') assert len(result['internal_pubkey_x_hex']) == 64 # x-only pubkey, 32 bytes def test_p2tr_unique_addresses(): r1 = generate_p2tr_address('mainnet') r2 = generate_p2tr_address('mainnet') assert r1['address'] != r2['address'] def test_p2tr_print_secretscan(capsys): result = generate_p2tr_address('mainnet') url = SECRETSCAN_URL.format(result['address']) print(f"\n[P2TR] Address: {result['address']}") print(f"[P2TR] Verify on SecretScan: {url}") captured = capsys.readouterr() assert 'secretscan.org' in captured.out # --- Error cases --- def test_p2tr_invalid_network_raises(): import pytest with pytest.raises(ValueError): generate_p2tr_address('invalid_net') # --- Taproot tweak: output key differs from internal key --- def test_p2tr_tweaked_key_differs_from_internal(): result = generate_p2tr_address('mainnet') # The address encodes the tweaked output key (x-only). # Derive internal key x-only from the result and verify they differ. internal_x = result['internal_pubkey_x_hex'] # Decode the bech32m address: find separator (last '1'), skip witness version from src.p2tr import convertbits, _BECH32_CHARSET addr = result['address'] sep = addr.rfind('1') data_chars = addr[sep + 1:] # data + checksum (6 chars) decoded = [_BECH32_CHARSET.index(c) for c in data_chars[:-6]] # strip checksum # decoded[0] = witness version (1 for Taproot), decoded[1:] = 32-byte prog in 5-bit groups output_prog = bytes(convertbits(decoded[1:], 5, 8, False)) output_x_hex = output_prog.hex() # In key-path-only Taproot, the tweak is non-zero so output != internal assert output_x_hex != internal_x # --- WIF format --- def test_p2tr_wif_mainnet_compressed_starts_k_or_l(): result = generate_p2tr_address('mainnet') assert result['private_key_wif'][0] in ('K', 'L') def test_p2tr_wif_testnet_starts_c(): result = generate_p2tr_address('testnet') assert result['private_key_wif'][0] == 'c' # --- All networks produce correct network field --- def test_p2tr_all_networks(): for network in NETWORKS: result = generate_p2tr_address(network) assert result['network'] == network