Skip to content

Bitcoin Address Types vs Address Formats - Reference Guide

CRITICAL REFERENCE: This document clarifies the distinction between address types and address formats to prevent common AI agent and developer confusion.

Table of Contents

Core Concepts

Address Type (Semantic Concept)

Address Type refers to the semantic purpose and script structure of a Bitcoin address.

  • Defines HOW bitcoins are locked (script type)
  • Determines signature requirements
  • Examples: P2PKH, P2SH, P2WPKH, P2WSH, P2TR

Address Format (Encoding Method)

Address Format refers to the encoding scheme used to represent the address as a string.

  • Defines HOW the address is displayed/encoded
  • Does NOT change the underlying script type
  • Examples: Base58, Bech32, Bech32m

Critical Distinction

Address Type ≠ Address Format

P2TR (address type) USES bech32m (address format)

Terminology Reference

Address Types (Script Types)

Address TypeFull NameDescriptionBIP
P2PKHPay-to-PubKey-HashLegacy single-sigBIP13
P2SHPay-to-Script-HashLegacy multisig wrapperBIP16
P2WPKHPay-to-Witness-PubKey-HashNative SegWit single-sigBIP141, BIP84
P2WSHPay-to-Witness-Script-HashNative SegWit multisigBIP141, BIP84
P2SH-P2WPKHNested SegWit single-sigSegWit wrapped in P2SHBIP141, BIP49
P2SH-P2WSHNested SegWit multisigSegWit multisig wrapped in P2SHBIP141, BIP49
P2TRPay-to-TaprootTaproot (Schnorr)BIP341, BIP86

Address Formats (Encoding Schemes)

FormatDescriptionAddress PrefixUsed ForChecksum
Base58Legacy encoding1... (P2PKH)
3... (P2SH)
P2PKH, P2SHBase58Check
Bech32SegWit encodingbc1q... (mainnet)
tb1q... (testnet)
bcrt1q... (regtest)
P2WPKH, P2WSHBCH error correction
Bech32mModified Bech32bc1p... (mainnet)
tb1p... (testnet)
bcrt1p... (regtest)
P2TR (Taproot)Fixed checksum

Key Relationships

┌─────────────────────────────────────────────────────────────┐
│                      Address Types                          │
├──────────────┬──────────────┬───────────────────────────────┤
│   Legacy     │   SegWit     │         Taproot              │
├──────────────┼──────────────┼───────────────────────────────┤
│ P2PKH, P2SH  │ P2WPKH,      │          P2TR                │
│              │ P2WSH,       │                              │
│              │ P2SH-P2WPKH, │                              │
│              │ P2SH-P2WSH   │                              │
└──────────────┴──────────────┴───────────────────────────────┘
       │              │                    │
       ▼              ▼                    ▼
   Base58          Bech32              Bech32m
 (1... 3...)      (bc1q...)           (bc1p...)

Configuration Values

In go-crypto-wallet Configuration

address_type Field

This field specifies the address type (semantic concept), NOT the encoding format.

Valid Values:

Config ValueActual Address TypeAddress FormatAddress PrefixBIP
"legacy"P2PKH (single-sig)
P2SH (multisig)
Base581... or 3...BIP44
"p2sh-segwit"P2SH-P2WPKH (single-sig)
P2SH-P2WSH (multisig)
Base583...BIP49
"bech32"P2WPKH (single-sig)
P2WSH (multisig)
Bech32bc1q... (62 chars for WSH)BIP84
"taproot"P2TRBech32mbc1p...BIP86
"bech32m"⚠️ INVALID - Use "taproot" instead---

⚠️ Common Mistake

yaml
# ❌ WRONG - "bech32m" is an encoding format, not an address type
address_type: "bech32m"

# ✅ CORRECT - "taproot" is the address type
address_type: "taproot"

key_type Field

This field specifies the BIP derivation path standard.

Valid Values:

Config ValueBIPDerivation PathAddress Type Compatibility
"bip44"BIP44m/44'/0'/account'/0/indexlegacy (P2PKH)
"bip49"BIP49m/49'/0'/account'/0/indexp2sh-segwit (P2SH-P2WPKH)
"bip84"BIP84m/84'/0'/account'/0/indexbech32 (P2WPKH)
"bip86"BIP86m/86'/0'/account'/0/indextaproot (P2TR)
"musig2"CustomCoin-level xpub exporttaproot (P2TR with MuSig2)

Automatic Derivation

In go-crypto-wallet, key_type is automatically derived from address_type:

