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
|