コード例 #1
0
 def test_test_lev_distance(self):
     with open('./tests/english.txt') as f:
         bip39 = BIP39WordList("file_list", handle=f)
         try:
             bip39.test_lev_distance(2)
         except ValidationFailed as e:
             pass
コード例 #2
0
 def test_getlines_long(self):
     bip39 = BIP39WordList("maxlength_l4", string=maxlength_l4)
     try:
         res = bip39.test_max_length(4)
     except ValidationFailed as e:
         res = e.status_obj
     expected_res = [2, 1]
     self.assertEqual(expected_res, res.getlines_long())
コード例 #3
0
 def test_similar_linegroup(self):
     bip39 = BIP39WordList("inituniq_2group_l3", string=inituniq_2group_l3)
     res = bip39.test_initial_chars(3)
     expected_res = [1, 2]
     self.assertEqual(expected_res, res.similar_linegroup("qu"))
     for t in [0, ""]:
         try:
             res.similar_linegroup(t)
             self.fail()
         except AssertionError as e:
             pass
コード例 #4
0
 def test_similargroup_all(self):
     bip39 = BIP39WordList("inituniq_2group_l3", string=inituniq_2group_l3)
     res = bip39.test_initial_chars(3)
     expected_res = {"qu": [("quick", 1), ("quote", 2)]}
     self.assertEqual(expected_res, res.similargroup_all(2))
     for t in [0, ""]:
         try:
             res.similargroup_all(t)
             self.fail()
         except AssertionError as e:
             pass
コード例 #5
0
 def test_similar_linegroup_many(self):
     bip39 = BIP39WordList("inituniq_4group_l3", string=inituniq_4group_l3)
     res = bip39.test_initial_chars(3)
     expected_res = {"qu": [1, 2], "ri": [4, 3]}
     self.assertEqual(expected_res, res.similar_linegroup_many(["qu",
                                                                "ri"]))
     for t in ["abc", [], ["a"], 0]:
         try:
             res.similar_linegroup_many(t)
             self.fail()
         except AssertionError as e:
             pass
コード例 #6
0
    def test_test_lowercase(self):
        try:
            bip39 = BIP39WordList("invalid_list",
                                  string="\n".join(invalid_list))
        except InvalidWordList as e:
            self.assertTrue(e.has_invalid_chars)
            self.assertFalse(e.has_2048_words)
            self.assertEqual(e.num_words, 3)
            self.assertEqual(e.err_lines, [])
        bip39 = BIP39WordList("valid_list", string=valid_list)
        res = bip39.test_lowercase()
        self.assertFalse(res.has_invalid_chars)
        self.assertFalse(res.has_2048_words)
        self.assertEqual(res.num_words, 4)
        self.assertEqual(res.err_lines, [])

        # We are going to load the english wordlist from the current folder
        # and also from the BIP Github repo.
        # Test fails if exceptions are thrown.
        with open('./tests/english.txt') as f:
            bip39 = BIP39WordList("file_list", handle=f)
        res = bip39.test_lowercase()

        # We only need to test this logic once.
        self.assertTrue(res.has_2048_words)
        self.assertEqual(res.num_words, 2048)

        bip39 = BIP39WordList(
            "url_list",
            url=
            "https://raw.githubusercontent.com/bitcoin/bips/master/bip-0039/english.txt"
        )

        try:
            bip39 = BIP39WordList("no_list")  # This should not work!
            self.fail()
        except ValueError as e:
            pass
        except InvalidWordList as e:
            pass
コード例 #7
0
 def test_getwordpairs_eq(self):
     bip39 = BIP39WordList("levdist_le2", string=levdist_le2)
     try:
         res = bip39.test_lev_distance(2)
     except ValidationFailed as e:
         res = e.status_obj
     expected_res = [("brol", "brow")]
     self.assertEqual(expected_res, res.getwordpairs_eq(1))
     try:
         res.getwordpairs_eq(2)
         self.fail()
     except AssertionError as e:
         pass
コード例 #8
0
 def test_getlinepairs_gt(self):
     bip39 = BIP39WordList("levdist_gt2", string=levdist_gt2)
     try:
         res = bip39.test_lev_distance(2)
     except ValidationFailed as e:
         res = e.status_obj
     expected_res = [(1, 2)]
     self.assertEqual(expected_res, res.getlinepairs_gt(2))
     try:
         res.getlinepairs_gt(0)
         self.fail()
     except AssertionError as e:
         pass
