def test_iteration_exponent(self):
        identifier = slip39.generate_random_identifier()
        mnemonics = slip39.split_ems(1, [(3, 5)], identifier, 1, self.EMS)
        mnemonics = mnemonics[0]
        identifier, exponent, ems = slip39.recover_ems(mnemonics[1:4])
        self.assertEqual(ems, self.EMS)

        identifier = slip39.generate_random_identifier()
        mnemonics = slip39.split_ems(1, [(3, 5)], identifier, 2, self.EMS)
        mnemonics = mnemonics[0]
        identifier, exponent, ems = slip39.recover_ems(mnemonics[1:4])
        self.assertEqual(ems, self.EMS)
Exemple #2
0
    def test_iteration_exponent(self):
        identifier = slip39.generate_random_identifier()
        mnemonics = slip39.generate_mnemonics_from_data(self.MS, identifier, 1, [(3, 5)], b"TREZOR", 1)
        mnemonics = mnemonics[0]
        identifier, exponent, ems = slip39.combine_mnemonics(mnemonics[1:4])
        self.assertEqual(slip39.decrypt(identifier, exponent, ems, b"TREZOR"), self.MS)
        self.assertNotEqual(slip39.decrypt(identifier, exponent, ems, b""), self.MS)

        identifier = slip39.generate_random_identifier()
        mnemonics = slip39.generate_mnemonics_from_data(self.MS, identifier, 1, [(3, 5)], b"TREZOR", 2)
        mnemonics = mnemonics[0]
        identifier, exponent, ems = slip39.combine_mnemonics(mnemonics[1:4])
        self.assertEqual(slip39.decrypt(identifier, exponent, ems, b"TREZOR"), self.MS)
        self.assertNotEqual(slip39.decrypt(identifier, exponent, ems, b""), self.MS)
Exemple #3
0
    def test_group_sharing(self):
        group_threshold = 2
        group_sizes = (5, 3, 5, 1)
        member_thresholds = (3, 2, 2, 1)
        identifier = slip39.generate_random_identifier()
        mnemonics = slip39.generate_mnemonics_from_data(
            self.MS, identifier, group_threshold, list(zip(member_thresholds, group_sizes))
        )

        # Test all valid combinations of mnemonics.
        for groups in combinations(zip(mnemonics, member_thresholds), group_threshold):
            for group1_subset in combinations(groups[0][0], groups[0][1]):
                for group2_subset in combinations(groups[1][0], groups[1][1]):
                    mnemonic_subset = list(group1_subset + group2_subset)
                    random.shuffle(mnemonic_subset)
                    identifier, exponent, ems = slip39.combine_mnemonics(mnemonic_subset)
                    self.assertEqual(slip39.decrypt(identifier, exponent, ems, b""), self.MS)


        # Minimal sets of mnemonics.
        identifier, exponent, ems = slip39.combine_mnemonics([mnemonics[2][0], mnemonics[2][2], mnemonics[3][0]])
        self.assertEqual(slip39.decrypt(identifier, exponent, ems, b""), self.MS)
        self.assertEqual(slip39.combine_mnemonics([mnemonics[2][3], mnemonics[3][0], mnemonics[2][4]])[2], ems)

        # One complete group and one incomplete group out of two groups required.
        with self.assertRaises(slip39.MnemonicError):
            slip39.combine_mnemonics(mnemonics[0][2:] + [mnemonics[1][0]])

        # One group of two required.
        with self.assertRaises(slip39.MnemonicError):
            slip39.combine_mnemonics(mnemonics[0][1:4])
