Generated the mnemonic-sentence from an entropy buffer without the salt This function also generates the correct checkout (Last word of the sentence)
Prime function to generate a mnemonic sentence
The reverse function of entropyToMnemonic This function converts a mnemonic sentence to an entropy buffer The function also check if the words in the sentence are in the word table and it check if the checksum is correct if this is not the case the it throws an BIP39Exception Because this function also appends the checksum to the entropy buffer to reverse the mnemonic-sentence the entropyToMnemonic should called with entropy_buf[0..$-1] (without the checksum)
Generated the 512bits seed from a mnemonic-sentence and an optional password Both the mnemonic_sentence and the password are NFKD normalized.
Check if the mnemonic sentence has the correct words and the correct checksum
Total number of bits
Max number of mnemonic word in a string
Bit size of the word number 2^11=2048
Helper function which appends the checksum the entropy_buf
* Helper function to check if the entropy length is correct * Params: * len = length of an entropy buffer * Returns: * true of the length is correct
* Reverse function of entropy * This function should only be used to analyze an entropy buffer * Params: * entropy_buf = byte array of an entropy buffer * Returns: * an array of mnemonic-indices
* Calculates the checksum of an entropy buffer * Params: * entropy_buf = entropy buffer * Returns: * checkout as a single byte
Calculates the entropy of a list of mnemonic-indices without the checksum This function should also be used analyze a mnemonic-indices list To produces a entropy the function mnemonicToEntropy should be used instead
Helper function to generated the mnemonic salt
Table of all the mnemonic words
Reverse lookup table of the mnemonic words
Test sample of bip39 https://learnmeabitcoin.com/technical/mnemonic
later echo alcohol essence charge eight feel sweet nephew apple aerobic device 01111101010010001011110000011000001001101010001001101000100011011101010100110110110111011001010001000001010101000001000010011110 0101 Examples: how to use the BIP39 function collection
1 import std.stdio; 2 import tagion.wallet.bip39_english; 3 import std.format; 4 import std.string : representation; 5 import tagion.hibon.HiBONtoText : decode; 6 7 const bip39 = BIP39(words); 8 { // Test of entropy and dentropy 9 const(ushort[]) expected_mnemonic_codes = [1390, 1586, 604, 1202, 689, 900]; 10 immutable expected_entropy = "101011011101100011001001001011100100101100100101011000101110000100"; 11 const entropy_bytes = bip39.entropy(expected_mnemonic_codes); 12 assert(expected_entropy == format("%(%011b%)", expected_mnemonic_codes)); 13 const dentropy_codes = bip39.dentropy(entropy_bytes); 14 assert(equal(expected_mnemonic_codes, dentropy_codes)); 15 } 16 { 17 // All zeros 18 auto entropy_bytes = ubyte(0).repeat(16).array; // All zeros 19 const ubyte expected_checksum = 0b00110000; 20 const checksum = bip39.deriveChecksumBits(entropy_bytes); 21 assert(expected_checksum == checksum); 22 bip39.addCheckSumBits(entropy_bytes); 23 const dentropy = bip39.dentropy(entropy_bytes); 24 25 const expected_words = ("abandon".repeat(11).array ~ "about").join(" "); 26 const generated_words = dentropy.map!(no => bip39.words[no]).join(" "); 27 assert(expected_words == generated_words); 28 assert(entropy_bytes == bip39.mnemonicToEntropy(generated_words)); 29 30 } 31 { 32 // All zeros 33 auto entropy_bytes = ubyte(0).repeat(32).array; // All zeros 34 const ubyte expected_checksum = 0b01100110; 35 //const entropy_bytes = format(" 36 const checksum = bip39.deriveChecksumBits(entropy_bytes); 37 assert(expected_checksum == checksum); 38 bip39.addCheckSumBits(entropy_bytes); 39 const dentropy = bip39.dentropy(entropy_bytes); 40 const expected_words = ("abandon".repeat(23).array ~ "art").join(" "); 41 const generated_words = dentropy.map!(no => bip39.words[no]).join(" "); 42 assert(expected_words == generated_words); 43 assert(entropy_bytes == bip39.mnemonicToEntropy(generated_words)); 44 } 45 { 46 const mnemonic = [ 47 "punch", 48 "shock", 49 "entire", 50 "north", 51 "file", 52 "identify" 53 ]; 54 const(ushort[]) expected_mnemonic_codes = [1390, 1586, 604, 1202, 689, 900]; 55 immutable expected_entropy = "101011011101100011001001001011100100101100100101011000101110000100"; 56 const mnemonic_codes = bip39.mnemonicNumbers(mnemonic); 57 assert(expected_mnemonic_codes == mnemonic_codes); 58 string mnemonic_codes_bits = format("%(%011b%)", mnemonic_codes); 59 assert(expected_entropy == mnemonic_codes_bits); 60 const entropy = bip39.entropy(mnemonic_codes); 61 string entropy_bits = format("%(%08b%)", entropy)[0 .. 11 * expected_mnemonic_codes.length]; 62 assert(expected_entropy == entropy_bits); 63 } 64 { 65 const mnemonic = [ 66 "later", 67 "echo", 68 "alcohol", 69 "essence", 70 "charge", 71 "eight", 72 "feel", 73 "sweet", 74 "nephew", 75 "apple", 76 "aerobic", 77 "device" 78 ]; 79 // const(ushort[]) mnemonic_code =[1390, 1586, 604, 1202, 689, 900]; 80 immutable expected_entropy = "011111010100100010111100000110000010011010100010011010001000110111010101001101101101110110010100010000010101010000010000100111100101"; 81 const mnemonic_codes = bip39.mnemonicNumbers(mnemonic); 82 string entropy_bits = format("%(%011b%)", bip39.mnemonicNumbers(mnemonic)); 83 assert(expected_entropy == entropy_bits); 84 85 } 86 { /// PBKDF2 BIP39 87 const mnemonic = [ 88 "basket", 89 "actual" 90 ]; 91 92 import tagion.crypto.pbkdf2; 93 import std.bitmanip : nativeToBigEndian; 94 import std.digest.sha : SHA512; 95 96 const mnemonic_codes = bip39.mnemonicNumbers(mnemonic); 97 98 const entropy = bip39.entropy(mnemonic_codes); 99 string mnemonic_codes_bits = format("%(%011b%)", mnemonic_codes); 100 string entropy_bits = format("%(%08b%)", entropy); //[0 .. 12 * mnemonic_codes.length]; 101 alias pbkdf2_sha512 = pbkdf2!SHA512; 102 string salt = "mnemonic"; //.representation; 103 const entropy1 = "basket actual".representation; 104 const result1 = pbkdf2_sha512(entropy1, salt.representation, 2048, 64); 105 } 106 107 { 108 } 109 /* 110 // The flowing list has been generated from 111 // from nodejs using 112 // https://github.com/bitcoinjs/bip39.git 113 const bip39 = require('bip39') 114 bip39.wordlists.english; 115 --- the bip39_english_test_list here 116 for(let i=0; i<bip39_english_test_list.length; i++) { 117 const words=bip39.entropyToMnemonic(bip39_english_test_list[i][0]); 118 const seed=bip39.mnemonicToSeedSync(words); 119 bip39_english_test_list[i][1]=words; 120 bip39_english_test_list[i][2]=seed.toString('hex'); 121 } 122 const content= JSON.stringify(bip39_english_test_list, null, 4); 123 const fs = require('node:fs'); 124 fs.writeFile('testvector.json', content, err => { 125 if (err) { 126 console.error(err); 127 } 128 }); 129 */ 130 const bip39_english_test_list = [ 131 132 [ 133 "00000000000000000000000000000000", 134 "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", 135 "5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4" 136 ], 137 [ 138 "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 139 "legal winner thank year wave sausage worth useful legal winner thank yellow", 140 "878386efb78845b3355bd15ea4d39ef97d179cb712b77d5c12b6be415fffeffe5f377ba02bf3f8544ab800b955e51fbff09828f682052a20faa6addbbddfb096" 141 ], 142 [ 143 "80808080808080808080808080808080", 144 "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", 145 "77d6be9708c8218738934f84bbbb78a2e048ca007746cb764f0673e4b1812d176bbb173e1a291f31cf633f1d0bad7d3cf071c30e98cd0688b5bcce65ecaceb36" 146 ], 147 [ 148 "ffffffffffffffffffffffffffffffff", 149 "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", 150 "b6a6d8921942dd9806607ebc2750416b289adea669198769f2e15ed926c3aa92bf88ece232317b4ea463e84b0fcd3b53577812ee449ccc448eb45e6f544e25b6" 151 ], 152 [ 153 "000000000000000000000000000000000000000000000000", 154 "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", 155 "4975bb3d1faf5308c86a30893ee903a976296609db223fd717e227da5a813a34dc1428b71c84a787fc51f3b9f9dc28e9459f48c08bd9578e9d1b170f2d7ea506" 156 ], 157 [ 158 "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 159 "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", 160 "b059400ce0f55498a5527667e77048bb482ff6daa16c37b4b9e8af70c85b3f4df588004f19812a1a027c9a51e5e94259a560268e91cd10e206451a129826e740" 161 ], 162 [ 163 "808080808080808080808080808080808080808080808080", 164 "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", 165 "04d5f77103510c41d610f7f5fb3f0badc77c377090815cee808ea5d2f264fdfabf7c7ded4be6d4c6d7cdb021ba4c777b0b7e57ca8aa6de15aeb9905dba674d66" 166 ], 167 [ 168 "ffffffffffffffffffffffffffffffffffffffffffffffff", 169 "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", 170 "d2911131a6dda23ac4441d1b66e2113ec6324354523acfa20899a2dcb3087849264e91f8ec5d75355f0f617be15369ffa13c3d18c8156b97cd2618ac693f759f" 171 ], 172 [ 173 "0000000000000000000000000000000000000000000000000000000000000000", 174 "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", 175 "408b285c123836004f4b8842c89324c1f01382450c0d439af345ba7fc49acf705489c6fc77dbd4e3dc1dd8cc6bc9f043db8ada1e243c4a0eafb290d399480840" 176 ], 177 [ 178 "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", 179 "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", 180 "761914478ebf6fe16185749372e91549361af22b386de46322cf8b1ba7e92e80c4af05196f742be1e63aab603899842ddadf4e7248d8e43870a4b6ff9bf16324" 181 ], 182 [ 183 "8080808080808080808080808080808080808080808080808080808080808080", 184 "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", 185 "848bbe19cad445e46f35fd3d1a89463583ac2b60b5eb4cfcf955731775a5d9e17a81a71613fed83f1ae27b408478fdec2bbc75b5161d1937aa7cdf4ad686ef5f" 186 ], 187 [ 188 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 189 "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", 190 "e28a37058c7f5112ec9e16a3437cf363a2572d70b6ceb3b6965447623d620f14d06bb321a26b33ec15fcd84a3b5ddfd5520e230c924c87aaa0d559749e044fef" 191 ], 192 [ 193 "77c2b00716cec7213839159e404db50d", 194 "jelly better achieve collect unaware mountain thought cargo oxygen act hood bridge", 195 "c7b8fbb38c1abe38dfc0fea9797804558dfac244cd7737ae3a1b619991e0ad520155d982f906629639dc39e440520f98f820bea4f886a63a45923a63441f25ef" 196 ], 197 [ 198 "b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", 199 "renew stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap", 200 "b1a1f06f175feccc998684667474b3d83efa57a0f39bb3a6cf3a3350ee7a6638ae6d15c4622c8252efe5aa319b026db1d4c91a80661ed34da1f2fb7d381224c8" 201 ], 202 [ 203 "3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", 204 "dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic", 205 "ecf9632e864630c00be4ca3d752d4f19a852cd628d9bbc3309a4c1a2f39801461a6816ca52793ddd3dacb242e207ad48e8bfde3afd0e8f978ad0e8cc4dd276c1" 206 ], 207 [ 208 "0460ef47585604c5660618db2e6a7e7f", 209 "afford alter spike radar gate glance object seek swamp infant panel yellow", 210 "3ddfd060236156416f8915ed6ced01c3316292aec7250434f7e32cda2338e76399874787257acad15618c81bcddd88714f8c0d316140dad809f0ca8b1a971679" 211 ], 212 [ 213 "72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", 214 "indicate race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left", 215 "fe34200c8c3781f81f48d19f628a7370eb25c94c75077c9a6d4a1ef30fd9cc2f29f8ea7ef52bb765c5278413c19b7b2854b62cb3591ce4d749cd7f497da436a6" 216 ], 217 [ 218 "2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", 219 "clutch control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste", 220 "fa9ca5ef1ebfcb5e945091d413843bf7ce748d27b8b99bb5373d34b9a6b1450d2a2d7f04480904b29c78a41a6ea949288f687f72b5b8e322193a7eae8151f109" 221 ], 222 [ 223 "eaebabb2383351fd31d703840b32e9e2", 224 "turtle front uncle idea crush write shrug there lottery flower risk shell", 225 "4ef6e8484a846392f996b15283906b73be4ec100859ce68689d5a0fad7f761745b86d70ea5f5c43e4cc93ce4b82b3d9aeed7f85d503fac00b10ebbc150399100" 226 ], 227 [ 228 "7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", 229 "kiss carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment", 230 "f0b24a453174e3c4f27634f3e2be07c069328f7cbaa24f695cbeb79a39e79f05154bddbabec57b832a46813d2e49e7b33f438e79cc566f78a3179dbce86cdd84" 231 ], 232 [ 233 "4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", 234 "exile ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top", 235 "8a91a843ad4fede95f23937099a94f117115a369903603761ecabae734b5d501ddba04b1a3c9f2256437ef2d230f295d8f08676e5de93ad5190da6645ded8160" 236 ], 237 [ 238 "18ab19a9f54a9274f03e5209a2ac8a91", 239 "board flee heavy tunnel powder denial science ski answer betray cargo cat", 240 "22087755f76d6fb93ddd19e71106d4d4146f48424a241c0eda88787227827166223f61860d53652b635f360b5a37dd26c8aed3fa10b6f8e95be18f1913f4ca88" 241 ], 242 [ 243 "18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", 244 "board blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief", 245 "99539dbb0a15a76cdadd9cc066bae337a006823fa3439b42656fd0fca3d48afe6a0ca6f7a1d10412df611c32e18669a29bc0494de61b4c36730a5c31045464e2" 246 ], 247 [ 248 "15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", 249 "beyond stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut", 250 "898c7388d88e3a5b3b2922a0f03f95c8e61aeadba9fa8a7b0b5629d7c98e1e0aec53f0b10fcbd4a913b4b8c985028b0026ec6fdb0a4442ee18344ca3fac4d692" 251 ] 252 ]; 253 { 254 foreach (i, test_data; bip39_english_test_list) { 255 const entropy_buf = test_data[0].decode; 256 const expected_sentence = test_data[1]; 257 const expected_seed = test_data[2].decode; 258 assert(bip39.validateMnemonic(expected_sentence)); 259 const generated_sentence = bip39.entropyToMnemonic(entropy_buf); 260 assert(expected_sentence == generated_sentence); 261 const generated_entropy_buf = bip39.mnemonicToEntropy(expected_sentence); 262 const generated_entropy_buf_without_checksum = generated_entropy_buf[0 .. $ - 1]; 263 assert(entropy_buf == generated_entropy_buf_without_checksum); 264 const generated_seed = bip39.mnemonicToSeed(generated_sentence); 265 assert(expected_seed == generated_seed); 266 const generated_checksum = bip39.deriveChecksumBits(entropy_buf); 267 assert(generated_checksum == generated_entropy_buf[$ - 1]); 268 } 269 } 270 271 { /// Check valid mnemonic sentences 272 assert(!bip39.validateMnemonic( 273 "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon"), 274 "Should failed on checksum"); 275 assert(!bip39.validateMnemonic("abandon abandon ability"), "Word list to short"); 276 assert(bip39.validateMnemonic( 277 "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"), 278 "Word list should be correct"); 279 280 }
BIP39 function collection