go
// internal/domain/address/types.go
func (a AddrType) ToKeyType() (key.KeyType, error) {
 switch a {
 case AddrTypeLegacy:
  return key.KeyTypeBIP44, nil
 case AddrTypeP2shSegwit:
  return key.KeyTypeBIP49, nil
 case AddrTypeBech32:
  return key.KeyTypeBIP84, nil
 case AddrTypeTaproot:
  return key.KeyTypeBIP86, nil
 case AddrTypeBCHCashAddr:
  // BCH uses BIP44 derivation path (same as legacy BTC)
  return key.KeyTypeBIP44, nil
 case AddrTypeETH:
  // Ethereum uses BIP44 derivation path
  return key.KeyTypeBIP44, nil
 default:
  return "", fmt.Errorf("unsupported address type for key derivation: %s", a)
 }
}

Configuration Example:

yaml
# Only specify address_type - key_type is derived automatically
address_type: "taproot"  # Automatically uses BIP86 (key_type)

# You do NOT need to specify:
# key_type: "bip86"  # This is automatic!

Common Mistakes

Mistake 1: Confusing "bech32m" with "taproot"

❌ WRONG:

yaml
address_type: "bech32m"  # This will fail - bech32m is a format, not a type

✅ CORRECT:

yaml
address_type: "taproot"  # Taproot uses bech32m format automatically

Explanation:

  • "bech32m" is an encoding format (how addresses are displayed)
  • "taproot" is an address type (the script structure)
  • Taproot addresses automatically use bech32m encoding
  • The configuration expects address types, not encoding formats

Mistake 2: Using "bech32" for Taproot

❌ WRONG:

yaml
address_type: "bech32"  # This creates P2WPKH addresses (bc1q...), NOT Taproot!

✅ CORRECT:

yaml
address_type: "taproot"  # This creates P2TR addresses (bc1p...)

Explanation:

  • "bech32" refers to Native SegWit (P2WPKH/P2WSH) addresses
  • Native SegWit uses the original bech32 encoding
  • Taproot uses the improved bech32m encoding
  • These are different address types with different encodings

Mistake 3: Mixing Address Prefixes

Address Prefix Meanings:

PrefixNetworkFormatAddress Type
bc1q...MainnetBech32P2WPKH (20-byte hash) or P2WSH (32-byte hash)
bc1p...MainnetBech32mP2TR (Taproot)
tb1q...TestnetBech32P2WPKH or P2WSH
tb1p...TestnetBech32mP2TR
bcrt1q...RegtestBech32P2WPKH or P2WSH
bcrt1p...RegtestBech32mP2TR

❌ WRONG Interpretation:

"I need a bc1p... address, so I'll set address_type: "bech32m""

✅ CORRECT Interpretation:

"I need a Taproot address, so I'll set address_type: "taproot", which produces bc1p... addresses automatically"

Mistake 4: Not Understanding the Relationship

┌──────────────────────────────────────────────────────┐
│ Configuration:  address_type: "taproot"             │
│                                                      │
│        ↓ (determines)                               │
│                                                      │
│ Address Type:   P2TR (Pay-to-Taproot)              │
│                                                      │
│        ↓ (automatically uses)                       │
│                                                      │
│ Address Format: bech32m                             │
│                                                      │
│        ↓ (results in)                               │
│                                                      │
│ Address Prefix: bc1p... (mainnet)                  │
│                 tb1p... (testnet)                   │
│                 bcrt1p... (regtest)                 │
└──────────────────────────────────────────────────────┘

Quick Reference Table

Address Type → Format → Prefix

Config: address_typeAddress TypeFormatMainnetTestnetRegtestLength
"legacy"P2PKHBase581...m.../n...m.../n...26-35
"legacy" (multisig)P2SHBase583...2...2...26-35
"p2sh-segwit"P2SH-P2WPKHBase583...2...2...26-35
"p2sh-segwit" (multisig)P2SH-P2WSHBase583...2...2...26-35
"bech32"P2WPKHBech32bc1q...tb1q...bcrt1q...42
"bech32" (multisig)P2WSHBech32bc1q...tb1q...bcrt1q...62
"taproot"P2TRBech32mbc1p...tb1p...bcrt1p...62

E2E Script Configuration

Pattern 9 (P2TR Taproot Single-sig):

bash
# Environment variable override
export WALLET_ADDRESS_TYPE="taproot"  # ✅ CORRECT

# NOT this:
export WALLET_ADDRESS_TYPE="bech32m"  # ❌ WRONG - will fail
export WALLET_ADDRESS_TYPE="bc1p"     # ❌ WRONG - that's a prefix, not a type

Examples

Example 1: Generating Taproot Addresses

Configuration:

yaml
# config/wallet/btc/keygen.yaml
address_type: "taproot"  # This is all you need!
# key_type is automatically set to "bip86"

Result:

