Skip to content

Commit

Permalink
Merge branch 'develop' into capture_qr_refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
odudex committed Aug 2, 2024
2 parents a35279f + 4f18fbe commit 9b0b3de
Show file tree
Hide file tree
Showing 18 changed files with 194 additions and 57 deletions.
25 changes: 25 additions & 0 deletions docs/getting-started/features/tinyseed.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
## Background
The examples below have been crated so that you can test the workflow for scanning both 12 and 24 word mnemonics. (Scanning the left plate for a 12 word mnemonic and both plates for 24) The resulting fingerprint from an successful scan is also incldued in the image.

### TinySeed
![](../../img/tinyseed_binarygrid/tinyseed.jpg)

### OneKey KeyTag
![](../../img/tinyseed_binarygrid/onekey_keytag.jpg)

### Binary Grid
![](../../img/tinyseed_binarygrid/binarygrid.jpg)

## 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)
4. The location of each cell within the 12x12 grid is calculated. (This uses the xpad and ypad variables)
5. Krux uses the grid created in 4 to evaluate which cells are marked and which are blank, once a seed with a valid checksum is detected, the user can then confirm the dots.

If you have a different type of grid that you want to use, you will need to edit the offsets and padding numbers in tiny_seed.py. (All of the sizes are scaled based on the size of the square detected in step 1...)

You can match the pre-sets for supported key-types to the physical dimensions of the tag as shown below. (The numbers for these offsets are in 1/10th of a millimeter)

![](../../img/tinyseed_binarygrid/size_reference.jpg)
16 changes: 13 additions & 3 deletions docs/getting-started/usage/loading-a-mnemonic.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,20 @@ It's unpleasant having to manually enter 12 or 24 words every time you want to u
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.
You can also use [an offline QR code generator for this](https://iancoleman.io/bip39/) (ideally on an airgapped device).

#### Tiny Seed
#### 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.

[Tiny Seed](https://tinyseed.io/) is a compact metal plate mnemonic backup method.
Krux devices have machine vision capabilities that allow users to scan these metal plates and instantly load mnemonics engraved on them. To properly scan them place the Tiny Seed 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. Find templates to scan or print [here](https://github.com/odudex/krux_binaries/tree/main/templates).
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)

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).

### Via Manual Input
<img src="../../../img/maixpy_m5stickv/load-mnemonic-manual-options-125.png" align="right">
Expand Down
Binary file added docs/img/tinyseed_binarygrid/binarygrid.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/tinyseed_binarygrid/onekey_keytag.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/tinyseed_binarygrid/size_reference.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/tinyseed_binarygrid/tinyseed.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions i18n/translations/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"Backup Mnemonic": "Mnemonik-Backup",
"Bad signature": "Ungültige Signatur",
"Baudrate": "Baudrate",
"Binary Grid": "Binäres Gitter",
"Border Padding": "Randpolsterung",
"Brightness": "Helligkeit",
"Buttons": "Tasten",
Expand Down
1 change: 1 addition & 0 deletions i18n/translations/es-MX.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"Backup Mnemonic": "Backup del Mnemónico",
"Bad signature": "Firma incorrecta",
"Baudrate": "Baudrate",
"Binary Grid": "Cuadrícula binaria",
"Border Padding": "Grosor del Borde",
"Brightness": "Brillo",
"Buttons": "Botones",
Expand Down
1 change: 1 addition & 0 deletions i18n/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"Backup Mnemonic": "Sauvegarde mnémonique",
"Bad signature": "Mauvaise signature",
"Baudrate": "Débit en bauds",
"Binary Grid": "Grille binaire",
"Border Padding": "Rembourrage de bordure",
"Brightness": "Luminosité",
"Buttons": "Boutons",
Expand Down
3 changes: 2 additions & 1 deletion i18n/translations/nl-NL.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"Backup Mnemonic": "Backup geheugensteun",
"Bad signature": "Ongeldige handtekening",
"Baudrate": "Baudratio",
"Binary Grid": "Binair raster",
"Border Padding": "Rand opvulling",
"Brightness": "Helderheid",
"Buttons": "Knoppen",
Expand Down Expand Up @@ -308,4 +309,4 @@
"is a valid receive address!": "is een valide ontvangst adres!",
"was NOT FOUND in the first %d change addresses": "werd NIET GEVONDEN in de eerste %d wisselgeld adressen",
"was NOT FOUND in the first %d receive addresses": "werd NIET GEVONDEN in de eerste %d ontvangst adressen"
}
}
1 change: 1 addition & 0 deletions i18n/translations/pl-PL.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"Backup Mnemonic": "Kopia zapasowa mnemonika",
"Bad signature": "zły podpis",
"Baudrate": "Baudrate",
"Binary Grid": "Siatka binarna",
"Border Padding": "Wyściółka graniczna",
"Brightness": "Jasność",
"Buttons": "Przyciski",
Expand Down
1 change: 1 addition & 0 deletions i18n/translations/pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"Backup Mnemonic": "Backup de Mnemônico",
"Bad signature": "Assinatura Inválida",
"Baudrate": "Baudrate",
"Binary Grid": "Grade binária",
"Border Padding": "Borda",
"Brightness": "Brilho",
"Buttons": "Botões",
Expand Down
1 change: 1 addition & 0 deletions i18n/translations/ru-RU.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"Backup Mnemonic": "Резервная мнемоника",
"Bad signature": "Плохая подпись",
"Baudrate": "Скорость Передачи Данных",
"Binary Grid": "Двоичная сетка",
"Border Padding": "Заполнение Границ",
"Brightness": "Яркость",
"Buttons": "Кнопки",
Expand Down
1 change: 1 addition & 0 deletions i18n/translations/tr-TR.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"Backup Mnemonic": "Yedek Mnemonic",
"Bad signature": "Geçersiz imza",
"Baudrate": "Baud Hızı",
"Binary Grid": "İkili Izgara",
"Border Padding": "Kenarlık Dolgusu",
"Brightness": "Parlaklık",
"Buttons": "Butonlar",
Expand Down
1 change: 1 addition & 0 deletions i18n/translations/vi-VN.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"Backup Mnemonic": "Sao lưu Mnemonic",
"Bad signature": "Chữ ký xấu",
"Baudrate": "Tốc độ baud",
"Binary Grid": "Lưới nhị phân",
"Border Padding": "Đệm viền",
"Brightness": "Độ sáng",
"Buttons": "Nút",
Expand Down
13 changes: 9 additions & 4 deletions src/krux/pages/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,14 @@ def load_key_from_camera(self):
self.ctx,
[
(t("QR Code"), self.load_key_from_qr_code),
("Tiny Seed", lambda: self.load_key_from_tiny_seed_image("TinySeed")),
(
"Tiny Seed",
self.load_key_from_tiny_seed_image,
"OneKey KeyTag",
lambda: self.load_key_from_tiny_seed_image("OneKey KeyTag"),
),
(
t("Binary Grid"),
lambda: self.load_key_from_tiny_seed_image("Binary Grid"),
),
],
)
Expand Down Expand Up @@ -679,7 +684,7 @@ def load_key_from_tiny_seed(self):
return self._load_key_from_words(words)
return MENU_CONTINUE

