mirror of
https://github.com/SeedSigner/seedsigner.git
synced 2026-10-05 15:08:25 +00:00
198 lines
8.5 KiB
Python
198 lines
8.5 KiB
Python
import pytest
|
|
import random
|
|
|
|
from embit import bip39
|
|
from seedsigner.helpers import mnemonic_generation
|
|
from seedsigner.models.settings_definition import SettingsConstants
|
|
|
|
|
|
|
|
def test_dice_rolls():
|
|
""" Given random dice rolls, the resulting mnemonic should be valid. """
|
|
dice_rolls = ""
|
|
for i in range(0, 99):
|
|
# Do not need truly rigorous random for this test
|
|
dice_rolls += str(random.randint(1, 6))
|
|
|
|
mnemonic = mnemonic_generation.generate_mnemonic_from_dice(dice_rolls)
|
|
|
|
assert len(mnemonic) == 24
|
|
assert bip39.mnemonic_is_valid(" ".join(mnemonic))
|
|
|
|
dice_rolls = ""
|
|
for i in range(0, mnemonic_generation.DICE__NUM_ROLLS__12WORD):
|
|
# Do not need truly rigorous random for this test
|
|
dice_rolls += str(random.randint(1, 6))
|
|
|
|
mnemonic = mnemonic_generation.generate_mnemonic_from_dice(dice_rolls)
|
|
assert len(mnemonic) == 12
|
|
assert bip39.mnemonic_is_valid(" ".join(mnemonic))
|
|
|
|
|
|
|
|
def test_calculate_checksum_input_type():
|
|
"""
|
|
Given an 11-word or 23-word mnemonic, the calculated checksum should yield a
|
|
valid complete mnemonic.
|
|
|
|
calculate_checksum should accept the mnemonic as:
|
|
* a list of strings
|
|
* string: "A B C", "A, B, C", "A,B,C"
|
|
"""
|
|
# Test mnemonics from https://iancoleman.io/bip39/
|
|
def _try_all_input_formats(partial_mnemonic: str):
|
|
# List of strings
|
|
mnemonic = mnemonic_generation.calculate_checksum(partial_mnemonic.split(" "))
|
|
assert bip39.mnemonic_is_valid(" ".join(mnemonic))
|
|
|
|
# Comma-separated string
|
|
mnemonic = mnemonic_generation.calculate_checksum(partial_mnemonic.replace(" ", ","))
|
|
assert bip39.mnemonic_is_valid(" ".join(mnemonic))
|
|
|
|
# Comma-separated string w/space
|
|
mnemonic = mnemonic_generation.calculate_checksum(partial_mnemonic.replace(" ", ", "))
|
|
assert bip39.mnemonic_is_valid(" ".join(mnemonic))
|
|
|
|
# Space-separated string
|
|
mnemonic = mnemonic_generation.calculate_checksum(partial_mnemonic)
|
|
assert bip39.mnemonic_is_valid(" ".join(mnemonic))
|
|
|
|
partial_mnemonic = "crawl focus rescue cable view pledge rather dinner cousin unfair day"
|
|
_try_all_input_formats(partial_mnemonic)
|
|
|
|
partial_mnemonic = "bubble father debate ankle injury fence mesh evolve section wet coyote violin pyramid flower rent arrow round clutch myth safe base skin mobile"
|
|
_try_all_input_formats(partial_mnemonic)
|
|
|
|
|
|
|
|
|
|
def test_calculate_checksum_invalid_mnemonics():
|
|
"""
|
|
Should raise an Exception on a mnemonic that is invalid due to length or using invalid words.
|
|
"""
|
|
with pytest.raises(Exception) as e:
|
|
# Mnemonic is too short: 10 words instead of 11
|
|
partial_mnemonic = "abandon " * 9 + "about"
|
|
mnemonic_generation.calculate_checksum(partial_mnemonic)
|
|
assert "12- or 24-word" in str(e)
|
|
|
|
with pytest.raises(Exception) as e:
|
|
# Valid mnemonic but unsupported length
|
|
mnemonic = "devote myth base logic dust horse nut collect buddy element eyebrow visit empty dress jungle"
|
|
mnemonic_generation.calculate_checksum(mnemonic)
|
|
assert "12- or 24-word" in str(e)
|
|
|
|
with pytest.raises(Exception) as e:
|
|
# Mnemonic is too short: 22 words instead of 23
|
|
partial_mnemonic = "abandon " * 21 + "about"
|
|
mnemonic_generation.calculate_checksum(partial_mnemonic)
|
|
assert "12- or 24-word" in str(e)
|
|
|
|
with pytest.raises(ValueError) as e:
|
|
# Invalid BIP-39 word
|
|
partial_mnemonic = "foobar " * 11 + "about"
|
|
mnemonic_generation.calculate_checksum(partial_mnemonic)
|
|
assert "not in the dictionary" in str(e)
|
|
|
|
|
|
|
|
def test_calculate_checksum_with_default_final_word():
|
|
""" 11-word and 23-word mnemonics use word `0000` as a temp final word to complete
|
|
the mnemonic.
|
|
"""
|
|
partial_mnemonic = "crawl focus rescue cable view pledge rather dinner cousin unfair day"
|
|
mnemonic1 = mnemonic_generation.calculate_checksum(partial_mnemonic)
|
|
|
|
partial_mnemonic += " abandon"
|
|
mnemonic2 = mnemonic_generation.calculate_checksum(partial_mnemonic)
|
|
assert mnemonic1 == mnemonic2
|
|
|
|
partial_mnemonic = "bubble father debate ankle injury fence mesh evolve section wet coyote violin pyramid flower rent arrow round clutch myth safe base skin mobile"
|
|
mnemonic1 = mnemonic_generation.calculate_checksum(partial_mnemonic)
|
|
|
|
partial_mnemonic += " abandon"
|
|
mnemonic2 = mnemonic_generation.calculate_checksum(partial_mnemonic)
|
|
assert mnemonic1 == mnemonic2
|
|
|
|
|
|
def test_generate_mnemonic_from_bytes():
|
|
"""
|
|
Should generate a valid BIP-39 mnemonic from entropy bytes
|
|
"""
|
|
# From iancoleman.io
|
|
entropy = "3350f6ac9eeb07d2c6209932808aa7f6"
|
|
expected_mnemonic = "crew marble private differ race truly blush basket crater affair prepare unique".split()
|
|
mnemonic = mnemonic_generation.generate_mnemonic_from_bytes(bytes.fromhex(entropy))
|
|
assert mnemonic == expected_mnemonic
|
|
|
|
entropy = "5bf41629fce815c3570955e8f45422abd7e2234141bd4d7ec63b741043b98cad"
|
|
expected_mnemonic = "fossil pass media what life ticket found click trophy pencil anger fish lawsuit balance agree dash estate wage mom trial aerobic system crawl review".split()
|
|
mnemonic = mnemonic_generation.generate_mnemonic_from_bytes(bytes.fromhex(entropy))
|
|
assert mnemonic == expected_mnemonic
|
|
|
|
|
|
|
|
def test_verify_against_coldcard_sample():
|
|
""" https://coldcard.com/docs/verifying-dice-roll-math """
|
|
dice_rolls = "123456"
|
|
expected = "mirror reject rookie talk pudding throw happy era myth already payment own sentence push head sting video explain letter bomb casual hotel rather garment"
|
|
|
|
mnemonic = mnemonic_generation.generate_mnemonic_from_dice(dice_rolls)
|
|
actual = " ".join(mnemonic)
|
|
assert bip39.mnemonic_is_valid(actual)
|
|
assert actual == expected
|
|
|
|
|
|
|
|
def test_known_dice_rolls():
|
|
""" Given 99 known dice rolls, the resulting mnemonic should be valid and match the expected. """
|
|
dice_rolls = "522222222222222222222222222222222222222222222555555555555555555555555555555555555555555555555555555"
|
|
expected = "resource timber firm banner horror pupil frozen main pear direct pioneer broken grid core insane begin sister pony end debate task silk empty curious"
|
|
|
|
mnemonic = mnemonic_generation.generate_mnemonic_from_dice(dice_rolls)
|
|
actual = " ".join(mnemonic)
|
|
assert bip39.mnemonic_is_valid(actual)
|
|
assert actual == expected
|
|
|
|
dice_rolls = "222222222222222222222222222222222222222222222555555555555555555555555555555555555555555555555555555"
|
|
expected = "garden uphold level clog sword globe armor issue two cute scorpion improve verb artwork blind tail raw butter combine move produce foil feature wave"
|
|
|
|
mnemonic = mnemonic_generation.generate_mnemonic_from_dice(dice_rolls)
|
|
actual = " ".join(mnemonic)
|
|
assert bip39.mnemonic_is_valid(actual)
|
|
assert actual == expected
|
|
|
|
dice_rolls = "222222222222222222222222222222222222222222222555555555555555555555555555555555555555555555555555556"
|
|
expected = "lizard broken love tired depend eyebrow excess lonely advance father various cram ignore panic feed plunge miss regret boring unique galaxy fan detail fly"
|
|
|
|
mnemonic = mnemonic_generation.generate_mnemonic_from_dice(dice_rolls)
|
|
actual = " ".join(mnemonic)
|
|
assert bip39.mnemonic_is_valid(actual)
|
|
assert actual == expected
|
|
|
|
|
|
|
|
def test_50_dice_rolls():
|
|
""" 50 dice roll input should yield the same 12-word mnemonic as iancoleman.io/bip39 """
|
|
# Check "Show entropy details", paste in dice_rolls sequence, click "Hex", select "Mnemonic Length" as "12 Words"
|
|
dice_rolls = "12345612345612345612345612345612345612345612345612"
|
|
expected = "unveil nice picture region tragic fault cream strike tourist control recipe tourist"
|
|
mnemonic = mnemonic_generation.generate_mnemonic_from_dice(dice_rolls)
|
|
actual = " ".join(mnemonic)
|
|
assert bip39.mnemonic_is_valid(actual)
|
|
assert actual == expected
|
|
|
|
dice_rolls = "11111111111111111111111111111111111111111111111111"
|
|
expected = "diet glad hat rural panther lawsuit act drop gallery urge where fit"
|
|
mnemonic = mnemonic_generation.generate_mnemonic_from_dice(dice_rolls)
|
|
actual = " ".join(mnemonic)
|
|
assert bip39.mnemonic_is_valid(actual)
|
|
assert actual == expected
|
|
|
|
dice_rolls = "66666666666666666666666666666666666666666666666666"
|
|
expected = "senior morning song proud recycle toy search apple trigger lend vibrant arrest"
|
|
mnemonic = mnemonic_generation.generate_mnemonic_from_dice(dice_rolls)
|
|
actual = " ".join(mnemonic)
|
|
assert bip39.mnemonic_is_valid(actual)
|
|
assert actual == expected
|