bip39 bitcoin wallet module

pull/3901/head
bipkitty 7 months ago
parent adbcef6909
commit f70f3761a9
No known key found for this signature in database
GPG Key ID: 2D1CDB7B55E5F2BF

1
.gitignore vendored

@ -1,3 +1,4 @@
.vscode
*.exe
*.bin
*.app

@ -0,0 +1,341 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#include "inc_vendor.h"
#include "inc_common.h"
#include "inc_types.h"
#include "inc_platform.h"
#include "inc_bip39.h"
#include "inc_hash_sha256.h"
CONSTANT_VK char BIP39_WORDS[2048][9] =
{ "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"
};
CONSTANT_VK u8 BIP39_WORD_LENGTHS[2048] =
{ 7, 7, 4, 5, 5, 6, 6, 8, 6, 5, 6, 8, 7, 6, 7, 4, 8, 7, 6, 3, 6, 5, 7, 6, 5, 3, 6, 7, 6, 5, 5, 7, 6, 7, 6, 6, 6, 5, 3, 5, 5, 5, 3, 3, 7, 5, 5, 5, 7, 5, 5, 3, 5, 5, 6, 5, 5, 7, 4, 5, 6, 7, 7, 5, 6, 6, 7, 6, 7, 5, 5, 5, 6, 5, 8, 6, 7, 6, 7, 7, 7, 3, 5, 7, 6, 5, 7, 5, 4, 6, 4, 5, 5, 3, 5, 5, 4, 6, 7, 6, 6, 5, 3, 8, 6, 7, 3, 6, 7, 5, 6, 6, 6, 7, 4, 6, 6, 8, 7, 7, 5, 6, 4, 6, 4, 6, 7, 7, 5, 5, 5, 4, 7, 5, 7, 4, 4, 8, 5, 5, 3, 7, 7, 4, 6, 6, 6, 3, 6, 7, 6, 4, 5, 6, 6, 5, 4, 6, 7, 6, 4, 6, 5, 6, 6, 7, 5, 4, 5, 7, 4, 6, 6, 7, 6, 7, 3, 4, 4, 7, 4, 5, 6, 5, 5, 5, 7, 5, 5, 5, 5, 5, 7, 6, 4, 4, 5, 5, 4, 4, 4, 4, 4, 5, 4, 5, 6, 6, 6, 4, 6, 6, 3, 3, 7, 5, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 5, 8, 6, 6, 5, 7, 5, 5, 6, 5, 6, 7, 5, 4, 4, 6, 6, 6, 6, 6, 5, 3, 8, 4, 6, 5, 4, 7, 5, 5, 6, 4, 4, 4, 4, 6, 4, 3, 5, 6, 5, 6, 5, 6, 6, 7, 7, 7, 3, 6, 4, 5, 6, 5, 4, 4, 4, 6, 6, 6, 3, 7, 5, 8, 6, 6, 5, 7, 4, 7, 6, 6, 6, 7, 6, 7, 5, 5, 8, 6, 5, 7, 6, 5, 4, 5, 5, 6, 4, 6, 5, 7, 5, 5, 7, 6, 6, 7, 7, 5, 5, 5, 8, 6, 7, 4, 5, 5, 4, 7, 4, 4, 5, 5,
6, 5, 6, 5, 5, 6, 4, 5, 4, 5, 5, 5, 5, 4, 5, 7, 6, 5, 5, 7, 4, 6, 4, 4, 7, 5, 6, 7, 4, 7, 5, 6, 7, 7, 7, 7, 8, 7, 8, 7, 8, 4, 4, 6, 4, 5, 4, 4, 7, 4, 6, 5, 7, 6, 6, 6, 5, 6, 5, 6, 5, 4, 5, 5, 6, 5, 5, 5, 6, 5, 4, 7, 5, 5, 6, 4, 5, 6, 5, 7, 5, 6, 7, 6, 5, 3, 7, 4, 7, 3, 8, 7, 7, 7, 5, 7, 6, 4, 5, 3, 6, 4, 5, 6, 6, 4, 8, 4, 3, 4, 6, 6, 6, 8, 6, 7, 8, 8, 4, 7, 6, 4, 6, 5, 7, 6, 6, 6, 7, 4, 6, 6, 7, 5, 6, 6, 8, 6, 6, 4, 7, 7, 6, 6, 7, 6, 6, 7, 4, 7, 5, 4, 6, 4, 6, 7, 7, 7, 6, 8, 6, 4, 8, 8, 7, 4, 7, 8, 7, 8, 6, 6, 7, 5, 6, 8, 3, 4, 7, 6, 6, 6, 5, 4, 4, 6, 4, 5, 6, 5, 7, 4, 5, 5, 5, 5, 5, 4, 5, 4, 4, 3, 4, 4, 4, 6, 4, 5, 4, 5, 7, 5, 5, 5, 4, 5, 6, 4, 4, 4, 7, 7, 4, 4, 7, 6, 3, 5, 6, 5, 5, 8, 7, 7, 8, 8, 5, 4, 6, 6, 7, 6, 7, 6, 7, 5, 6, 5, 3, 7, 7, 5, 6, 7, 6, 6, 7, 5, 6, 6, 6, 6, 6, 5, 6, 5, 8, 7, 5, 5, 3, 5, 5, 7, 5, 5, 6, 5, 7, 6, 7, 6, 8, 4, 5, 6, 5, 7, 6, 8, 6, 7, 6, 7, 8, 7, 7, 5, 5, 4, 6, 6, 6, 6, 7, 6, 7, 6, 5, 3, 7, 6, 4, 7, 4, 5, 5, 4, 5, 4, 6, 6, 3, 5, 7, 4, 7, 3, 5, 6, 7, 5, 8, 7, 8, 7, 3, 4, 4, 6, 5,
8, 5, 5, 3, 5, 7, 5, 6, 4, 4, 6, 5,
4, 4, 6, 6, 4, 4, 5, 6, 4, 3, 7, 3, 4, 5, 5, 4, 6, 4, 6, 4, 5, 5, 5, 6, 5, 5, 3, 4, 5, 3, 4, 4, 6, 4, 4, 5, 6, 6, 4, 7, 5, 7, 6, 6, 5, 3, 7, 5, 8, 5, 6, 6, 4, 5, 5, 5, 6, 5, 4, 3, 5, 7, 4, 6, 6, 4, 6, 7, 4, 3, 6, 7, 6, 6, 7, 3, 4, 4, 6, 5, 4, 7, 6, 5, 6, 7, 7, 5, 5, 4, 6, 6, 7, 4, 4, 4, 6, 5, 5, 5, 7, 5, 5, 5, 5, 4, 4, 4, 7, 4, 4, 5, 7, 6, 6, 6, 4, 4, 5, 5, 5, 5, 5, 7, 5, 5, 4, 5, 4, 7, 5, 4, 5, 5, 5, 5, 5, 6, 3, 3, 5, 4, 4, 6, 7, 4, 5, 6, 4, 5, 7, 3, 4, 4, 6, 4, 6, 5, 5, 8, 6, 5, 6, 4, 3, 4, 6, 4, 4, 4, 3, 4, 7, 5, 6, 4, 4, 7, 6, 4, 5, 4, 4, 4, 6, 5, 8, 4, 5, 4, 5, 3, 4, 5, 6, 5, 7, 6, 4, 6, 5, 4, 7, 6, 3, 4, 4, 8, 4, 6, 3, 7, 7, 5, 7, 7, 6, 6, 6, 7, 7, 4, 7, 6, 8, 5, 8, 6, 8, 6, 7, 6, 6, 7, 7, 6, 6, 6, 5, 8, 5, 7, 6, 6, 6, 7, 7, 6, 8, 4, 6, 6, 7, 4, 6, 7, 5, 4, 5, 6, 6, 3, 4, 7, 5, 5, 5, 3, 4, 4, 7, 3, 5, 5, 4, 6, 6, 4, 4, 8, 4, 4, 7, 3, 4, 3, 6, 4, 7, 4, 3, 7, 4, 6, 4, 4, 5, 5, 4, 3, 5, 5, 6, 4, 4, 4, 8, 6, 5, 5, 5, 5, 7, 4, 3, 4, 7, 5, 4, 6, 4, 5, 5, 7, 4, 3, 5, 6, 7, 5, 4, 6, 4, 7, 6, 6, 5, 4, 7, 7, 7,
4, 4, 5, 4, 4, 5, 4, 4, 6, 4, 6, 4,
6, 4, 4, 7, 5, 4, 5, 6, 4, 4, 7, 4, 6, 4, 5, 5, 7, 6, 5, 5, 6, 6, 7, 3, 5, 6, 4, 4, 4, 5, 4, 6, 3, 6, 7, 5, 7, 6, 5, 6, 5, 6, 6, 6, 8, 4, 4, 6, 5, 8, 4, 6, 6, 7, 4, 6, 4, 7, 4, 8, 5, 5, 6, 4, 6, 6, 7, 4, 5, 5, 5, 5, 4, 7, 5, 6, 6, 8, 4, 7, 5, 4, 7, 5, 6, 7, 6, 6, 4, 7, 3, 5, 7, 6, 5, 6, 3, 6, 7, 6, 7, 5, 4, 5, 4, 7, 8, 6, 6, 5, 8, 5, 4, 5, 4, 6, 4, 8, 6, 6, 8, 5, 4, 6, 6, 7, 4, 5, 4, 6, 6, 5, 6, 6, 4, 4, 4, 8, 7, 7, 6, 5, 4, 3, 7, 7, 5, 4, 4, 4, 5, 5, 5, 7, 6, 6, 5, 4, 7, 4, 7, 6, 5, 3, 7, 6, 5, 3, 3, 4, 6, 6, 7, 7, 6, 7, 5, 5, 7, 4, 3, 5, 6, 5, 3, 4, 3, 5, 7, 4, 4, 3, 5, 6, 4, 4, 5, 7, 6, 6, 6, 5, 7, 5, 8, 5, 6, 8, 6, 7, 5, 7, 5, 6, 7, 4, 4, 4, 3, 5, 6, 6, 5, 4, 6, 4, 4, 6, 4, 5, 5, 5, 7, 5, 6, 6, 4, 6, 5, 4, 5, 4, 7, 6, 7, 5, 4, 7, 5, 6, 4, 7, 7, 3, 7, 6, 6, 6, 7, 6, 6, 3, 5, 5, 6, 8, 5, 6, 7, 5, 3, 6, 4, 5, 4, 7, 4, 6, 5, 5, 5, 6, 7, 5, 4, 6, 6, 5, 4, 6, 4, 4, 5, 5, 4, 6, 4, 4, 4, 7, 7, 8, 8, 4, 6, 7, 7, 6, 5, 8, 6, 7, 6, 7, 7, 6, 7, 5, 5, 7, 5, 8, 6, 7, 5, 7, 7, 7, 6, 7, 7, 7, 5, 8, 7, 7, 5, 7, 6, 7, 4,
4, 5, 7, 5, 5, 5, 8, 6, 7, 5, 4, 3,
6, 7, 7, 7, 7, 8, 5, 4, 4, 5, 6, 7, 4, 4, 5, 5, 4, 4, 5, 5, 4, 5, 6, 5, 5, 4, 4, 6, 5, 3, 5, 5, 4, 6, 5, 7, 6, 7, 6, 6, 7, 6, 7, 6, 6, 6, 6, 7, 6, 5, 7, 6, 4, 6, 8, 6, 6, 6, 5, 4, 6, 6, 6, 7, 6, 7, 6, 8, 6, 8, 8, 6, 6, 7, 6, 7, 6, 6, 6, 6, 3, 6, 4, 4, 4, 5, 5, 5, 5, 4, 4, 6, 4, 6, 5, 5, 4, 5, 5, 6, 6, 7, 4, 6, 4, 4, 6, 5, 5, 5, 5, 6, 4, 3, 4, 3, 6, 5, 3, 6, 7, 4, 4, 5, 6, 5, 4, 6, 4, 6, 4, 7, 7, 5, 7, 4, 3, 5, 4, 5, 7, 5, 6, 6, 7, 8, 8, 5, 5, 6, 6, 5, 3, 6, 6, 4, 6, 6, 7, 8, 4, 4, 7, 6, 4, 7, 6, 5, 8, 6, 7, 7, 6, 5, 5, 6, 5, 7, 5, 4, 5, 7, 6, 5, 5, 4, 6, 5, 4, 5, 4, 5, 8, 5, 6, 5, 7, 3, 7, 4, 4, 5, 5, 4, 6, 4, 5, 6, 7, 6, 5, 4, 5, 6, 7, 3, 4, 5, 6, 3, 5, 4, 5, 5, 4, 4, 5, 7, 5, 5, 6, 4, 6, 4, 4, 5, 5, 5, 5, 5, 6, 5, 5, 4, 5, 4, 4, 6, 6, 4, 4, 4, 5, 7, 5, 8, 5, 7, 4, 4, 5, 4, 4, 5, 4, 6, 5, 5, 5, 7, 5, 5, 7, 5, 5, 5, 6, 5, 6, 5, 4, 6, 5, 5, 7, 5, 5, 4, 5, 6, 6, 3, 6, 7, 8, 6, 7, 5, 5, 6, 5, 5, 5, 5, 4, 5, 5, 4, 4, 6, 5, 5, 5, 5, 7, 5, 5, 5, 5, 8, 6, 6, 6, 8, 7, 5, 7, 5, 7, 6, 6, 7, 4, 6, 6, 5, 7, 4, 6, 3, 5,
6, 5, 6, 7, 4, 7, 5, 8, 8, 6, 7, 7,
7, 5, 4, 5, 5, 5, 5, 4, 5, 6, 5, 6, 7, 5, 6, 5, 6, 3, 4, 6, 4, 4, 4, 6, 4, 5, 6, 4, 5, 4, 4, 3, 6, 6, 4, 4, 4, 4, 5, 4, 5, 4, 6, 5, 4, 5, 4, 7, 5, 6, 5, 5, 7, 6, 4, 5, 4, 6, 4, 4, 3, 5, 6, 5, 5, 7, 5, 7, 3, 8, 6, 5, 6, 8, 4, 6, 7, 4, 5, 3, 5, 6, 5, 7, 8, 4, 5, 7, 6, 5, 4, 3, 5, 5, 7, 6, 5, 8, 4, 5, 6, 4, 5, 4, 5, 5, 5, 5, 7, 4, 4, 6, 7, 5, 4, 5, 7, 5, 5, 3, 4, 7, 6, 4, 6, 6, 4, 6, 6, 6, 5, 4, 5, 3, 4, 7, 4, 8, 6, 7, 5, 7, 5, 4, 6, 6, 7, 7, 6, 4, 8, 7, 6, 5, 7, 6, 6, 7, 6, 4, 5, 5, 5, 4, 5, 3, 4, 6, 7, 5, 7, 6, 6, 5, 5, 6, 5, 3, 6, 5, 7, 4, 5, 7, 6, 6, 7, 5, 4, 6, 7, 4, 6, 7, 6, 7, 7, 7, 5, 4, 7, 7, 6, 7, 5, 4, 5, 6, 5, 5, 5, 5, 4, 7, 6, 4, 6, 4, 5, 4, 4, 4, 6, 4, 7, 4, 7, 4, 4, 5, 5, 4, 3, 6, 6, 4, 6, 7, 3, 7, 7, 5, 7, 4, 3, 5, 4, 5, 5, 4, 5, 4, 7, 4, 5, 4, 4, 4, 3, 6, 4, 4, 4, 6, 6, 4, 6, 4, 4, 7, 4, 5, 6, 4, 4, 4, 4, 5, 5, 5, 4, 5, 7, 5, 5, 5, 4, 4, 6, 3, 5, 5, 5, 4, 4, 3
};
DECLSPEC msg_encoder_t encoder_init (PRIVATE_AS u32 * output)
{
msg_encoder_t encoder;
encoder.index = 0;
encoder.len = 0;
encoder.bitwise_offset = 32;
encoder.output = output;
return encoder;
}
// Encodes a char into the output
DECLSPEC void encode_char (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u8 c)
{
if (encoder->bitwise_offset == 0)
{
encoder->bitwise_offset = 32;
encoder->index++;
}
encoder->bitwise_offset -= 8;
encoder->output[encoder->index] |= c << encoder->bitwise_offset;
encoder->len++;
}
// Encodes a u32 array into the output, big-endian (in order)
DECLSPEC void encode_array_be (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * array, PRIVATE_AS const u32 len, PRIVATE_AS const u32 start_index)
{
for (u32 i = start_index; i < len; i++)
{
u32 array_index = i / 4;
u32 array_offset = 24 - (i % 4) * 8;
encode_char (encoder, array[array_index] >> array_offset & 0xff);
}
}
// Encodes a u32 array into the output, little-endian (reverse order)
DECLSPEC void encode_array_le (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * array, PRIVATE_AS const u32 len, PRIVATE_AS const u32 start_index)
{
for (u32 i = start_index; i < len; i++)
{
u32 array_index = i / 4;
u32 array_offset = (i % 4) * 8;
encode_char (encoder, array[array_index] >> array_offset & 0xff);
}
}
// Encodes one of the BIP-39 seed words
DECLSPEC u32 encode_mnemonic_word (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 word_index)
{
for (int j = 0; j < BIP39_WORD_LENGTHS[word_index]; j++)
{
encode_char (encoder, BIP39_WORDS[word_index][j]);
}
}
DECLSPEC bool bip39_matches (PRIVATE_AS const char *word, PRIVATE_AS const u32 word_index)
{
for (int j = 0; j < BIP39_WORD_LENGTHS[word_index] + 1; j++)
{
if (BIP39_WORDS[word_index][j] != word[j])
return false;
}
return true;
}
// Encodes the mnemonic_phrase as specified in BIP-39
DECLSPEC void encode_mnemonic_phrase (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * words)
{
for (int i = 0; words[i] != MNEMONIC_END; i++)
{
encode_mnemonic_word (encoder, words[i]);
if (words[i + 1] != MNEMONIC_END)
{
encode_char (encoder, ' ');
}
}
}
// Compare all BIP39 words against the word to find a match, returning the index
DECLSPEC u32 bip39_from_word (PRIVATE_AS const char *word)
{
for (int i = 0; i < 2048; i++)
{
if (bip39_matches (word, i))
return i;
}
return MNEMONIC_ERROR;
}
DECLSPEC u32 bip39_byte_from_password (PRIVATE_AS const u32 * password, PRIVATE_AS const u32 index, PRIVATE_AS const u32 bits)
{
u32 index32 = index / 4;
u32 offset32 = (index % 4) * 8;
u32 bits32 = (password[index32] >> offset32 & 0xff);
// 48 is the character before '1' which is where the bin charsets begin
u32 min_bits = BIP39_BYTE_OFFSET + bits;
u32 max_bits = 2;
for (int i = 1; i < bits; i++)
{
max_bits *= 2;
}
max_bits += min_bits;
// Check whether the password contains an invalid encoded byte
if (bits32 < min_bits || bits32 >= max_bits)
{
// Could be a good place to fail except it gets triggered by autotuning
// printf("\nError: password[%d] contains invalid char '%c' dec '%d'", index, bits32, bits32);
return 0;
}
return bits32 - min_bits;
}
// Computes the last checksum word with the last_entropy bits from the password
DECLSPEC u32 bip39_checksum_word (PRIVATE_AS const u32 * wordlist, PRIVATE_AS const u32 num_words, PRIVATE_AS const u32 * password, PRIVATE_AS const u32 password_index)
{
u32 entropy[16] = { 0 };
u32 total_bits = num_words * 11;
u32 total_entroy = total_bits - total_bits % 32;
u32 checksum_bits = total_bits - total_entroy;
u32 entropy_bits = 11 - checksum_bits;
u32 last_entropy = bip39_byte_from_password (password, password_index, entropy_bits);
// Encode the 11-bits words into entropy array
u32 index = 0;
int offset = 32;
for (int i = 0; i < num_words - 1; i++)
{
offset -= 11;
if (offset < 0)
{
entropy[index] |= (wordlist[i] >> -offset);
index++;
offset += 32;
}
entropy[index] |= (wordlist[i] << offset);
}
// Encode the lasts_bits of entropy
offset -= entropy_bits;
if (offset < 0)
{
entropy[index] |= (last_entropy >> -offset);
index++;
offset += 32;
}
entropy[index] |= (last_entropy << offset);
sha256_ctx_t ctx;
sha256_init (&ctx);
sha256_update (&ctx, entropy, total_entroy / 8);
sha256_final (&ctx);
u32 checksum = ctx.h[0] >> (32 - checksum_bits);
return checksum | last_entropy << checksum_bits;
}
// Fills in BIP-39 words given a salt, pulling guesses from the password, generating the checksum
DECLSPEC u32 bip39_guess_words (PRIVATE_AS const u32 * password, PRIVATE_AS const u32 * salt, PRIVATE_AS u32 * wordlist)
{
u32 salt_index = 0;
while (salt[salt_index] != DERIVATION_END)
{
salt_index++;
}
salt_index++;
u32 password_index = 0;
for (int i = salt_index; salt[i - 1] != MNEMONIC_END; i++)
{
u32 word_index = i - salt_index;
u32 word = salt[i];
if (salt[i] == MNEMONIC_GUESS)
{
if (salt[i + 1] == MNEMONIC_END)
{
word = bip39_checksum_word (wordlist, word_index + 1, password, password_index);
password_index += 1;
}
else
{
u32 bit5 = bip39_byte_from_password (password, password_index, 5);
u32 bit6 = bip39_byte_from_password (password, password_index + 1, 6);
u32 bit11 = (bit5 << 6) | bit6;
word = bit11;
password_index += 2;
}
}
wordlist[word_index] = word;
}
return password_index;
}
/******************************************************************************
* This section contains some unit tests
******************************************************************************/
DECLSPEC bool bip39_byte_from_password_test ()
{
u32 password[2] = { 0x34333231, 0x433a3532 };
u32 max[4] = { 1, 3, 7, 15 };
for (int i = 0; i < 4; i++)
{
if (bip39_byte_from_password (password, i, i + 1) != 0)
return false;
}
for (int i = 0; i < 4; i++)
{
if (bip39_byte_from_password (password, i + 4, i + 1) != max[i])
return false;
}
return true;
}
DECLSPEC u32 bip39_checksum_word_test ()
{
u32 wordlist[11] = { 382, 566, 904, 858, 1836, 1147, 894, 1014, 1380, 1932, 744 };
u32 entropy[1] = { 0x0000005A };
entropy[0] += BIP39_BYTE_OFFSET + 7;
if (bip39_checksum_word (wordlist, 12, entropy, 0) != 1444)
return false;
u32 wordlist2[23] = { 70, 1828, 769, 514, 1812, 937, 323, 1091, 1874, 1275, 363, 1482, 1136, 1131, 1941, 1888, 672, 1584, 1493, 1015, 1090, 960, 920 };
u32 entropy2[1] = { 0x00000006 };
entropy2[0] += BIP39_BYTE_OFFSET + 3;
if (bip39_checksum_word (wordlist2, 24, entropy2, 0) != 1590)
return false;
return true;
}
DECLSPEC bool bip39_guess_words_test ()
{
// Tests the min and max of bit-11 words (0 and 2047)
u32 salt[9] = { 0, DERIVATION_END, 1, 2, 3, MNEMONIC_GUESS, MNEMONIC_GUESS, 6, MNEMONIC_END };
u32 password[1] = { 0x75543635 };
u32 expected[7] = { 1, 2, 3, 0, 2047, 6, MNEMONIC_END };
u32 words[7] = { 0 };
bip39_guess_words (password, salt, words);
for (int i = 0; i < 7; i++)
{
if (expected[i] != words[i])
return false;
}
// Tests checksum derivation
u32 salt2[14] = { DERIVATION_END, 881, 1096, 399, 1671, 966, 819, 1392, 1511, 1797, 231, 273, MNEMONIC_GUESS, MNEMONIC_END };
u32 password2[1] = { 0x00000016 };
password2[0] += BIP39_BYTE_OFFSET + 7;
u32 expected2[13] = { 881, 1096, 399, 1671, 966, 819, 1392, 1511, 1797, 231, 273, 355, MNEMONIC_END };
u32 words2[13] = { 0 };
bip39_guess_words (password2, salt2, words2);
for (int i = 0; i < 13; i++)
{
if (expected2[i] != words2[i])
return false;
}
return true;
}