def load_key_from_tiny_seed_image(self):
def load_key_from_tiny_seed_image(self, grid_type="TinySeed"):
"""Menu handler to scan key from Tiny Seed sheet metal storage method"""
from .tiny_seed import TinyScanner

Expand All @@ -694,7 +699,7 @@ def load_key_from_tiny_seed_image(self):
if not self.prompt(t("Proceed?"), BOTTOM_PROMPT_LINE):
return MENU_CONTINUE

tiny_scanner = TinyScanner(self.ctx)
tiny_scanner = TinyScanner(self.ctx, grid_type)
words = tiny_scanner.scanner(len_mnemonic == 24)
del tiny_scanner
if words is None:
Expand Down
107 changes: 93 additions & 14 deletions src/krux/pages/tiny_seed.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,55 @@ def _editable_bit():
class TinyScanner(Page):
"""Uses camera sensor to detect punch pattern on a Tiny Seed, in metal or paper"""

def __init__(self, ctx):
# Settings for different binary grid types
binary_grid_settings = {
"TinySeed": {
"xpad_factor": (240 / (12 * 345)),
"ypad_factor": (210 / (12 * 272)),
"x_offset_factor_amigo_p0": 39 / 345,
"y_offset_factor_amigo_p0": 44 / 272,
"x_offset_factor_amigo_p1": 42 / 345,
"y_offset_factor_amigo_p1": 41 / 272,
"x_offset_factor_p0": 65 / 345,
"y_offset_factor_p0": 17 / 272,
"x_offset_factor_p1": 62 / 345,
"y_offset_factor_p1": 22 / 272,
"aspect_high": 1.3,
"aspect_low": 1.1,
},
"OneKey KeyTag": {
"xpad_factor": 240 / (12 * 360),
"ypad_factor": 240 / (12 * 335),
"x_offset_factor_amigo_p0": 50 / 360,
"y_offset_factor_amigo_p0": 67 / 335,
"x_offset_factor_amigo_p1": 50 / 360,
"y_offset_factor_amigo_p1": 67 / 335,
"x_offset_factor_p0": 68 / 360,
"y_offset_factor_p0": 30 / 335,
"x_offset_factor_p1": 68 / 360,
"y_offset_factor_p1": 30 / 335,
"aspect_high": 1.1,
"aspect_low": 0.9,
},
"Binary Grid": {
"xpad_factor": 1 / 14,
"ypad_factor": 1 / 14,
"x_offset_factor_amigo_p0": 1 / 14,
"y_offset_factor_amigo_p0": 1 / 14,
"x_offset_factor_amigo_p1": 1 / 14,
"y_offset_factor_amigo_p1": 1 / 14,
"x_offset_factor_p0": 1 / 14,
"y_offset_factor_p0": 1 / 14,
"x_offset_factor_p1": 1 / 14,
"y_offset_factor_p1": 1 / 14,
"aspect_high": 1.1,
"aspect_low": 0.9,
},
}

