Beispiel #1
0
    async def next_menu(self, idx, choice):

        words = WordNestMenu.words
        cls = self.__class__

        if choice.label[-1] == '-':
            ch = letter_choices(choice.label[0:-1])

            return cls(items=[MenuItem(i, menu=self.next_menu) for i in ch])

        # terminal choice, start next word
        words.append(choice.label)

        #print(("words[%d]: " % len(words)) + ' '.join(words))
        assert len(words) <= self.target_words

        if len(words) == 23 and self.has_checksum:
            # we can provide final 8 choices, but only for 24-word case
            final_words = list(bip39.a2b_words_guess(words))

            async def picks_chk_word(s, idx, choice):
                # they picked final word, the word includes valid checksum bits
                words.append(choice.label)
                await cls.done_cb(words.copy())

            items = [MenuItem(w, f=picks_chk_word) for w in final_words]
            items.append(MenuItem('(none above)', f=self.explain_error))
            return cls(is_commit=True, items=items)

        # add a few top-items in certain cases
        if len(words) == self.target_words:
            if self.has_checksum:
                try:
                    bip39.a2b_words(' '.join(words))
                    correct = True
                except ValueError:
                    correct = False
            else:
                correct = True

            # they have checksum right, so they are certainly done.
            if correct:
                # they are done, don't force them to do any more!
                return await cls.done_cb(words.copy())
            else:
                # give them a chance to confirm and/or start over
                return cls(is_commit=True,
                           items=[
                               MenuItem('(INCORRECT)', f=self.explain_error),
                               MenuItem('(start over)', f=self.start_over)
                           ])

        # pop stack to reset depth, and start again at a- .. z-
        cls.pop_all()

        return cls(items=None, is_commit=True)
Beispiel #2
0
    async def all_done(new_words):
        # So we have another part, might be done or not.
        global import_xor_parts
        assert len(new_words) == 24
        import_xor_parts.append(new_words)

        XORWordNestMenu.pop_all()

        num_parts = len(import_xor_parts)
        seed = xor32(*(bip39.a2b_words(w) for w in import_xor_parts))

        msg = "You've entered %d parts so far.\n\n" % num_parts
        if num_parts >= 2:
            chk_word = bip39.b2a_words(seed).split(' ')[-1]
            msg += "If you stop now, the 24th word of the XOR-combined seed phrase\nwill be:\n\n"
            msg += "24: %s\n\n" % chk_word

        if all((not x) for x in seed):
            # zero seeds are never right.
            msg += "ZERO WARNING\nProvided seed works out to all zeros "\
                    "right now. You may have doubled a part or made some other mistake.\n\n"

        msg += "Press (1) to enter next list of words, or (2) if done with all words."

        ch = await ux_show_story(msg,
                                 strict_escape=True,
                                 escape='12x',
                                 sensitive=True)

        if ch == 'x':
            # give up
            import_xor_parts.clear()  # concern: we are contaminated w/ secrets
            return None
        elif ch == '1':
            # do another list of words
            nxt = XORWordNestMenu(num_words=24)
            the_ux.push(nxt)
        elif ch == '2':
            # done; import on temp basis, or be the main secret
            from pincodes import pa
            enc = stash.SecretStash.encode(seed_phrase=seed)

            if pa.is_secret_blank():
                # save it since they have no other secret
                set_seed_value(encoded=enc)

                # update menu contents now that wallet defined
                goto_top_menu()
            else:
                pa.tmp_secret(enc)
                await ux_show_story(
                    "New master key in effect until next power down.")

        return None
Beispiel #3
0
def set_seed_value(words=None, encoded=None):
    # Save the seed words into secure element, and reboot. BIP-39 password
    # is not set at this point (empty string)
    if words:
        bip39.a2b_words(words)      # checksum check

        # map words to bip39 wordlist indices
        data = [bip39.wordlist_en.index(w) for w in words]

        # map to packed binary representation.
        val = 0
        for v in data:
            val <<= 11
            val |= v

        # remove the checksum part
        vlen = (len(words) * 4) // 3
        val >>= (len(words) // 3)

        # convert to bytes
        seed = val.to_bytes(vlen, 'big')
        assert len(seed) == vlen

        # encode it for our limited secret space
        nv = SecretStash.encode(seed_phrase=seed)
    else:
        nv = encoded

    from glob import dis
    dis.fullscreen('Applying...')
    pa.change(new_secret=nv)

    # re-read settings since key is now different
    # - also captures xfp, xpub at this point
    pa.new_main_secret(nv)

    # check and reload secret
    pa.reset()
    pa.login()
Beispiel #4
0
def test_a2b():
    for value, words in b39_data.vectors:
        got = bip39.a2b_words(words)
        assert got == value
Beispiel #5
0
def test_vectors():
    for raw, words, ms, _ in b39_vectors.english[0:10]:
        assert bip39.a2b_words(words) == a2b_hex(raw)
        got = bip39.master_secret(words.encode('utf'), a2b_hex('5452455a4f52'))
        assert got == a2b_hex(ms)