@ -0,0 +1,56 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#ifndef INC_BIP39_H
#define INC_BIP39_H
// Special salt codes
#define MNEMONIC_END (0x1FFFFFFF)
#define MNEMONIC_ERROR (0x2FFFFFFF)
#define MNEMONIC_GUESS (0x3FFFFFFF)
#define DERIVATION_END (0x4FFFFFFF)
#define DERIVATION_ERROR (0x5FFFFFFF)
#define DERIVATION_HARDENED (0x80000000)
// Start of BIP-39 xbit charsets
#define BIP39_BYTE_OFFSET (48)
// Address (digest) encoding types
#define XPUB_ADDRESS_ID (0)
#define P2PKH_ADDRESS_ID (1)
#define P2SHWPKH_ADDRESS_ID (2)
#define P2WPKH_ADDRESS_ID (3)
// BIP-39 variables that store the iterations of PBKDF2-SHA512
typedef struct bip39_tmp
{
u64 ipad[8];
u64 opad[8];
u64 dgst[16];
u64 out[16];
u32 salt_index;
} bip39_tmp_t;
// Represents the current state of encoding a message
typedef struct msg_encoder
{
u32 bitwise_offset;
u32 index;
u32 *output;
u32 len;
} msg_encoder_t;
DECLSPEC msg_encoder_t encoder_init (PRIVATE_AS u32 * output);
DECLSPEC void encode_char (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u8 c);
DECLSPEC void encode_array_be (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * array, PRIVATE_AS const u32 len, PRIVATE_AS const u32 start_index);
DECLSPEC void encode_array_le (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * array, PRIVATE_AS const u32 len, PRIVATE_AS const u32 start_index);
DECLSPEC u32 encode_mnemonic_word (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 word_index);
DECLSPEC void encode_mnemonic_phrase (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * words);
DECLSPEC u32 bip39_guess_words (PRIVATE_AS const u32 * password, PRIVATE_AS const u32 * salt, PRIVATE_AS u32 * wordlist);
DECLSPEC u32 bip39_from_word (PRIVATE_AS const char *word);
#endif // INC_BIP39_H

