# Eddycoin recovery words - specification (wallet v3, 2026-10-27) Status: implemented in `eddycoin_seed.py` + `eddycoin_wallet.py` (Windows exe, CLI). In use on the Eddycoin mainnet (eddycoin-mainnet-1). ## 1. Words (BIP39, unchanged standard) - New wallets: 256 bits of entropy from the OS (`os.urandom`) + 8-bit SHA-256 checksum = **24 words** from the **official BIP39 English wordlist** (embedded; SHA-256 `2f5eed53a4727b4bf8880d8f3f199efc90e58503646d9ff8eff3a2ed3b24dbda`, identical to bitcoin/bips bip-0039/english.txt and trezor/python-mnemonic; checked at program start). - Restore accepts exactly 24 words (case-insensitive, extra spaces/newlines ignored, the unique 4-letter prefixes are accepted); unknown words and a wrong checksum are refused with a clear message. - seed = PBKDF2-HMAC-SHA512(password = NFKD(words), salt = "mnemonic" + NFKD(passphrase), 2048 iterations, 64 bytes). ## 2. Optional extra word (BIP39 passphrase, "25th word") - Optional, any Unicode text (also made-up words). Case-sensitive, spaces count (NFKD-normalized as in BIP39). - Never stored anywhere. Different / missing passphrase = different, valid, empty wallet (standard BIP39 behaviour). ## 3. Key derivation - **Curve: NIST P-256 (secp256r1)** - this is the curve Eddycoin signs and verifies with (wallet, node, Y-Chain, web page). secp256k1 would NOT produce valid Eddycoin signatures, so the BIP32 analogue for P-256 is used: - **SLIP-0010, curve nist256p1** (master key HMAC key "Nist256p1 seed", BIP32-style CKDpriv with retry rule). - **Path m/44'/3339'/0'/0/0** (3339 = "EDDY" on a phone keypad; not registered in SLIP-44 - unused as of 2026-10-27, could be registered later; changing it later would change every address, so it is fixed now). - Private key -> uncompressed public key 04||X||Y -> address exactly as before: `"eddy1" + sha256("EDDY-ADDR|v1|" + pubhex)[:40]`. Transaction format and signatures are unchanged. ## 4. Wallet file - Same format as v2 (`"version": 2`, PBKDF2-SHA256 600,000 + AES-256-GCM, AAD = address) so older wallets and the web page still read it. Added fields: - `encryptedWords`: the 24 words, encrypted the same way (own salt + nonce, AAD = address + "|bip39-words"). - `recovery`: scheme + path (public information, no secret). - Words are never written unencrypted by the program, except on explicit request (CLI `--words-out` / `show-words --out`, new file, mode 0600). Change password re-encrypts the words too. Export private key is unchanged. - Older wallets without words keep working (open, send, export); "Recovery words" explains they have none. ## 5. User flow GUI: Step 1 password (+ name) -> button "Create new wallet" -> Step 2 the 24 words + warning (paper only, never share, never photograph) + checkbox "I have written all 24 words on paper" -> Step 3 retype 3 random words -> Step 4 optional extra word (two entries, warning) -> file saved. "Restore from words" (24 words + optional extra word + new password, shows the restored address before saving). "Recovery words" button (password) shows the words again. CLI: `--cli create FILE [--with-passphrase] [--words-out F]`, `--cli restore FILE [--with-passphrase]`, `--cli show-words FILE [--out F]`. ## 6. Test vectors (all PASS, `tests/test_seed.py`) - BIP39 official English vectors (trezor vectors.json, passphrase "TREZOR"): 24/24 entropy->words and words->seed. - SLIP-0010 nist256p1 vectors 1 + 2 + derivation-retry + seed-retry: 13/13 private keys and chain codes. - Cross-check against the reference `mnemonic` 0.21 package: identical words validity and seeds.