File: misc.py

package info (click to toggle)
python-ledger-bitcoin 0.4.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 720 kB
  • sloc: python: 9,357; makefile: 2
file content (70 lines) | stat: -rw-r--r-- 1,763 bytes parent folder | download
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
"""Misc utility functions used across embit"""
import sys

# implementation-specific functions and libraries:
if sys.implementation.name == "micropython":
    from micropython import const
    import secp256k1
else:
    from .util import secp256k1

    def const(x):
        return x


try:
    # if urandom is available from os module:
    from os import urandom as urandom
except ImportError:
    # otherwise - try reading from /dev/urandom
    def urandom(n: int) -> bytes:
        with open("/dev/urandom", "rb") as f:
            return f.read(n)


def getrandbits(k: int) -> int:
    b = urandom(k // 8 + 1)
    return int.from_bytes(b, "big") % (2**k)


def secure_randint(vmin: int, vmax: int) -> int:
    """
    Normal random.randint uses PRNG that is not suitable
    for cryptographic applications.
    This one uses os.urandom for randomness.
    """
    import math

    assert vmax > vmin
    delta = vmax - vmin
    nbits = math.ceil(math.log2(delta + 1))
    randn = getrandbits(nbits)
    while randn > delta:
        randn = getrandbits(nbits)
    return vmin + randn


def copy(a: bytes) -> bytes:
    """Ugly copy that works everywhere incl micropython"""
    if len(a) == 0:
        return b""
    return a[:1] + a[1:]


def read_until(s, chars=b",)(#"):
    """Read from stream until one of `char` characters.
    By default `chars=,)(#`.

    Return a tuple (result: bytes, char: bytes | None)
    where result is bytes read from the stream until char,
    char contains this character or None if the end of stream reached.
    """
    res = b""
    chunk = b""
    while True:
        chunk = s.read(1)
        if len(chunk) == 0:
            return res, None
        if chunk in chars:
            return res, chunk
        res += chunk