The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Changes 015
MANIFEST 11
META.yml 22
README 22
lib/Digest/SHA/PurePerl.pm 107137
shasum 2947
t/dumpload.t 1020
t/gglong.t 7216
t/hmacsha.t 33
t/ireland.t 1011
t/podcover.t 20
t/state.t 094
12 files changed (This is a version diff) 330328
@@ -1,5 +1,20 @@
 Revision history for Perl module Digest::SHA::PurePerl.
 
+5.88  Mon Mar 17 08:46:10 MST 2014
+	- changed text file test (-T) to act on filehandles
+		-- ref. addfile portable mode
+		-- improves consistency when reading from STDIN
+		-- still acts on filenames for early Perls (< 5.6)
+	- added -M and -V options to shasum
+		-- undocumented: for development and testing use only
+
+5.87  Mon Feb 17 16:42:02 MST 2014
+	- simplified capture of intermediate SHA states
+		-- can now be done via strings (ref. getstate/putstate)
+
+5.86  Thu Jan 30 08:24:28 MST 2014
+	- changes only to Digest::SHA for version 5.86
+
 5.85  Wed Jun 26 04:05:26 MST 2013
 	- corrected typos in shasum script
 		-- ref. Bug #85430 (posted at Digest::SHA)
@@ -9,7 +9,6 @@ lib/Digest/SHA/PurePerl.pm
 t/allfcns.t
 t/base64.t
 t/bitbuf.t
-t/dumpload.t
 t/fips180-4.t
 t/fips198.t
 t/gg.t
@@ -27,5 +26,6 @@ t/sha224.t
 t/sha256.t
 t/sha384.t
 t/sha512.t
+t/state.t
 t/unicode.t
 t/woodbury.t
@@ -1,6 +1,6 @@
 --- #YAML:1.0
 name: Digest-SHA-PurePerl
-version: 5.85
+version: 5.88
 abstract: Perl implementation of SHA-1/224/256/384/512
 license: perl
 author:
@@ -11,7 +11,7 @@ requires:
 provides:
   Digest::SHA::PurePerl:
     file: lib/Digest/SHA/PurePerl.pm
-    version: 5.85
+    version: 5.88
 meta-spec:
   version: 1.3
   url: http://module-build.sourceforge.net/META-spec-v1.3.html
@@ -1,4 +1,4 @@
-Digest::SHA::PurePerl version 5.85
+Digest::SHA::PurePerl version 5.88
 ==================================
 
 Digest::SHA::PurePerl is a complete implementation of the NIST
@@ -29,7 +29,7 @@ DEPENDENCIES
 
 COPYRIGHT AND LICENSE
 
-Copyright (C) 2003-2013 Mark Shelor
+Copyright (C) 2003-2014 Mark Shelor
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
@@ -9,7 +9,7 @@ use integer;
 use FileHandle;
 use Carp qw(croak);
 
-$VERSION = '5.85';
+$VERSION = '5.88';
 
 require Exporter;
 @ISA = qw(Exporter);
