Source code for helium_py.crypto.mnemonic

"""Mnemonic class for cryptography."""
from math import floor
from typing import Any, List, Tuple

from . import utils
from .wordlists.english import wordlist

ALLOWABLE_MNEMONIC_LENGTHS = (12, 24)


[docs]class Mnemonic: """Mnemonic class with conversion to/from entropy.""" words: List[str]
[docs] def __init__(self, words: List[str]): """Initialize Mnemonic class with list of words.""" self.words = words
[docs] @staticmethod def create(length: int = 12) -> 'Mnemonic': """Return a randomly generated Mnemonic of the provided length.""" if length not in ALLOWABLE_MNEMONIC_LENGTHS: raise ValueError(f'supported mnemonic lengths: 12, 24. received {length}') entropy_bytes = 16 if length == 12 else 32 entropy = utils.random_bytes(entropy_bytes) return Mnemonic.from_entropy(entropy)
[docs] @staticmethod def from_entropy(entropy: bytes) -> 'Mnemonic': """Return a Mnemonic generated from provided entropy.""" if len(entropy) < 16: raise ValueError('invalid entropy, less than 16') if len(entropy) > 32: raise ValueError('invalid entropy, greater than 32') if len(entropy) % 4 != 0: raise ValueError('invalid entropy, not divisible by 4') entropyBits = utils.bytes_to_binary(entropy) checksumBits = utils.derive_checksum_bits(entropy) bits = entropyBits + checksumBits chunks = [bits[x:x + 11] for x in range(0, len(bits), 11)] words = [wordlist[int(binary, 2)] for binary in chunks] return Mnemonic(words)
def _get_entropy_bits_and_checksum(self) -> Tuple[str, str]: bits = ''.join([ f'{bin(wordlist.index(word))}'.lstrip('0b').zfill(11) for word in self.words ]) # split the binary string into entropy and checksum dividerIndex = floor(len(bits) / 33) * 32 return (bits[0:dividerIndex], bits[dividerIndex:]) @staticmethod def _get_entropy_bytes(entropyBits) -> Tuple[List[Any], List[bytes]]: # calculate the checksum and compare chunks = [entropyBits[x:x + 8] for x in range(0, len(entropyBits), 8)] return (chunks, [int(entropy, 2).to_bytes((len(entropy) + 7) // 8, byteorder='big') for entropy in chunks])
[docs] def to_entropy(self) -> bytes: """Return entropy bytes generated from provided Mnemonic.""" entropyBits, checksumBits = self._get_entropy_bits_and_checksum() entropy_chunks, entropy_bytes = self._get_entropy_bytes(entropyBits) if len(entropy_bytes) < 16: raise ValueError('invalid entropy, less than 16') if len(entropy_bytes) > 32: raise ValueError('invalid entropy, greater than 32') if len(entropy_bytes) % 4 != 0: raise ValueError('invalid entropy, not divisible by 4') # calculate the checksum and compare entropy = bytes([int(byte_val, 2) for byte_val in entropy_chunks]) new_checksum = utils.derive_checksum_bits(entropy) if checksumBits != '0000' and new_checksum != checksumBits: raise ValueError('invalid checksum') return entropy