Exemple #4
0
    def test_invalid_sharing(self):
        identifier = slip39.generate_random_identifier()
        # Short master secret.
        with self.assertRaises(ValueError):
            slip39.generate_mnemonics_from_data(self.MS[:14], identifier, 1, [(2, 3)])

        # Odd length master secret.
        with self.assertRaises(ValueError):
            slip39.generate_mnemonics_from_data(self.MS + b"X", identifier,1, [(2, 3)])

        # Group threshold exceeds number of groups.
        with self.assertRaises(ValueError):
            slip39.generate_mnemonics_from_data(self.MS, identifier, 3, [(3, 5), (2, 5)])

        # Invalid group threshold.
        with self.assertRaises(ValueError):
            slip39.generate_mnemonics_from_data(self.MS, identifier, 0, [(3, 5), (2, 5)])

        # Member threshold exceeds number of members.
        with self.assertRaises(ValueError):
            slip39.generate_mnemonics_from_data(self.MS, identifier, 2, [(3, 2), (2, 5)])

        # Invalid member threshold.
        with self.assertRaises(ValueError):
            slip39.generate_mnemonics_from_data(self.MS, identifier, 2, [(0, 2), (2, 5)])

        # Group with multiple members and threshold 1.
        with self.assertRaises(ValueError):
            slip39.generate_mnemonics_from_data(self.MS, identifier, 2, [(3, 5), (1, 3), (2, 5)])
    def test_invalid_sharing(self):
        identifier = slip39.generate_random_identifier()

        # Group threshold exceeds number of groups.
        with self.assertRaises(ValueError):
            slip39.generate_mnemonics_from_data(self.EMS, identifier, 3,
                                                [(3, 5), (2, 5)], 1)

        # Invalid group threshold.
        with self.assertRaises(ValueError):
            slip39.generate_mnemonics_from_data(self.EMS, identifier, 0,
                                                [(3, 5), (2, 5)], 1)

        # Member threshold exceeds number of members.
        with self.assertRaises(ValueError):
            slip39.generate_mnemonics_from_data(self.EMS, identifier, 2,
                                                [(3, 2), (2, 5)], 1)

        # Invalid member threshold.
        with self.assertRaises(ValueError):
            slip39.generate_mnemonics_from_data(self.EMS, identifier, 2,
                                                [(0, 2), (2, 5)], 1)

        # Group with multiple members and threshold 1.
        with self.assertRaises(ValueError):
            slip39.generate_mnemonics_from_data(self.EMS, identifier, 2,
                                                [(3, 5), (1, 3), (2, 5)], 1)
 def test_basic_sharing_random(self):
     ems = random.bytes(32)
     identifier = slip39.generate_random_identifier()
     mnemonics = slip39.split_ems(1, [(3, 5)], identifier, 1, ems)
     mnemonics = mnemonics[0]
     self.assertEqual(slip39.recover_ems(mnemonics[:3]),
                      slip39.recover_ems(mnemonics[2:]))
Exemple #7
0
 def test_all_groups_exist(self):
     for group_threshold in (1, 2, 5):
         identifier = slip39.generate_random_identifier()
         mnemonics = slip39.generate_mnemonics_from_data(
             self.MS, identifier, group_threshold, [(3, 5), (1, 1), (2, 3), (2, 5), (3, 5)]
         )
         self.assertEqual(len(mnemonics), 5)
         self.assertEqual(len(sum(mnemonics, [])), 19)
 def test_basic_sharing_random(self):
     ems = random.bytes(32)
     identifier = slip39.generate_random_identifier()
     mnemonics = slip39.generate_mnemonics_from_data(
         ems, identifier, 1, [(3, 5)], 1)
     mnemonics = mnemonics[0]
     self.assertEqual(slip39.combine_mnemonics(mnemonics[:3]),
                      slip39.combine_mnemonics(mnemonics[2:]))
 def test_all_groups_exist(self):
     for group_threshold in (1, 2, 5):
         identifier = slip39.generate_random_identifier()
         mnemonics = slip39.split_ems(group_threshold, [(3, 5), (1, 1),
                                                        (2, 3), (2, 5),
                                                        (3, 5)], identifier,
                                      1, self.EMS)
         self.assertEqual(len(mnemonics), 5)
         self.assertEqual(len(sum(mnemonics, [])), 19)
    def test_iteration_exponent(self):
        identifier = slip39.generate_random_identifier()
        mnemonics = slip39.generate_mnemonics_from_data(
            self.EMS, identifier, 1, [(3, 5)], 1)
        mnemonics = mnemonics[0]
        identifier, exponent, ems, group_count = slip39.combine_mnemonics(
            mnemonics[1:4])
        self.assertEqual(ems, self.EMS)
        self.assertEqual(group_count, 1)

        identifier = slip39.generate_random_identifier()
        mnemonics = slip39.generate_mnemonics_from_data(
            self.EMS, identifier, 1, [(3, 5)], 2)
        mnemonics = mnemonics[0]
        identifier, exponent, ems, group_count = slip39.combine_mnemonics(
            mnemonics[1:4])
        self.assertEqual(group_count, 1)
        self.assertEqual(ems, self.EMS)
