from hashlib import blake2b, shake_128, md5, sha256, sha1 import os from base64 import b64encode, b64decode, b85encode, b85decode import base32_lib as b32 DIGEST_SIZE_BYTES = 3 DIGEST_SIZE_BITMASK = 0xffffff DIGEST_SIZE_SIGNED_TO_UNSIGNED_BITMASK = 0x1ffffff DIGEST_SIZE_SIGNED_TO_UNSIGNED_BIT = 0x1000000 DIGEST_SIZE_NIBBLES = DIGEST_SIZE_BYTES * 2 B64ALTCHARS = b'.-' def sha1hash(data: str): return sha1(data.encode("utf-8"), usedforsecurity=False).hexdigest()[:DIGEST_SIZE_BYTES] def sha256hash(data: str): return sha256(data.encode("utf-8"), usedforsecurity=False).hexdigest()[:DIGEST_SIZE_BYTES] def md5hash(data: str): return md5(data.encode("utf-8"), usedforsecurity=False).hexdigest()[:DIGEST_SIZE_BYTES] def shake(data: str): return shake_128(data.encode("utf-8"), usedforsecurity=False).hexdigest(DIGEST_SIZE_BYTES) def blake(data: bytes, person: bytes = None) -> bytes: return blake2b( data, usedforsecurity=False, digest_size=DIGEST_SIZE_BYTES, person=person ).digest() def blake_file(path: str, person: bytes = None, root: str ='rest/static') -> bytes: fd = os.open(f'{root}/{path}', os.O_RDONLY, 0o600) with open(fd, "rb") as f: f.seek(0) _blake = blake2b(usedforsecurity=False, digest_size=DIGEST_SIZE_BYTES, person='upload'.encode('utf-8')) while f.peek(1): _blake.update(f.read(1024)) return _blake.digest() def python(data: str): return hash(data) def normalize_hash(_hash: int) -> int: #hex = hash_to_hex(_hash) #return int(hex, 16) #_bytes = _hash.to_bytes(8, byteorder='big', signed=True) #return bytes_to_hash(_bytes) return _hash & DIGEST_SIZE_BITMASK def normalize_bytes(_bytes: bytes) -> bytes: return (b'\x00' * DIGEST_SIZE_BYTES + _bytes)[-DIGEST_SIZE_BYTES:] def normalize_hex(_hex: str) -> str: #_bytes = hex_to_bytes(hex) #return _bytes.hex() return _hex.zfill(DIGEST_SIZE_NIBBLES)[-DIGEST_SIZE_NIBBLES:] def hex_to_bytes(_hex: str) -> bytes: _bytes = bytes.fromhex(_hex.zfill(DIGEST_SIZE_NIBBLES)) return normalize_bytes(_bytes) def bytes_to_hex(_bytes: bytes) -> str: return normalize_bytes(_bytes).hex() def hash_to_bytes(_hash: int) -> bytes: _bytes = _hash.to_bytes(8, byteorder='big', signed=True) return normalize_bytes(_bytes) def bytes_to_hash(_bytes: bytes) -> int: norm = normalize_bytes(_bytes) return int.from_bytes(norm, byteorder='big', signed=False) def hash_to_hex(_hash: int) -> str: #return hash_to_bytes(_hash).hex() #return normalize_hex( #return f"{_hash + (1 << 64):x}"[-4:] #return hex(_hash + (1<<64))[2:][-4:] #return f"{_hash & 0xffff:04x}" return hex((_hash|DIGEST_SIZE_SIGNED_TO_UNSIGNED_BIT) & DIGEST_SIZE_SIGNED_TO_UNSIGNED_BITMASK)[3:] def hex_to_hash(_hex: str) -> int: #_bytes = bytes.fromhex(hex.zfill(4)) #return bytes_to_hash(_bytes) #return int(normalize_hex(hex), 16) return int(_hex, 16) & DIGEST_SIZE_BITMASK def remove_padding(f): def wrap(*args, **kwargs): return f(*args, **kwargs).split('=')[0] return wrap def fix_padding(f): def wrap(_b64, *args, **kwargs): pad = (4 - len(_b64)) % 4 fixed = _b64 + '='*pad return f(fixed, *args, **kwargs) return wrap def normalize_base32(_b32: str): return _b32.upper().zfill(DIGEST_SIZE_BYTES*8//5+1) def add_padding_base32(f): def wrap(*args, **kwargs): return normalize_base32(f(*args, **kwargs)) return wrap @remove_padding def hash_to_base64(_hash: int) -> str: return b64encode(hash_to_bytes(_hash), altchars=B64ALTCHARS).decode("utf-8") @remove_padding def hex_to_base64(_hex: str) -> str: return b64encode(hex_to_bytes(_hex), altchars=B64ALTCHARS).decode("utf-8") @remove_padding def bytes_to_base64(_bytes: str) -> str: return b64encode(normalize_bytes(_bytes), altchars=B64ALTCHARS).decode("utf-8") @fix_padding def base64_to_hash(_b64: str) -> str: return bytes_to_hash(b64decode(_b64, altchars=B64ALTCHARS)) @fix_padding def base64_to_hex(_b64: str) -> str: return bytes_to_hex(b64decode(_b64, altchars=B64ALTCHARS)) @fix_padding def base64_to_bytes(_b64: str) -> str: return normalize_bytes(b64decode(_b64, altchars=B64ALTCHARS)) #@remove_padding def hash_to_base85(_hash: int) -> str: return b85encode(hash_to_bytes(_hash)).decode("utf-8") #@remove_padding def hex_to_base85(_hex: str) -> str: return b85encode(hex_to_bytes(_hex)).decode("utf-8") #@remove_padding def bytes_to_base85(_bytes: str) -> str: return b85encode(normalize_bytes(_bytes)).decode("utf-8") #@fix_padding def base85_to_hash(_b64: str) -> str: return bytes_to_hash(b85decode(_b64)) #@fix_padding def base85_to_hex(_b64: str) -> str: return bytes_to_hex(b85decode(_b64)) #@fix_padding def base85_to_bytes(_b64: str) -> str: return normalize_bytes(b85decode(_b64)) @add_padding_base32 def hash_to_base32(_hash: int) -> str: return b32.encode(_hash & DIGEST_SIZE_BITMASK) @add_padding_base32 def hex_to_base32(_hex: str) -> str: return b32.encode(hex_to_hash(_hex)) @add_padding_base32 def bytes_to_base32(_bytes: bytes) -> str: return b32.encode(bytes_to_hash(_bytes)) #@fix_padding def base32_to_hash(_b64: str) -> str: return b32.decode(_b64) #@fix_padding def base32_to_hex(_b64: str) -> str: return hash_to_hex(base32_to_hash(_b64)) #@fix_padding def base32_to_bytes(_b64: str) -> str: return hash_to_bytes(base32_to_hash(_b64))