# 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;
our @EXPORT_OK = qw(sha1_hex sha256_hex sha256 sha_all);
use autodie qw(sysread);
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) = (PublicInbox::SHA->new($n));
	while (sysread($fh, $buf, 65536)) { $dig->add($buf) }
	$dig
}

1;
