File: utils.py

package info (click to toggle)
python-shamir-mnemonic 0.3.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 244 kB
  • sloc: python: 1,173; makefile: 34
file content (41 lines) | stat: -rw-r--r-- 1,570 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from typing import Iterable


class MnemonicError(Exception):
    pass


def _round_bits(n: int, radix_bits: int) -> int:
    """Get the number of `radix_bits`-sized digits required to store a `n`-bit value."""
    return (n + radix_bits - 1) // radix_bits


def bits_to_bytes(n: int) -> int:
    """Round up bit count to whole bytes."""
    return _round_bits(n, 8)


def bits_to_words(n: int) -> int:
    """Round up bit count to a multiple of word size."""
    # XXX
    # In order to properly functionally decompose the original 1-file implementation,
    # function bits_to_words can only exist if it knows the value of RADIX_BITS (which
    # informs us of the word size). However, constants.py make use of the function,
    # because some constants count word-size of things.
    #
    # I considered the "least evil" solution to define bits_to_words in utils where it
    # logically belongs, and import constants only inside the function. This will work
    # as long as calls to bits_to_words only happens *after* RADIX_BITS are declared.
    #
    # An alternative is to have a private implementation of bits_to_words in constants
    from . import constants

    assert hasattr(constants, "RADIX_BITS"), "Declare RADIX_BITS *before* calling this"

    return _round_bits(n, constants.RADIX_BITS)


def int_to_indices(value: int, length: int, radix_bits: int) -> Iterable[int]:
    """Convert an integer value to indices in big endian order."""
    mask = (1 << radix_bits) - 1
    return ((value >> (i * radix_bits)) & mask for i in reversed(range(length)))