# begin mtve
sub md5_hex
{
    my ($str) = @_;

    my @Y = (0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476);
    my @T = map int 2**32 * abs sin, 1..64;
    my @U = (7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21);
    my $L = length $str;
    $str .=  pack 'Bx'.(63 & 55 - $L).'VV', 1, 8 * $L;

    $str =~ s!(\C{64})!
        my @V = unpack 'V16', $1;
        my @Z = @Y;
        for my $K (0..3) {
            my $I = (0, 1, 5, 0)[$K];
            for (0..15) {
                my ($C, $D, $A, $B) = @Z = @Z[-1..2];
                my $N = $U[$K * 4 + $_ % 4];
                $D = ($D
                    +   ( $A & $B | ~$A & $C
                        , $A & $C | $B & ~$C
                        , $A ^ $B ^ $C
                        , $A | ~$C ^ $B
                        )[$K]
                    + $V[$I & 15]
                    + $T[$K * 16 + $_]
                ) % 2**32;
                $Z[1] = ($A + ($D << $N | $D >> 32 - $N)) % 2**32;
                $I += (1, 5, 3, 7)[$K];
            }
        }
        $Y[$_] = ($Y[$_] + $Z[$_]) % 2**32
            for 0..3;
    !eg;
    return unpack 'H64', pack 'V4', @Y;
}
# end mtve
