# 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
-
-}