diff --git a/include/bip39/electrum.h b/include/bip39/electrum.h
new file mode 100644
index 000000000..750fa85ef
--- /dev/null
+++ b/include/bip39/electrum.h
@@ -0,0 +1,1652 @@
+
+/**
+ *
+ * Electrum - lightweight Bitcoin client
+ * Copyright (C) 2011 thomasv@gitorious
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ *
+ *
+ * list of words from http://en.wiktionary.org/wiki/Wiktionary:Frequency_lists/Contemporary_poetry
+ *
+ */
+
+const char * const wordlist_electrum[] = {
+"like",
+"just",
+"love",
+"know",
+"never",
+"want",
+"time",
+"out",
+"there",
+"make",
+"look",
+"eye",
+"down",
+"only",
+"think",
+"heart",
+"back",
+"then",
+"into",
+"about",
+"more",
+"away",
+"still",
+"them",
+"take",
+"thing",
+"even",
+"through",
+"long",
+"always",
+"world",
+"too",
+"friend",
+"tell",
+"try",
+"hand",
+"thought",
+"over",
+"here",
+"other",
+"need",
+"smile",
+"again",
+"much",
+"cry",
+"been",
+"night",
+"ever",
+"little",
+"said",
+"end",
+"some",
+"those",
+"around",
+"mind",
+"people",
+"girl",
+"leave",
+"dream",
+"left",
+"turn",
+"myself",
+"give",
+"nothing",
+"really",
+"off",
+"before",
+"something",
+"find",
+"walk",
+"wish",
+"good",
+"once",
+"place",
+"ask",
+"stop",
+"keep",
+"watch",
+"seem",
+"everything",
+"wait",
+"got",
+"yet",
+"made",
+"remember",
+"start",
+"alone",
+"run",
+"hope",
+"maybe",
+"believe",
+"body",
+"hate",
+"after",
+"close",
+"talk",
+"stand",
+"own",
+"each",
+"hurt",
+"help",
+"home",
+"god",
+"soul",
+"new",
+"many",
+"two",
+"inside",
+"should",
+"true",
+"first",
+"fear",
+"mean",
+"better",
+"play",
+"another",
+"gone",
+"change",
+"use",
+"wonder",
+"someone",
+"hair",
+"cold",
+"open",
+"best",
+"any",
+"behind",
+"happen",
+"water",
+"dark",
+"laugh",
+"stay",
+"forever",
+"name",
+"work",
+"show",
+"sky",
+"break",
+"came",
+"deep",
+"door",
+"put",
+"black",
+"together",
+"upon",
+"happy",
+"such",
+"great",
+"white",
+"matter",
+"fill",
+"past",
+"please",
+"burn",
+"cause",
+"enough",
+"touch",
+"moment",
+"soon",
+"voice",
+"scream",
+"anything",
+"stare",
+"sound",
+"red",
+"everyone",
+"hide",
+"kiss",
+"truth",
+"death",
+"beautiful",
+"mine",
+"blood",
+"broken",
+"very",
+"pass",
+"next",
+"forget",
+"tree",
+"wrong",
+"air",
+"mother",
+"understand",
+"lip",
+"hit",
+"wall",
+"memory",
+"sleep",
+"free",
+"high",
+"realize",
+"school",
+"might",
+"skin",
+"sweet",
+"perfect",
+"blue",
+"kill",
+"breath",
+"dance",
+"against",
+"fly",
+"between",
+"grow",
+"strong",
+"under",
+"listen",
+"bring",
+"sometimes",
+"speak",
+"pull",
+"person",
+"become",
+"family",
+"begin",
+"ground",
+"real",
+"small",
+"father",
+"sure",
+"feet",
+"rest",
+"young",
+"finally",
+"land",
+"across",
+"today",
+"different",
+"guy",
+"line",
+"fire",
+"reason",
+"reach",
+"second",
+"slowly",
+"write",
+"eat",
+"smell",
+"mouth",
+"step",
+"learn",
+"three",
+"floor",
+"promise",
+"breathe",
+"darkness",
+"push",
+"earth",
+"guess",
+"save",
+"song",
+"above",
+"along",
+"both",
+"color",
+"house",
+"almost",
+"sorry",
+"anymore",
+"brother",
+"okay",
+"dear",
+"game",
+"fade",
+"already",
+"apart",
+"warm",
+"beauty",
+"heard",
+"notice",
+"question",
+"shine",
+"began",
+"piece",
+"whole",
+"shadow",
+"secret",
+"street",
+"within",
+"finger",
+"point",
+"morning",
+"whisper",
+"child",
+"moon",
+"green",
+"story",
+"glass",
+"kid",
+"silence",
+"since",
+"soft",
+"yourself",
+"empty",
+"shall",
+"angel",
+"answer",
+"baby",
+"bright",
+"dad",
+"path",
+"worry",
+"hour",
+"drop",
+"follow",
+"power",
+"war",
+"half",
+"flow",
+"heaven",
+"act",
+"chance",
+"fact",
+"least",
+"tired",
+"children",
+"near",
+"quite",
+"afraid",
+"rise",
+"sea",
+"taste",
+"window",
+"cover",
+"nice",
+"trust",
+"lot",
+"sad",
+"cool",
+"force",
+"peace",
+"return",
+"blind",
+"easy",
+"ready",
+"roll",
+"rose",
+"drive",
+"held",
+"music",
+"beneath",
+"hang",
+"mom",
+"paint",
+"emotion",
+"quiet",
+"clear",
+"cloud",
+"few",
+"pretty",
+"bird",
+"outside",
+"paper",
+"picture",
+"front",
+"rock",
+"simple",
+"anyone",
+"meant",
+"reality",
+"road",
+"sense",
+"waste",
+"bit",
+"leaf",
+"thank",
+"happiness",
+"meet",
+"men",
+"smoke",
+"truly",
+"decide",
+"self",
+"age",
+"book",
+"form",
+"alive",
+"carry",
+"escape",
+"damn",
+"instead",
+"able",
+"ice",
+"minute",
+"throw",
+"catch",
+"leg",
+"ring",
+"course",
+"goodbye",
+"lead",
+"poem",
+"sick",
+"corner",
+"desire",
+"known",
+"problem",
+"remind",
+"shoulder",
+"suppose",
+"toward",
+"wave",
+"drink",
+"jump",
+"woman",
+"pretend",
+"sister",
+"week",
+"human",
+"joy",
+"crack",
+"grey",
+"pray",
+"surprise",
+"dry",
+"knee",
+"less",
+"search",
+"bleed",
+"caught",
+"clean",
+"embrace",
+"future",
+"king",
+"son",
+"sorrow",
+"chest",
+"hug",
+"remain",
+"sat",
+"worth",
+"blow",
+"daddy",
+"final",
+"parent",
+"tight",
+"also",
+"create",
+"lonely",
+"safe",
+"cross",
+"dress",
+"evil",
+"silent",
+"bone",
+"fate",
+"perhaps",
+"anger",
+"class",
+"scar",
+"snow",
+"tiny",
+"tonight",
+"continue",
+"control",
+"dog",
+"edge",
+"mirror",
+"month",
+"suddenly",
+"comfort",
+"given",
+"loud",
+"quickly",
+"gaze",
+"plan",
+"rush",
+"stone",
+"town",
+"battle",
+"ignore",
+"spirit",
+"stood",
+"stupid",
+"yours",
+"brown",
+"build",
+"dust",
+"hey",
+"kept",
+"pay",
+"phone",
+"twist",
+"although",
+"ball",
+"beyond",
+"hidden",
+"nose",
+"taken",
+"fail",
+"float",
+"pure",
+"somehow",
+"wash",
+"wrap",
+"angry",
+"cheek",
+"creature",
+"forgotten",
+"heat",
+"rip",
+"single",
+"space",
+"special",
+"weak",
+"whatever",
+"yell",
+"anyway",
+"blame",
+"job",
+"choose",
+"country",
+"curse",
+"drift",
+"echo",
+"figure",
+"grew",
+"laughter",
+"neck",
+"suffer",
+"worse",
+"yeah",
+"disappear",
+"foot",
+"forward",
+"knife",
+"mess",
+"somewhere",
+"stomach",
+"storm",
+"beg",
+"idea",
+"lift",
+"offer",
+"breeze",
+"field",
+"five",
+"often",
+"simply",
+"stuck",
+"win",
+"allow",
+"confuse",
+"enjoy",
+"except",
+"flower",
+"seek",
+"strength",
+"calm",
+"grin",
+"gun",
+"heavy",
+"hill",
+"large",
+"ocean",
+"shoe",
+"sigh",
+"straight",
+"summer",
+"tongue",
+"accept",
+"crazy",
+"everyday",
+"exist",
+"grass",
+"mistake",
+"sent",
+"shut",
+"surround",
+"table",
+"ache",
+"brain",
+"destroy",
+"heal",
+"nature",
+"shout",
+"sign",
+"stain",
+"choice",
+"doubt",
+"glance",
+"glow",
+"mountain",
+"queen",
+"stranger",
+"throat",
+"tomorrow",
+"city",
+"either",
+"fish",
+"flame",
+"rather",
+"shape",
+"spin",
+"spread",
+"ash",
+"distance",
+"finish",
+"image",
+"imagine",
+"important",
+"nobody",
+"shatter",
+"warmth",
+"became",
+"feed",
+"flesh",
+"funny",
+"lust",
+"shirt",
+"trouble",
+"yellow",
+"attention",
+"bare",
+"bite",
+"money",
+"protect",
+"amaze",
+"appear",
+"born",
+"choke",
+"completely",
+"daughter",
+"fresh",
+"friendship",
+"gentle",
+"probably",
+"six",
+"deserve",
+"expect",
+"grab",
+"middle",
+"nightmare",
+"river",
+"thousand",
+"weight",
+"worst",
+"wound",
+"barely",
+"bottle",
+"cream",
+"regret",
+"relationship",
+"stick",
+"test",
+"crush",
+"endless",
+"fault",
+"itself",
+"rule",
+"spill",
+"art",
+"circle",
+"join",
+"kick",
+"mask",
+"master",
+"passion",
+"quick",
+"raise",
+"smooth",
+"unless",
+"wander",
+"actually",
+"broke",
+"chair",
+"deal",
+"favorite",
+"gift",
+"note",
+"number",
+"sweat",
+"box",
+"chill",
+"clothes",
+"lady",
+"mark",
+"park",
+"poor",
+"sadness",
+"tie",
+"animal",
+"belong",
+"brush",
+"consume",
+"dawn",
+"forest",
+"innocent",
+"pen",
+"pride",
+"stream",
+"thick",
+"clay",
+"complete",
+"count",
+"draw",
+"faith",
+"press",
+"silver",
+"struggle",
+"surface",
+"taught",
+"teach",
+"wet",
+"bless",
+"chase",
+"climb",
+"enter",
+"letter",
+"melt",
+"metal",
+"movie",
+"stretch",
+"swing",
+"vision",
+"wife",
+"beside",
+"crash",
+"forgot",
+"guide",
+"haunt",
+"joke",
+"knock",
+"plant",
+"pour",
+"prove",
+"reveal",
+"steal",
+"stuff",
+"trip",
+"wood",
+"wrist",
+"bother",
+"bottom",
+"crawl",
+"crowd",
+"fix",
+"forgive",
+"frown",
+"grace",
+"loose",
+"lucky",
+"party",
+"release",
+"surely",
+"survive",
+"teacher",
+"gently",
+"grip",
+"speed",
+"suicide",
+"travel",
+"treat",
+"vein",
+"written",
+"cage",
+"chain",
+"conversation",
+"date",
+"enemy",
+"however",
+"interest",
+"million",
+"page",
+"pink",
+"proud",
+"sway",
+"themselves",
+"winter",
+"church",
+"cruel",
+"cup",
+"demon",
+"experience",
+"freedom",
+"pair",
+"pop",
+"purpose",
+"respect",
+"shoot",
+"softly",
+"state",
+"strange",
+"bar",
+"birth",
+"curl",
+"dirt",
+"excuse",
+"lord",
+"lovely",
+"monster",
+"order",
+"pack",
+"pants",
+"pool",
+"scene",
+"seven",
+"shame",
+"slide",
+"ugly",
+"among",
+"blade",
+"blonde",
+"closet",
+"creek",
+"deny",
+"drug",
+"eternity",
+"gain",
+"grade",
+"handle",
+"key",
+"linger",
+"pale",
+"prepare",
+"swallow",
+"swim",
+"tremble",
+"wheel",
+"won",
+"cast",
+"cigarette",
+"claim",
+"college",
+"direction",
+"dirty",
+"gather",
+"ghost",
+"hundred",
+"loss",
+"lung",
+"orange",
+"present",
+"swear",
+"swirl",
+"twice",
+"wild",
+"bitter",
+"blanket",
+"doctor",
+"everywhere",
+"flash",
+"grown",
+"knowledge",
+"numb",
+"pressure",
+"radio",
+"repeat",
+"ruin",
+"spend",
+"unknown",
+"buy",
+"clock",
+"devil",
+"early",
+"false",
+"fantasy",
+"pound",
+"precious",
+"refuse",
+"sheet",
+"teeth",
+"welcome",
+"add",
+"ahead",
+"block",
+"bury",
+"caress",
+"content",
+"depth",
+"despite",
+"distant",
+"marry",
+"purple",
+"threw",
+"whenever",
+"bomb",
+"dull",
+"easily",
+"grasp",
+"hospital",
+"innocence",
+"normal",
+"receive",
+"reply",
+"rhyme",
+"shade",
+"someday",
+"sword",
+"toe",
+"visit",
+"asleep",
+"bought",
+"center",
+"consider",
+"flat",
+"hero",
+"history",
+"ink",
+"insane",
+"muscle",
+"mystery",
+"pocket",
+"reflection",
+"shove",
+"silently",
+"smart",
+"soldier",
+"spot",
+"stress",
+"train",
+"type",
+"view",
+"whether",
+"bus",
+"energy",
+"explain",
+"holy",
+"hunger",
+"inch",
+"magic",
+"mix",
+"noise",
+"nowhere",
+"prayer",
+"presence",
+"shock",
+"snap",
+"spider",
+"study",
+"thunder",
+"trail",
+"admit",
+"agree",
+"bag",
+"bang",
+"bound",
+"butterfly",
+"cute",
+"exactly",
+"explode",
+"familiar",
+"fold",
+"further",
+"pierce",
+"reflect",
+"scent",
+"selfish",
+"sharp",
+"sink",
+"spring",
+"stumble",
+"universe",
+"weep",
+"women",
+"wonderful",
+"action",
+"ancient",
+"attempt",
+"avoid",
+"birthday",
+"branch",
+"chocolate",
+"core",
+"depress",
+"drunk",
+"especially",
+"focus",
+"fruit",
+"honest",
+"match",
+"palm",
+"perfectly",
+"pillow",
+"pity",
+"poison",
+"roar",
+"shift",
+"slightly",
+"thump",
+"truck",
+"tune",
+"twenty",
+"unable",
+"wipe",
+"wrote",
+"coat",
+"constant",
+"dinner",
+"drove",
+"egg",
+"eternal",
+"flight",
+"flood",
+"frame",
+"freak",
+"gasp",
+"glad",
+"hollow",
+"motion",
+"peer",
+"plastic",
+"root",
+"screen",
+"season",
+"sting",
+"strike",
+"team",
+"unlike",
+"victim",
+"volume",
+"warn",
+"weird",
+"attack",
+"await",
+"awake",
+"built",
+"charm",
+"crave",
+"despair",
+"fought",
+"grant",
+"grief",
+"horse",
+"limit",
+"message",
+"ripple",
+"sanity",
+"scatter",
+"serve",
+"split",
+"string",
+"trick",
+"annoy",
+"blur",
+"boat",
+"brave",
+"clearly",
+"cling",
+"connect",
+"fist",
+"forth",
+"imagination",
+"iron",
+"jock",
+"judge",
+"lesson",
+"milk",
+"misery",
+"nail",
+"naked",
+"ourselves",
+"poet",
+"possible",
+"princess",
+"sail",
+"size",
+"snake",
+"society",
+"stroke",
+"torture",
+"toss",
+"trace",
+"wise",
+"bloom",
+"bullet",
+"cell",
+"check",
+"cost",
+"darling",
+"during",
+"footstep",
+"fragile",
+"hallway",
+"hardly",
+"horizon",
+"invisible",
+"journey",
+"midnight",
+"mud",
+"nod",
+"pause",
+"relax",
+"shiver",
+"sudden",
+"value",
+"youth",
+"abuse",
+"admire",
+"blink",
+"breast",
+"bruise",
+"constantly",
+"couple",
+"creep",
+"curve",
+"difference",
+"dumb",
+"emptiness",
+"gotta",
+"honor",
+"plain",
+"planet",
+"recall",
+"rub",
+"ship",
+"slam",
+"soar",
+"somebody",
+"tightly",
+"weather",
+"adore",
+"approach",
+"bond",
+"bread",
+"burst",
+"candle",
+"coffee",
+"cousin",
+"crime",
+"desert",
+"flutter",
+"frozen",
+"grand",
+"heel",
+"hello",
+"language",
+"level",
+"movement",
+"pleasure",
+"powerful",
+"random",
+"rhythm",
+"settle",
+"silly",
+"slap",
+"sort",
+"spoken",
+"steel",
+"threaten",
+"tumble",
+"upset",
+"aside",
+"awkward",
+"bee",
+"blank",
+"board",
+"button",
+"card",
+"carefully",
+"complain",
+"crap",
+"deeply",
+"discover",
+"drag",
+"dread",
+"effort",
+"entire",
+"fairy",
+"giant",
+"gotten",
+"greet",
+"illusion",
+"jeans",
+"leap",
+"liquid",
+"march",
+"mend",
+"nervous",
+"nine",
+"replace",
+"rope",
+"spine",
+"stole",
+"terror",
+"accident",
+"apple",
+"balance",
+"boom",
+"childhood",
+"collect",
+"demand",
+"depression",
+"eventually",
+"faint",
+"glare",
+"goal",
+"group",
+"honey",
+"kitchen",
+"laid",
+"limb",
+"machine",
+"mere",
+"mold",
+"murder",
+"nerve",
+"painful",
+"poetry",
+"prince",
+"rabbit",
+"shelter",
+"shore",
+"shower",
+"soothe",
+"stair",
+"steady",
+"sunlight",
+"tangle",
+"tease",
+"treasure",
+"uncle",
+"begun",
+"bliss",
+"canvas",
+"cheer",
+"claw",
+"clutch",
+"commit",
+"crimson",
+"crystal",
+"delight",
+"doll",
+"existence",
+"express",
+"fog",
+"football",
+"gay",
+"goose",
+"guard",
+"hatred",
+"illuminate",
+"mass",
+"math",
+"mourn",
+"rich",
+"rough",
+"skip",
+"stir",
+"student",
+"style",
+"support",
+"thorn",
+"tough",
+"yard",
+"yearn",
+"yesterday",
+"advice",
+"appreciate",
+"autumn",
+"bank",
+"beam",
+"bowl",
+"capture",
+"carve",
+"collapse",
+"confusion",
+"creation",
+"dove",
+"feather",
+"girlfriend",
+"glory",
+"government",
+"harsh",
+"hop",
+"inner",
+"loser",
+"moonlight",
+"neighbor",
+"neither",
+"peach",
+"pig",
+"praise",
+"screw",
+"shield",
+"shimmer",
+"sneak",
+"stab",
+"subject",
+"throughout",
+"thrown",
+"tower",
+"twirl",
+"wow",
+"army",
+"arrive",
+"bathroom",
+"bump",
+"cease",
+"cookie",
+"couch",
+"courage",
+"dim",
+"guilt",
+"howl",
+"hum",
+"husband",
+"insult",
+"led",
+"lunch",
+"mock",
+"mostly",
+"natural",
+"nearly",
+"needle",
+"nerd",
+"peaceful",
+"perfection",
+"pile",
+"price",
+"remove",
+"roam",
+"sanctuary",
+"serious",
+"shiny",
+"shook",
+"sob",
+"stolen",
+"tap",
+"vain",
+"void",
+"warrior",
+"wrinkle",
+"affection",
+"apologize",
+"blossom",
+"bounce",
+"bridge",
+"cheap",
+"crumble",
+"decision",
+"descend",
+"desperately",
+"dig",
+"dot",
+"flip",
+"frighten",
+"heartbeat",
+"huge",
+"lazy",
+"lick",
+"odd",
+"opinion",
+"process",
+"puzzle",
+"quietly",
+"retreat",
+"score",
+"sentence",
+"separate",
+"situation",
+"skill",
+"soak",
+"square",
+"stray",
+"taint",
+"task",
+"tide",
+"underneath",
+"veil",
+"whistle",
+"anywhere",
+"bedroom",
+"bid",
+"bloody",
+"burden",
+"careful",
+"compare",
+"concern",
+"curtain",
+"decay",
+"defeat",
+"describe",
+"double",
+"dreamer",
+"driver",
+"dwell",
+"evening",
+"flare",
+"flicker",
+"grandma",
+"guitar",
+"harm",
+"horrible",
+"hungry",
+"indeed",
+"lace",
+"melody",
+"monkey",
+"nation",
+"object",
+"obviously",
+"rainbow",
+"salt",
+"scratch",
+"shown",
+"shy",
+"stage",
+"stun",
+"third",
+"tickle",
+"useless",
+"weakness",
+"worship",
+"worthless",
+"afternoon",
+"beard",
+"boyfriend",
+"bubble",
+"busy",
+"certain",
+"chin",
+"concrete",
+"desk",
+"diamond",
+"doom",
+"drawn",
+"due",
+"felicity",
+"freeze",
+"frost",
+"garden",
+"glide",
+"harmony",
+"hopefully",
+"hunt",
+"jealous",
+"lightning",
+"mama",
+"mercy",
+"peel",
+"physical",
+"position",
+"pulse",
+"punch",
+"quit",
+"rant",
+"respond",
+"salty",
+"sane",
+"satisfy",
+"savior",
+"sheep",
+"slept",
+"social",
+"sport",
+"tuck",
+"utter",
+"valley",
+"wolf",
+"aim",
+"alas",
+"alter",
+"arrow",
+"awaken",
+"beaten",
+"belief",
+"brand",
+"ceiling",
+"cheese",
+"clue",
+"confidence",
+"connection",
+"daily",
+"disguise",
+"eager",
+"erase",
+"essence",
+"everytime",
+"expression",
+"fan",
+"flag",
+"flirt",
+"foul",
+"fur",
+"giggle",
+"glorious",
+"ignorance",
+"law",
+"lifeless",
+"measure",
+"mighty",
+"muse",
+"north",
+"opposite",
+"paradise",
+"patience",
+"patient",
+"pencil",
+"petal",
+"plate",
+"ponder",
+"possibly",
+"practice",
+"slice",
+"spell",
+"stock",
+"strife",
+"strip",
+"suffocate",
+"suit",
+"tender",
+"tool",
+"trade",
+"velvet",
+"verse",
+"waist",
+"witch",
+"aunt",
+"bench",
+"bold",
+"cap",
+"certainly",
+"click",
+"companion",
+"creator",
+"dart",
+"delicate",
+"determine",
+"dish",
+"dragon",
+"drama",
+"drum",
+"dude",
+"everybody",
+"feast",
+"forehead",
+"former",
+"fright",
+"fully",
+"gas",
+"hook",
+"hurl",
+"invite",
+"juice",
+"manage",
+"moral",
+"possess",
+"raw",
+"rebel",
+"royal",
+"scale",
+"scary",
+"several",
+"slight",
+"stubborn",
+"swell",
+"talent",
+"tea",
+"terrible",
+"thread",
+"torment",
+"trickle",
+"usually",
+"vast",
+"violence",
+"weave",
+"acid",
+"agony",
+"ashamed",
+"awe",
+"belly",
+"blend",
+"blush",
+"character",
+"cheat",
+"common",
+"company",
+"coward",
+"creak",
+"danger",
+"deadly",
+"defense",
+"define",
+"depend",
+"desperate",
+"destination",
+"dew",
+"duck",
+"dusty",
+"embarrass",
+"engine",
+"example",
+"explore",
+"foe",
+"freely",
+"frustrate",
+"generation",
+"glove",
+"guilty",
+"health",
+"hurry",
+"idiot",
+"impossible",
+"inhale",
+"jaw",
+"kingdom",
+"mention",
+"mist",
+"moan",
+"mumble",
+"mutter",
+"observe",
+"ode",
+"pathetic",
+"pattern",
+"pie",
+"prefer",
+"puff",
+"rape",
+"rare",
+"revenge",
+"rude",
+"scrape",
+"spiral",
+"squeeze",
+"strain",
+"sunset",
+"suspend",
+"sympathy",
+"thigh",
+"throne",
+"total",
+"unseen",
+"weapon",
+"weary"};
\ No newline at end of file
diff --git a/include/dogecoin/bip39.h b/include/dogecoin/bip39.h
index 8aa993f82..1d6052b1d 100644
--- a/include/dogecoin/bip39.h
+++ b/include/dogecoin/bip39.h
@@ -204,6 +204,26 @@ LIBDOGECOIN_API int generateRandomEnglishMnemonic(const ENTROPY_SIZE size, MNEMO
/* return: 0 (success), -1 (fail) */
LIBDOGECOIN_API int generateEnglishMnemonic(const HEX_ENTROPY entropy, const ENTROPY_SIZE size, MNEMONIC mnemonic);
+/* Check if mnemonic is an Electrum v2+ seed */
+/* mnemonic code words */
+/* pointer to receive version number (optional, may be NULL) */
+/* returns 0 (success), -1 (fail) */
+LIBDOGECOIN_API int dogecoin_mnemonic_is_electrum_seed(const char* mnemonic, uint32_t* out_version);
+
+/* Derive the seed from an Electrum v2+ mnemonic and optional passphrase */
+/* mnemonic code words */
+/* passphrase (optional) */
+/* 512-bit seed */
+/* returns 0 (success), -1 (fail) */
+LIBDOGECOIN_API int dogecoin_seed_from_electrum_mnemonic(const char* mnemonic, const char* passphrase, SEED seed);
+
+/* Derive the seed from an Electrum v1 mnemonic and optional passphrase */
+/* mnemonic code words (12 words from 1626-word list) */
+/* passphrase (optional) */
+/* 512-bit seed (16 bytes of decoded entropy, zero-padded) */
+/* returns 0 (success), -1 (fail) */
+LIBDOGECOIN_API int dogecoin_seed_from_electrum_v1_mnemonic(const char* mnemonic, const char* passphrase, SEED seed);
+
LIBDOGECOIN_END_DECL
#endif // __LIBDOGECOIN_BIP39_H__
diff --git a/include/dogecoin/key.h b/include/dogecoin/key.h
index cf4d83099..f32a79c2e 100644
--- a/include/dogecoin/key.h
+++ b/include/dogecoin/key.h
@@ -103,6 +103,13 @@ LIBDOGECOIN_API void getWifEncodedPrivKey(const uint8_t privkey[DOGECOIN_ECKEY_P
// wrapper for wif decoding
LIBDOGECOIN_API int getDecodedPrivKeyWif(const char privkey_wif[PRIVKEYWIFLEN], const dogecoin_bool is_testnet, uint8_t privkey[DOGECOIN_ECKEY_PKEY_LENGTH]);
+// Electrum v1 (pre-v2) deterministic key derivation.
+// Takes raw 16-byte v1 seed (in first 16 bytes), stretches it, and derives child key.
+LIBDOGECOIN_API int electrum_v1_derive_privkey32(const uint8_t v1_seed[32],
+ uint32_t n,
+ uint32_t for_change,
+ uint8_t out_priv32[32]);
+
LIBDOGECOIN_END_DECL
#endif // __LIBDOGECOIN_KEY_H__
diff --git a/src/bip39.c b/src/bip39.c
index 63cdbc232..853611dbe 100644
--- a/src/bip39.c
+++ b/src/bip39.c
@@ -26,11 +26,18 @@
*/
#include
+#include
+#include
+#include
+
#include
#include
#include
#include
#include
+#ifndef UTF8PROC_STATIC
+#define UTF8PROC_STATIC
+#endif
#include
#ifdef _WIN32
@@ -40,6 +47,317 @@
#include
#endif
+#include // For wordlist_electrum[1626]
+
+/*
+ * Electrum seed support (minimal, additive)
+ *
+ * Electrum v2+:
+ * - seed version = int(prefix,16) where prefix comes from HMAC-SHA512("Seed version", prepared_seed)
+ * - seed bytes = PBKDF2-HMAC-SHA512(password=prepared_seed, salt="electrum"+passphrase, rounds=2048, dklen=64)
+ *
+ * Electrum v1 (pre-v2):
+ * - 12 words from 1626-word list encode/decode a 16-byte (128-bit) seed
+ * - seed bytes = stretched seed (32 bytes):
+ * seed = SHA256(mnemonic + (" " + passphrase if passphrase non-empty))
+ * stretched = seed
+ * repeat 100000 times: stretched = SHA256(stretched + seed)
+ * - NOTE: v1 is 32 bytes. We place it in seed[0..31] and zero seed[32..63].
+ */
+
+#define ELECTRUM_V1_WORDLIST_SIZE 1626
+#define ELECTRUM_V1_SEED_BYTES 16
+/* Electrum v1 requires exactly 12 words (4 groups of 3) encoding 16 bytes.
+ * Verified: bip-utils ElectrumV1MnemonicConst.MNEMONIC_WORD_NUM == [12] */
+#define ELECTRUM_V1_WORDS 12
+
+/* HMAC-SHA512(key, msg) -> hex string */
+static void electrum_hmac_sha512_hex(const unsigned char* key, size_t keylen,
+ const unsigned char* msg, size_t msglen,
+ char out_hex[129])
+{
+ unsigned char mac[SHA512_DIGEST_LENGTH];
+ dogecoin_mem_zero(mac, sizeof(mac));
+ dogecoin_mem_zero(out_hex, 129);
+
+ /* libdogecoin sha2 provides hmac_sha512 */
+ hmac_sha512(key, keylen, msg, msglen, mac);
+
+ for (size_t i = 0; i < SHA512_DIGEST_LENGTH; i++) {
+ sprintf(&out_hex[i * 2], "%02x", mac[i]);
+ }
+ out_hex[128] = '\0';
+ dogecoin_mem_zero(mac, sizeof(mac));
+}
+
+/* Check if mnemonic is an Electrum v2+ seed and optionally return its version. */
+/* mnemonic code words */
+/* pointer to receive version number (optional, may be NULL) */
+/* returns 0 (success), -1 (fail) */
+int dogecoin_mnemonic_is_electrum_seed(const char* mnemonic, uint32_t* out_version)
+{
+ if (!mnemonic) return -1;
+
+ /* NFKD + casefold in a single utf8proc_map call */
+ utf8proc_uint8_t *norm = NULL;
+ utf8proc_ssize_t norm_ret = utf8proc_map(
+ (const utf8proc_uint8_t *)mnemonic, 0, &norm,
+ (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
+ UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT |
+ UTF8PROC_CASEFOLD));
+ if (norm_ret < 0 || !norm) return -1;
+
+ size_t seed_len = (size_t)norm_ret;
+
+ char mac_hex[129];
+ electrum_hmac_sha512_hex((const unsigned char*)"Seed version", strlen("Seed version"),
+ norm, seed_len,
+ mac_hex);
+ dogecoin_free(norm);
+
+ /* prefix length = int(mac_hex[0],16) + 2 */
+ int nibble = 0;
+ if (mac_hex[0] >= '0' && mac_hex[0] <= '9') nibble = mac_hex[0] - '0';
+ else if (mac_hex[0] >= 'a' && mac_hex[0] <= 'f') nibble = mac_hex[0] - 'a' + 10;
+ else if (mac_hex[0] >= 'A' && mac_hex[0] <= 'F') nibble = mac_hex[0] - 'A' + 10;
+ else return -1;
+
+ int prefix_len = nibble + 2;
+ if (prefix_len < 2 || prefix_len > 8) return -1; /* sanity */
+
+ char prefix[9];
+ dogecoin_mem_zero(prefix, sizeof(prefix));
+ memcpy(prefix, mac_hex, (size_t)prefix_len);
+ prefix[prefix_len] = '\0';
+
+ uint32_t ver = (uint32_t)strtoul(prefix, NULL, 16);
+
+ /* known Electrum v2+ versions */
+ if (ver == 0x01 || ver == 0x100 || ver == 0x101) {
+ if (out_version) *out_version = ver;
+ return 0;
+ }
+
+ return -1;
+}
+
+/* Derive the 64-byte seed from an Electrum v2+ seed phrase and optional passphrase. */
+/* mnemonic code words */
+/* passphrase (optional) */
+/* 512-bit seed */
+/* returns 0 (success), -1 (fail) */
+int dogecoin_seed_from_electrum_mnemonic(const char* mnemonic, const char* passphrase, SEED seed)
+{
+ if (!mnemonic || !seed) {
+ fprintf(stderr, "ERROR: invalid input arguments\n");
+ return -1;
+ }
+
+ if (passphrase == NULL) {
+ passphrase = "";
+ }
+
+ /* NFKD + casefold in a single utf8proc_map call */
+ utf8proc_uint8_t *norm = NULL;
+ utf8proc_ssize_t norm_ret = utf8proc_map(
+ (const utf8proc_uint8_t *)mnemonic, 0, &norm,
+ (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
+ UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT |
+ UTF8PROC_CASEFOLD));
+ if (norm_ret < 0 || !norm) {
+ fprintf(stderr, "ERROR: failed to NFKD-normalize electrum mnemonic\n");
+ return -1;
+ }
+
+ size_t seed_len = (size_t)norm_ret;
+
+ size_t salt_len = strlen("electrum") + strlen(passphrase);
+ char* salt = malloc(salt_len + 1);
+ if (!salt) {
+ fprintf(stderr, "ERROR: Failed to allocate memory for electrum salt\n");
+ dogecoin_free(norm);
+ return -1;
+ }
+ salt[0] = '\0';
+ strcat(salt, "electrum");
+ strcat(salt, passphrase);
+
+ /* PBKDF2-HMAC-SHA512, rounds=2048, dkLen=64 */
+ memset(seed, 0, MAX_SEED_SIZE);
+ pbkdf2_hmac_sha512(norm, seed_len,
+ (const unsigned char*)salt, strlen(salt),
+ ITERATIONS, seed);
+
+ dogecoin_mem_zero(norm, seed_len);
+ dogecoin_free(norm);
+ dogecoin_mem_zero(salt, salt_len + 1);
+ dogecoin_free(salt);
+ return 0;
+}
+
+/*
+ * Electrum v1 (pre-v2) seed support (minimal, additive)
+ */
+
+/*
+ * Find word index in Electrum v1 wordlist.
+ * Returns index 0-1625, or -1 if not found.
+ */
+static int electrum_v1_find_word(const char* word)
+{
+ if (!word) return -1;
+
+ for (int i = 0; i < ELECTRUM_V1_WORDLIST_SIZE; i++) {
+ if (strcmp(word, wordlist_electrum[i]) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/* Decode 12-word Electrum v1 mnemonic to 16-byte seed (old_mnemonic.mn_decode).
+ * Electrum v1 requires exactly 12 words — each group of 3 words encodes 32 bits
+ * via base-1626 arithmetic, yielding 4 × 4 = 16 bytes of entropy. */
+static int electrum_v1_decode_mnemonic(const char* mnemonic,
+ unsigned char seed16_out[ELECTRUM_V1_SEED_BYTES])
+{
+ if (!mnemonic || !seed16_out) return -1;
+
+ /* NFKD + casefold in a single utf8proc_map call */
+ utf8proc_uint8_t *norm = NULL;
+ utf8proc_ssize_t norm_ret = utf8proc_map(
+ (const utf8proc_uint8_t *)mnemonic, 0, &norm,
+ (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
+ UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT |
+ UTF8PROC_CASEFOLD));
+ if (norm_ret < 0 || !norm) return -1;
+
+ /* copy to mutable stack buffer for strtok_r */
+ char buf[MAX_MNEMONIC_STRING_SIZE];
+ dogecoin_mem_zero(buf, sizeof(buf));
+ if ((size_t)norm_ret >= sizeof(buf)) {
+ dogecoin_free(norm);
+ return -1;
+ }
+ memcpy(buf, norm, (size_t)norm_ret + 1);
+ dogecoin_free(norm);
+
+ /* parse 12 words */
+ uint16_t idx[ELECTRUM_V1_WORDS];
+ int wc = 0;
+ char* saveptr = NULL;
+
+ char* tok = strtok_r(buf, " ", &saveptr);
+ while (tok) {
+ if (wc >= ELECTRUM_V1_WORDS) return -1;
+ int w = electrum_v1_find_word(tok);
+ if (w < 0) return -1;
+ idx[wc++] = (uint16_t)w;
+ tok = strtok_r(NULL, " ", &saveptr);
+ }
+ if (wc != ELECTRUM_V1_WORDS) return -1;
+
+ const uint32_t N = ELECTRUM_V1_WORDLIST_SIZE;
+
+ /* each 3 words -> 32 bits */
+ for (int g = 0; g < 4; g++) {
+ uint32_t w1 = idx[g * 3 + 0];
+ uint32_t w2 = idx[g * 3 + 1];
+ uint32_t w3 = idx[g * 3 + 2];
+
+ uint32_t d12 = (w2 + N - w1) % N;
+ uint32_t d23 = (w3 + N - w2) % N;
+
+ uint64_t x64 = (uint64_t)w1
+ + (uint64_t)N * (uint64_t)d12
+ + (uint64_t)N * (uint64_t)N * (uint64_t)d23;
+
+ /* reject impossible triples (some word triples map above 2^32-1) */
+ if (x64 > 0xFFFFFFFFULL) return -1;
+
+ uint32_t x = (uint32_t)x64;
+
+ seed16_out[g * 4 + 0] = (unsigned char)(x >> 24);
+ seed16_out[g * 4 + 1] = (unsigned char)(x >> 16);
+ seed16_out[g * 4 + 2] = (unsigned char)(x >> 8);
+ seed16_out[g * 4 + 3] = (unsigned char)(x);
+ }
+
+ return 0;
+}
+
+/* Encode 16-byte seed to 12 Electrum v1 words (old_mnemonic.mn_encode). */
+static int electrum_v1_encode_mnemonic(const unsigned char seed16[ELECTRUM_V1_SEED_BYTES],
+ char* out, size_t outlen)
+{
+ if (!seed16 || !out || outlen == 0) return -1;
+
+ const uint32_t N = ELECTRUM_V1_WORDLIST_SIZE;
+ size_t pos = 0;
+ out[0] = '\0';
+
+ for (int g = 0; g < 4; g++) {
+ uint32_t x =
+ ((uint32_t)seed16[g * 4 + 0] << 24) |
+ ((uint32_t)seed16[g * 4 + 1] << 16) |
+ ((uint32_t)seed16[g * 4 + 2] << 8) |
+ ((uint32_t)seed16[g * 4 + 3]);
+
+ uint32_t w1 = x % N;
+ uint32_t w2 = ((x / N) + w1) % N;
+ uint32_t w3 = ((x / (N * N)) + w2) % N;
+
+ const char* a = wordlist_electrum[w1];
+ const char* b = wordlist_electrum[w2];
+ const char* c = wordlist_electrum[w3];
+
+ const char* sp = (pos == 0) ? "" : " ";
+ int n = snprintf(out + pos, outlen - pos, "%s%s %s %s", sp, a, b, c);
+ if (n < 0 || (size_t)n >= outlen - pos) return -1;
+ pos += (size_t)n;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Decode Electrum v1 seed from 12-word mnemonic.
+ *
+ * Decodes a valid 12-word Electrum v1 mnemonic (from the 1626-word list)
+ * to a 16-byte seed using base-1626. The raw decoded seed is stored in
+ * seed[0..15] and the remaining bytes are zeroed.
+ *
+ * In original Electrum v1, the seed is the raw decoded value (e.g.
+ * '8edad31a95e7d59f8837667510d75a4d'). The stretch_key() operation is
+ * applied later during key derivation, not during seed storage.
+ *
+ * Returns 0 on success, -1 if the mnemonic is not a valid Electrum v1 mnemonic.
+ */
+int dogecoin_seed_from_electrum_v1_mnemonic(const char* mnemonic, const char* passphrase, SEED seed)
+{
+ (void)passphrase; /* unused in Electrum v1 seed decoding */
+ memset(seed, 0, MAX_SEED_SIZE);
+
+ if (!mnemonic || !seed) {
+ return -1;
+ }
+
+ /* Decode 12-word mnemonic to 16-byte seed */
+ unsigned char seed16[ELECTRUM_V1_SEED_BYTES];
+ dogecoin_mem_zero(seed16, sizeof(seed16));
+
+ if (electrum_v1_decode_mnemonic(mnemonic, seed16) != 0) {
+ return -1; /* Not a valid Electrum v1 mnemonic */
+ }
+
+ /* Store the raw decoded 16-byte seed directly */
+ memcpy(seed, seed16, ELECTRUM_V1_SEED_BYTES);
+
+ dogecoin_mem_zero(seed16, sizeof(seed16));
+ return 0;
+}
+
/*
* This function implements the first part of the BIP-39 algorithm.
* The randomness or entropy for the mnemonic must be a multiple of
@@ -73,7 +391,6 @@ int get_mnemonic(const int entropysize, const char* entropy, const char* wordlis
return -1;
}
-
int entBytes = entropysize / 8; // bytes instead of bits
int csAdd = entropysize / 32; // portion in bits of a single byte
@@ -88,7 +405,6 @@ int get_mnemonic(const int entropysize, const char* entropy, const char* wordlis
entropyBits[0] = '\0';
dogecoin_mem_zero(entropyBits, entropysize + 1); // Initialize entropyBits to all zeros
-
char binaryByte[9] = "";
/* Allocate memory for local entropy */
@@ -275,7 +591,7 @@ int get_root_seed(const char *pass, const char *passphrase, SEED seed) {
DWORD error = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&message, 0, NULL);
- fprintf(stderr, "ERROR: getting length of normalized passphrase: %s\n", message);
+ fprintf(stderr, "ERROR: getting length of normalized passphrase: %s\n", (char*)message);
LocalFree(message);
dogecoin_free(salt);
dogecoin_free(pass_w);
@@ -331,10 +647,10 @@ int get_root_seed(const char *pass, const char *passphrase, SEED seed) {
}
/* Convert normalized passphrase and salt to multi-byte characters */
- int norm_pass_mb_len = WideCharToMultiByte(CP_UTF8, 0, norm_pass, norm_pass_len, NULL, 0, NULL, NULL);
- int norm_salt_mb_len = WideCharToMultiByte(CP_UTF8, 0, norm_salt, norm_salt_len, NULL, 0, NULL, NULL);
+ int norm_pass_mb_len = WideCharToMultiByte(CP_UTF8, 0, norm_pass, (int)norm_pass_len, NULL, 0, NULL, NULL);
+ int norm_salt_mb_len = WideCharToMultiByte(CP_UTF8, 0, norm_salt, (int)norm_salt_len, NULL, 0, NULL, NULL);
- if (norm_pass_len == 0) {
+ if (norm_pass_mb_len == 0) {
fprintf(stderr, "ERROR: converting normalized passphrase to multi-byte characters\n");
dogecoin_free(salt);
dogecoin_free(pass_w);
@@ -343,8 +659,8 @@ int get_root_seed(const char *pass, const char *passphrase, SEED seed) {
dogecoin_free(norm_salt);
return -1;
}
- if (norm_salt_len == 0) {
- fprintf(stderr, "ERROR: converting normalized seed to multi-byte characters\n");
+ if (norm_salt_mb_len == 0) {
+ fprintf(stderr, "ERROR: converting normalized salt to multi-byte characters\n");
dogecoin_free(salt);
dogecoin_free(pass_w);
dogecoin_free(salt_w);
@@ -353,7 +669,7 @@ int get_root_seed(const char *pass, const char *passphrase, SEED seed) {
return -1;
}
- char* norm_pass_mb = malloc(norm_pass_mb_len * sizeof(char));
+ char* norm_pass_mb = malloc((size_t)norm_pass_mb_len);
if (norm_pass_mb == NULL) {
fprintf(stderr, "ERROR: allocating memory for normalized passphrase multi-byte characters\n");
dogecoin_free(salt);
@@ -363,7 +679,7 @@ int get_root_seed(const char *pass, const char *passphrase, SEED seed) {
dogecoin_free(norm_salt);
return -1;
}
- char* norm_salt_mb = malloc(norm_salt_mb_len * sizeof(char));
+ char* norm_salt_mb = malloc((size_t)norm_salt_mb_len);
if (norm_salt_mb == NULL) {
fprintf(stderr, "ERROR: allocating memory for normalized salt multi-byte characters\n");
dogecoin_free(salt);
@@ -375,7 +691,7 @@ int get_root_seed(const char *pass, const char *passphrase, SEED seed) {
return -1;
}
- if (WideCharToMultiByte(CP_UTF8, 0, norm_pass, norm_pass_len, norm_pass_mb, norm_pass_mb_len, NULL, NULL) == 0) {
+ if (WideCharToMultiByte(CP_UTF8, 0, norm_pass, (int)norm_pass_len, norm_pass_mb, norm_pass_mb_len, NULL, NULL) == 0) {
fprintf(stderr, "ERROR: converting normalized passphrase to multi-byte characters\n");
dogecoin_free(salt);
dogecoin_free(pass_w);
@@ -387,8 +703,8 @@ int get_root_seed(const char *pass, const char *passphrase, SEED seed) {
return -1;
}
- if (WideCharToMultiByte(CP_UTF8, 0, norm_salt, norm_salt_len, norm_salt_mb, norm_salt_mb_len, NULL, NULL) == 0) {
- fprintf(stderr, "ERROR: converting normalized passphrase to multi-byte characters\n");
+ if (WideCharToMultiByte(CP_UTF8, 0, norm_salt, (int)norm_salt_len, norm_salt_mb, norm_salt_mb_len, NULL, NULL) == 0) {
+ fprintf(stderr, "ERROR: converting normalized salt to multi-byte characters\n");
dogecoin_free(salt);
dogecoin_free(pass_w);
dogecoin_free(salt_w);
@@ -407,7 +723,9 @@ int get_root_seed(const char *pass, const char *passphrase, SEED seed) {
dogecoin_free(norm_salt);
/* pbkdf2 hmac sha512 */
- pbkdf2_hmac_sha512((const unsigned char*) norm_pass_mb, norm_pass_mb_len, (const unsigned char*) norm_salt_mb, norm_salt_mb_len, ITERATIONS, seed);
+ pbkdf2_hmac_sha512((const unsigned char*) norm_pass_mb, (size_t)norm_pass_mb_len,
+ (const unsigned char*) norm_salt_mb, (size_t)norm_salt_mb_len,
+ ITERATIONS, seed);
dogecoin_free(norm_pass_mb);
dogecoin_free(norm_salt_mb);
@@ -633,8 +951,8 @@ int produce_mnemonic_sentence(const int segSize, const int checksumBits, const c
* ensuring that the segment array does not overflow.
*/
- strncat(segment, entropy, segSize - strlen(segment) - 1);
- strncat(segment, csBits, segSize - strlen(segment) - 1);
+ strncat(segment, entropy, segSize - (int)strlen(segment) - 1);
+ strncat(segment, csBits, segSize - (int)strlen(segment) - 1);
dogecoin_free (csBits);
@@ -750,7 +1068,7 @@ int verify_mnemonic_sentence(const char* mnemonic, const char* wordlist[], const
}
/* compute bit lengths */
- int total_bits = word_count * BITS_PER_WORD;
+ int total_bits = (int)(word_count * BITS_PER_WORD);
int checksum_bits = total_bits / 33;
int entropy_bits = total_bits - checksum_bits;
int entropy_bytes = entropy_bits / 8;
@@ -804,12 +1122,12 @@ int verify_mnemonic_sentence(const char* mnemonic, const char* wordlist[], const
dogecoin_free(buf);
return -1;
}
- dogecoin_mem_zero(entropy, entropy_bytes);
+ dogecoin_mem_zero(entropy, (size_t)entropy_bytes);
for (int i = 0; i < entropy_bytes; i++) {
unsigned char byte = 0;
for (int b = 0; b < 8; b++) {
if (bitstr[i * 8 + b] == '1') {
- byte |= (1 << (7 - b));
+ byte |= (unsigned char)(1 << (7 - b));
}
}
entropy[i] = byte;
@@ -817,7 +1135,7 @@ int verify_mnemonic_sentence(const char* mnemonic, const char* wordlist[], const
/* SHA-256 and compare checksum bits */
unsigned char hash[SHA256_DIGEST_LENGTH];
- sha256_raw(entropy, entropy_bytes, hash);
+ sha256_raw(entropy, (size_t)entropy_bytes, hash);
for (int i = 0; i < checksum_bits; i++) {
char expected = ((hash[0] >> (7 - i)) & 1) ? '1' : '0';
@@ -833,12 +1151,12 @@ int verify_mnemonic_sentence(const char* mnemonic, const char* wordlist[], const
/* clean up */
utils_clear_buffers();
- dogecoin_mem_zero(entropy, entropy_bytes);
- dogecoin_mem_zero(bitstr, total_bits);
+ dogecoin_mem_zero(entropy, (size_t)entropy_bytes);
+ dogecoin_mem_zero(bitstr, (size_t)total_bits);
dogecoin_mem_zero(buf, mlen + 1);
dogecoin_free(bitstr);
dogecoin_free(entropy);
- free(buf);
+ dogecoin_free(buf);
return 0;
}
@@ -864,7 +1182,7 @@ int dogecoin_generate_mnemonic (const ENTROPY_SIZE entropy_size, const char* lan
if (entropy_size != NULL) {
/* load custom word file into memory if path is valid */
- if (filepath != NULL) {
+ if (filepath != NULL) {
if (get_custom_words (filepath, (char **) wordlist) == -1) {
/* Free memory for custom words */
@@ -890,11 +1208,11 @@ int dogecoin_generate_mnemonic (const ENTROPY_SIZE entropy_size, const char* lan
if (entropy != NULL) {
/* Calculate expected size of entropy hex string */
- size_t expected_entropy_size = strtol(entropy_size, NULL, 10) / 8 * HEX_CHARS_PER_BYTE;
+ size_t expected_entropy_size = (size_t)strtol(entropy_size, NULL, 10) / 8 * HEX_CHARS_PER_BYTE;
/* Verify size of the string equals the entropy_size specified */
if (strlen(entropy) != expected_entropy_size) {
- fprintf(stderr, "ERROR: invalid entropy string, expected %ld characters\n", expected_entropy_size);
+ fprintf(stderr, "ERROR: invalid entropy string, expected %ld characters\n", (long)expected_entropy_size);
/* Free memory for custom words */
if (filepath != NULL) {
@@ -907,7 +1225,7 @@ int dogecoin_generate_mnemonic (const ENTROPY_SIZE entropy_size, const char* lan
}
/* convert string value for entropy size to base 10 and get mnemonic */
- if (get_mnemonic(strtol(entropy_size, NULL, 10), entropy, (const char **) wordlist, space, entropy_out, words, size) == -1) {
+ if (get_mnemonic((int)strtol(entropy_size, NULL, 10), entropy, (const char **) wordlist, space, entropy_out, words, size) == -1) {
fprintf(stderr, "ERROR: Failed to get mnemonic\n");
/* Free memory for custom words */
@@ -1002,7 +1320,15 @@ int dogecoin_seed_from_mnemonic (const char* mnemonic, const char* passphrase, S
passphrase = "";
}
- /* get binary seed */
+ /* Electrum v2+ (post-v2) auto-detect */
+ if (dogecoin_mnemonic_is_electrum_seed(mnemonic, NULL) == 0) {
+ if (dogecoin_seed_from_electrum_mnemonic(mnemonic, passphrase, seed) == 0) {
+ return 0;
+ }
+ /* fall through to BIP39 if something failed */
+ }
+
+ /* BIP39 seed derivation */
if (get_root_seed(mnemonic, passphrase, seed) == -1) {
fprintf(stderr, "ERROR: Failed to get root seed\n");
return -1;
diff --git a/src/cli/such.c b/src/cli/such.c
index 5ae7a79c6..d1a13fad6 100644
--- a/src/cli/such.c
+++ b/src/cli/such.c
@@ -47,6 +47,7 @@
#include
#include
+#include
#include
#include
#include
@@ -54,6 +55,8 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -626,6 +629,7 @@ static struct option long_options[] =
{"command", required_argument, NULL, 'c'},
{"silent", no_argument, NULL, 'b'},
{"overwrite", no_argument, NULL, 'w'},
+ {"electrum_v1", no_argument, NULL, 'l'},
{"testnet", no_argument, NULL, 't'},
{"regtest", no_argument, NULL, 'r'},
{"version", no_argument, NULL, 'v'},
@@ -642,7 +646,7 @@ static void print_usage()
printf("Usage: such -c (-m|-derived_path ) (-k|-pubkey ) (-p|-privkey ) (-h|-sighash ) \
(-s|-script