Overview
This document specifies how Cowboy private keys are stored on disk, encoded for transport, and backed up by users. Cowboy uses a self-describing, checksummed PEM envelope as the primary storage format, BIP-39 mnemonics with BIP-32/44 HD derivation as the human-readable backup and multi-key format, and an encrypted JSON keystore for production deployments. Cowboy uses secp256k1 (ECDSA) for all account keys. This is the same curve used by Ethereum and Bitcoin, which gives Cowboy native Ethereum key compatibility — the same private key can control both a Cowboy account and an EVM address.Key Format: PEM Envelope
File Format (.cowboy/key)
The primary on-disk format is a PEM-style envelope with base64-encoded key material:
Structure
Specification
Header and Footer
The file MUST begin with
-----BEGIN COWBOY PRIVATE KEY----- and end with -----END COWBOY PRIVATE KEY-----, each on their own line. These markers make the format self-describing and prevent accidental use of non-key files.Metadata Headers
Between the header and the base64 body, zero or more
Unknown headers MUST be ignored by parsers (forward compatibility).
Key: Value metadata lines MAY appear. Defined headers:| Header | Required | Values | Description |
|---|---|---|---|
Curve | Yes | secp256k1 | The elliptic curve for this key |
Checksum | Yes | 4 hex characters | First 4 hex characters of SHA-256(raw_key_bytes) |
Body
A single line of standard base64 (RFC 4648) encoding of the raw 32-byte private key. The line MUST NOT contain whitespace.
Address Derivation
From a secp256k1 private key, the Cowboy address is derived using the Ethereum-standard method:- Compute the uncompressed public key (64 bytes, without the
04prefix). - Hash with Keccak-256.
- Take the last 20 bytes as the address.
0x... address on both chains.
Checksum Calculation
The checksum provides corruption detection:- Decodes the base64 body to get the raw key bytes.
- Computes
SHA-256(raw_key_bytes). - Compares the first 4 hex characters against the
Checksumheader. - If they don’t match, prints an error and refuses to use the key.
Parsing Rules
Example: Full Round-Trip
Backup & Recovery: BIP-39 Mnemonic
For human-readable backup and recovery, Cowboy uses BIP-39 mnemonics as the seed format. Combined with BIP-32/44 hierarchical deterministic (HD) derivation, a single 24-word mnemonic can derive an unlimited number of Cowboy keys.Export
Import
Mnemonic Specification
Encoding (BIP-39)
Encoding (BIP-39)
The mnemonic is generated from 256 bits of cryptographically random entropy:
- Generate 32 bytes (256 bits) of random entropy.
- Compute SHA-256 of the entropy; take the first 8 bits as a checksum.
- Concatenate: 256 bits of entropy + 8 bits of checksum = 264 bits.
- Split into 24 groups of 11 bits.
- Each 11-bit value maps to a word in the BIP-39 English wordlist (2048 words).
"mnemonic" (no user passphrase by default). This seed feeds into BIP-32 HD derivation.Wordlist
Wordlist
Only the BIP-39 English wordlist is supported. The wordlist is well-established, widely available, and avoids internationalization complexity.
HD Derivation (BIP-32/44)
Cowboy uses standard BIP-32/44 hierarchical deterministic derivation to produce account keys from a mnemonic seed. This is the same scheme used by Ethereum wallets (MetaMask, Ledger, Trezor), which means:- A Cowboy mnemonic imported into MetaMask produces the same addresses
- A MetaMask/Ledger mnemonic imported into Cowboy produces the same addresses
- Hardware wallets work out of the box
Derivation Path
| Level | Value | Meaning |
|---|---|---|
44' | BIP-44 | Multi-account HD wallets |
60' | Ethereum coin type | Ethereum-compatible key derivation |
0' | Account | Hardened account group |
0 | Change | External chain (receiving addresses) |
account_index | 0, 1, 2, … | Sequential account index |
60') rather than registering a separate coin type. This is intentional — Cowboy accounts are Ethereum addresses, and using the same derivation path means full wallet compatibility.
Deriving Multiple Keys
Hardware Wallet Support
Cowboy supports signing transactions via hardware wallets (Ledger, Trezor) using the same BIP-44 derivation path. The private key never leaves the hardware device.How It Works
- The CLI constructs the transaction and computes the signing hash (
keccak256(CBOR(tx))). - The hash is sent to the hardware wallet over USB/HID.
- The user confirms on the device screen.
- The device signs with the private key at the specified BIP-44 path and returns the signature.
- The CLI attaches the signature and broadcasts the transaction.
CLI Usage
Supported Devices
| Device | Connection | Library | Status |
|---|---|---|---|
| Ledger Nano S/X/S Plus | USB HID | ledger-transport-hid | Planned |
| Trezor Model T/One | USB HID | trezor-transport | Planned |
m/44'/60'/0'/0/n) and secp256k1 signing, hardware wallets require no custom firmware or app — the existing Ethereum app on Ledger/Trezor works directly.
Auto-Discovery with Hardware Wallets
When--ledger or --trezor is passed, the CLI skips file-based key discovery entirely and communicates with the device directly. Hardware wallet flags take priority over all other key sources.
Environment Variable Format
When using theCOWBOY_PRIVATE_KEY environment variable, the value is the raw 32-byte key in hex encoding (with or without 0x prefix):
- It’s a single-line value (no PEM headers)
- It’s commonly used for secrets in environment variables across the ecosystem
- It’s easy to set programmatically
CLI Commands
Wallet commands:| Command | Description |
|---|---|
cowboy wallet create | Generate a new key in PEM format |
cowboy wallet create --encrypt | Generate a new key as encrypted keystore |
cowboy wallet create --from-mnemonic | Derive key from BIP-39 mnemonic via BIP-44 |
cowboy wallet address | Derive and print public address from private key |
cowboy wallet address --ledger | Print address from hardware wallet |
cowboy wallet accounts --mnemonic | List derived accounts from a mnemonic |
cowboy wallet export --mnemonic | Export key’s mnemonic (if created from one) |
cowboy wallet import --mnemonic | Import key from BIP-39 mnemonic, write PEM file |
cowboy wallet encrypt | Encrypt an existing PEM key to .cowboy/key.enc |
cowboy wallet decrypt | Decrypt a keystore back to PEM |
Security Considerations
File Permissions
File Permissions
The CLI MUST set
.cowboy/key to mode 0600 (owner read/write only) on creation. On load, if the file is group- or world-readable, the CLI SHOULD print a warning:Mnemonic Handling
Mnemonic Handling
When displaying mnemonics, the CLI MUST:
- Print a warning about secure storage before showing the words.
- Never write mnemonics to log files or shell history.
- Clear terminal scrollback is recommended but not enforced.
Encryption at Rest
Encryption at Rest
Unencrypted PEM keys are protected by filesystem permissions (
0600), which is sufficient for local development. For production or shared machines, use the encrypted keystore format (cowboy wallet encrypt), which wraps the key in AES-256-GCM with an Argon2id-derived passphrase.Hardware Wallets
Hardware Wallets
Hardware wallets provide the strongest key security — the private key is generated on-device and never exposed to the host machine. For high-value accounts or production validators, hardware wallet signing is strongly recommended.
Encrypted Keystore
For production deployments and shared machines, Cowboy supports passphrase-encrypted key files. An encrypted keystore wraps the PEM key material in an AES-256-GCM envelope, with the encryption key derived from a user passphrase via Argon2id.File Format (.cowboy/key.enc)
Encryption Specification
Key Derivation
The passphrase is fed into Argon2id to derive a 32-byte encryption key:
Argon2id is chosen over scrypt (used by Ethereum’s keystore v3) because it provides stronger resistance to both GPU and side-channel attacks.
| Parameter | Value | Rationale |
|---|---|---|
m_cost | 65536 (64 MiB) | Memory-hard; resists GPU/ASIC attacks |
t_cost | 3 iterations | Balances security with ~1s unlock time on modern hardware |
p_cost | 1 (single-threaded) | Deterministic timing; no parallelism variance |
salt | 16 random bytes | Unique per keystore; prevents rainbow tables |
Encryption
The raw 32-byte private key is encrypted with AES-256-GCM:
- Generate a 12-byte random nonce.
- Encrypt the key bytes with AES-256-GCM using the derived key and nonce.
- Store the ciphertext and 16-byte authentication tag separately.
Checksum
The
checksum field contains the same SHA-256-based checksum as the PEM format (first 4 hex chars of SHA-256(raw_key_bytes)). This allows verifying the key after decryption without exposing any information about the plaintext key in the encrypted file.The checksum is computed over the plaintext key bytes before encryption and verified after decryption.CLI Commands
Auto-Discovery with Encrypted Keys
The key auto-discovery order is extended to check for encrypted keystores:--ledger/--trezorflag (hardware wallet, skips file discovery)--private-key <path>flagCOWBOY_PRIVATE_KEYenvironment variable (hex).cowboy/keyfile (PEM).cowboy/key.encfile (encrypted keystore) — prompts for passphrase
COWBOY_KEY_PASSPHRASE environment variable.
Passphrase Requirements
The CLI enforces minimum passphrase quality on creation:- Minimum 8 characters
- No maximum length
- No character-class requirements (length is the primary security factor)
When to Use Each Format
| Scenario | Recommended Format |
|---|---|
| Local development (single user) | PEM (unencrypted) |
| Shared development machine | Encrypted keystore |
| CI/CD pipeline | Env var (COWBOY_PRIVATE_KEY) or secrets manager |
| Production validator/runner | Hardware wallet or encrypted keystore |
| Long-term backup | BIP-39 mnemonic (paper/metal) |
| Managing multiple accounts | BIP-39 mnemonic + HD derivation |
Further Reading
- Key Auto-Discovery — How the CLI finds keys
- cowboy wallet — Wallet command reference
- Cowboy Design Decisions — Cryptographic design rationale

