diff --git a/docs/css/custom.css b/docs/css/custom.css
index a4b76c206..9bd546b1c 100644
--- a/docs/css/custom.css
+++ b/docs/css/custom.css
@@ -4,4 +4,9 @@
.md-typeset img.twemoji {
margin: 0 !important;
+}
+
+.md-typeset h5 {
+ color: black;
+ text-transform: none;
}
\ No newline at end of file
diff --git a/docs/getting-started/features/tinyseed.en.md b/docs/getting-started/features/tinyseed.en.md
index e135d260e..358e73c48 100644
--- a/docs/getting-started/features/tinyseed.en.md
+++ b/docs/getting-started/features/tinyseed.en.md
@@ -12,6 +12,7 @@ The examples below have been crated so that you can test the workflow for scanni
## Size, Offset and Padding Reference
The general logic for how these are processed is:
+
1. Krux first looks for a square (Which works best if with a well lit square, with clean edges, on a dark background)
2. This square is checked and if the ratio of length to height is within a defined range for the given seed type, the square is further processed. (Uses the aspect_high and aspect_low variables)
3. An X and Y offset are applied to work out the corner of the seed grid within the seed plate. Some devices like the Maix Amigo use a mirrored coordinate system and some seed types will have a slightly different layout on the front and back of the plate. (Uses the x_offset and y_offset variables, p0 for the front face and p1 for the reverse face)
diff --git a/docs/getting-started/installing/from-gui.en.md b/docs/getting-started/installing/from-gui.en.md
index d22a72366..d0d15cec2 100644
--- a/docs/getting-started/installing/from-gui.en.md
+++ b/docs/getting-started/installing/from-gui.en.md
@@ -6,13 +6,13 @@ available for Linux and Windows.
Download the installer by choosing the right asset for your operating system from our
[Github releases page](https://github.com/selfcustody/krux-installer/releases):
-| **Operational System** | **File** |
-|------------------------------------------------------------|:----------------------------------:|
-| Windows | `krux-installer_0.0.13.exe*` |
-| Debian-based: Ubuntu, PopOS, etc... | `krux-installer_0.0.13_amd64.deb*` |
-| RedHat-based: Fedora, etc... | `krux-installer-0.0.13.x86_64.rpm*`|
-| Any linux distribution | `krux-installer-0.0.13.AppImage*` |
-| Package for Archlinux on [AUR](https://aur.archlinux.org/).| `krux-installer-bin` |
+| **Operational System** | **File** |
+|------------------------------------------------------------|:------------------------------------------:|
+| Windows | `{{latest_installer_underline}}.exe` |
+| Debian-based: Ubuntu, PopOS, etc... | `{{latest_installer_underline}}_amd64.deb` |
+| RedHat-based: Fedora, etc... | `{{latest_installer}}.x86_64.rpm` |
+| Any linux distribution | `{{latest_installer}}.AppImage` |
+| Package for Archlinux on [AUR](https://aur.archlinux.org/).| `krux-installer-bin` |
### Verify files
If you trust the project developers, you can skip to [install](#install):
@@ -33,10 +33,10 @@ If you trust the project developers, you can skip to [install](#install):
```pwsh
# Compare this output:
- (Get-FileHash 'krux-installer_0.0.13.exe').Hash
+ (Get-FileHash '{{latest_installer_underline}}.exe').Hash
# With this:
- Get-Content 'krux-installer_0.0.13.exe.sha256.txt'
+ Get-Content '{{latest_installer_underline}}.exe.sha256.txt'
```
|
@@ -44,7 +44,7 @@ If you trust the project developers, you can skip to [install](#install):
Debian-based |
```bash
- sha256sum --check ./krux-installer_0.0.13_amd64.deb.sha256.txt
+ sha256sum --check ./{{latest_installer_underline}}_amd64.deb.sha256.txt
```
|
@@ -52,7 +52,7 @@ If you trust the project developers, you can skip to [install](#install):
RedHat-based |
```bash
- sha256txt --check ./krux-installer-0.0.13.x86_64.rpm.sha256.txt
+ sha256txt --check ./{{latest_installer}}.x86_64.rpm.sha256.txt
```
|
@@ -60,7 +60,7 @@ If you trust the project developers, you can skip to [install](#install):
Any Linux distribution |
```bash
- sha256sum --check ./krux-installer-0.0.13.AppImage.sha256.txt
+ sha256sum --check ./{{latest_installer}}.AppImage.sha256.txt
```
|
@@ -80,10 +80,10 @@ Then you can verify:
| System | Command |
|------------------------|-------------------------------------------------------|
-| Windows (powershell) | `gpg --verify krux-installer_0.0.13.exe.sig` |
-| Debian-based | `gpg --verify ./krux-installer_0.0.13_amd64.deb.sig` |
-| RedHat-based | `gpg --verify ./krux-installer-0.0.13.x86_64.rpm.sig` |
-| Any Linux distribution | `gpg --verify ./krux-installer-0.0.13.AppImage.sig` |
+| Windows (powershell) | `gpg --verify {{latest_installer_underline}}.exe.sig` |
+| Debian-based | `gpg --verify ./{{latest_installer_underline}}_amd64.deb.sig` |
+| RedHat-based | `gpg --verify ./{{latest_installer}}.x86_64.rpm.sig` |
+| Any Linux distribution | `gpg --verify ./{{latest_installer}}.AppImage.sig` |
> ⚠️ TIP: If the verification was successful, you may get a message similar to: `Good signature from "qlrddev "`
@@ -102,7 +102,7 @@ Each system require different steps to install:
Windows |
- - The
krux-installer_0.0.13.exe is a NSIS installer;
+ - The
{{latest_installer_underline}}.exe is a NSIS installer;
- The first time you run the
.exe file the system will ask you to trust the application;
- See windows section below for more information
|
@@ -111,8 +111,8 @@ Each system require different steps to install:
Debian-based |
- - Install with dpkg:
sudo dpkg -i krux-installer_0.0.13_amd64.deb ;
- - Update it with apt-get:
sudo apt-get install -f krux-installer_0.0.13_amd64.deb .
+ - Install with dpkg:
sudo dpkg -i {{latest_installer_underline}}_amd64.deb ;
+ - Update it with apt-get:
sudo apt-get install -f {{latest_installer_underline}}_amd64.deb .
|
@@ -120,8 +120,8 @@ Each system require different steps to install:
RedHat-based |
- - Fedora:
sudo dnf install krux-installer-0.0.13.x86_64.rpm ;
- - Other RedHat based distros:
sudo yum localinstall krux-installer-0.0.13.x86_64.rpm .
+ - Fedora:
sudo dnf install {{latest_installer}}.x86_64.rpm ;
+ - Other RedHat based distros:
sudo yum localinstall {{latest_installer}}.x86_64.rpm .
|
@@ -129,9 +129,9 @@ Each system require different steps to install:
Any Linux distribution |
- - Place the
krux-installer-0.0.13.AppImage where you want;
- - Modify permision to execute:
chmod +x krux-installer-0.0.13.AppImage ;
- - Run it:
./krux-installer-0.0.13.AppImage .
+ - Place the
{{latest_installer}}.AppImage where you want;
+ - Modify permision to execute:
chmod +x {{latest_installer}}.AppImage ;
+ - Run it:
./{{latest_installer}}.AppImage .
|
diff --git a/docs/getting-started/installing/from-pre-built-release.en.md b/docs/getting-started/installing/from-pre-built-release.en.md
index eafa59601..9fa180adb 100644
--- a/docs/getting-started/installing/from-pre-built-release.en.md
+++ b/docs/getting-started/installing/from-pre-built-release.en.md
@@ -6,13 +6,13 @@ Head over to the [releases](https://github.com/selfcustody/krux/releases) page a
### Verify the files
Before installing the release, it's a good idea to check that:
-1. The *SHA256 hash* of `krux-vX.Y.Z.zip` matches the hash in `krux-vX.Y.Z.zip.sha256.txt`
-2. The *signature file* `krux-vX.Y.Z.zip.sig` can be verified with the [`selfcustody.pem` public key](https://github.com/selfcustody/krux/blob/main/selfcustody.pem) found in the root of the krux repository.
+1. The *SHA256 hash* of `{{latest_krux}}.zip` matches the hash in `{{latest_krux}}.zip.sha256.txt`
+2. The *signature file* `{{latest_krux}}.zip.sig` can be verified with the [`selfcustody.pem` public key](https://github.com/selfcustody/krux/blob/main/selfcustody.pem) found in the root of the krux repository.
You can either do this manually or with the `krux` shell script, which contains helper commands for this:
```bash
-./krux sha256 krux-vX.Y.Z.zip
-./krux verify krux-vX.Y.Z.zip selfcustody.pem
+./krux sha256 {{latest_krux}}.zip
+./krux verify {{latest_krux}}.zip selfcustody.pem
```
On Mac you may need to install `coreutils` to be able to use `sha256sum`
@@ -25,7 +25,7 @@ Fun fact: Each Krux release is signed with Krux!
### Flash the firmware onto the device
Extract the latest version of Krux you downloaded and enter the folder:
```bash
-unzip krux-vX.Y.Z.zip && cd krux-vX.Y.Z
+unzip {{latest_krux}}.zip && cd {{latest_krux}}
```
Connect the device to your computer via USB (for Maix Amigo, make sure you’re using bottom port), power it on, and run the following, replacing `DEVICE` with either `m5stickv`, `amigo`, `bit`, `cube`, `dock` or `yahboom` (to yahboom you may need to manually specify the port, for example `/dev/ttyUSB0` on Linux or `COM6` on Windows):
diff --git a/docs/getting-started/installing/from-source.en.md b/docs/getting-started/installing/from-source.en.md
index 6ab049bb9..6ea5269a3 100644
--- a/docs/getting-started/installing/from-source.en.md
+++ b/docs/getting-started/installing/from-source.en.md
@@ -29,7 +29,7 @@ The first command will create `privkey.pem` and `pubkey.pem` files you can use w
Once you've updated the `SIGNER_PUBKEY` with this value, you can proceed with the regular build process.
### Build the firmware (Linux or WSL)
-The [krux](https://github.com/selfcustody/krux/blob/main/krux) bash script contains commands for common development tasks. It assumes a Linux host, you will need to have [Docker Desktop or Docker Engine](https://docs.docker.com/desktop/), `openssl`, and `wget` installed at a minimum for the commands to work as expected. It works on Windows using WSL. The channel Crypto Guide from Youtube made a step-by-step video - [Krux DIY Bitcoin Signer: Build From Source & Verify (With Windows + WSL2 + Docker)](https://www.youtube.com/watch?v=Vmr_TFy2TfQ)
+The [krux bash script](https://github.com/selfcustody/krux/blob/main/krux) contains commands for common development tasks. It assumes a Linux host, you will need to have [Docker Desktop or Docker Engine](https://docs.docker.com/desktop/), `openssl`, and `wget` installed at a minimum for the commands to work as expected. It works on Windows using WSL. The channel Crypto Guide from Youtube made a step-by-step video - [Krux DIY Bitcoin Signer: Build From Source & Verify (With Windows + WSL2 + Docker)](https://www.youtube.com/watch?v=Vmr_TFy2TfQ)
To build and flash the firmware:
```bash
diff --git a/docs/getting-started/installing/from-test-release.en.md b/docs/getting-started/installing/from-test-release.en.md
index 542b54863..4a4f19e92 100644
--- a/docs/getting-started/installing/from-test-release.en.md
+++ b/docs/getting-started/installing/from-test-release.en.md
@@ -7,7 +7,7 @@ Keep in mind that these are unsigned binaries.
Download experimental compiled firmware or the Android app `apk` from our [test (beta) repository](https://github.com/odudex/krux_binaries).
#### Android
-The Krux Android app is designed for learning about Krux and Bitcoin air-gapped transactions. Due to the numerous potential vulnerabilities inherent in smartphones, such as the lack of control over the operating system, libraries, and hardware peripherals, the Krux app should NOT be used to manage wallets containing savings or important keys and mnemonics. For secure management of your keys, a dedicated device is recommended. [More](../../faq.md#what-is-krux-android-app)
+The [Krux Android app](../../faq.md#what-is-krux-android-app) is designed for learning about Krux and Bitcoin air-gapped transactions. Due to the numerous potential vulnerabilities inherent in smartphones, such as the lack of control over the operating system, libraries, and hardware peripherals, the Krux app should NOT be used to manage wallets containing savings or important keys and mnemonics. For secure management of your keys, a dedicated device is recommended.
#### Compiled firmware for Kendryte K210 devices
#### M5StickV
@@ -110,17 +110,17 @@ To Flash Yahboom k210 module you'll have to manually specify the port.
##### Linux
See the correct port using `ls /dev/ttyUSB*`, in the example below we use `/dev/ttyUSB0`:
```bash
-./ktool-linux -B goE -b 1500000 -p /dev/ttyUSB0 yahboom/kboot.kfpkg
+./ktool-linux -B goE -b 1500000 -p /dev/ttyUSB0 maixpy_yahboom/kboot.kfpkg
```
##### Mac
See the correct port using the command line: `ls /dev/cu.usbserial*`, in the example below we use `/dev/cu.usbserial-10`:
```bash
-./ktool-mac -B goE -b 1500000 -p /dev/cu.usbserial-10 yahboom/kboot.kfpkg
+./ktool-mac -B goE -b 1500000 -p /dev/cu.usbserial-10 maixpy_yahboom/kboot.kfpkg
```
##### Windows
See the correct port at Device Manager > Ports (COM & LPT), in the example below we use `COM6`:
```pwsh
-.\ktool-win.exe -B goE -b 1500000 -p COM6 yahboom\kboot.kfpkg
+.\ktool-win.exe -B goE -b 1500000 -p COM6 maixpy_yahboom\kboot.kfpkg
```
diff --git a/docs/getting-started/usage/generating-a-mnemonic.en.md b/docs/getting-started/usage/generating-a-mnemonic.en.md
index ef7851d0e..e899886b6 100644
--- a/docs/getting-started/usage/generating-a-mnemonic.en.md
+++ b/docs/getting-started/usage/generating-a-mnemonic.en.md
@@ -6,18 +6,14 @@ At the start screen, after selecting New Mnemonic, you will be taken to a second
## Camera
+(Experimental!) Choose between 12, 24 words or double mnemonic, then take a random picture and Krux will generate a mnemonic from the hash of the image bytes.
-(Experimental!) Choose between 12 or 24 words, then take a random picture and Krux will generate a mnemonic from the hash of the image bytes.
-
-
-
-
-
-
-
+
+
+
+
#### Image Entropy Quality Estimation
-
@@ -25,78 +21,68 @@ During image capture, entropy quality estimation is displayed to assist you in o
-## Words
+#### Double mnemonic
+It is the combination of two 12-word mnemonics that also forms a valid 24-word BIP-39 mnemonic. This is achieved by using the first 16 bytes (128 bits) of the image's entropy to generate the first 12-word, then using the next 16 bytes to generate the second 12-word and checking if these two 12-word together forms a valid 24-word, if not, we iterate over the second 12-word incrementing its entropy bytes until the two 12-word forms a valid 24-word.
+
+Some might say that the name double mnemonic is incorrect because we end up with two 12-word plus a 24-word mnemonic (12 + 12 + 24), so it's a triple mnemonic! But we only use entropy for the two 12-word ones, hence the name double mnemonic. Also, this name has already been used in this [double mnemonic generator](https://stepansnigirev.github.io/seed-tools/double_mnemonic.html) since July 2023.
+
+Some may wonder what is the use of this, it may be useful to some [plausible deniability](https://en.bitcoin.it/wiki/Privacy) or even a way to improve your [OPSEC](https://en.wikipedia.org/wiki/Operations_security).
+## Words
Print the BIP39 word list in 3D or on paper, then cut out the words and place them in a bucket. Manually draw 11 or 23 words from the bucket.
For the final word, Krux will assist you in picking a valid 12th or 24th word by adjusting its smart keypad to only allow typing words with a valid checksum. Alternatively, you can leave it empty, and Krux will select a final, valid checksum word for you.
## Dice Rolls
-
### Via D6
+Choose between 12 or 24 words. The entropy in a single roll of a D6 is 2.585 bits ( log2(6) ); therefore a minimum of a 50 rolls will be required for 128 bits of entropy, enough to generate a 12-word mnemonic. For 24-word, or an entropy of 256 bits, a minimum of 99 rolls will be required.
-Choose between 12 or 24 words.
-
-The entropy in a single roll of a D6 is 2.585 bits ( log2(6) ); therefore a minimum of a 50 rolls will be required for 128 bits of entropy, enough to generate a 12-word mnemonic. For 24 words, or an entropy of 256 bits, a minimum of 99 rolls will be required.
-
-
-
-
-
-
-
+
+
+
+
### Via D20
-
Since a D20 has more possible outcomes, the entropy is increased per roll to 4.322 bits ( log2(20) ). This means that only 30 rolls are necessary to create a 12-word mnemonic and 60 rolls for a 24-word mnemonic.
-
-
-
-
-
-
+
+
+
+
### Dice Rolls Entropy Quality Estimation
-
When you input your dice rolls, you'll see two progress bars filling up. The top progress bar shows how many rolls you've entered compared to the minimum number needed. The bottom progress bar shows the real-time calculated Shannon's entropy compared to the required minimum (128 bits for 12 words and 256 bits for 24 words). When the Shannon's entropy estimation reaches the recommended level, the progress bar will be full, and its frame will change color. If you've met the minimum number of rolls but the entropy estimation is still below the recommended level, a warning will appear, suggesting you add more rolls to increase entropy.
Note: Similar to image entropy quality estimation, dice rolls Shannon's entropy serves as an indicator and should not be considered an absolute measure of cryptographic entropy.
-Learn more about [Krux Entropy Quality Estimation](../features/entropy.md)
+Learn more about [Krux Entropy Quality Estimation](../features/entropy.md).
-### Stats for Nerds
+
-A low Shannon's entropy value might suggest that your dice are biased or that there's a problem with how you're gathering entropy. To investigate further, examine the "Stats for Nerds" section to check the distribution of your rolls and look for any abnormalities.
+### Stats for Nerds
+A low Shannon's entropy value could suggest that your dice are biased or that there's a problem with how you're gathering entropy. To investigate further, examine the "Stats for Nerds" section to check the distribution of your rolls and look for any abnormalities.
-
-
-
-
-
-
+
+
+
+
## How it works
-
For dice rolls, Krux keeps track of every roll you enter and displays the cumulative string of outcomes after each roll.
-When you have entered your final roll, Krux will hash this string using SHA256 and output the resulting hash to the screen so that you can verify it for yourself.
+When you have entered your final roll, Krux will hash this string using [SHA256](https://en.bitcoin.it/wiki/SHA-256) and output the resulting hash to the screen so that you can verify it for yourself.
-In the case a camera snapshot is used as source, image bytes, which contain pixels data in RGB565 format, will be hashed just like it is done with the dice rolls string.
+In case a camera snapshot is used as a source, the image bytes, which contain pixels data in RGB565 format, will be hashed in the same way as the dice rolls.
-
-
-
-
+
+
+
+
Krux then takes this hash, runs [`unhexlify`](https://docs.python.org/3/library/binascii.html#binascii.unhexlify) on it to encode it as bytes, and deterministically converts it into a mnemonic according to the [BIP-39 Reference Implementation](https://github.com/trezor/python-mnemonic/blob/6b7ebdb3624bbcae1a7b3c5485427a5587795120/src/mnemonic/mnemonic.py#L189-L207).
Note: For 12-word mnemonics, only the first half of the SHA256 hash is used (128 bits), while 24-word mnemonics use the full hash (256 bits).
-
-
-
### How to verify
-
Don't trust, verify. We encourage you not to trust any claim you cannot verify yourself. Therefore, there are wallets that use compatible algorithms to calculate the entropy derived from dice rolls. You can use the [SeedSigner](https://seedsigner.com/) or [Coldcard](https://coldcard.com/) hardware wallets, or even the [Bitcoiner Guide website](https://bitcoiner.guide/seed/), they share the same logic that Krux uses and will give the same mnemonic for the dice roll method.
diff --git a/docs/getting-started/usage/loading-a-mnemonic.en.md b/docs/getting-started/usage/loading-a-mnemonic.en.md
index 80ee0d01b..2db8d181e 100644
--- a/docs/getting-started/usage/loading-a-mnemonic.en.md
+++ b/docs/getting-started/usage/loading-a-mnemonic.en.md
@@ -1,4 +1,4 @@
-Once you have either a 12- or 24-word BIP-39 mnemonic, choose `Load Mnemonic` on Krux's start menu, and you will be presented with several input methods:
+Once you have either a 12 or 24-word BIP-39 mnemonic, choose `Load Mnemonic` on Krux's start menu (aka login menu), and you will be presented with several input methods:
@@ -8,8 +8,7 @@ Once you have either a 12- or 24-word BIP-39 mnemonic, choose `Load Mnemonic` on
### Via Camera
-
-You can choose to use the camera to scan a `QR code` or `Tiny Seed` metal plate backup.
+You can choose to use the camera to scan a `QR code`, `Tiny Seed`, `OneKey KeyTag` or a `Binary Grid`.
----8<----
camera-scan-tips.en.txt
@@ -26,29 +25,19 @@ It's unpleasant having to manually enter 12 or 24 words every time you want to u
- [Compact SeedQR](https://github.com/SeedSigner/seedsigner/blob/dev/docs/seed_qr/README.md/#compactseedqr-specification): Basically, it is the mnemonic words bits concatenated as bytes.
- [Encrypted Mnemonic](../features/encrypted-mnemonics.md): A specification created by Krux that encrypts the mnemonic words bits and adds some information about the encryption used.
-After opening your wallet via one of the manual methods you can use Krux to create QR codes of all types above, transcript them to paper or metal using the transcription helpers or attach a thermal printer to your Krux and print out the mnemonic. Check out the [Printing section](../features/printing.md) for more information.
+After opening a wallet via one of the methods available you can use Krux to [backup the mnemonic](navigating-the-main-menu.md#backup-mnemonic) as QR code, transcribe them to paper or metal using the transcription helpers or attach a thermal printer to your Krux and print out the mnemonic as QR. Check out the [printing section](../features/printing.md) for more information.
You can also use [an offline QR code generator for this](https://iancoleman.io/bip39/) (ideally on an airgapped device).
#### Tiny Seed, OneKey KeyTag or Binary Grid
-Tiny Seed (and similar methods) directly encode a seed as binary, allowing for a very compact mnemonic storage method when compared to SeedQR and Compact SeedQR.
-
-Krux devices have machine vision capabilities that allow users to scan these metal plates and instantly load mnemonics engraved on them. (This feature is not available in Krux on Android)
-
-To properly scan them place the Tiny Seed (or similar) over a black background and paint the punched bits black to increase contrast. You can also scan the thermally printed version, or a filled template.
-
-[You can find some examples of seeds encoded with each of the supported formats here.](../features/tinyseed.md)
+[Tiny Seed](https://tinyseed.io/), [Onekey KeyTag](https://onekey.so/products/onekey-keytag/) and others directly encode a seed as binary, allowing for a very compact mnemonic storage. Krux devices have machine vision capabilities that allow users to scan these metal plates and instantly load mnemonics engraved on them (this feature is not available in Krux Android app).
-Retail versions of this type of seed can be purchased here:
-[Tiny Seed](https://tinyseed.io/)
-[Onekey KeyTag](https://onekey.so/products/onekey-keytag/)
-
-Alternatively, you can find templates to scan or print [here](https://github.com/odudex/krux_binaries/tree/main/templates).
+To properly scan, place the backup plate over a black background and paint the punched bits black to increase contrast. You can also scan the thermally printed version, or a filled template. You can find some [examples of mnemonics encoded here](../features/tinyseed.md). Alternatively, you can find [templates to scan or print here](https://github.com/odudex/krux_binaries/tree/main/templates).
### Via Manual Input
-Manually type `Words`, `Word Numbers`, `Tiny Seed` (toggle the bits or punches) or [`Stackbit`](https://stackbit.me) (model 1248 metal plate backup).
+Manually type `Words`, `Word Numbers`, `Tiny Seed` (toggle the bits or punches) or [`Stackbit 1248`](https://stackbit.me/produto/stackbit-1248/).
@@ -84,7 +73,7 @@ Enter the BIP-39 mnemonic word's numbers (1-2048) in binary format, toggling nec
-Enter the BIP-39 mnemonic word's numbers (1-2048) using the Stackbit 1248 metal plate backup method, where each of the four digits of the word's number is a sum of the numbers marked (punched) 1, 2, 4, or 8. For example, to enter the word "pear", number 1297, you must punch (1)(2)(1+8=9)(1+2+4=7).
+Enter the BIP-39 mnemonic word's numbers (1-2048) using the Stackbit 1248 metal plate backup method, where each of the four digits of the word's number is a sum of the numbers marked (punched) 1, 2, 4, or 8. For example, to enter the word "oyster", number 1268, you must punch (1)(2)(2,4)(8).
@@ -97,105 +86,70 @@ You can retrieve mnemonics previously stored on device's internal flash or exter
## Wallet Loading
-
### Confirm Mnemonic Words
-
+
-Once you have entered your mnemonic, you will be presented with the full list of words to confirm.
+Once you have entered your mnemonic, you will be presented with the full list of words to confirm. If you see an asterisk (`*`) in the header, it means this is a [double mnemonic](generating-a-mnemonic.md/#double-mnemonic).
### Confirm Wallet Attributes
+
+
You will be presented with a screen containing wallet attributes, if they are as expected just press `Load Wallet` and you'll be ready to use your loaded key.
-
-
-
-#### Attributes
-
-**Fingerprint**
-
- 73c5da0a
-
+
+#### Fingerprint
+* :material-fingerprint: ` 73c5da0a `:
The BIP-32 master wallet's fingerprint, if you have it noted down, will help you make sure you entered the correct mnemonic and passphrase (optional) and will load the expected wallet.
-**Network**
-
- Mainnet
-
-
+#### Network
+* ` Mainnet `:
Check if you are loading a `Testnet` or `Mainnet` wallet.
-**Single/Multisig**
-
- Single-sig
-
-
+#### Single / Multisig
+* ` Single-sig `:
Check if you are loading a `Single-sig` or `Multisig` wallet.
-**Derivation Path**
-
- m/84'/0'/0'
-
-
+#### Derivation Path
+* ` m/84'/0'/0' `:
The derivation path is a sequence of numbers, or "nodes", that define the script type, network, and account index of your wallet.
+ * **Script Type** `84'`: The first number defines the script type. The default is `84'`, corresponding to a Native Segwit wallet. Other values include:
+ * `44'` for Legacy
+ * `49'` for Nested Segwit
+ * `86'` for Taproot
+ * `48'` for Multisig
+ * **Network** `0'`: The second number defines the network:
+ * `0'` for Mainnet
+ * `1'` for Testnet
+ * **Account Index** `0'`: The third number is the account index, with `0'` being the default.
+ * **Additional**: For multisig wallets, a fourth node with the value `2'` is added to the derivation path.
-1. Script Type: The first number defines the script type. The default is 84', corresponding to a Native Segwit wallet. Other values include:
-
- `44'` for Legacy
-
- `49'` for Nested Segwit
-
- `86'` for Taproot
-
- `48'` for Multisig
-
-
-2. Network: The second number defines the network:
-
- `0'` for Mainnet
-
- `1'` for Testnet
-
-
-3. Account Index: The third number is the account index, with `0'` being the default.
-
-For multisig wallets, a fourth node with the value `2'` is added to the derivation path.
-
-**Passphrase**
-
- No Passphrase
-
-
+#### Passphrase
+* ` No Passphrase `:
Informs if the wallet has a loaded passphrase.
-### Changing Wallet Attributes
-
+### Customize
You can change any of the attributes before and after loading a wallet.
-It is also possible to change default settings for `Network` and `Single/Multisig` on settings.
+It is also possible to change default settings for `Network` and `Single/Multisig` on [settings](../settings.md).
#### Passphrase
-
-You can type or scan a BIP-39 passphrase. When typing, swipe left :material-gesture-swipe-left: or right :material-gesture-swipe-right: to change keypads if your device has a touchscreen. For scanning, you can also create a QR code from your offline passphrase in [Tools](../features/tools.md/#create-qr-code).
+You can type or scan a BIP-39 passphrase. When typing, swipe left :material-gesture-swipe-left: or right :material-gesture-swipe-right: to change keypads if your device has a touchscreen. You can also hold the button `PAGE` or `PAGE_PREV` when navigating among letters while typing text to fast forward or backward. For scanning, you can also create a QR code from your offline passphrase using the [create QR code tool](../features/tools.md/#create-qr-code).
#### Customize
-
Press `Customize` to open a menu where you can change the `Network`, `Single/Multisig`, `Script Type` and `Account`.
-
Now, onto the main menu...
-
-
diff --git a/docs/getting-started/usage/navigating-the-main-menu.en.md b/docs/getting-started/usage/navigating-the-main-menu.en.md
index 23998c7d7..08742bd57 100644
--- a/docs/getting-started/usage/navigating-the-main-menu.en.md
+++ b/docs/getting-started/usage/navigating-the-main-menu.en.md
@@ -3,8 +3,6 @@ After entering your mnemonic, and loading a wallet, you will find yourself on Kr
-
-
### Backup Mnemonic
@@ -16,7 +14,6 @@ If you set a [printer](../settings.md/#printer), it will also give the option to
#### QR Code
-
- **Plaintext QR**
@@ -48,8 +45,6 @@ Words are converted to their BIP-39 numeric indexes, those numbers are then conc
This option converts the encrypted mnemonic into a QR code. Enter an encryption key and, optionally, a custom ID. When you scan this QR code through "Load Mnemonic" -> "Via Camera" -> "QR Code," you will be prompted to enter the decryption key to load the mnemonic stored in it. Like any QR code, it can be printed if a thermal printer driver is set up.
-
-
#### Encrypted
@@ -62,7 +57,6 @@ When using any of the encryption methods, you will be prompted to enter an encry
See this page to find out more about: [Krux Mnemonics Encryption](../../getting-started/features/encrypted-mnemonics.md).
-
- **Store on Flash**
This option stores the encrypted mnemonic in the device's flash memory. You can decrypt and load it later through the "Load Mnemonic" -> "From Storage" option.
@@ -74,9 +68,12 @@ If an SD card is available, this option stores the encrypted mnemonic on it. You
- **Encrypted QR Code**
It's another path for the same functionality present on QR Code backups, described above.
+
+
#### Other Formats
- **Words**
+
@@ -85,18 +82,16 @@ Display the BIP-39 mnemonic words as text so you can write them down.
- **Numbers**
+
Display the BIP-39 mnemonic word numbers (1-2048) in decimal, hex, or octal format.
-
-
-
-
- **Stackbit 1248**
+
@@ -105,6 +100,7 @@ This metal backup format represents the BIP-39 mnemonic word's numbers (1-2048).
- **Tiny Seed**
+
@@ -116,30 +112,24 @@ This metal backup format represents the BIP-39 mnemonic word's numbers (1-2048)
A menu will be presented with options to display your master extended public key (xpub) as text and as a QR code. Depending on the script type or whether a single-sig or multisig wallet was loaded, the options shown will be xpub, ypub, zpub, or Zpub. When displayed as text, the extended public key can be stored on an SD card if available. If you choose to export a QR code, you can not only scan it but also save it as an image on an SD card or print it if a thermal printer is attached.
-
-
-
-
-
-
+
+
+
+
+
+
All QR codes will contain [key origin information in key expressions](https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki#Key_Expressions). If your coordinator cannot parse this information, it will not be capable of importing the wallet's fingerprint. As a result, Krux will not perform important verifications when signing transactions created by it unless you manually add the fingerprint so that it can be used to create Krux-compatible PSBTs.
Always prefer to import extended public keys directly from Krux when setting up a coordinator instead of copying it (or parts of it) from other sources.
-
-
### Wallet
Here you can load view and save wallet descriptors, add or change passphrases, customize wallet's attributes, generate and load a BIP85 child mnemonic.
#### Wallet Descriptor
-
A Bitcoin Wallet Output Script Descriptor defines a set of addresses in a wallet. It includes the following information:
-
- Script Type: Specifies the type of script (e.g., P2PKH, P2SH, P2WPKH).
-
- Origin Info: Defines the master fingerprint and derivation path used to derive keys.
-
- Extended Public Keys: usually represented as an xpub, but could be ypub, zpub, etc.
Output descriptors standardize how wallets generate addresses, ensuring compatibility and security. They help wallets and other software understand how to derive and verify the addresses used in transactions.
@@ -148,10 +138,10 @@ For multisig wallets, it is essential to load a descriptor to check addresses an
When you select the "Wallet Descriptor" option for the first time, you will be prompted to load a wallet descriptor via QR code or SD card. After loading, a preview of the wallet attributes will be displayed for confirmation.
-
-
-
-
+
+
+
+
If you access the "Wallet Descriptor" option again after loading your wallet, you will see the wallet's name, fingerprints, and the abbreviated XPUBs of all cosigners, along with a QR code containing the exact data that was initially loaded. If an SD card is inserted, you can save the descriptor to it for later use without the assistance of a coordinator. Additionally, if you have a thermal printer attached, you can print this QR code.
@@ -162,7 +152,6 @@ Please note that if you customize the wallet parameters or restart the device, t
#### Passphrase
-
@@ -183,20 +172,17 @@ Here you are presented to the exact same customization options you have while lo
#### BIP85
-
Bitcoin BIP85, also known as the Deterministic Entropy From BIP32 Keychains, allows for the generation of deterministic entropy using a BIP32 master key. This entropy can then be used to create various cryptographic keys and mnemonics (e.g., BIP39 seed phrases). BIP85 ensures that all derived keys and mnemonics are deterministic and reproducible, meaning they can be recreated from the same master key. This feature is useful for securely managing multiple child keys from a single master key without the need to store each one separately.
-
-
-
-
+
+
+
+
Choose between a 12 or 24 words child then type the desired index to export a child mnemonic. After being presented to the new mnemonic, you can choose to load and use it right away.
Please note passphrases will be removed when loading a BIP85 child.
-
-
### Address
@@ -262,11 +248,9 @@ If a thermal printer is attached to your device, you can also print the PSBT QR
#### Message
-
Similar to PSBTs, Krux can load, sign, and export signatures for messages. This feature allows you to attest not only to the ownership of the messages themselves but also to the ownership of Bitcoin addresses and the authorship of documents and files.
##### Standard Messages and Files
-
@@ -281,8 +265,9 @@ This feature is used to sign Krux releases, airgapped, using a Krux device.
##### Messages at Address
-
Coordinators like Sparrow and Specter offer the possibility to sign messages at a Bitcoin receive address, allowing you to attest ownership of that address. Krux will detect if the message is of this type and present a similar workflow for signing. The main difference is that the address will be displayed along with the raw message, and since the message is signed with a derived address instead of the master public key, Krux won't offer the option to export the raw public key after the signature.
+
+
\ No newline at end of file
diff --git a/docs/img/maixpy_amigo/load-mnemonic-camera-options-150.en.png b/docs/img/maixpy_amigo/load-mnemonic-camera-options-150.en.png
index dcd7fc95a..4aef1a273 100644
Binary files a/docs/img/maixpy_amigo/load-mnemonic-camera-options-150.en.png and b/docs/img/maixpy_amigo/load-mnemonic-camera-options-150.en.png differ
diff --git a/docs/img/maixpy_amigo/load-mnemonic-seq-double-mnemonic-150.en.png b/docs/img/maixpy_amigo/load-mnemonic-seq-double-mnemonic-150.en.png
new file mode 100644
index 000000000..b78b1bf62
Binary files /dev/null and b/docs/img/maixpy_amigo/load-mnemonic-seq-double-mnemonic-150.en.png differ
diff --git a/docs/img/maixpy_m5stickv/load-mnemonic-camera-options-125.en.png b/docs/img/maixpy_m5stickv/load-mnemonic-camera-options-125.en.png
index 6a4c81853..fd47cf038 100644
Binary files a/docs/img/maixpy_m5stickv/load-mnemonic-camera-options-125.en.png and b/docs/img/maixpy_m5stickv/load-mnemonic-camera-options-125.en.png differ
diff --git a/docs/parts.en.md b/docs/parts.en.md
index 93bd4e0d0..57717e384 100644
--- a/docs/parts.en.md
+++ b/docs/parts.en.md
@@ -17,7 +17,7 @@
:material-information:{id="camera-info"}:
-Only `OV7740` and `OV2640` have an anti-glare mode to better capture images from high brightness screens or with incident light.
+Only `OV7740`, `OV2640` and `GC2145` have an anti-glare mode to better capture images from high brightness screens or with incident light.
:material-numeric-1-circle:{id="m5stickv-info"}:
diff --git a/docs/snippets/camera-scan-tips.en.txt b/docs/snippets/camera-scan-tips.en.txt
index 0fa7b4ee3..bfbd8720c 100644
--- a/docs/snippets/camera-scan-tips.en.txt
+++ b/docs/snippets/camera-scan-tips.en.txt
@@ -1 +1 @@
-If you are in a dark environment, you can hold down the `ENTER` button of the M5StickV or Maix Amigo to turn on their LED light to potentially increase visibility. Some cameras (`OV7740` and `OV2640`) have an anti-glare mode to better capture images from high brightness screens or with incident light, they are present on M5StickV, Amigo, Cube and some Yahboom. To enable/disable the anti-glare mode on a supported device just press the `PAGE` button while scanning.
\ No newline at end of file
+If you are in a dark environment, you can hold down the `ENTER` button of the M5StickV or Maix Amigo to turn on their LED light to potentially increase visibility. Some cameras (`OV7740`, `OV2640` and `GC2145`) have an anti-glare mode to better capture images from high brightness screens or with incident light, they are present on M5StickV, Amigo, Cube and Yahboom. To enable/disable the anti-glare mode on a supported device just press the `PAGE` button while scanning.
\ No newline at end of file
diff --git a/i18n/translations/de-DE.json b/i18n/translations/de-DE.json
index c885f5cb7..ba3d1ab1f 100644
--- a/i18n/translations/de-DE.json
+++ b/i18n/translations/de-DE.json
@@ -69,6 +69,7 @@
"Display": "Bildschirm",
"Do not power off, it may take a while to complete.": "Schalten Sie das Gerät nicht aus, es kann eine Weile dauern.",
"Done?": "Fertig?",
+ "Double mnemonic": "Doppelte Gedächtnisstütze",
"Driver": "Driver",
"Encrypted": "Verschlüsselt",
"Encrypted QR Code": "Verschlüsselter QR-Code",
@@ -200,7 +201,7 @@
"Printing": "Wird gedruckt",
"Proceed anyway?": "Trotzdem fortfahren?",
"Proceed?": "Weiter?",
- "Processing ...": "Wird bearbeitet ...",
+ "Processing..": "Wird bearbeitet..",
"QR Code": "QR-Code",
"RX Pin": "RX Pin",
"Receive": "Empfangen",
@@ -226,7 +227,6 @@
"Save to SD card": "Auf SD-Karte speichern?",
"Save to SD card?": "Auf SD-Karte speichern?",
"Saved to SD card": "Auf SD-Karte gespeichert",
- "Saving ...": "Wird gespeichert …",
"Scale": "Skala",
"Scan Address": "Adresse\nscannen",
"Scan BIP39 Passphrase": "Scan BIP39 Passphrase",
diff --git a/i18n/translations/es-MX.json b/i18n/translations/es-MX.json
index 3e3c06404..cfac03997 100644
--- a/i18n/translations/es-MX.json
+++ b/i18n/translations/es-MX.json
@@ -69,6 +69,7 @@
"Display": "Pantalla",
"Do not power off, it may take a while to complete.": "No apagues el dispositivo, puede tardar un tiempo en completarse.",
"Done?": "¿Listo?",
+ "Double mnemonic": "Doble mnemónico",
"Driver": "Operador",
"Encrypted": "Cifrado",
"Encrypted QR Code": "Código QR Cifrado",
@@ -200,7 +201,7 @@
"Printing": "Imprimiendo",
"Proceed anyway?": "¿Proceder de todas maneras?",
"Proceed?": "¿Continuar?",
- "Processing ...": "Procesando ...",
+ "Processing..": "Procesando..",
"QR Code": "Código QR",
"RX Pin": "RX Pin",
"Receive": "Recepción",
@@ -226,7 +227,6 @@
"Save to SD card": "Guardar en tarjeta SD",
"Save to SD card?": "¿Guardar en la tarjeta SD?",
"Saved to SD card": "Guardado en la tarjeta SD",
- "Saving ...": "Guardando ...",
"Scale": "Escala",
"Scan Address": "Escanear Dirección",
"Scan BIP39 Passphrase": "Escanear Passphrase BIP39",
diff --git a/i18n/translations/fr-FR.json b/i18n/translations/fr-FR.json
index ddd7349b1..de249ca14 100644
--- a/i18n/translations/fr-FR.json
+++ b/i18n/translations/fr-FR.json
@@ -69,6 +69,7 @@
"Display": "Affichage",
"Do not power off, it may take a while to complete.": "Ne pas éteindre, cela peut prendre un certain temps.",
"Done?": "Terminé ?",
+ "Double mnemonic": "Double mnémonique",
"Driver": "Conducteur",
"Encrypted": "Chiffré",
"Encrypted QR Code": "Code QR crypté",
@@ -200,7 +201,7 @@
"Printing": "Impression",
"Proceed anyway?": "Procéder quand même ?",
"Proceed?": "Procéder ?",
- "Processing ...": "Traitement ...",
+ "Processing..": "Traitement..",
"QR Code": "QR Code",
"RX Pin": "RX Fiche",
"Receive": "Recevoir",
@@ -226,7 +227,6 @@
"Save to SD card": "Enregistrer sur la carte SD",
"Save to SD card?": "Enregistrer sur la carte SD ?",
"Saved to SD card": "Enregistré sur la carte SD",
- "Saving ...": "Enregistrement en cours...",
"Scale": "L'échelle",
"Scan Address": "Scannez l'adresse",
"Scan BIP39 Passphrase": "Scannez la phrase secrète BIP-39",
diff --git a/i18n/translations/nl-NL.json b/i18n/translations/nl-NL.json
index c9a384508..d1ad7b6d5 100644
--- a/i18n/translations/nl-NL.json
+++ b/i18n/translations/nl-NL.json
@@ -69,6 +69,7 @@
"Display": "Weergave",
"Do not power off, it may take a while to complete.": "Schakel het apparaat niet uit, het kan even duren voordat het klaar is.",
"Done?": "Klaar?",
+ "Double mnemonic": "Dubbel geheugensteuntje",
"Driver": "Driver",
"Encrypted": "Versleuteld",
"Encrypted QR Code": "Versleutelde QR code",
@@ -200,7 +201,7 @@
"Printing": "Afdrukken",
"Proceed anyway?": "Toch doorgaan?",
"Proceed?": "Doorgaan?",
- "Processing ...": "Verwerken...",
+ "Processing..": "Verwerken..",
"QR Code": "QR code",
"RX Pin": "RX pin",
"Receive": "Ontvangen",
@@ -226,7 +227,6 @@
"Save to SD card": "Opslaan op SD kaart",
"Save to SD card?": "Opslaan op SD kaart?",
"Saved to SD card": "Opgeslagen op SD kaart",
- "Saving ...": "Opslaan bezig...",
"Scale": "Schaal",
"Scan Address": "Adres scannen",
"Scan BIP39 Passphrase": "BIP-39 Wachtwoord Scannen",
diff --git a/i18n/translations/pl-PL.json b/i18n/translations/pl-PL.json
index 1694902f1..560747a61 100644
--- a/i18n/translations/pl-PL.json
+++ b/i18n/translations/pl-PL.json
@@ -69,6 +69,7 @@
"Display": "Wyświetlacz",
"Do not power off, it may take a while to complete.": "Nie wyłączaj zasilania, może to chwilę potrwać.",
"Done?": "Zrobione?",
+ "Double mnemonic": "Podwójna mnemotechnika",
"Driver": "Kierowca",
"Encrypted": "Zaszyfrowane",
"Encrypted QR Code": "Zaszyfrowany kod QR",
@@ -200,7 +201,7 @@
"Printing": "Drukowanie",
"Proceed anyway?": "Kontynuować mimo to?",
"Proceed?": "Przystępować?",
- "Processing ...": "Przetwarzanie ...",
+ "Processing..": "Przetwarzanie..",
"QR Code": "Kod QR",
"RX Pin": "Pin Rx",
"Receive": "Odbierać",
@@ -226,7 +227,6 @@
"Save to SD card": "Zapisz na karcie SD",
"Save to SD card?": "Zapisz na karcie SD?",
"Saved to SD card": "Zapisano na karcie SD",
- "Saving ...": "Zapisywanie...",
"Scale": "Skala",
"Scan Address": "Adres skanowania",
"Scan BIP39 Passphrase": "Scan BIP39 Passphrase",
diff --git a/i18n/translations/pt-BR.json b/i18n/translations/pt-BR.json
index ba247659a..ef31fd09c 100644
--- a/i18n/translations/pt-BR.json
+++ b/i18n/translations/pt-BR.json
@@ -69,6 +69,7 @@
"Display": "Display",
"Do not power off, it may take a while to complete.": "Não desligue, pode demorar um pouco para concluir.",
"Done?": "Feito?",
+ "Double mnemonic": "Duplo mnemônico",
"Driver": "Driver",
"Encrypted": "Criptografado",
"Encrypted QR Code": "Código QR Criptografado",
@@ -200,7 +201,7 @@
"Printing": "Imprimindo",
"Proceed anyway?": "Continuar mesmo assim?",
"Proceed?": "Seguir?",
- "Processing ...": "Processando ...",
+ "Processing..": "Processando..",
"QR Code": "Código QR",
"RX Pin": "Pino RX",
"Receive": "Recebimento",
@@ -226,7 +227,6 @@
"Save to SD card": "Salvar no cartão SD",
"Save to SD card?": "Salvar no cartão SD?",
"Saved to SD card": "Salvo no cartão SD",
- "Saving ...": "Salvando...",
"Scale": "Escala",
"Scan Address": "Escanear Endereço",
"Scan BIP39 Passphrase": "Escanear a senha BIP39",
diff --git a/i18n/translations/ru-RU.json b/i18n/translations/ru-RU.json
index 79c1a713c..0a8466d88 100644
--- a/i18n/translations/ru-RU.json
+++ b/i18n/translations/ru-RU.json
@@ -69,6 +69,7 @@
"Display": "Дисплеи",
"Do not power off, it may take a while to complete.": "Не выключайте питание, это может занять некоторое время.",
"Done?": "Готово?",
+ "Double mnemonic": "Двойная мнемоника",
"Driver": "Драйвер",
"Encrypted": "Зашифровано",
"Encrypted QR Code": "Зашифрованный QR Код",
@@ -200,7 +201,7 @@
"Printing": "Идет печать",
"Proceed anyway?": "Все равно продолжить?",
"Proceed?": "Продолжить?",
- "Processing ...": "Обработка ...",
+ "Processing..": "Обработка..",
"QR Code": "QR Код",
"RX Pin": "RX Пин",
"Receive": "Получить",
@@ -226,7 +227,6 @@
"Save to SD card": "Сохранить на SD-карту",
"Save to SD card?": "Сохранить на SD карту?",
"Saved to SD card": "Сохранено на SD карту",
- "Saving ...": "Сохранение...",
"Scale": "Шкала",
"Scan Address": "Отсканировать Адрес",
"Scan BIP39 Passphrase": "Отсканировать BIP39 фразу-пароль",
diff --git a/i18n/translations/tr-TR.json b/i18n/translations/tr-TR.json
index 51d8059aa..f78f0ca85 100644
--- a/i18n/translations/tr-TR.json
+++ b/i18n/translations/tr-TR.json
@@ -69,6 +69,7 @@
"Display": "Ekran",
"Do not power off, it may take a while to complete.": "Kapatmayın, tamamlanması biraz zaman alabilir.",
"Done?": "Tamamlandı mı?",
+ "Double mnemonic": "Çifte anımsatıcı",
"Driver": "Sürücü",
"Encrypted": "Şifrelenmiş",
"Encrypted QR Code": "Şifrelenmiş QR Kodu",
@@ -200,7 +201,7 @@
"Printing": "Yazdırılıyor",
"Proceed anyway?": "Yine de devam edilsin mi?",
"Proceed?": "Devam edilsin mi?",
- "Processing ...": "İşleniyor ...",
+ "Processing..": "İşleniyor..",
"QR Code": "QR Kodu",
"RX Pin": "RX Pini",
"Receive": "Al",
@@ -226,7 +227,6 @@
"Save to SD card": "SD karta kaydet",
"Save to SD card?": "SD karta kaydedilsin mi?",
"Saved to SD card": "SD karta kaydedildi",
- "Saving ...": "Kaydediliyor ...",
"Scale": "Ölçek",
"Scan Address": "Adresi Tara",
"Scan BIP39 Passphrase": "BIP39 Parolasını Tara",
diff --git a/i18n/translations/vi-VN.json b/i18n/translations/vi-VN.json
index bb075b0c5..62e66598d 100644
--- a/i18n/translations/vi-VN.json
+++ b/i18n/translations/vi-VN.json
@@ -69,6 +69,7 @@
"Display": "Hiển thị",
"Do not power off, it may take a while to complete.": "Không được tắt máy, có thể mất một lúc để hoàn thành.",
"Done?": "Hoàn tất?",
+ "Double mnemonic": "Từ gợi nhớ kép",
"Driver": "Driver",
"Encrypted": "Đã mã hóa",
"Encrypted QR Code": "Mã QR được mã hóa",
@@ -200,7 +201,7 @@
"Printing": "Đang in",
"Proceed anyway?": "Vẫn tiếp tục?",
"Proceed?": "Thực hiện?",
- "Processing ...": "Đang xử lý ...",
+ "Processing..": "Đang xử lý..",
"QR Code": "Mã QR",
"RX Pin": "RX Pin",
"Receive": "Nhận được",
@@ -226,7 +227,6 @@
"Save to SD card": "Lưu vào thẻ SD",
"Save to SD card?": "Lưu vào thẻ SD?",
"Saved to SD card": "Đã lưu vào thẻ SD",
- "Saving ...": "Đang lưu...",
"Scale": "Tỉ lệ",
"Scan Address": "Quét địa chỉ",
"Scan BIP39 Passphrase": "Quét cụm mật khẩu BIP39",
diff --git a/krux b/krux
index baf5befd3..6c9696ea4 100755
--- a/krux
+++ b/krux
@@ -59,6 +59,9 @@ if [ "$1" == "build" ]; then
[ "$device" == "maixpy_dock" ]||[ "$device" == "maixpy_yahboom" ]||[ "$device" == "maixpy_cube" ]; then
declare $(grep -m 1 version pyproject.toml | sed 's/ *= */=/g' | sed 's/"//g' | sed 's/\r//g')
sed -i -- 's/VERSION = ".*"/VERSION = "'"$version"'"/g' src/krux/metadata.py
+
+ # docs: latest_krux version
+ sed -i -- 's/ latest_krux: krux-v.*/ latest_krux: krux-v'$version'/g' mkdocs.yml
mkdir -p build
docker build . -t krux-builder --build-arg DEVICE=$device
diff --git a/mkdocs.yml b/mkdocs.yml
index 30e084574..836bcfd5e 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -51,6 +51,9 @@ edit_uri: edit/main/docs
docs_dir: docs
site_dir: public
extra:
+ latest_krux: krux-v24.07.0
+ latest_installer: krux-installer-0.0.13
+ latest_installer_underline: krux-installer_0.0.13
social:
- icon: fontawesome/solid/bullhorn
link: https://bitcointalk.org/index.php?topic=5489022.0
@@ -91,6 +94,7 @@ nav:
- Tools: getting-started/features/tools.en.md
- Transcribing QR Codes: getting-started/features/QR-transcript-tools.en.md
- Empirical Entropy Measurement: getting-started/features/entropy.en.md
+ - Tiny Seed and other metal plates: getting-started/features/tinyseed.en.md
- Settings: getting-started/settings.en.md
- Navigation Overview: getting-started/navigation.en.md
- Devices and Parts List: parts.en.md
@@ -101,6 +105,7 @@ nav:
plugins:
- search
+ - macros
- i18n:
docs_structure: suffix
languages:
diff --git a/poetry.lock b/poetry.lock
index c8a7caa6c..b5cecf6a7 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -671,6 +671,27 @@ mergedeep = ">=1.3.4"
platformdirs = ">=2.2.0"
pyyaml = ">=5.1"
+[[package]]
+name = "mkdocs-macros-plugin"
+version = "1.0.5"
+description = "Unleash the power of MkDocs with macros and variables"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "mkdocs-macros-plugin-1.0.5.tar.gz", hash = "sha256:fe348d75f01c911f362b6d998c57b3d85b505876dde69db924f2c512c395c328"},
+ {file = "mkdocs_macros_plugin-1.0.5-py3-none-any.whl", hash = "sha256:f60e26f711f5a830ddf1e7980865bf5c0f1180db56109803cdd280073c1a050a"},
+]
+
+[package.dependencies]
+jinja2 = "*"
+mkdocs = ">=0.17"
+python-dateutil = "*"
+pyyaml = "*"
+termcolor = "*"
+
+[package.extras]
+test = ["mkdocs-include-markdown-plugin", "mkdocs-macros-test", "mkdocs-material (>=6.2)"]
+
[[package]]
name = "mkdocs-material"
version = "9.5.28"
@@ -1478,6 +1499,20 @@ files = [
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
+[[package]]
+name = "termcolor"
+version = "2.4.0"
+description = "ANSI color formatting for output in terminal"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"},
+ {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"},
+]
+
+[package.extras]
+tests = ["pytest", "pytest-cov"]
+
[[package]]
name = "tomli"
version = "2.0.1"
@@ -1635,4 +1670,4 @@ simulator = ["Pillow", "numpy", "opencv-python", "pygame", "pyzbar"]
[metadata]
lock-version = "2.0"
python-versions = "^3.9.1"
-content-hash = "235e193b46ca306b56a2055685ac78418466ac23acfd19b3ac8c2bdf329024d5"
+content-hash = "2721280557ad4eca70abac3b4f9454ec3a4166ab90e1b3ece4e695a668e6a02e"
diff --git a/pyproject.toml b/pyproject.toml
index 22e4b132a..bca3a1e0a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -38,6 +38,7 @@ mkdocs = "^1.6.0"
mkdocs-material = "^9.5.28"
mkdocs-static-i18n = "^1.2.3"
pymdown-extensions = "^10.8.1"
+mkdocs-macros-plugin = "^1.0.5"
# Simulator dependencies. Optional extras
numpy = { version = "^1.25.2", optional = true }
diff --git a/simulator/generate-device-screenshots.sh b/simulator/generate-device-screenshots.sh
index 8d82e0a06..0786fa151 100755
--- a/simulator/generate-device-screenshots.sh
+++ b/simulator/generate-device-screenshots.sh
@@ -46,6 +46,7 @@ poetry run poe simulator --sequence sequences/logo.txt --device $device
poetry run poe simulator --sequence sequences/load-mnemonic-options.txt --sd --device $device
poetry run poe simulator --sequence sequences/new-mnemonic-options.txt --sd --device $device
poetry run poe simulator --sequence sequences/load-mnemonic-sequence.txt --sd --device $device
+poetry run poe simulator --sequence sequences/load-mnemonic-double-mnemonic.txt --sd --device maixpy_amigo
# Home
poetry run poe simulator --sequence sequences/home-options.txt --device $device
diff --git a/simulator/sequences/load-mnemonic-double-mnemonic.txt b/simulator/sequences/load-mnemonic-double-mnemonic.txt
new file mode 100644
index 000000000..b44de2b6a
--- /dev/null
+++ b/simulator/sequences/load-mnemonic-double-mnemonic.txt
@@ -0,0 +1,9 @@
+include _wait-for-logo.txt
+
+# Navigate to via QR
+x3 press BUTTON_A
+
+qrcode double-mnemonic.png
+wait 0.5
+
+screenshot load-mnemonic-seq-double-mnemonic.png
diff --git a/simulator/sequences/qrcodes/double-mnemonic.png b/simulator/sequences/qrcodes/double-mnemonic.png
new file mode 100644
index 000000000..aa6cdd6cc
Binary files /dev/null and b/simulator/sequences/qrcodes/double-mnemonic.png differ
diff --git a/src/krux/bip39.py b/src/krux/bip39.py
new file mode 100644
index 000000000..4c797fe8a
--- /dev/null
+++ b/src/krux/bip39.py
@@ -0,0 +1,45 @@
+# Mnemonic convertion to seed and to/from bytes
+# pylint: disable=W0102
+
+import hashlib
+from embit.wordlists.bip39 import WORDLIST
+
+WORDINDEX = {word: i for i, word in enumerate(WORDLIST)}
+
+
+def mnemonic_to_bytes(mnemonic: str, ignore_checksum: bool = False, wordlist=WORDLIST):
+ """Verifies the mnemonic checksum and returns it in bytes"""
+ words = mnemonic.strip().split()
+ if len(words) % 3 != 0 or not 12 <= len(words) <= 24:
+ raise ValueError("Invalid recovery phrase")
+
+ accumulator = 0
+ try:
+ if wordlist is WORDLIST:
+ for word in words:
+ accumulator = (accumulator << 11) + WORDINDEX[word]
+ else:
+ for word in words:
+ accumulator = (accumulator << 11) + wordlist.index(word)
+ except Exception:
+ raise ValueError("Word '%s' is not in the dictionary" % word)
+
+ entropy_length_bits = len(words) * 11 // 33 * 32
+ checksum_length_bits = len(words) * 11 // 33
+ checksum = accumulator & (2**checksum_length_bits - 1)
+ accumulator >>= checksum_length_bits
+ data = accumulator.to_bytes(entropy_length_bits // 8, "big")
+ computed_checksum = hashlib.sha256(data).digest()[0] >> 8 - checksum_length_bits
+
+ if not ignore_checksum and checksum != computed_checksum:
+ raise ValueError("Checksum verification failed")
+ return data
+
+
+def mnemonic_is_valid(mnemonic: str, wordlist=WORDLIST):
+ """Checks if mnemonic is valid (checksum and words)"""
+ try:
+ mnemonic_to_bytes(mnemonic, wordlist=wordlist)
+ return True
+ except:
+ return False
diff --git a/src/krux/display.py b/src/krux/display.py
index c30a2df0d..b1e0dfc91 100644
--- a/src/krux/display.py
+++ b/src/krux/display.py
@@ -24,6 +24,7 @@
import time
from .themes import theme
from .krux_settings import Settings
+from .settings import THIN_SPACE
DEFAULT_PADDING = 10
MINIMAL_PADDING = 5
@@ -51,8 +52,6 @@
SMALLEST_WIDTH = 135
SMALLEST_HEIGHT = 240
-THIN_SPACE = " "
-
# Splash will use horizontally-centered text plots. Uses Thin spaces to help with alignment
SPLASH = [
"██" + THIN_SPACE * 3,
diff --git a/src/krux/key.py b/src/krux/key.py
index 05865048a..77b2a591a 100644
--- a/src/krux/key.py
+++ b/src/krux/key.py
@@ -31,7 +31,7 @@
from embit import bip32, bip39
from embit.wordlists.bip39 import WORDLIST
from embit.networks import NETWORKS
-from .settings import TEST_TXT
+from .settings import TEST_TXT, THIN_SPACE
DER_SINGLE = "m/%dh/%dh/%dh"
DER_MULTI = "m/%dh/%dh/%dh/2h"
@@ -191,13 +191,13 @@ def get_default_derivation(multisig, network, account=0, script_type=P2WPKH):
@staticmethod
def format_derivation(derivation, pretty=False):
"""Helper method to display the derivation path formatted"""
- formatted_txt = DERIVATION_PATH_SYMBOL + " %s" if pretty else "%s"
+ formatted_txt = DERIVATION_PATH_SYMBOL + THIN_SPACE + "%s" if pretty else "%s"
return (formatted_txt % derivation).replace("h", HARDENED_STR_REPLACE)
@staticmethod
def format_fingerprint(fingerprint, pretty=False):
"""Helper method to display the fingerprint formatted"""
- formatted_txt = FINGERPRINT_SYMBOL + " %s" if pretty else "%s"
+ formatted_txt = FINGERPRINT_SYMBOL + THIN_SPACE + "%s" if pretty else "%s"
return formatted_txt % hexlify(fingerprint).decode("utf-8")
@staticmethod
diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py
index 5b959529d..b294e30f5 100644
--- a/src/krux/pages/__init__.py
+++ b/src/krux/pages/__init__.py
@@ -257,14 +257,25 @@ def display_qr_codes(self, data, qr_format, title=""):
done = True
# interval done in input.py using timers
- def display_mnemonic(self, mnemonic, suffix=""):
+ def display_mnemonic(
+ self, mnemonic: str, suffix="", display_mnemonic: str = None, fingerprint=""
+ ):
"""Displays the 12 or 24-word list of words to the user"""
- words = mnemonic.split(" ")
+ from ..wallet import is_double_mnemonic
+
+ if display_mnemonic is None:
+ display_mnemonic = mnemonic
+ words = display_mnemonic.split(" ")
word_list = [
str(i + 1) + "." + (" " if i + 1 < 10 else " ") + word
for i, word in enumerate(words)
]
- header = "BIP39" + " " + suffix
+
+ if is_double_mnemonic(mnemonic):
+ suffix += "*"
+ if fingerprint:
+ fingerprint = "\n" + fingerprint
+ header = "BIP39" + " " + suffix + fingerprint
self.ctx.display.clear()
self.ctx.display.draw_hcentered_text(header)
starting_y_offset = DEFAULT_PADDING // 4 + (
@@ -829,14 +840,17 @@ def _draw_menu(self, selected_item_index):
offset_y += delta_y
-def choose_len_mnemonic(ctx):
+def choose_len_mnemonic(ctx, double_mnemonic=False):
"""Reusable '12 or 24 words?" menu choice"""
+ items = [
+ (t("12 words"), lambda: 12),
+ (t("24 words"), lambda: 24),
+ ]
+ if double_mnemonic:
+ items += [(t("Double mnemonic"), lambda: 48)]
submenu = Menu(
ctx,
- [
- (t("12 words"), lambda: 12),
- (t("24 words"), lambda: 24),
- ],
+ items,
back_status=lambda: None,
)
_, num_words = submenu.run_loop()
diff --git a/src/krux/pages/capture_entropy.py b/src/krux/pages/capture_entropy.py
index 362aec691..a0031094b 100644
--- a/src/krux/pages/capture_entropy.py
+++ b/src/krux/pages/capture_entropy.py
@@ -173,7 +173,7 @@ def capture(self, show_entropy_details=True):
self.flash_text(t("Capture cancelled"))
return None
- self.ctx.display.draw_centered_text(t("Processing ..."))
+ self.ctx.display.draw_centered_text(t("Processing.."))
self.entropy_measurement_update(img, all_at_once=True)
diff --git a/src/krux/pages/encryption_ui.py b/src/krux/pages/encryption_ui.py
index 125e1a0bd..f4601b04d 100644
--- a/src/krux/pages/encryption_ui.py
+++ b/src/krux/pages/encryption_ui.py
@@ -183,7 +183,7 @@ def store_mnemonic_on_memory(self, sd_card=False):
return
self.ctx.display.clear()
- self.ctx.display.draw_centered_text(t("Processing ..."))
+ self.ctx.display.draw_centered_text(t("Processing.."))
words = self.ctx.wallet.key.mnemonic
if mnemonic_storage.store_encrypted(key, mnemonic_id, words, sd_card, i_vector):
self.ctx.display.clear()
@@ -205,7 +205,7 @@ def encrypted_qr_code(self):
key, mnemonic_id, i_vector = user_inputs
self.ctx.display.clear()
- self.ctx.display.draw_centered_text(t("Processing ..."))
+ self.ctx.display.draw_centered_text(t("Processing.."))
from ..encryption import EncryptedQRCode
@@ -275,7 +275,7 @@ def _load_encrypted_mnemonic(self, mnemonic_id, sd_card=False):
self.flash_error(t("Key was not provided"))
return MENU_CONTINUE
self.ctx.display.clear()
- self.ctx.display.draw_centered_text(t("Processing ..."))
+ self.ctx.display.draw_centered_text(t("Processing.."))
mnemonic_storage = MnemonicStorage()
try:
words = mnemonic_storage.decrypt(key, mnemonic_id, sd_card).split()
diff --git a/src/krux/pages/home_pages/addresses.py b/src/krux/pages/home_pages/addresses.py
index c0807cd4b..0ab52d606 100644
--- a/src/krux/pages/home_pages/addresses.py
+++ b/src/krux/pages/home_pages/addresses.py
@@ -21,8 +21,9 @@
# THE SOFTWARE.
import gc
-from ...display import BOTTOM_PROMPT_LINE, THIN_SPACE
+from ...display import BOTTOM_PROMPT_LINE
from ...krux_settings import t
+from ...settings import THIN_SPACE
from ...qr import FORMAT_NONE
from .. import (
Page,
diff --git a/src/krux/pages/home_pages/bip85.py b/src/krux/pages/home_pages/bip85.py
index 88fb50916..26b5bc303 100644
--- a/src/krux/pages/home_pages/bip85.py
+++ b/src/krux/pages/home_pages/bip85.py
@@ -76,7 +76,8 @@ def export(self):
if not Settings().security.hide_mnemonic:
self.display_mnemonic(
bip85_words,
- suffix=t("Words") + "\n%s" % key.fingerprint_hex_str(True),
+ suffix=t("Words"),
+ fingerprint=key.fingerprint_hex_str(True),
)
else:
self.ctx.display.draw_centered_text(key.fingerprint_hex_str(True))
diff --git a/src/krux/pages/home_pages/home.py b/src/krux/pages/home_pages/home.py
index ed8d115e5..8152c80a9 100644
--- a/src/krux/pages/home_pages/home.py
+++ b/src/krux/pages/home_pages/home.py
@@ -353,7 +353,7 @@ def sign_psbt(self):
return MENU_CONTINUE
self.ctx.display.clear()
- self.ctx.display.draw_centered_text(t("Processing ..."))
+ self.ctx.display.draw_centered_text(t("Processing.."))
outputs, fee_percent = signer.outputs()
# Warn if fees greater than 10% of what is spent
diff --git a/src/krux/pages/home_pages/mnemonic_backup.py b/src/krux/pages/home_pages/mnemonic_backup.py
index 6d9db11b5..26b892a7e 100644
--- a/src/krux/pages/home_pages/mnemonic_backup.py
+++ b/src/krux/pages/home_pages/mnemonic_backup.py
@@ -93,9 +93,9 @@ def encrypt_qr_code(self):
encrypt_qr_code = EncryptMnemonic(self.ctx)
return encrypt_qr_code.encrypted_qr_code()
- def show_mnemonic(self, mnemonic, suffix=""):
+ def show_mnemonic(self, mnemonic, suffix="", display_mnemonic=None):
"""Displays only the mnemonic words or indexes"""
- self.display_mnemonic(mnemonic, suffix)
+ self.display_mnemonic(mnemonic, suffix, display_mnemonic)
self.ctx.input.wait_for_button()
# Avoid printing text on a cnc
@@ -121,28 +121,31 @@ def display_mnemonic_numbers(self):
(
t("Decimal"),
lambda: self.show_mnemonic(
+ self.ctx.wallet.key.mnemonic,
+ Utils.BASE_DEC_SUFFIX,
Utils.get_mnemonic_numbers(
self.ctx.wallet.key.mnemonic, Utils.BASE_DEC
),
- Utils.BASE_DEC_SUFFIX,
),
),
(
t("Hexadecimal"),
lambda: self.show_mnemonic(
+ self.ctx.wallet.key.mnemonic,
+ Utils.BASE_HEX_SUFFIX,
Utils.get_mnemonic_numbers(
self.ctx.wallet.key.mnemonic, Utils.BASE_HEX
),
- Utils.BASE_HEX_SUFFIX,
),
),
(
t("Octal"),
lambda: self.show_mnemonic(
+ self.ctx.wallet.key.mnemonic,
+ Utils.BASE_OCT_SUFFIX,
Utils.get_mnemonic_numbers(
self.ctx.wallet.key.mnemonic, Utils.BASE_OCT
),
- Utils.BASE_OCT_SUFFIX,
),
),
],
diff --git a/src/krux/pages/login.py b/src/krux/pages/login.py
index 0ec146baa..6f4ff6587 100644
--- a/src/krux/pages/login.py
+++ b/src/krux/pages/login.py
@@ -23,7 +23,6 @@
import sys
from embit.networks import NETWORKS
from embit.wordlists.bip39 import WORDLIST
-from embit import bip39
from ..display import DEFAULT_PADDING, FONT_HEIGHT, BOTTOM_PROMPT_LINE
from ..krux_settings import Settings
from ..qr import FORMAT_UR
@@ -153,13 +152,15 @@ def new_key_from_dice(self, d_20=False):
dice_entropy = DiceEntropy(self.ctx, d_20)
captured_entropy = dice_entropy.new_key()
if captured_entropy is not None:
- words = bip39.mnemonic_from_bytes(captured_entropy).split()
+ from embit.bip39 import mnemonic_from_bytes
+
+ words = mnemonic_from_bytes(captured_entropy).split()
return self._load_key_from_words(words)
return MENU_CONTINUE
def new_key_from_snapshot(self):
"""Use camera's entropy to create a new mnemonic"""
- len_mnemonic = choose_len_mnemonic(self.ctx)
+ len_mnemonic = choose_len_mnemonic(self.ctx, True)
if not len_mnemonic:
return MENU_CONTINUE
@@ -175,6 +176,7 @@ def new_key_from_snapshot(self):
entropy_bytes = camera_entropy.capture()
if entropy_bytes is not None:
import binascii
+ from embit.bip39 import mnemonic_from_bytes
entropy_hash = binascii.hexlify(entropy_bytes).decode()
self.ctx.display.clear()
@@ -182,9 +184,49 @@ def new_key_from_snapshot(self):
t("SHA256 of snapshot:") + "\n\n%s" % entropy_hash
)
self.ctx.input.wait_for_button()
+
+ self.ctx.display.clear()
+ self.ctx.display.draw_centered_text(t("Processing.."))
+
num_bytes = 16 if len_mnemonic == 12 else 32
- words = bip39.mnemonic_from_bytes(entropy_bytes[:num_bytes]).split()
- return self._load_key_from_words(words)
+ entropy_mnemonic = mnemonic_from_bytes(entropy_bytes[:num_bytes])
+
+ # Double mnemonic check
+ if len_mnemonic == 48:
+ from ..wallet import is_double_mnemonic
+
+ if not is_double_mnemonic(entropy_mnemonic):
+ from ..wdt import wdt
+ import time
+ from krux.bip39 import mnemonic_is_valid
+
+ pre_t = time.ticks_ms()
+ tries = 0
+
+ # create two 12w mnemonic with the provided entropy
+ first_12 = mnemonic_from_bytes(entropy_bytes[:16])
+ second_entropy_mnemonic_int = int.from_bytes(
+ entropy_bytes[16:32], "big"
+ )
+ double_mnemonic = False
+ while not double_mnemonic:
+ wdt.feed()
+ tries += 1
+ # increment the second mnemonic entropy
+ second_entropy_mnemonic_int += 1
+ second_12 = mnemonic_from_bytes(
+ second_entropy_mnemonic_int.to_bytes(16, "big")
+ )
+ entropy_mnemonic = first_12 + " " + second_12
+ double_mnemonic = mnemonic_is_valid(entropy_mnemonic)
+
+ print(
+ "Tries: %d" % tries,
+ "/ %d" % (time.ticks_ms() - pre_t),
+ "ms",
+ )
+
+ return self._load_key_from_words(entropy_mnemonic.split())
return MENU_CONTINUE
def _load_key_from_words(self, words, charset=LETTERS):
@@ -204,7 +246,7 @@ def _load_key_from_words(self, words, charset=LETTERS):
DIGITS_OCT: Utils.BASE_OCT_SUFFIX,
}
numbers_str = Utils.get_mnemonic_numbers(mnemonic, charset_type[charset])
- self.display_mnemonic(numbers_str, suffix_dict[charset])
+ self.display_mnemonic(mnemonic, suffix_dict[charset], numbers_str)
if not self.prompt(t("Continue?"), BOTTOM_PROMPT_LINE):
return MENU_CONTINUE
self.ctx.display.clear()
@@ -289,6 +331,7 @@ def _encrypted_qr_code(self, data):
public_data + "\n\n" + t("Decrypt?"), self.ctx.display.height() // 2
):
from .encryption_ui import EncryptionKey
+ from embit.bip39 import mnemonic_from_bytes
key_capture = EncryptionKey(self.ctx)
key = key_capture.encryption_key()
@@ -296,12 +339,12 @@ def _encrypted_qr_code(self, data):
self.flash_error(t("Key was not provided"))
return MENU_CONTINUE
self.ctx.display.clear()
- self.ctx.display.draw_centered_text(t("Processing ..."))
+ self.ctx.display.draw_centered_text(t("Processing.."))
word_bytes = encrypted_qr.decrypt(key)
if word_bytes is None:
self.flash_error(t("Failed to decrypt"))
return MENU_CONTINUE
- return bip39.mnemonic_from_bytes(word_bytes).split()
+ return mnemonic_from_bytes(word_bytes).split()
return MENU_CONTINUE # prompt NO
return None
@@ -342,9 +385,11 @@ def load_key_from_qr_code(self):
except:
pass
+ # CompactSeedQR format
if len(data_bytes) in (16, 32):
- # CompactSeedQR format
- words = bip39.mnemonic_from_bytes(data_bytes).split()
+ from embit.bip39 import mnemonic_from_bytes
+
+ words = mnemonic_from_bytes(data_bytes).split()
# SeedQR format
elif len(data_bytes) in (48, 96):
words = [
diff --git a/src/krux/pages/qr_view.py b/src/krux/pages/qr_view.py
index 2673cc02d..d73358b40 100644
--- a/src/krux/pages/qr_view.py
+++ b/src/krux/pages/qr_view.py
@@ -25,8 +25,9 @@
from . import Page, Menu, MENU_CONTINUE, MENU_EXIT, ESC_KEY
from ..themes import theme, WHITE, BLACK
from ..krux_settings import t
+from ..settings import THIN_SPACE
from ..qr import get_size
-from ..display import DEFAULT_PADDING, FONT_HEIGHT, SMALLEST_WIDTH, THIN_SPACE
+from ..display import DEFAULT_PADDING, FONT_HEIGHT, SMALLEST_WIDTH
from ..input import (
BUTTON_ENTER,
BUTTON_PAGE,
@@ -373,7 +374,7 @@ def save_bmp_image(self, file_name, resolution):
return
self.ctx.display.clear()
- self.ctx.display.draw_centered_text(t("Saving ..."))
+ self.ctx.display.draw_centered_text(t("Processing.."))
bmp_img.save("/sd/" + file_name)
self.flash_text(t("Saved to SD card") + ":\n%s" % file_name)
diff --git a/src/krux/pages/utils.py b/src/krux/pages/utils.py
index 3e5de2d92..fefdc2261 100644
--- a/src/krux/pages/utils.py
+++ b/src/krux/pages/utils.py
@@ -73,10 +73,10 @@ def load_file(self, file_ext="", prompt=True, only_get_filename=False):
return "", None
@staticmethod
- def get_mnemonic_numbers(words, base=BASE_DEC):
+ def get_mnemonic_numbers(mnemonic: str, base=BASE_DEC):
"""Returns the mnemonic as indexes in decimal, hexadecimal, or octal"""
word_numbers = []
- for word in words.split(" "):
+ for word in mnemonic.split(" "):
word_numbers.append(WORDLIST.index(word) + 1)
if base == Utils.BASE_HEX:
diff --git a/src/krux/psbt.py b/src/krux/psbt.py
index fff82c01e..5a9594de3 100644
--- a/src/krux/psbt.py
+++ b/src/krux/psbt.py
@@ -26,10 +26,10 @@
from urtypes.crypto import CRYPTO_PSBT
from .baseconv import base_decode
from .krux_settings import t
+from .settings import THIN_SPACE
from .qr import FORMAT_PMOFN, FORMAT_BBQR
from .key import Key, P2PKH, P2SH, P2SH_P2WPKH, P2SH_P2WSH, P2WPKH, P2WSH, P2TR
from .sats_vb import SatsVB
-from .display import THIN_SPACE
# PSBT Output Types:
CHANGE = 0
diff --git a/src/krux/settings.py b/src/krux/settings.py
index 51a308add..4d8a4765b 100644
--- a/src/krux/settings.py
+++ b/src/krux/settings.py
@@ -38,6 +38,8 @@
MAIN_TXT = "main"
TEST_TXT = "test"
+THIN_SPACE = " "
+
class SettingsNamespace:
"""Represents a settings namespace containing settings and child namespaces"""
diff --git a/src/krux/translations.py b/src/krux/translations.py
index bcc0d8d93..9cd68e73d 100644
--- a/src/krux/translations.py
+++ b/src/krux/translations.py
@@ -92,6 +92,7 @@
3278654271: "Bildschirm",
3895447625: "Schalten Sie das Gerät nicht aus, es kann eine Weile dauern.",
3836852788: "Fertig?",
+ 690625786: "Doppelte Gedächtnisstütze",
382368239: "Driver",
3582575312: "Verschlüsselt",
1244124409: "Verschlüsselter QR-Code",
@@ -223,7 +224,7 @@
3388542885: "Wird gedruckt",
3593149291: "Trotzdem fortfahren?",
2580599003: "Weiter?",
- 556126964: "Wird bearbeitet ...",
+ 3108881025: "Wird bearbeitet..",
1848310591: "QR-Code",
710709610: "RX Pin",
2697857197: "Empfangen",
@@ -249,7 +250,6 @@
2163347007: "Auf SD-Karte speichern?",
3531742595: "Auf SD-Karte speichern?",
2940025484: "Auf SD-Karte gespeichert",
- 3531363515: "Wird gespeichert …",
763824768: "Skala",
4117455079: "Adresse\nscannen",
4038076821: "Scan BIP39 Passphrase",
@@ -402,6 +402,7 @@
3278654271: "Pantalla",
3895447625: "No apagues el dispositivo, puede tardar un tiempo en completarse.",
3836852788: "¿Listo?",
+ 690625786: "Doble mnemónico",
382368239: "Operador",
3582575312: "Cifrado",
1244124409: "Código QR Cifrado",
@@ -533,7 +534,7 @@
3388542885: "Imprimiendo",
3593149291: "¿Proceder de todas maneras?",
2580599003: "¿Continuar?",
- 556126964: "Procesando ...",
+ 3108881025: "Procesando..",
1848310591: "Código QR",
710709610: "RX Pin",
2697857197: "Recepción",
@@ -559,7 +560,6 @@
2163347007: "Guardar en tarjeta SD",
3531742595: "¿Guardar en la tarjeta SD?",
2940025484: "Guardado en la tarjeta SD",
- 3531363515: "Guardando ...",
763824768: "Escala",
4117455079: "Escanear Dirección",
4038076821: "Escanear Passphrase BIP39",
@@ -712,6 +712,7 @@
3278654271: "Affichage",
3895447625: "Ne pas éteindre, cela peut prendre un certain temps.",
3836852788: "Terminé\u2009?",
+ 690625786: "Double mnémonique",
382368239: "Conducteur",
3582575312: "Chiffré",
1244124409: "Code QR crypté",
@@ -843,7 +844,7 @@
3388542885: "Impression",
3593149291: "Procéder quand même\u2009?",
2580599003: "Procéder\u2009?",
- 556126964: "Traitement ...",
+ 3108881025: "Traitement..",
1848310591: "QR Code",
710709610: "RX Fiche",
2697857197: "Recevoir",
@@ -869,7 +870,6 @@
2163347007: "Enregistrer sur la carte SD",
3531742595: "Enregistrer sur la carte SD\u2009?",
2940025484: "Enregistré sur la carte SD",
- 3531363515: "Enregistrement en cours...",
763824768: "L'échelle",
4117455079: "Scannez l'adresse",
4038076821: "Scannez la phrase secrète BIP-39",
@@ -1022,6 +1022,7 @@
3278654271: "Weergave",
3895447625: "Schakel het apparaat niet uit, het kan even duren voordat het klaar is.",
3836852788: "Klaar?",
+ 690625786: "Dubbel geheugensteuntje",
382368239: "Driver",
3582575312: "Versleuteld",
1244124409: "Versleutelde QR code",
@@ -1153,7 +1154,7 @@
3388542885: "Afdrukken",
3593149291: "Toch doorgaan?",
2580599003: "Doorgaan?",
- 556126964: "Verwerken...",
+ 3108881025: "Verwerken..",
1848310591: "QR code",
710709610: "RX pin",
2697857197: "Ontvangen",
@@ -1179,7 +1180,6 @@
2163347007: "Opslaan op SD kaart",
3531742595: "Opslaan op SD kaart?",
2940025484: "Opgeslagen op SD kaart",
- 3531363515: "Opslaan bezig...",
763824768: "Schaal",
4117455079: "Adres scannen",
4038076821: "BIP-39 Wachtwoord Scannen",
@@ -1332,6 +1332,7 @@
3278654271: "Wyświetlacz",
3895447625: "Nie wyłączaj zasilania, może to chwilę potrwać.",
3836852788: "Zrobione?",
+ 690625786: "Podwójna mnemotechnika",
382368239: "Kierowca",
3582575312: "Zaszyfrowane",
1244124409: "Zaszyfrowany kod QR",
@@ -1463,7 +1464,7 @@
3388542885: "Drukowanie",
3593149291: "Kontynuować mimo to?",
2580599003: "Przystępować?",
- 556126964: "Przetwarzanie ...",
+ 3108881025: "Przetwarzanie..",
1848310591: "Kod QR",
710709610: "Pin Rx",
2697857197: "Odbierać",
@@ -1489,7 +1490,6 @@
2163347007: "Zapisz na karcie SD",
3531742595: "Zapisz na karcie SD?",
2940025484: "Zapisano na karcie SD",
- 3531363515: "Zapisywanie...",
763824768: "Skala",
4117455079: "Adres skanowania",
4038076821: "Scan BIP39 Passphrase",
@@ -1642,6 +1642,7 @@
3278654271: "Display",
3895447625: "Não desligue, pode demorar um pouco para concluir.",
3836852788: "Feito?",
+ 690625786: "Duplo mnemônico",
382368239: "Driver",
3582575312: "Criptografado",
1244124409: "Código QR Criptografado",
@@ -1773,7 +1774,7 @@
3388542885: "Imprimindo",
3593149291: "Continuar mesmo assim?",
2580599003: "Seguir?",
- 556126964: "Processando ...",
+ 3108881025: "Processando..",
1848310591: "Código QR",
710709610: "Pino RX",
2697857197: "Recebimento",
@@ -1799,7 +1800,6 @@
2163347007: "Salvar no cartão SD",
3531742595: "Salvar no cartão SD?",
2940025484: "Salvo no cartão SD",
- 3531363515: "Salvando...",
763824768: "Escala",
4117455079: "Escanear Endereço",
4038076821: "Escanear a senha BIP39",
@@ -1952,6 +1952,7 @@
3278654271: "Дисплеи",
3895447625: "Не выключайте питание, это может занять некоторое время.",
3836852788: "Готово?",
+ 690625786: "Двойная мнемоника",
382368239: "Драйвер",
3582575312: "Зашифровано",
1244124409: "Зашифрованный QR Код",
@@ -2083,7 +2084,7 @@
3388542885: "Идет печать",
3593149291: "Все равно продолжить?",
2580599003: "Продолжить?",
- 556126964: "Обработка ...",
+ 3108881025: "Обработка..",
1848310591: "QR Код",
710709610: "RX Пин",
2697857197: "Получить",
@@ -2109,7 +2110,6 @@
2163347007: "Сохранить на SD-карту",
3531742595: "Сохранить на SD карту?",
2940025484: "Сохранено на SD карту",
- 3531363515: "Сохранение...",
763824768: "Шкала",
4117455079: "Отсканировать Адрес",
4038076821: "Отсканировать BIP39 фразу-пароль",
@@ -2262,6 +2262,7 @@
3278654271: "Ekran",
3895447625: "Kapatmayın, tamamlanması biraz zaman alabilir.",
3836852788: "Tamamlandı mı?",
+ 690625786: "Çifte anımsatıcı",
382368239: "Sürücü",
3582575312: "Şifrelenmiş",
1244124409: "Şifrelenmiş QR Kodu",
@@ -2393,7 +2394,7 @@
3388542885: "Yazdırılıyor",
3593149291: "Yine de devam edilsin mi?",
2580599003: "Devam edilsin mi?",
- 556126964: "İşleniyor ...",
+ 3108881025: "İşleniyor..",
1848310591: "QR Kodu",
710709610: "RX Pini",
2697857197: "Al",
@@ -2419,7 +2420,6 @@
2163347007: "SD karta kaydet",
3531742595: "SD karta kaydedilsin mi?",
2940025484: "SD karta kaydedildi",
- 3531363515: "Kaydediliyor ...",
763824768: "Ölçek",
4117455079: "Adresi Tara",
4038076821: "BIP39 Parolasını Tara",
@@ -2572,6 +2572,7 @@
3278654271: "Hiển thị",
3895447625: "Không được tắt máy, có thể mất một lúc để hoàn thành.",
3836852788: "Hoàn tất?",
+ 690625786: "Từ gợi nhớ kép",
382368239: "Driver",
3582575312: "Đã mã hóa",
1244124409: "Mã QR được mã hóa",
@@ -2703,7 +2704,7 @@
3388542885: "Đang in",
3593149291: "Vẫn tiếp tục?",
2580599003: "Thực hiện?",
- 556126964: "Đang xử lý ...",
+ 3108881025: "Đang xử lý..",
1848310591: "Mã QR",
710709610: "RX Pin",
2697857197: "Nhận được",
@@ -2729,7 +2730,6 @@
2163347007: "Lưu vào thẻ SD",
3531742595: "Lưu vào thẻ SD?",
2940025484: "Đã lưu vào thẻ SD",
- 3531363515: "Đang lưu...",
763824768: "Tỉ lệ",
4117455079: "Quét địa chỉ",
4038076821: "Quét cụm mật khẩu BIP39",
diff --git a/src/krux/wallet.py b/src/krux/wallet.py
index 367c7d20b..fd23896b8 100644
--- a/src/krux/wallet.py
+++ b/src/krux/wallet.py
@@ -455,3 +455,20 @@ def derivation_to_script_wrapper(derivation):
format_str = "tr({})"
return format_str
+
+
+def is_double_mnemonic(mnemonic: str):
+ """Check if the mnemonic is a double mnemonic (12+12+24)"""
+
+ words = mnemonic.split(" ")
+ if len(words) > 12:
+ from krux.bip39 import mnemonic_is_valid
+
+ if (
+ mnemonic_is_valid(" ".join(words[:12]))
+ and mnemonic_is_valid(" ".join(words[12:]))
+ and mnemonic_is_valid(mnemonic)
+ ):
+ return True
+
+ return False
diff --git a/tests/pages/home_pages/test_bip85.py b/tests/pages/home_pages/test_bip85.py
index d2809637c..dfa21e31a 100644
--- a/tests/pages/home_pages/test_bip85.py
+++ b/tests/pages/home_pages/test_bip85.py
@@ -3,6 +3,7 @@
def test_bip85_wallet_creation(mocker, amigo, tdata):
from krux.krux_settings import Settings
+ from krux.settings import THIN_SPACE
from krux.pages.home_pages.bip85 import Bip85
from krux.wallet import Wallet
from krux.input import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV
@@ -149,7 +150,7 @@ def test_bip85_wallet_creation(mocker, amigo, tdata):
if case[2]:
bip85_ui.display_mnemonic.assert_called_with(
- case[2], suffix="Words" + "\n⊚ %s" % case[3]
+ case[2], suffix="Words", fingerprint="⊚" + THIN_SPACE + "%s" % case[3]
)
else:
bip85_ui.display_mnemonic.assert_not_called()
@@ -166,4 +167,4 @@ def test_bip85_wallet_creation(mocker, amigo, tdata):
bip85_ui = Bip85(ctx)
mocker.spy(bip85_ui, "display_mnemonic")
bip85_ui.export()
- ctx.display.draw_centered_text.assert_called_with("⊚ %s" % case[3])
+ ctx.display.draw_centered_text.assert_called_with("⊚" + THIN_SPACE + "%s" % case[3])
diff --git a/tests/pages/home_pages/test_home.py b/tests/pages/home_pages/test_home.py
index ac84a0b44..35c0f3a2e 100644
--- a/tests/pages/home_pages/test_home.py
+++ b/tests/pages/home_pages/test_home.py
@@ -741,6 +741,7 @@ def test_psbt_warnings(mocker, m5stickv, tdata):
B64_PSBT_FILE_EXTENSION,
SIGNED_FILE_SUFFIX,
)
+ from krux.settings import THIN_SPACE
PSBT_FILE_NAME = "test.psbt"
SIGNED_PSBT_FILE_NAME = "test-signed.psbt"
@@ -808,7 +809,13 @@ def test_psbt_warnings(mocker, m5stickv, tdata):
"Warning: Path mismatch\nWallet: m/48'/0'/0'/2'\nPSBT: m/48'/1'/0'/2'"
),
mocker.call(
- "PSBT policy:\np2wsh\n2 of 3\n⊚ 26bb83c4\n⊚ 0208cb77\n⊚ 73c5da0a"
+ "PSBT policy:\np2wsh\n2 of 3\n⊚"
+ + THIN_SPACE
+ + "26bb83c4\n⊚"
+ + THIN_SPACE
+ + "0208cb77\n⊚"
+ + THIN_SPACE
+ + "73c5da0a"
),
]
)
@@ -1032,7 +1039,7 @@ def test_sign_high_fee(mocker, m5stickv, tdata):
mocker.call(
"Warning: Path mismatch\nWallet: m/84'/0'/0'\nPSBT: m/84'/1'/0'"
),
- mocker.call("Processing ..."),
+ mocker.call("Processing.."),
mocker.call("Warning: High fees!\n799.7% of the amount."),
]
)
@@ -1082,7 +1089,7 @@ def test_sign_self(mocker, m5stickv, tdata):
mocker.call(
"Warning: Path mismatch\nWallet: m/84'/0'/0'\nPSBT: m/84'/1'/0'"
),
- mocker.call("Processing ..."),
+ mocker.call("Processing.."),
mocker.call("Warning: High fees!\n799.7% of the amount."),
]
)
@@ -1133,7 +1140,7 @@ def test_sign_spent_and_self(mocker, m5stickv, tdata):
mocker.call(
"Warning: Path mismatch\nWallet: m/84'/0'/0'\nPSBT: m/84'/1'/0'"
),
- mocker.call("Processing ..."),
+ mocker.call("Processing.."),
mocker.call("Warning: High fees!\n235.9% of the amount."),
]
)
diff --git a/tests/pages/home_pages/test_mnemonic_backup.py b/tests/pages/home_pages/test_mnemonic_backup.py
index b00509179..eee7af4d0 100644
--- a/tests/pages/home_pages/test_mnemonic_backup.py
+++ b/tests/pages/home_pages/test_mnemonic_backup.py
@@ -89,7 +89,7 @@ def test_mnemonic_words(mocker, m5stickv, tdata):
mnemonics.mnemonic()
mnemonics.display_mnemonic.assert_called_with(
- ctx.wallet.key.mnemonic, "Mnemonic"
+ ctx.wallet.key.mnemonic, "Mnemonic", None
)
assert ctx.input.wait_for_button.call_count == len(case[2])
diff --git a/tests/pages/test_login.py b/tests/pages/test_login.py
index 7338915af..491b54ed7 100644
--- a/tests/pages/test_login.py
+++ b/tests/pages/test_login.py
@@ -167,7 +167,7 @@ def test_new_12w_from_snapshot(m5stickv, mocker):
from krux.input import BUTTON_ENTER, BUTTON_PAGE_PREV
# mocks a result of a hashed image
- mock_capture_entropy = mocker.patch(
+ mocker.patch(
"krux.pages.capture_entropy.CameraEntropy.capture", return_value=b"\x01" * 32
)
@@ -196,6 +196,79 @@ def test_new_12w_from_snapshot(m5stickv, mocker):
assert ctx.wallet.key.mnemonic == MNEMONIC
+def test_new_24w_from_snapshot(m5stickv, mocker):
+ from krux.pages.login import Login
+ from krux.input import BUTTON_ENTER, BUTTON_PAGE
+
+ # mocks a result of a hashed image
+ mocker.patch(
+ "krux.pages.capture_entropy.CameraEntropy.capture", return_value=b"\x01" * 32
+ )
+
+ BTN_SEQUENCE = (
+ # 1 move to select 24 words, 1 press to proceed
+ [BUTTON_PAGE, BUTTON_ENTER]
+ +
+ # 1 press to proceed msg
+ [BUTTON_ENTER]
+ +
+ # SHA256
+ [BUTTON_ENTER]
+ +
+ # Words 2x
+ [BUTTON_ENTER, BUTTON_ENTER]
+ +
+ # Load Wallet
+ [BUTTON_ENTER]
+ )
+ MNEMONIC = "absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice comic"
+ ctx = create_ctx(mocker, BTN_SEQUENCE)
+ login = Login(ctx)
+ login.new_key_from_snapshot()
+
+ assert ctx.input.wait_for_button.call_count == len(BTN_SEQUENCE)
+ assert ctx.wallet.key.mnemonic == MNEMONIC
+
+
+def test_new_double_mnemonic_from_snapshot(m5stickv, mocker):
+ from krux.pages.login import Login
+ from krux.input import BUTTON_ENTER, BUTTON_PAGE
+ from krux.wallet import is_double_mnemonic
+ from krux.display import DEFAULT_PADDING
+ from krux.themes import WHITE, BLACK
+
+ # mocks a result of a hashed image
+ mocker.patch(
+ "krux.pages.capture_entropy.CameraEntropy.capture", return_value=b"\x01" * 32
+ )
+
+ BTN_SEQUENCE = (
+ # 2 moves to select double mnemonic, 1 press to proceed
+ [BUTTON_PAGE, BUTTON_PAGE, BUTTON_ENTER]
+ +
+ # 1 press to proceed msg
+ [BUTTON_ENTER]
+ +
+ # SHA256
+ [BUTTON_ENTER]
+ +
+ # Words 2x
+ [BUTTON_ENTER, BUTTON_ENTER]
+ +
+ # Load Wallet
+ [BUTTON_ENTER]
+ )
+ MNEMONIC = "absurd amount doctor acoustic avoid letter advice cage absurd amount doctor adjust absurd amount doctor acoustic avoid letter advice cage absurd amount doll fancy"
+ ctx = create_ctx(mocker, BTN_SEQUENCE)
+ login = Login(ctx)
+ login.new_key_from_snapshot()
+
+ assert ctx.input.wait_for_button.call_count == len(BTN_SEQUENCE)
+ assert ctx.wallet.key.mnemonic == MNEMONIC
+ assert is_double_mnemonic(MNEMONIC) == True
+ ctx.display.draw_hcentered_text.assert_has_calls([mocker.call("BIP39 Mnemonic*")])
+
+
########## load words from qrcode tests
diff --git a/tests/test_bip39.py b/tests/test_bip39.py
new file mode 100644
index 000000000..d6fd67800
--- /dev/null
+++ b/tests/test_bip39.py
@@ -0,0 +1,86 @@
+from krux import bip39 as kruxbip39
+from embit import bip39
+from embit.wordlists.bip39 import WORDLIST
+import secrets
+import pytest
+
+
+def test_one_word_mnemonics():
+ for numwords in (12, 15, 18, 21, 24):
+ for word in WORDLIST:
+ mnemonic = (word + " ") * numwords
+ assert kruxbip39.mnemonic_is_valid(mnemonic) == bip39.mnemonic_is_valid(
+ mnemonic
+ )
+
+
+def test_edge_cases():
+ cases = [16, 20, 24, 28, 32] # 12w, 15w, 18w, 21w and 24w
+ for case in cases:
+ ALL_ZERO_BYTES = b"\x00" * case
+ ALL_ONE_BYTES = b"\xff" * case
+
+ assert (
+ kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(ALL_ZERO_BYTES))
+ == ALL_ZERO_BYTES
+ )
+ assert (
+ kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(ALL_ONE_BYTES))
+ == ALL_ONE_BYTES
+ )
+
+ int_val = max_val = int.from_bytes(ALL_ONE_BYTES, "big")
+ while int_val > 0:
+ int_val = int_val // 2
+ b = int_val.to_bytes(case, "big")
+ assert kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(b)) == b
+
+ b = (max_val - int_val).to_bytes(case, "big")
+ assert kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(b)) == b
+
+
+def test_random_cases():
+ for _ in range(20000):
+ for size in (16, 20, 24, 28, 32):
+ token_bytes = secrets.token_bytes(size)
+ assert (
+ kruxbip39.mnemonic_to_bytes(bip39.mnemonic_from_bytes(token_bytes))
+ == token_bytes
+ )
+
+
+def test_random_cases_custom_wordlist():
+ wordlist = tuple(kruxbip39.WORDLIST)
+ for _ in range(200):
+ for size in (16, 20, 24, 28, 32):
+ token_bytes = secrets.token_bytes(size)
+ assert (
+ kruxbip39.mnemonic_to_bytes(
+ bip39.mnemonic_from_bytes(token_bytes), wordlist=wordlist
+ )
+ == token_bytes
+ )
+
+
+def test_invalid_words():
+ cases = [
+ "not all twelve of these words are in the english bip39 wordslist",
+ "not all fifteen of these words are in the english bip39 wordslist thirteen fourteen fifteen",
+ "not all eighteen of these words are in the english bip39 wordslist thirteen fourteen fifteen sixteen seventeen eighteen",
+ "not all twenty-one of these words are in the english bip39 wordslist thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twenty-one",
+ "not all twenty-four of these words are in the english bip39 wordslist thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twenty-one twenty-two twenty-three twenty-four",
+ ]
+ for case in cases:
+ with pytest.raises(ValueError, match=" is not in the dictionary"):
+ kruxbip39.mnemonic_to_bytes(case)
+
+
+def test_invalid_mnemonic_length():
+ cases = [
+ "nine is divisible by three but is not valid",
+ "thirteen is between twelve and twenty-four but it is not divisible by three",
+ "twenty-seven is divisible by three but it is not a mnemonic with valid length because bip39 support mnemonics of length twelve fifteen eighteen twenty-one and twenty-four only",
+ ]
+ for case in cases:
+ with pytest.raises(ValueError, match="Invalid recovery phrase"):
+ kruxbip39.mnemonic_to_bytes(case)
diff --git a/tests/test_touch.py b/tests/test_touch.py
index b85547176..3170b0e24 100644
--- a/tests/test_touch.py
+++ b/tests/test_touch.py
@@ -29,6 +29,6 @@ def test_touch_event(mocker, amigo):
touch.touch_driver.irq_point = TOUCH_POINT_1 # Simulate touch event
for _ in range(len(EVENTS)):
- event = touch.event()
+ event = touch.event(validate_position=True)
assert event == False
assert touch.current_index() == 3