@ -0,0 +1,634 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#define SECP256K1_TMPS_TYPE PRIVATE_AS
#ifdef KERNEL_STATIC
#include M2S(INCLUDE_PATH/inc_vendor.h)
#include M2S(INCLUDE_PATH/inc_types.h)
#include M2S(INCLUDE_PATH/inc_platform.cl)
#include M2S(INCLUDE_PATH/inc_common.cl)
#include M2S(INCLUDE_PATH/inc_rp.h)
#include M2S(INCLUDE_PATH/inc_rp.cl)
#include M2S(INCLUDE_PATH/inc_scalar.cl)
#include M2S(INCLUDE_PATH/inc_simd.cl)
#include M2S(INCLUDE_PATH/inc_hash_base58.cl)
#include M2S(INCLUDE_PATH/inc_hash_sha256.cl)
#include M2S(INCLUDE_PATH/inc_hash_ripemd160.cl)
#include M2S(INCLUDE_PATH/inc_ecc_secp256k1.cl)
#include M2S(INCLUDE_PATH/inc_hash_sha512.cl)
#include M2S(INCLUDE_PATH/inc_bip39.cl)
#endif
#define COMPARE_S M2S(INCLUDE_PATH/inc_comp_single.cl)
#define COMPARE_M M2S(INCLUDE_PATH/inc_comp_multi.cl)
/*******************************************************************************
* This section is adapted from the optimized scalar_8x32 operations from
* https://github.com/bitcoin-core/secp256k1/, MIT license
******************************************************************************/
// Represents the extended private key and chain code (each 256-bits)
typedef struct extended_key
{
// private_key is stored in reverse order for secp256k1 algorithms
u32 private_key[8];
u32 chain_code[8];
} extended_key_t;
#define SECP256K1_N_C_0 (~SECP256K1_N0 + 1)
#define SECP256K1_N_C_1 (~SECP256K1_N1)
#define SECP256K1_N_C_2 (~SECP256K1_N2)
#define SECP256K1_N_C_3 (~SECP256K1_N3)
#define SECP256K1_N_C_4 (1)
DECLSPEC int secp256k1_scalar_check_overflow (const u32 * a)
{
int yes = 0;
int no = 0;
no |= (a[7] < SECP256K1_N7); /* No need for a > check. */
no |= (a[6] < SECP256K1_N6); /* No need for a > check. */
no |= (a[5] < SECP256K1_N5); /* No need for a > check. */
no |= (a[4] < SECP256K1_N4);
yes |= (a[4] > SECP256K1_N4) & ~no;
no |= (a[3] < SECP256K1_N3) & ~yes;
yes |= (a[3] > SECP256K1_N3) & ~no;
no |= (a[2] < SECP256K1_N2) & ~yes;
yes |= (a[2] > SECP256K1_N2) & ~no;
no |= (a[1] < SECP256K1_N1) & ~yes;
yes |= (a[1] > SECP256K1_N1) & ~no;
yes |= (a[0] >= SECP256K1_N0) & ~no;
return yes;
}
DECLSPEC void secp256k1_scalar_reduce (u32 * r, u32 overflow)
{
u64 t;
t = (u64) r[0] + overflow * SECP256K1_N_C_0;
r[0] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) r[1] + overflow * SECP256K1_N_C_1;
r[1] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) r[2] + overflow * SECP256K1_N_C_2;
r[2] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) r[3] + overflow * SECP256K1_N_C_3;
r[3] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) r[4] + overflow * SECP256K1_N_C_4;
r[4] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) r[5];
r[5] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) r[6];
r[6] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) r[7];
r[7] = t & 0xFFFFFFFFUL;
}
DECLSPEC void secp256k1_scalar_add (u32 * r, const u32 * a, const u32 * b)
{
int overflow;
u64 t = (u64) a[0] + b[0];
r[0] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) a[1] + b[1];
r[1] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) a[2] + b[2];
r[2] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) a[3] + b[3];
r[3] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) a[4] + b[4];
r[4] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) a[5] + b[5];
r[5] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) a[6] + b[6];
r[6] = t & 0xFFFFFFFFUL;
t >>= 32;
t += (u64) a[7] + b[7];
r[7] = t & 0xFFFFFFFFUL;
t >>= 32;
overflow = t + secp256k1_scalar_check_overflow (r);
secp256k1_scalar_reduce (r, overflow);
}
/*******************************************************************************
* This section includes functions for encoding messages into u32 output buffers
* necessary for generating various hashes.
******************************************************************************/
// Encodes the passphrase as specified in BIP-39
DECLSPEC void encode_passphrase (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const u32 * password, PRIVATE_AS const u32 password_len, PRIVATE_AS const u32 start_index)
{
const char salt[] = "mnemonic";
for (u32 i = 0; i < 8; i++)
{
encode_char (encoder, salt[i]);
}
encode_array_le (encoder, password, password_len, start_index);
}
// Encodes the derived 33 byte compressed public key for a given private_key
DECLSPEC void encode_compressed_public_key (PRIVATE_AS msg_encoder_t * encoder, PRIVATE_AS const extended_key_t * key)
{
secp256k1_t preG;
set_precomputed_basepoint_g (&preG);
u32 x[8];
u32 y[8];
// This next line reduces performance by ~40% compared to the pure 2048 round PBKDF2-HMAC-SHA512 derivation
// Possibly could be eliminated through precalculation as in https://github.com/XopMC/CudaBrainSecp
point_mul_xy (x, y, key->private_key, &preG);
encode_char (encoder, 0x02 | (y[0] & 1));
for (int i = 0; i < 8; i++)
{
encode_array_be (encoder, &x[7 - i], 4, 0);
}
}
/*******************************************************************************
* This section runs contains some common cryptographic helper functions.
******************************************************************************/
// Run another iteration of PBKDF2-HMAC-SHA512, optimized for loops
DECLSPEC void run_sha512_hmac_iter (PRIVATE_AS u32x * w0, PRIVATE_AS u32x * w1, PRIVATE_AS u32x * w2, PRIVATE_AS u32x * w3, PRIVATE_AS u32x * w4, PRIVATE_AS u32x * w5, PRIVATE_AS u32x * w6, PRIVATE_AS u32x * w7, PRIVATE_AS u64x * ipad, PRIVATE_AS u64x * opad, PRIVATE_AS u64x * digest)
{
digest[0] = ipad[0];
digest[1] = ipad[1];
digest[2] = ipad[2];
digest[3] = ipad[3];
digest[4] = ipad[4];
digest[5] = ipad[5];
digest[6] = ipad[6];
digest[7] = ipad[7];
sha512_transform_vector (w0, w1, w2, w3, w4, w5, w6, w7, digest);
w0[0] = h32_from_64 (digest[0]);
w0[1] = l32_from_64 (digest[0]);
w0[2] = h32_from_64 (digest[1]);
w0[3] = l32_from_64 (digest[1]);
w1[0] = h32_from_64 (digest[2]);
w1[1] = l32_from_64 (digest[2]);
w1[2] = h32_from_64 (digest[3]);
w1[3] = l32_from_64 (digest[3]);
w2[0] = h32_from_64 (digest[4]);
w2[1] = l32_from_64 (digest[4]);
w2[2] = h32_from_64 (digest[5]);
w2[3] = l32_from_64 (digest[5]);
w3[0] = h32_from_64 (digest[6]);
w3[1] = l32_from_64 (digest[6]);
w3[2] = h32_from_64 (digest[7]);
w3[3] = l32_from_64 (digest[7]);
w4[0] = 0x80000000;
w4[1] = 0;
w4[2] = 0;
w4[3] = 0;
w5[0] = 0;
w5[1] = 0;
w5[2] = 0;
w5[3] = 0;
w6[0] = 0;
w6[1] = 0;
w6[2] = 0;
w6[3] = 0;
w7[0] = 0;
w7[1] = 0;
w7[2] = 0;
w7[3] = (128 + 64) * 8;
digest[0] = opad[0];
digest[1] = opad[1];
digest[2] = opad[2];
digest[3] = opad[3];
digest[4] = opad[4];
digest[5] = opad[5];
digest[6] = opad[6];
digest[7] = opad[7];
sha512_transform_vector (w0, w1, w2, w3, w4, w5, w6, w7, digest);
}
// Runs a single iteration of SHA512-HMAC to create an extended key
DECLSPEC extended_key_t run_sha512_hmac (PRIVATE_AS const u32 * key, PRIVATE_AS u32 key_bytes, PRIVATE_AS u32 * msg, PRIVATE_AS u32 msg_bytes)
{
// SHA512-HMAC requires length 32 arrays initialized to 0
u32 key_buf[32] = { 0 };
u32 msg_buf[32] = { 0 };
for (u32 i = 0; i * 4 < key_bytes; i++)
{
key_buf[i] = key[i];
}
for (u32 i = 0; i * 4 < msg_bytes; i++)
{
msg_buf[i] = msg[i];
}
// Run SHA512-HMAC algorithm on key and message
sha512_hmac_ctx_t sha512_hmac_ctx;
sha512_hmac_init (&sha512_hmac_ctx, key_buf, key_bytes);
sha512_hmac_update (&sha512_hmac_ctx, msg_buf, msg_bytes);
sha512_hmac_final (&sha512_hmac_ctx);
// Split the 512-bit result into 256-bit private_key (reversed) and 256-bit chain_code
extended_key_t extended;
for (int i = 0; i < 4; i++)
{
int j = i * 2;
extended.private_key[7 - j] = h32_from_64_S (sha512_hmac_ctx.opad.h[i]);
extended.private_key[6 - j] = l32_from_64_S (sha512_hmac_ctx.opad.h[i]);
}
for (int i = 4; i < 8; i++)
{
int j = (i - 4) * 2;
extended.chain_code[j] = h32_from_64_S (sha512_hmac_ctx.opad.h[i]);
extended.chain_code[j + 1] = l32_from_64_S (sha512_hmac_ctx.opad.h[i]);
}
return extended;
}
// Calculates HASH160 given a message, defined as RIPE160(SHA256(msg))
DECLSPEC ripemd160_ctx_t run_hash160 (PRIVATE_AS const u32 * msg, PRIVATE_AS const u32 msg_bytes)
{
// SHA256 requires length 16 arrays initialized to 0
u32 msg_buf[32] = { 0 };
for (u32 i = 0; i * 4 < msg_bytes; i++)
{
msg_buf[i] = msg[i];
}
sha256_ctx_t ctx;
sha256_init (&ctx);
sha256_update (&ctx, msg_buf, msg_bytes);
sha256_final (&ctx);
for (u32 i = 8; i < 16; i++)
ctx.h[i] = 0;
ripemd160_ctx_t rctx;
ripemd160_init (&rctx);
ripemd160_update_swap (&rctx, ctx.h, 32);
ripemd160_final (&rctx);
return rctx;
}
/*******************************************************************************
* This section specifies how to derive extended private keys from secrets
* according to the BIP-32 specification.
* https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
******************************************************************************/
// Derives the BIP32 master extended key from a 512-bit seed
DECLSPEC extended_key_t extended_key_master (PRIVATE_AS const u64 * seed)
{
u32 master_seed[16] = { 0 };
for (int i = 0; i < 8; i++)
{
int j = i * 2;
master_seed[j + 1] = l32_from_64_S (seed[i]);
master_seed[j] = h32_from_64_S (seed[i]);
}
// Encoding of "Bitcoin seed" from BIP32
u32 bitcoin_seed[3] = { 0x42697463, 0x6f696e20, 0x73656564 };
return run_sha512_hmac (bitcoin_seed, 12, master_seed, 64);
}
// Helper for tweaking the child key with the parent key
DECLSPEC void extended_key_tweak (extended_key_t * key, const extended_key_t * tweak)
{
secp256k1_scalar_add (key->private_key, key->private_key, tweak->private_key);
}
// Derives the BIP32 hardened child key
DECLSPEC extended_key_t extended_key_hardened (PRIVATE_AS const extended_key_t * parent_key, PRIVATE_AS const u32 i)
{
u32 output[32] = { 0 };
msg_encoder_t encoder = encoder_init (output);
encode_char (&encoder, 0);
for (int i = 0; i < 8; i++)
{
encode_array_be (&encoder, &parent_key->private_key[7 - i], 4, 0);
}
encode_array_be (&encoder, &i, 4, 0);
extended_key_t child_key = run_sha512_hmac (parent_key->chain_code, 32, output, encoder.len);
extended_key_tweak (&child_key, parent_key);
return child_key;
}
// Derives the BIP32 normal child key
DECLSPEC extended_key_t extended_key_normal (PRIVATE_AS const extended_key_t * parent_key, PRIVATE_AS const u32 i)
{
u32 output[32] = { 0 };
msg_encoder_t encoder = encoder_init (output);
encode_compressed_public_key (&encoder, parent_key);
encode_array_be (&encoder, &i, 4, 0);
extended_key_t child_key = run_sha512_hmac (parent_key->chain_code, 32, output, encoder.len);
extended_key_tweak (&child_key, parent_key);
return child_key;
}
// Derives the BIP32 key using the derivation path
DECLSPEC extended_key_t extended_key_derivation (PRIVATE_AS u64 * seed, PRIVATE_AS const u32 * derivation)
{
extended_key_t key = extended_key_master (seed);
for (int i = 0; derivation[i] != DERIVATION_END; i++)
{
if (derivation[i] >= DERIVATION_HARDENED)
{
key = extended_key_hardened (&key, derivation[i]);
}
else
{
key = extended_key_normal (&key, derivation[i]);
}
}
return key;
}
DECLSPEC void printf_array (const u32 * bytes, const u32 len)
{
printf ("\n'");
for (int i = 0; i <= len / 4; i++)
{
printf ("%c", bytes[i] >> 24 & 0xff);
printf ("%c", bytes[i] >> 16 & 0xff);
printf ("%c", bytes[i] >> 8 & 0xff);
printf ("%c", bytes[i] >> 0 & 0xff);
}
printf ("'");
}
// Debugging for printing out the private key followed by a ' ' then the chain code
DECLSPEC void extended_key_printf (extended_key_t * key)
{
for (int i = 0; i < 8; i++)
{
printf ("%08x", key->private_key[7 - i]);
}
printf (" ");
for (int i = 0; i < 8; i++)
{
printf ("%08x", key->chain_code[i]);
}
}
/*******************************************************************************
* This section contains the init, loop, and comp functions required by the pure
* kernel modules.
******************************************************************************/
// Initialize the PBKDF2-SHA512 with the mnemonic and passphrase as described in BIP-32
KERNEL_FQ void m28510_init (KERN_ATTR_TMPS (bip39_tmp_t))
{
const u64 gid = get_global_id (0);
if (gid >= GID_CNT)
return;
// Get the BIP39 word list
u32 pw_index = 0;
u32 words[25] = { MNEMONIC_END };
pw_index = bip39_guess_words (pws[gid].i, salt_bufs[SALT_POS_HOST].salt_buf, words);
tmps[gid].salt_index = SALT_POS_HOST;
u32 mnemonic[64] = { 0 };
msg_encoder_t mnemonic_encoder = encoder_init (mnemonic);
encode_mnemonic_phrase (&mnemonic_encoder, words);
u32 passphrase[64] = { 0 };
msg_encoder_t passphrase_encoder = encoder_init (passphrase);
encode_passphrase (&passphrase_encoder, pws[gid].i, pws[gid].pw_len, pw_index);
sha512_hmac_ctx_t sha512_hmac_ctx;
sha512_hmac_init (&sha512_hmac_ctx, mnemonic, mnemonic_encoder.len);
for (int i = 0; i < 8; i++)
{
tmps[gid].ipad[i] = sha512_hmac_ctx.ipad.h[i];
tmps[gid].opad[i] = sha512_hmac_ctx.opad.h[i];
}
sha512_hmac_update (&sha512_hmac_ctx, passphrase, passphrase_encoder.len);
u32 w0[4] = { 1, 0, 0, 0 };
u32 w1[4] = { 0 };
u32 w2[4] = { 0 };
u32 w3[4] = { 0 };
u32 w4[4] = { 0 };
u32 w5[4] = { 0 };
u32 w6[4] = { 0 };
u32 w7[4] = { 0 };
sha512_hmac_update_128 (&sha512_hmac_ctx, w0, w1, w2, w3, w4, w5, w6, w7, 4);
sha512_hmac_final (&sha512_hmac_ctx);
for (int i = 0; i < 8; i++)
{
tmps[gid].dgst[i] = sha512_hmac_ctx.opad.h[i];
tmps[gid].out[i] = sha512_hmac_ctx.opad.h[i];
}
}
// Identical to most modules that run PBKDF2-HMAC-SHA512 iterations
KERNEL_FQ void m28510_loop (KERN_ATTR_TMPS (bip39_tmp_t))
{
const u64 gid = get_global_id (0);
if ((gid * VECT_SIZE) >= GID_CNT)
return;
u64x ipad[8];
u64x opad[8];
for (u32 i = 0; i < 8; i++)
{
ipad[i] = pack64v (tmps, ipad, gid, i);
opad[i] = pack64v (tmps, opad, gid, i);
}
u64x dgst[8];
u64x out[8];
for (u32 i = 0; i < 8; i++)
{
dgst[i] = pack64v (tmps, dgst, gid, i);
out[i] = pack64v (tmps, out, gid, i);
}
for (u32 j = 0; j < LOOP_CNT; j++)
{
u32x w0[4];
u32x w1[4];
u32x w2[4];
u32x w3[4];
u32x w4[4];
u32x w5[4];
u32x w6[4];
u32x w7[4];
w0[0] = h32_from_64 (dgst[0]);
w0[1] = l32_from_64 (dgst[0]);
w0[2] = h32_from_64 (dgst[1]);
w0[3] = l32_from_64 (dgst[1]);
w1[0] = h32_from_64 (dgst[2]);
w1[1] = l32_from_64 (dgst[2]);
w1[2] = h32_from_64 (dgst[3]);
w1[3] = l32_from_64 (dgst[3]);
w2[0] = h32_from_64 (dgst[4]);
w2[1] = l32_from_64 (dgst[4]);
w2[2] = h32_from_64 (dgst[5]);
w2[3] = l32_from_64 (dgst[5]);
w3[0] = h32_from_64 (dgst[6]);
w3[1] = l32_from_64 (dgst[6]);
w3[2] = h32_from_64 (dgst[7]);
w3[3] = l32_from_64 (dgst[7]);
w4[0] = 0x80000000;
w4[1] = 0;
w4[2] = 0;
w4[3] = 0;
w5[0] = 0;
w5[1] = 0;
w5[2] = 0;
w5[3] = 0;
w6[0] = 0;
w6[1] = 0;
w6[2] = 0;
w6[3] = 0;
w7[0] = 0;
w7[1] = 0;
w7[2] = 0;
w7[3] = (128 + 64) * 8;
run_sha512_hmac_iter (w0, w1, w2, w3, w4, w5, w6, w7, ipad, opad, dgst);
for (u32 i = 0; i < 8; i++)
{
out[i] ^= dgst[i];
}
}
for (u32 i = 0; i < 8; i++)
{
unpack64v (tmps, dgst, gid, i, dgst[i]);
unpack64v (tmps, out, gid, i, out[i]);
}
}
// Final digest comparison depends on the address type
KERNEL_FQ void m28510_comp (KERN_ATTR_TMPS (bip39_tmp_t))
{
const u64 gid = get_global_id (0);
if (gid >= GID_CNT)
return;
// Get hardened 512-bit seed and useful salt values
u64 *seed = tmps[gid].out;
const u32 address_id = salt_bufs[SALT_POS_HOST].salt_buf[0];
const u32 *derivation_path = &salt_bufs[SALT_POS_HOST].salt_buf[1];
// 128-bits that get compared with the digest bits
u32 r0;
u32 r1;
u32 r2;
u32 r3;
if (address_id == XPUB_ADDRESS_ID)
{
extended_key_t master_key = extended_key_master (seed);
r0 = hc_swap32_S (master_key.chain_code[0]);
r1 = hc_swap32_S (master_key.chain_code[1]);
r2 = hc_swap32_S (master_key.chain_code[2]);
r3 = hc_swap32_S (master_key.chain_code[3]);
}
else if (address_id == P2PKH_ADDRESS_ID || address_id == P2WPKH_ADDRESS_ID)
{
const extended_key_t key = extended_key_derivation (seed, derivation_path);
u32 pubkey[9] = { 0 };
msg_encoder_t pubkey_encoder = encoder_init (pubkey);
encode_compressed_public_key (&pubkey_encoder, &key);
ripemd160_ctx_t hash160 = run_hash160 (pubkey, pubkey_encoder.len);
r0 = hash160.h[0];
r1 = hash160.h[1];
r2 = hash160.h[2];
r3 = hash160.h[3];
}
else if (address_id == P2SHWPKH_ADDRESS_ID)
{
const extended_key_t key = extended_key_derivation (seed, derivation_path);
u32 pubkey[9] = { 0 };
msg_encoder_t pubkey_encoder = encoder_init (pubkey);
encode_compressed_public_key (&pubkey_encoder, &key);
ripemd160_ctx_t hash160 = run_hash160 (pubkey, pubkey_encoder.len);
u32 script[9] = { 0 };
msg_encoder_t script_encoder = encoder_init (script);
encode_char (&script_encoder, 0x0);
encode_char (&script_encoder, 0x14);
encode_array_le (&script_encoder, hash160.h, 20, 0);
ripemd160_ctx_t script_hash160 = run_hash160 (script, script_encoder.len);
r0 = script_hash160.h[0];
r1 = script_hash160.h[1];
r2 = script_hash160.h[2];
r3 = script_hash160.h[3];
}
#define il_pos 0
#ifdef KERNEL_STATIC
#include COMPARE_M
#endif
}