@@ -691,83 +691,76 @@ sub _shacpy {
 sub _shadup { my($self) = @_; my($copy); _shacpy($copy, $self) }
 
 sub _shadump {
-	my $file = shift;
-	my $fh = (!defined($file) || $file eq "")
-			? FileHandle->new("> -")
-			: FileHandle->new($file, "w") or return;
 	my $self = shift;
-	my $is32bit = $self->{alg} <= 256;
-	my $fmt = $is32bit ? ":%08x" : ":%016x";
+	for (qw(alg H block blockcnt lenhh lenhl lenlh lenll)) {
+		return unless defined $self->{$_};
+	}
 
-	printf $fh "alg:%d\n", $self->{alg};
+	my @state = ();
+	my $fmt = ($self->{alg} <= 256 ? "%08x" : "%016x");
 
-	printf $fh "H";
-	for (@{$self->{H}}) { printf $fh $fmt, $is32bit ? $_ & $MAX32 : $_ }
+	push(@state, "alg:" . $self->{alg});
+
+	my @H = map { $self->{alg} <= 256 ? $_ & $MAX32 : $_ } @{$self->{H}};
+	push(@state, "H:" . join(":", map { sprintf($fmt, $_) } @H));
 
-	printf $fh "\nblock";
 	my @c = unpack("C*", $self->{block});
 	push(@c, 0x00) while scalar(@c) < ($self->{blocksize} >> 3);
-	for (@c) { printf $fh ":%02x", $_ }
-
-	printf $fh "\nblockcnt:%u\n", $self->{blockcnt};
-
-	printf $fh "lenhh:%lu\n", $self->{lenhh} & $MAX32;
-	printf $fh "lenhl:%lu\n", $self->{lenhl} & $MAX32;
-	printf $fh "lenlh:%lu\n", $self->{lenlh} & $MAX32;
-	printf $fh "lenll:%lu\n", $self->{lenll} & $MAX32;
-
-	close($fh);
-	$self;
+	push(@state, "block:" . join(":", map {sprintf("%02x", $_)} @c));
+	push(@state, "blockcnt:" . $self->{blockcnt});
+
+	push(@state, "lenhh:" . $self->{lenhh});
+	push(@state, "lenhl:" . $self->{lenhl});
+	push(@state, "lenlh:" . $self->{lenlh});
+	push(@state, "lenll:" . $self->{lenll});
+	join("\n", @state) . "\n";
 }
 
-sub _match {
-	my($fh, $tag) = @_;
-	my @f;
-	while (<$fh>) {
+sub _shaload {
+	my $state = shift;
+
+	my %s = ();
+	for (split(/\n/, $state)) {
 		s/^\s+//;
 		s/\s+$//;
 		next if (/^(#|$)/);
-		@f = split(/[:\s]+/);
-		last;
+		my @f = split(/[:\s]+/);
+		my $tag = shift(@f);
+		$s{$tag} = join('', @f);
 	}
-	shift(@f) eq $tag or return;
-	return(@f);
-}
 
-sub _shaload {
-	my $file = shift;
-	my $fh = (!defined($file) || $file eq "")
-			? FileHandle->new("< -")
-			: FileHandle->new($file, "r") or return;
-
-	my @f = _match($fh, "alg") or return;
-	my $self = _shaopen(shift(@f)) or return;
-
-	@f = _match($fh, "H") or return;
-	my $numxdigits = $self->{alg} <= 256 ? 8 : 16;
-	for (@f) { $_ = "0" . $_ while length($_) < $numxdigits }
-	for (@f) { $_ = substr($_, 1) while length($_) > $numxdigits }
-	@{$self->{H}} = map { $self->{alg} <= 256 ? hex($_) :
-		((hex(substr($_, 0, 8)) << 16) << 16) |
-		hex(substr($_, 8)) } @f;
-
-	@f = _match($fh, "block") or return;
-	for (@f) { $self->{block} .= chr(hex($_)) }
-
-	@f = _match($fh, "blockcnt") or return;
-	$self->{blockcnt} = shift(@f);
+	# H and block may contain arbitrary values, but check everything else
+	grep { $_ == $s{alg} } (1,224,256,384,512,512224,512256) or return;
+	length($s{H}) == ($s{alg} <= 256 ? 64 : 128) or return;
+	length($s{block}) == ($s{alg} <= 256 ? 128 : 256) or return;
+	{
+		no integer;
+		for (qw(blockcnt lenhh lenhl lenlh lenll)) {
+			0 <= $s{$_} or return;
+			$s{$_} <= 4294967295 or return;
+		}
+		$s{blockcnt} < ($s{alg} <= 256 ? 512 : 1024) or return;
+	}
+
+	my $self = _shaopen($s{alg}) or return;
+
+	my @h = $s{H} =~ /(.{8})/g;
+	for (@{$self->{H}}) {
+		$_ = hex(shift @h);
+		if ($self->{alg} > 256) {
+			$_ = (($_ << 16) << 16) | hex(shift @h);
+		}
+	}
+
+	$self->{blockcnt} = $s{blockcnt};
+	$self->{block} = pack("H*", $s{block});
 	$self->{block} = substr($self->{block},0,_BYTECNT($self->{blockcnt}));
 
-	@f = _match($fh, "lenhh") or return;
-	$self->{lenhh} = shift(@f);
-	@f = _match($fh, "lenhl") or return;
-	$self->{lenhl} = shift(@f);
-	@f = _match($fh, "lenlh") or return;
-	$self->{lenlh} = shift(@f);
-	@f = _match($fh, "lenll") or return;
-	$self->{lenll} = shift(@f);
+	$self->{lenhh} = $s{lenhh};
+	$self->{lenhl} = $s{lenhl};
+	$self->{lenlh} = $s{lenlh};
+	$self->{lenll} = $s{lenll};
 
-	close($fh);
 	$self;
 }
 
@@ -932,6 +925,20 @@ sub _addfile {
     $self;
 }
 
+my $_can_T_filehandle;
+
+sub _istext {
+	local *FH = shift;
+	my $file = shift;
+
+	if (! defined $_can_T_filehandle) {
+		local $^W = 0;
+		eval { -T FH };
+		$_can_T_filehandle = $@ ? 0 : 1;
+	}
+	return $_can_T_filehandle ? -T FH : -T $file;
+}
+
 sub _Addfile {
 	my ($self, $file, $mode) = @_;
 
@@ -959,55 +966,70 @@ sub _Addfile {
 	}
 
 	binmode(FH) if $binary || $portable;
-	unless ($portable && -T $file) {
+	unless ($portable && _istext(*FH, $file)) {
 		$self->_addfile(*FH);
 		close(FH);
 		return($self);
 	}
 
-	my ($n1, $n2);
-	my ($buf1, $buf2) = ("", "");
-
-	while (($n1 = read(FH, $buf1, 4096))) {
-		while (substr($buf1, -1) eq "\015") {
-			$n2 = read(FH, $buf2, 4096);
-			_bail("Read failed") unless defined $n2;
-			last unless $n2;
-			$buf1 .= $buf2;
-		}
-		$buf1 =~ s/\015?\015\012/\012/g;	# DOS/Windows
-		$buf1 =~ s/\015/\012/g;			# early MacOS
-		$self->add($buf1);
+	while (<FH>) {
+		s/\015?\015\012/\012/g;		# DOS/Windows
+		s/\015/\012/g;			# early MacOS
+		$self->add($_);
 	}
-	_bail("Read failed") unless defined $n1;
 	close(FH);
 
 	$self;
 }
 
-sub dump {
+sub getstate {
 	my $self = shift;
-	my $file = shift;
 
-	$file = "" unless defined $file;
-	_shadump($file, $self) or return;
-	return($self);
+	return _shadump($self);
 }
 
-sub load {
+sub putstate {
 	my $class = shift;
-	my $file = shift;
+	my $state = shift;
 
-	$file = "" unless defined $file;
 	if (ref($class)) {	# instance method
-		my $self = _shaload($file) or return;
+		my $self = _shaload($state) or return;
 		return(_shacpy($class, $self));
 	}
-	my $self = _shaload($file) or return;
+	my $self = _shaload($state) or return;
 	bless($self, $class);
 	return($self);
 }
 
+sub dump {
+	my $self = shift;
+	my $file = shift;
+
+	my $state = $self->getstate or return;
+	$file = "-" if (!defined($file) || $file eq "");
+
+	local *FH;
+	open(FH, "> $file") or return;
+	print FH $state;
+	close(FH);
+
+	return($self);
+}
+
+sub load {
+	my $class = shift;
+	my $file = shift;
+
+	$file = "-" if (!defined($file) || $file eq "");
+	
+	local *FH;
+	open(FH, "< $file") or return;
+	my $str = join('', <FH>);
+	close(FH);
+
+	$class->putstate($str);
+}
+
 1;
 __END__
 
@@ -1045,9 +1067,9 @@ In programs:
 	$sha->add_bits($bits);
 	$sha->add_bits($data, $nbits);
 
-	$sha_copy = $sha->clone;	# if needed, make copy of
-	$sha->dump($file);		#	current digest state,
-	$sha->load($file);		#	or save it on disk
+	$sha_copy = $sha->clone;	# make copy of digest object
+	$state = $sha->getstate;	# save current state to string
+	$sha->putstate($state);		# restore previous $state
 
 	$digest = $sha->digest;		# compute digest
 	$digest = $sha->hexdigest;
@@ -1123,16 +1145,15 @@ Note that for larger bit-strings, it's more efficient to use the
 two-argument version I<add_bits($data, $nbits)>, where I<$data> is
 in the customary packed binary format used for Perl strings.
 
-The module also lets you save intermediate SHA states to disk, or
-display them on standard output.  The I<dump()> method generates
-portable, human-readable text describing the current state of
-computation.  You can subsequently retrieve the file with I<load()>
-to resume where the calculation left off.
+The module also lets you save intermediate SHA states to a string.  The
+I<getstate()> method generates portable, human-readable text describing
+the current state of computation.  You can subsequently restore that
+state with I<putstate()> to resume where the calculation left off.
 
 To see what a state description looks like, just run the following:
 
 	use Digest::SHA::PurePerl;
-	Digest::SHA::PurePerl->new->add("Shaw" x 1962)->dump;
+	print Digest::SHA::PurePerl->new->add("Shaw" x 1962)->getstate;
 
 As an added convenience, the Digest::SHA::PurePerl module offers
 routines to calculate keyed hashes using the HMAC-SHA-1/224/256/384/512
@@ -1385,21 +1406,30 @@ a convenient way to calculate the digest values of partial-byte data by
 using files, rather than having to write programs using the I<add_bits>
 method.
 
+=item B<getstate>
+
+Returns a string containing a portable, human-readable representation
+of the current SHA state.
+
+=item B<putstate($str)>
+
+Returns a Digest::SHA object representing the SHA state contained
+in I<$str>.  The format of I<$str> matches the format of the output
+produced by method I<getstate>.  If called as a class method, a new
+object is created; if called as an instance method, the object is reset
+to the state contained in I<$str>.
+
 =item B<dump($filename)>
 
-Provides persistent storage of intermediate SHA states by writing
-a portable, human-readable representation of the current state to
-I<$filename>.  If the argument is missing, or equal to the empty
-string, the state information will be written to STDOUT.
+Writes the output of I<getstate> to I<$filename>.  If the argument is
+missing, or equal to the empty string, the state information will be
+written to STDOUT.
 
 =item B<load($filename)>
 
-Returns a Digest::SHA::PurePerl object representing the intermediate
-SHA state that was previously dumped to I<$filename>.  If called
-as a class method, a new object is created; if called as an instance
-method, the object is reset to the state contained in I<$filename>.
-If the argument is missing, or equal to the empty string, the state
-information will be read from STDIN.
+Returns a Digest::SHA object that results from calling I<putstate> on
+the contents of I<$filename>.  If the argument is missing, or equal to
+the empty string, the state information will be read from STDIN.
 
 =item B<digest>
 
@@ -1553,7 +1583,7 @@ darkness and moored it in so perfect a calm and in so brilliant a light"
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (C) 2003-2013 Mark Shelor
+Copyright (C) 2003-2014 Mark Shelor
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
@@ -2,10 +2,10 @@
 
 	## shasum: filter for computing SHA digests (ref. sha1sum/md5sum)
 	##
-	## Copyright (C) 2003-2013 Mark Shelor, All Rights Reserved
+	## Copyright (C) 2003-2014 Mark Shelor, All Rights Reserved
 	##
-	## Version: 5.85
-	## Wed Jun 26 04:05:26 MST 2013
+	## Version: 5.88
+	## Mon Mar 17 08:46:10 MST 2014
 
 	## shasum SYNOPSIS adapted from GNU Coreutils sha1sum.
 	## Add an "-a" option for algorithm selection, a "-p"
@@ -47,10 +47,11 @@ shasum - Print or Check SHA Checksums
 
    shasum -a 512224 -c checksumfile
 
- The sums are computed as described in FIPS-180-4.  When checking, the
- input should be a former output of this program.  The default mode is to
- print a line with checksum, a character indicating type (`*' for binary,
- ` ' for text, `?' for portable, `^' for BITS), and name for each FILE.
+ The sums are computed as described in FIPS PUB 180-4.  When checking,
+ the input should be a former output of this program.  The default
+ mode is to print a line with checksum, a character indicating type
+ (`*' for binary, ` ' for text, `?' for portable, `^' for BITS),
+ and name for each FILE.
 
  Report shasum bugs to mshelor@cpan.org
 
@@ -82,7 +83,7 @@ the 7-bit message I<0001100>:
 
 =head1 AUTHOR
 
-Copyright (c) 2003-2013 Mark Shelor <mshelor@cpan.org>.
+Copyright (c) 2003-2014 Mark Shelor <mshelor@cpan.org>.
 
 =head1 SEE ALSO
 
@@ -97,23 +98,7 @@ use strict;
 use Fcntl;
 use Getopt::Long;
 
-my $VERSION = "5.85";
-
-
-	## Try to use Digest::SHA.  If not installed, use the slower
-	## but functionally equivalent Digest::SHA::PurePerl instead.
-
-my $MOD_PREFER = "Digest::SHA";
-my $MOD_SECOND = "Digest::SHA::PurePerl";
-
-my $module = $MOD_PREFER;
-eval "require $module";
-if ($@) {
-	$module = $MOD_SECOND;
-	eval "require $module";
-	die "Unable to find $MOD_PREFER or $MOD_SECOND\n" if $@;
-}
-
+my $VERSION = "5.88";
 
 sub usage {
 	my($err, $msg) = @_;
@@ -123,9 +108,11 @@ sub usage {
 		warn($msg . "Type shasum -h for help\n");
 		exit($err);
 	}
-	my($USAGE) = $POD =~ /SYNOPSIS\n\n(.+)\n=head1 DESCRIPTION\n/sm;
+	my($USAGE) = $POD =~ /SYNOPSIS(.+?)^=/sm;
+	$USAGE =~ s/^\s*//;
+	$USAGE =~ s/\s*$//;
 	$USAGE =~ s/^ //gm;
-	print $USAGE;
+	print $USAGE, "\n";
 	exit($err);
 }
 
@@ -139,7 +126,7 @@ select((select(STDERR), $| = 1)[0]);
 	## Collect options from command line
 
 my ($alg, $binary, $check, $text, $status, $warn, $help, $version);
-my ($portable, $BITS);
+my ($portable, $BITS, $modules, $versions);
 
 eval { Getopt::Long::Configure ("bundling") };
 GetOptions(
@@ -148,7 +135,9 @@ GetOptions(
 	's|status' => \$status, 'w|warn' => \$warn,
 	'h|help' => \$help, 'v|version' => \$version,
 	'p|portable' => \$portable,
-	'0|01' => \$BITS
+	'0|01' => \$BITS,
+	'M|MODULES=s' => \$modules,
+	'V|VERSIONS' => \$versions,
 ) or usage(1, "");
 
 
@@ -164,6 +153,28 @@ usage(1, "shasum: --status option used only when verifying checksums\n")
 	if $status && !$check;
 
 
+	## Try to use Digest::SHA.  If not installed, use the slower
+	## but functionally equivalent Digest::SHA::PurePerl instead.
+
+	## If option -M "Mod::Num1 Mod::Num2 ..." is invoked, try
+	## those modules instead, in the order indicated.
+
+my @MODS = defined $modules
+		? split(" ", $modules)
+		: qw(Digest::SHA Digest::SHA::PurePerl);
+
+my $module;
+for (@MODS) {
+	my $mod = $_;
+	if (eval "require $mod") {
+		$module = $mod;
+		last;
+	}
+}
+die "shasum: Unable to find " . join(" or ", @MODS) . "\n"
+	unless defined $module;
+
+
 	## Default to SHA-1 unless overridden by command line option
 
 $alg = 1 unless defined $alg;
@@ -178,6 +189,13 @@ if ($version) {
 	exit(0);
 }
 
+if ($versions) {
+	print "shasum $VERSION\n";
+	print "$module ", eval "\$${module}::VERSION", "\n";
+	print "perl ", defined $^V ? sprintf("%vd", $^V) : $], "\n";
+	exit(0);
+}
+
 
 	## Try to figure out if the OS is DOS-like.  If it is,
 	## default to binary mode when reading files, unless
@@ -1,102 +0,0 @@
-use strict;
-use FileHandle;
-
-my $MODULE;
-
-BEGIN {
-	$MODULE = (-d "src") ? "Digest::SHA" : "Digest::SHA::PurePerl";
-	eval "require $MODULE" || die $@;
-	$MODULE->import(qw(sha384_hex sha512_hex));
-}
-
-BEGIN {
-	if ($ENV{PERL_CORE}) {
-		chdir 't' if -d 't';
-		@INC = '../lib';
-	}
-}
-
-my @sharsp = (
-	"34aa973cd4c4daa4f61eeb2bdbad27316534016f",
-	"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0",
-	"9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985",
-	"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"
-);
-
-my $numtests = scalar @sharsp;
-print "1..$numtests\n";
-
-my @tempfiles;
-END { 1 while unlink @tempfiles }
-
-my @statefiles = ("dl001.tmp", "dl256.tmp", "dl384.tmp", "dl512.tmp");
-for (@statefiles) {
-	push @tempfiles, $_;
-	my $fh = FileHandle->new($_, "w");
-	for (1 .. 8) { my $line = <DATA>; print $fh $line }
-	$fh->close;
-}
-my $tmpfile = "dumpload.tmp";
-push @tempfiles, $tmpfile;
-
-my @alg = (1, 256, 384, 512);
-my $data = "a" x 990000;
-
-my $testnum = 1;
-while (@sharsp) {
-	my $skip = 0;
-	my $alg = shift @alg;
-	my $rsp = shift @sharsp;
-	my $file = shift @statefiles; push(@statefiles, $file);
-	if ($alg == 384) { $skip = sha384_hex("") ? 0 : 1 }
-	if ($alg == 512) { $skip = sha512_hex("") ? 0 : 1 }
-	if ($skip) {
-		print "ok ", $testnum++, " # skip: no 64-bit\n";
-		next;
-	}
-	my $digest;
-	my $state;
-	unless ($state = $MODULE->load($file)) {
-		print "not ok ", $testnum++, "\n";
-		next;
-	}
-	$state->add_bits($data, 79984)->dump($tmpfile);
-	$state->load($tmpfile)->add_bits($data, 16);
-	$digest = $state->hexdigest;
-	print "not " unless $digest eq $rsp;
-	print "ok ", $testnum++, "\n";
-}
-
-__DATA__
-alg:1
-H:9d6f7d2f:65e21307:c6f41af6:7c7fd3a9:8dec6058:00000000:00000000:00000000
-block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
-blockcnt:384
-lenhh:0
-lenhl:0
-lenlh:0
-lenll:7920000
-alg:256
-H:2d6c0def:4244ade7:fc8c121c:108f4493:ec3fbec2:91425a6e:b8d30d2a:9db24273
-block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
-blockcnt:384
-lenhh:0
-lenhl:0
-lenlh:0
-lenll:7920000
-alg:384
-H:598147f4583a61f7:8d194a4d7c9008cb:39725c96557d600f:d7f2079ce8251f19:bd735d446f9a3c7c:234de90b9060898d:a5b481b9d635d190:81c6e74ee4556125
-block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
-blockcnt:384
-lenhh:0
-lenhl:0
-lenlh:0
-lenll:7920000
-alg:512
-H:0442fe29a02b8c30:13553e6dbedc2aa0:8f891a0cb2ac3107:6fa1762b40ac04dd:dcbf420d729eea79:34703e9672dcf145:7bf9aaa14d400433:2aa65f044825466d
-block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
-blockcnt:384
-lenhh:0
-lenhl:0
-lenlh:0
-lenll:7920000
@@ -1,7 +1,6 @@
 # Test against long bitwise vectors from Jim Gillogly and Francois Grieu
 
 use strict;
-use FileHandle;
 
 my $MODULE;
 
@@ -50,97 +49,42 @@ my @vec011 = (	# 011 rep 1431655764
 	"0110", "a3d7438c589b0b932aa91cc2446f06df9abc73f0",
 	"01101", "3eee3e1e28dede2ca444d68da5675b2faaab3203"
 );
-print "1..", scalar(@vec110) / 2 + scalar(@vec011) / 2, "\n";
 
-my $STATE110 = "gglong0.tmp";
-my $STATE011 = "gglong1.tmp";
-
-END { 1 while unlink $STATE110, $STATE011 }
-
-for ($STATE011, $STATE110) {
-	my $fh = FileHandle->new($_, "w");
-	for (1 .. 8) { my $line = <DATA>; print $fh $line }
-	$fh->close;
-}
-
-my $reps = 1 << 14;
-my $loops = int(1431655764 / $reps);
-my $rest = 3 * (1431655764 - $loops * $reps);
-
-sub state110 {
-	my $i;
-	my $state;
-	my $bitstr;
-
-	$state = $MODULE->new(1);
-	if (-r $STATE110) {
-		if ($state->load($STATE110)) {
-			return($state);
-		}
-	}
-	$bitstr = pack("B*", "110" x $reps);
-	$state->reset;
-	for ($i = 0; $i < $loops; $i++) {
-		$state->add_bits($bitstr, 3 * $reps);
-	}
-	$state->add_bits($bitstr, $rest);
-	$state->dump($STATE110);
-	return($state);
-}
-
-sub state011 {
-	my $i;
-	my $state;
-	my $bitstr;
-
-	$state = $MODULE->new(1);
-	if (-r $STATE011) {
-		if ($state->load($STATE011)) {
-			return($state);
-		}
-	}
-	$bitstr = pack("B*", "011" x $reps);
-	$state->reset;
-	for ($i = 0; $i < $loops; $i++) {
-		$state->add_bits($bitstr, 3 * $reps);
-	}
-	$state->add_bits($bitstr, $rest);
-	$state->dump($STATE011);
-	return($state);
-}
-
-my $i;
+my($STATE110, $STATE011) = ('', '');
+for (1 .. 8) { my $line = <DATA>; $STATE110 .= $line }
+for (1 .. 8) { my $line = <DATA>; $STATE011 .= $line }
 
 my $testnum = 1;
+print "1..", scalar(@vec110)/2 + scalar(@vec011)/2, "\n";
 
-my $state110 = state110();
-for ($i = 0; $i < @vec110/2; $i++) {
+my $state110 = $MODULE->putstate($STATE110);
+while (@vec110) {
 	my $state = $state110->clone;
-	$state->add_bits($vec110[2*$i]);
-	print "not " unless $state->hexdigest eq $vec110[2*$i+1];
+	$state->add_bits(shift @vec110);
+	print "not " unless $state->hexdigest eq (shift @vec110);
 	print "ok ", $testnum++, "\n";
 }
 
-my $state011 = state011();
-for ($i = 0; $i < @vec011/2; $i++) {
+my $state011 = $MODULE->putstate($STATE011);
+while (@vec011) {
 	my $state = $state011->clone;
-	$state->add_bits($vec011[2*$i]);
-	print "not " unless $state->hexdigest eq $vec011[2*$i+1];
+	$state->add_bits(shift @vec011);
+	print "not " unless $state->hexdigest eq (shift @vec011);
 	print "ok ", $testnum++, "\n";
 }
 
 __DATA__
 alg:1
-H:7950cbe2:86a45aa0:91ff7dff:29015b42:3912e764:00000000:00000000:00000000
-block:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6
+H:dfc51a14:87b4a4b7:ecf19acd:8cbbe40e:03a435f8:00000000:00000000:00000000
+block:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d
 blockcnt:508
 lenhh:0
 lenhl:0
 lenlh:0
 lenll:4294967292
 alg:1
-H:dfc51a14:87b4a4b7:ecf19acd:8cbbe40e:03a435f8:00000000:00000000:00000000
-block:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d
+H:7950cbe2:86a45aa0:91ff7dff:29015b42:3912e764:00000000:00000000:00000000
+block:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6:db:6d:b6
 blockcnt:508
 lenhh:0
 lenhl:0
@@ -7,7 +7,7 @@ my $MODULE;
 BEGIN {
 	$MODULE = (-d "src") ? "Digest::SHA" : "Digest::SHA::PurePerl";
 	eval "require $MODULE" || die $@;
-	$MODULE->import(qw(hmac_sha256_hex));
+	$MODULE->import(qw(hmac_sha256 hmac_sha256_hex));
 }
 
 BEGIN {
@@ -51,11 +51,11 @@ my @out = (
 	"6355ac22e890d0a3c8481a5ca4825bc884d3e7a1ff98a2fc2ac7d8e064c3b2e6"
 );
 
-	# do the first one using multi-argument data feed
+	# do first one using multi-argument data feed and binary output
 
 my $testnum = 1;
 my @args = split(//, shift @data);
-print "not " unless hmac_sha256_hex(@args, shift @keys) eq shift @out;
+print "not " unless hmac_sha256(@args, shift @keys) eq pack("H*", shift @out);
 print "ok ", $testnum++, "\n";
 
 while (@data) {
@@ -1,5 +1,4 @@
 use strict;
-use FileHandle;
 
 my $MODULE;
 
@@ -19,20 +18,14 @@ BEGIN {
 # David Ireland's test vector - SHA-256 digest of "a" x 536870912
 
 # Adapted from Julius Duque's original script (t/24-ireland.tmp)
-#	- modified to use state cache via dump()/load() methods
+#	- modified to use state cache via putstate method
 
 print "1..1\n";
 
-my $tempfile = "ireland.tmp";
-END { 1 while unlink $tempfile }
-
-my $fh = FileHandle->new($tempfile, "w");
-while (<DATA>) { print $fh $_ }  close($fh);
-
 my $rsp = "b9045a713caed5dff3d3b783e98d1ce5778d8bc331ee4119d707072312af06a7";
 
 my $sha;
-if ($sha = $MODULE->load($tempfile)) {
+if ($sha = $MODULE->putstate(join('', <DATA>))) {
 	$sha->add("aa");
 	print "not " unless $sha->hexdigest eq $rsp;
 	print "ok 1\n";
@@ -40,11 +33,19 @@ if ($sha = $MODULE->load($tempfile)) {
 else { print "not ok 1\n" }
 
 __DATA__
+
+	# Verify comments/blank lines ignored in state data
+			
 alg:256
 H:dd75eb45:02d4f043:06b41193:6fda751d:73064db9:787d54e1:52dc3fe0:48687dfa
-block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
+
+block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00
 blockcnt:496
+                            
 lenhh:0
 lenhl:0
 lenlh:0
+
+# Note: add'ing two more bytes will cause lenll (below) to overflow
+
 lenll:4294967280
@@ -32,9 +32,7 @@ if ($MODULE eq "Digest::SHA") {
 		B64digest
 		Hexdigest
 		shaclose
-		shadump
 		shadup
-		shaload
 		shaopen
 		sharewind
 		shawrite
@@ -0,0 +1,94 @@
+use strict;
+
+my $MODULE;
+
+BEGIN {
+	$MODULE = (-d "src") ? "Digest::SHA" : "Digest::SHA::PurePerl";
+	eval "require $MODULE" || die $@;
+	$MODULE->import(qw(sha384_hex sha512_hex));
+}
+
+BEGIN {
+	if ($ENV{PERL_CORE}) {
+		chdir 't' if -d 't';
+		@INC = '../lib';
+	}
+}
+
+my @sharsp = (
+	"34aa973cd4c4daa4f61eeb2bdbad27316534016f",
+	"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0",
+	"9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985",
+	"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"
+);
+
+my $numtests = scalar @sharsp;
+print "1..$numtests\n";
+
+my($state001, $state256, $state384, $state512) = ('', '', '', '');
+for (1 .. 8) { my $line = <DATA>; $state001 .= $line }
+for (1 .. 8) { my $line = <DATA>; $state256 .= $line }
+for (1 .. 8) { my $line = <DATA>; $state384 .= $line }
+for (1 .. 8) { my $line = <DATA>; $state512 .= $line }
+my @states = ($state001, $state256, $state384, $state512);
+
+my @alg = (1, 256, 384, 512);
+my $data = "a" x 990000;
+
+my $testnum = 1;
+while (@sharsp) {
+	my $skip = 0;
+	my $alg = shift @alg;
+	my $rsp = shift @sharsp;
+	if ($alg == 384) { $skip = sha384_hex("") ? 0 : 1 }
+	if ($alg == 512) { $skip = sha512_hex("") ? 0 : 1 }
+	if ($skip) {
+		print "ok ", $testnum++, " # skip: no 64-bit\n";
+		next;
+	}
+	my $digest;
+	my $state;
+	unless ($state = $MODULE->putstate(shift @states)) {
+		print "not ok ", $testnum++, "\n";
+		next;
+	}
+	my $statestr = $state->add_bits($data, 79984)->getstate;
+	$state->putstate($statestr)->add_bits($data, 16);
+	$digest = $state->hexdigest;
+	print "not " unless $digest eq $rsp;
+	print "ok ", $testnum++, "\n";
+}
+
+__DATA__
+alg:1
+H:9d6f7d2f:65e21307:c6f41af6:7c7fd3a9:8dec6058:00000000:00000000:00000000
+block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
+blockcnt:384
+lenhh:0
+lenhl:0
+lenlh:0
+lenll:7920000
+alg:256
+H:2d6c0def:4244ade7:fc8c121c:108f4493:ec3fbec2:91425a6e:b8d30d2a:9db24273
+block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
+blockcnt:384
+lenhh:0
+lenhl:0
+lenlh:0
+lenll:7920000
+alg:384
+H:598147f4583a61f7:8d194a4d7c9008cb:39725c96557d600f:d7f2079ce8251f19:bd735d446f9a3c7c:234de90b9060898d:a5b481b9d635d190:81c6e74ee4556125
+block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
+blockcnt:384
+lenhh:0
+lenhl:0
+lenlh:0
+lenll:7920000
+alg:512
+H:0442fe29a02b8c30:13553e6dbedc2aa0:8f891a0cb2ac3107:6fa1762b40ac04dd:dcbf420d729eea79:34703e9672dcf145:7bf9aaa14d400433:2aa65f044825466d
+block:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:61:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
+blockcnt:384
+lenhh:0
+lenhl:0
+lenlh:0
+lenll:7920000