blob: 5eb882c642adc4bf1763ac80683c608e9cd617fe [file] [log] [blame]
# Copyright (C) all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
# OpenSSL exception added in commit 22711f81f4e79da6b796820e37803a05cae14645
# (README: add OpenSSL exception, 2015-10-05)
# Replaces most uses of Digest::SHA with OpenSSL via Net::SSLeay if
# possible. OpenSSL SHA-256 is nearly twice as fast as Digest::SHA on
# x86-64, and SHA-1 is a bit faster as well.
# I don't think we can implement Digest::SHA->clone with what Net::SSLeay
# gives us... (maybe EVP_MD_CTX_copy+EVP_MD_CTX_copy_ex need to be added
# to Net::SSLeay?)
package PublicInbox::SHA;
use v5.12;
require Exporter;
use Errno qw(EAGAIN EINTR);
use PublicInbox::IO qw(poll_in);
use Carp qw(croak);
our @EXPORT_OK = qw(sha1_hex sha256_hex sha256 sha_all);
our @ISA;
BEGIN {
push @ISA, 'Exporter';
unless (eval(<<'EOM')) {
use Net::SSLeay 1.43;
my %SHA = (
1 => Net::SSLeay::EVP_sha1(),
256 => Net::SSLeay::EVP_sha256(),
);
sub new {
my ($cls, $n) = @_;
my $mdctx = Net::SSLeay::EVP_MD_CTX_create();
Net::SSLeay::EVP_DigestInit($mdctx, $SHA{$n}) or
die "EVP_DigestInit $n: $!";
bless \$mdctx, $cls;
}
sub add {
my $self = shift;
Net::SSLeay::EVP_DigestUpdate($$self, $_) for @_;
$self;
}
sub digest { Net::SSLeay::EVP_DigestFinal(${$_[0]}) };
sub hexdigest { unpack('H*', Net::SSLeay::EVP_DigestFinal(${$_[0]})) }
sub DESTROY { Net::SSLeay::EVP_MD_CTX_destroy(${$_[0]}) };
sub sha1_hex { unpack('H*', Net::SSLeay::SHA1($_[0])) };
sub sha256_hex { unpack('H*', Net::SSLeay::SHA256($_[0])) };
*sha256 = \&Net::SSLeay::SHA256;
# end of eval
EOM
require Digest::SHA; # stdlib fallback
push @ISA, 'Digest::SHA';
*sha1_hex = \&Digest::SHA::sha1_hex;
*sha256_hex = \&Digest::SHA::sha256_hex;
*sha256 = \&Digest::SHA::sha256;
}
} # /BEGIN
sub sha_all ($$) {
my ($n, $fh) = @_;
my ($dig, $buf, $r) = (PublicInbox::SHA->new($n));
while (1) {
$r = sysread($fh, $buf, 65536);
if ($r) {
$dig->add($buf);
} elsif (!defined $r) {
if ($! == EAGAIN) {
poll_in($fh);
} elsif ($! != EINTR) {
croak "sysread: $!";
} # next on EINTR
} else { # EOF:
return $dig;
}
}
}
1;