@ -0,0 +1 @@
456789:;<=>?@ABC

@ -0,0 +1 @@
56789:;<=>?@ABCDEFGHIJKLMNOPQRST

@ -0,0 +1 @@
6789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstu

@ -0,0 +1 @@
789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€亗儎厗噲墛媽崕彁憭摂晼棙櫄洔潪煚、¥ウЖ┆<D096><E29486><EFBFBD>辈炒刀

@ -0,0 +1,14 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#ifndef HC_EMU_INC_BIP39_H
#define HC_EMU_INC_BIP39_H
#include "emu_general.h"
#include "inc_vendor.h"
#include "inc_bip39.h"
#endif // HC_EMU_INC_BIP39_H

@ -405,7 +405,7 @@ EMU_OBJS_ALL := emu_general emu_inc_common emu_inc_platform emu_inc_s
EMU_OBJS_ALL += emu_inc_rp emu_inc_rp_optimized
EMU_OBJS_ALL += emu_inc_hash_md4 emu_inc_hash_md5 emu_inc_hash_ripemd160 emu_inc_hash_sha1 emu_inc_hash_sha256 emu_inc_hash_sha384 emu_inc_hash_sha512 emu_inc_hash_streebog256 emu_inc_hash_streebog512 emu_inc_ecc_secp256k1 emu_inc_bignum_operations
EMU_OBJS_ALL += emu_inc_cipher_aes emu_inc_cipher_camellia emu_inc_cipher_des emu_inc_cipher_kuznyechik emu_inc_cipher_serpent emu_inc_cipher_twofish
EMU_OBJS_ALL += emu_inc_hash_base58
EMU_OBJS_ALL += emu_inc_hash_base58 emu_inc_bip39
OBJS_ALL := affinity autotune backend benchmark bitmap bitops combinator common convert cpt cpu_crc32 debugfile dictstat dispatch dynloader event ext_ADL ext_cuda ext_hip ext_nvapi ext_nvml ext_nvrtc ext_hiprtc ext_OpenCL ext_sysfs_amdgpu ext_sysfs_cpu ext_iokit ext_lzma filehandling folder hashcat hashes hlfmt hwmon induct interface keyboard_layout locking logfile loopback memory monitor mpsp outfile_check outfile pidfile potfile restore rp rp_cpu selftest slow_candidates shared status stdout straight terminal thread timer tuningdb usage user_options wordlist $(EMU_OBJS_ALL)