grid_settings = None

def __init__(self, ctx, grid_type="TinySeed"):
super().__init__(ctx, None)
self.ctx = ctx
# Capturing flag used for first page of 24 words seed
Expand All @@ -591,6 +639,7 @@ def __init__(self, ctx):
self.time_frame = time.ticks_ms()
self.previous_seed_numbers = [1] * 12
self.tiny_seed = TinySeed(self.ctx)
self.grid_settings = self.binary_grid_settings[grid_type]

def _map_punches_region(self, rect_size, page=0):
# Think in portrait mode, with Tiny Seed tilted 90 degrees
Expand All @@ -599,22 +648,46 @@ def _map_punches_region(self, rect_size, page=0):
if not page:
if board.config["type"] == "amigo":
# Amigo has mirrored coordinates
x_offset = rect_size[0] + (rect_size[2] * 39) / 345
y_offset = rect_size[1] + (rect_size[3] * 44) / 272
x_offset = (
rect_size[0]
+ rect_size[2] * self.grid_settings["x_offset_factor_amigo_p0"]
)
y_offset = (
rect_size[1]
+ rect_size[3] * self.grid_settings["y_offset_factor_amigo_p0"]
)
else:
x_offset = rect_size[0] + (rect_size[2] * 65) / 345
y_offset = rect_size[1] + (rect_size[3] * 17) / 272
x_offset = (
rect_size[0]
+ rect_size[2] * self.grid_settings["x_offset_factor_p0"]
)
y_offset = (
rect_size[1]
+ rect_size[3] * self.grid_settings["y_offset_factor_p0"]
)
else:
if board.config["type"] == "amigo":
x_offset = rect_size[0] + (rect_size[2] * 42) / 345
y_offset = rect_size[1] + (rect_size[3] * 41) / 272
x_offset = (
rect_size[0]
+ rect_size[2] * self.grid_settings["x_offset_factor_amigo_p1"]
)
y_offset = (
rect_size[1]
+ rect_size[3] * self.grid_settings["y_offset_factor_amigo_p1"]
)
else:
x_offset = rect_size[0] + (rect_size[2] * 62) / 345
y_offset = rect_size[1] + (rect_size[3] * 22) / 272
x_offset = (
rect_size[0]
+ rect_size[2] * self.grid_settings["x_offset_factor_p1"]
)
y_offset = (
rect_size[1]
+ rect_size[3] * self.grid_settings["y_offset_factor_p1"]
)
self.x_regions.append(int(x_offset))
self.y_regions.append(int(y_offset))
x_pad = rect_size[2] * 240 / (12 * 345)
y_pad = rect_size[3] * 210 / (12 * 272)
x_pad = rect_size[2] * self.grid_settings["xpad_factor"]
y_pad = rect_size[3] * self.grid_settings["ypad_factor"]
for _ in range(12):
x_offset += x_pad
y_offset += y_pad
Expand Down Expand Up @@ -744,6 +817,10 @@ def _gradient_value(self, index, gradient_corners):
def _detect_tiny_seed(self, img):
"""Detects Tiny Seed as a bright blob against a dark surface"""

# Load Settings for the grid type we are using
aspect_low = self.grid_settings["aspect_low"]
aspect_high = self.grid_settings["aspect_high"]

def _choose_rect(rects):
for rect in rects:
aspect = rect[2] / rect[3]
Expand All @@ -752,13 +829,15 @@ def _choose_rect(rects):
and rect[1]
and (rect[0] + rect[2]) < img.width()
and (rect[1] + rect[3]) < img.height()
and aspect_low < aspect < 1.3
and aspect_low < aspect < aspect_high
):
return rect
return None

# Big lenses cameras seems to distor aspect ratio to 1.1
aspect_low = 1.1 if self.ctx.camera.cam_id in (OV2640_ID, OV5642_ID) else 1.2
# Big lenses cameras seems to distort aspect ratio
if self.ctx.camera.cam_id not in (OV2640_ID, OV5642_ID):
aspect_low += 0.1

stats = img.get_statistics()
# # Debug stats
# img.draw_string(10,10,"Mean:"+str(stats.mean()))
Expand Down
Loading

0 comments on commit 9b0b3de

Please sign in to comment.