def process_all(mnemonics: list) -> bytes: """ Receives all mnemonics and processes it into pre-master secret which is usually then stored in the storage. """ identifier, iteration_exponent, secret = slip39.combine_mnemonics( mnemonics) storage.set_slip39_iteration_exponent(iteration_exponent) storage.set_slip39_identifier(identifier) return secret
def generate_from_secret(master_secret: bytes, count: int, threshold: int) -> str: """ Generates new Shamir backup for 'master_secret'. Multiple groups are not yet supported. """ identifier, group_mnemonics = slip39.generate_single_group_mnemonics_from_data( master_secret, threshold, count) storage.set_slip39_iteration_exponent(slip39.DEFAULT_ITERATION_EXPONENT) storage.set_slip39_identifier(identifier) return group_mnemonics
def process_single(mnemonic: str) -> bytes: """ Receives single mnemonic and processes it. Returns what is then stored in storage or None if more shares are needed. """ identifier, iteration_exponent, _, _, _, index, threshold, value = slip39.decode_mnemonic( mnemonic) # TODO: use better data structure for this if threshold == 1: raise ValueError("Threshold equal to 1 is not allowed.") # if recovery is not in progress already, start it and wait for more mnemonics if not storage.is_slip39_in_progress(): storage.set_slip39_in_progress(True) storage.set_slip39_iteration_exponent(iteration_exponent) storage.set_slip39_identifier(identifier) storage.set_slip39_threshold(threshold) storage.set_slip39_remaining(threshold - 1) storage.set_slip39_words_count(len(mnemonic.split())) storage.set_slip39_mnemonic(index, mnemonic) return None # we need more shares # check identifier and member index of this share against stored values if identifier != storage.get_slip39_identifier(): # TODO: improve UX (tell user) raise ValueError("Share identifiers do not match") if storage.get_slip39_mnemonic(index): # TODO: improve UX (tell user) raise ValueError("This mnemonic was already entered") # append to storage remaining = storage.get_slip39_remaining() - 1 storage.set_slip39_remaining(remaining) storage.set_slip39_mnemonic(index, mnemonic) if remaining != 0: return None # we need more shares # combine shares and return the master secret mnemonics = storage.get_slip39_mnemonics() if len(mnemonics) != threshold: raise ValueError("Some mnemonics are still missing.") _, _, secret = slip39.combine_mnemonics(mnemonics) return secret
async def reset_device(ctx, msg): # validate parameters and device state _validate_reset_device(msg) # make sure user knows he's setting up a new wallet await layout.show_reset_device_warning(ctx, msg.slip39) # request new PIN if msg.pin_protection: newpin = await request_pin_confirm(ctx) else: newpin = "" # generate and display internal entropy int_entropy = random.bytes(32) if __debug__: debug.reset_internal_entropy = int_entropy if msg.display_random: await layout.show_internal_entropy(ctx, int_entropy) # request external entropy and compute the master secret entropy_ack = await ctx.call(EntropyRequest(), MessageType.EntropyAck) ext_entropy = entropy_ack.entropy secret = _compute_secret_from_entropy(int_entropy, ext_entropy, msg.strength) if msg.slip39: storage.set_slip39_identifier(slip39.generate_random_identifier()) storage.set_slip39_iteration_exponent( slip39.DEFAULT_ITERATION_EXPONENT) # should we back up the wallet now? if not msg.no_backup and not msg.skip_backup: if not await layout.confirm_backup(ctx): if not await layout.confirm_backup_again(ctx): msg.skip_backup = True # generate and display backup information for the master secret if not msg.no_backup and not msg.skip_backup: if msg.slip39: await backup_slip39_wallet(ctx, secret) else: await backup_bip39_wallet(ctx, secret) # write PIN into storage if not config.change_pin(pin_to_int(""), pin_to_int(newpin)): raise wire.ProcessError("Could not change PIN") # write settings and master secret into storage storage.load_settings(label=msg.label, use_passphrase=msg.passphrase_protection) if msg.slip39: mnemonic.slip39.store(secret=secret, needs_backup=msg.skip_backup, no_backup=msg.no_backup) else: # in BIP-39 we store mnemonic string instead of the secret mnemonic.bip39.store( secret=bip39.from_data(secret).encode(), needs_backup=msg.skip_backup, no_backup=msg.no_backup, ) # if we backed up the wallet, show success message if not msg.no_backup and not msg.skip_backup: await layout.show_backup_success(ctx) return Success(message="Initialized")