@ -0,0 +1,11 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#include "common.h"
#include "types.h"
#include "emu_general.h"
#include "inc_bip39.cl"

@ -0,0 +1,747 @@
/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#include "common.h"
#include "types.h"
#include "modules.h"
#include "bitops.h"
#include "convert.h"
#include "shared.h"
#include "memory.h"
#include "bitops.h"
#include "emu_inc_hash_base58.h"
#include "emu_inc_bip39.h"
static const char SEPARATOR = ':';
static const u32 ATTACK_EXEC = ATTACK_EXEC_OUTSIDE_KERNEL;
static const u32 DGST_POS0 = 0;
static const u32 DGST_POS1 = 1;
static const u32 DGST_POS2 = 2;
static const u32 DGST_POS3 = 3;
static const u32 DGST_SIZE = DGST_SIZE_4_32;
static const u32 HASH_CATEGORY = HASH_CATEGORY_CRYPTOCURRENCY_WALLET;
static const char *HASH_NAME = "Bitcoin seed words and passphrase";
static const u64 KERN_TYPE = 28510;
static const u32 OPTI_TYPE = OPTI_TYPE_ZERO_BYTE | OPTI_TYPE_USES_BITS_64 | OPTI_TYPE_SLOW_HASH_SIMD_LOOP;
static const u64 OPTS_TYPE = OPTS_TYPE_COPY_TMPS;
static const u32 SALT_TYPE = SALT_TYPE_EMBEDDED;
static const char *ST_PASS = "hashcat";
static const char *ST_HASH = "P2PKH:m/44h/0h/0h/0/0:balcony catalog winner letter alley this:1B2hrNm7JGW6Wenf8oMvjWB3DPT9H9vAJ9";
typedef struct address_base58
{
u32 digest_len;
u32 address_len;
u32 prefix_len;
u8 prefix[];
} address_base58_t;
static const address_base58_t XPUB_ADDRESS = { 82, 111, 13, {0x04, 0x88, 0xb2, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF} };
static const address_base58_t P2PKH_ADDRESS = { 25, 34, 1, {0x0} };
static const address_base58_t P2SHWPKH_ADDRESS = { 25, 34, 1, {0x05} };
/******************************************************************************
* This section provides utilities for decoding the hash value.
* We need to parse out the address type, derivation path, mnemonic phrase,
* as the salt.
******************************************************************************/
// Output the next index from the derivation_path and increment the derivation_path pointer
DECLSPEC u32 decode_derivation_path (PRIVATE_AS u8 ** derivation_path, PRIVATE_AS const char end_char)
{
char word[9] = { 0 };
u32 hardened = 0;
if (derivation_path[0][0] == end_char)
return DERIVATION_END;
for (int i = 0; i < 9; i++)
{
// Parse out the digits or whether child is hardened
if (derivation_path[0][0] == 'h' || derivation_path[0][0] == '\'')
{
hardened = DERIVATION_HARDENED;
}
else if (derivation_path[0][0] == '/')
{
// Ends one child of the derivation path
*derivation_path += 1;
return hc_strtoul (word, 0, 10) | hardened;
}
else if (derivation_path[0][0] == end_char)
{
// Ends but don't advance derivation_path pointer so we'll return DERIVATION_END next
return hc_strtoul (word, 0, 10) | hardened;
}
else if (derivation_path[0][0] <= '9' && derivation_path[0][0] >= '0')
{
word[i] = derivation_path[0][0];
}
else
{
return DERIVATION_ERROR;
}
*derivation_path += 1;
}
// Derivation path is too long
return DERIVATION_ERROR;
}
// Output the next word index from the mnemonic_phrase and increment the mnemonic_phrase pointer
DECLSPEC u32 decode_mnemonic_phrase (PRIVATE_AS u8 ** mnemonic_phrase, PRIVATE_AS const char end_char)
{
char word[9] = { 0 };
if (mnemonic_phrase[0][0] == end_char)
return MNEMONIC_END;
for (int i = 0; i < 9; i++)
{
word[i] = mnemonic_phrase[0][0];
*mnemonic_phrase += 1;
if (mnemonic_phrase[0][0] == end_char)
break;
if (mnemonic_phrase[0][0] == ' ')
{
*mnemonic_phrase += 1;
break;
}
}
if (strncmp (word, "?", 1) == 0)
return MNEMONIC_GUESS;
return bip39_from_word (word);
}
// Helper for base58 decoding into the digest, assumes prefix ends in 0xFF
static bool decode_base58 (const address_base58_t * type, const char *address, u8 * digest)
{
u32 len = type->digest_len;
u32 prefix_len = type->prefix_len;
u8 decoded_address[128] = { 0 };
if (!b58dec (decoded_address, &len, (u8 *) address, type->address_len))
return false;
if (!b58check (decoded_address, len))
return false;
if (len != type->digest_len)
return false;
// skip encoding the known prefix (not useful for digest entropy)
for (u32 i = 0; i < prefix_len; i++)
{
if (type->prefix[i] != decoded_address[i])
return false;
}
for (u32 i = 0; i < type->digest_len - prefix_len; i++)
{
digest[i] = decoded_address[i + prefix_len];
}
return true;
}
// Helper for base58 encoding into the digest
static void encode_base58 (const address_base58_t * type, u8 * address, const u8 * digest)
{
u32 len = 0xFFFFFFFF;
u32 prefix_len = type->prefix_len;
u8 decoded_address[128] = { 0 };
// build the address using the known prefix
for (u32 i = 0; i < prefix_len; i++)
{
decoded_address[i] = type->prefix[i];
}
for (u32 i = 0; i < type->digest_len - prefix_len; i++)
{
decoded_address[prefix_len + i] = digest[i];
}
b58enc (address, &len, decoded_address, type->digest_len);
// Sometimes encoding adds unnecessary zeros to the prefix
u32 offset = len - type->address_len - 1;
for (u32 i = 0; i < type->address_len; i++)
{
address[i] = address[i + offset];
}
address[type->address_len] = 0x0;
}
/******************************************************************************
* This section provides utilities for bech32 encoding/decoding necessary for
* newer bitcoin address types. Could be refactored for use in other bitcoin
* modules.
*
* Adapted from https://github.com/sipa/bech32/tree/master/ref/c
* Copyright (c) 2017, 2021 Pieter Wuille, MIT license
******************************************************************************/
typedef enum
{
BECH32_ENCODING_NONE,
BECH32_ENCODING_BECH32,
BECH32_ENCODING_BECH32M
} bech32_encoding;
static u32 bech32_polymod_step (uint32_t pre)
{
u8 b = pre >> 25;
return ((pre & 0x1FFFFFF) << 5) ^ (-((b >> 0) & 1) & 0x3b6a57b2UL) ^ (-((b >> 1) & 1) & 0x26508e6dUL) ^ (-((b >> 2) & 1) & 0x1ea119faUL) ^ (-((b >> 3) & 1) & 0x3d4233ddUL) ^ (-((b >> 4) & 1) & 0x2a1462b3UL);
}
static u32 bech32_final_constant (bech32_encoding enc)
{
if (enc == BECH32_ENCODING_BECH32)
return 1;
if (enc == BECH32_ENCODING_BECH32M)
return 0x2bc830a3;
return 0;
}
static const char *charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
static const int8_t charset_rev[128] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
};
int bech32_encode (char *output, const char *hrp, const uint8_t * data, size_t data_len, bech32_encoding enc)
{
uint32_t chk = 1;
size_t i = 0;
while (hrp[i] != 0)
{
int ch = hrp[i];
if (ch < 33 || ch > 126)
{
return 0;
}
if (ch >= 'A' && ch <= 'Z')
return 0;
chk = bech32_polymod_step (chk) ^ (ch >> 5);
++i;
}
if (i + 7 + data_len > 90)
return 0;
chk = bech32_polymod_step (chk);
while (*hrp != 0)
{
chk = bech32_polymod_step (chk) ^ (*hrp & 0x1f);
*(output++) = *(hrp++);
}
*(output++) = '1';
for (i = 0; i < data_len; ++i)
{
if (*data >> 5)
return 0;
chk = bech32_polymod_step (chk) ^ (*data);
*(output++) = charset[*(data++)];
}
for (i = 0; i < 6; ++i)
{
chk = bech32_polymod_step (chk);
}
chk ^= bech32_final_constant (enc);
for (i = 0; i < 6; ++i)
{
*(output++) = charset[(chk >> ((5 - i) * 5)) & 0x1f];
}
*output = 0;
return 1;
}
bech32_encoding bech32_decode (char *hrp, uint8_t * data, size_t *data_len, const char *input)
{
uint32_t chk = 1;
size_t i;
size_t input_len = strlen (input);
size_t hrp_len;
int have_lower = 0, have_upper = 0;
if (input_len < 8 || input_len > 90)
{
return BECH32_ENCODING_NONE;
}
*data_len = 0;
while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1')
{
++(*data_len);
}
hrp_len = input_len - (1 + *data_len);
if (1 + *data_len >= input_len || *data_len < 6)
{
return BECH32_ENCODING_NONE;
}
*(data_len) -= 6;
for (i = 0; i < hrp_len; ++i)
{
int ch = input[i];
if (ch < 33 || ch > 126)
{
return BECH32_ENCODING_NONE;
}
if (ch >= 'a' && ch <= 'z')
{
have_lower = 1;
}
else if (ch >= 'A' && ch <= 'Z')
{
have_upper = 1;
ch = (ch - 'A') + 'a';
}
hrp[i] = ch;
chk = bech32_polymod_step (chk) ^ (ch >> 5);
}
hrp[i] = 0;
chk = bech32_polymod_step (chk);
for (i = 0; i < hrp_len; ++i)
{
chk = bech32_polymod_step (chk) ^ (input[i] & 0x1f);
}
++i;
while (i < input_len)
{
int v = (input[i] & 0x80) ? -1 : charset_rev[(int) input[i]];
if (input[i] >= 'a' && input[i] <= 'z')
have_lower = 1;
if (input[i] >= 'A' && input[i] <= 'Z')
have_upper = 1;
if (v == -1)
{
return BECH32_ENCODING_NONE;
}
chk = bech32_polymod_step (chk) ^ v;
if (i + 6 < input_len)
{
data[i - (1 + hrp_len)] = v;
}
++i;
}
if (have_lower && have_upper)
{
return BECH32_ENCODING_NONE;
}
if (chk == bech32_final_constant (BECH32_ENCODING_BECH32))
{
return BECH32_ENCODING_BECH32;
}
else if (chk == bech32_final_constant (BECH32_ENCODING_BECH32M))
{
return BECH32_ENCODING_BECH32M;
}
else
{
return BECH32_ENCODING_NONE;
}
}
static int convert_bits (uint8_t * out, size_t *outlen, int outbits, const uint8_t * in, size_t inlen, int inbits, int pad)
{
uint32_t val = 0;
int bits = 0;
uint32_t maxv = (((uint32_t) 1) << outbits) - 1;
while (inlen--)
{
val = (val << inbits) | *(in++);
bits += inbits;
while (bits >= outbits)
{
bits -= outbits;
out[(*outlen)++] = (val >> bits) & maxv;
}
}
if (pad)
{
if (bits)
{
out[(*outlen)++] = (val << (outbits - bits)) & maxv;
}
}
else if (((val << (outbits - bits)) & maxv) || bits >= inbits)
{
return 0;
}
return 1;
}
int segwit_addr_encode (char *output, const char *hrp, int witver, const uint8_t * witprog, size_t witprog_len)
{
uint8_t data[65];
size_t datalen = 0;
bech32_encoding enc = BECH32_ENCODING_BECH32;
if (witver > 16)
return 0;
if (witver == 0 && witprog_len != 20 && witprog_len != 32)
return 0;
if (witprog_len < 2 || witprog_len > 40)
return 0;
if (witver > 0)
enc = BECH32_ENCODING_BECH32M;
data[0] = witver;
convert_bits (data + 1, &datalen, 5, witprog, witprog_len, 8, 1);
++datalen;
return bech32_encode (output, hrp, data, datalen, enc);
}
int segwit_addr_decode (int *witver, uint8_t * witdata, size_t *witdata_len, const char *hrp, const char *addr)
{
uint8_t data[84];
char hrp_actual[84];
size_t data_len;
bech32_encoding enc = bech32_decode (hrp_actual, data, &data_len, addr);
if (enc == BECH32_ENCODING_NONE)
return 0;
if (data_len == 0 || data_len > 65)
return 0;
if (strncmp (hrp, hrp_actual, 84) != 0)
return 0;
if (data[0] > 16)
return 0;
if (data[0] == 0 && enc != BECH32_ENCODING_BECH32)
return 0;
if (data[0] > 0 && enc != BECH32_ENCODING_BECH32M)
return 0;
*witdata_len = 0;
if (!convert_bits (witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0))
return 0;
if (*witdata_len < 2 || *witdata_len > 40)
return 0;
if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32)
return 0;
*witver = data[0];
return 1;
}
/******************************************************************************
* This section contains the typical module functions found in most modules
* such as the encoding and decoding of the hash value to the digest.
******************************************************************************/
u32 module_attack_exec (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return ATTACK_EXEC;
}
u32 module_dgst_pos0 (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return DGST_POS0;
}
u32 module_dgst_pos1 (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return DGST_POS1;
}
u32 module_dgst_pos2 (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return DGST_POS2;
}
u32 module_dgst_pos3 (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return DGST_POS3;
}
u32 module_dgst_size (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return DGST_SIZE;
}
u32 module_hash_category (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return HASH_CATEGORY;
}
const char *module_hash_name (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return HASH_NAME;
}
u64 module_kern_type (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return KERN_TYPE;
}
u32 module_opti_type (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return OPTI_TYPE;
}
u64 module_opts_type (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return OPTS_TYPE;
}
u32 module_salt_type (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return SALT_TYPE;
}
const char *module_st_hash (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return ST_HASH;
}
const char *module_st_pass (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return ST_PASS;
}
u64 module_tmp_size (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const user_options_t * user_options, MAYBE_UNUSED const user_options_extra_t * user_options_extra)
{
return (const u64) sizeof (bip39_tmp_t);
}
int module_hash_decode (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED void *digest_buf, MAYBE_UNUSED salt_t * salt, MAYBE_UNUSED void *esalt_buf, MAYBE_UNUSED void *hook_salt_buf, MAYBE_UNUSED hashinfo_t * hash_info, const char *line_buf, MAYBE_UNUSED const int line_len)
{
u8 *digest = (u8 *) digest_buf;
hc_token_t token;
memset (&token, 0, sizeof (hc_token_t));
token.token_cnt = 4;
token.sep[0] = SEPARATOR;
token.sep[1] = SEPARATOR;
token.sep[2] = SEPARATOR;
token.sep[3] = SEPARATOR;
const int rc_tokenizer = input_tokenizer ((const u8 *) line_buf, line_len, &token);
if (rc_tokenizer != PARSER_OK)
return (rc_tokenizer);
const char *address_type = (char *) token.buf[0];
const char *derivation_path = (char *) token.buf[1];
const char *mnemonic_phrase = (char *) token.buf[2];
const char *address = (char *) token.buf[3];
// Store address type in salt[0] and convert into digest
if (strncmp (address_type, "XPUB", token.len[0]) == 0)
{
salt->salt_buf[0] = XPUB_ADDRESS_ID;
if (!decode_base58 (&XPUB_ADDRESS, address, digest))
return PARSER_HASH_ENCODING;
}
else if (strncmp (address_type, "P2PKH", token.len[0]) == 0)
{
salt->salt_buf[0] = P2PKH_ADDRESS_ID;
if (!decode_base58 (&P2PKH_ADDRESS, address, digest))
return PARSER_HASH_ENCODING;
}
else if (strncmp (address_type, "P2PKH-P2WPKH", token.len[0]) == 0)
{
salt->salt_buf[0] = P2SHWPKH_ADDRESS_ID;
if (!decode_base58 (&P2SHWPKH_ADDRESS, address, digest))
return PARSER_HASH_ENCODING;
}
else if (strncmp (address_type, "P2PWPKH", token.len[0]) == 0)
{
salt->salt_buf[0] = P2WPKH_ADDRESS_ID;
int ver;
size_t witprog_len;
if (!segwit_addr_decode (&ver, digest, &witprog_len, "bc", address))
return PARSER_HASH_ENCODING;
if (ver != 0)
return PARSER_HASH_ENCODING;
if (witprog_len != 20)
return PARSER_HASH_ENCODING;
}
else
{
return PARSER_SIGNATURE_UNMATCHED;
}
u32 salt_index = 1;
// Store the derivation path in the salt
if (strncmp (derivation_path, "m/", 2) != 0)
return PARSER_SALT_VALUE;
derivation_path += 2;
for (u32 derivation = 0; derivation != DERIVATION_END; salt_index++)
{
derivation = decode_derivation_path ((u8 **) & derivation_path, SEPARATOR);
if (derivation == DERIVATION_ERROR)
return PARSER_SALT_VALUE;
salt->salt_buf[salt_index] = derivation;
}
// Store the mnemonic words in the salt
for (u32 mnemonic = 0; mnemonic != MNEMONIC_END; salt_index++)
{
mnemonic = decode_mnemonic_phrase ((u8 **) & mnemonic_phrase, SEPARATOR);
if (mnemonic == MNEMONIC_ERROR)
return PARSER_SALT_ENCODING;
salt->salt_buf[salt_index] = mnemonic;
}
// BIP39 requires 2048 iterations of PBKDF2-HMAC-SHA512
salt->salt_iter = 2047;
salt->salt_len = salt_index + 1;
return (PARSER_OK);
}
int module_hash_encode (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const void *digest_buf, MAYBE_UNUSED const salt_t * salt, MAYBE_UNUSED const void *esalt_buf, MAYBE_UNUSED const void *hook_salt_buf, MAYBE_UNUSED const hashinfo_t * hash_info, char *line_buf, MAYBE_UNUSED const int line_size)
{
const u8 *digest = (const u8 *) digest_buf;
u8 address[128];
if (salt->salt_buf[0] == XPUB_ADDRESS_ID)
{
encode_base58 (&XPUB_ADDRESS, address, digest);
}
else if (salt->salt_buf[0] == P2PKH_ADDRESS_ID)
{
encode_base58 (&P2PKH_ADDRESS, address, digest);
}
else if (salt->salt_buf[0] == P2SHWPKH_ADDRESS_ID)
{
encode_base58 (&P2SHWPKH_ADDRESS, address, digest);
}
else if (salt->salt_buf[0] == P2WPKH_ADDRESS_ID)
{
segwit_addr_encode ((char *) address, "bc", 0, digest, 20);
}
return snprintf (line_buf, line_size, "%s", address);
}
int module_build_plain_postprocess (MAYBE_UNUSED const hashconfig_t * hashconfig, MAYBE_UNUSED const hashes_t * hashes, MAYBE_UNUSED const void *tmps, const u32 * src_buf, MAYBE_UNUSED const size_t src_sz, MAYBE_UNUSED const int src_len, u32 * dst_buf, MAYBE_UNUSED const size_t dst_sz)
{
u32 buf[32] = { 0 };
msg_encoder_t encoder = encoder_init (buf);
bip39_tmp_t *tmp = (bip39_tmp_t *) tmps;
const u32 *salt = hashes->salts_buf[tmp->salt_index].salt_buf;
u32 words[32] = { 0 };
u32 pw_index = bip39_guess_words (src_buf, salt, words);
u32 salt_index = 0;
while (salt[salt_index] != DERIVATION_END)
{
salt_index++;
}
salt_index++;
for (u32 i = salt_index; salt[salt_index] != MNEMONIC_END; salt_index++)
{
if (salt[salt_index] == MNEMONIC_GUESS)
{
encode_mnemonic_word (&encoder, words[salt_index - i]);
encode_char (&encoder, ',');
}
}
encode_array_le (&encoder, src_buf, src_len, pw_index);
for (u32 i = 0; i <= encoder.len / 4; i++)
{
dst_buf[i] = byte_swap_32 (buf[i]);
}
return encoder.len;
}
void module_init (module_ctx_t * module_ctx)
{
module_ctx->module_context_size = MODULE_CONTEXT_SIZE_CURRENT;
module_ctx->module_interface_version = MODULE_INTERFACE_VERSION_CURRENT;
module_ctx->module_attack_exec = module_attack_exec;
module_ctx->module_benchmark_esalt = MODULE_DEFAULT;
module_ctx->module_benchmark_hook_salt = MODULE_DEFAULT;
module_ctx->module_benchmark_mask = MODULE_DEFAULT;
module_ctx->module_benchmark_charset = MODULE_DEFAULT;
module_ctx->module_benchmark_salt = MODULE_DEFAULT;
module_ctx->module_build_plain_postprocess = module_build_plain_postprocess;
module_ctx->module_deep_comp_kernel = MODULE_DEFAULT;
module_ctx->module_deprecated_notice = MODULE_DEFAULT;
module_ctx->module_dgst_pos0 = module_dgst_pos0;
module_ctx->module_dgst_pos1 = module_dgst_pos1;
module_ctx->module_dgst_pos2 = module_dgst_pos2;
module_ctx->module_dgst_pos3 = module_dgst_pos3;
module_ctx->module_dgst_size = module_dgst_size;
module_ctx->module_dictstat_disable = MODULE_DEFAULT;
module_ctx->module_esalt_size = MODULE_DEFAULT;
module_ctx->module_extra_buffer_size = MODULE_DEFAULT;
module_ctx->module_extra_tmp_size = MODULE_DEFAULT;
module_ctx->module_extra_tuningdb_block = MODULE_DEFAULT;
module_ctx->module_forced_outfile_format = MODULE_DEFAULT;
module_ctx->module_hash_binary_count = MODULE_DEFAULT;
module_ctx->module_hash_binary_parse = MODULE_DEFAULT;
module_ctx->module_hash_binary_save = MODULE_DEFAULT;
module_ctx->module_hash_decode_postprocess = MODULE_DEFAULT;
module_ctx->module_hash_decode_potfile = MODULE_DEFAULT;
module_ctx->module_hash_decode_zero_hash = MODULE_DEFAULT;
module_ctx->module_hash_decode = module_hash_decode;
module_ctx->module_hash_encode_status = MODULE_DEFAULT;
module_ctx->module_hash_encode_potfile = MODULE_DEFAULT;
module_ctx->module_hash_encode = module_hash_encode;
module_ctx->module_hash_init_selftest = MODULE_DEFAULT;
module_ctx->module_hash_mode = MODULE_DEFAULT;
module_ctx->module_hash_category = module_hash_category;
module_ctx->module_hash_name = module_hash_name;
module_ctx->module_hashes_count_min = MODULE_DEFAULT;
module_ctx->module_hashes_count_max = MODULE_DEFAULT;
module_ctx->module_hlfmt_disable = MODULE_DEFAULT;
module_ctx->module_hook_extra_param_size = MODULE_DEFAULT;
module_ctx->module_hook_extra_param_init = MODULE_DEFAULT;
module_ctx->module_hook_extra_param_term = MODULE_DEFAULT;
module_ctx->module_hook12 = MODULE_DEFAULT;
module_ctx->module_hook23 = MODULE_DEFAULT;
module_ctx->module_hook_salt_size = MODULE_DEFAULT;
module_ctx->module_hook_size = MODULE_DEFAULT;
module_ctx->module_jit_build_options = MODULE_DEFAULT;
module_ctx->module_jit_cache_disable = MODULE_DEFAULT;
module_ctx->module_kernel_accel_max = MODULE_DEFAULT;
module_ctx->module_kernel_accel_min = MODULE_DEFAULT;
module_ctx->module_kernel_loops_max = MODULE_DEFAULT;
module_ctx->module_kernel_loops_min = MODULE_DEFAULT;
module_ctx->module_kernel_threads_max = MODULE_DEFAULT;
module_ctx->module_kernel_threads_min = MODULE_DEFAULT;
module_ctx->module_kern_type = module_kern_type;
module_ctx->module_kern_type_dynamic = MODULE_DEFAULT;
module_ctx->module_opti_type = module_opti_type;
module_ctx->module_opts_type = module_opts_type;
module_ctx->module_outfile_check_disable = MODULE_DEFAULT;
module_ctx->module_outfile_check_nocomp = MODULE_DEFAULT;
module_ctx->module_potfile_custom_check = MODULE_DEFAULT;
module_ctx->module_potfile_disable = MODULE_DEFAULT;
module_ctx->module_potfile_keep_all_hashes = MODULE_DEFAULT;
module_ctx->module_pwdump_column = MODULE_DEFAULT;
module_ctx->module_pw_max = MODULE_DEFAULT;
module_ctx->module_pw_min = MODULE_DEFAULT;
module_ctx->module_salt_max = MODULE_DEFAULT;
module_ctx->module_salt_min = MODULE_DEFAULT;
module_ctx->module_salt_type = module_salt_type;
module_ctx->module_separator = MODULE_DEFAULT;
module_ctx->module_st_hash = module_st_hash;
module_ctx->module_st_pass = module_st_pass;
module_ctx->module_tmp_size = module_tmp_size;
module_ctx->module_unstable_warning = MODULE_DEFAULT;
module_ctx->module_warmup_disable = MODULE_DEFAULT;
}

