# New Ticket Created by Nick Glencross # Please include the string: [perl #36052] # in the subject line of all future correspondence about this issue. # <URL: https://rt.perl.org/rt3/Ticket/Display.html?id=36052 >
I've finally got access to a big endian platform, and have made the changes required to get correct checksums from the MD5 library. All (MD5) tests pass, and are no longer skip on certain platforms. [All being well, I should have a version can can do incremental hashes RSN!] Regards, Nick p.s. A fair number of libraries have renamed .imc to .pir. I'd be grateful if someone would do the same for me. It should just be a case of 'svn rename' on the library file, a corresponding change in the MANIFEST, and a replacement of .imc with .pir (or should .pbc be better?) in t/library/md5.t
Index: runtime/parrot/library/Digest/MD5.imc =================================================================== --- runtime/parrot/library/Digest/MD5.imc (revision 8230) +++ runtime/parrot/library/Digest/MD5.imc (working copy) @@ -6,7 +6,7 @@ =head1 NAME -MD5.imc - calculate MD5 checksums +MD5.imc - calculates MD5 checksums =head1 SYNOPSIS @@ -41,55 +41,25 @@ =head1 BUGS -This section provides a list of bugs. +Still has some limitations on input buffer size, largely due to memory +consumption which should be resolved soon. -=over 4 - -=item * - -By all accounts, doesn't seem to work on big endian systems, but I -don't have access to investigate. - -=item * - -There is some scope to optimise things a little further, perhaps removing -some of the 'and's (for 64-bit) which may be superflouous. - -=back - =cut ########################################################################### # Export function entries to globals .sub onload @LOAD - .local pmc endian - endian = new Integer - endian = 0 - $P0 = _config() - - $I0 = $P0["bigendian"] - unless $I0 goto is_little_endian - endian = 1 - printerr "This appears to be a big endian processor: " - printerr "Please verify the MD5 checksum\n" - -is_little_endian: - - store_global "Digest", "_md5_swap_endian", endian - .local pmc f f = find_global "Digest", "_md5sum" - global "_md5sum" = f + global "_md5sum" = f f = find_global "Digest", "_md5_hex" - global "_md5_hex" = f + global "_md5_hex" = f f = find_global "Digest", "_md5_print" global "_md5_print" = f .end -.include "library/config.imc" - ########################################################################### # Main backend entry point @@ -98,85 +68,73 @@ .sub _md5sum .param string str - .local pmc buffer, context - buffer = new FixedIntegerArray - + .local pmc context context = new FixedIntegerArray context = 4 - $P0 = find_global "Digest", "_md5_swap_endian" - $I0 = $P0 - _md5_create_buffer (str, buffer, $I0) + .local pmc buffer + buffer = _md5_create_buffer (str) _md5_init (context) _md5_process_buffer (context, buffer) - .return(context) - + .return (context) .end ########################################################################### # Low-level macros used in MD5 -# A parrot rol instruction might be good (as it can often be JIT'd) -.macro rol (x,n, out) - #.out = .x << .n - #tmp2 = 32 - .n - #tmp2 = .x >>> tmp2 - #.out |= tmp2 - rot .out, .x, .n, 32 -.endm - .macro FF (b,c,d) - tmp1 = .c ~ .d - tmp1 &= .b - tmp1 ~= .d + tmp = .c ~ .d + tmp &= .b + tmp ~= .d .endm .macro FH (b,c,d) - tmp1 = .b ~ .c - tmp1 ~= .d + tmp = .b ~ .c + tmp ~= .d .endm .macro FI (b,c,d) - tmp1 = ~.d - tmp1 |= .b - tmp1 ~= .c + tmp = ~.d + tmp |= .b + tmp ~= .c .endm ########################################################################### # Higher level MD5 operations .macro common (a, b, k, s, T) - .a += tmp1 + .a += tmp .a += .T - tmp2 = .k + idx - tmp1 = buffer[tmp2] - .a += tmp1 + tmp = .k + idx + tmp = buffer[tmp] + .a += tmp .a &= 0xffffffff - .rol (.a, .s, tmp1) - .a = .b + tmp1 + tmp = rot .a, .s, 32 + .a = .b + tmp .a &= 0xffffffff .endm + .macro OP1 (aa,bb,cc,dd, kk, ss, TT) - .FF (.bb,.cc,.dd) + .FF (.bb,.cc,.dd) .common (.aa, .bb, .kk, .ss, .TT) .endm .macro OP2 (aa,bb,cc,dd, kk, ss, TT) - .FF (.dd,.bb,.cc) + .FF (.dd,.bb,.cc) .common (.aa, .bb, .kk, .ss, .TT) .endm .macro OP3 (aa,bb,cc,dd, kk, ss, TT) - .FH (.bb,.cc,.dd) + .FH (.bb,.cc,.dd) .common (.aa, .bb, .kk, .ss, .TT) .endm .macro OP4 (aa,bb,cc,dd, kk, ss, TT) - .FI (.bb,.cc,.dd) + .FI (.bb,.cc,.dd) .common (.aa, .bb, .kk, .ss, .TT) .endm @@ -197,11 +155,10 @@ $I10 |= $I11 $I10 |= $I12 - .w = $I10 | $I13 + $I10 |= $I13 # For 64-bit architectures - .w &= 0xffffffff - + .w = $I10 & 0xffffffff .endm ########################################################################### @@ -224,9 +181,10 @@ .sub _md5_create_buffer .param string str - .param pmc buffer - .param int endian + .local pmc buffer + buffer = new FixedIntegerArray + .local int counter .local int subcounter .local int slow_counter @@ -239,7 +197,7 @@ # Work out how many words to allocate .local int words - words = len + 8 + words = len + 8 words |= 63 inc words words /= 4 @@ -251,11 +209,11 @@ subcounter = 0 slow_counter = 0 -md5_create_buffer_loop: +create_buffer_loop: $I5 = counter + subcounter - if $I5 > len goto md5_create_buffer_break + if $I5 > len goto create_buffer_break # MD5 pad character, which goes last $I4 = 0x80 @@ -266,37 +224,32 @@ string_char: word <<= 8 - word |= $I4 + word |= $I4 inc subcounter - if subcounter != 4 goto md5_create_buffer_loop + if subcounter != 4 goto create_buffer_loop - if endian goto endian_ok1 .swap (word) -endian_ok1: buffer[slow_counter] = word - word = 0 - counter += 4 - subcounter = 0 + word = 0 + counter += 4 + subcounter = 0 inc slow_counter - goto md5_create_buffer_loop + goto create_buffer_loop -md5_create_buffer_break: +create_buffer_break: # Check for a partial word if subcounter == 0 goto complete subcounter = 4 - subcounter - .local int shift - shift = 8*subcounter - word <<= shift + $I0 = 8*subcounter + word <<= $I0 - if endian goto endian_ok2 .swap (word) -endian_ok2: buffer[slow_counter] = word @@ -304,14 +257,16 @@ # The number of bits in the string go into the last two words - $I1 = len >>> 29 + $I0 = len >>> 29 dec words - buffer[words] = $I1 + buffer[words] = $I0 $I0 = len << 3 dec words buffer[words] = $I0 + .return (buffer) + .end ########################################################################### @@ -323,7 +278,7 @@ .local int A, B, C, D .local int A_save, B_save, C_save, D_save - .local int tmp1, tmp2, idx, len + .local int tmp, idx, len idx = 0 len = elements buffer @@ -333,7 +288,7 @@ C = context[2] D = context[3] -md5_loop: +loop: A_save = A B_save = B @@ -419,7 +374,7 @@ idx += 16 - if idx < len goto md5_loop + if idx < len goto loop context[0] = A context[1] = B @@ -446,8 +401,8 @@ $P0[2] = C $P0[3] = D - sprintf $S0, "%08lx%08lx%08lx%08lx", $P0 - .return($S0) + $S0 = sprintf "%08lx%08lx%08lx%08lx", $P0 + .return ($S0) .end ########################################################################### @@ -464,80 +419,22 @@ C = context[2] D = context[3] - $P0 = find_global "Digest", "_md5_swap_endian" - if $P0 goto dont_swap - .swap (A) .swap (B) .swap (C) .swap (D) -dont_swap: - $S0 = _md5_format_vals (A,B,C,D) - .return($S0) + .return ($S0) .end -# Convenience subroutine to print the MD5 string +# Convenience subroutine to print the MD5 hash for a string .sub _md5_print .param pmc context $S0 = _md5_hex (context) print $S0 -.end -########################################################################### - -# For debugging - -.sub _md5_print_buffer - .param pmc buffer - .param int word_size - - .local int size - - size = buffer - - .local int counter - .local int value - - counter = 0 - -print_buffer_loop: - if counter >= size goto print_buffer_done - value = buffer[counter] - $S0 = _md5_number_as_hex (value, word_size) - print $S0 - print " | " - counter = counter + 1 - goto print_buffer_loop - -print_buffer_done: - - print "\n" - + .return ($S0) .end - -########################################################################### - -# Also for debugging - -.sub _md5_number_as_hex - .param int number - .param int word_size - - $P0 = new FixedIntegerArray - $P0 = 1 - $P0[0] = number - - $S1 = "%0" - $S0 = word_size - concat $S1, $S0 - concat $S1, "lx" - - sprintf $S0, $S1, $P0 - - .return($S0) - -.end Index: t/library/md5.t =================================================================== --- t/library/md5.t (revision 8230) +++ t/library/md5.t (working copy) @@ -12,20 +12,9 @@ use strict; use Parrot::Test tests => 6; -use Parrot::Config; -my $bigendian = $PConfig{bigendian}; - -SKIP: { - -if ($bigendian) -{ - skip('MD5 only known to work on little endian bit processors', 6) -} - - ############################## -# Stress IMCC and parrot using MD5 library +# Stress parrot using MD5 library pir_output_is(<<'CODE', <<'OUT', "Miscellaneous words"); .sub _main @@ -808,5 +797,3 @@ 8408bf5f0144309374e66278bec290b2 982e0fde28cd2f62ef8db2d8dfd0f0d7 OUT - -}