package Crypt::Sodium::XS::hash;
use strict;
use warnings;

use Crypt::Sodium::XS;
use Exporter 'import';

_define_constants();

my @bases = qw(
  init
);

my @constant_bases = qw(
  BYTES
);

my $default = [
  "hash",
  (map { "hash_$_" } @bases),
  (map { "hash_$_" } @constant_bases, "PRIMITIVE"),
];
my $sha256 = [
  "hash_sha256",
  (map { "hash_sha256_$_" } @bases),
  (map { "hash_sha256_$_" } @constant_bases),
];
my $sha512 = [
  "hash_sha512",
  (map { "hash_sha512_$_" } @bases),
  (map { "hash_sha512_$_" } @constant_bases),
];

our %EXPORT_TAGS = (
  all => [ @$default, @$sha256, @$sha512 ],
  default => $default,
  sha256 => $sha256,
  sha512 => $sha512,
);

our @EXPORT_OK = @{$EXPORT_TAGS{all}};

1;

__END__

=encoding utf8

=head1 NAME

Crypt::Sodium::XS::hash - SHA2 cryptographic hashing

=head1 SYNOPSIS

  use Crypt::Sodium::XS::hash ":default";

  my $hash = hash("arbitrary input data");

  my $multipart = hash_init();
  $multipart->update("arbitrary");
  $multipart->update("input", " data");
  $hash = $multipart->final;

=head1 DESCRIPTION

The SHA-256 and SHA-512 functions are provided for interoperability with other
applications. If you are looking for a generic hash function and not
specifically SHA-2, using L<Crypt::Sodium::XS::generichash> (BLAKE2b) might be
a better choice.

These functions are also not suitable for hashing passwords or deriving keys
from passwords. Use L<Crypt::Sodium::XS::pwhash> instead.

These functions are not keyed and are thus deterministic. In addition, the
untruncated versions are vulnerable to length extension attacks.

A message can be hashed in a single pass, but a multi-part API is also
available to process a message as a sequence of multiple chunks.

=head1 FUNCTIONS

Nothing is exported by default. A C<:default> tag imports the functions and
constants documented below. A separate C<:E<lt>primitiveE<gt>> import tag is
provided for each of the primitives listed in L</PRIMITIVES>. These tags import
the C<hash_E<lt>primitiveE<gt>_*> functions and constants for that primitive. A
C<:all> tag imports everything.

=head2 hash

=head2 hash_E<lt>primitiveE<gt>

  my $hash = hash($message);

C<$message> is the message to hash. It may be a L<Crypt::Sodium::XS::MemVault>.

Returns the hash output of L</hash_BYTES> bytes.

=head2 MULTI-PART INTERFACE

=head2 hash_init

=head2 hash_E<lt>primitiveE<gt>_init

  my $multipart = hash_init($flags);

C<$flags> is optional. It is the flags used for the multipart protected memory
object. See L<Crypt::Sodium::XS::ProtMem>.

Returns a multipart hashing object. See L</MULTI-PART INTERFACE>.

=head1 MULTI-PART INTERFACE

A multipart hashing object is created by calling the L</hash_init> function.
Data to be hashed is added by calling the L</update> method of that object as
many times as desired. An output hash is generated by calling its L</final>
method. Do not use the object after calling L</final>.

The multipart hashing object is an opaque object which provides the following
methods:

=head2 clone

  my $multipart_copy = $multipart->clone;

Returns a cloned copy of the multipart hashing object, duplicating its internal
state.

=head2 final

  my $hash = $multipart->final;

Retruns the final hash for all data added with L</update>.

Once C<final> has been called, the hashing object must not be used further.

=head2 update

  $multipart->update(@messages);

Adds all given arguments (stringified) to hashed data. Any argument may be a
L<Crypt::Sodium::XS::MemVault>.

=head1 CONTSANTS

=head2 hash_PRIMITIVE

  my $default_primitive = hash_PRIMITIVE();

Returns the name of the default primitive.

=head2 hash_BYTES

=head2 hash_E<lt>primitiveE<gt>_BYTES

  my $hash_size = hash_BYTES();

Returns the size, in bytes, of hash output.

=head1 PRIMITIVES

All constants (except _PRIMITIVE) and functions have
C<hash_E<lt>primitiveE<gt>>-prefixed couterparts (e.g., hash_sha256,
hash_sha512_BYTES).

=over 4

=item * sha256

=item * sha512 (default)

=back

=head1 SEE ALSO

=over

=item L<Crypt::Sodium::XS>

=item L<Crypt::Sodium::XS::OO::hash>

=item L<https://doc.libsodium.org/advanced/sha-2_hash_function>

=back

=head1 FEEDBACK

For reporting bugs, giving feedback, submitting patches, etc. please use the
following:

=over 4

=item *

RT queue at L<https://rt.cpan.org/Dist/Display.html?Name=Crypt-Sodium-XS>

=item *

IRC channel C<#sodium> on C<irc.perl.org>.

=item *

Email the author directly.

=back

=head1 AUTHOR

Brad Barden E<lt>perlmodules@5c30.orgE<gt>

=head1 COPYRIGHT & LICENSE

Copyright (c) 2022 Brad Barden. All rights reserved.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=cut