Exemple #11
0
 def test_basic_sharing_fixed(self):
     generated_identifier = slip39.generate_random_identifier()
     mnemonics = slip39.generate_mnemonics_from_data(self.MS, generated_identifier, 1, [(3, 5)])
     mnemonics = mnemonics[0]
     identifier, exponent, ems = slip39.combine_mnemonics(mnemonics[:3])
     self.assertEqual(slip39.decrypt(identifier, exponent, ems, b""), self.MS)
     self.assertEqual(generated_identifier, identifier)
     self.assertEqual(slip39.combine_mnemonics(mnemonics[1:4])[2], ems)
     with self.assertRaises(slip39.MnemonicError):
         slip39.combine_mnemonics(mnemonics[1:3])
 def test_basic_sharing_fixed(self):
     generated_identifier = slip39.generate_random_identifier()
     mnemonics = slip39.split_ems(1, [(3, 5)], generated_identifier, 1,
                                  self.EMS)
     mnemonics = mnemonics[0]
     identifier, exponent, ems = slip39.recover_ems(mnemonics[:3])
     self.assertEqual(ems, self.EMS)
     self.assertEqual(generated_identifier, identifier)
     self.assertEqual(slip39.recover_ems(mnemonics[1:4])[2], ems)
     with self.assertRaises(slip39.MnemonicError):
         slip39.recover_ems(mnemonics[1:3])
Exemple #13
0
    def test_group_sharing_threshold_1(self):
        group_threshold = 1
        group_sizes = (5, 3, 5, 1)
        member_thresholds = (3, 2, 2, 1)
        identifier = slip39.generate_random_identifier()
        mnemonics = slip39.generate_mnemonics_from_data(
            self.MS, identifier, group_threshold, list(zip(member_thresholds, group_sizes))
        )

        # Test all valid combinations of mnemonics.
        for group, threshold in zip(mnemonics, member_thresholds):
            for group_subset in combinations(group, threshold):
                mnemonic_subset = list(group_subset)
                random.shuffle(mnemonic_subset)
                identifier, exponent, ems = slip39.combine_mnemonics(mnemonic_subset)
                self.assertEqual(slip39.decrypt(identifier, exponent, ems, b""), self.MS)
    def test_group_sharing_threshold_1(self):
        group_threshold = 1
        group_sizes = (5, 3, 5, 1)
        member_thresholds = (3, 2, 2, 1)
        identifier = slip39.generate_random_identifier()
        mnemonics = slip39.split_ems(group_threshold,
                                     list(zip(member_thresholds, group_sizes)),
                                     identifier, 1, self.EMS)

        # Test all valid combinations of mnemonics.
        for group, threshold in zip(mnemonics, member_thresholds):
            for group_subset in combinations(group, threshold):
                mnemonic_subset = list(group_subset)
                random.shuffle(mnemonic_subset)
                identifier, exponent, ems = slip39.recover_ems(mnemonic_subset)
                self.assertEqual(ems, self.EMS)