@ -0,0 +1,45 @@
# Runs tests of the BIP39 directly against hashcat
set -e
TEST1="XPUB:m/:coral dice harvest:xpub661MyMwAqRbcFaizXLqdLrqBkUJo4JyyXYNucU2hWQBDfhmCd3TL7USdpjhUddedvEiSo31BRg9QB4a5PNKcuQRWT6DA2YveGA2tzsqZQwg"
PASS1="hashca?4"
TEST2="P2PKH:m/44h/0h/0h/0/0:balcony catalog winner letter alley this:1B2hrNm7JGW6Wenf8oMvjWB3DPT9H9vAJ9"
PASS2="hashca?4"
TEST3="P2PKH-P2WPKH:m/49h/0h/0h/0/1:cage keep stone swarm open race toward state subway dutch extra short purpose interest enough idle found guilt will salt mixed boil heavy thing:361yU4TkuRSLTdTkfEUbWGfTJgJjFDZUvG"
PASS3="hashca?4"
TEST4="P2PWPKH:m/84h/0h/0h/0/2:donate dolphin bachelor excess stuff flower spread crazy scorpion zoo skull lottery:bc1q490ra0dcf4l58jzt2445akrxpj6aftkfdvs8n7"
PASS4="hashca?4"
# security sugar abandon diamond abandon orient zoo example crane fruit senior decade
TEST5="P2PWPKH:m/84h/0h/0h/0/0:security sugar ? diamond ? orient ? example crane fruit senior ?:bc1q6dlx8mxcxm3qterx35cul7z76v975tf2vq06yr"
PASS5="5656?1?2?3hashcat"
if [ -z $1 ] || [ -z $2 ]; then
echo "Usage ./tools/bip39-tests.sh <test|run|bench> <#|all>"
exit -1
fi
rm -f hashcat.potfile
for i in $(seq 1 5);
do
if [[ "$2" = "$i" ]] || [[ "$2" = "all" ]]; then
echo "Running $1 #$i"
TEST="TEST$i"
PASS="PASS$i"
if [ $1 = "test" ]; then
./hashcat -m 28510 -a 3 --force -n 1 -u 1 -T 1 -1 T -2 u -3 S -4 t "${!TEST}" "${!PASS}"
elif [ $1 = "run" ]; then
./hashcat -m 28510 -a 3 -1 charsets/bin/5bit.hcchr -2 charsets/bin/6bit.hcchr -3 charsets/bin/7bit.hcchr -4 ?l "${!TEST}" "${!PASS}"
elif [ $1 = "bench" ]; then
./hashcat -m 28510 -a 3 -1 charsets/bin/5bit.hcchr -2 charsets/bin/6bit.hcchr -3 charsets/bin/7bit.hcchr -4 ?l --status "${!TEST}" "?1?2?1?2?1?2?3?l"
fi
fi
done
echo -e "\nResults (should be 5 if running all tests):"
cat hashcat.potfile
Loading…
Cancel
Save