ハッシュ値を圧縮すればもっと短くできる?→長くなった


時間がない方に向けて結論

ハッシュ文字列をzip圧縮すると、長くなります。
SHA256の場合:元256bit=64文字=32byte → 137byte(428%増)
SHA3_512の場合:元512bit=128文字=64byte → 169byte(264%増)

当たり前だろという声も聞こえる気がします。
恥を忍んでソースはこちら
https://github.com/yo16/compress_str

はじめに思ったこと

ハッシュ化して256bitなり512bitなりになった後の16進数の文字列を見ると、異常に長く感じますよね?長いですわ。例えばSHA256でも661b976821ad4a7545054a2e45367e3af53522477d39b28fdca26b36fed95f8b1a2005e3188b682a74f9e772aa3cb7201fcb6d01ce6cb2cdf720690fd26d5bb1eになって64文字。512だと倍。これをDBへ格納して、なんなら表示したりとか気が知れない。

だけどそもそも16進数、つまり読み直せば2進数、バイナリですよね。上のも、011110000101001010111000010101011....(さすがに略.16進数の4倍みたいに0/1の値。こうやって表現すると、これってコンピューターの中のバイナリファイルだなーと思いました。

そしたらそのバイナリファイルを圧縮すれば小さくなるんだから、圧縮結果をもう一度2進数にして、16進数にすれば、短い文字列ができるんじゃないか・・・?

実験

1. 文字列をハッシュ化する関数

記事の本筋ではないので超絶割愛。知りたければGitHubのソースを見てください。

hashing.py
# キモのところ
import hashlib
h = hashlib.sha256(s).hexdigest()

2. zip圧縮

ハッシュ化した文字列をバイナリ化して、zip化して、文字列化(16進数)する。
難しいことはないのだけれど、普段、バイナリの操作はあまりやらないので試行錯誤。

compress_str.py
def do_compress(str_hex:str)->str:
    """文字列の16進数をバイナリ値にそのまま変換し、zip圧縮して返す

    Args:
        str_hex (str): 16進数の文字列(先頭にbはない)

    Returns:
        str: zip圧縮したバイナリ値を16進数にした文字列
    """
    # 16進数文字列をそのままバイナリ化
    b = bytes.fromhex(str_hex)
    
    # バイナリをzip化
    zip_stream = io.BytesIO()
    with zipfile.ZipFile(zip_stream, 'w', compression=zipfile.ZIP_DEFLATED) as new_zip:
        new_zip.writestr('_', b)
    
    # zipしたバイナリ値をそのまま取得
    h = zip_stream.getvalue()

    # 16進数にして返す
    return h.hex()

3. 評価

実行するところとその結果。

compress_str.pyのメイン
test_str = 'test123'
#ret = do_hashing(test_str, ret_type='Hex', hash_method='SHA256')
ret = do_hashing(test_str, ret_type='Hex', hash_method='SHA3_512')
print(ret)
print(f'{len(ret)/2} bytes')        # 16進数1文字=4bit=0.5byte
# >>> 64.0 bytes

ret2 = do_compress(ret)
print(ret2)
print(f'{len(ret2)/2} bytes')
# >>> 169.0 bytes

最初に書いた通り、

  • SHA256の場合
    • 元256bit = 64文字 = 32byte
    • → Zip → 137byte(428%増)
  • SHA3_512の場合
    • 元512bit = 128文字 = 64byte
    • → Zip → 169byte(264%増)

ZIP圧縮方法変更してもっと圧縮するとかは、もうそういうレベルではないのでやってません。

あとがき

残念でしたが、思いついたことがダメだとすぐ判明してスッキリしました。コーディングできる人でよかった。(間違ってなければ)