#!/usr/bin/env python3 """Test eddycoin_seed.py against the official BIP39 (trezor/python-mnemonic vectors.json, English, passphrase TREZOR) and SLIP-0010 nist256p1 test vectors; compare with the reference 'mnemonic' package if installed. Prints no secrets of real wallets.""" import json, os, sys HERE = os.path.dirname(os.path.abspath(__file__)); sys.path.insert(0, os.path.join(HERE, "..")) import eddycoin_seed as S res = {} V = json.load(open(os.path.join(HERE, "bip39_vectors_official.json")))["english"] ok = 0 for ent, words, seed, _xprv in V: assert S.entropy_to_words(bytes.fromhex(ent)) == words, ent assert S.check(words, (12, 15, 18, 21, 24)) == words assert S.to_seed(words, "TREZOR").hex() == seed, ent ok += 1 res["bip39_official_vectors"] = "%d/%d" % (ok, len(V)) # SLIP-0010 nist256p1 vectors (private key + chain code at every level) SL = [("000102030405060708090a0b0c0d0e0f", [ ("m", "beeb672fe4621673f722f38529c07392fecaa61015c80c34f29ce8b41b3cb6ea", "612091aaa12e22dd2abef664f8a01a82cae99ad7441b7ef8110424915c268bc2"), ("m/0'", "3460cea53e6a6bb5fb391eeef3237ffd8724bf0a40e94943c98b83825342ee11", "6939694369114c67917a182c59ddb8cafc3004e63ca5d3b84403ba8613debc0c"), ("m/0'/1", "4187afff1aafa8445010097fb99d23aee9f599450c7bd140b6826ac22ba21d0c", "284e9d38d07d21e4e281b645089a94f4cf5a5a81369acf151a1c3a57f18b2129"), ("m/0'/1/2'", "98c7514f562e64e74170cc3cf304ee1ce54d6b6da4f880f313e8204c2a185318", "694596e8a54f252c960eb771a3c41e7e32496d03b954aeb90f61635b8e092aa7"), ("m/0'/1/2'/2", "ba96f776a5c3907d7fd48bde5620ee374d4acfd540378476019eab70790c63a0", "5996c37fd3dd2679039b23ed6f70b506c6b56b3cb5e424681fb0fa64caf82aaa"), ("m/0'/1/2'/2/1000000000", "b9b7b82d326bb9cb5b5b121066feea4eb93d5241103c9e7a18aad40f1dde8059", "21c4f269ef0a5fd1badf47eeacebeeaa3de22eb8e5b0adcd0f27dd99d34d0119")]), ("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542", [ ("m", "96cd4465a9644e31528eda3592aa35eb39a9527769ce1855beafc1b81055e75d", "eaa31c2e46ca2962227cf21d73a7ef0ce8b31c756897521eb6c7b39796633357"), ("m/0", "84e9c258bb8557a40e0d041115b376dd55eda99c0042ce29e81ebe4efed9b86a", "d7d065f63a62624888500cdb4f88b6d59c2927fee9e6d0cdff9cad555884df6e"), ("m/0/2147483647'", "f235b2bc5c04606ca9c30027a84f353acf4e4683edbd11f635d0dcc1cd106ea6", "96d2ec9316746a75e7793684ed01e3d51194d81a42a3276858a5b7376d4b94b9"), ("m/0/2147483647'/1", "7c0b833106235e452eba79d2bdd58d4086e663bc8cc55e9773d2b5eeda313f3b", "974f9096ea6873a915910e82b29d7c338542ccde39d2064d1cc228f371542bbc")]), ("000102030405060708090a0b0c0d0e0f", [ # derivation retry ("m/28578'", "e94c8ebe30c2250a14713212f6449b20f3329105ea15b652ca5bdfc68f6c65c2", "06f0db126f023755d0b8d86d4591718a5210dd8d024e3e14b6159d63f53aa669"), ("m/28578'/33941", "9e87fe95031f14736774cd82f25fd885065cb7c358c1edf813c72af535e83071", "092154eed4af83e078ff9b84322015aefe5769e31270f62c3f66c33888335f3a")]), ("a7305bc8df8d0951f0cb224c0e95d7707cbdf2c6ce7e8d481fec69c7ff5e9446", [ # seed retry ("m", "7762f9729fed06121fd13f326884c82f59aa95c57ac492ce8c9654e60efd130c", "3b8c18469a4634517d6d0b65448f8e6c62091b45540a1743c5846be55d47d88f")])] n = 0 for seed, chain in SL: for path, cc, priv in chain: k, c = S.derive(bytes.fromhex(seed), path) assert c.hex() == cc and k.to_bytes(32, "big").hex() == priv, (seed[:8], path) n += 1 res["slip10_nist256p1_vectors"] = "%d/%d" % (n, n) # bad words for bad, why in (("abandon " * 23 + "abandon", "checksum"), ("abandon " * 23 + "zzzz", "not in"), ("abandon " * 12, "expected")): try: S.check(bad); raise AssertionError("accepted bad words") except S.BadWords as e: assert why in str(e), str(e) res["bad_words_rejected"] = True for _ in range(50): w = S.generate(); assert len(w.split()) == 24 and S.check(w) == w res["generate_24_words_valid_x50"] = True try: from mnemonic import Mnemonic M = Mnemonic("english") for _ in range(20): w = S.generate(); assert M.check(w) and M.to_seed(w, "x y") == S.to_seed(w, "x y") res["matches_reference_mnemonic_pkg"] = True except ImportError: res["matches_reference_mnemonic_pkg"] = "skipped (package not installed)" print(json.dumps(res, indent=1)); print("OVERALL PASS")