'''
# System --> Windows & Python3.8.0
# File ----> md5.py
# Author --> Illusionna
# Create --> 2024/04/29 17:55:49
'''
# -*- Encoding: UTF-8 -*-


import os
import math
import platform

def cls() -> None:
    os.system('')
    try:
        os.system(
            {'Windows': 'cls', 'Linux': 'clear'}[platform.system()]
        )
    except:
        print('\033[H\033[J', end='')
cls()

def MD5(input:bytes) -> str:
    """
    计算 md5 哈希散列值.

    输入: 字节流.

    输出: 32 位长度的十六进制字符串.
    """
    # -------------------------------------------------------------------------
    # 零比特填充.
    omega = list(map(lambda x: x, input))
    N = len(omega)
    K = (N - 56) // 64 + 1
    M = 64 * K + 55 - N
    omega.append(128)   # 往列表添加 10000000 比特流对应的整数 128.
    omega.extend([0 for __ in range(0, M, 1)])      # 建议使用列表推导式写法.
    # -------------------------------------------------------------------------
    # 有效信息比特流长度填充, 填充的数据与十进制 255 做 & 运算, 强制截断.
    omega.extend([(((N * 8) >> (8 * i)) & 0xff) for i in range(0, 8, 1)])
    # -------------------------------------------------------------------------
    # 初始化全局幻数.
    A = 0x67452301; B = 0xefcdab89; C = 0x98badcfe; D = 0x10325476
    # -------------------------------------------------------------------------
    # 定义辅助函数.
    F = lambda X, Y, Z:     (X & Y) | ((~X) & Z)
    G = lambda X, Y, Z:     (X & Z) | (Y & (~Z))
    H = lambda X, Y, Z:     X ^ Y ^ Z
    I = lambda X, Y, Z:     Y ^ (X | (~Z))
    L = lambda X, s:        ((X << s) | (X >> (32 - s))) & 0xffffffff
    T = lambda x:           int(abs(math.sin(x)) * (1 << 32))
    # -------------------------------------------------------------------------
    # 定义数学书法字体 H 函数和 32 比特流拼接函数.
    mathcalH = lambda q, w, e, r: (q << 0) | (w << 8) | (e << 16) | (r << 24)
    X = lambda k: mathcalH(omega[k], omega[k+1], omega[k+2], omega[k+3])    # 连续 4 字节.
    # -------------------------------------------------------------------------
    # 定义迭代结束输出后, 对换十六进制成为字符串函数.
    # swap = lambda x: (x << 24) & 0xff000000 | (x << 8) & 0x00ff0000 | (x >> 8) & 0x0000ff00 | (x >> 24) & 0x000000ff
    # -------------------------------------------------------------------------
    swap = lambda x: (x >> 24) & 0xff | ((x >> 16) & 0xff) << 8 | ((x >> 8) & 0xff) << 16 | (x & 0xff) << 24
    # -------------------------------------------------------------------------
    # 设定循环左移偏量.
    S = 4 * [7, 12, 17, 22] + 4 * [5, 9, 14, 20] + 4 * [4, 11, 16, 23] + 4 * [6, 10, 15, 21]
    # -------------------------------------------------------------------------
    # 加密迭代.
    for i in range(0, K+1, 1):
        AA = A; BB = B; CC = C; DD = D
        for j in range(0, 64, 1):
            aa = DD; bb = AA; cc = BB; dd = CC
            a = AA; b = BB; c = CC; d = DD
            if 0 <= j <= 15:
                k = i * 64 + j * 4
                tmp: int = (a + (F(b, c, d) & 0xffffffff) + X(k) + T(j+1)) & 0xffffffff
            elif 16 <= j <= 31:
                k = i * 64 + (((5 * j) + 1) % 16) * 4
                tmp: int = (a + (G(b, c, d) & 0xffffffff) + X(k) + T(j+1)) & 0xffffffff
            elif 32 <= j <= 47:
                k = i * 64 + (((3 * j) + 5) % 16) * 4
                tmp: int = (a + (H(b, c, d) & 0xffffffff) + X(k) + T(j+1)) & 0xffffffff
            else:
                k = i * 64 + ((7 * j) % 16) * 4
                tmp: int = (a + (I(b, c, d) & 0xffffffff) + X(k) + T(j+1)) & 0xffffffff
            bb = b + L(tmp, S[j])
            AA = aa; BB = bb; CC = cc; DD = dd
        A = (A + AA) & 0xffffffff; B = (B + BB) & 0xffffffff
        C = (C + CC) & 0xffffffff; D = (D + DD) & 0xffffffff
    digest = (swap(A) << 96) | (swap(B) << 64) | (swap(C) << 32) | swap(D)
    md5 = hex(digest)[2:].rjust(32, '0')
    return md5


if __name__ == '__main__':
    import hashlib
    INPUT = b'Ark'
    lib = hashlib.md5(INPUT).hexdigest()
    cus = MD5(INPUT)
    print(f"hashlib: \033[33m{lib}\033[0m")
    print(f"custom:  \033[32m{cus}\033[0m")