#!perl -wl

# Computes the hash of the empty string with various hash algorithms, outputting the values in decimal and hexadecimal

# Copyright 2026 Ken Takusagawa

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

use Digest::SHA;
use Digest::MD5;
use bigint;
$message=shift;
$message=""unless defined$message;
print"message ($message)";
# 1533 is useful for testing sha-512 because it starts with zeroes
#message="1533";
for$alg((0, 1, 224, 256, 384, 512, 512224, 512256)){
    if(0==$alg){
        $func=Digest::MD5->new;
        $salg='MD5';
    }else{
        $func=Digest::SHA->new($alg);
        if($alg=~/^512(...)/){
            $salg="SHA-512/$1";
        }else{
            $salg="SHA-$alg";
        }
    }
    $func->add($message);
    #need to clone because digest (and hexdigist) are read-once-only, destroying state after read.  we need to read twice to compare unpack vs hexdigest.
    $h=$func->clone->digest;
    #$h="\x01\x02";
    @a=unpack("H*",$h);
    print"$salg hexadecimal ",$a[0];
    die unless$a[0]eq$func->hexdigest;

    @a=unpack("C*",$h);
    $s=0;for(@a){$s*=2**8;$s+=$_;}
    print"$salg big-endian to decimal $s";
    $bigendian=$s;
    $s=0;for(reverse@a){$s*=2**8;$s+=$_;}
    print"$salg little-endian by bytes to decimal $s";

    @a=unpack("B*",$h);
    # B returns just a string of binary
    die unless@a==1;
    @a=split'',$a[0];
    #print scalar@a;
    $s=0;for(@a){$s*=2**1;$s+=$_;}
    die unless$s==$bigendian;
    $s=0;for(reverse@a){$s*=2**1;$s+=$_;}
    print"$salg little-endian by bits to decimal $s";
}
# other word size and endianness options for the pack template (see perldoc -f pack)
# h 4 bits, little endian
# H 4 big
# S< or v 16 little
# S> or n 16 big
# L< or V 32 little
# L> or N 32 big
# Q< 64 little
# Q> 64 big