コード例 #9
0
 def test_getwords_gt(self):
     bip39 = BIP39WordList("maxlength_l4", string=maxlength_l4)
     try:
         res = bip39.test_max_length(1)
     except ValidationFailed as e:
         res = e.status_obj
     expected_res = ["block", "blocks"]
     self.assertEqual(expected_res, res.getwords_gt(4))
     for t in [0, ""]:
         try:
             res.getwords_gt(t)
             self.fail()
         except AssertionError as e:
             pass
コード例 #10
0
 def test_getlines_list(self):
     bip39 = BIP39WordList("maxlength_l4", string=maxlength_l4)
     try:
         res = bip39.test_max_length(1)
     except ValidationFailed as e:
         res = e.status_obj
     expected_res = [4, 1]
     self.assertEqual(expected_res, res.getlines_list([3, 6]))
     for t in ["abc", [], ["a"], 0]:
         try:
             res.getlines_list(t)
             self.fail()
         except AssertionError as e:
             pass
コード例 #11
0
 def test_similargroup_many(self):
     bip39 = BIP39WordList("inituniq_4group_l3", string=inituniq_4group_l3)
     res = bip39.test_initial_chars(3)
     expected_res = {
         "qu": [("quick", 1), ("quote", 2)],
         "ri": [("rich", 4), ("risk", 3)]
     }
     self.assertEqual(expected_res, res.similargroup_many(["qu", "ri"]))
     for t in ["abc", [], ["a"], 0]:
         try:
             res.similargroup_many(t)
             self.fail()
         except AssertionError as e:
             pass
コード例 #12
0
 def test_getdist_all(self):
     bip39 = BIP39WordList("levdist_le2", string=levdist_le2)
     try:
         res = bip39.test_lev_distance(2)
     except ValidationFailed as e:
         res = e.status_obj
     expected_res = [(("brol", "brow"), (2, 1), 1)]
     self.assertEqual(expected_res, res.getdist_all("brow"))
     for t in [1, "", "ABC"]:
         try:
             res.getdist_all(t)
             self.fail()
         except AssertionError as e:
             pass
コード例 #13
0
 def test_getdist(self):
     bip39 = BIP39WordList("levdist_le2", string=levdist_le2)
     try:
         res = bip39.test_lev_distance(2)
     except ValidationFailed as e:
         res = e.status_obj
     expected_res = 1
     self.assertEqual(expected_res, res.getdist("brow", "brol"))
     for t in [(1, "abc"), ("", "abc"), ("ABC", "abc"),
               ("abc", 1), ("abc", ""), ("abc", "ABC")]:
         try:
             res.getdist(*t)
             self.fail()
         except AssertionError as e:
             pass
コード例 #14
0
 def test_getwordpairs_list(self):
     concat = "\n".join([levdist_le2]+["zzyzx"])
     bip39 = BIP39WordList("levdist_concat", string=concat)
     try:
         res = bip39.test_lev_distance(2)
     except ValidationFailed as e:
         res = e.status_obj
     expected_res = [("brol", "brow")]
     self.assertEqual(expected_res, res.getwordpairs_list([1,2]))
     for t in ["abc", [], ["a"], 0]:
         try:
             res.getwordpairs_list(t)
             self.fail()
         except AssertionError as e:
             pass
コード例 #15
0
 def test_getdist_all_list(self):
     concat = "\n".join([levdist_le2]+["zzyzx"])
     bip39 = BIP39WordList("concat", string=concat)
     try:
         res = bip39.test_lev_distance(2)
     except ValidationFailed as e:
         res = e.status_obj
     expected_res = [(("brol", "brow"), (2, 1), 1)]
     self.assertEqual(expected_res, res.getdist_all_list("brow", [1]))
     for t in [1, "", "ABC"]:
         for u in ["abc", [], ["a"], 0]:
             try:
                 res.getdist_all_list(t, u)
                 self.fail()
             except AssertionError as e:
                 pass
             except KeyError as e:
                 pass
コード例 #16
0
 def test_getdist_all_gt(self):
     bip39 = BIP39WordList("levdist_gt2", string=levdist_gt2)
     try:
         res = bip39.test_lev_distance(2)
     except ValidationFailed as e:
         res = e.status_obj
     expected_res = [(("brpyt", "brown"), (2, 1), 3)]
     self.assertEqual(expected_res, res.getdist_all_gt("brown", 2))
     for t in [1, "", "ABC"]:
         try:
             res.getdist_all_gt(t, 1)
             self.fail()
         except AssertionError as e:
             pass
     try:
         res.getdist_all_gt("abc", 0)
         self.fail()
     except AssertionError as e:
         pass
     except KeyError as e:
         pass