bash
$ keygen --coin btc create hdkey --account payment --count 1
# Generates address with derivation path: m/86'/0'/1'/0/0
# Address format: bcrt1p... (regtest) or bc1p... (mainnet)
# Address encoding: bech32m (automatic)

Example 2: Bitcoin Core RPC

Generating New Address:

bash
# Correct: Specify the address type
bitcoin-cli -regtest -rpcwallet=watch getnewaddress "" bech32m
# Returns: bcrt1p... (Taproot address)

# Also correct: Use label "taproot"
bitcoin-cli -regtest -rpcwallet=watch getnewaddress "mylabel" bech32m

# IMPORTANT: The "bech32m" parameter here refers to the desired format,
# which Bitcoin Core interprets as "generate a Taproot address"

Example 3: Identifying Address Type from Prefix

python
def identify_address_type(address: str) -> str:
    """Identify Bitcoin address type from prefix."""

    if address.startswith('1'):
        return "P2PKH (Legacy)"
    elif address.startswith(('3', '2')):
        return "P2SH (Legacy multisig or Nested SegWit)"
    elif address.startswith(('bc1q', 'tb1q', 'bcrt1q')):
        # Check length: 42 = P2WPKH, 62 = P2WSH
        if len(address) == 42:
            return "P2WPKH (Native SegWit)"
        elif len(address) == 62:
            return "P2WSH (Native SegWit Multisig)"
    elif address.startswith(('bc1p', 'tb1p', 'bcrt1p')):
        return "P2TR (Taproot)"

    return "Unknown"

# Examples
print(identify_address_type("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"))
# Output: "P2PKH (Legacy)"

print(identify_address_type("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"))
# Output: "P2WPKH (Native SegWit)"

print(identify_address_type("bc1p5d7rjq7g6rdk2yhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3297"))
# Output: "P2TR (Taproot)"

AI Agent Guidelines

When Reviewing Code or Configuration

  1. Never suggest address_type: "bech32m"

    • ✅ Use address_type: "taproot" instead
    • Bech32m is the encoding, not the type
  2. Verify Environment Variable Names

    • WALLET_ADDRESS_TYPE="taproot"
    • WALLET_ADDRESS_TYPE="bech32m"
  3. Check Address Prefix Expectations

    • bc1q... (42 chars) = P2WPKH (Native SegWit single-sig)
    • bc1q... (62 chars) = P2WSH (Native SegWit multisig)
    • bc1p... (62 chars) = P2TR (Taproot)
  4. Bitcoin Core RPC Calls

    • getnewaddress "" bech32m → Creates Taproot address (bc1p...)
    • getnewaddress "" bech32 → Creates Native SegWit address (bc1q...)

Common Confusion Patterns

AI Agent Says...Correct Interpretation
"Set address format to bech32m""Set address type to taproot"
"Use bech32m addresses""Use Taproot addresses (which use bech32m encoding)"
"Configure bech32m""Configure taproot (which automatically uses bech32m)"

References

BIPs (Bitcoin Improvement Proposals)

  • BIP13: Address Format for pay-to-script-hash
  • BIP16: Pay to Script Hash (P2SH)
  • BIP44: Multi-Account Hierarchy for Deterministic Wallets (Legacy)
  • BIP49: Derivation scheme for P2WPKH-nested-in-P2SH (Nested SegWit)
  • BIP84: Derivation scheme for P2WPKH (Native SegWit)
  • BIP86: Key Derivation for Single Key P2TR Outputs (Taproot)
  • BIP141: Segregated Witness (SegWit)
  • BIP173: Base32 address format for native v0-16 witness outputs (Bech32)
  • BIP350: Bech32m format for v1+ witness addresses (Taproot)
  • BIP340: Schnorr Signatures for secp256k1
  • BIP341: Taproot: SegWit version 1 spending rules

Internal Code References

  • internal/domain/address/types.go: Address type definitions and conversions
  • internal/domain/key/types.go: Key type definitions (BIP44/49/84/86)
  • pkg/address/: Address encoding/decoding utilities

Summary

Remember These Key Points

  1. Taproot is an address type (P2TR)
  2. Bech32m is an encoding format
  3. In configuration, use address_type: "taproot", NOT "bech32m"
  4. Taproot addresses automatically use bech32m encoding
  5. Address prefixes tell you the type:
    • bc1q... = Native SegWit (Bech32)
    • bc1p... = Taproot (Bech32m)

Quick Decision Guide

Need to create Taproot addresses?

yaml
# Step 1: Configure
address_type: "taproot"  # That's it!

# Step 2: Generate
$ keygen create hdkey --account payment

# Step 3: Verify
$ keygen export address --account payment
# Should see: bcrt1p... addresses

Last Updated: 2026-01-16 Version: 1.0 Maintainer: go-crypto-wallet team