# -*- coding: utf-8 -*- """Eddycoin recovery words: BIP39 (English) + SLIP-0010 key derivation on NIST P-256. Spec: SEED_SPEC.md next to this file. Summary: * 24 words = 256-bit entropy + 8-bit SHA-256 checksum, official BIP39 English wordlist (embedded below, SHA-256 2f5eed53a4727b4bf8880d8f3f199efc90e58503646d9ff8eff3a2ed3b24dbda, checked at import). * seed = PBKDF2-HMAC-SHA512(NFKD(words), "mnemonic" + NFKD(passphrase), 2048 iterations, 64 bytes) (BIP39) * key = SLIP-0010 for curve nist256p1 (= P-256 / secp256r1, the curve Eddycoin signs with), path m/44'/3339'/0'/0/0 (3339 = "EDDY" on a phone keypad; not a registered SLIP-44 number) * address = the usual Eddycoin address of the uncompressed public key: "eddy1" + sha256("EDDY-ADDR|v1|" + pubhex)[:40] BIP39 code follows the reference implementation trezor/python-mnemonic (MIT, (c) 2013-2016 Pavol Rusnak); verified against the official BIP39 and SLIP-0010 nist256p1 test vectors (see _tools/test_seed.py). """ import hashlib, hmac, os, unicodedata WORDLIST_SHA256 = "2f5eed53a4727b4bf8880d8f3f199efc90e58503646d9ff8eff3a2ed3b24dbda" _WORDS = ( 'abandon ability able about above absent absorb abstract absurd abuse access accident account accuse achieve ' 'acid acoustic acquire across act action actor actress actual adapt add addict address adjust admit adult ' 'advance advice aerobic affair afford afraid again age agent agree ahead aim air airport aisle alarm album ' 'alcohol alert alien all alley allow almost alone alpha already also alter always amateur amazing among amount ' 'amused analyst anchor ancient anger angle angry animal ankle announce annual another answer antenna antique ' 'anxiety any apart apology appear apple approve april arch arctic area arena argue arm armed armor army around ' 'arrange arrest arrive arrow art artefact artist artwork ask aspect assault asset assist assume asthma athlete ' 'atom attack attend attitude attract auction audit august aunt author auto autumn average avocado avoid awake ' 'aware away awesome awful awkward axis baby bachelor bacon badge bag balance balcony ball bamboo banana banner ' 'bar barely bargain barrel base basic basket battle beach bean beauty because become beef before begin behave ' 'behind believe below belt bench benefit best betray better between beyond bicycle bid bike bind biology bird ' 'birth bitter black blade blame blanket blast bleak bless blind blood blossom blouse blue blur blush board boat ' 'body boil bomb bone bonus book boost border boring borrow boss bottom bounce box boy bracket brain brand brass ' 'brave bread breeze brick bridge brief bright bring brisk broccoli broken bronze broom brother brown brush ' 'bubble buddy budget buffalo build bulb bulk bullet bundle bunker burden burger burst bus business busy butter ' 'buyer buzz cabbage cabin cable cactus cage cake call calm camera camp can canal cancel candy cannon canoe ' 'canvas canyon capable capital captain car carbon card cargo carpet carry cart case cash casino castle casual ' 'cat catalog catch category cattle caught cause caution cave ceiling celery cement census century cereal ' 'certain chair chalk champion change chaos chapter charge chase chat cheap check cheese chef cherry chest ' 'chicken chief child chimney choice choose chronic chuckle chunk churn cigar cinnamon circle citizen city civil ' 'claim clap clarify claw clay clean clerk clever click client cliff climb clinic clip clock clog close cloth ' 'cloud clown club clump cluster clutch coach coast coconut code coffee coil coin collect color column combine ' 'come comfort comic common company concert conduct confirm congress connect consider control convince cook cool ' 'copper copy coral core corn correct cost cotton couch country couple course cousin cover coyote crack cradle ' 'craft cram crane crash crater crawl crazy cream credit creek crew cricket crime crisp critic crop cross crouch ' 'crowd crucial cruel cruise crumble crunch crush cry crystal cube culture cup cupboard curious current curtain ' 'curve cushion custom cute cycle dad damage damp dance danger daring dash daughter dawn day deal debate debris ' 'decade december decide decline decorate decrease deer defense define defy degree delay deliver demand demise ' 'denial dentist deny depart depend deposit depth deputy derive describe desert design desk despair destroy ' 'detail detect develop device devote diagram dial diamond diary dice diesel diet differ digital dignity dilemma ' 'dinner dinosaur direct dirt disagree discover disease dish dismiss disorder display distance divert divide ' 'divorce dizzy doctor document dog doll dolphin domain donate donkey donor door dose double dove draft dragon ' 'drama drastic draw dream dress drift drill drink drip drive drop drum dry duck dumb dune during dust dutch ' 'duty dwarf dynamic eager eagle early earn earth easily east easy echo ecology economy edge edit educate effort ' 'egg eight either elbow elder electric elegant element elephant elevator elite else embark embody embrace ' 'emerge emotion employ empower empty enable enact end endless endorse enemy energy enforce engage engine ' 'enhance enjoy enlist enough enrich enroll ensure enter entire entry envelope episode equal equip era erase ' 'erode erosion error erupt escape essay essence estate eternal ethics evidence evil evoke evolve exact example ' 'excess exchange excite exclude excuse execute exercise exhaust exhibit exile exist exit exotic expand expect ' 'expire explain expose express extend extra eye eyebrow fabric face faculty fade faint faith fall false fame ' 'family famous fan fancy fantasy farm fashion fat fatal father fatigue fault favorite feature february federal ' 'fee feed feel female fence festival fetch fever few fiber fiction field figure file film filter final find ' 'fine finger finish fire firm first fiscal fish fit fitness fix flag flame flash flat flavor flee flight flip ' 'float flock floor flower fluid flush fly foam focus fog foil fold follow food foot force forest forget fork ' 'fortune forum forward fossil foster found fox fragile frame frequent fresh friend fringe frog front frost ' 'frown frozen fruit fuel fun funny furnace fury future gadget gain galaxy gallery game gap garage garbage ' 'garden garlic garment gas gasp gate gather gauge gaze general genius genre gentle genuine gesture ghost giant ' 'gift giggle ginger giraffe girl give glad glance glare glass glide glimpse globe gloom glory glove glow glue ' 'goat goddess gold good goose gorilla gospel gossip govern gown grab grace grain grant grape grass gravity ' 'great green grid grief grit grocery group grow grunt guard guess guide guilt guitar gun gym habit hair half ' 'hammer hamster hand happy harbor hard harsh harvest hat have hawk hazard head health heart heavy hedgehog ' 'height hello helmet help hen hero hidden high hill hint hip hire history hobby hockey hold hole holiday hollow ' 'home honey hood hope horn horror horse hospital host hotel hour hover hub huge human humble humor hundred ' 'hungry hunt hurdle hurry hurt husband hybrid ice icon idea identify idle ignore ill illegal illness image ' 'imitate immense immune impact impose improve impulse inch include income increase index indicate indoor ' 'industry infant inflict inform inhale inherit initial inject injury inmate inner innocent input inquiry insane ' 'insect inside inspire install intact interest into invest invite involve iron island isolate issue item ivory ' 'jacket jaguar jar jazz jealous jeans jelly jewel job join joke journey joy judge juice jump jungle junior junk ' 'just kangaroo keen keep ketchup key kick kid kidney kind kingdom kiss kit kitchen kite kitten kiwi knee knife ' 'knock know lab label labor ladder lady lake lamp language laptop large later latin laugh laundry lava law lawn ' 'lawsuit layer lazy leader leaf learn leave lecture left leg legal legend leisure lemon lend length lens ' 'leopard lesson letter level liar liberty library license life lift light like limb limit link lion liquid list ' 'little live lizard load loan lobster local lock logic lonely long loop lottery loud lounge love loyal lucky ' 'luggage lumber lunar lunch luxury lyrics machine mad magic magnet maid mail main major make mammal man manage ' 'mandate mango mansion manual maple marble march margin marine market marriage mask mass master match material ' 'math matrix matter maximum maze meadow mean measure meat mechanic medal media melody melt member memory ' 'mention menu mercy merge merit merry mesh message metal method middle midnight milk million mimic mind minimum ' 'minor minute miracle mirror misery miss mistake mix mixed mixture mobile model modify mom moment monitor ' 'monkey monster month moon moral more morning mosquito mother motion motor mountain mouse move movie much ' 'muffin mule multiply muscle museum mushroom music must mutual myself mystery myth naive name napkin narrow ' 'nasty nation nature near neck need negative neglect neither nephew nerve nest net network neutral never news ' 'next nice night noble noise nominee noodle normal north nose notable note nothing notice novel now nuclear ' 'number nurse nut oak obey object oblige obscure observe obtain obvious occur ocean october odor off offer ' 'office often oil okay old olive olympic omit once one onion online only open opera opinion oppose option ' 'orange orbit orchard order ordinary organ orient original orphan ostrich other outdoor outer output outside ' 'oval oven over own owner oxygen oyster ozone pact paddle page pair palace palm panda panel panic panther paper ' 'parade parent park parrot party pass patch path patient patrol pattern pause pave payment peace peanut pear ' 'peasant pelican pen penalty pencil people pepper perfect permit person pet phone photo phrase physical piano ' 'picnic picture piece pig pigeon pill pilot pink pioneer pipe pistol pitch pizza place planet plastic plate ' 'play please pledge pluck plug plunge poem poet point polar pole police pond pony pool popular portion position ' 'possible post potato pottery poverty powder power practice praise predict prefer prepare present pretty ' 'prevent price pride primary print priority prison private prize problem process produce profit program project ' 'promote proof property prosper protect proud provide public pudding pull pulp pulse pumpkin punch pupil puppy ' 'purchase purity purpose purse push put puzzle pyramid quality quantum quarter question quick quit quiz quote ' 'rabbit raccoon race rack radar radio rail rain raise rally ramp ranch random range rapid rare rate rather ' 'raven raw razor ready real reason rebel rebuild recall receive recipe record recycle reduce reflect reform ' 'refuse region regret regular reject relax release relief rely remain remember remind remove render renew rent ' 'reopen repair repeat replace report require rescue resemble resist resource response result retire retreat ' 'return reunion reveal review reward rhythm rib ribbon rice rich ride ridge rifle right rigid ring riot ripple ' 'risk ritual rival river road roast robot robust rocket romance roof rookie room rose rotate rough round route ' 'royal rubber rude rug rule run runway rural sad saddle sadness safe sail salad salmon salon salt salute same ' 'sample sand satisfy satoshi sauce sausage save say scale scan scare scatter scene scheme school science ' 'scissors scorpion scout scrap screen script scrub sea search season seat second secret section security seed ' 'seek segment select sell seminar senior sense sentence series service session settle setup seven shadow shaft ' 'shallow share shed shell sheriff shield shift shine ship shiver shock shoe shoot shop short shoulder shove ' 'shrimp shrug shuffle shy sibling sick side siege sight sign silent silk silly silver similar simple since sing ' 'siren sister situate six size skate sketch ski skill skin skirt skull slab slam sleep slender slice slide ' 'slight slim slogan slot slow slush small smart smile smoke smooth snack snake snap sniff snow soap soccer ' 'social sock soda soft solar soldier solid solution solve someone song soon sorry sort soul sound soup source ' 'south space spare spatial spawn speak special speed spell spend sphere spice spider spike spin spirit split ' 'spoil sponsor spoon sport spot spray spread spring spy square squeeze squirrel stable stadium staff stage ' 'stairs stamp stand start state stay steak steel stem step stereo stick still sting stock stomach stone stool ' 'story stove strategy street strike strong struggle student stuff stumble style subject submit subway success ' 'such sudden suffer sugar suggest suit summer sun sunny sunset super supply supreme sure surface surge surprise ' 'surround survey suspect sustain swallow swamp swap swarm swear sweet swift swim swing switch sword symbol ' 'symptom syrup system table tackle tag tail talent talk tank tape target task taste tattoo taxi teach team tell ' 'ten tenant tennis tent term test text thank that theme then theory there they thing this thought three thrive ' 'throw thumb thunder ticket tide tiger tilt timber time tiny tip tired tissue title toast tobacco today toddler ' 'toe together toilet token tomato tomorrow tone tongue tonight tool tooth top topic topple torch tornado ' 'tortoise toss total tourist toward tower town toy track trade traffic tragic train transfer trap trash travel ' 'tray treat tree trend trial tribe trick trigger trim trip trophy trouble truck true truly trumpet trust truth ' 'try tube tuition tumble tuna tunnel turkey turn turtle twelve twenty twice twin twist two type typical ugly ' 'umbrella unable unaware uncle uncover under undo unfair unfold unhappy uniform unique unit universe unknown ' 'unlock until unusual unveil update upgrade uphold upon upper upset urban urge usage use used useful useless ' 'usual utility vacant vacuum vague valid valley valve van vanish vapor various vast vault vehicle velvet vendor ' 'venture venue verb verify version very vessel veteran viable vibrant vicious victory video view village ' 'vintage violin virtual virus visa visit visual vital vivid vocal voice void volcano volume vote voyage wage ' 'wagon wait walk wall walnut want warfare warm warrior wash wasp waste water wave way wealth weapon wear weasel ' 'weather web wedding weekend weird welcome west wet whale what wheat wheel when where whip whisper wide width ' 'wife wild will win window wine wing wink winner winter wire wisdom wise wish witness wolf woman wonder wood ' 'wool word work world worry worth wrap wreck wrestle wrist write wrong yard year yellow you young youth zebra ' 'zero zone zoo ' ) WORDS = _WORDS.split() if len(WORDS) != 2048 or hashlib.sha256(("\n".join(WORDS) + "\n").encode()).hexdigest() != WORDLIST_SHA256: raise RuntimeError("BIP39 wordlist damaged") _INDEX = {w: i for i, w in enumerate(WORDS)} COIN_TYPE = 3339 PATH = "m/44'/%d'/0'/0/0" % COIN_TYPE HARD = 0x80000000 N_P256 = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 class BadWords(ValueError): pass def _nfkd(s): return unicodedata.normalize("NFKD", s) def entropy_to_words(entropy): if len(entropy) not in (16, 20, 24, 28, 32): raise ValueError("entropy must be 128-256 bits") h = hashlib.sha256(entropy).hexdigest() bits = bin(int.from_bytes(entropy, "big"))[2:].zfill(len(entropy) * 8) + bin(int(h, 16))[2:].zfill(256)[: len(entropy) * 8 // 32] return " ".join(WORDS[int(bits[i * 11:(i + 1) * 11], 2)] for i in range(len(bits) // 11)) def generate(strength=256): """new random recovery words (default 24 words / 256 bits), from the OS random generator""" return entropy_to_words(os.urandom(strength // 8)) def normalize_words(text): """lower-case, single spaces; accepts the unique 4-letter prefixes people often write down""" out = [] for w in _nfkd(str(text or "")).lower().replace(",", " ").split(): if w not in _INDEX and len(w) >= 4: m = [x for x in WORDS if x.startswith(w)] if len(m) == 1: w = m[0] out.append(w) return " ".join(out) def check(words, allowed=(24,)): """raises BadWords with a user-friendly reason; returns the normalized words""" ws = normalize_words(words).split() if len(ws) not in allowed: raise BadWords("expected %s words, got %d" % (" or ".join(map(str, allowed)), len(ws))) bad = [i + 1 for i, w in enumerate(ws) if w not in _INDEX] if bad: raise BadWords("word %s is not in the BIP39 English word list - check the spelling" % ", ".join("#%d" % i for i in bad)) b = "".join(bin(_INDEX[w])[2:].zfill(11) for w in ws) cs = len(b) // 33 ent = int(b[:-cs], 2).to_bytes(len(b[:-cs]) // 8, "big") if bin(int(hashlib.sha256(ent).hexdigest(), 16))[2:].zfill(256)[:cs] != b[-cs:]: raise BadWords("the words do not fit together (checksum) - a word is wrong or two are swapped") return " ".join(ws) def to_seed(words, passphrase=""): """BIP39 seed (64 bytes). The optional passphrase is the '25th word': any text, case-sensitive.""" return hashlib.pbkdf2_hmac("sha512", _nfkd(words).encode("utf-8"), ("mnemonic" + _nfkd(passphrase or "")).encode("utf-8"), 2048) # ---- SLIP-0010, curve nist256p1 ---- def _pub_compressed(k): from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import ec return ec.derive_private_key(k, ec.SECP256R1()).public_key().public_bytes(serialization.Encoding.X962, serialization.PublicFormat.CompressedPoint) def master_key(seed): data = seed while True: I = hmac.new(b"Nist256p1 seed", data, hashlib.sha512).digest() k = int.from_bytes(I[:32], "big") if 0 < k < N_P256: return k, I[32:] data = I def ckd_priv(k, c, i): if i >= HARD: data = b"\x00" + k.to_bytes(32, "big") + i.to_bytes(4, "big") else: data = _pub_compressed(k) + i.to_bytes(4, "big") while True: I = hmac.new(c, data, hashlib.sha512).digest() il = int.from_bytes(I[:32], "big"); ki = (il + k) % N_P256 if il < N_P256 and ki != 0: return ki, I[32:] data = b"\x01" + I[32:] + i.to_bytes(4, "big") def parse_path(path): p = path.strip().split("/") if p[0] != "m": raise ValueError("path must start with m") return [int(x[:-1]) + HARD if x.endswith(("'", "H", "h")) else int(x) for x in p[1:]] def derive(seed, path=PATH): k, c = master_key(seed) for i in parse_path(path): k, c = ckd_priv(k, c, i) return k, c def private_key_int(words, passphrase="", path=PATH): return derive(to_seed(check(words), passphrase), path)[0]