Exemple #15
0
async def reset_device(ctx: wire.Context, msg: ResetDevice) -> Success:
    # validate parameters and device state
    _validate_reset_device(msg)

    is_slip39_simple = msg.backup_type == ResetDeviceBackupType.Slip39_Single_Group

    # make sure user knows he's setting up a new wallet
    await _show_reset_device_warning(ctx, is_slip39_simple)

    # 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(), EntropyAck)
    ext_entropy = entropy_ack.entropy
    # For SLIP-39 this is the Encrypted Master Secret
    secret = _compute_secret_from_entropy(int_entropy, ext_entropy,
                                          msg.strength)

    if is_slip39_simple:
        storage.device.set_slip39_identifier(
            slip39.generate_random_identifier())
        storage.device.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 is_slip39_simple:
            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.device.load_settings(label=msg.label,
                                 use_passphrase=msg.passphrase_protection)
    if is_slip39_simple:
        storage.device.store_mnemonic_secret(
            secret,  # this is the EMS in SLIP-39 terminology
            mnemonic.TYPE_SLIP39,
            needs_backup=msg.skip_backup,
            no_backup=msg.no_backup,
        )
    else:
        # in BIP-39 we store mnemonic string instead of the secret
        storage.device.store_mnemonic_secret(
            bip39.from_data(secret).encode(),
            mnemonic.TYPE_BIP39,
            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")
Exemple #16
0
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")
Exemple #17
0
async def reset_device(ctx: wire.Context, msg: ResetDevice) -> Success:
    # validate parameters and device state
    _validate_reset_device(msg)

    # make sure user knows they're setting up a new wallet
    if msg.backup_type == BackupType.Slip39_Basic:
        prompt = "Create a new wallet\nwith Shamir Backup?"
    elif msg.backup_type == BackupType.Slip39_Advanced:
        prompt = "Create a new wallet\nwith Super Shamir?"
    else:
        prompt = "Do you want to create\na new wallet?"
    await confirm_reset_device(ctx, prompt)
    await LoadingAnimation()

    # wipe storage to make sure the device is in a clear state
    storage.reset()

    # request and set new PIN
    if msg.pin_protection:
        newpin = await request_pin_confirm(ctx)
        if not config.change_pin("", newpin, None, None):
            raise wire.ProcessError("Failed to set PIN")

    # 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(), EntropyAck)
    ext_entropy = entropy_ack.entropy
    # For SLIP-39 this is the Encrypted Master Secret
    secret = _compute_secret_from_entropy(int_entropy, ext_entropy, msg.strength)

    # Check backup type, perform type-specific handling
    if msg.backup_type == BackupType.Bip39:
        # in BIP-39 we store mnemonic string instead of the secret
        secret = bip39.from_data(secret).encode()
    elif msg.backup_type in (BackupType.Slip39_Basic, BackupType.Slip39_Advanced):
        # generate and set SLIP39 parameters
        storage.device.set_slip39_identifier(slip39.generate_random_identifier())
        storage.device.set_slip39_iteration_exponent(slip39.DEFAULT_ITERATION_EXPONENT)
    else:
        # Unknown backup type.
        raise RuntimeError

    # If either of skip_backup or no_backup is specified, we are not doing backup now.
    # Otherwise, we try to do it.
    perform_backup = not msg.no_backup and not msg.skip_backup

    # If doing backup, ask the user to confirm.
    if perform_backup:
        perform_backup = await confirm_backup(ctx)

    # generate and display backup information for the master secret
    if perform_backup:
        await backup_seed(ctx, msg.backup_type, secret)

    # write settings and master secret into storage
    if msg.label is not None:
        storage.device.set_label(msg.label)
    storage.device.set_passphrase_enabled(bool(msg.passphrase_protection))
    storage.device.store_mnemonic_secret(
        secret,  # for SLIP-39, this is the EMS
        msg.backup_type,
        needs_backup=not perform_backup,
        no_backup=msg.no_backup,
    )

    # if we backed up the wallet, show success message
    if perform_backup:
        await layout.show_backup_success(ctx)

    return Success(message="Initialized")
Exemple #18
0
async def reset_device(ctx: wire.Context, msg: ResetDevice) -> Success:
    # validate parameters and device state
    _validate_reset_device(msg)

    # make sure user knows they're setting up a new wallet
    await layout.show_reset_device_warning(ctx, msg.backup_type)

    # 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(), EntropyAck)
    ext_entropy = entropy_ack.entropy
    # For SLIP-39 this is the Encrypted Master Secret
    secret = _compute_secret_from_entropy(int_entropy, ext_entropy,
                                          msg.strength)

    if msg.backup_type != BackupType.Bip39:
        storage.device.set_slip39_identifier(
            slip39.generate_random_identifier())
        storage.device.set_slip39_iteration_exponent(
            slip39.DEFAULT_ITERATION_EXPONENT)

    # If either of skip_backup or no_backup is specified, we are not doing backup now.
    # Otherwise, we try to do it.
    perform_backup = not msg.no_backup and not msg.skip_backup

    # If doing backup, ask the user to confirm.
    if perform_backup:
        perform_backup = await layout.confirm_backup(ctx)

    # Check backup type, convert seed accordingly
    if msg.backup_type == BackupType.Bip39:
        # in BIP-39 we store mnemonic string instead of the secret
        secret = bip39.from_data(secret).encode()
    elif msg.backup_type not in (BackupType.Slip39_Basic,
                                 BackupType.Slip39_Advanced):
        # Unknown backup type.
        # This check might seem superfluous, because we are checking
        # in `_validate_reset_device` already, however, this is critical part,
        # so just to make sure.
        raise RuntimeError

    # generate and display backup information for the master secret
    if perform_backup:
        await backup_seed(ctx, msg.backup_type, secret)

    # write PIN into storage
    if not config.change_pin(pin_to_int(""), pin_to_int(newpin), None, None):
        raise wire.ProcessError("Could not change PIN")

    # write settings and master secret into storage
    storage.device.load_settings(label=msg.label,
                                 use_passphrase=msg.passphrase_protection)
    storage.device.store_mnemonic_secret(
        secret,  # for SLIP-39, this is the EMS
        msg.backup_type,
        needs_backup=not perform_backup,
        no_backup=msg.no_backup,
    )

    # if we backed up the wallet, show success message
    if perform_backup:
        await layout.show_backup_success(ctx)

    return Success(message="Initialized")