|
21 | 21 | DEFAULT_P2WSH_PATH,
|
22 | 22 | )
|
23 | 23 | from buidl.libsec_status import is_libsec_enabled
|
24 |
| -from buidl.mnemonic import BIP39 |
| 24 | +from buidl.mnemonic import BIP39, dice_rolls_to_mnemonic |
25 | 25 | from buidl.shamir import ShareSet
|
26 | 26 | from buidl.psbt import MixedNetwork, PSBT
|
27 | 27 |
|
@@ -246,6 +246,35 @@ def _get_bip39_firstwords():
|
246 | 246 | return fw
|
247 | 247 |
|
248 | 248 |
|
| 249 | +##################################################################### |
| 250 | +# Dice rolls |
| 251 | +##################################################################### |
| 252 | + |
| 253 | + |
| 254 | +def _get_num_words(): |
| 255 | + num_words = _get_int( |
| 256 | + prompt="How many mnemonic words should be generated?", |
| 257 | + default=24, |
| 258 | + minimum=12, |
| 259 | + maximum=24, |
| 260 | + ) |
| 261 | + if num_words not in (12, 15, 18, 21, 24): |
| 262 | + raise ValueError( |
| 263 | + "Provided number of mnemonic words must be 12, 15, 18, 21, or 24 words" |
| 264 | + ) |
| 265 | + return num_words |
| 266 | + |
| 267 | + |
| 268 | +def _get_dice_values(): |
| 269 | + dice_vals = input( |
| 270 | + blue_fg( |
| 271 | + "Enter the numbers from the 6-sided dice rolls" |
| 272 | + '\n(e.g., "14625363...", >= 100 values recommended): ' |
| 273 | + ) |
| 274 | + ).strip() |
| 275 | + return dice_vals |
| 276 | + |
| 277 | + |
249 | 278 | #####################################################################
|
250 | 279 | # PSBT Signer
|
251 | 280 | #####################################################################
|
@@ -487,6 +516,55 @@ def do_generate_seed(self, arg):
|
487 | 516 | print_yellow("Copy-paste this into Specter-Desktop:")
|
488 | 517 | print_green(key_record)
|
489 | 518 |
|
| 519 | + def do_generate_seed_from_dice(self, arg): |
| 520 | + """Calculate bitcoin public and private key information from BIP39 words created from dice rolls""" |
| 521 | + |
| 522 | + blue_fg("Generates a mnemonic from 6-sided dice rolls.") |
| 523 | + num_words = _get_num_words() |
| 524 | + dice_vals = _get_dice_values() |
| 525 | + |
| 526 | + if self.ADVANCED_MODE: |
| 527 | + password = _get_password() |
| 528 | + else: |
| 529 | + password = "" |
| 530 | + |
| 531 | + if _get_bool(prompt="Use Mainnet?", default=False): |
| 532 | + network = "mainnet" |
| 533 | + else: |
| 534 | + network = "testnet" |
| 535 | + |
| 536 | + if self.ADVANCED_MODE: |
| 537 | + path_to_use = _get_path(network=network) |
| 538 | + use_slip132_version_byte = _get_bool( |
| 539 | + prompt="Encode with SLIP132 version byte?", default=True |
| 540 | + ) |
| 541 | + else: |
| 542 | + path_to_use = None # buidl will use default path |
| 543 | + use_slip132_version_byte = True |
| 544 | + |
| 545 | + words = dice_rolls_to_mnemonic(dice_vals, num_words) |
| 546 | + hd_priv = HDPrivateKey.from_mnemonic( |
| 547 | + mnemonic=words, |
| 548 | + password=password.encode(), |
| 549 | + network=network, |
| 550 | + ) |
| 551 | + |
| 552 | + key_record = hd_priv.generate_p2wsh_key_record( |
| 553 | + bip32_path=path_to_use, use_slip132_version_byte=use_slip132_version_byte |
| 554 | + ) |
| 555 | + |
| 556 | + print(yellow_fg("SECRET INFO") + red_fg(" (guard this VERY carefully)")) |
| 557 | + print_green( |
| 558 | + f"Dice rolls used: {dice_vals}" |
| 559 | + f"\nFull ({len(words.split())} word) mnemonic (including last word): {words}" |
| 560 | + ) |
| 561 | + if password: |
| 562 | + print_green(f"Passphrase: {password}") |
| 563 | + |
| 564 | + print_yellow(f"\nPUBLIC KEY INFO ({network})") |
| 565 | + print_yellow("Copy-paste this into Specter-Desktop:") |
| 566 | + print_green(key_record) |
| 567 | + |
490 | 568 | def do_create_output_descriptors(self, arg):
|
491 | 569 | """Combine m-of-n public key records into a multisig output descriptor (account map)"""
|
492 | 570 |
|
|
0 commit comments