コード例 #17
0
def main():
    log_file = None
    try:
        parser = argparse.ArgumentParser(
            formatter_class=argparse.RawTextHelpFormatter,
            description='BIP39 wordlist validator')
        parser.add_argument('input', type=str, help='path to the input file')
        parser.add_argument('-d',
                            '--min-levenshtein-distance',
                            dest='lev_dist',
                            default=default_lev,
                            type=int,
                            help='set the minimum required \
  Levenshtein distance between words (default: {})'.format(default_lev))
        parser.add_argument('-u',
                            '--max-initial-unique',
                            dest='init_uniq',
                            default=default_init_uniq,
                            type=int,
                            help='set the maximum \
  required unique initial characters between words (default: {})'.format(
                                default_init_uniq))
        parser.add_argument('-l',
                            '--max-length',
                            dest='max_length',
                            default=default_max_length,
                            type=int,
                            help='set the maximum length of \
  each word (default: {})'.format(default_max_length))
        parser.add_argument('-D',
                            '--no-levenshtein-distance',
                            dest='no_lev_dist',
                            help='do not run the Levenshtein distance test',
                            action='store_true')
        parser.add_argument(
            '-U',
            '--no-initial-unique',
            dest='no_init_uniq',
            help='do not run the unique initial characters test',
            action='store_true')
        parser.add_argument('-L',
                            '--no-max-length',
                            dest='no_max_length',
                            help='do not run the maximum length test',
                            action='store_true')
        parser.add_argument(
            '-o',
            '--output-file',
            type=str,
            dest='output',
            help='logs all console output to an additional file')
        parser.add_argument(
            '-a',
            '--ascii',
            dest='ascii',
            help='turn off rich text formatting and progress bars for console \
  output',
            action='store_true')
        parser.add_argument(
            '-q',
            '--quiet',
            dest='quiet',
            help='do not display details of test failures, only whether they \
  succeeded or failed',
            action='store_true')
        parser.add_argument(
            '--nosane',
            dest='nosane',
            action='store_true',
            help=
            'Suppress wordlist sanity check. This might cause other tests to fail.'
        )
        parser.add_argument(
            '--debug',
            dest='debug',
            action='store_true',
            help='turn on debugging mode (intended for developers)')
        parser.add_argument(
            '--pycharm-debug',
            dest='pycharm_debug',
            action='store_true',
            help=
            're-raise exceptions out of main() to Pycharm (intended for developers)'
        )
        parser.add_argument('-v',
                            '--version',
                            action='version',
                            version=version_str())

        args = parser.parse_args()

        # If there is an output file, then attempt to open it.
        if args.output:
            try:
                absout = abspath(args.output)
                # Set the ascii flag if desired before printing this
                setargs(None, args)
                logdefault("Attempting to open log file {} for writing".format(
                    absout))
                log_file = open(absout, 'w')
                setargs(log_file, args)
            except OSError as e:
                logerror("open {} for writing failed: {}".format(
                    e.filename, e.strerror))
                abort(args.debug)
        else:
            setargs(None, args)

        # Now validate the parameters
        if args.lev_dist <= 0:
            logerror("Invalid value for --min-levenshtein-distance {}".format(
                args.lev_dist))
            abort(args.debug)
        if args.init_uniq <= 0:
            logerror("Invalid value for --min-initial-unique {}".format(
                args.init_uniq))
            abort(args.debug)
        if args.max_length <= 0:
            logerror("Invalid value for --max-length {}".format(
                args.max_length))
            abort(args.debug)

        try:
            valid_url = validators.url(args.input)
            if valid_url:
                kwargs = {'url': args.input}
                logdefault("Reading wordlist URL {}".format(args.input))
            else:
                f = open(args.input)
                kwargs = {'handle': f}
                logdefault("Reading wordlist file {}".format(args.input))
            try:
                bip39 = BIP39WordList(desc=f"{args.input}", **kwargs)
                loginfo("{} words read".format(len(bip39)))
            except InvalidWordList as e:
                handle_invalid_wordlist(args, e)
            if not valid_url:
                f.close()
        except OSError as e:
            logerror("Cannot read {}: {}".format(e.filename, e.strerror))
            abort(args.debug)

        tally = 0
        total = 4 - int(args.no_lev_dist) - int(args.no_init_uniq)\
                - int(args.no_max_length)

        logdefault("Checking wordlist for invalid characters")
        try:
            tup = bip39._test_lowercase_1()
            kwargs = tup[3]
            kwargs = progressbar('Looking for invalid characters', tup[0],
                                 tup[1], tup[2], **kwargs)
            validity = bip39._test_lowercase_2(kwargs)
            check_validity_warnings(validity)
            tally += 1
            loginfo("Valid characters test succeeded")
        except InvalidWordList as e:
            handle_invalid_wordlist(args, e)
            if args.nosane:
                logwarning(
                    "Valid characters test failed, but --nosane passed; ignoring error"
                )

        logdefault("Finished checking wordlist for invalid characters")
        separator()

        if not args.no_lev_dist:
            logdefault("Performing Levenshtein distance test")
            try:
                tup = bip39._test_lev_distance_1(n=args.lev_dist)
                kwargs = tup[3]
                kwargs = progressbar('Computing Levenshtein distance', tup[0],
                                     tup[1], tup[2], **kwargs)
                bip39._test_lev_distance_2(kwargs)
                loginfo("No word pairs with Levenshtein distance less than {}" \
                            .format(args.lev_dist))
                tally += 1
                loginfo("Levenshtein distance test succeeded")
            except ValidationFailed as e:
                lev_dist = e.status_obj
                word_pairs = lev_dist.getwordpairs_lt()
                logerror("{} word pairs with Levenshtein distance less than {}\n" \
                             .format(len(word_pairs), args.lev_dist))
                for i in range(1, args.lev_dist):
                    words_list = [
                        *zip(lev_dist.getwordpairs_eq(i),
                             lev_dist.getlinepairs_eq(i))
                    ]
                    logerror("{} word pairs with Levenshtein distance *equal* to {}:" \
                                 .format(len(words_list), i))
                    for words, lines in words_list:
                        logerror("    \"{}\" (line {}) <--> \"{}\" (line {})" \
                                    .format(words[0], lines[0], words[1], lines[1]))
                    logerror("")
                logerror(
                    "{} total words below minimum Levenshtein distance".format(
                        len(word_pairs)))
                logerror("Levenshtein distance test failed")

            logdefault("Finished performing Levenshtein distance test")
            separator()

        if not args.no_init_uniq:
            logdefault("Performing unique initial characters test")
            try:
                tup = bip39._test_initial_chars_1(n=args.init_uniq)
                kwargs = tup[3]
                kwargs = progressbar('Checking initial characters', tup[0],
                                     tup[1], tup[2], **kwargs)
                bip39._test_initial_chars_2(kwargs)
                loginfo("All words are unique to {} initial characters".format(
                    args.init_uniq))
                tally += 1
                loginfo("Unique initial characters test succeeded")
            except ValidationFailed as e:
                similar = e.status_obj
                # Filter out groups with just one word in them as those are unique
                groups = similar.groups_length(args.init_uniq)
                logerror("{} groups of similar words (by {} initial characters)\n" \
                             .format(len(groups.items()), args.init_uniq))
                for pre, group in groups.items():
                    logerror("Similar words with prefix \"{}\":".format(pre))
                    for wordline in group:
                        logerror("    \"{}\" (line {})".format(
                            wordline[0], wordline[1]))
                    logerror("")
                logerror("{} total similar words".format(len(groups.keys())))
                logerror("Unique initial characters test failed")
        logdefault("Finished unique initial characters test")
        separator()

        if not args.no_max_length:
            logdefault("Performing maximum word length test")
            try:
                tup = bip39._test_max_length_1(n=args.max_length)
                kwargs = tup[3]
                kwargs = progressbar('Checking length', tup[0], tup[1], tup[2],
                                     **kwargs)
                bip39._test_max_length_2(kwargs)
                loginfo("Length of all words are {} chracters or less".format(
                    args.max_length))
                tally += 1
                loginfo("Maximum word length test succeeded")
            except ValidationFailed as e:
                lengths = e.status_obj
                words = lengths.getwords_gt(args.max_length)
                lines = lengths.getlines_gt(args.max_length)
                logerror("Words longer than {} characters:".format(
                    args.max_length))
                for word, line in [*zip(words, lines)]:
                    logerror("    \"{}\" (line {})".format(word, line))
                logerror("{} words longer than {} characters".format(
                    len(lengths), args.max_length))
                logerror("Maximum word length test failed")
        logdefault("Finished maximum word length test")
        separator()

        logdefault("{} of {} checks passed".format(tally, total))
        if log_file:
            log_file.close()
        exit(0)
    except Exception as e:
        print("Got unknown exception {}: {}".format(type(e), str(e)))
        if args.pycharm_debug:
            raise e
        else:
            abort(args.debug)
コード例 #18
0
 def test_test_max_length(self):
     with open('./tests/english.txt') as f:
         bip39 = BIP39WordList("file_list", handle=f)
         bip39.test_initial_chars(4)