diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..74b5505 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,25 @@ +name: Test Python package + +on: [push, pull_request] + +jobs: + build: + env: + OPENSSL_CONF: ${{ github.workspace }}/config/openssl.cnf + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10"] + steps: + - name: checkout repo + uses: actions/checkout@v4 + - name: set up python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: install + run: make install + - name: lint + run: make check + - name: pytest + run: make test diff --git a/.gitignore b/.gitignore index bee8a64..b93d119 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ __pycache__ +.DS_Store +*.egg-info diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000..f238bf7 --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,2 @@ +[settings] +profile = black diff --git a/LICENSE.md b/LICENSE.md index 93dd837..f49a4e1 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,21 +1,201 @@ -MIT License - -Copyright (c) 2023 Aneesh Karve - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Makefile b/Makefile index 19ed3ed..db174a8 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,25 @@ +.PHONY: check install install-go lint test test-network + +check: + black . --check + isort . --check + +# developer install only +install: + pip install -r requirements.txt -r test-requirements.txt + pip install -e . + +install-go: + # you must have go installed https://go.dev/doc/install + go install github.com/rhysd/actionlint/cmd/actionlint@latest + +lint: + isort . + black . + actionlint + test: - python -m pytest tests/test.py -m "not network" -sx + python -m pytest tests -m "not network" -x -test-on: - python -m pytest tests/test.py \ No newline at end of file +test-network: + python -m pytest tests \ No newline at end of file diff --git a/README.md b/README.md index 12ff06c..fdd425c 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,241 @@ -# BIP-39 Mnemonic Seed Generator in Python +# `bipsea`: unlimited cryptographic entropy for Bitcoin, passwords, and other secrets -## Disclaimer +> _One Seed to rule them all, +> One Key to find them, +> One Path to bring them all, +> And in cryptography bind them._ +> —[BIP-85](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki) -This is **BETA SOFTWARE**. Use it at your own risk. +bipsea is a standalone, unit-tested implementation of BIP-85 and BIP-32. +bipsea is designed for readability and security. bipsea offers a command-line +interface and an API. -Please carefully test and ensure that generated seeds work as -desired before trusting large quantities of coin to its mnemonics. +bipsea relies on cryptographic primitives from Python `secrets`, `hashlib`, and +the external [python-ecdsa](https://github.com/tlsfuzzer/python-ecdsa). +bipsea does not rely on third-party libraries from any wallet vendor. -Or, better yet, read the code and see if you think it's correct -(*pull requests welcome*). +You can run bipsea offline on to generate general-use passwords, Bitcoin seed words, +and more. Consider dedicated cold hardware that runs [Tails](https://tails.net), +never has network access, and disables +[Intel Management Engine](https://support.system76.com/articles/intel-me/) +and other possible backdoors. -## Why another mnemonic generator? +# How is this useful? -I created this repo for myself because all prior code I found for -generating seed words was incomplete, opaque, and difficult to trust. +BIP-85 is the foundation for a next generation password manager that enables you +to protect and store a _single_ master secret that can derive _millions of independent, multi-purpose secrets_. -This repo is designed to be a correct, transparent, and trustworthy -implementation of BIP-39 that you can verify for yourself and then -use it to **generate or checksum your own seedwords offline**. +BIP-85 offers the following benefits: +* The security of numerous independent passwords with the operational efficiency +of a single master password. (The master secret can be multi-factor.) +* Uses Bitcoin's well-tested hierarchical deterministic wallet +tree (including primitives like ECDSA and hardened children) +* Can generate millions of new Bitcoin wallet seed words and master keys +* Can generate millions of new passwords from a single master root key (xprv) +and a short derivation path. -### What was wrong with prior seed generators? +Unlike a password manager, which protects many secrets with one hot secret, +BIP-85 _derives_ many secrets from one protected secret. Therefore you only need +to back up the derivation paths and the services they are for. You do not need to +back up the derived secrets. -* Outdated (e.g. Python 2) -* Poorly commented (or not commented at all) -* Incomplete (e.g. didn't include checksum calculation) -* Ran in a browser :( -* Didn't use a cryptographically strong source of entropy +You could safely store all derivation paths in a hot password manager +like Keychain. You could even store the derived secrets in a hot password manager +at no risk to the master private key. -> I later found Trezor's [mnemonic](https://github.com/trezor/python-mnemonic/tree/master) -> which is close to what I wanted but I still find this repo code easier to read -> (and use on the CLI). We now use mnemonic as an oracle for testing. +> Note: bipsea alone is not password manager, but you might use it to implement one. -## Pre-requisites -* Python 3.x +# How does it work? -### Installation -* Clone this repo -* `pip install -r requirements.txt` +The root of your BIP-85 password tree is a standard Bitcoin master private key (xprv). -## Usage +> In general, you _should not use a wallet seed with funds in it_. +> In any case, fresh seeds are free and easy to generate with bipsea. + +The master key then uses the BIP-32 derivation tree with a clever twist: the +derivation path includes a purpose code (`83696968'`) followed by an _application_ +code. In this way, each unique derivation path produces a unique, independent, +and secure _derived entropy_ as a pure function of the master private key and the +derivation path. + +BIP-85 specifies a variety of application codes including the following: + +| application code | description | +|------------------|-------------| +| `39'` | as in BIP-39, to generate seed words | +| `2'` | for HD-Seed wallet import format ([WIF](https://en.bitcoin.it/wiki/Wallet_import_format)) | +| `32'` | as in BIP-32, to generate extended private keys (xprv) | +| `128169'` | for 16 to 64 bytes of random hex | +| `707764'` | for 20 to 86 characters of a base64 password | +| `707785'` | for 10 to 80 characters of a base85 password | + +bipsea implements all of the above applications plus the BIP-85 discrete random +number generator (DRNG). bipsea does not implement the RSA application codes from +BIP-85 but you could potentially use the DRNG for RSA and similar applications. + +## Example derivation path + +Consider `m/83696968'/707764'/10'/0'`. It produces the password +`dKLoepugzd` according to the following logic: + +| path segment | description | +|--------------|-------------------------------------------| +| `m` | master private key | +| `83696968'` | purpose code for BIP-85 | +| `707764'` | application code for base64 password | +| `10'` | number of password characters | +| `0'` | index, 0 to 2³¹ - 1 for millions of unique passwords | + +> `'` denotes hardened child derivation, recommended for all BIP-85 applications. +_Hardened_ derivation means that, even if both the parent public key and the child +private key are exposed, the parent private key remains secure. + +## BIP-32 hierarchical deterministic wallet tree + +![](imgs/derivation.png) + +## How do I know the bipsea implementation is correct? + +bipsea passes all BIP-32 and BIP-85 test vectors with the following provisos: +* Only generates seed phrases in English +* Fails a single partial test for derived entropy (but passes all others) from BIP-85 + +### TODO + +* [ ] File the above and other clarification issues to BIP-85 + +Run `make test` for details. ```sh -# see commands -python seedwords.py --help -# generate 15 seed words at random (with checksum in final word) -python seedwords.py --nwords 15 +pip install bipsea ``` -### Verifying the word list for yourself +# Developer + +``` +make install +make install-go # requires go +make test +``` + +See [Makefile](./Makefile) for more commands. + + +# Usage + +``` +bipsea --help +``` + +## `bipsea seed` + +### New seed words ```sh -curl -o english_source.txt https://raw.githubusercontent.com/bitcoin/bips/master/bip-0039/english.txt +bipsea seed -n 12 --pretty +``` + 1) crumble + 2) shallow + 3) hair + 4) federal + 5) cycle + 6) grid + 7) million + 8) twist + 9) turn + 10) verb + 11) orphan + 12) suggest + +### xprv from existing seed words + +``` +bipsea seed -f words -i "airport letter idea forget broccoli prefer panda food delay struggle ridge salute above want dinner" -t xprv +``` + xprv9s21ZrQH143K3YwuXcacSSghcUfrrEyj9hTHU3a2gmr6SzPBaxmuTgKGBWtFdnnCjwGYMkU7mLvxba8FFPGLQUMvyACZTEdSCJ8uBwh5Aqs + +## xprv from dice rolls (or any string) +``` +bipsea seed -f string -i "123456123456123456" -t xprv +``` + Stretching 144 bits of entropy to 256 bits. Better to provide more entropy. + xprv9s21ZrQH143K35QDSCrHfhTJNQGS8ehYV74s65pMwTHfHq89oqcqVQJU4iD3B2M68skmz32eT8Kdr1thXJ6tHXRpy77QtAN1dhEdvqYPiVm + +This is similar to how [coldcard implements verifiable dice rolls](https://coldcard.com/docs/verifying-dice-roll-math/). +If you are now thinking, _I could use any string to derive a master key_, +then you get it. And we haven't even gottent into BIP-85. + +> That said, **do not get cute and derive valuable keys or secrets from short +> strings**. You can only stretch entropy so far. **Weak entropy in, weaker entropy out**. +> Short, common strings are also susceptible to +[rainbow table attacks](https://en.wikipedia.org/wiki/Rainbow_table). + + +## `bipsea entropy` + +`bipsea entropy` requires you to pipe in an xprv. + +### base64 password -shasum -a 256 english_source.txt -shasum -a 256 english.txt ``` +bipsea seed -t xprv | bipsea entropy -a base85 -n 10 +``` + C(s>@zBUg8 + +Increment the index to get a fresh password. -## Project goals +``` +bipsea seed -t xprv | bipsea entropy -a base85 -n 10 -i 1 +``` + s#c+vT_jpP -* [x] Click CLI utility -* [x] Use Python `secrets` for strong random behavior where possible -* [x] Add Unit tests -* [x] Investigate [embit](https://github.com/diybitcoinhardware/embit/blob/master/src/embit/bip39.py) +Alternatively you can pipe in an existing xprv: + +``` +echo "$myxprv" | bipsea entropy -a base85 -n 10 +``` -## Sources +### Derived seed words -* Implemented according to [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki). -* BIP39 word list from [bips/bip-0039](https://github.com/bitcoin/bips/tree/master/bip-0039). +``` +bipsea seed -t xprv | bipsea entropy -a words +``` + loan height quality library maid defense minor token thought music claim actual hour ship robust burst live broccoli + +### DRNG, enter the matrix + +``` +bipsea seed -t xprv | bipsea entropy -a drng -n 10000 +``` + <10K hex chars from the DRNG> + +# For the curious and paranoid + +BIP-85 derives the entropy for each application by computing an HMAC of the private +ECDSA key of the last hardened child. Private child keys are pure functions of the +parent key and the child index (one segment in the derivation path). In this way +BIP-85 entropy is hierarchical, deterministic, and irreversibly hardened as long +as ECDSA remains secure. ECDSA is believed to be secure but no one knows for sure. +Moreover, we may never be able to prove that ECDSA is secure or insecure if, +for example, "P is not equal to NP" is unprovable. + +ECDSA is not [post-quantum secure](https://blog.cloudflare.com/pq-2024). +If someone somewhere creates a quant computer with sufficient logical q-bits +to run Shor's algorithm on large keys, then ECDSA private keys can be +reverse-engineered from public keys. As unlikely as the emergence of a quantum +computer may seem, the Chromium team is +[taking no chances](https://blog.chromium.org/2024/05/advancing-our-amazing-bet-on-asymmetric.html) +and has begun to roll out quantum-resistant changes to SSL. + +All of that to say **even the hardest cryptography falls to the problem of induction**: + +> Just because no one broke has broken ECDSA yet doesn't mean no one will break it tomorrow. + +# References + +1. [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) +hierarchical deterministic wallets +1. [BIP-85](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki) +generalized cryptographic entropy +1. [BIP-44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) +generalized BIP-32 paths diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bip32.py b/bip32.py new file mode 100644 index 0000000..a36183a --- /dev/null +++ b/bip32.py @@ -0,0 +1,262 @@ +""" +Complete implementation of BIP-32 hierarchical deterministic wallets. +https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki HDW +""" + +import hashlib +import hmac +import logging +from typing import List + +from ecdsa import SECP256k1, SigningKey, VerifyingKey +from ecdsa.keys import MalformedPointError + +from bip32types import VERSIONS, ExtendedKey +from util import LOGGER + +logger = logging.getLogger(LOGGER) + + +# same count for hardened and unhardened children +TYPED_CHILD_KEY_COUNT = 2**31 + + +def to_master_key(seed: bytes, mainnet: bool, private: bool) -> ExtendedKey: + master = hmac_sha512(key=b"Bitcoin seed", data=seed) + secret_key = master[:32] + chain_code = master[32:] + pub_key = to_public_key(bytes(1) + secret_key) + + return ExtendedKey( + version=VERSIONS["mainnet" if mainnet else "testnet"][ + "private" if private else "public" + ], + depth=bytes(1), + finger=bytes(4), + child_number=bytes(4), + chain_code=chain_code, + data=bytes(1) + secret_key if private else pub_key, + ) + + +def derive_key(master: ExtendedKey, path: List[str], private: bool): + """master: extended private key""" + indexes = [segment_to_index(s) for s in path[1:]] + key_chain = [ + ( + master + if indexes or private + else N( + master.data, + master.chain_code, + master.child_number, + depth=bytes(1), + finger=master.finger, + version=VERSIONS[master.get_network()]["public"], + ) + ) + ] + for depth, (index, _) in enumerate(indexes, 1): + parent = key_chain[-1] + key_chain.append( + CKDpriv( + parent.data, + parent.chain_code, + index, + depth.to_bytes(1, "big"), + version=parent.version, + ) + ) + # only use N() or CKDpub() if public at the highest depth (final segment) + # so as to avoid complex, hard-to-read flow control with look-ahead since once + # we harden a child anywhere in the chain we can't recover the private key + if private or not indexes: + return key_chain[-1] + else: + last_is_hardened = indexes[-1][1] + parent = key_chain[-1] + if last_is_hardened: + # N() is not a true derivation so just neuter the very last private key + return N( + parent.data, + parent.chain_code, + parent.child_number, + parent.depth, + finger=parent.finger, + version=VERSIONS[parent.get_network()]["public"], + ) + else: + # CKDpub() is a true derivation so go to grandparent as parent + grand_parent = key_chain[-2] + return CKDpub( + to_public_key(grand_parent.data), + grand_parent.chain_code, + parent.child_number, + parent.depth, + finger=parent.finger, + version=VERSIONS[parent.get_network()]["public"], + ) + + +def CKDpriv( + secret_key: bytes, + chain_code: bytes, + child_number: int, + depth: bytes, + version: bytes, +) -> ExtendedKey: + hardened = child_number >= TYPED_CHILD_KEY_COUNT + secret_int = int.from_bytes(secret_key[1:], "big") + data = ( + secret_key + if hardened + else VerifyingKey.from_public_point( + secret_int * SECP256k1.generator, + curve=SECP256k1, + ).to_string("compressed") + ) + while True: + derived = hmac_sha512( + key=chain_code, data=data + child_number.to_bytes(4, "big") + ) + if validate_derived_key(derived): + break + else: + child_number += 1 + if hardened: + assert child_number < 2**32 + else: + assert child_number < TYPED_CHILD_KEY_COUNT + + child_key_int = ( + int.from_bytes(derived[:32], "big") + int.from_bytes(secret_key, "big") + ) % SECP256k1.order + child_key = bytes(1) + child_key_int.to_bytes(32, "big") + + return ExtendedKey( + version=version, + depth=depth, + finger=fingerprint(secret_key), + child_number=child_number.to_bytes(4, "big"), + chain_code=derived[32:], + data=child_key, + ) + + +def N( + private_key: bytes, + chain_code: bytes, + child_number: bytes, + depth: bytes, + finger: bytes, + version: bytes, +) -> ExtendedKey: + """neuter a private key into the public one (no derivation per se) + pass in the fingerprint since it is from the parent (which we don't have) + """ + return ExtendedKey( + version=version, + depth=depth, + finger=finger, + child_number=child_number, + chain_code=chain_code, + data=to_public_key(private_key), + ) + + +def CKDpub( + public_key: bytes, + chain_code: bytes, + child_number: bytes, + depth: bytes, + finger: bytes, + version: bytes, +) -> ExtendedKey: + child_number_int = int.from_bytes(child_number, "big") + if child_number_int >= TYPED_CHILD_KEY_COUNT: + raise ValueError(f"Cannot call CKDpub() for hardened child: {child_number_int}") + + parent_key = VerifyingKey.from_string(public_key, curve=SECP256k1).pubkey.point + while True: + derived = hmac_sha512(key=chain_code, data=public_key + child_number) + derived_key = int.from_bytes(derived[:32], "big") + derived_chain_code = derived[32:] + if derived_key >= SECP256k1.order: + child_number += 1 + assert child_number < TYPED_CHILD_KEY_COUNT, "exhausted available children" + continue + child_point = SECP256k1.generator * derived_key + parent_key + try: + child_key = VerifyingKey.from_public_point( + child_point, + curve=SECP256k1, + ).to_string("compressed") + except MalformedPointError as m: + # Is this in fact how we detect the point at infinity? + logger.warning( + "Point at infinity? Retrying with higher child_number in CKDPub()", m + ) + child_number += 1 + continue + break + + return ExtendedKey( + version=version, + depth=depth, + finger=finger, + child_number=child_number_int.to_bytes(4, "big"), + chain_code=derived_chain_code, + data=child_key, + ) + + +def to_public_key(secret_key: bytes, as_point=False): + """returns compressed ecdsa public key""" + # ecdsa from_/to_string are actually from_/to_bytes b/c of some kind of + # Python 2 hangover + assert len(secret_key) == 33 + # chop the first byte 0x00 else ECDSA will throw + private_key = SigningKey.from_string(secret_key[1:], curve=SECP256k1) + public_key = private_key.get_verifying_key() + compressed = public_key.to_string("compressed") + + return compressed + + +def segment_to_index(segment: str) -> (bytes, bool): + """for internal (non-m) derivation path segments which should all be integers + once the optional hardened symbol is dropped""" + # As of BIP-44 we can use ' for hardened paths + # https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki + hardened = segment[-1] in ("h", "H", "'") + if hardened: + segment = segment[:-1] + index = int(segment) + assert index <= (TYPED_CHILD_KEY_COUNT - 1) + if hardened: + index += TYPED_CHILD_KEY_COUNT + + return (index, hardened) + + +def fingerprint(private_key: bytes) -> bytes: + pub_key = to_public_key(private_key) + ripemd = hashlib.new("ripemd160") + ripemd.update(hashlib.sha256(pub_key).digest()) + fingerprint = ripemd.digest()[:4] + + return fingerprint + + +def hmac_sha512(key: bytes, data: bytes) -> bytes: + return hmac.new(key=key, msg=data, digestmod="sha512").digest() + + +def validate_derived_key(key: bytes) -> bool: + assert len(key) == 64 + secret_key = key[:32] + secret_int = int.from_bytes(secret_key, "big") + if (secret_int == 0) or (secret_int >= SECP256k1.order): + return False + + return True diff --git a/bip32types.py b/bip32types.py new file mode 100644 index 0000000..68205cf --- /dev/null +++ b/bip32types.py @@ -0,0 +1,130 @@ +import logging +from collections import namedtuple + +import base58 +from ecdsa import SECP256k1 + +from util import LOGGER + +logger = logging.getLogger(LOGGER) + + +VERSIONS = { + "mainnet": { + "public": bytes.fromhex("0488B21E"), + "private": bytes.fromhex("0488ADE4"), + }, + "testnet": { + "public": bytes.fromhex("043587CF"), + "private": bytes.fromhex("04358394"), + }, +} + + +class ExtendedKey( + namedtuple( + "ExtendedKey", + [ + "version", + "depth", + "finger", + "child_number", + "chain_code", + "data", + ], + ) +): + def get_network(self) -> bool: + # we check integrity elsewhere so not mainnet is enough to mean testnet + return "mainnet" if self.version in VERSIONS["mainnet"].values() else "testnet" + + def is_public(self) -> bool: + return self.data[:1] in ( + bytes.fromhex("02"), + bytes.fromhex("03"), + ) + + def is_private(self) -> bool: + return self.data[:1] == bytes.fromhex("00") + + def __str__(self) -> str: + # return super().__str__() + key_ = ( + self.version + + self.depth + + self.finger + + self.child_number + + self.chain_code + + self.data + ) + return base58.b58encode_check(key_, alphabet=base58.BITCOIN_ALPHABET).decode() + + def __new__( + cls, + version: bytes, + depth: bytes, + finger: bytes, + child_number: bytes, + chain_code: bytes, + data: bytes, + ): + assert len(version) == 4 + assert len(depth) == 1 + assert len(finger) == 4 + assert len(child_number) == 4 + assert len(chain_code) == 32 + assert len(data) == 33 + return super().__new__( + cls, version, depth, finger, child_number, chain_code, data + ) + + +def parse_ext_key(key: str): + """ + master - bip32 extended key, base 58 + """ + master_dec = base58.b58decode_check(key, alphabet=base58.BITCOIN_ALPHABET) + assert len(master_dec) == 78, "expected 78 bytes" + + ext_key = ExtendedKey( + version=master_dec[:4], + depth=master_dec[4:5], # slice so we get bytes, not an int + finger=master_dec[5:9], + child_number=master_dec[9:13], + chain_code=master_dec[13:45], + data=master_dec[45:], + ) + + if True: + matches = 0 + for net in VERSIONS: + for vis in VERSIONS[net]: + if ext_key.version == VERSIONS[net][vis]: + matches += 1 + if net == "mainnet": + assert key.startswith("x") + else: + assert key.startswith("t") + if vis == "public": + assert key[1:4] == "pub" + assert ext_key.is_public() + else: + assert key[1:4] == "prv" + assert ext_key.is_private() + assert matches == 1, f"unrecognized version: {ext_key.version}" + + int_key = int.from_bytes(ext_key.data, "big") + if (int_key < 1) or (int_key >= SECP256k1.order): + raise ValueError(f"Key out of bounds: {ext_key.data}") + depth = int.from_bytes(ext_key.depth, "big") + if depth == 0: + assert ext_key.finger == bytes(4) + assert ext_key.child_number == bytes(4) + else: + assert ext_key.finger != bytes(4) + + assert len(ext_key.version) == 4 + assert len(ext_key.finger) == len(ext_key.child_number) == 4 + assert len(ext_key.data) - 1 == 32 == len(ext_key.chain_code) + + return ext_key diff --git a/bip85.py b/bip85.py new file mode 100644 index 0000000..008061a --- /dev/null +++ b/bip85.py @@ -0,0 +1,170 @@ +import base64 +import hashlib +import logging +import re +from typing import Dict, Union + +import base58 + +from bip32 import VERSIONS, ExtendedKey +from bip32 import derive_key as derive_key_bip32 +from bip32 import hmac_sha512 +from seedwords import entropy_to_words +from util import LOGGER, to_hex_string + +logger = logging.getLogger(LOGGER) + + +HMAC_KEY = b"bip-entropy-from-k" +CODE_39_TO_BITS = { + "12'": 128, + "18'": 192, + "21'": 224, + "24'": 256, +} +LANGUAGE_CODES = { + "English": "0'", + "Japanese": "1'", + "Korean": "2'", + "Spanish": "3'", + "Chinese (Simplified)": "4'", + "Chinese (Traditional)": "5'", + "French": "6'", + "Italian": "7'", + "Czech": "8'", +} +PURPOSE_CODES = {"BIP-85": "83696968'"} + + +def apply_85(derived_key: ExtendedKey, path: str) -> Dict[str, Union[bytes, str]]: + """returns a dict with 'entropy': bytes and 'application': str""" + segments = split_and_validate(path) + purpose = segments[1] + if purpose != PURPOSE_CODES["BIP-85"]: + raise ValueError(f"Not a BIP85 path: {path}") + if len(segments) < 4 or not all(s.endswith("'") for s in segments[1:]): + raise ValueError( + f"BIP-85 paths should have 4+ segments and hardened children: {segments}" + ) + application, *indexes = segments[2:] + + entropy = to_entropy(derived_key.data[1:]) + # BIP 39 + if application == "39'": + language, n_words = indexes[:2] + if not language == LANGUAGE_CODES["English"]: + raise ValueError(f"Only English BIP39 words from BIP85 are supported.") + if not n_words in CODE_39_TO_BITS: + raise ValueError(f"Expected word codes {CODE_39_TO_BITS.keys()}") + n_bytes = CODE_39_TO_BITS[n_words] // 8 + trimmed_entropy = entropy[:n_bytes] + n_words_int = int(n_words[:-1]) # chop the ' from hardened derivation + return { + "entropy": trimmed_entropy, + "application": " ".join(entropy_to_words(n_words_int, trimmed_entropy)), + } + # WIF + elif application == "2'": + trimmed_entropy = entropy[: 256 // 8] + prefix = b"\x80" if derived_key.get_network() == "mainnet" else b"\xef" + suffix = b"\x01" # use with compressed public keys because BIP32 + extended = prefix + trimmed_entropy + suffix + hash1 = hashlib.sha256(extended).digest() + hash2 = hashlib.sha256(hash1).digest() + + return { + "entropy": trimmed_entropy, + "application": base58.b58encode_check(extended), + "checksum": hash2[:4], + } + # XPRV + elif application == "32'": + derived_key = ExtendedKey( + # TODO: file against bip85 that there is no provision to specify + # main vs testnet + # TODO: file against bip85 that they are inconsistent with + # hmac entropy order :shrug: + version=VERSIONS["mainnet"]["private"], + depth=bytes(1), + finger=bytes(4), + child_number=bytes(4), + chain_code=entropy[:32], + data=bytes(1) + entropy[32:], + ) + + return { + # TODO: also file against bip85 that there is no consistency about + # returned entropy length in test vectors? + # TODO: this is wrong on multiple levels; first we use + # 64 bytes from the entropy for this application + # second this isn't even the chain_code which in some universe + # might be considered derived entropy :( + "entropy": entropy[32:], + "application": str(derived_key), + } + # HEX + elif application == "128169'": + num_bytes = int(indexes[0][:-1]) + if not (16 <= num_bytes <= 64): + raise ValueError(f"Expected num_bytes in [16, 64], got {num_bytes}") + + return {"entropy": entropy, "application": to_hex_string(entropy[:num_bytes])} + # PWD BASE64 + elif application == "707764'": + pwd_len = int(indexes[0][:-1]) + # TODO file Base64 typo in 85 "encode the all 64 bytes of entropy". + if not (20 <= pwd_len <= 86): + raise ValueError(f"Expected pwd_len in [16, 64], got {num_bytes}") + + return { + "entropy": entropy, + "application": base64.b64encode(entropy).decode("utf-8")[:pwd_len], + } + # PWD BASE85 + elif application == "707785'": + pwd_len = int(indexes[0][:-1]) + if not (10 <= pwd_len <= 80): + raise ValueError("Expected pwd_len in [16, 64], got {num_bytes}") + + return { + "entropy": entropy, + "application": base64.b85encode(entropy).decode("utf-8")[:pwd_len], + } + else: + raise NotImplementedError(f"Unsupported application: {application}") + + +def to_entropy(data: bytes) -> bytes: + return hmac_sha512(key=HMAC_KEY, data=data) + + +def derive(master: ExtendedKey, path: str, private: bool = True): + if not master.is_private(): + raise ValueError("Derivations should begin with a private master key") + + return derive_key_bip32(master, split_and_validate(path), private) + + +class DRNG: + def __init__(self, seed: bytes): + if len(seed) != 64: + raise ValueError("Seed must be exactly 64 bytes long") + self.shake = hashlib.shake_256(seed) + self.cursor = 0 + + def read(self, n: int) -> bytes: + start = self.cursor + self.cursor = stop = start + n + + return self.shake.digest(stop)[start:stop] + + +def split_and_validate(path: str): + segments = path.split("/") + if segments[0] != "m": + raise ValueError(f"Expected 'm' (xprv) at root of derivation path: {path}") + pattern = r"^\d+['hH]?$" + if not all(re.match(pattern, s) for s in segments[1:]): + raise ValueError(f"Unexpected path segments: {path}") + + return segments diff --git a/bipsea.py b/bipsea.py new file mode 100644 index 0000000..57f618b --- /dev/null +++ b/bipsea.py @@ -0,0 +1,246 @@ +"""CLI""" + +import hashlib +import logging +import re +import select +import sys +import threading + +import click + +from bip32 import to_master_key +from bip32types import parse_ext_key +from bip85 import DRNG, PURPOSE_CODES, apply_85, derive, to_entropy +from seedwords import ( + N_WORDS_ALLOWED, + bip39_english_words, + entropy_to_words, + to_master_seed, + warn_stretching, +) +from util import LOGGER, __version__, to_hex_string + +SEED_FROM_VALUES = [ + "string", + "rand", + "words", +] +SEED_TO_VALUES = [ + "words", + "tprv", + "xprv", +] +TIMEOUT = 1 + +APPLICATIONS = { + "base64": "707764'", + "base85": "707785'", + "drng": None, + "hex": "128169'", + "words": "39'", + "wif": "2'", + "xprv": "32'", # TODO file to 85 is there a testnet here +} + +N_WORDS_ALLOWED_HELP = "|".join(str(n) for n in N_WORDS_ALLOWED) + + +logger = logging.getLogger(LOGGER) + + +class InputThread(threading.Thread): + def run(self): + self.seed = click.get_text_stream("stdin").read().strip() + + +@click.group() +@click.version_option(version=__version__, prog_name="bipsea") +def cli(): + pass + + +@click.command(help="Generate a master private seed") +@click.option( + "-f", + "--from", + "from_", + type=click.Choice(SEED_FROM_VALUES, case_sensitive=True), + required=True, + help="|".join(SEED_FROM_VALUES), + default="rand", +) +@click.option("-i", "--input", help="string in the format specified by --from") +@click.option( + "-t", + "--to", + type=click.Choice(SEED_TO_VALUES, case_sensitive=True), + default="words", + help="|".join(SEED_TO_VALUES), + required=True, +) +@click.option( + "-n", + "--number", + type=click.Choice(N_WORDS_ALLOWED), +) +@click.option("-p", "--passphrase", default="") +@click.option( + "--pretty", is_flag=True, default=False, help="number and separate seed words" +) +def seed(from_, input, to, number, passphrase, pretty): + if input: + input = input.strip() + if (from_ == "rand" and input) or (from_ != "rand" and not input): + raise click.BadOptionUsage( + option_name="--from", + message="--input is required (unless --from rand)", + ) + if from_ == "words": + if number: + raise click.BadOptionUsage( + option_name="--number", + message="omit when you specify --from words", + ) + if to == "words": + raise click.BadOptionUsage( + option_name="--to", message="--from words is redundant" + ) + words = re.split(r"\s+", input) + n_words = len(words) + if not n_words in N_WORDS_ALLOWED: + raise click.BadOptionUsage( + option_name="--number", + message=f"must be in {N_WORDS_ALLOWED_HELP}", + ) + else: + if not number: + number = 24 # set here so we don't falsely trip `if number` above + else: + number = int(number) + if from_ == "string": + string_bytes = input.encode("utf-8") + # this is how entropy works out in BIP-39 + target_bits = 128 + ((number - 12) // 3) * 32 + short = len(string_bytes) * 8 - target_bits + if short < 0: + warn_stretching(short + target_bits, target_bits) + entropy = hashlib.sha256(string_bytes).digest() + elif from_ == "rand": + entropy = None + words = entropy_to_words( + n_words=int(number), user_entropy=entropy, passphrase=passphrase + ) + if to == "words": + english_words = set(bip39_english_words()) + if not all(w in english_words for w in words): + raise click.BadOptionUsage( + option_name="--input", + message=f"One or more words not in BIP-39 English list: {words}", + ) + output = " ".join(words) + if pretty: + output = "\n".join(f"{i+1}) {w}" for i, w in enumerate(words)) + + click.echo(output) + + elif to in ("tprv", "xprv"): + if pretty: + raise click.BadOptionUsage( + option_name="--pretty", message="no effect with --to xprv" + ) + mainnet = to == "xprv" + seed = to_master_seed(words, passphrase) + kprv = to_master_key(seed, mainnet=mainnet, private=True) + + click.echo(kprv) + + +cli.add_command(seed) + + +@click.command(name="entropy", help="Derive entropy according to BIP-85") +@click.option( + "-a", + "--application", + required=True, + help="|".join(APPLICATIONS.keys()), + type=click.Choice(APPLICATIONS.keys(), case_sensitive=True), +) +@click.option( + "-n", + "--number", + type=int, + help="target length for derived entropy (in bytes, chars, or words)", +) +@click.option( + "-i", + "--index", + type=click.IntRange(0, 2**31 - 1), + default=0, + help="child index", +) +# TODO test_cli cases for bipsea entropy +def bip85(application, number, index): + stdin, o, stderr = select.select([sys.stdin], [], [sys.stderr], TIMEOUT) + if number: + if application in {"wif"}: + raise click.BadOptionUsage( + option_name="--number", + message="--number has no effect when --application wif", + ) + else: + number = 18 + if stdin: + logger.debug(stdin) + prv = sys.stdin.readline().strip() + if not prv[:4] in ("tprv", "xprv"): + no_prv() + master = parse_ext_key(prv) + + path = f"m/{PURPOSE_CODES['BIP-85']}" + app_value = APPLICATIONS[application] + path += f"/{app_value}" if app_value else "" + if application == "words": + if number not in N_WORDS_ALLOWED: + raise click.BadOptionUsage( + option_name="--number", + message=f"--application wif requires --number in {N_WORDS_ALLOWED_HELP}", + ) + path += f"/0'/{number}'/{index}'" + elif application in ("wif", "xprv"): + path += f"/{index}'" + elif application in ("hex", "base64", "base85"): + path += f"/{number}'/{index}'" + else: + assert application == "drng" + # TODO file to 85: not clear structure of master root keys; is it {0'}/{index}'? + path += f"/0'/{index}" + + # TODO do we need to derive testnet? + derived = derive(master, path) + + if application == "drng": + drng = DRNG(to_entropy(master.data[1:])) + output = to_hex_string(drng.read(number)) + else: + output = apply_85(derived, path)["application"] + + click.echo(output) + else: + no_prv() + + +cli.add_command(bip85) + + +def no_prv(): + raise click.BadOptionUsage( + option_name="[incoming pipe]", + message="Bad input. Need xprv or tprv. Try `bipsea seed -t xprv | bipsea entropy -a base64`", + ) + click.echo() + + +if __name__ == "__main__": + cli() diff --git a/config/README.md b/config/README.md new file mode 100644 index 0000000..b4d5bf8 --- /dev/null +++ b/config/README.md @@ -0,0 +1,7 @@ +# Why this file? + +ripemd160 is no longer supported out of the box, so we re-enable it with this file. + + +# References +* https://github.com/ethereum/execution-specs/issues/506 diff --git a/config/openssl.cnf b/config/openssl.cnf new file mode 100644 index 0000000..adfa225 --- /dev/null +++ b/config/openssl.cnf @@ -0,0 +1,14 @@ +openssl_conf = openssl_init + +[openssl_init] +providers = provider_sect + +[provider_sect] +default = default_sect +legacy = legacy_sect + +[default_sect] +activate = 1 + +[legacy_sect] +activate = 1 diff --git a/imgs/derivation.png b/imgs/derivation.png new file mode 100644 index 0000000..39ade83 Binary files /dev/null and b/imgs/derivation.png differ diff --git a/pytest.ini b/pytest.ini index d8050a0..73ec3ec 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,3 +1,6 @@ [pytest] markers = - network: mark test as needing network access \ No newline at end of file + network: mark test as needing network access + +log_cli = true +log_cli_level = DEBUG diff --git a/requirements.txt b/requirements.txt index 4175f6a..0cc37fc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ click>=8.1.3 -mnemonic~=0.21 -pytest~=6.2.5 \ No newline at end of file +base58>=2.1.1 +ecdsa>=0.19.0 +pytest>=6.2.5 + diff --git a/seedwords.py b/seedwords.py index 27ceb30..5854358 100644 --- a/seedwords.py +++ b/seedwords.py @@ -1,93 +1,97 @@ #!/usr/bin/python -"""Implement BIP-39 in a Python CLI +"""Complete implementation of BIP-39 in Python with CLI https://en.bitcoin.it/wiki/BIP_0039 + +TODO: CLI design: +(xprv or seed or entropy) | derivation path > output? """ -import binascii import hashlib -import math -from unicodedata import normalize -from hashlib import pbkdf2_hmac +import logging import secrets +from hashlib import pbkdf2_hmac +from typing import List +from unicodedata import normalize import click +from util import LOGGER, from_hex + +logger = logging.getLogger(LOGGER) + + # https://raw.githubusercontent.com/bitcoin/bips/master/bip-0039/english.txt DICT_NAME = "english.txt" DICT_HASH = "2f5eed53a4727b4bf8880d8f3f199efc90e58503646d9ff8eff3a2ed3b24dbda" N_MNEMONICS = 2048 N_WORD_BITS = 11 +N_WORDS_ALLOWED = [12, 15, 18, 21, 24] -@click.command() -@click.option("--nwords", default=12, type=click.IntRange(12, 24)) -@click.option("--number/--no-number", help="Number the word list", default=False) -@click.option("--meta/--no-meta", help="Display entropy, checksum, seed", default=False) -@click.option( - "--entropy", - "user_entropy", - type=int, - default=None, - help="Provide your own entropy as an int", -) -@click.option("--passphrase", type=str, default="", help="Optional BIP39 passphrase") -def gen_words(nwords, number, meta, user_entropy, passphrase): - assert (nwords % 3) == 0, "--nwords must be divisible by 3" - n_checksum_bits = nwords // 3 # CS in BIP39 - n_total_bits = nwords * N_WORD_BITS # ENT+CS in BIP39 +def entropy_to_words(n_words: int, user_entropy: bytes, passphrase: bytes = b""): + """* If the caller does not provide entropy use secrets.randbits to generate it + * Only produces seed words in English""" + if n_words not in N_WORDS_ALLOWED: + raise ValueError(f"n_words must be one of {N_WORDS_ALLOWED}") + n_checksum_bits = n_words // 3 # CS in BIP39 + n_total_bits = n_words * N_WORD_BITS # ENT+CS in BIP39 n_entropy_bits = n_total_bits - n_checksum_bits # ENT in BIP39 assert (n_entropy_bits % 32) == 0, "Entropy bits must be a multiple of 32" assert ( n_checksum_bits == n_entropy_bits // 32 ), "Unexpected mismatch between checksum and entropy sizes" - if user_entropy: - strength = math.ceil(math.log(user_entropy, 2)) + 1 - implied = math.ceil(strength / N_WORD_BITS) - print(f"Seed @ {strength} bits of entropy ({implied} words)") + int_entropy = ( + int.from_bytes(user_entropy, "big") + if user_entropy + else secrets.randbits(n_entropy_bits) + ) + difference = int_entropy.bit_length() - n_entropy_bits + if difference > 0: + int_entropy >>= difference + elif difference <= -8: + warn_stretching(difference + n_entropy_bits, n_entropy_bits) - int_entropy = user_entropy if user_entropy else secrets.randbits(n_entropy_bits) entropy_hash = hashlib.sha256(int_entropy.to_bytes(n_entropy_bits // 8, "big")) int_checksum = int.from_bytes(entropy_hash.digest(), "big") >> ( 8 * entropy_hash.digest_size - n_checksum_bits # cut hash down to CS-many bits ) int_entropy_cs = (int_entropy << n_checksum_bits) + int_checksum # shift CS bits in - dictionary = dictionary_as_array() # get bip39 words from disk + dictionary = bip39_english_words() # get bip39 words from disk swords = [] mask11 = N_MNEMONICS - 1 # mask lowest 11 bits - for _ in range(nwords): + for _ in range(n_words): idx = int_entropy_cs & mask11 swords.append(dictionary[idx]) int_entropy_cs >>= N_WORD_BITS + assert int_entropy_cs == 0, "Unexpected unused entropy" swords.reverse() # backwards is forwards because we started masking from the checksum end - if meta: - print(f"ENT (int, {n_entropy_bits} bits) {int_entropy}") - print(f"CS (int, {n_checksum_bits}) {int_checksum}") - print("SEED (hex)", to_seed(swords, passphrase).hex()) - if number: - for i, m in enumerate(swords): - print(f"{i + 1}) {m}") - else: - print(" ".join(swords)) + return swords -def dictionary_as_array(file_name=DICT_NAME): +def bip39_english_words(file_name=DICT_NAME) -> List[str]: + """returns a set or array of bip39 english words""" with open(file_name, "rb") as source: raw = source.read() file_hash = hashlib.sha256() file_hash.update(raw) assert DICT_HASH == file_hash.hexdigest(), f"unexpected contents: {DICT_NAME}" dictionary = raw.decode().split("\n")[:-1] - assert len(dictionary) == N_MNEMONICS, f"expected {N_MNEMONICS} words" + assert ( + len(dictionary) == N_MNEMONICS == len(set(dictionary)) + ), f"expected {N_MNEMONICS} words" return dictionary -def to_seed(mnemonic, passphrase="", iterations=2048): +def to_master_seed(mnemonic: List[str], passphrase, iterations=2048): + """converts english mnemonics to all lower case""" + mnemonic = [m.lower() for m in mnemonic] + assert set(mnemonic) mnemonic_nfkd = normalize("NFKD", " ".join(mnemonic)).encode("utf-8") salt_nfkd = normalize("NFKD", "mnemonic" + passphrase).encode("utf-8") @@ -100,5 +104,13 @@ def to_seed(mnemonic, passphrase="", iterations=2048): return seed +def warn_stretching(given: int, target: int): + click.secho( + f"Stretching {given} bits of entropy to {target} bits. Better to provide more entropy.", + fg="yellow", + err=True, + ) + + if __name__ == "__main__": - gen_words() + entropy_to_words() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..6ea76a7 --- /dev/null +++ b/setup.py @@ -0,0 +1,40 @@ +from setuptools import find_packages, setup + +from util import __app_name__, __version__ + +setup( + name=__app_name__, + version=__version__, + packages=find_packages(), + description="Python implementation of BIP 85 (and BIP 32)", + author="Aneesh Karve", + author_email="bonded_metals_0u@icloud.com", + classifiers=[ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + ], + keywords="Bitcoin BIP85 BIP32 cryptography", + install_requires=[ + "click", + "base58", + "ecdsa", + "pytest", + ], + tests_require=[ + "black", + "pytest", + "requests", + ], + project_urls={ + "Source": "https://github.com/akarve/bipsea", + }, + entry_points={ + "console_scripts": [ + "bipsea=bipsea:cli", + ], + }, +) diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..85f09d9 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,5 @@ +black>=24.4.2 +isort>=5.13.2 +pytest>=8.2.1 +requests>=2.32.2 + diff --git a/tests/data/README.md b/tests/data/README.md new file mode 100644 index 0000000..1af7e6e --- /dev/null +++ b/tests/data/README.md @@ -0,0 +1,2 @@ +# Source +https://github.com/trezor/python-mnemonic/blob/master/vectors.json diff --git a/tests/data/bip32_vectors.py b/tests/data/bip32_vectors.py new file mode 100644 index 0000000..7e059cb --- /dev/null +++ b/tests/data/bip32_vectors.py @@ -0,0 +1,157 @@ +VECTORS = [ + { + "seed_hex": "000102030405060708090a0b0c0d0e0f", + "chain": { + "m": { + "ext pub": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8", + "ext prv": "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", + }, + "m/0H": { + "ext pub": "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw", + "ext prv": "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7", + }, + "m/0H/1": { + "ext pub": "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ", + "ext prv": "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs", + }, + "m/0H/1/2H": { + "ext pub": "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5", + "ext prv": "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM", + }, + "m/0H/1/2H/2": { + "ext pub": "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV", + "ext prv": "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334", + }, + "m/0H/1/2H/2/1000000000": { + "ext pub": "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy", + "ext prv": "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76", + }, + }, + }, + { + "seed_hex": "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542", + "chain": { + "m": { + "ext pub": "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB", + "ext prv": "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U", + }, + "m/0": { + "ext pub": "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH", + "ext prv": "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt", + }, + "m/0/2147483647H": { + "ext pub": "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a", + "ext prv": "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9", + }, + "m/0/2147483647H/1": { + "ext pub": "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon", + "ext prv": "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef", + }, + "m/0/2147483647H/1/2147483646H": { + "ext pub": "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL", + "ext prv": "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc", + }, + "m/0/2147483647H/1/2147483646H/2": { + "ext pub": "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt", + "ext prv": "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j", + }, + }, + }, + { + "seed_hex": "4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be", + "chain": { + "m": { + "ext pub": "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13", + "ext prv": "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6", + }, + "m/0H": { + "ext pub": "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y", + "ext prv": "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L", + }, + }, + }, + { + "seed_hex": "3ddd5602285899a946114506157c7997e5444528f3003f6134712147db19b678", + "chain": { + "m": { + "ext pub": "xpub661MyMwAqRbcGczjuMoRm6dXaLDEhW1u34gKenbeYqAix21mdUKJyuyu5F1rzYGVxyL6tmgBUAEPrEz92mBXjByMRiJdba9wpnN37RLLAXa", + "ext prv": "xprv9s21ZrQH143K48vGoLGRPxgo2JNkJ3J3fqkirQC2zVdk5Dgd5w14S7fRDyHH4dWNHUgkvsvNDCkvAwcSHNAQwhwgNMgZhLtQC63zxwhQmRv", + }, + "m/0H": { + "ext pub": "xpub69AUMk3qDBi3uW1sXgjCmVjJ2G6WQoYSnNHyzkmdCHEhSZ4tBok37xfFEqHd2AddP56Tqp4o56AePAgCjYdvpW2PU2jbUPFKsav5ut6Ch1m", + "ext prv": "xprv9vB7xEWwNp9kh1wQRfCCQMnZUEG21LpbR9NPCNN1dwhiZkjjeGRnaALmPXCX7SgjFTiCTT6bXes17boXtjq3xLpcDjzEuGLQBM5ohqkao9G", + }, + "m/0H/1H": { + "ext pub": "xpub6BJA1jSqiukeaesWfxe6sNK9CCGaujFFSJLomWHprUL9DePQ4JDkM5d88n49sMGJxrhpjazuXYWdMf17C9T5XnxkopaeS7jGk1GyyVziaMt", + "ext prv": "xprv9xJocDuwtYCMNAo3Zw76WENQeAS6WGXQ55RCy7tDJ8oALr4FWkuVoHJeHVAcAqiZLE7Je3vZJHxspZdFHfnBEjHqU5hG1Jaj32dVoS6XLT1", + }, + }, + }, +] + +INVALID_KEYS = [ + ( + "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5fTtTQBm", + "pubkey version / prvkey mismatch", + ), + ( + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGTQQD3dC4H2D5GBj7vWvSQaaBv5cxi9gafk7NF3pnBju6dwKvH", + "prvkey version / pubkey mismatch", + ), + ( + "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Txnt3siSujt9RCVYsx4qHZGc62TG4McvMGcAUjeuwZdduYEvFn", + "invalid pubkey prefix 04", + ), + ( + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGpWnsj83BHtEy5Zt8CcDr1UiRXuWCmTQLxEK9vbz5gPstX92JQ", + "invalid prvkey prefix 04", + ), + ( + "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6N8ZMMXctdiCjxTNq964yKkwrkBJJwpzZS4HS2fxvyYUA4q2Xe4", + "invalid pubkey prefix 01", + ), + ( + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD9y5gkZ6Eq3Rjuahrv17fEQ3Qen6J", + "invalid prvkey prefix 01", + ), + ( + "xprv9s2SPatNQ9Vc6GTbVMFPFo7jsaZySyzk7L8n2uqKXJen3KUmvQNTuLh3fhZMBoG3G4ZW1N2kZuHEPY53qmbZzCHshoQnNf4GvELZfqTUrcv", + "zero depth with non-zero parent fingerprint", + ), + ( + "xpub661no6RGEX3uJkY4bNnPcw4URcQTrSibUZ4NqJEw5eBkv7ovTwgiT91XX27VbEXGENhYRCf7hyEbWrR3FewATdCEebj6znwMfQkhRYHRLpJ", + "zero depth with non-zero parent fingerprint", + ), + ( + "xprv9s21ZrQH4r4TsiLvyLXqM9P7k1K3EYhA1kkD6xuquB5i39AU8KF42acDyL3qsDbU9NmZn6MsGSUYZEsuoePmjzsB3eFKSUEh3Gu1N3cqVUN", + "zero depth with non-zero index", + ), + ( + "xpub661MyMwAuDcm6CRQ5N4qiHKrJ39Xe1R1NyfouMKTTWcguwVcfrZJaNvhpebzGerh7gucBvzEQWRugZDuDXjNDRmXzSZe4c7mnTK97pTvGS8", + "zero depth with non-zero index", + ), + ( + "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHGMQzT7ayAmfo4z3gY5KfbrZWZ6St24UVf2Qgo6oujFktLHdHY4", + "unknown extended key version", + ), + ( + "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHPmHJiEDXkTiJTVV9rHEBUem2mwVbbNfvT2MTcAqj3nesx8uBf9", + "unknown extended key version", + ), + ( + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzF93Y5wvzdUayhgkkFoicQZcP3y52uPPxFnfoLZB21Teqt1VvEHx", + "private key 0 not in 1..n-1", + ), + ( + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD5SDKr24z3aiUvKr9bJpdrcLg1y3G", + "private key n not in 1..n-1", + ), + ( + "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Q5JXayek4PRsn35jii4veMimro1xefsM58PgBMrvdYre8QyULY", + "invalid pubkey 020000000000000000000000000000000000000000000000000000000000000007", + ), + ( + "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHL", + "invalid checksum", + ), +] diff --git a/tests/data/bip39_vectors.py b/tests/data/bip39_vectors.py new file mode 100644 index 0000000..8938cf8 --- /dev/null +++ b/tests/data/bip39_vectors.py @@ -0,0 +1,1462 @@ +VECTORS = { + "english": [ + [ + "00000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", + "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04", + "xprv9s21ZrQH143K3h3fDYiay8mocZ3afhfULfb5GX8kCBdno77K4HiA15Tg23wpbeF1pLfs1c5SPmYHrEpTuuRhxMwvKDwqdKiGJS9XFKzUsAF", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank yellow", + "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607", + "xprv9s21ZrQH143K2gA81bYFHqU68xz1cX2APaSq5tt6MFSLeXnCKV1RVUJt9FWNTbrrryem4ZckN8k4Ls1H6nwdvDTvnV7zEXs2HgPezuVccsq", + ], + [ + "80808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage above", + "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8", + "xprv9s21ZrQH143K2shfP28KM3nr5Ap1SXjz8gc2rAqqMEynmjt6o1qboCDpxckqXavCwdnYds6yBHZGKHv7ef2eTXy461PXUjBFQg6PrwY4Gzq", + ], + [ + "ffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a13332572917f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069", + "xprv9s21ZrQH143K2V4oox4M8Zmhi2Fjx5XK4Lf7GKRvPSgydU3mjZuKGCTg7UPiBUD7ydVPvSLtg9hjp7MQTYsW67rZHAXeccqYqrsx8LcXnyd", + ], + [ + "000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent", + "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa", + "xprv9s21ZrQH143K3mEDrypcZ2usWqFgzKB6jBBx9B6GfC7fu26X6hPRzVjzkqkPvDqp6g5eypdk6cyhGnBngbjeHTe4LsuLG1cCmKJka5SMkmU", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will", + "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c392d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd", + "xprv9s21ZrQH143K3Lv9MZLj16np5GzLe7tDKQfVusBni7toqJGcnKRtHSxUwbKUyUWiwpK55g1DUSsw76TF1T93VT4gz4wt5RM23pkaQLnvBh7", + ], + [ + "808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always", + "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ffb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65", + "xprv9s21ZrQH143K3VPCbxbUtpkh9pRG371UCLDz3BjceqP1jz7XZsQ5EnNkYAEkfeZp62cDNj13ZTEVG1TEro9sZ9grfRmcYWLBhCocViKEJae", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when", + "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528", + "xprv9s21ZrQH143K36Ao5jHRVhFGDbLP6FCx8BEEmpru77ef3bmA928BxsqvVM27WnvvyfWywiFN8K6yToqMaGYfzS6Db1EHAXT5TuyCLBXUfdm", + ], + [ + "0000000000000000000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", + "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8", + "xprv9s21ZrQH143K32qBagUJAMU2LsHg3ka7jqMcV98Y7gVeVyNStwYS3U7yVVoDZ4btbRNf4h6ibWpY22iRmXq35qgLs79f312g2kj5539ebPM", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title", + "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87", + "xprv9s21ZrQH143K3Y1sd2XVu9wtqxJRvybCfAetjUrMMco6r3v9qZTBeXiBZkS8JxWbcGJZyio8TrZtm6pkbzG8SYt1sxwNLh3Wx7to5pgiVFU", + ], + [ + "8080808080808080808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless", + "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f", + "xprv9s21ZrQH143K3CSnQNYC3MqAAqHwxeTLhDbhF43A4ss4ciWNmCY9zQGvAKUSqVUf2vPHBTSE1rB2pg4avopqSiLVzXEU8KziNnVPauTqLRo", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote", + "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad", + "xprv9s21ZrQH143K2WFF16X85T2QCpndrGwx6GueB72Zf3AHwHJaknRXNF37ZmDrtHrrLSHvbuRejXcnYxoZKvRquTPyp2JiNG3XcjQyzSEgqCB", + ], + [ + "9e885d952ad362caeb4efe34a8e91bd2", + "ozone drill grab fiber curtain grace pudding thank cruise elder eight picnic", + "274ddc525802f7c828d8ef7ddbcdc5304e87ac3535913611fbbfa986d0c9e5476c91689f9c8a54fd55bd38606aa6a8595ad213d4c9c9f9aca3fb217069a41028", + "xprv9s21ZrQH143K2oZ9stBYpoaZ2ktHj7jLz7iMqpgg1En8kKFTXJHsjxry1JbKH19YrDTicVwKPehFKTbmaxgVEc5TpHdS1aYhB2s9aFJBeJH", + ], + [ + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "gravity machine north sort system female filter attitude volume fold club stay feature office ecology stable narrow fog", + "628c3827a8823298ee685db84f55caa34b5cc195a778e52d45f59bcf75aba68e4d7590e101dc414bc1bbd5737666fbbef35d1f1903953b66624f910feef245ac", + "xprv9s21ZrQH143K3uT8eQowUjsxrmsA9YUuQQK1RLqFufzybxD6DH6gPY7NjJ5G3EPHjsWDrs9iivSbmvjc9DQJbJGatfa9pv4MZ3wjr8qWPAK", + ], + [ + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "hamster diagram private dutch cause delay private meat slide toddler razor book happy fancy gospel tennis maple dilemma loan word shrug inflict delay length", + "64c87cde7e12ecf6704ab95bb1408bef047c22db4cc7491c4271d170a1b213d20b385bc1588d9c7b38f1b39d415665b8a9030c9ec653d75e65f847d8fc1fc440", + "xprv9s21ZrQH143K2XTAhys3pMNcGn261Fi5Ta2Pw8PwaVPhg3D8DWkzWQwjTJfskj8ofb81i9NP2cUNKxwjueJHHMQAnxtivTA75uUFqPFeWzk", + ], + [ + "c0ba5a8e914111210f2bd131f3d5e08d", + "scheme spot photo card baby mountain device kick cradle pact join borrow", + "ea725895aaae8d4c1cf682c1bfd2d358d52ed9f0f0591131b559e2724bb234fca05aa9c02c57407e04ee9dc3b454aa63fbff483a8b11de949624b9f1831a9612", + "xprv9s21ZrQH143K3FperxDp8vFsFycKCRcJGAFmcV7umQmcnMZaLtZRt13QJDsoS5F6oYT6BB4sS6zmTmyQAEkJKxJ7yByDNtRe5asP2jFGhT6", + ], + [ + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "horn tenant knee talent sponsor spell gate clip pulse soap slush warm silver nephew swap uncle crack brave", + "fd579828af3da1d32544ce4db5c73d53fc8acc4ddb1e3b251a31179cdb71e853c56d2fcb11aed39898ce6c34b10b5382772db8796e52837b54468aeb312cfc3d", + "xprv9s21ZrQH143K3R1SfVZZLtVbXEB9ryVxmVtVMsMwmEyEvgXN6Q84LKkLRmf4ST6QrLeBm3jQsb9gx1uo23TS7vo3vAkZGZz71uuLCcywUkt", + ], + [ + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "panda eyebrow bullet gorilla call smoke muffin taste mesh discover soft ostrich alcohol speed nation flash devote level hobby quick inner drive ghost inside", + "72be8e052fc4919d2adf28d5306b5474b0069df35b02303de8c1729c9538dbb6fc2d731d5f832193cd9fb6aeecbc469594a70e3dd50811b5067f3b88b28c3e8d", + "xprv9s21ZrQH143K2WNnKmssvZYM96VAr47iHUQUTUyUXH3sAGNjhJANddnhw3i3y3pBbRAVk5M5qUGFr4rHbEWwXgX4qrvrceifCYQJbbFDems", + ], + [ + "23db8160a31d3e0dca3688ed941adbf3", + "cat swing flag economy stadium alone churn speed unique patch report train", + "deb5f45449e615feff5640f2e49f933ff51895de3b4381832b3139941c57b59205a42480c52175b6efcffaa58a2503887c1e8b363a707256bdd2b587b46541f5", + "xprv9s21ZrQH143K4G28omGMogEoYgDQuigBo8AFHAGDaJdqQ99QKMQ5J6fYTMfANTJy6xBmhvsNZ1CJzRZ64PWbnTFUn6CDV2FxoMDLXdk95DQ", + ], + [ + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "light rule cinnamon wrap drastic word pride squirrel upgrade then income fatal apart sustain crack supply proud access", + "4cbdff1ca2db800fd61cae72a57475fdc6bab03e441fd63f96dabd1f183ef5b782925f00105f318309a7e9c3ea6967c7801e46c8a58082674c860a37b93eda02", + "xprv9s21ZrQH143K3wtsvY8L2aZyxkiWULZH4vyQE5XkHTXkmx8gHo6RUEfH3Jyr6NwkJhvano7Xb2o6UqFKWHVo5scE31SGDCAUsgVhiUuUDyh", + ], + [ + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "all hour make first leader extend hole alien behind guard gospel lava path output census museum junior mass reopen famous sing advance salt reform", + "26e975ec644423f4a4c4f4215ef09b4bd7ef924e85d1d17c4cf3f136c2863cf6df0a475045652c57eb5fb41513ca2a2d67722b77e954b4b3fc11f7590449191d", + "xprv9s21ZrQH143K3rEfqSM4QZRVmiMuSWY9wugscmaCjYja3SbUD3KPEB1a7QXJoajyR2T1SiXU7rFVRXMV9XdYVSZe7JoUXdP4SRHTxsT1nzm", + ], + [ + "f30f8c1da665478f49b001d94c5fc452", + "vessel ladder alter error federal sibling chat ability sun glass valve picture", + "2aaa9242daafcee6aa9d7269f17d4efe271e1b9a529178d7dc139cd18747090bf9d60295d0ce74309a78852a9caadf0af48aae1c6253839624076224374bc63f", + "xprv9s21ZrQH143K2QWV9Wn8Vvs6jbqfF1YbTCdURQW9dLFKDovpKaKrqS3SEWsXCu6ZNky9PSAENg6c9AQYHcg4PjopRGGKmdD313ZHszymnps", + ], + [ + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress clump", + "7b4a10be9d98e6cba265566db7f136718e1398c71cb581e1b2f464cac1ceedf4f3e274dc270003c670ad8d02c4558b2f8e39edea2775c9e232c7cb798b069e88", + "xprv9s21ZrQH143K4aERa2bq7559eMCCEs2QmmqVjUuzfy5eAeDX4mqZffkYwpzGQRE2YEEeLVRoH4CSHxianrFaVnMN2RYaPUZJhJx8S5j6puX", + ], + [ + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "void come effort suffer camp survey warrior heavy shoot primary clutch crush open amazing screen patrol group space point ten exist slush involve unfold", + "01f5bced59dec48e362f2c45b5de68b9fd6c92c6634f44d6d40aab69056506f0e35524a518034ddc1192e1dacd32c1ed3eaa3c3b131c88ed8e7e54c49a5d0998", + "xprv9s21ZrQH143K39rnQJknpH1WEPFJrzmAqqasiDcVrNuk926oizzJDDQkdiTvNPr2FYDYzWgiMiC63YmfPAa2oPyNB23r2g7d1yiK6WpqaQS", + ], + ], + "chinese_simplified": [ + [ + "00000000000000000000000000000000", + "的 的 的 的 的 的 的 的 的 的 的 在", + "7f7c7f91ef81f0fb6a3b95b346c50e6472c1d554f8ba90637bad8afce4a4de87c322c1acafa2f6f5e9a8f9b2d2c40e9d389efdc2adbe4445c21a0939fb39e91f", + "xprv9s21ZrQH143K2LTAgxJMxVMKie6n9HQHMUohP6x2cx1TVBr6dxnL3mnSLRiXjiCM7g2ZF3BHzpdbFuhdeh7ZRrzv2EEjg5Tv7kgKZrqbVLc", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "枪 疫 霉 尝 俩 闹 饿 贤 枪 疫 霉 卿", + "816a69d6866891b246b4d33f54d6d2be624470141754396205d039bdd8003949fec4340253dde4c8e11437a181ad992f56d5b976eb9fbe48f4c5e5fec60a27e1", + "xprv9s21ZrQH143K2t2fMBqtVAVWU3JSpmEbbddwouLX8NoBbcTykD1Tm4s9api6K9zvoKSESUsA7aVxbZRunM5yrjZRNZnZckve98hxUorv2Uv", + ], + [ + "80808080808080808080808080808080", + "壤 对 据 人 三 谈 我 表 壤 对 据 不", + "07b6eada2601141ef9748bdf5af296a134f0f9215a946813b84338dcfba93c8247b0c3429a91e0a1b85a93bd9f1275a9524acecadc9b516c3cf4c8990f44052c", + "xprv9s21ZrQH143K2cgeQUKgCSmaRVXFjEGThqrnNFmH71qG8z3bWqYcbX9zakkRxmDp583tqf3cQzmxtn4C2XqinMNb2HkhXBDYhekCB8AwZWV", + ], + [ + "ffffffffffffffffffffffffffffffff", + "歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 逻", + "08ac5d9bed9441013b32bc317aaddeb8310011f219b48239faa4adeeb8b79cb0a3e4d1cb460d2dd37888c0a19bef6edd90ced0fd613d48899eab9ee649d77fcd", + "xprv9s21ZrQH143K3Zkkh1w8EbXYQWAS5ekbitA2WVrswJY9uEJzig2BtairT72n98ySwQUAhYBsLW9EBjJ1XUinrSb69Ty4mttMLnaUooJwsJ3", + ], + [ + "000000000000000000000000000000000000000000000000", + "的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 动", + "b8fb8047e84951d846dbfbbce3edd0c9e316dc40f35b39f03a837db85f5587ac209088e883b5d924a0a43ad154a636fb65df28fdae821226f0f014a49e773356", + "xprv9s21ZrQH143K36LufUjTLqXnTiY6ach28pUYMkJ63swx4FhjPkzqD9YRqDZ452whYcNzKpPC8yfBm1eomL2z3VLC4zcwU71oKvMQ5NnD4h1", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "枪 疫 霉 尝 俩 闹 饿 贤 枪 疫 霉 尝 俩 闹 饿 贤 枪 殿", + "74187bbdce2dba25eed3b9aebdc65dcb7c61e74c58591451d47f9c7b7b17545a527880640bfb9cab36989eba1edddf57bfce7340697926de7f0b9ec1e0345c38", + "xprv9s21ZrQH143K47jLpKzSgdpMLSKP2ZMLXHHUqYYGKbXNE4k3TA2czvJCx5JAJFNkWKZf2B1AbYoUBpc96YoiwM7yfxyr8gvfNNgL7sFNum6", + ], + [ + "808080808080808080808080808080808080808080808080", + "壤 对 据 人 三 谈 我 表 壤 对 据 人 三 谈 我 表 壤 民", + "e3629a601f4b87101c4bb36496e3dbd146063351f5e47c048211faddab78efdb91910f0eea5c8e53cfb851aa3e156b0bb5c501b83baaf5f5d4a1679a5bb7d885", + "xprv9s21ZrQH143K4RfeWihCeh1FJL9SobvinRW4z76RL2X1TB6xreXgaMvJGggUgagkaNr7zX47YHEDYdzJmig8SG3Scuet8smspn7HicCtwHa", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 裕", + "013c8d6868537176fac7bfa966e6219830008f03b650b0f18a12fd67d9ebf871c400c5f980aa073ddd1b23d60846e357aee193ce7644b574bf65e04cf913e39c", + "xprv9s21ZrQH143K2YiskWzQq8kpFFCoFKKU4L8D6Y593dS2sExuVQ4GjnS57RhibwTWjnD7NTCE7ye4cQbCK6Bw674SHb3xWaQYH3NBLFCGYJb", + ], + [ + "0000000000000000000000000000000000000000000000000000000000000000", + "的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 性", + "1981c3e3ddfd80f6e9ee1c5ef27ba2697df3d1468496f1d56ae3d8e0b3f0677bbbdfca954e48eb86fe6a36fc0f597bf18ea00248757a01e82182badff94abbbd", + "xprv9s21ZrQH143K25ttGBGbx6h9VBpa9ELbpw35XQqDR8deXRyVP2AbtgJ79Nq2cW8KaDizbwuoHUYR1o4tLPhYvSCTNMft4ZEfiDztmjXKPCj", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "枪 疫 霉 尝 俩 闹 饿 贤 枪 疫 霉 尝 俩 闹 饿 贤 枪 疫 霉 尝 俩 闹 饿 搭", + "b1eb831927f1c488e233725f9c409dd9bdb9342324393fa56d958e8842623d222510c322f5ba2899428ae08ece8bd87788748c67bdfa73588669ab816c5f3555", + "xprv9s21ZrQH143K4VNNDqCgnETDkPiihzHpxC9wGE6TBGXaeEd9VkQRHQPotwheeaNFGHGKaPWv5zTqfknzgdWiKFC6DqaqBFKjNSmxas968Vz", + ], + [ + "8080808080808080808080808080808080808080808080808080808080808080", + "壤 对 据 人 三 谈 我 表 壤 对 据 人 三 谈 我 表 壤 对 据 人 三 谈 我 五", + "470e61f7e976fa18c7d559e842ba7f39849b2f72ef15428f4276c5160002f36416cd22c2a86bb686d69f6b91818538aa57ae1aab27b3181b92132c59be2b329b", + "xprv9s21ZrQH143K3bUoGmLq8aXRKzvUhseqrXw1t7XYCirduP5XLJtVxCos3rYLDvW8V7pK3voZ4EWSdeXiKdbWNjxmiPRDfet23Av9VRaR3ej", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 佳", + "8e6607a07fa664d6e4ead23fcc08caf72216d6f078c3b2e5be94e4b6e8d64c784d36bf9b70144fa05840e9a49899128111be5093a2b552b6ab76c0906e9b0e65", + "xprv9s21ZrQH143K2ghKxX47TRr4GnQh3diJFN5rJfybjxuwr3xP6pafXrBhwXJsw4HwoiPZ1f6fFPR964eoXybV2su498Ant3kYuYKE3CszLsU", + ], + [ + "9e885d952ad362caeb4efe34a8e91bd2", + "蒙 台 脱 纪 构 硫 浆 霉 感 仅 鱼 汤", + "decd71d2824a1bbadf8c3942f43504a648a8db5f1cac0ae1d0f787728353002a12644b1a6b725147c91682e7f33aec13493b9a779a7dd8ee15a5d10ab21d49e5", + "xprv9s21ZrQH143K44Xrktko35a7gPGVo91Va79LNer1MzVokcrYKFP6GMLAcuJP3fBSdbRuG2DauFC48H6LmyZLfkUyjpm1R2AxYVbnT2P5tur", + ], + [ + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "父 泥 炼 胁 鞋 控 载 政 惨 逐 整 碗 环 惯 案 棒 订 移", + "ff66373b70b72b34842f936bf3bb44d661fdafaee7740d574fed6aa2ef07783cb6111f2862cbd3fc5528e322dfe054557a74a568a1b46c020cb88938e2293ca0", + "xprv9s21ZrQH143K3JLu5XeRDQA5RwHh6gUXaQfRf7ihtVguJvd6EFoAzsoyotvNTDZfC6cciies7fhcqaMRTEsZUSbRYqBdaviWRHatRMoHX6s", + ], + [ + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "宁 照 违 材 交 养 违 野 悉 偷 梅 设 贵 帝 鲜 仰 圈 首 荷 钩 隙 抓 养 熟", + "6ba622f907c61e29e44833b08441b7afa84889a48ca90ebf90f585e257662b2c1b0c35ad54088e745c73689921209fdd4b5b8ace5d850e366d7c2042a076e660", + "xprv9s21ZrQH143K3dE2RQqFbapci6WBj47vZCkLVf4r14QsRZ6Ny2ck6s8tzZQzQaM55Tt4d2tRS9AuFrEJ4yBXsmP8yKeVGXT8E97iRVkDzCj", + ], + [ + "c0ba5a8e914111210f2bd131f3d5e08d", + "伐 旱 泡 口 线 揭 县 杨 断 芳 额 件", + "7346996be5f2b02c67ec465c677197375b589b6e8871c842505b139c2d47feca75a2a941623d6486aff6b21c95193a8177960d123cf610f03f3224a9fa7d0eed", + "xprv9s21ZrQH143K3A2p7cttKM5L39rutYgY4jqZ16z7hpAEdyiT8fr5eKdaHGLMM2ZmsUFNvGcSfyGMp1sz9nVyg3ZXop1hesUbgAvVBzx4rix", + ], + [ + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "福 惜 怀 叔 筋 酵 货 科 牙 冒 辈 罩 悬 耕 浇 呵 连 级", + "09098e00fcc1bfa7d5b9f0c12dfe1993bbd5a0915200a53fb40b2d6d487b969a18463565c1e035569796a7d8b99f82a4c4b17002b0c582037da95bacfeb422b3", + "xprv9s21ZrQH143K4LdjFgCrosa76XBrNQ4imGB7XNc5MhfkASrmAHVNWYLNGY6kNj8foXBLS9aUD8RDubyj3NKWarmXxRQ28AeWVPbLD3a1FEq", + ], + [ + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "仪 未 九 茶 队 梯 妇 孤 托 病 泉 贺 产 绘 吹 测 局 碳 征 墨 晶 帮 息 延", + "6d55f2dd8d42f1cc5e0b4ef6e8a95200580ff4e29d2a3dfa7f9ddb1af0aa2e93780d84d952d39776a379ddc017847ea01aa01b85dc208e7f69891d5b7cbf2eb0", + "xprv9s21ZrQH143K2tkCCjLXj2L9Ds9FttWwH6Eqt3uvihwUvpSpTm3RmRtSkapxASEUW5HXE6Qx2H1viBxXbLZVKxyfQ7fyFn6NcDspgJfdPaT", + ], + [ + "23db8160a31d3e0dca3688ed941adbf3", + "济 扶 块 言 穗 定 万 绘 姻 逃 颗 焰", + "bf8dcc2fb4dc8fd2311943b527864feabfebd5fffb6641555519da3606265e895bab5aa1647f6e5afb0cb6ea4d0b27e8a9f2f49251b68ad6bf898937581351cb", + "xprv9s21ZrQH143K2i53x2geCJi6A2QJpaHpxeGK8oeMxYs1tUrUwU3ddu9jHVucF3ePQ1koQ1TVFHnfP21ScWzp8xKnMinNUSW5itm7PicXWYW", + ], + [ + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "虑 铺 目 祸 英 钩 尤 添 醇 嘛 触 独 起 赋 连 剪 邦 中", + "07e1a2dc2eea79bb12be53d6fb662edf87796cad60e8d10a655ba39a95c5a68eb21f865a1b2f37d780286adbbddeccba3f7844c8a2b1a82029e6a855c713aecf", + "xprv9s21ZrQH143K4V2oh58ZSb1CAbYkwB6ThJmTpRC51uKha9hy51R6RVzzbcEog3n6h4u7FtotS9arBvLofX7A3Apvcaedmeg1jkt7Vkt9TtA", + ], + [ + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "而 怕 夏 客 盖 古 松 面 解 谓 鲜 唯 障 烯 共 吴 永 丁 赤 副 醒 分 猛 埔", + "0402ae511062cfacbd5e33637a95e57e2e14fde0c5dd471fe66fc1154b6373802aa8641a78b91658052bff0a5c5bd075f01fc74b0d73e95a890430ff6f0e728e", + "xprv9s21ZrQH143K4LSoFcKBWtmUHjzuH56srzrkpPfGx3i36UXpVUEtGvCuZ3egRTyDkaqRN5Ec1HXvXGSGTXLyAKzCRnTspi1D9NdmQmWqM5x", + ], + [ + "f30f8c1da665478f49b001d94c5fc452", + "昏 途 所 够 请 乃 风 一 雕 缺 垫 阀", + "aa7e38f64810007db63e31c479b9848cd5ffda839546749669bf53476dd036a33fd77d0a13d4418fb536ea78b028fc19533db4bc9e0e12a14a9432cb9fd112a2", + "xprv9s21ZrQH143K31afj91bWiGw2aC2xHJwrWsMs9MuvEWZETkpWr15ZNF6LFjkHh53iD2bwJYEawvCCvDRaqDsr37fhapgGDkA7UATtwBsZu3", + ], + [ + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "瓶 顾 床 圈 倡 励 炭 柄 且 招 价 紧 折 将 乎 硬 且 空", + "2a6181cf2b069ba30a87228d54770ed5abf61e8151abdb0b27646a87a6100d4b7b496c3ca26f027d0b06724c6c5a469f43a7f1ffb7782e5afb01d143ca65973d", + "xprv9s21ZrQH143K3ji6aQ9QQi4WkFhAqnrzRANJkYkRWkMqbr51mAV6JYUt85oR8Jt3D7DreQdsb9292ips6VKwpitAhLR7rfLdhYz7zgYei2F", + ], + [ + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "柄 需 固 姆 色 斥 霍 握 宾 琴 况 团 抵 经 摸 郭 沙 鸣 拖 妙 阳 辈 掉 迁", + "4dccb0a3578716975b840c51e279c2af728567ff42e98dd09b9e61742b41d9f30d411a501172cce9b7d5706a480dd4d4e7fb26021a36a74381156b09d251d65a", + "xprv9s21ZrQH143K2hLNNA7KnimwonwFXCiGVM3K29DgZiTcVUJ8t8jkc2mXUzFZmoFgXWh9UhJFbyKM44Qm2KeGsrEevajZZfKyoLyFmyoDpUx", + ], + ], + "chinese_traditional": [ + [ + "00000000000000000000000000000000", + "的 的 的 的 的 的 的 的 的 的 的 在", + "7f7c7f91ef81f0fb6a3b95b346c50e6472c1d554f8ba90637bad8afce4a4de87c322c1acafa2f6f5e9a8f9b2d2c40e9d389efdc2adbe4445c21a0939fb39e91f", + "xprv9s21ZrQH143K2LTAgxJMxVMKie6n9HQHMUohP6x2cx1TVBr6dxnL3mnSLRiXjiCM7g2ZF3BHzpdbFuhdeh7ZRrzv2EEjg5Tv7kgKZrqbVLc", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "槍 疫 黴 嘗 倆 鬧 餓 賢 槍 疫 黴 卿", + "f38af46f6bc3222b0f5aa14dd5b8b506e51131510f2450ec9fb52c28617cfa59d436055fe542e25dfa01415639d2171e41796f169f8bbc18516941dfdee8fb72", + "xprv9s21ZrQH143K2HYJ8dR81cQGust8Gm4MeyfC6off5BvCfffAxE33WhiYxB4aLV6meXP6QmoKZkLX8UJgrZPcA4A2EKU4iaPWenb6Wg9kxzd", + ], + [ + "80808080808080808080808080808080", + "壤 對 據 人 三 談 我 表 壤 對 據 不", + "33f373da1a6b4300dad5cc70d2329ed614512e3c8a423673c294110521326ca66753b9663bdd7c844f17d81609a410a61809dd5113823009f729e2f2f940cab9", + "xprv9s21ZrQH143K4SV7MzxYhSQtxP5gWGCD75QiUsp7z1s7Kuc8b4V4F6wRqKvhdczy3qi2uNeN9Vw4PnKYJtoaFdHFX4qbxweuRDmQqgMjKRJ", + ], + [ + "ffffffffffffffffffffffffffffffff", + "歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 邏", + "cfd5f4fa6f2a422811951739b1dad9f5291f9cbc977a14ae9dd35dc8ab17aeec9ee6f1455b20f881838f4f945850765dd002a9abcdbe7be002ffcdaf6f63fdaa", + "xprv9s21ZrQH143K2BptXPaTm7CCWCs4v3tfG5jGAa9zLqSTKNL1ah8veMWc53hio5grKVriWhKjNKbCA2w6svkL4NC6pkiRwVkbwazVXtjdgEv", + ], + [ + "000000000000000000000000000000000000000000000000", + "的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 動", + "717f4f70c7550da57e42c6b49ac47b5bad3249605ed2f869900596c2de7653a8528380e5c31709ed9c2d19b868bc530158712e97276886b4863d036177bcab33", + "xprv9s21ZrQH143K39TvGFp5nfiw3zXib4v4waTbxFYoDNoD4pp4DMBneg9MgSqfK4xL7hK1YjDEa5BWMXKVgTxMiNXNSdT3Wv59pD4PB3LDDKP", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "槍 疫 黴 嘗 倆 鬧 餓 賢 槍 疫 黴 嘗 倆 鬧 餓 賢 槍 殿", + "2b219a8be0a8e27a6b50d0a74eb42175bd23e22cf4081518c9a74cbfe2cbace46f0adad8d390f8a2ac30feb26226db14fbc545d18ba0e56a853cbf103c92539e", + "xprv9s21ZrQH143K2wC9BUJ9F5CsmV7a6PJQkxc9TT8gUrkoTXurPztKKosq5REGzdEzEuKn221vm2A5KnjrDBC1KcLo4VeYGSkkwxXWYrqSrXW", + ], + [ + "808080808080808080808080808080808080808080808080", + "壤 對 據 人 三 談 我 表 壤 對 據 人 三 談 我 表 壤 民", + "d29225f73231521784d98820ebf0ae4d827c5a9e0c0f8845fd63866cdc70b3a40a2281f3f6c6181c5a53e440528dbf83947a4b2056749cb9cc9c83dcd5c91b0f", + "xprv9s21ZrQH143K2MQFKxX1ReLYY2rNunsfLpU8F5WRVWeLfauPhD5huvXEzxoPvmLhD3QtSj1Z5jnM51q9NrRjYBaHG5XJzfVsjXWYQop9pXz", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 裕", + "013c8d6868537176fac7bfa966e6219830008f03b650b0f18a12fd67d9ebf871c400c5f980aa073ddd1b23d60846e357aee193ce7644b574bf65e04cf913e39c", + "xprv9s21ZrQH143K2YiskWzQq8kpFFCoFKKU4L8D6Y593dS2sExuVQ4GjnS57RhibwTWjnD7NTCE7ye4cQbCK6Bw674SHb3xWaQYH3NBLFCGYJb", + ], + [ + "0000000000000000000000000000000000000000000000000000000000000000", + "的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的 性", + "1981c3e3ddfd80f6e9ee1c5ef27ba2697df3d1468496f1d56ae3d8e0b3f0677bbbdfca954e48eb86fe6a36fc0f597bf18ea00248757a01e82182badff94abbbd", + "xprv9s21ZrQH143K25ttGBGbx6h9VBpa9ELbpw35XQqDR8deXRyVP2AbtgJ79Nq2cW8KaDizbwuoHUYR1o4tLPhYvSCTNMft4ZEfiDztmjXKPCj", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "槍 疫 黴 嘗 倆 鬧 餓 賢 槍 疫 黴 嘗 倆 鬧 餓 賢 槍 疫 黴 嘗 倆 鬧 餓 搭", + "fd50ad67903b2046356e67e55d67309b6f0ccd7c23bfefd049a5b8a40d56c507d73a5517e2d2785f024a7794854594aaad845dd0fbd0432c25a96f2a7181a2cc", + "xprv9s21ZrQH143K4TP9sQD1LnxuSy6WUe1hF7JMPo4qN6TMX5udfEcJh9x4PqbetYoC9c1hpx7RxP6VcgzdPxPCJ91De4R1TgGNVC9AFhxMwkX", + ], + [ + "8080808080808080808080808080808080808080808080808080808080808080", + "壤 對 據 人 三 談 我 表 壤 對 據 人 三 談 我 表 壤 對 據 人 三 談 我 五", + "d029fc9737b801cb4f9aadf5feed02a117b76ead7058e055cc39cb44864023eb492e6a15c68569d6a03a5b11bf15a456c64e1781a553589b47ab569801239a00", + "xprv9s21ZrQH143K4bYXrWpQYgiSHDM1iVkNVnyqbpjyZksLS2fmxKCbwQjz3sBFTD1aFY4xWrYdHTyeFYjnYWfKGLc5WCkpokdAZyP9XEGJCsa", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 歇 佳", + "8e6607a07fa664d6e4ead23fcc08caf72216d6f078c3b2e5be94e4b6e8d64c784d36bf9b70144fa05840e9a49899128111be5093a2b552b6ab76c0906e9b0e65", + "xprv9s21ZrQH143K2ghKxX47TRr4GnQh3diJFN5rJfybjxuwr3xP6pafXrBhwXJsw4HwoiPZ1f6fFPR964eoXybV2su498Ant3kYuYKE3CszLsU", + ], + [ + "9e885d952ad362caeb4efe34a8e91bd2", + "蒙 台 脫 紀 構 硫 漿 黴 感 僅 魚 湯", + "27ca577f0318b6c6067acce7aefacd12bc9fbbc8e365fdc16bfc0ffd76379b0768dc56877f19eee4c1222dfb5a94a5516c5707e6a6ad070af9a0fe7f7799ac5e", + "xprv9s21ZrQH143K3FtWQPZHP7Gpf5qgbvXqPNo5iCSfkGhWnATeqM5FuQ3YTx4sSciJx1MjVnbM3XQ16N83x5gNwcsVG7PTf1cRDhvyGZ45EY5", + ], + [ + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "父 泥 煉 脅 鞋 控 載 政 慘 逐 整 碗 環 慣 案 棒 訂 移", + "fcac6cdda6c67e46ea46e66d00df3cfb1e437aa05f1b280f5427c0ce521a94b5a01ab016d235b7944f36d76ba0a297968ae0d882fde95c96cae34e35f2433c82", + "xprv9s21ZrQH143K4YANCnajhJxfsFsDEZGitTmP934osTHvUmTEtfSaYk8rmvj914uGUYaJH5ALjDgVyNYW5gRGPdQBFaqoSbGkHXhfdVkNVY2", + ], + [ + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "寧 照 違 材 交 養 違 野 悉 偷 梅 設 貴 帝 鮮 仰 圈 首 荷 鉤 隙 抓 養 熟", + "969aaf00b9af97a1c3fd0b7b35480aebf51577658067df966caaf5cace472d2ecdaa2978470be83463262340527c0564d8c57f86764d48e9bebd1ce594955a6e", + "xprv9s21ZrQH143K3aULbWnFhpGS2h19R5JdizbLLLQTDsGmKP5A1sqQop1Ff8Q7NEetRHRNFR8AAsPm1kr5hGU5VLYKURZeiVe9k5hqVmhZ5zF", + ], + [ + "c0ba5a8e914111210f2bd131f3d5e08d", + "伐 旱 泡 口 線 揭 縣 楊 斷 芳 額 件", + "09c172005e7dd81fcd55b87d13f114207ce7726376ea74a1b9085a799b2afbd5ac5526059e722987a65f858e5301edd5f4c91deaf9d7b4f9bcc38919e5ec3725", + "xprv9s21ZrQH143K2sMUzpWRrPMF1Xx29Yos3Kah6H4E9YaJqDm2yEMXypoKdX1ugkn1Vx3k9Pr2LsKNQnHqoDFP5Jepm2PCkUS1GrQZps1wxkD", + ], + [ + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "福 惜 懷 叔 筋 酵 貨 科 牙 冒 輩 罩 懸 耕 澆 呵 連 級", + "3e09d89450ae45cc1a07ab308649f291ad5c1452da509d7269daef52ddd04db8bbb6bcb8a71322c4d25ed4686d910e84156fccfbac2838ba482bdd1e4b2ea693", + "xprv9s21ZrQH143K4bLxh3ir6ziqU7t6URBK7uA8Md4tzAd3TAuBNyZREqEoZBevwu8Uw6tfMujFRWrZvCy47nbnKgDhsFaC2hvFJwRdkhnoM1v", + ], + [ + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "儀 未 九 茶 隊 梯 婦 孤 托 病 泉 賀 產 繪 吹 測 局 碳 徵 墨 晶 幫 息 延", + "d687bb89cb435fe1de166e953b41500f3717a497ca35c78322f66cd63e675fe0c8aba92463544631cdd6a985db03bdfcbfd839002ec609879e8768a3ffdb5fea", + "xprv9s21ZrQH143K2LB4bPuHTErkGLt8DV5BbRsS82ySFPdQr57fzBY5D7VadhJHruxFzVcYdEbDqK8QWPSqj6LCiyQgFFurfnWWm1v6N2nGovN", + ], + [ + "23db8160a31d3e0dca3688ed941adbf3", + "濟 扶 塊 言 穗 定 萬 繪 姻 逃 顆 焰", + "806655cee21d12c952d6a11c12e742809c4452b6e07458c6ddc2cc2a8920e308476f3c6ba7fbbdab3de3a7bcecd4de5dd82dee7a217d0cd071eaa2313ca390da", + "xprv9s21ZrQH143K3Kcz7sz3UyDYJhSjUYujBdxFwDHCbqmKWqN3hSf1pjnqoxuAKsQXbnvrxzRBLqPN9BKxHUiYgn1DjhwaStTfZQTCsaTEWxZ", + ], + [ + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "慮 鋪 目 禍 英 鉤 尤 添 醇 嘛 觸 獨 起 賦 連 剪 邦 中", + "b609a4e17fa8c3c0b4da704b1699631f0d85f5b7bcc7d1488270551670b5393a0dfcb4d8eba9860c2c211324bbf3b587763ad1ac6a9e61a4e2e015bb6cc6a58a", + "xprv9s21ZrQH143K2Gmewuzc56mbdKTqPezqWqk7ih9AdnLc9A2865TYtywU9sZ547mKYFKnbVatAuUUGtqgAz1ENkv9FU85jARHkCmtAGLmExn", + ], + [ + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "而 怕 夏 客 蓋 古 松 面 解 謂 鮮 唯 障 烯 共 吳 永 丁 赤 副 醒 分 猛 埔", + "8ce6b92bf95337a49bfd3d80774c9a73d05046eb2cb41789092a3bfbe7005ca668c427a42f1a93982d9076511330817b6d0bd49ba4f5a39e5756472b162f7ba0", + "xprv9s21ZrQH143K41g7SsRpGA4g25xDiqjkhq8DNbJD7jgSksvt9kakaTzukN4SfVrUM2A9yGVPggP9eFAmuriRSpPLahm4ngaxvNHyQp82cee", + ], + [ + "f30f8c1da665478f49b001d94c5fc452", + "昏 途 所 夠 請 乃 風 一 雕 缺 墊 閥", + "e62457aa7f30c24fa46b90aeba2cbb9e77c28fcafa0c10dab01f5323eb1cef22f23c0e52cb5dffa2b2911a29992213c2cb20564af268eed03ea11292fff1a737", + "xprv9s21ZrQH143K3JPEGRnwbdy5xdTvVdXEDGJX8gc385oC3H4veWiCVDrdeeFPWrU7Pz3PNMHcZrbutLY1UGs5dE83U925xKXLUrXXpz2ihKw", + ], + [ + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "瓶 顧 床 圈 倡 勵 炭 柄 且 招 價 緊 折 將 乎 硬 且 空", + "6b5591c758a069d3425bf93399398e8ef3e1c32c27f46e0a5284976dcacf25895f5d7747b84f38596247557debd133576932d394ad24c7a00aa24555fa668c5b", + "xprv9s21ZrQH143K2hh1em7CqtG7uL1bTNG5hfP35X6Y8uwnTDiS9Cm87WNcZvmFHLf3JwoP2W82VzaRejpqr7oPnFLguhVSr5pWnG9YSV4SdeH", + ], + [ + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "柄 需 固 姆 色 斥 霍 握 賓 琴 況 團 抵 經 摸 郭 沙 鳴 拖 妙 陽 輩 掉 遷", + "17ec1a79121f3541e2d78ece35c8cfe7f5763b39d93fa90492c4beca26ee69d3aa7f4b1e6a2ac5e8225e08dded19357ee44b852dca425792842ec8eae09ae43f", + "xprv9s21ZrQH143K4RoVseL4UENdN7Ag1WmcK7Q6Pk329krQW4RifHJ5sNizkG1PiyRXAouyL7KDFJSQAD1VarGTPftD1yZZAni3QczW8V5gNVG", + ], + ], + "czech": [ + [ + "00000000000000000000000000000000", + "abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace agrese", + "872501bed75c98fbf943a67907bf394995f337e9adfa23687282d1135c262421715a0bcccfe2d3f5f8b72c8e2fa12a7a7267f8047b744557f4a9d49d11ccc75f", + "xprv9s21ZrQH143K3rnjkVvSaFkwgg1J2tnUAeqv8SCEWTWdLVZiJsjM6Z5ieeUnrR1Ws6sDb8Guqp43CXVRmPooUs2cjwefSXh3EyXx2vmzZ96", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "obrazec znak uznat zubovina zeman skupina zrcadlo vzchopit obrazec znak uznat zubr", + "68e1bd31ed5f20c9ab108c03b524e85209b0b27af80cb5d48fa71d03dbb528b73c2349bb8576f9b68825272984061594f520e54605a4898ba61c433d06bf5de7", + "xprv9s21ZrQH143K4JXKqKovjKKSb7zgQcgbuKNNjaWyYBjjdny1SyXiPbjzSNUR6uLmNmPJ1NcWzeHDLqmopeTTbZ3DbPobsm4pbDrNrqhEDbK", + ], + [ + "80808080808080808080808080808080", + "obvinit bageta doma amputace bidlo jedle arogance butik obvinit bageta doma akce", + "067089f8edbbb8bc8ab6d0f3e29f250d136955745797a20b63fd4372627c51c4576ebd5fb6c6d4825d21f448cc24b342ce3b0117fedf41369cb5a6be77494aa7", + "xprv9s21ZrQH143K4YKjBNHoBtUM2qhAvjVvXsBZJGAhogbqhBbgTvjRjPSgC5ShPUeGRCRTdRMYLZ7wWxRWwcvgQm9xX7b5udk9p5yfiekNMQK", + ], + [ + "ffffffffffffffffffffffffffffffff", + "zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zticha", + "04d0a733d43c640a4492b670a9549c60a358a681891cc2337a01a3c8288cd2941b7e057dbcf2dffd1e614cf5fcc9d38d9228fbd3ea5ceb508b8aacac5f35ccd9", + "xprv9s21ZrQH143K3pcHonm1bGBQvbLf6Ty3c7HKCyzFr4C4DnvLPaT1JUUJ4MxkWyNhPpCjVsLMJEndqUocNxhqZ3UfFwxAsn7zajkE7n3yXYq", + ], + [ + "000000000000000000000000000000000000000000000000", + "abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace balonek", + "b5eb0b74cb5f2c616e7136182597ab61dd94594d22f15ce6c94e04eb7336a56d3e445ec1279c1f04b861de5f7c6b2fc95227db53be4996de3ba87d6d76b09098", + "xprv9s21ZrQH143K2Edeaippdsom8CKbdVxcorYqTexQoxhdci7pVuv6K1yFYnGunPP3d6oKyE3ax354UgfNUu6Kes1hvjvJcoyHfyjxwbjhFqM", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "obrazec znak uznat zubovina zeman skupina zrcadlo vzchopit obrazec znak uznat zubovina zeman skupina zrcadlo vzchopit obrazec zmije", + "93ff13dee31715a6568609df3f7ea295d58728a65611ea03620d2105a0efbbaa39d8b6541b3b5a57a25dbdfd5006f0c58779a7ed196e25a1a97d1442e3f080fa", + "xprv9s21ZrQH143K3SW9C3X4jc47HaXuDHjRvpCDxoo7PgTpMG5EZoFkDCkCzhs2yMvaUQidKKXBDChe2ns524iFEbrJFqNCPFvR1bjyRmq5rxj", + ], + [ + "808080808080808080808080808080808080808080808080", + "obvinit bageta doma amputace bidlo jedle arogance butik obvinit bageta doma amputace bidlo jedle arogance butik obvinit bezinka", + "1843be39a115dad287e10d256d2e9bb81244cefda2b7ead8a762f53033512abc7b6db26e2ebe8053fb82e313c24bcf62ae84ba4aa2900ca0fcdcb1affc38887a", + "xprv9s21ZrQH143K3uYc2wzd6UfPLXqfQKsYJVyWL2HeCZ1YKhqd3jt5y4w9bfLTf4bAqvD3NbJ8ifa6vbTvHL2t87wsgi22RXd8c8Moknbzdcc", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zlehka", + "43b7d9b1b25d046f8a89fb57ba10bed11b5273574bb820eb01cc0733a421f1c98ceb2db42d299e7e96aa2c58435e916821bc9d505525b3b5448ecd4c97babe0b", + "xprv9s21ZrQH143K3LM3GwVcGcoMnK9UmQKxTaq1GiX1HsG5u76FmfUi5cTcH97WSXxVNLgURJCgL8RT1qDNsiQ9Sw1DDVAhiu4h4xMz6mtFDzL", + ], + [ + "0000000000000000000000000000000000000000000000000000000000000000", + "abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace abdikace branka", + "dd2a9f662649585707dadc6e8b2df2c0e0e2691d53bacea2212aff4063ab4fdc79b703a7ce6744da31cd2ee12e56b9ee0f430a238b892fa660ed0ce879f2c472", + "xprv9s21ZrQH143K3RHkXA6CEXUxT6nXGMM1zKuxgGQBD6k9gErraXywHoiqx4syweAftp5SCU7XSoFz5T3RbPs3HNZtZFa5JcR9ZD5TUmV15tB", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "obrazec znak uznat zubovina zeman skupina zrcadlo vzchopit obrazec znak uznat zubovina zeman skupina zrcadlo vzchopit obrazec znak uznat zubovina zeman skupina zrcadlo veskrze", + "f4e4e2d8817cbb3925d6a0e8a2a466dbe1353a5885ec203030722607b8b5f229c71066c18681fda4291d0e323e4f6ba099b5b7efff442adfa14124fd07147fa8", + "xprv9s21ZrQH143K4bgmXSbkNXn4ntJoQWUwRscM7yiZjzHbBFc5nMmgMeVcVJS6ZqXcWaTp6Phy8PAji336TDSNmiSWK7cmuzCSxkobg11RTN2", + ], + [ + "8080808080808080808080808080808080808080808080808080808080808080", + "obvinit bageta doma amputace bidlo jedle arogance butik obvinit bageta doma amputace bidlo jedle arogance butik obvinit bageta doma amputace bidlo jedle arogance cihla", + "bb8b82baced0db7764e102d1d1f68035269e84ec6c1ed0e09b2a31094330967aff9e1a490a407fef736fb8719c60bfb8cb0be9b27fce97c3b619409c195e2f1d", + "xprv9s21ZrQH143K2aufrtmAWe6Ppto9BA4jSHu3XmKbMemyWEJ37Zfwxie44JJi8pXDxfjkSv8LxdKKs9rmV1R9SxCfAtcttf6g2JK3mRwPyzM", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zvyk zavolat", + "3991e1ccc78af78d58cae577b786f7c950e1f23311d0c5f6d51b884d6142a6b4fc91a227c895313bf3d35731682678653101f51546717d60438d54dead32f834", + "xprv9s21ZrQH143K26BAmMqZUKy3rpA3bYvGiip1tjQ2gnLwKrm9zucVU6n5PSJ9FLWeW1JjQJyZJ52QAV3HtevGNQ3BnTh91mAWgaacd6UenQ7", + ], + [ + "9e885d952ad362caeb4efe34a8e91bd2", + "pokoj jogurt malovat kroupa holub malvice rachot uznat hnout kasa karamel potupa", + "f3922b8086d559436ba2d04bc2aae4174e6504d7d4d451f7282d0b41a1b8cc958b45a896985e0b9316ad09c62f7d62dac85bc3d3e2e2423bcad3336412fd33f8", + "xprv9s21ZrQH143K3gt3UuAosyvKpAmRpGfWuM19LVhrpWshTnv8o9Z2SPx7PxfgPQSZtm7U34cWo2NUrUtWCtXLhKDFZxg9pjM9KRde9dLwsZC", + ], + [ + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "masakr odtok pijavice tajga upravit krmelec krvinka buditel zavinit lakomec flirt traktor kresba plevel kapitola tlupa paseka ladnost", + "8c7c2b7767caa63139099cc5faf955cc582abc43494fc0f94b1f490ddfb7c221df55b663711755602c1354862c1da7a1241d17888f1be6f4ba7f58634758ea0b", + "xprv9s21ZrQH143K4TFHpb3sbWvTgFjmH2b2r6TAWi1L9UxyL2hBXQeDwVgQmR7CG3agahDGRPWJZDWZjcAYwEGjRzycaRzTmbmxjaJxujKScF1", + ], + [ + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "migrace iluze pukavec kaktus drogerie hrobka pukavec onehdy suchar veterina rorejs cukr mihule koza makovice uvozovka oklika inzerce odhadce zprudka spousta namluvit hrobka obsluha", + "4b315b6c57139dfd19187b6029ad8b2fc6165dd97a43e59c4606a11deb192b25df5ad4e8fc3b4c2da9b9e80eae48946d769bc7bc95786f93b934bbc842cb8002", + "xprv9s21ZrQH143K2ro2PraMEHNWQX4w969ZUPVBZFY8pViiRNPhsRjFbj2exS12cg2YCa6kkYUCSJBhuHCicMAGqj1ZtSvKYXLjaErhCBve7XT", + ], + [ + "c0ba5a8e914111210f2bd131f3d5e08d", + "sledovat ticho potkan dotaz carevna pahorek ihned nikterak hematom pokrok neochota cvik", + "ce64d48ded9f32127bc7ef66c829e32b576927ffa1f323f0020f58c3256fdeb5ee2ec7bc257bb492e4fa1ae1e7f41b8affd9f68a2143e2d54e443e54d866e6e0", + "xprv9s21ZrQH143K24d38NZ3eGjiZ5cuqmVJjsC2piMq6ZPSsEfgPf6F9XZJvfsExo6M2P5NCgdaUYgeLchyBw8sAWkH8joq4yMeNF1i12zXWWN", + ], + [ + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "most uvolnit novota usmrtit terapie tehdy litovat filozof radon svrab surovina zdivo stanice pejsek ukrojit vymizet helma decibel", + "8efd8d7625a41d02e53b8f363678acb389136ee9b19512381417e7f3295cc5bea28a7feeadf29ed8c2bd617e67feee3c736bed06f29ed3538777d58187458955", + "xprv9s21ZrQH143K3Vd6GfvEYmC1ut3Z9uKS5weiaKT77zoz4uc4MaJMnQWsXYFLK2wp3DiARFbUyEv8yLqAirLmWMDmsXFhPioprwBiqQbTPb7", + ], + [ + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "poloha koruna dobytek makak domluvit svatba paluba utahovat orlice jakost sypat podvod barva technika pastelka kurt ikona obvod mokro recept napnout kabel lord nasadit", + "e69afd8c8b83713ce327570ca2dd9d588dd1f266fde95d7848059fdcec016e8f9f587a8fcbdbd061ecd9a5e1e90f51f9453af914df7d8e9b5758f91a1963a413", + "xprv9s21ZrQH143K2zXve6cknQXePKGSMLedfyGDpgQZ5oNB7YKgyJqjXoZeQ4qj1vd2HZpnF77g1nqihMeAi7wnYd3c3hrgczNAadCKdetb2tf", + ], + [ + "23db8160a31d3e0dca3688ed941adbf3", + "drak uniforma kuna kapka tmel bedna evoluce technika vypustit popadat rychlost vodstvo", + "cb409aa4d44356187fc1f0777afc3f0057bad31090e589e1a8a13911a0604e9ebe976bbbd1633b3320049e58ae4939591150f1b84fc552975d4c7b5774efd20f", + "xprv9s21ZrQH143K3S5abSGNCkH4QWovuVGtqjrufboCgkqDvPGUtnUgPFNqXwVyWMD45MmwRFDYUe7Ny89sqvCqxPMWtq2CDa14t1CYxLjefgT", + ], + [ + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "ochladit silnice exkurze zrnitost jiskra zprudka pstruh tlukot vytasit valoun najisto kralovat bobek uklidnit helma ubytovna pysk andulka", + "a295037a0335fc58e639e1eb4ad8c6679386cc0b6696c6c0947b9d4420083740c02a3c7e429c698b3650c5d370b87427ff094e17a18778d917cf5fa274c89b23", + "xprv9s21ZrQH143K3se5sFVgT6vXcaaKoaHse8ATQJAgDHVBfdwAT2BDgm5YoEPJKR7NN7o5ukvzfKvjZ16NsLG6qngxkRfQRKuSsqyFmcyjpf9", + ], + [ + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "bavlna mozaika ofsajd kukla obliba kormidlo monarcha batoh chmura mdloba makovice obilnice popel pohnutka duchovno panika neuron okupant rukavice kouzlo stehno badatel sklenice rozchod", + "a3314b5d32a47a746f1605029ef41e446e589ec3879b8509a93779bdb5df018c102dc93d3925b1bc04badc7b7e78ed3c79f05485a289d3a8f4731282f4b65f2e", + "xprv9s21ZrQH143K2NiewxC1w9akTDfjsfRQ7yyv42HTukKMZ2qqx9zRrq4YYoHUnEeSR9kVa8hY8vHzCYhPxzK8VF4vKJhQNAjGpn94j9r7nEi", + ], + [ + "f30f8c1da665478f49b001d94c5fc452", + "zajet nutrie beton kobyla kriket sranda elektron abeceda uboze lump vzorek potvora", + "a5fe5fd9fc7a02f2753029978da50e8c1af2a773977ecfda7147c184374376fc1780d4c2516d23eb1559e9cf46cc6f60d30418ba05fc789295adc483f26641ea", + "xprv9s21ZrQH143K3Pg1Wcq1fLNYrSSbfioYAiYMqkY4bEN9JrUFnJNLsK2Z7b7stHtJae53w7GD7rrDjJ56CCMNYJzwpdC54pSFkCGV3VYwGbY", + ], + [ + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "slezina navzdory odjinud oklika ucho ropucha rohovka zavalit graf panenka invalida katedra odebrat deska metoda ohryzek graf flotila", + "73716db54d10471971852df2bda795452cfe9b38aaef918da7a2216a3b4249d76b4627b603a03537e5dc2152e54c709acba85d361f4978733af4b7366b13a61c", + "xprv9s21ZrQH143K2YLLxKi6GZjifUEoqww1zAAUd26JY5T54Z6HgEip3hkFKUfAAeVqEmZrdoHoahhm71MvBwkMTZALYrJtZfe4eLqMyZE1op1", + ], + [ + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "zavalit genetika kapusta tvrdost dopad ujmout zdobit mistr splav ptactvo fosfor hoch pocit beztak slon poplach mazivo tancovat pravda uvalit konkurs surovina nazvat vypadat", + "dba03d22ab6f6963abff6d9f9433a6aa733490dab58b39e3eef635c9f4fd6ad8242c3eecc4db0f26a447af06a089d935b3225e36615a07babdf2177ea3fd1670", + "xprv9s21ZrQH143K29UvdRPWan6npJHgHs7bmiduFR6qWzf5z7gFuqqcR7XoHpSBamvgTn1Qzy3JqMSuyxJEnFN5s2s9mbMna7WAiKheLFAA4x4", + ], + ], + "french": [ + [ + "00000000000000000000000000000000", + "abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abeille", + "3bf3366c40256d7e2fca716fddf8673425c7c7e444af290ee1edf1bbf095e6e78a7190253f3e46f1e2069345d4b05ac17b242faa225c0a3e4d268976744e0698", + "xprv9s21ZrQH143K4ZsEXSdGmcpsqn4YxjPgHqa4DFvMRmD4oTkiFuYia3srKewVsU75LN4jP6PeXPYFWYpgP8B74tQjwG1GoQ9T8eJxGDjzibF", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "implorer visage sonnette voyage véloce pourpre volaille tribunal implorer visage sonnette voyelle", + "ab9180b7dfdde74e5cf8781e5692e2c0b55afa8bc1987fa8e14e3fb83c88b195c53e9f939f8febc33d2958f5fcd8add57843cb318d8886130ef9c9879c826357", + "xprv9s21ZrQH143K3MCzhsD85FFZ2d8vDN2QdRTN63gbU3qHjZxn7utU1kwYGR5bxQkssS1Tji4Tuw8vpTzDWogXxhbWYDKuZveeRBe5wiNsuFJ", + ], + [ + "80808080808080808080808080808080", + "indexer acompte bolide abrasif agréable dédale abusif appuyer indexer acompte bolide abolir", + "0c1ece83a464688d74744723d609e30e191d05ab8c082cf34bb2405bc4363dbcf6a9f83707b577d230728b3943920f876ec844e86dd0d117152c23802d25be3f", + "xprv9s21ZrQH143K36u4b8J8pxUwCCnciUPZF3JjZsq5mPCDEpNWA1j4DnYDJ53NV7b6cmNTM6Je6DG11hJw8Fq1HXKEasrpxDC8WqaEsD5BPGq", + ], + [ + "ffffffffffffffffffffffffffffffff", + "zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie voter", + "7d2f168ce71ba3e40e74baf47a072a94e49973c0dbdb33a62b3a285ab167c704a85d6ce0d15cc6a4dd3bf1311334ee0d290ae7d20115863d5f5633b8dfacf2d4", + "xprv9s21ZrQH143K2AsqW9AAdu5C4zUaV45MgyzBQAYbEKtKusR83UzLwCZdqDwqJ59ebNryoNuVA5pEiY1eBYqr64UGkwZGezwaceCqxPWia7M", + ], + [ + "000000000000000000000000000000000000000000000000", + "abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser adéquat", + "93d81d146eccb7c624cc25daa4cd52736d64bdc0fe020940157e73c108a87ee34d94d7e9554e02ea0f9a7ea5574426220bae7c4959c197a6c9e2318cb252683c", + "xprv9s21ZrQH143K2iCVwUFixFL9fh5f6XrcBfaLgRzozbBgzj3dTo7fBTn4EsQ8ERgq9hTPxFf2hgE57vJDfEGKwsegQFoo2mEM6HEgFavJkQU", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "implorer visage sonnette voyage véloce pourpre volaille tribunal implorer visage sonnette voyage véloce pourpre volaille tribunal implorer vinaigre", + "dcf42783150cdb92672c9ea7d13f145401661f10b89bfb012a803ca7713e97181ee28ac327a982060a7f8aaa6e8c649ca2c5b83c24458393fe41739ced31d987", + "xprv9s21ZrQH143K2Lq1fbvL5nedyALbSBmmm4EbcVduaPFArtunM6azzNy96pcKbLvVBQcFFDa3Agp54eMhCBH5Ehtbxitv525n2SrhYvALPiD", + ], + [ + "808080808080808080808080808080808080808080808080", + "indexer acompte bolide abrasif agréable dédale abusif appuyer indexer acompte bolide abrasif agréable dédale abusif appuyer indexer agencer", + "b039606212ccadb0d05c7a0c08605c5137028d0253d26b9ad6ee113f9595700d9834b2eec8b224975a6d9585d7ad39e962036edcf07d5b125b0fc225d519982f", + "xprv9s21ZrQH143K3m5hJrQxzUdU4bDDvLSisrf1Cv5HQNCEzbUokwaVa8X1huTY2JaTPJug14EbopY3gtdfWjmVoo4CHLzuwjf5Jhdjgaqsh9n", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie viande", + "e12d20a535ef5e9e2f87e05b5261bdb51451e052fe484feb87543f5cb7a8822c4aa0152492be1259fba00a28c1e95518a90f0645bdd0eb822516d37ac881f7e0", + "xprv9s21ZrQH143K2woSZYBmSoRYygWNGUUrkLiy2i4FmReSqyc568kb1siagkBpHFj6MzLbfuh8TaWKDckfnfphrYyKTAG2rk5y4sGv4fjn5gD", + ], + [ + "0000000000000000000000000000000000000000000000000000000000000000", + "abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser abaisser anaphore", + "0f3eec3279b55f3cacdbf1aef705a086078d7eb8048e402202572e7038e9487e39104b4794e88a42192af030a176b034fa36ca6641fb8128fd23c30806b96c23", + "xprv9s21ZrQH143K4UeephsshHgatV7uj2D2DotKpGrWx6ShwxPdRxXtyQWxnadSvjT8Df7UDxmRuiFJa92evePgqwgJSG5pY8VPJ8hNiyGHr1C", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "implorer visage sonnette voyage véloce pourpre volaille tribunal implorer visage sonnette voyage véloce pourpre volaille tribunal implorer visage sonnette voyage véloce pourpre volaille studieux", + "8f12b35fe92a7586dfbdab9721a91300d0dbe3185d0943021667e62fd5a643e0cf2443e544738c5234009aa50faac0dbb123ac847c31dc25d875c56fe39c6186", + "xprv9s21ZrQH143K43qySSryByKtU1Df5foSz6kDEHUsR524HZJzxnKrrU3wTdeSvHVvpitC8nAb2kdeVWGREu22KaiaMF3YjEZQdb7htpY6CXP", + ], + [ + "8080808080808080808080808080808080808080808080808080808080808080", + "indexer acompte bolide abrasif agréable dédale abusif appuyer indexer acompte bolide abrasif agréable dédale abusif appuyer indexer acompte bolide abrasif agréable dédale abusif axiome", + "53ab1d10dc8de3a80171b5f00495a3b49e2c5afd486f8111b1afd0ad24f43eb0aab4acab1d4c51126beea32405947924c237157b29dca69fcf64eb635708895f", + "xprv9s21ZrQH143K31JiBbFJEViuVwAuWSD5X8PKzS4d2PoSCxHpBXpicCEMKndL8TURUZ2zeoA4vDGkECeJS9wMhrRcmW6ATmPmmwC3ziuBRdP", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie zoologie valable", + "b5e96f552ba44ec827c1bc5ef362e8cea68dd6f36f2c8640aeb171cf9b66198fbdf155fdbcf7dc505431068f972a92442f33cda0065afc1e9a7f5f7097ea6c6a", + "xprv9s21ZrQH143K2umcmDhRrUZ8wsZ7ACj6rvFCEuDK1coHWpo1RwYPvy3dpWmvPjstSMm9fm3igm9gjsAesjqAU6Tnejizy919FSmyofhRTyS", + ], + [ + "9e885d952ad362caeb4efe34a8e91bd2", + "monument dépenser féroce entasser comédie ferveur optique sonnette codifier discuter dioxyde nerveux", + "d322acd69a849cce8719674eeb7cd76520de01ea35210012a44a5dcc19faf285202c3fb3c749a46d338ad54ddd398029ee308ee352a89f65180dbd3ff750dd50", + "xprv9s21ZrQH143K4RswQfcyMEjx6Kc5tEBR43MNp7XJH5mWushqBryZTc97VNPNVfRop62sGwu7Tg3vsd559P1G8h6M2N9j1Zj1vVn1919uvmb", + ], + [ + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "fiasco ivoire mardi révulsif signal enlever envahir anormal vaisseau essayer céleste sagesse engager mener différer ruisseau lutter esprit", + "3c0c90b30e1a8bd7aafda95f92fb09bae64988e2431d6c3896c8502f76203652f0db1d4640417d8d3f00ea4de59f1719513f1c01145eb8ee4b0fd73d4c4f706a", + "xprv9s21ZrQH143K3eSdUPkhpFZamFuu35iaZqRwFWijYkE54fvUKoSNBHkXetNx56yvcJSFoeHT9y4AFuWTcFFzezPuk6D6LqnNscjFnvdGYDt", + ], + [ + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "flatteur cultiver oisillon destrier brusque crainte oisillon labourer remède substrat parfumer banquier flèche enclave fémur sombre jongler damier insigne voguer rasage gomme crainte incendie", + "7363c9fd3127cb683ad39697f3a7282a06f1fd1ab1ceae8e2e0d7ab2766f3b8fb29162bf46e0d6a4917a0085b763f7f6f36adfdde742b6aa4ff1973149b5d239", + "xprv9s21ZrQH143K3YEnEhMfv1Mwoc91DekvEqXxL85fFtRKtfFk3Jsqu72bUd35jHsTA7aBShvTmhhBrHhqGZ1uVg7RTwzTpnarDUoGU8ZXQ9D", + ], + [ + "c0ba5a8e914111210f2bd131f3d5e08d", + "prélude routine négation brasier arlequin logique cuivre hiberner cirque moqueur halte barque", + "c46b545d5e7398d0b5344ecbcc20769fb0fbf674848eef1591725a1113f5bed0edf6d78925798cf87994157f43bd9d0eb5e6f3de7959e2e88f6a586e7499b79a", + "xprv9s21ZrQH143K4U7WubDzyDun3RrpuVsFECM9u9tNxjhJhZFCJL5DJvGhKkUAbmmhqpwUV7UvgPPG2QFoDq7jYY6Neb6MnQmQYTo3RF57ZXS", + ], + [ + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "froid soluble horde sinistre rouge rocheux exiler causer orbite résineux renfort vaste récolter maison serrure tonique cirer bélier", + "93856e02d3ab2e6738958350f2a96a18183c0c02aa7cf50e4e6877b1d4f9eb4be1806b034e4a4a271390b7b6ba6b4209f5e293840e93a41a2ecb16ad47936c03", + "xprv9s21ZrQH143K2wjyyXXC3Cra6k8WJ3CPEWc1EgwEyUNjLAxGVoegrni9eMik71k4L6wWxLtqcwgD9TzKLLiaSddwLFp4F6hJ4LuDBWqVJcq", + ], + [ + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "mouche embryon bison femme bondir renvoi louer social largeur déborder rétablir miracle adresse rivière machine époque culminer indice frégate ouvrage gourmand déposer exulter grappin", + "08cd47b905df56e3bfbca6d1ddb7ee7ae75d45f6e5928d337bacf34754d392c7225c611136148e130dc516cdc7ade8e8a95ba62ccfdac01a107875ce3e2cefd2", + "xprv9s21ZrQH143K3BFxuNuyFSUgQQ3f4tv6HLktHoVxvMfBKVBow3i9GqeTF9oBbG87rZBX79QTCQqgPbn3ywWc8G4ZiUdhdY3xDAciXLtE9aJ", + ], + [ + "23db8160a31d3e0dca3688ed941adbf3", + "brochure sextuple épisode digérer ruser affecter cantine rivière torse muscle permuter talisman", + "8e4635efc7352a6fa18723aff498fa297c1ed1997c0f3e77a11e65155b25934cf90e74ac66d207175507887068a5c85d24b825d06a31ce75651fc9893e509869", + "xprv9s21ZrQH143K2CpRxCahnStujg79zUscDimXKHemoY4A1Kep85cPai2e8wJ4Y5R4uhrG76merXXjSuukqjVrzJMBPsGC8apQqHymDsBPf9e", + ], + [ + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "informer poivre capable volcan dénicher voguer offenser ruiner tragique sortir glace enduire allouer serein cirer semaine opportun abriter", + "ed4ed89acf10eb53fd67c9f81f4e8cbe39dafe42c27e942e67559a825c6083d3373a3e98215c37318f0f28c13546895e76a080521222f6d70a9528a582dcdcef", + "xprv9s21ZrQH143K3N7dvQS9PoT9BemrTHWfp4qzUPT7hbGdZ5uMn6RgMwKerbmrrAqjrMGUskpGJaaorTXnbgtidgEbboJVjH18qDMkLFPf36V", + ], + [ + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "adverbe fuite jaune épaule imbiber éluder frémir adulte attentif filou fémur idylle muséum mobile bureau loyal hélium jugement péplum encadrer rédiger acier posséder pavillon", + "81ecca7ce712963df79d6611d2510e9fa31d307557a5eeea9513a9a940c2531472fec2c6988b70f649b8a3416f8f90f5c9c8f0ac4897f4a5a1304c651226f330", + "xprv9s21ZrQH143K2ZnKtKjoyhEcsuEzLEzq5oC8sGegz59C3vf4T8VjvRN2UQQsHw2ndFj1UMNo1uuVtxKzjmNLvVAd2SURTgkVXKykFc1S8jG", + ], + [ + "f30f8c1da665478f49b001d94c5fc452", + "ultrason hublot agacer éclore englober ravin caféine abandon séduire farfelu tropical nettoyer", + "2efa119637c044ba28eb610178d7de49dabed93fc16f5af675aa661b731567ed3ad7aeb36a04adfbfb694bbd065f6f840ab80369ec3c253ca122deb208ef9f7d", + "xprv9s21ZrQH143K4NWbtgfxvJK1Us782vFXDdb2bTK839KWEUZFnQTXXt85hAHXML9xkKyuiaiKgD1n6ytUZdgT8hirdn4SQ4DR4T4MPiNQz3K", + ], + [ + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "prétexte grogner instinct jongler sembler paresse papier vaillant chenille louve cynique dissiper inoculer besogne flairer jeunesse chenille cellule", + "887a87c38340befd47d650b73849907b5892a0db26e17ab55601e4e789ae1d0dd4bc3e7fcae0fae25c3e0d3315456fe8a5d84944d2b799cb63fb9544fbd0e568", + "xprv9s21ZrQH143K4G36f6wnN8JWRYHdbvANd8fF6c1pjb6T11LKxw3Xch5iacc9vyGQDcf51GrF7kknKumq5csscAByQiC1gaY7vFygMghGtJ4", + ], + [ + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "vaillant chance dimanche sécable bonus séparer vecteur forcer raideur officier censurer cohésion meuble agiter prison mutation filière rincer novice solitude élargir renfort gronder tornade", + "e59bf24814adb55cfc2399e03d94e81df4a906ca5e75f36f2e297623ffc418b8202e9b1444e0e97234e2d55e194d45f89491dc9533a1c799fbb86c5838cc3454", + "xprv9s21ZrQH143K2gBerhfhuxyfCEXGiLW3sxY1scEJUtvroAtxPqqatzqTzDmkgxDsL7C7MMbBk1ZKBXHpYiJziBM2VFbTbA3G1qjDkTt8PU5", + ], + ], + "italian": [ + [ + "00000000000000000000000000000000", + "abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abete", + "d2ae4bbd4efc4aba345b66dc2bfa4ea280d85810945ba4e100707694d5731c5a42ac0d0308ba9ad176966879328f1aa014fbcbeb46d671d9475c38254bf1eeb7", + "xprv9s21ZrQH143K3ZxfinfrsmnuKNwdvRtypJ1TEs8JuE6MEmAMDwsSZApCyBFopme4iR7RnRt9XKFprfLKs9vooFuFK6h2a2hzHuXTmE9md1a", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "mimosa vita sussurro zinco vero saltare zattera ulisse mimosa vita sussurro zircone", + "f8c609647319a50116e9b7d1a0ec5535c6d08d6c958911fd2c8b2dfd55a61e63e9c6c60c22b5c3aec725acb41980e63cb3ed75fb80648092dee1bbbeab476a6d", + "xprv9s21ZrQH143K3yxi91AAWZvT8797G7kL34h3453QNFSiQybwss1gmx2zYCmbg4tiZdYSEsd7arPWYd5MQh28VBvcEqvXSBRu1zYajyJnzFD", + ], + [ + "80808080808080808080808080808080", + "misurare afoso bravura accadere alogeno dottore acrilico arazzo misurare afoso bravura abisso", + "4025269bc4f7550bbc3c61592944946b0d4ac855a5e4582bf86069cc0c9429455cc40d84ba215ed1cec28e27ffc88460c38b9c4e8c486ae878d7c85e95b222bf", + "xprv9s21ZrQH143K4Hh5BqryXtMu7QLbJC7yDh9kscJ4h3PuxA382w6YyjMMkiFVyfmdYFwfP8sVWR1eLygHmczccbzH7pTGXbeqAy54fNVA13M", + ], + [ + "ffffffffffffffffffffffffffffffff", + "zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zerbino", + "24182cf43f956410b5def9df90e3db0d6f3199c2ebd26e7ddef888ee3bece9101d132e449bb9e1c23dd9ccc6131d2f649c021ee591e88cef8d17cb434ef69efb", + "xprv9s21ZrQH143K2hiPzq8SzzER9TQDFYpnYbfg1hE8wUYwcb7JNRyM4aDB14WfoUghRrBKFGffUx5YsTZvPbdCbuVMJG7egUZVsRTJCviSror", + ], + [ + "000000000000000000000000000000000000000000000000", + "abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco agitare", + "2161a4b869f98778b6321714e2502adb11ea120c12163b46fa34e36442ad1981b911a2f9ec82b497e7cd206fa7af2f21a94bb6e4a90159965854784e1558658b", + "xprv9s21ZrQH143K48ZSAvHY5BjAyPXxL3pREwQPZ9DxPagzRuK8f5TcKnDr3z2MSjB58uC871CjjjsNTaUa9BxEzEwraQutT42co4mfFGusE2B", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "mimosa vita sussurro zinco vero saltare zattera ulisse mimosa vita sussurro zinco vero saltare zattera ulisse mimosa virulento", + "d9a6205a985fde8c2337f6cc6acf77a93d6ec7dc792551c01400f5d9aaa86aa943416c99fe60be141ca27ab333d9f96648b40b266d6b2d6a6e5b07c8939568be", + "xprv9s21ZrQH143K2wPR9TuAQcWLNSM8X9oRjUCC3GN6aGevV1zfm8cwi2JtrzS21GzAaqd2MJDszoka7xiduQrDc666Wk27qYhUTagEfr4E218", + ], + [ + "808080808080808080808080808080808080808080808080", + "misurare afoso bravura accadere alogeno dottore acrilico arazzo misurare afoso bravura accadere alogeno dottore acrilico arazzo misurare allievo", + "cfb1f800cd5a0f7a8cffb12231fc61739f5f87c963ead5e205dd48221c3417eb1173d3209d9a8ffc4f00ab291bc22c1480b4a0a4fdeef9a1f3916d0ccbed5591", + "xprv9s21ZrQH143K2EQGrM2arQhKSEhd4DwraP86UrUKsVcLvM2NujY9rPJK78rGUCD4Z3AG8tz8brxcSaDQYDw18jZz8FuT1H6ZdwFyUQVERus", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa vile", + "05a43b9c258f6e83f4073fe4a66d6309e94610fe12dd5d598f4725e4e85ff1fde5ff5b1e61b40e09a481a98953f9dc818342172a460e5e6d17d9ab14874447e2", + "xprv9s21ZrQH143K39Y9dY1q4sf3Bv7dkFfDasdSbWUKNx7GCsMp1JTo8KFDRq5TNkGr1wQYm3QZaALpFhcHWhPV67oVZQFMRFu51yVxeL9KDMF", + ], + [ + "0000000000000000000000000000000000000000000000000000000000000000", + "abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco angelo", + "84055239f41c182bbfe6ede6db2e8bc4a97cf86746643b7ea6910c71d67bb2a678a97ecd378cfbf59e30db720b1cfde0faaee73afd3c5deef2188e307d04442c", + "xprv9s21ZrQH143K2b5TRb8ReAEzasjVej3ttSzyy5YRu91SdQKP4XUZtgeUipuJx6YoArxkiRSBU5eP2wu6dmgLhgBQJ8Bx5UXmwFudc423DdN", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "mimosa vita sussurro zinco vero saltare zattera ulisse mimosa vita sussurro zinco vero saltare zattera ulisse mimosa vita sussurro zinco vero saltare zattera tarpare", + "f0e226efcd929216020a9e8f879f06b146d28fecd2856bd401a62ecc0ece8bc6ea717e3f9df523a6a00bd4ca8965e0498d63e779e3156dbf174ebac74ad7be31", + "xprv9s21ZrQH143K2dys2Z5k2tZoxJuBENLaf3cTEpb7JUeXDp9i63vbPMqVNqHqx5bGJ5tdNug3JFWJCC4amzYLoFRi3YS55MiHnnUN6w1V57h", + ], + [ + "8080808080808080808080808080808080808080808080808080808080808080", + "misurare afoso bravura accadere alogeno dottore acrilico arazzo misurare afoso bravura accadere alogeno dottore acrilico arazzo misurare afoso bravura accadere alogeno dottore acrilico baco", + "ef549c1e44a7b183031b41f9f692795406de605e43ecc628911a38d7c92f392660c48313a08cf1a055a420d4a8c6b12bef7ff354c903303bc3a5dc12948ff5be", + "xprv9s21ZrQH143K2mWU418GviWbPrYTveuukEHsYJRn8aUxV5PrE4XacaDX74amiRkH3m3Qmnz7YPRRXkF33z5472Trb39RksWRmcJitkT5uJx", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa zuppa vedetta", + "5089f33aee7852d86a01e8afbfdc8a0ad5af51538e62e3f007d098fa4fc9817ddc990fa87b7235273798e2df52228b62738df923bc2d711fed9cc0558b3ebfec", + "xprv9s21ZrQH143K2VqjZNjnyCMUrTw6XhLt2BsaPVpHD8MKpKq5mq9S5SLyMSv58y7nCofNGZSgQQpky6aujCURjVuAM9jCcN6xjzbeRQYYACi", + ], + [ + "9e885d952ad362caeb4efe34a8e91bd2", + "pesista educare imballo formica curvo imbevuto raddoppio sussurro croce eppure epilogo poligono", + "4ffd8b7879c0c6d7eee14682a26465d6429b8b921d6ea3299fb8a448d84d19b47ead5b23fd14449539cbd358abd19a23560dbd8c4bf6c153d98ea0fce7f474de", + "xprv9s21ZrQH143K2bsiFmYu4jzf5fjcHrrEarDgY3NYhmUEU5bxz3eS3NwS924WYnioF6rf6Fij6XQdmCNjcCJwqdFJ1AKKLMxa4obLnbdFgA6", + ], + [ + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "immolato mummia oviparo sigla stirpe fonetico fosso appetito vasca galoppo cigno solubile foderato pargolo enduro sociale ormeggio galateo", + "188305ae9b45e400f6a3ad839061265f36e6050118283b85a3ea842aae1cca29c808978b3b0e297dbd794b74916fc43da57172e90c9fdab930638863c3472522", + "xprv9s21ZrQH143K4RNJpMYxxAuHtA77jzNEAjh3MznXe6FejAGGUPHTDUFL3z6LB1FioxHnMirHNcHyV4QVsXs8rZACW8YSJcNo3Wqjg7dNoUC", + ], + [ + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "infatti dire pudica elica camola deposito pudica nobile servire taverna restauro baritono inflitto flacone ilare suonare nastrare dito montato vulcano scrutinio lisca deposito mirtillo", + "093ef04fe24f1c45148f3d4d9a54fb033638011507418cd7cbd91a8fa12157e1cbd9d095b2a660db26e8d674cbf6033a384954fdeadcd7c20cbbd3da46d90f1a", + "xprv9s21ZrQH143K2ZBg22DZJyspAmZcVMa1efjpsz89Hmcsu7dPZ39sH5RCCNr2kBRNFQUUmcwsNUTyZ6UGk7zjZKgCdXrmxg8gJ7FBCEeE5Au", + ], + [ + "c0ba5a8e914111210f2bd131f3d5e08d", + "sarto smottato podismo burlone aria omissione dipolo marmo coricato peso malto basso", + "d9e2a2e18ca8173859b0030186941149f630483cc9fcf3b189e5752d4f8b7dce2b285008f52ff1301dd2e2a673a4c76f8ffec9f8617fd577173b90c6af95631f", + "xprv9s21ZrQH143K2FR5gEkuFMhmYGVyUKiSrZspfn52HonhhbvwWrn5fL7aST1yxtAfd8cQSyWVGH9TamV4SPvyKRZbSV2U7ZTurX1Zoe86ngE", + ], + [ + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "italia sultano meccanico strappo smeraldo sipario gommone chimera raffica sforzato sfamato vendemmia segnalato oscurare staffa trio cordata benda", + "c40130a2db00d82c2dfb127c768724c522cbf7f47b464061198c65e9bf4e3879262dd112cb7a526bf4450785e9f7f7e7511f05985d9104d9e75e1baf038c91e6", + "xprv9s21ZrQH143K3QTUdUYC375Cvtyea83NqatsgA5z3BMp95Fbd7QfQRvzqgjuCMU9zhSgiVtAYuDoR1GK9gQRP8juxnFR2Hd4v3mNgfMySGq", + ], + [ + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "piacere feudo bisonte ignorato brevetto sfida onorevole stufo nulla docente sfuso perbene albo sinusoide orologio fulmine diradare mitezza iride rata londra egoismo gravoso luce", + "e384b6486328949618978c6d2607df3e7a9db9acc94ab24183aa4e7c1af0107ecbcee2dcead27d7f20acaa427d3d6eeac620ff24ae4ac2ba3b6ef01585418f25", + "xprv9s21ZrQH143K32TYshJvJnEHVnwukKyvaQauzBPx42JYyGT1FfyUvjT5iEfYuaETkYiAUJE434hs5Qkh7FRSqK7kwy5GwjsfS4S5txFKwbL", + ], + [ + "23db8160a31d3e0dca3688ed941adbf3", + "calmo statuto fucsia energia sodale aliante cedibile sinusoide trovare pila rinnovo tiro", + "5d5faba1d0db08a9f0cdb602e571a9b73565707429d2482e4fcde5a9bac1728b053c65853199fbdba73716bcb8da0616820fc817a309c99607dc56dddb34c344", + "xprv9s21ZrQH143K2h5d8kmFvaQT4xHzXrAVwmwAMyF1p7jBg2QoE8RGGFWe1NyqcNPhy18CJ6UKcvHTXkijihhLE18yrpec1DxggywYDVWGiUo", + ], + [ + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "modulo rubizzo cefalo zavorra economia vulcano prudente soccorso tuta svedese limitare fluente amico srotolato cordata sportivo querela accusato", + "7f7bd54b8bf5c99a949d3ddc1d4baeec78e503f14ddd20500e307be89e940e5ead97530c014c33053a9b0c942094ea1bad649b2d23d6288dea8fcfe2e3a83c52", + "xprv9s21ZrQH143K4AwqRHE1Swki4WW3ok7NF5cCs57wYAEhcaDhw9oVh1xwSbCeofP9GMZkTmZo6kSjj5Xh36tuuPebZhDBQRcgRnzLaSgrpL7", + ], + [ + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "alcolico lacrima muto frigo michele fessura irrigato alce ateismo incendio ilare metallo pilifero pergamena canotto opposto manovra nemmeno rimorchio fisico selettivo aforisma sabotato riciclato", + "197457046ab546a171b247c54bb8392aa2ee2d40f07831019776745f17aee46fe9f1611f86f9d7f0cbcacc03ce696082fc13529ba0cab0d57f76934383be0f3c", + "xprv9s21ZrQH143K416VC54NFDGXsQeXLSAf2JaUD8jQR4SDqAFq2S3BdcSRW66avfcoRK5FsPPCuBKaShrskgoGchxdAeBzVMPFHrJkCwAWgiE", + ], + [ + "f30f8c1da665478f49b001d94c5fc452", + "utopia melodia allegro evoluto folata scuola carisma abbaglio spillato guanto unificato pollice", + "53c4c5de8a16381908e397fcb8ce5dcd8c90911d9b538afe83862468816889768d94d040bd249f4eb25d915b05b31addfa0b06d89fe15f521fbf3c8545bbb434", + "xprv9s21ZrQH143K3u8cCFUJiaxUCKdGZ9Z2u76hUbKNMoCy51gq982aahsMbN5ArmhR1VHFJSMKLsFLkTsSX2gwjrEfj31QsDqCh3nE6FmcV4e", + ], + [ + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "satira lusinga mordere nastrare sposo responso replica varcato colza opinione distanza erario monetario bici india narice colza cilindro", + "5c8c80b1e440dad220a295b282fad7e8a44bfee5210d853fd52d26e8a006787ac7bf4b0a4f81d029e2ae9cdf71814f193bbb23e4b3e149d2f99b03e2417b39a0", + "xprv9s21ZrQH143K2gMABxA98Be2P18eaj1zxU5qV6sCiMT42cuvLQ3dM2VBnEAvpFwWEDtDcbSkteNAF8nUuCyBETqpAeKmqV6niTPFEECGcLx", + ], + [ + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "varcato codice enzima spessore brillante squillo vento insieme scoprire prugna circa cruciale peccato allusivo savio pilota inarcare simulato precluso sugo fegato sfamato lusso trono", + "e89b83bd1a5fa859922e0045acc84cd04edeb4bf6b5352d197fbed50af0938b17bca7ab9beb8c882d0e0a67597d9e14e88c10e63b824e9206d2848fbb8a55b64", + "xprv9s21ZrQH143K42yTQvEavGhekzrzpxHY1nspnh5qcgThCuNVAyJPWRMeznMV9FnChg5f7k51DBMawNZKWTFCLy2az1CnyGgCJ2Jk5PGb6Qv", + ], + ], + "japanese": [ + [ + "00000000000000000000000000000000", + "あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら", + "5a6c23b5abdd5c3e1f7d77ad25ecd715647bdafb44dab324c730a76a45d7421daccee1a4ff0739715a2c56a8a9f1e527a5e3496224d91293bfcd9b5393bfff83", + "xprv9s21ZrQH143K2TDo8AAss7eUkUqLFzBnypFpqjQUMVUrSMvrrgLiRxQPrYnhfoS9NPp3rex725rcuN8pkDL6pwqWfdPtiqa9ib1B37vZwfy", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかめ", + "9d269b22155b3c915b09abfefd4e1104573c528f6977cde89c6a68152c3c714dc6c7e0e62f221c322f3f76e4d0bcca66c06e3d2f6a8d70d612c87dd6dee63976", + "xprv9s21ZrQH143K3kavBMu7K49k18vjQHhNL1ciMgn7S9kDMKdyK1vEpF46UWyoXCvdBLEp8U2bhissPkC6iwXjMgRXyQ6SHbyYYGcnFqNXTW1", + ], + [ + "80808080808080808080808080808080", + "そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あかちゃん", + "17914bd3fe4b9e1224c968ec6b967fc6144a5795adbb2636a17f77da9b6b118200ad788672fd06096ca62683940523f5178f6ce3845c967cbd4ad2b3643cc660", + "xprv9s21ZrQH143K2NAPUK7UVbLB4Dd7Hvb7fqysvFyKES5iujX4BfrwUmy1wvWJb3kBc1Zs2jxTTBxBPHuHziB1ZWWUxELrn8g8VLrbjaWDmRe", + ], + [ + "ffffffffffffffffffffffffffffffff", + "われる われる われる われる われる われる われる われる われる われる われる ろんぶん", + "4bd21b75de4f262b0771a97d6fc877ee19329236ced6e974c4c81a094a5f896758033f7eae270216d727539eee3bc9ba5cad21132a1c6e41a50820e0ac928e83", + "xprv9s21ZrQH143K43f5tXeZRJ2RMiS6nLhxcqvopg9mc84xTiX1UjLjVQDBHrwmypY45SPscFqT7zJet5b3riay95fJMM4dfZXtoBTcKKkKEao", + ], + [ + "000000000000000000000000000000000000000000000000", + "あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あらいぐま", + "a59401a14bb821cce86ec32add8f273a3e07e9c8b1ed430d5d1a06dbf3c083ff2ffb4bb26a384b8faecb58f6cb4c07cfbf2c91108385f6773f2fefd1581926b5", + "xprv9s21ZrQH143K3VMwP9nGq47t86uaVENmykbCRuUDKFDSfgDFjJUFuF88JfPPMzwgwFPoaJaAD3YeqrCQBFY5S2jaCXXuc5Vg7u9jb6iB6XF", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れいぎ", + "809861f80877e3adc842b0204e401d5aeac1d16d24072f387107f9cf95b639d0a76141ab25d3dc90752472787307a7d8b1a534bea237c2bb348faac973e17488", + "xprv9s21ZrQH143K29NaQCx2DxPkszvvbYj5FmZ7RMMAoCE932mUkfzaAYFf18JiaFC4bJujA7XAsm7TFddxdkXfn6U34te59Bp27CWp71mw55c", + ], + [ + "808080808080808080808080808080808080808080808080", + "そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら いきなり", + "01187da93480d0369fff3fc5331284ad6a60cd3ce1f60dbec60899191afa2a2b807cd030038a93ddaf14d4f75d6de4a0e049ee58c92197eb9ca995770b558486", + "xprv9s21ZrQH143K312KY5MRB74dWa9BDHG7rV4oK7VAfA1eVKPDddPEUTXRZ5ShDzVQJp7d8q8xQLPYVcHYVuxb7sUo6EQpJUytZRHxyytSYbV", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる りんご", + "a1385ef66f20a905bbfc70f8be6ecfec341ff76d208e89e1a400ccea34313c99e93f4fba9c6f0729397b9002972af93179dc9dd8af7704fa3d28e656248274dc", + "xprv9s21ZrQH143K2LmZMWVM3JxKTHZEDZg1ZEUZH6hx9yJhBWRSgGGYD8TAaPa6MYto1t1bBXgPYFMLx1Gidw8fJADdFNzvqrAcXiadUPfTTVh", + ], + [ + "0000000000000000000000000000000000000000000000000000000000000000", + "あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん いってい", + "c91afc204a8b098524c5e2134bf4955b9a9ddd5d4bb78c2184bb4378a306e851b60f3e4032fc910ecb48acfb9e441dd3ceaaab9e14700b11396b94e27e8ac2da", + "xprv9s21ZrQH143K2WD9BSegbAkGzg4XbqeY7gzCYGWaWfmRifMJJtmDo1pjXmyuEwPnKcLwTZ1uqosvTRBAcPdUUvdHxY6rKj6R28vWVWGLKuu", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん まんきつ", + "79aff5bc7868b9054f6c35bb3fa286c72a6931d5999c6c45a029ad31da550b71c8db72e594875e1d61788371b31a03b70fe1d9484840d403e56a1a2783bf9d7e", + "xprv9s21ZrQH143K3ZPQiQ24sxzu5PsqazSLn1W48saAFWiDhugDPp7dKB3v5JLfMqzTbqjdwE8P2UxFSKwnFc5CpgMaH2dSmoWDRuaAbrZbJF2", + ], + [ + "8080808080808080808080808080808080808080808080808080808080808080", + "そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる うめる", + "0f46c02350b3f1227c3566dea2ff0f2caf716495a95725b320a31a3058d5d62596fdb816be75909d2c5f7094beb171dc504ea8ea60f5e2e40bd8aa0d9339aab0", + "xprv9s21ZrQH143K2TSJ2oumYNzqQGKmvehh1NKNzAjpu6Ue5yPvtzFvX8aCvBk2eTg8TJfwjiGLfA2KCiajZ1VXBvtQXqk7Wryxgps4BYyNmZt", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる らいう", + "a0705c2feebefb61509dcc49c57586c35379c1981c688fc1d452da44443d9a651a374f1ad2ee3d7847b50655cf9241d7e607be436c0df7c8bac42f2a82985a79", + "xprv9s21ZrQH143K2k4V9TkTiFB2LviDq1oSHbRha8AmnPvBtRRVAnf9WJERojPPdki6sbiuNbxv91VhhdreJnaZh29Ay892Mj6KB2aZnysqfvR", + ], + [ + "9e885d952ad362caeb4efe34a8e91bd2", + "ておくれ げざん しねま こりる きぼう しねん ななおし ほんやく きない けむり けまり てんない", + "b80f83f27ec3a6cbe804be0661e9bcc30583484dbbd37f689d4952bdf4ad29d9b9f5774fc4c87b733169416418b81f272a3eab37feb22f5c8f6deea6bb08f8c1", + "xprv9s21ZrQH143K3VLugmPmzLDwfFeo8cgoZ2ajCQwWhGKfXut8C1XhdSNuAnXjz5W2bbbNPmr87yMHAaPMaUhE6MNnfGc21WRc5Lj94Tbbnnh", + ], + [ + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "しはつ たいちょう ちめいど ひりつ ほくろ こやく こんかい いひん よろしい さくら がはく ふっかつ こまる つごう けぬき ふすま ちから さくし", + "926ce4647a8f91552ae00efa8880ed7e43b6f8e9cf51c38851b0e242569ea96d77a19c777d28dc33d8912c3e3bc6c59f7a82b6daa25add2c39a492fdebae79da", + "xprv9s21ZrQH143K3eVmFcDa4FcZCGeNryYBv99mdgidpSeFBt6ppQQjE6MXegs3xmT4arCDXvtg6dGpr7vFY8A9bzzeJ7E9jyzWLPDSrixwqub", + ], + [ + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "しやくしょ くちこみ どんぶり けつじょ おとしもの くうぐん どんぶり たずさわる ひたむき みうち にほん うわさ しゃけん このよ じどう ほめる たいよう くふう そんちょう ろくが はんこ せあぶら くうぐん そっこう", + "94308a93dc1bc12f8e917b2445581240d83cd82ad3c52f9ba4125aa6ce5490a3624fb3dfd7e22923ef7ff3b778157e8bec76392b122bf465fcc56ab4f5a73401", + "xprv9s21ZrQH143K3ResRww4txupLREzrNjYYi6X5FKpKvFUoCwhJS1HtSn21gDkXcBYxQBd9RngafHfWqktMmLgPrVJTisEQbRn4strGawHGpQ", + ], + [ + "c0ba5a8e914111210f2bd131f3d5e08d", + "はいち ふかい てんすう おさない いろえんぴつ だんち くださる せんちょう きさらぎ てきとう せもたれ うんどう", + "5fae92448afda85f10a50236144cee3068ce21e20a34447a9a4b6e9d5b000a4347a151d7024c2068c4d3c29c46a6f541a94b98624cc25b2c8ff42cafe6a3087b", + "xprv9s21ZrQH143K3PD5fc3CCepnLDsenZAqyKpcbquY3BR9sfosi7rbjXMo5nL9qUb91FwYUFdN9wJt9v95YoKJJFm9V7a2Xb1sZgstQkZ54cL", + ], + [ + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "すいえい ほとんど せんやく ほしい ふうふ ひんそう ざんしょ がちょう なにわ ひはん ひつじゅひん られつ はんぼうき ちそう ほいく めだつ きさま えがお", + "a49ff09e55b62b8fd3d4b88b4fae2c9062e18c06105c796505fde3cc7655cfb9c922c02817d18dd40832ecd19d80a71fd62d915c34cd8d95fc55591d12b6f677", + "xprv9s21ZrQH143K4AKun3sek391JX1qnWpxriP3eyJviCUq6ouiH3RDzJ1f7Gm6c7dgAkxn18EcaZ6CBNvVkmLxVvB1fdBdLiGeHXf69j4eCR1", + ], + [ + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "てそう こつこつ えんちょう じてん おおや ぴっちり だんねつ ほそく たなばた くらべる ひまん ていき あんい ひんしゅ ちきん ざいげん くたびれる そなえる しんか にいがた せきむ けしょう しあさって せたい", + "55d101db3cb8872853a3e84ec97fdeac63fdab33d92def4dc4694beff0f504da29f953bb463d9cbaf0c4d442672d40c5a58d6aed35d5fdbb2768dcc482b59bc0", + "xprv9s21ZrQH143K2dmFtHdM2tu7mDdKwsbeU7ekYU2dsFDBt7dNbXcsLTnN2MNi3hQssGdcPgEfiXNJcgnoo76t1nAHaoyVBXZ1z6hP8L2UGTs", + ], + [ + "23db8160a31d3e0dca3688ed941adbf3", + "おたく ほうりつ さいかい げねつ ふせい いいだす かいてん ひんしゅ もえる てのひら ねいき むいか", + "1b0fca340ccf977258987a793b3e61b0e20291f8c27645e74621e87c01d0e881cd601bbb0ed98388d22dea341498ed74aea32975a56bd3bdc6027196b7a21640", + "xprv9s21ZrQH143K3Z6vsGR17YLtiGF2gTkCm9Z7XnJm1ffrLQ9ah7AVye6NyACmsWLZBoREcdCRS7tq4Hrx1NDWqHj3MctxWixcH7XBuigtJri", + ], + [ + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "そむく のぞく かいふく ろてん げきやく ろくが ともだち ふじみ やおや まかせる すらすら こぼれる いぜん へんたい きさま へきが なたでここ あさひ", + "d7919c8a5458fa4ff55431021938b15bf39b7542df902f371625d9f064a37b1d06a34cba920a9c8b8d6bf34514f542f5ee91b9eab81a063f9acfad932b43c62b", + "xprv9s21ZrQH143K462YnNY39Q7Pq8ZXzCXs9k9GexnGbyjVvu3QhrNLCkPxNUtaKZBzqffnmiuU4ZiA5UQKtwVqr1WmXyM3QjVaVg8Cc93xMDQ", + ], + [ + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "あんぜん すうじつ たいふう こんぽん そこそこ こたつ しんせいじ あんこ うしなう しまる じどう そうり てはい ていし おめでとう たんまつ せんげん たおる ぬめり このまま ひいき あまい のらねこ にんそう", + "1003a30a516cfa1c30de2a53fe6c5936dcb8ae893f944f459ea4e1f2202716320350dc2ee5d92289dae3c5b1771fec863fbbc40146fed04d0855c6af70b0c7aa", + "xprv9s21ZrQH143K24jAnV3a4K7xAoD486pMXSvAj41fkB61DopHqcyznUX1zmkFgEGBpNkXi6dckNcpcwXB65i71eBwP25t24QZHVRGJYURZ2Y", + ], + [ + "f30f8c1da665478f49b001d94c5fc452", + "ようきゅう そあく いきおい こうつう こもじ はんだん おんしゃ あいさつ へいたく しすう ゆうびんきょく てんぷら", + "17593d396c66d776bc15c06e5348bdfa38927daf92402c335041dc500d7c8ea9eccf4f4d1c187785b8c9128d06bd7048a1706006fab82abece74185448caa811", + "xprv9s21ZrQH143K3P24yRmaXsA2pntRyM375Kb6cF4P73bMQNKyXUPPR86X5o83UmTi4iyQWaCL48EoJUVqC7KxsPXbrAC4nKxjMh7FZJcucRE", + ], + [ + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "はえる せっさたくま そんみん たいよう へこむ になう にっさん よゆう きあつ だんぼう くねくね けらい そんけい えほうまき しゃうん たいむ きあつ かぶか", + "2567b4dc469b5d1d7c4aece40e642dea3d5cebd80a577b5a4d72fc2b60da6ca657d3a01270c47530ac71f812e648bac01aaadc62c444749fddec8982430fce7c", + "xprv9s21ZrQH143K2UfZfzss5CkDCtkRJvLN7DmM4sWjUaYMF4rfeWDERACvg7jGSSkGeFLrcHdpXUFty7wJ5yzyzcbRDqv7b9H6usZ16PnKy2c", + ], + [ + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "よゆう かんけい けぶかい へいこう おかず べんごし りえき じゆう はんい ともる かほご きぬごし つみき いきる はかる てふだ しほう ひろう とくてん ほったん こさめ ひつじゅひん せつぞく めんどう", + "909c8c992019adde332a11f0ebd1b0c0fbc9dd96e4d3d30ca4ecb0d06f743841cd25380f87b3a538f46dfa3fb3a5ab330487f99d128b1c6bcdbe476d3bbe2af2", + "xprv9s21ZrQH143K3a5iyuaeKiPGQbhQLUaBhzfd7inUA5ndrmcYEc7zZzTLGM37Du2M11nXChrzXyZ8ZYtH2dG1CkWE39R749XhcKUcVs9avTR", + ], + ], + "korean": [ + [ + "00000000000000000000000000000000", + "가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가능", + "a253d07f616223e337b6fa257632a2cc37e1ba36ff0bc7cf5a943366fa1b9ef02d6aa0333da51c17902951634b8aa81b6692a194b07f4f8c542335d73c96aad3", + "xprv9s21ZrQH143K2EgqD4YCzE4rJ8rojXAMzqftKGS7694ApSkSoLgheNMawZYv2sArwHhLq4AaJfV6WWtGLjFWdFBT47wsjnq9v6iMXojWZ1V", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "실장 활동 큰절 흔적 형제 제대로 훈련 한글 실장 활동 큰절 흔히", + "e6995bf885f5c64932ca28bbb00bc100a6b89cb6edc987bb05f05f99ae7caf78329029c189834c1cca938000bcf08423da011558a60cf3d90c9035eaaf241b9e", + "xprv9s21ZrQH143K3CgBqqMtQxnP4VvSCjaTs2GfqHadwo4ddmKkvzasAHRwAsSDqjvJQu8jmAdEgBrLkVYhHdyZKWkZbyfuwPQG84PrWjEuCLQ", + ], + [ + "80808080808080808080808080808080", + "실현 감소 기법 가상 걱정 무슨 가족 공간 실현 감소 기법 가득", + "1bb52039a6cc288cf806740836002abce493724edac3d3b9458e3581427df76414b422171ef115d823a01c6b39fa68bd0fed20bf5e64dec008fcb22e4b7f26bb", + "xprv9s21ZrQH143K3v6uaDUdZX7Cr8uC3hCE6gJ1MiGsnmRojRtUN6Y8nBiWVfMUc1skLwuUb3NshkJSdCuFew5G2y6YTDCRsSWNxYsJgZCpRxL", + ], + [ + "ffffffffffffffffffffffffffffffff", + "힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 흑백", + "b6eb986d6aaf7d0cd0eae2a667ff8bde68c8780fb5a728cf500e29119ce99c9b079a4217836879c1e73b8a85422a85b564d819699a4310a1d007b5be24c24b6d", + "xprv9s21ZrQH143K2P5vpGbzebpVw9pZzmHHyuoTFDAFCR5UTVwQPdkuKPJB5fP4a6YgAT6seAuv9uGsMcnoyVFkVxoKZxQgB1SXjy89nHvvSHx", + ], + [ + "000000000000000000000000000000000000000000000000", + "가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 강도", + "f40a8db48df9a7fdd73a7b3ceb45f668e4eff098f275a0a5cd739d31572c90aa92bc08b9043d0adf059a945e47e2fdbc26c89dcc15b3893a2a705e4539523ae3", + "xprv9s21ZrQH143K4FQh3Y65u7oFeQhimhg8fjRV12vp7kYxB1EnjiBVFY1B7AdjQgLcfzK8qLjaZKFq4gfPC5pQtFtDnHi6Y988Skm2oRr758w", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "실장 활동 큰절 흔적 형제 제대로 훈련 한글 실장 활동 큰절 흔적 형제 제대로 훈련 한글 실장 환갑", + "3162bc17e0f2f01ee571022444d2c5fbddf6a68dedfe734c319fb574592e9c0328f6526116b3b0b025b23391781d0bef8f43bc8ddc2b054b9f52e1fd6a88e3d2", + "xprv9s21ZrQH143K2cE8CZ9tqfnmvNZcEJpwnyRRcsqDPokupVqx1hecEjQF2zrM6amGPiDiEKGZdNWrps6DdEcP83UABBjV7yJSkAFUWcP1FDF", + ], + [ + "808080808080808080808080808080808080808080808080", + "실현 감소 기법 가상 걱정 무슨 가족 공간 실현 감소 기법 가상 걱정 무슨 가족 공간 실현 거액", + "9fa92e4524e0f7412935b2deea23593c0955f9679d3285e3b955f5cdd2a659ee005ee99bd385f63d82cbdb54a3849229fc9a700e198b65a1452b511884b543eb", + "xprv9s21ZrQH143K2XL77upQ6FjJr8a9oDGHakG1HQozxUzHJ1aVbv6JLPuX2nXdbopUnxBoKgVBHiZphPg4Krqm1xxUm6YPcZg9NeAiqT1MAcK", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 화살", + "2543a88c8a31570dc9ee868a7b153f7f2e42700778bae7a3aba7017357e708b5cea97e0d9753c9226abc90b83c76ae369d74515ac64102c51a5fd0f809cf8b92", + "xprv9s21ZrQH143K3AK2RE2fUZyLssNUUJPyAYjXGDGE7Ysq8hTx7MG43NG7KDALxx6TaVjXCmxFwB2wZnNtSBM2asDYC4YcDMEc9sbCyPPYjdo", + ], + [ + "0000000000000000000000000000000000000000000000000000000000000000", + "가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 가격 계단", + "edb71011bc0c227103ba8a769cc36ba609e5407a771727fc0c8cba1b5a44d21ab9163d9deaa37427ccc579864e21f08d0fdd3a53a6be258d3c73b898a01ce2b2", + "xprv9s21ZrQH143K2vZcddzTch42FzN5kcvsdtyMNR6QfEgZy1JEor4wzwFKj4JGq8kJEyC4zMQHhN7Q9mhRZJdYceTALfwxmpUAD6AtSzU3n7L", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "실장 활동 큰절 흔적 형제 제대로 훈련 한글 실장 활동 큰절 흔적 형제 제대로 훈련 한글 실장 활동 큰절 흔적 형제 제대로 훈련 통로", + "dbd640cc9d3e99939bb0fc4473738571e314c29468f01fa85f57e296cf6e8e269d6e32434e46aaa63384930cae83728623195a932a48ccb71a9ea247720d9371", + "xprv9s21ZrQH143K38C9hPGqNHuxsvKmNVwY2gRiRjjbzuBNme4PgfyLzkhYEt4fGm73xs6c9QDh2GxxkntMiFyeDsMDPkLDa9TkubnWZFCsJP9", + ], + [ + "8080808080808080808080808080808080808080808080808080808080808080", + "실현 감소 기법 가상 걱정 무슨 가족 공간 실현 감소 기법 가상 걱정 무슨 가족 공간 실현 감소 기법 가상 걱정 무슨 가족 구속", + "9a0ec04a48287ae628d61428f921de5f40fc1035f21883798e05c36f9705b2525a00ebd6bb89fcae9b8af8e9861d0083de331199d6b85b24cff598609a49b305", + "xprv9s21ZrQH143K3PRHhckbBdnb1HMFJWXd2oPh4sXWWP8iMrH5fkxKnDucKqdWFv895Z7BRWKmbHj5gRvB6QddHeMUrk7wzSRzf7ZqkkVCipS", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 힘껏 허용", + "340bd57209e54e8bde6ca750147933f7e44995047da87b61f64f70f26f289a377e25a65f5efb11f9e651917ec9866d54846516ae0fba956f5f536422bb47d91c", + "xprv9s21ZrQH143K4Cr2Z2NiQPe5Xz6W92ZCE6SpW5NVmfvjtJgJUAG6WwkQ4iZ1AyfbUDb3yoiQsdoGHSSXNEMtAX3xPdtD38n5JeD8Lx7XNR9", + ], + [ + "9e885d952ad362caeb4efe34a8e91bd2", + "원고 물질 생일 부산 마요네즈 생활 일찍 큰절 동화책 반성 반드시 의식", + "8d148c7f8ed529d7a88fe2bc8bff574b56406f9928ab5426df793f4d3a5121c7c6974c856ad20f66ecf04fbecd3bc025912b3e41d500f1e5be896505e01d08d6", + "xprv9s21ZrQH143K3t9XU9hQ1sEMc3LTT3MZ4Ar51RchXDvo5sjxDF7bFNaLfz7DttnvUqKAThXzv99QKccqpLQB6DdgR3NJV58AixcCdbw6ZTu", + ], + [ + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "서비스 알코올 오로지 착각 카운터 부근 부정 고양이 허락 비디오 단맛 체온 본인 완전 바람 철학 영하 비닐", + "3b67b06a2386240f75abe8f7905fd0fdb4cc2baa88c090eb9bca3cf144e6e33bbf3dd9085addfa52cd0ff9f2f9cd63ca69e7e77ce903ace942ec7f5b451148a2", + "xprv9s21ZrQH143K315xG5w3u3mrnhSMVsNVdKmA9VZVXeV3fAcLX94k4N9oDEgSAxsMi3RhACEKFfgWkFex6T1uHSjSeHPxnnVF7muEAVNycgE", + ], + [ + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "설렁탕 모범 일곱 민간 낙엽 매스컴 일곱 언어 지진 통장 잠시 국제 설문 복도 생방송 큰딸 약수 목소리 아직 횡단보도 중독 수필 매스컴 실컷", + "06b321dd10cd2d0dec17212163c5d31f5ebda67027c0159380348d31ec5c5e7914ec75a44d4e225bbe5ce3db967e2f1ae2c9d463a638951b3e16d75ecb92cb17", + "xprv9s21ZrQH143K4TY4YjtQLxBPerqUshALn696njp6gNVkBTYWWZ5jrQPZRuqxiMoJ6RjQpVgVZFqKBRsWnGcci6UNgPdHbRBuVn93aKdCD1n", + ], + [ + "c0ba5a8e914111210f2bd131f3d5e08d", + "제주도 처음 의견 김밥 공부 연출 모델 시장 대합실 원래 시금치 군인", + "5e68ec0b343b62e221ede6dd5d6f33dcf8b5b4f4925ce6a30f49b17182ed0a40f7c7f3248463843f1999dd671a2e9c2abf4e5443a4e88f2bbf10b79524cab827", + "xprv9s21ZrQH143K4B4gzTqVD1szP9igPch2u3xqQZ2gBsYe4u9kunYh5smSB3Md8EXktwjWafLwMasGuLPiSGXPCwNTgdcEPBsgtq6MiGMscje", + ], + [ + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "소음 큰길 식당 커튼 책임 창구 사흘 다양성 일행 질병 진급 혈액 증가 예산 치약 하룻밤 대한민국 그날", + "c8a07b4a163c3cf4ef400a96bdb7edc012dacb957326de185e66f7804e912c02329ab07520ef05dba38b2b3f6ded8a8691e1b17a38658aaddaed7ca95ff1588b", + "xprv9s21ZrQH143K2h4eVKk7zbdHmjz5U5poyBbddPTS38xb7rjA9NMdUjYC3Dy2X7top1kVw51cFuJ2UHmFU3WGAzb5Hz4imvuz3ZKWy2R7gAP", + ], + [ + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "월급 보너스 금고 생물 기분 진리 열매 콘서트 에어컨 몸무게 집중 우체국 강제 창고 영혼 분필 모든 심리 소나기 자랑 순서 미디어 삼십 술집", + "683d1f6324fa54a4c4efa9b0573fae573ebc1c8b373890eb9b1e6f760f586126af2a3a39e0494f653ce6dbb954353023c304dd42d80aa939eb5a31acaaa3a60b", + "xprv9s21ZrQH143K48a2XvjEnkvM3ry54SZdbERB51GvtK6S5hbSwV5SbBkqa2KNW7b3gwY7hC2JMgiNMD45aMhABCDvXUoZTvrq6typLaUAz6k", + ], + [ + "23db8160a31d3e0dca3688ed941adbf3", + "나들이 침대 분야 바이러스 첫날 개선 논문 창고 하필 윗사람 저고리 팩스", + "f767f63c4febb5c832890f6129d0c3721555de40c28ac11093d23447f507b98f134cfef190cf0f12f1e41278fae5334f460c24c69cadc9aacc5d98efb3903f06", + "xprv9s21ZrQH143K3K9kkX6aq8Tmqp5RjoDwbrEbqStVfNmSWBofcYA3wYA2MQsDsTZjkfkeu7gz9yJB4foKXE1mveXDf48vdA7L5mPZfC8aYdW", + ], + [ + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "씨름 정도 놀이 훨씬 물결 횡단보도 인천 철저히 학비 킬로 수염 본격적 결심 취업 대한민국 출연 일정 가운데", + "739584c55ab1c8053a44ca3fb50237e066590c92043cf3f45748768df65778bb79175d511543d96112f0a0e7960df081f74e6e477b953a1681cb5331de8abc3e", + "xprv9s21ZrQH143K3XQJtWHu2YWz62N1SFBLpbweVNpCUoeFEWdukPL2rXvQ7HoDBwPWCnBc5otLQnHomemkmZ19m49YjQTqZY6uvjbDQaWpS5B", + ], + [ + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "개구리 속담 액수 북한 실내 병아리 소망 같이 관찰 선물 생방송 신용 유난히 운반 남대문 열차 시설 양주 재판 보편적 증세 감기 정오 장미", + "068f3943d3b3ba61b74e7900d936fcf4d73fc74852bc011e7405213edebed9f1d6b9a25db10c3ad5552b779225321a36304c757d0479e8b591655d0188961120", + "xprv9s21ZrQH143K4ameDhGSneS8UaxoYBfQ547c6eDEBvDJJ2cqzFHCCfqcoybLTVreVRjQo6SUDKzoHeNtR9bCQY2qF3iWCJTheeDYTUSGdTs", + ], + [ + "f30f8c1da665478f49b001d94c5fc452", + "해결 식초 거실 백성 볼펜 중세 냄새 가끔 출근 상인 한번 의심", + "5f7125457857a8870d1ace1eb0f87479385d08ab8827998f57cb0cab5289d31a360310cdffaf4e8d1202a13fd8bba2ed9bc240a59b6d486d418647c55c7bca44", + "xprv9s21ZrQH143K2fhpmAA6AkCVJWY7je61aLnS882ga5H3cMuoSp4G4SCzg47MRUjVFQYVytFdSu3M1hYyhW3xkuGqxnUXx1K6jFTg4C5gmst", + ], + [ + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "제한 스위치 아프리카 약수 출입 잠수함 잔디 향상 당장 열정 목록 반장 아시아 그토록 선풍기 약간 당장 단순", + "8c6f94c633c8752381e7bb207083025d7cef6c448695393fc21553e1ac269991a3ace1a2562a6129bdc34494c7a6c01d19f600da9af985eb001d71d2fb9e1480", + "xprv9s21ZrQH143K2b5dBGtut1we5Wz9S2L2XAXfj6xftmT2omNHimaPwbTWszDvwSLfpjpQCjXKfqW827u8a4ADhCQEnTiiFj4dtbc2DZJRucn", + ], + [ + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "향상 담배 박수 추측 기술 충분히 협력 성적 줄무늬 인체 단위 딸아이 왼손 거짓 조깅 유명 석사 참석 이야기 크림 변동 진급 스케이트 하지만", + "0ecef71bd6f0948d9186c2786086a00f7140a00d37c836d01567077aac0dbc69f62189c02a9138dcc79a74dbb676b74aad4959fdbbf1d06a7798385f8eec97b0", + "xprv9s21ZrQH143K3zjSpKnVTgqBrJfMK5iZXLrGb5Z4zcWKo9URusFq4n7YjnLR3RCqD8Mytzk4qjHnk52PfdQUHCCJUnKnZxqhMXGGVVe1NXZ", + ], + ], + "portuguese": [ + [ + "00000000000000000000000000000000", + "abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abater", + "ab9742b024a1e8bd241b76f8b3a157e9d442da60277bc8f36b8b23afe163de79414fb49fd1a8dd26f4ea7f0dc965c760b3b80727557bdca61e1f0b0f069952f2", + "xprv9s21ZrQH143K4ayH97er9xirrbGL9hEywmMfh1LdQjwtrsnrvENN7c2yKs82HypXo4GAMt4wpnna9doa1FDFYXQTSFReWDY4XAf4imN5m6s", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "imitador vinheta sogro xerife veleiro pomar volumoso tratador imitador vinheta sogro xingar", + "298d1614ff06ae803709f5be5331135cb74e6cc77fa09e07a3e887c2e370401f9a73a409dadf58b5a5197b27ffb3fa5dd528aad9a1a8750d7669ce950ee60c2c", + "xprv9s21ZrQH143K3H4uYufypQuRqf28rLoZpLTwjpeCiPBpcZtJpupYd2oS39oGnrHd7fPAgU5d8bfTpYd97MShp4f9fBGj5K1F9NqgZFpmbVj", + ], + [ + "80808080808080808080808080808080", + "inalador acirrar barulho abotoar afivelar coruja abutre amostra inalador acirrar barulho abduzir", + "800fd4e7691fbc3ceed246c211a38949c3607fe269a35829e40ca9d3e26515a4ebd64d8bfe9b66b49543fe9dab78bde7cb7102968ce669f55293bcc02e26ba0e", + "xprv9s21ZrQH143K2qEuVaHnXDY1HbcQ9nMyNoi5tgGyFxfYXVxHipQ9hcmS2QitJxsNFatCZk4EYoyyNdWamAjJiMLhuimpjiWHPvJCw28EMSr", + ], + [ + "ffffffffffffffffffffffffffffffff", + "zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido xeque", + "7fb404372815ea28ef97a64249acd71a293ea0437b3dac8f7e193a10f3584e2055753cc8d6f025229f65e61318fc4e10d4017bd3cc3496f535eca3247d26acd6", + "xprv9s21ZrQH143K3tfxkHq74PSrq4HqTjs5sHHxBpjoP26GnJ5Q8w7tEn5kmPESuqN5TQb9Lu4LysqMAcXHWNsr3DKSnvuu3vx6sK7V6Hhv2iD", + ], + [ + "000000000000000000000000000000000000000000000000", + "abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate acumular", + "81c66b6789e8b91c169335be4436fd9736ca9c06425acd09b0525e1d6836383130f7f7d31378aaef8b7109503972f40d42f6c6b9f99765827bea762515d3404d", + "xprv9s21ZrQH143K4LsdmZ3NinpZHGbQ6n7aQr5uV8Rv7Fq8yNPdAzsyrezon8NZ3ZCzode5jS2PXzN1C68amwDmp2bgAEF4jDG7NUbdRYCjR8r", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "imitador vinheta sogro xerife veleiro pomar volumoso tratador imitador vinheta sogro xerife veleiro pomar volumoso tratador imitador viga", + "17040704dd985478b7d0666c7078201e3cd7d1fd1aca0d7d47c98a91ec7845500c611d987339a1d4c12bc506feb7c486eef0aa8ce679b1d184db5ca40fe8ef67", + "xprv9s21ZrQH143K3XAGBJxF36qFzxkFaSEsNjqKvCtT3s7WfzgMBRcv8G9K2CRGXXhLYPWKSipBrd9dyLSRuTzQWbAJkhghki7Nn13QfHqCSBq", + ], + [ + "808080808080808080808080808080808080808080808080", + "inalador acirrar barulho abotoar afivelar coruja abutre amostra inalador acirrar barulho abotoar afivelar coruja abutre amostra inalador afastar", + "0f637bf3a487c26fb73f6a464f62ef1f6ca73a6ae083e220374c82881bf4ed2dafd874956ce368c4441e6269759c5864197e87421fbcdb7f6d63df17b4f7df81", + "xprv9s21ZrQH143K25VJsZdwtDCmzZ5C2LkJyNDKrHiFfHHBEmtvn77g7qrBRGHTum98TqU7sWCGFZ8vjtcPVAfgGcV51vi2BrPR66KC7wNxb3z", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido viaduto", + "042e40dacea1df76335445c37171e5c0fde334236abe1b5d69378548875d157968dfff5889641f16690dca9baa4d9e5fbf56e3aaf0765144ba96b819f37fd0ae", + "xprv9s21ZrQH143K3xAXH3i9VReyK3HSyzSmN11DXikYFTA3senE3iWDCdYTFXL9JkBM7CeCS31NBBHNu2tH5T1iDWCBEu1TeWLfELH4CaGAiRR", + ], + [ + "0000000000000000000000000000000000000000000000000000000000000000", + "abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate abacate alinhar", + "8fe67c9f53a30f75513830e18f6bd0950354297a4977393fae3577363393e679cc13452bcfc9460b28a913ab8de9efc55f5901d1ba77e5eec791afd967768607", + "xprv9s21ZrQH143K3UVmtSkznKJCHUGjkjoHkUd6dxdfo91K8sdpEVmzjyRMB3Sf2WC7WKzmZLw2cfJ43LAEENq2v1gASK4TmMUTkbWVoJaZLge", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "imitador vinheta sogro xerife veleiro pomar volumoso tratador imitador vinheta sogro xerife veleiro pomar volumoso tratador imitador vinheta sogro xerife veleiro pomar volumoso sucata", + "feac9ad4e1a4a4399a7d57fe47bf64b404a7588eca1025abfa299365f7a75639317e2c89a94812db33405aa0213846bfd6d53dfd02743e2cf3b6984eb9fcf19f", + "xprv9s21ZrQH143K2Syz6ZuTcKmPtPee4Xn5HMEnuZcNZ1s7hJdgjRLFJ8f4d8DnoBBTUchCBjBnjubsz3wum7zbhdp5h9hm4g6DVDo2LaHGJ2a", + ], + [ + "8080808080808080808080808080808080808080808080808080808080808080", + "inalador acirrar barulho abotoar afivelar coruja abutre amostra inalador acirrar barulho abotoar afivelar coruja abutre amostra inalador acirrar barulho abotoar afivelar coruja abutre asilado", + "32c8feae6a0bee33166468a770cb28459727e10f4f5ffef64977d5ef52a68ec51d832751a10c025058612ab256052cdfa9d8c5c87560de0453efe5a7d4597771", + "xprv9s21ZrQH143K4XMzpdgrkDGxnU31ezynvtw3iBEfRB8sriHpEwyu2Gb65ao9YLcTTWTyxNh2g2AdtYmZ4wpTaAxLpJBzWY7jAvG1HyotoEt", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido zumbido validade", + "739a6edd208d09e28fa97f8e8709aaf185e173125b1b427c04d1539173c88b78e81610a759e14f97a2038dcdc2c466a072788e3d7c88cc9bf36b96cb29510e77", + "xprv9s21ZrQH143K45qUnDL5tCHKGpht6amXS4d278iTXWRJXthNTufwnbnvr6rU8kd4Nb5s9aBWdYFtfcdGkg4GdL91jRhGRtP8mZbjtTvpGsy", + ], + [ + "9e885d952ad362caeb4efe34a8e91bd2", + "mexicano crosta farpa empolgar chatice fartura olaria sogro centeio defesa dedal multar", + "1f0397e6d2aaf8d6867d648e9bc27b12a4ee1b61a47fb63c6676c153c472d708f02344ac56fd1a8e135e18cce4eef711e7e88529bd6c54b90715e9b3d9fb8467", + "xprv9s21ZrQH143K2ynvNymKuhxopGpKrkH5skB2FqBYXP3N4goobBbXfYS8Vqhr6QAZQqxxr5caCjvSC3P3itpqqbntU9jTmmEdoM1E8Z5f1GU", + ], + [ + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "fazenda invasor magreza repolho separado emenda enchente amassar valente enxerto cachorro roteiro eliminar marinho deboche rodovia locutor envolver", + "1335d5a679638f63a494f1b71f6c6c448ccb0384167f3ef3ad07456f0b70f13b8f6097c1315186543a09325ca3581f329cdb66674d0f97c4474950e3aef3b9e9", + "xprv9s21ZrQH143K4MHxCTSXTFPDppSnKcW22kjYEg7NMCcHEobe5G337nzsfnuud8asiYwnyMQMG9WkAwPW78E1otspYE4T5t2AU2cArUhhQGg", + ], + [ + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "filho comentar obrigado cunhado biologia clone obrigado julgador rebolar sufixo pacote atingir filtrar edital fardado siri janta conhecer inibido vogal quiosque genoma clone impor", + "ca0462775b11a28cb36c497a36da8e46c1ab618facf7640b42fd4974085e1d682a6ca660560a3b72dc602ff56e4027b53a8ffb691a96e4c827ef4e6d665565bf", + "xprv9s21ZrQH143K4B1eibfqLNQbrVycyNgNCgQvDFtBLDYbEPtVXRBn44GPmw8fasfeCrV5tc8BFhzSnbg3pHdafof5rrXHm4XUK6EBrpoZni5", + ], + [ + "c0ba5a8e914111210f2bd131f3d5e08d", + "pote ringue muda benzer andaime levitar comando guloso carreira micro grilo atracar", + "556b77fc49cd57f7c9c92fafedac1c8341598666721b874db50da261c7cded491c22ecd3235e508822507212698f645bb198f0bb1aecd50d22339e77619a765e", + "xprv9s21ZrQH143K2NhKv3Pg9xyGsPMDwukoomCFE74Fk4w4K6pe8hetKjNrSWEmzPSr482zkiZ73aE5wTYY8jvLN4Wruv83p6mmxnxkF7qkUBM", + ], + [ + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "frieza sirene hibernar setembro rigidez retalho exagero cabana oliveira refugiar recrutar vazar ramal lousa segmento tocha carpete autoria", + "3059ded790eac1a5bb614c2a88989a4b5d7d4db20acc95f2a9eee1a5889012fa2b7ad2c0b0c5b81abe94d3e4c6c58265058fb257bb051552fe5f82fc45389132", + "xprv9s21ZrQH143K2EN6vqxgJ2XMXNZx6GWcdcFXajpxqDfWvsrYFETHVWUEZr34sP49GinmReyfUgpakD6xT99vcV7yiAvPnf8BbEJ2PsWf8EH", + ], + [ + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "mimado drible baioneta fantoche bastante redonda ligeiro simpatia lamber copeiro reitor mensagem adeus resumir lombo enraizar combinar inapto fosco orfanato gincana cubano exibir global", + "f26d817eb6474c6ac3358737afd31a4b4be74ba268cb7dd0bab44f959c9b4be5ef7d65245bd0da8f21694bf380e3e4a9fe7f82777b4d59a8c738fc460b0c3210", + "xprv9s21ZrQH143K4QArHuoZ7djwjgsdKRekuqKqFEBZbYpAQJU2a1mDMm4z8iG28oBs2kAEaGQDPjLu3kiNz3BV5Lio26Zt1z5KzEBxtSJGtCR", + ], + [ + "23db8160a31d3e0dca3688ed941adbf3", + "bifocal semanal enlatar debulhar roedor adquirir branco resumir tora modular patrono tangente", + "fccd6ccf9cad7af20eaaba21e9f4fbb149907c41b5e000ce398e8956c15a5436e04091402d4851c4cc8cccf9e8a90dc8219f3104698d1022064538c6303dcdef", + "xprv9s21ZrQH143K25Rf7o8uUBtDjSZkJ4S2Cspm3JN9USxBAXmmUYvw9n7W3qsxbkkptFhejjufMUtKx5QhCMG8Z6RjT58F9kVrRGKMQhatmtb", + ], + [ + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "indeciso pires braveza vontade criada vogal nutrir rodeio toxina soletrar gelo elaborar ajudar sediado carpete sarjeta oficina abreviar", + "c22c6e716250a3b98b0f342f77d4f1fe9a4eab81304fbcc9eb9f9852db769b4164daf2aecf72e6d9879713768628780d0b9900ece13c75aa1f433d48ea5c9839", + "xprv9s21ZrQH143K4UsyxJK2nxQFmMtrqR5QUuHaK1KiZkp1LZKMqPuUCCe3xqVWDycrKjDSctxm2sPQ72MBM3yZx6tX7Jvemccncy4nw3HEjFb", + ], + [ + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "adjetivo fugir irritado engenho iluminar dourado fralda aditivo aprovar ferrugem fardado ignorado moeda mesada bisneto linda guache jejum pastel ecologia rapel acionado pneu palmada", + "6fc110cbcad37d6a43aadf52643ca9172f51c6fac45bf0a17e60e0fc24b5d1cffc73dd0606c427ef789f9e96c1d05af88a806005a21a4f2f93a5e41ab19fd7d6", + "xprv9s21ZrQH143K2VBbZdEtqReQrWkiSUvySRGbPbyP9sm8vHAWDwXc1GwsBHc8LQU82gydYVQ2YCDGZKKzKPX8SaWCf2jrQRC7hVAgb2GYZuD", + ], + [ + "f30f8c1da665478f49b001d94c5fc452", + "turbo hoje aeronave diagrama embargo rachar bochecha abaixo sanidade extinto tridente mundial", + "d666e6f21c3f8934aa38e45db96ee64eb490156655c2be5d4da4359fc9b11cf9ffda5802ef0eedcc154fb790c41f50ec0cb40b4236972538d8a6e27e54115706", + "xprv9s21ZrQH143K4CtpNWJhUqGJ7sMBw5MfYzKSNUmFABS3NwoqGtdAXUMyci5F11H9Vbx3kbiEqjDPMvTj84nMVZM9PF7u8ouNEruefbPFc9G", + ], + [ + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "povoar gorjeta injetar janta saturar paciente ovelha vaidoso cancelar limpador confuso degelo inflamar avisar ficheiro italiano cancelar cacique", + "cb72a39ca9d39c4283398a9995754bdff1785ccc0d96f842d748f4fe904f9dc9a963b7e89ca8070154edbc7d1efc90e1554ac4dc34646c38d6950ffaabeee350", + "xprv9s21ZrQH143K2GgN5EwWK5f6MXbTAvTvN4uiu5pZSgb4MxBAy8VTabQfb7Dc3kp1VmEuKTWJbUtM2Hu8KpFUKWPm48ubQ5JHUHg5PeLwz2m", + ], + [ + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "vaidoso calota decote sambar batida seda vazio flora queda nuvem cadeado certeiro matinal afetivo praxe moinho feno resgatar nervoso sintonia dobrador recrutar gorro tonel", + "8c6d156ba11fbc606a92071e7230fda2446333510ef5f9bed4712b2d737ab43d2e06c4fb3929dfd072ccc8b9003c6bfa62d5b8fcf04396508c54215357f6f8cf", + "xprv9s21ZrQH143K3fnoXd9pUHy7b6hH79o9bMW45Zc9486jaN1KKJVZrm1XosHw3sduFw58ADzqLZR1TvaB7enqXZoB8hyptgcijczutBxqKNB", + ], + ], + "spanish": [ + [ + "00000000000000000000000000000000", + "ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco abierto", + "29a2ee16de47d07025de37e7d9c596869439f9bcd26a702d2bae64db2bf0f68383841c5444b5b3bd39dd720d2ebe59969e110e5955c8e6d32c6c3294fd87439b", + "xprv9s21ZrQH143K49iYfUTNyLe6mVRHvYSg58nfiLkcSREsu5QefrsvQ9KWsMtX7SXsXwvs6J1esWdna2weySpUFZNN6qiXuHcobEMWGLfyaHG", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "ligero vista talar yogur venta queso yacer trozo ligero vista talar zafiro", + "1580aa5d5d67057b3a0a12253c283b93921851555529d0bbe9634349d641029216f791ddce3527819d44d833a0df3500b15fd8ba4cae7ca24e1464b9167de633", + "xprv9s21ZrQH143K27g7EMkgY2F1fuyqSEKq6n1iJCHuiUX5F3oGESmJSS6DcKW5JZ6qWWJ7x8wS1FCrd1NhRS4xCWDn9Bb1HzBuNpitD7FeYGv", + ], + [ + "80808080808080808080808080808080", + "lino admitir bolero abrir álbum dejar acelga aprender lino admitir bolero abogado", + "a89366f7f9c4bd98afca8edf1242507506562b8eb8a3a60468cafcb6f3037aba1e4d9a7497f6d49fa94aca87c95703873741441a719325af371f8eda9b59dc83", + "xprv9s21ZrQH143K2dG5ptughpsWSbdXdRVg6ZZtF8RehVMaDNM2TJ6NZAtorTDm2EVpt5nwpsgtjgYW3GD6oP8Nk3ZhibRQFRJ4f5JoDrunY1m", + ], + [ + "ffffffffffffffffffffffffffffffff", + "zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo yodo", + "a9d1f751178872cc53fc5433e9b2a97526448adc4b824cedeadd8a127c2416481345dfbef2bfc78275f3498e40b4e8e2e00560100e543aba3f324e752f032bc9", + "xprv9s21ZrQH143K4TU3oETVCyPLTqmC8C7zqqSR7L8JpMiR68YNhyvfEmXpRh6pP8gPghpFbvNSQCQppPDf55iNnZhT9iza6HRpTvKeLSDNFCg", + ], + [ + "000000000000000000000000000000000000000000000000", + "ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco afición", + "6c9f21d46c56f723cd734e308f10ebf44b5b92a2e0d80fd66a2952b8d37af5219e0b93c59e1d8e63b47ac657ec2c524e5fb951d87cac824f84a3ac6264b7aaac", + "xprv9s21ZrQH143K3AjqVTqs8gbpkEoSkCVEM6dAGvRm2TJgxTLih4TuPPSp6gheAkXpPRhG63Fb9Cr5MEto2j6hGJ4ZVPa3C1GHXUyPPwMRXCV", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "ligero vista talar yogur venta queso yacer trozo ligero vista talar yogur venta queso yacer trozo ligero violín", + "f73b28d7e180e0a92c57276a29489c10a992c8a465ab61be0ade4708543436a682b2a3c22de57c48736ae6f29bebf3e506779c74bc1a835ad6b9f4e174126ca8", + "xprv9s21ZrQH143K4PEMCi1dMq3ZwveC5um6cXR3tp4Z6LUGLhz4pmkaDU44UoSTiMQHv5icYPjH5EooZNorbDB7fLMDa531HHrKKnEEqCT5Tfs", + ], + [ + "808080808080808080808080808080808080808080808080", + "lino admitir bolero abrir álbum dejar acelga aprender lino admitir bolero abrir álbum dejar acelga aprender lino alacrán", + "f799e5c2782b50d0eb1d25b5f94984c5b4037ade236c6aa3b48b3df01b703d8ede5f94555f4e78f87a642a9676ba052865418c469c5739b3e93acc528fad30b7", + "xprv9s21ZrQH143K2UeG5FGYFmkW7oTy35ZFgQ7qdR5tzBdKxGLCEfVJPPA98e2wUpfD3Eg6GS4833dFVVKafB3RNGMSZtxoWc56Yxo7PaBgYds", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffff", + "zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo viejo", + "2fd3964ac77c52232dc0eb2ab237fea2de9b7509005214101ecbbaeb40f34bce7735e848fca6339f76f289904c6db959fa573fc0aa607d969ac256693b4fb7af", + "xprv9s21ZrQH143K3zwjASrAazc9EGeoVcQXA3unTmgxG9ZS7nc75inZw19oktj1y3n2Y7yetBatSN3v2UpS9ms3PvmrgQEMC4jox4ZV1ZrW6Qz", + ], + [ + "0000000000000000000000000000000000000000000000000000000000000000", + "ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ábaco ancla", + "f600536eca941ed937318828e9ebab24b3b571558250e7a8342fc3cf16c458b2d7b36c36155a86cc308f7bef6d87b05d5dbe347f1a83c3dfbabd89e9c45b7883", + "xprv9s21ZrQH143K2J842VWEPWH3ssnSvZYhRCzPoEcifAN4UgETeYkTdvnMUgnuftLyeGttvdvec8F1YJCmQz5mS956jsb2m8yDXZtnxRgiYgX", + ], + [ + "7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "ligero vista talar yogur venta queso yacer trozo ligero vista talar yogur venta queso yacer trozo ligero vista talar yogur venta queso yacer teatro", + "3d2a3aec779195f2628e800879d600cfaf2d7fcfa998657068db53906a00608fcc94fc78ceab8c97d6191389c4e468815ea0d11ffa4280c34c3cf17721a27c73", + "xprv9s21ZrQH143K2WBRPum95TFxfz8niK5sbiDpQjyr915SjEJc99BrYoRhPuYvfzFhPwqUNAFtEdw4khqQMK4ge8EnTZZASbv7oy8t6SMzVSM", + ], + [ + "8080808080808080808080808080808080808080808080808080808080808080", + "lino admitir bolero abrir álbum dejar acelga aprender lino admitir bolero abrir álbum dejar acelga aprender lino admitir bolero abrir álbum dejar acelga aumento", + "dd095dddb50de059f5cb6932d529ad37dd32d40f72da3d0c7671ffc6bd967b4392fe233e5e9a4d9e5e60413160ae215e34375db85e95ccbab4fd4712f32216ab", + "xprv9s21ZrQH143K3SQcqhHXxwZ793d4RXPpUQJQm8Bpf799AZPzicBxB87hu4Sm2DvWBqFvmxEjN3bY6EVzUxhJbHKdtV2k6u4c3ZNRFGhZDma", + ], + [ + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo zurdo varón", + "deea21c6902df5ef4a8efab8e14de53004c68817ea3de421cdd184f4159a6e9947376ed794c3ce67534f37f80b46674e85335555b5c53f44fdfef27991fedc0e", + "xprv9s21ZrQH143K4TyBobPSoDLEze5gKjiTZXzaJaND1QHqmrnx6kULMJhGvQkraSHgUsjmisepryPQqTfWyM3ETLjusTsW35KumQ3w3RyusSM", + ], + [ + "9e885d952ad362caeb4efe34a8e91bd2", + "obra diadema gorila farmacia colgar gorra pausa talar cocina duda dragón optar", + "fcf6ebfc7d9eebab56ca868cbd2d5d05a6f2142ba903c52855dad4ab8c0c2cf6b4e047a2dd97cf382ae717dc18d155a45fc798e6f0a0b89971a4224e2a285701", + "xprv9s21ZrQH143K3pxsjjkbjzEu1f9qaeGb9wTLZ39rUF4CoP125zApXELXDspSNV1Cn8vjvXKNQymm8iwSRpJr9AZyKvHTVVbg1Tq6kY48iTV", + ], + [ + "6610b25967cdcca9d59875f5cb50b0ea75433311869e930b", + "gráfico madera muro rutina suelo falso favor añadir variar firma casco semana fácil neón don sección morder fingir", + "5b48222ce814960e3b2f507ba58e96b4fa655f76060943b47c7a1396d431c570849e6f1595add9474934a72110bd3da06824428650be819f8d093e0023fccee6", + "xprv9s21ZrQH143K3JpnkDoEPYdCo6QEBW4eUfKe1CCweKfHF5DkonVNPQRkDcYEva6pBBfGLeRt56UB6oSnhemWzbSBXCpdefk3hBDWqUAPb2E", + ], + [ + "68a79eaca2324873eacc50cb9c6eca8cc68ea5d936f98787c60c7ebc74e6ce7c", + "guion culebra parcela diluir buitre crecer parcela marzo roce tejado picar azafrán guitarra exilio goloso tabla mando curar loco voto reparto insecto crecer lince", + "5dd9ecc2a8f504413ee001e4f27f25ad14533a35b3986b4ad505a9774740d0c0a6bbac6953a1ee47104357f4a5bc4acbc0f71813f9532fa667f3d3b6f2d6dd6d", + "xprv9s21ZrQH143K4XB8BVsQ9TsrC12DWTkizmcY3X6kVqycT1pAVLhx3EHfWow3H27QV4YH8kMLum7nzjSexrAxh8tKZzHRYPPexmAaaM1KEYQ", + ], + [ + "c0ba5a8e914111210f2bd131f3d5e08d", + "ración sapo opción brinco árbol mismo cueva lamer cigarro obrero júpiter azufre", + "49b0de91db6c84527afe1bccb2525b93dbdae0306bd3ea8a1f629ea1704195d450a0a3211894c417f586fde217f024b4159a4f6ac7f5d18bb8b7bbf72c4f4d20", + "xprv9s21ZrQH143K3W9fk6GQj1oNT2gYszJhNBhZjPmkTsR2jmoE89oRHHknYt8WLWREtopcnPs1ZWoJjV3A5QxrW5crBA5s6bWgp2DCfLUDA5Y", + ], + [ + "6d9be1ee6ebd27a258115aad99b7317b9c8d28b6d76431c3", + "honor tabique lata sultán sanidad salón gafas carga payaso rostro rojizo vena retrato móvil soplar trabajo cifra balde", + "484af722d01c9cdc9ac50f3fdfeec010c7f713fb90dbfe84dae21d8215b683e660ddeec44d685faf3e653f396ef8ce0d341097c50bffcf67ea094ebb44294df4", + "xprv9s21ZrQH143K2ouVUYDQXJpeurwoTTmfvUThuo1vRhuSXrVrKgsxAtaet1U9M5WZDpqaiLAPz17LLSuHmQG4eMMAy48Zt4AMzUwgNnEXY1Q", + ], + [ + "9f6a2878b2520799a44ef18bc7df394e7061a224d2c33cd015b157d746869863", + "océano eterno bestia golfo bomba ron moda sur médula danza rueda núcleo agrio salmón morir ficha cuidar linterna higiene pensar iris diario ganso jamón", + "8cc9507c9ccafaf341a243e5b82c348e374b24c8c594131add8684cfc1e61ab51e5476a4006d4d780bd2b82e9d9581ae1af67c8845e40246d5b1110814a88088", + "xprv9s21ZrQH143K3rpBRE8Wy6o6fZ6P6SX9ZrPCATgfgMHBHK4y9vbkj3VW19wRGR6tAeT7td2iB5bvwRXqXZ2FkBCmeCsJD4Uxf363BEuBwtx", + ], + [ + "23db8160a31d3e0dca3688ed941adbf3", + "bucle sótano fibra donar seco aire campo salmón trato odio poco tierra", + "55b603a9cd15a9769e21fd22a384d12de9afe0b9c0af0f07aee688cddd792b2863064767a6df9e8aebb4bf10d4482de07ffe6d7f7440df73f04fc544236fee06", + "xprv9s21ZrQH143K31JznDuVnKRYfF538PE1GSe5W75rLGwpSuDFWaQrW48bSuzvkD7cPWqLHcjxi1AjQYFjzCEVkwpU8sq4XScgZigY4TQrSEk", + ], + [ + "8197a4a47f0425faeaa69deebc05ca29c0a5b5cc76ceacc0", + "llaga pudor candil yate detalle voto papá saxofón tribu talla infiel exponer altivo sonoro cifra solapa pata abuso", + "b63a7651d8655add895fd8a45f0fd4c0c71bd8863a8e0fd72782b2f36d43ef2fa8830ab46647afc8c437e701aed41b0bc6b2df9f11887c44457aefe2c11d413d", + "xprv9s21ZrQH143K3CSbDbXN4ckMcyDHyLwkrQqvXL4xBRATernArEtGvZG8eFhxLbbRBZqaBnRc3ZyrN349dRxUeAozveLohZ5AWRKsDuk6XT1", + ], + [ + "066dca1a2bb7e8a1db2832148ce9933eea0f3ac9548d793112d9a95c9407efad", + "águila hoyo maldad fértil libertad estilo historia agudo asilo grosor goloso leopardo odisea nueve butaca molde lacio mañana plomo exento rey adicto puño piña", + "e4df51858246fe7a1f5b7e0045704ba76ff9d2b099707ea1d8b731dc3216c3de4edc63bad0911179d818b20e2c2a4e8da9e62dac242f6369221802e25abd0ceb", + "xprv9s21ZrQH143K381uk3B2rYMvPGDjn8oqzxK2tGqoNmB9eN2puxmZtB3BximsnfUd6u3eKP58aVTrUmKW4xA4ckETJwd6YPVa7G8nLkdBknC", + ], + [ + "f30f8c1da665478f49b001d94c5fc452", + "urbe lección ajuste enero faena reptil caimán abdomen sobre genio túnel óptica", + "f5e417f1f68c479cd3058e836ce47aaa52629ac4cb93e99e8025ab38e76a6fab56f6b5a6c1f20637bf29e108f41bca76a1a061d8f8ea40f7c0e5a15552c23ae2", + "xprv9s21ZrQH143K3sNRU3fx6SQaMRXAAJPHtmBFpXF5MhZ6AEURc2zE2gmVexqAA6EFyTBUBfxv982cwPLR2fM81SivaJXcN2FdbmgzrFbEdqs", + ], + [ + "c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05", + "rama jeringa logro mando soldado pezuña pésimo vampiro cerrar mojar cupón dueño llover barro guerra mambo cerrar casero", + "0ae0e69a6ab7c290e1319018a36a7481b6969f73745db1fe56ed4b928b17458bd86e580b6925ec6b64558e4a1431b4761d0928928b689c37efad8122edd7762c", + "xprv9s21ZrQH143K2VwsYAPzaKfUBfB8WtQXQux4e5R2cnLhipQ7zQfwWqg2Hozhrh44r1ZtMDzxVDA2PyUqEBtu9o2BidJjQ2psh8QspU8siVK", + ], + [ + "f585c11aec520db57dd353c69554b21a89b20fb0650966fa0a9d6f74fd989d8f", + "vampiro célula dos simio bono sondeo vencer haz remar papel castor codo nivel alarma rapaz ofensa gripe sagaz otro tabaco esfuerzo rojizo jinete traje", + "c87970357a0faf4ebf604d9c486726e1af8d2874d40f3ba30e5774d615c6eb7ecc6cc04d85d6be4e3e36cf4771f8e15350152351f918bf4a555a33d57f90d61c", + "xprv9s21ZrQH143K4UfkWbEcDPVrme1ea7d9BcQR6XtJ1VJucg1haNWCKCxqkXBshF3QkTSq3HHX2V3qiZmob9bJTnnj6ny5SbvwMp26v6HwxTd", + ], + ], +} diff --git a/tests/data/bip85_vectors.py b/tests/data/bip85_vectors.py new file mode 100644 index 0000000..1d3886e --- /dev/null +++ b/tests/data/bip85_vectors.py @@ -0,0 +1,90 @@ +EXT_KEY_TO_ENTROPY = [ + { + "master": "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + "path": "m/83696968'/0'/0'", + "derived_key": "cca20ccb0e9a90feb0912870c3323b24874b0ca3d8018c4b96d0b97c0e82ded0", + "derived_entropy": "efecfbccffea313214232d29e71563d941229afb4338c21f9517c41aaa0d16f00b83d2a09ef747e7a64e8e2bd5a14869e693da66ce94ac2da570ab7ee48618f7", + }, + { + "master": "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + "path": "m/83696968'/0'/1'", + "derived_key": "503776919131758bb7de7beb6c0ae24894f4ec042c26032890c29359216e21ba", + "derived_entropy": "70c6e3e8ebee8dc4c0dbba66076819bb8c09672527c4277ca8729532ad711872218f826919f6b67218adde99018a6df9095ab2b58d803b5b93ec9802085a690e", + }, + { + "master": "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + "path": "m/83696968'/0'/0'", + "derived_key": "cca20ccb0e9a90feb0912870c3323b24874b0ca3d8018c4b96d0b97c0e82ded0", + "derived_entropy": "efecfbccffea313214232d29e71563d941229afb4338c21f9517c41aaa0d16f00b83d2a09ef747e7a64e8e2bd5a14869e693da66ce94ac2da570ab7ee48618f7", + "drng": "b78b1ee6b345eae6836c2d53d33c64cdaf9a696487be81b03e822dc84b3f1cd883d7559e53d175f243e4c349e822a957bbff9224bc5dde9492ef54e8a439f6bc8c7355b87a925a37ee405a7502991111", + "drng_length": 80, + }, +] + +BIP39 = [ + { + "master": "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + "path": "m/83696968'/39'/0'/12'/0'", + "derived_entropy": "6250b68daf746d12a24d58b4787a714b", + "derived_mnemonic": "girl mad pet galaxy egg matter matrix prison refuse sense ordinary nose", + "mnemonic_length": 12, + }, + { + "master": "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + "path": "m/83696968'/39'/0'/18'/0'", + "derived_entropy": "938033ed8b12698449d4bbca3c853c66b293ea1b1ce9d9dc", + "derived_mnemonic": "near account window bike charge season chef number sketch tomorrow excuse sniff circle vital hockey outdoor supply token", + "mnemonic_length": 18, + }, + { + "master": "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + "path": "m/83696968'/39'/0'/24'/0'", + "derived_entropy": "ae131e2312cdc61331542efe0d1077bac5ea803adf24b313a4f0e48e9c51f37f", + "derived_mnemonic": "puppy ocean match cereal symbol another shed magic wrap hammer bulb intact gadget divorce twin tonight reason outdoor destroy simple truth cigar social volcano", + "mnemonic_length": 24, + }, +] + +XPRV = [ + { + "master": "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + "path": "m/83696968'/32'/0'", + "derived_entropy": "ead0b33988a616cf6a497f1c169d9e92562604e38305ccd3fc96f2252c177682", + "derived_key": "xprv9s21ZrQH143K2srSbCSg4m4kLvPMzcWydgmKEnMmoZUurYuBuYG46c6P71UGXMzmriLzCCBvKQWBUv3vPB3m1SATMhp3uEjXHJ42jFg7myX", + }, +] + +WIF = [ + { + "master": "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + "path": "m/83696968'/2'/0'", + "derived_entropy": "7040bb53104f27367f317558e78a994ada7296c6fde36a364e5baf206e502bb1", + "derived_wif": "Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp", + }, +] + +HEX = [ + { + "master": "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + "path": "m/83696968'/128169'/64'/0'", + "derived_entropy": "492db4698cf3b73a5a24998aa3e9d7fa96275d85724a91e71aa2d645442f878555d078fd1f1f67e368976f04137b1f7a0d19232136ca50c44614af72b5582a5c", + }, +] + +PWD_BASE64 = [ + { + "master": "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + "path": "m/83696968'/707764'/21'/0'", + "derived_entropy": "d7ad61d4a76575c5bad773feeb40299490b224e8e5df6c8ad8fe3d0a6eed7b85ead9fef7bcca8160f0ee48dc6e92b311fc71f2146623cc6952c03ce82c7b63fe", + "derived_pwd": "dKLoepugzdVJvdL56ogNV", + }, +] + +PWD_BASE85 = [ + { + "master": "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb", + "path": "m/83696968'/707785'/12'/0'", + "derived_entropy": "f7cfe56f63dca2490f65fcbf9ee63dcd85d18f751b6b5e1c1b8733af6459c904a75e82b4a22efff9b9e69de2144b293aa8714319a054b6cb55826a8e51425209", + "derived_pwd": "_s`{TW89)i4`", + }, +] diff --git a/tests/test.py b/tests/test.py deleted file mode 100644 index 6d3541b..0000000 --- a/tests/test.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -for we accept non-deterministic tests as good in the huge space of possible -entropy -""" -import hashlib -import secrets -import string - -from mnemonic import Mnemonic -import pytest -import requests -from click.testing import CliRunner -from seedwords import DICT_HASH, N_MNEMONICS, gen_words - -COVERAGE = 2**10 # stochastic -WORD_COUNTS = {12, 15, 18, 21, 24} - - -def test_entropy_flag(): - """the entropy we report is also what mnemo computes""" - runner = CliRunner() - for w in WORD_COUNTS: - for _ in range(COVERAGE): - result = runner.invoke(gen_words, ["--meta", "--nwords", w]) - lines = result.output.splitlines() - entropy = int(lines[0].split()[-1]) - phrase = lines[-1] - mnemo = Mnemonic("english") - assert mnemo.check(phrase) - assert int.from_bytes(mnemo.to_entropy(phrase), "big") == entropy - - -def test_no_args(): - """no args produces 12 seed words and checksums out""" - runner = CliRunner() - result = runner.invoke(gen_words) - assert result.exit_code == 0 - assert len(result.output.splitlines()[-1].split()) == 12 - mnemo = Mnemonic("english") - assert mnemo.check(result.output.splitlines()[-1]) - - -def test_seed(): - """seed we put in is also what mnemonic gets out""" - runner = CliRunner() - for w in WORD_COUNTS: - for _ in range(COVERAGE): - ebits = 128 + (((w - 12) // 3) * 32) - entropy = secrets.randbits(ebits) - passphrase = _random_passphrase() - result = runner.invoke( - gen_words, - [ - "--nwords", - w, - "--entropy", - entropy, - "--passphrase", - passphrase, - "--meta", - ], - ) - lines = result.output.splitlines() - words = lines[-1] - mnemo = Mnemonic("english") - assert mnemo.check(words) - assert int.from_bytes(mnemo.to_entropy(words), "big") == entropy - seed = lines[-2].split()[-1] - assert seed == mnemo.to_seed(words, passphrase).hex() - - -def test_word_counts(): - """test differing word counts; incl erroneous ones""" - runner = CliRunner() - for c in range(31): - result = runner.invoke(gen_words, ["--nwords", str(c)]) - if c in WORD_COUNTS: - assert result.exit_code == 0 - assert len(result.output.split()) == c - mnemo = Mnemonic("english") - assert mnemo.check(result.output.splitlines()[-1]) - - else: - assert result.exit_code != 0 - if result.exit_code != 2: - assert "Error" in str(result) - - -@pytest.mark.network -def test_words_in_bip39_wordlist(): - """make sure we match github""" - url = "https://raw.githubusercontent.com/bitcoin/bips/master/bip-0039/english.txt" - response = requests.get(url) - wordlist = response.text.split() - assert len(wordlist) == N_MNEMONICS - response_hash = hashlib.sha256(response.content).hexdigest() - assert response_hash == DICT_HASH, f"Hash mismatch: {response_hash} != {DICT_HASH}" - - -def _random_passphrase(): - alphabet = string.ascii_letters + string.digits - return "".join(secrets.choice(alphabet) for _ in range(secrets.randbelow(32))) diff --git a/tests/test_bip32.py b/tests/test_bip32.py new file mode 100644 index 0000000..8021e2c --- /dev/null +++ b/tests/test_bip32.py @@ -0,0 +1,43 @@ +import logging + +import pytest +from data.bip32_vectors import INVALID_KEYS, VECTORS + +from bip32 import to_master_key +from bip32types import parse_ext_key +from bip85 import derive +from util import LOGGER, from_hex + +logger = logging.getLogger(LOGGER) + + +@pytest.mark.parametrize( + "vector", + VECTORS, + ids=[ + f"Vector-{i + 1}-{', '.join(e['chain'].keys())}" for i, e in enumerate(VECTORS) + ], +) +def test_vectors(vector): + seed = from_hex(vector["seed_hex"]) + for ch, tests in vector["chain"].items(): + for type_, expected in tests.items(): + assert type_ in ("ext pub", "ext prv") + master = to_master_key(seed, mainnet=True, private=True) + derived = derive(master, ch, private=type_ == "ext prv") + if not str(derived) == expected: + logger.error("derived:") + logger.error(repr(derived)) + logger.error("expected:") + logger.error(repr(parse_ext_key(expected))) + assert str(derived) == expected + + +@pytest.mark.parametrize( + "key, reason", + INVALID_KEYS, + ids=[f"Vector-5-{reason[:32]}-{key[:8]}" for key, reason in INVALID_KEYS], +) +def test_invalid_keys(key, reason): + with pytest.raises((AssertionError, ValueError)): + parse_ext_key(key) diff --git a/tests/test_bip39.py b/tests/test_bip39.py new file mode 100644 index 0000000..eb0a5dd --- /dev/null +++ b/tests/test_bip39.py @@ -0,0 +1,62 @@ +import hashlib +import logging +import re +import warnings +from unicodedata import is_normalized + +import pytest +import requests +from data.bip39_vectors import VECTORS + +from bip32 import to_master_key +from seedwords import DICT_HASH, N_MNEMONICS, entropy_to_words, to_master_seed +from util import LOGGER, from_hex + +logger = logging.getLogger(LOGGER) + +WORD_COUNTS = {12, 15, 18, 21, 24} + + +@pytest.mark.parametrize( + "language, vectors", VECTORS.items(), ids=[l for l in VECTORS.keys()] +) +def test_vectors(language, vectors): + for vector in vectors: + _, mnemonic, seed, xprv = vector + expected_words = re.split(r"\s", mnemonic) + expected_seed = from_hex(seed) + computed_seed = to_master_seed(expected_words, passphrase="TREZOR") + assert expected_seed == computed_seed + computed_xprv = to_master_key(expected_seed, mainnet=True, private=True) + assert str(computed_xprv) == xprv + + +@pytest.mark.parametrize( + "language, vectors", VECTORS.items(), ids=[l for l in VECTORS.keys()] +) +def test_seed_word_generation(language, vectors): + for vector in vectors: + entropy_str, mnemonic, seed, xprv = vector + expected_words = re.split(r"\s", mnemonic) + if language == "english": + entropy_bytes = from_hex(entropy_str) + if all(b == 0 for b in entropy_bytes): + warnings.simplefilter("ignore") + computed_words = entropy_to_words( + len(expected_words), user_entropy=entropy_bytes, passphrase="TREZOR" + ) + assert expected_words == computed_words + else: + pytest.skip(f"{language} not supported") + + +@pytest.mark.network +def test_words_in_bip39_wordlist(): + """make sure we match github""" + url = "https://raw.githubusercontent.com/bitcoin/bips/master/bip-0039/english.txt" + response = requests.get(url) + wordlist = response.text.split() + assert all(is_normalized("NFKD", w) for w in wordlist) + assert len(wordlist) == N_MNEMONICS + response_hash = hashlib.sha256(response.content).hexdigest() + assert response_hash == DICT_HASH, f"Hash mismatch: {response_hash} != {DICT_HASH}" diff --git a/tests/test_bip85.py b/tests/test_bip85.py new file mode 100644 index 0000000..64d32ee --- /dev/null +++ b/tests/test_bip85.py @@ -0,0 +1,111 @@ +import logging + +import pytest +from data.bip85_vectors import ( + BIP39, + EXT_KEY_TO_ENTROPY, + HEX, + PWD_BASE64, + PWD_BASE85, + WIF, + XPRV, +) + +from bip32types import parse_ext_key +from bip85 import DRNG, apply_85, derive, to_entropy, to_hex_string +from util import LOGGER, to_hex_string + +logger = logging.getLogger(LOGGER) + + +@pytest.mark.parametrize( + "vector", + EXT_KEY_TO_ENTROPY, + ids=[f"Vector-{i + 1}" for i, e in enumerate(EXT_KEY_TO_ENTROPY)], +) +def test_entropy(vector): + master = parse_ext_key(vector["master"]) + derived_key = derive(master, vector["path"]) + secret = derived_key.data[1:] # chop the BIP32 byte prefix + assert to_hex_string(secret) == vector["derived_key"] + entropy = to_entropy(secret) + assert to_hex_string(entropy) == vector["derived_entropy"] + if "drng" in vector: + output = DRNG(entropy).read(vector["drng_length"]) + assert to_hex_string(output) == vector["drng"] + + +@pytest.mark.parametrize("vector", PWD_BASE64) +def test_pwd_base64(vector): + master = parse_ext_key(vector["master"]) + path = vector["path"] + output = apply_85(derive(master, path), path) + assert vector["derived_pwd"] == output["application"] + + +@pytest.mark.parametrize("vector", PWD_BASE64) +@pytest.mark.xfail( + reason="Head scratcher: correct password, bad entropy. File to BIP-85." +) +def test_pwd_base64_entropy(vector): + master = parse_ext_key(vector["master"]) + path = vector["path"] + output = apply_85(derive(master, path), path) + assert vector["derived_entropy"] == to_hex_string(output["entropy"]) + + +@pytest.mark.parametrize("vector", PWD_BASE85) +def test_pwd_base85(vector): + master = parse_ext_key(vector["master"]) + path = vector["path"] + output = apply_85(derive(master, path), path) + assert vector["derived_pwd"] == output["application"] + assert vector["derived_entropy"] == to_hex_string(output["entropy"]) + + +@pytest.mark.parametrize("vector", BIP39) +def test_bip39(vector): + master = parse_ext_key(vector["master"]) + path = vector["path"] + output = apply_85(derive(master, path), path) + assert to_hex_string(output["entropy"]) == vector["derived_entropy"] + assert len(output["application"].split(" ")) == vector["mnemonic_length"] + assert output["application"] == vector["derived_mnemonic"] + + +@pytest.mark.parametrize("vector", HEX) +def test_hex(vector): + master = parse_ext_key(vector["master"]) + path = vector["path"] + output = apply_85(derive(master, path), path) + assert vector["derived_entropy"] == output["application"] + + +@pytest.mark.parametrize("vector", XPRV) +def test_rsa_unsupported(vector): + """currently no support for RSA application. + path format: m/83696968'/828365'/{key_bits}'/{key_index}'""" + rsa_path = "m/83696968'/828365'/1024'/0'" + master = parse_ext_key(vector["master"]) + with pytest.raises(NotImplementedError): + apply_85(derive(master, rsa_path), rsa_path) + + +@pytest.mark.parametrize("vector", WIF) +def test_wif(vector): + master = parse_ext_key(vector["master"]) + path = vector["path"] + output = apply_85(derive(master, path), path) + assert to_hex_string(output["entropy"]) == vector["derived_entropy"] + # TODO: file against BIP85 poor test case does not include WIF checksum + # (not a correct WIF) + assert output["application"].decode("utf-8") == vector["derived_wif"] + + +@pytest.mark.parametrize("vector", XPRV) +def test_xprv(vector): + master = parse_ext_key(vector["master"]) + path = vector["path"] + output = apply_85(derive(master, path), path) + assert vector["derived_key"] == output["application"] + assert to_hex_string(output["entropy"]) == vector["derived_entropy"] diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..eb41637 --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,125 @@ +import logging + +import pytest +from click.testing import CliRunner + +from bipsea import N_WORDS_ALLOWED, cli +from tests.data.bip39_vectors import VECTORS +from util import LOGGER + +logger = logging.getLogger(LOGGER) + + +@pytest.fixture +def runner(): + return CliRunner() + + +@pytest.mark.parametrize("language, vectors", VECTORS.items()) +def test_seed_command_to_actual_seed(runner, language, vectors): + for vector in vectors: + _, mnemonic, _, xprv = vector + + for upper in (True, False): + mnemonic = mnemonic.upper() if upper else mnemonic + result = runner.invoke( + cli, + ["seed", "-t", "xprv", "-f", "words", "-i", mnemonic, "-p", "TREZOR"], + ) + assert result.exit_code == 0 + assert result.output.strip() == xprv + + +@pytest.mark.parametrize("language, vectors", VECTORS.items()) +def test_seed_option_sensitivity(runner, language, vectors): + """prove that passphrase and mnemonic changes alter xprv (but white space around + mnemonic doesn't)""" + # make tests faster by only covering one per language + for vector in vectors[:1]: + _, mnemonic, _, xprv = vector + + change_passphrase = runner.invoke( + cli, ["seed", "-t", "xprv", "-f", "words", "-i", mnemonic, "-p", "TrEZOR"] + ) + assert change_passphrase.exit_code == 0 + assert change_passphrase.output.strip() != xprv + + append_mnemonic = runner.invoke( + cli, + ["seed", "-t", "xprv", "-f", "words", "-i", mnemonic + ".", "-p", "TREZOR"], + ) + assert append_mnemonic.exit_code == 0 + assert append_mnemonic.output.strip() != xprv + + whitespace_mnemonic = runner.invoke( + cli, + [ + "seed", + "-t", + "xprv", + "-f", + "words", + "-i", + " " + mnemonic + " \t\n ", + "-p", + "TREZOR", + ], + ) + assert whitespace_mnemonic.exit_code == 0 + assert whitespace_mnemonic.output.strip() == xprv + + testnet = runner.invoke( + cli, ["seed", "-t", "tprv", "-f", "words", "-i", mnemonic, "-p", "TREZOR"] + ) + assert testnet.exit_code == 0 + tprv = testnet.output.strip() + assert tprv != xprv + assert tprv.startswith("tprv") + + +@pytest.mark.parametrize("n", N_WORDS_ALLOWED) +def test_seed_command_n_words(runner, n): + for from_ in ("string", "rand"): + cmd = ["seed", "-t", "words", "-n", n] + cmd += ["-f", from_] + if from_ == "string": + # "s"*15 is shorter than the lowest entropy of 128 bits + # "l"*32 is longer than the highest entropy of 256 bits + for input in ("s" * 15, "l" * 32): + cmd += ["-i", input] + result = runner.invoke(cli, cmd, catch_exceptions=False) + if "s" in input: + assert "Stretching" in result.output + else: + assert "Stretching" not in result.output + assert len(result.output.split()) == int(n) + assert result.exit_code == 0 + + +def test_bip85_command(runner): + pass + + +def test_from_and_to_words(runner): + result = runner.invoke(cli, ["seed", "--from", "words", "--to", "words"]) + assert result.exit_code != 0 + assert "--input" in result.output + assert "--from rand" in result.output + + +def test_from_and_n(runner): + result = runner.invoke(cli, ["seed", "--from", "words", "-n", "45"]) + assert result.exit_code != 0 + assert "--number" in result.output + + +def test_bad_from(runner): + result = runner.invoke(cli, ["seed", "--from", "baz"]) + assert result.exit_code != 0 + assert "not one of" in result.output + + +def test_bad_to(runner): + result = runner.invoke(cli, ["seed", "--to", "blah"]) + assert result.exit_code != 0 + assert "not one of" in result.output diff --git a/util.py b/util.py new file mode 100644 index 0000000..7756471 --- /dev/null +++ b/util.py @@ -0,0 +1,35 @@ +"""constants and utilities""" + +import binascii +from hashlib import pbkdf2_hmac +from unicodedata import normalize as unicode_normalize + +__version__ = "0.1" +__app_name__ = "bipsea" + +FORMAT = "utf-8" +NFKD = "NFKD" +LOGGER = __app_name__ + + +def from_hex(input: str, passphrase: str = "") -> bytes: + return bytes.fromhex(input + passphrase) + + +def to_hex_string(data: bytes) -> str: + return binascii.hexlify(data).decode("utf-8") + + +def pbkdf2( + mnemonic: str, passphrase: str, iterations: int = 2048, hash_name: str = "sha512" +) -> bytes: + return pbkdf2_hmac( + hash_name=hash_name, + password=normalize(mnemonic), + salt=normalize("mnemonic" + passphrase), + iterations=iterations, + ) + + +def normalize(input: str) -> str: + return unicode_normalize(NFKD, input).encode(FORMAT)