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

use Crypt::Sodium::XS::hash;
use parent 'Crypt::Sodium::XS::OO::Base';

my %methods = (
  default => {
    BYTES => \&Crypt::Sodium::XS::hash::hash_BYTES,
    PRIMITIVE => \&Crypt::Sodium::XS::hash::hash_PRIMITIVE,
    hash => \&Crypt::Sodium::XS::hash::hash,
    init => sub { die "init is not supported for default primitive" },
  },
  sha256 => {
    BYTES => \&Crypt::Sodium::XS::hash::hash_sha256_BYTES,
    PRIMITIVE => sub { 'sha256' },
    hash => \&Crypt::Sodium::XS::hash::hash_sha256,
    init => \&Crypt::Sodium::XS::hash::hash_sha256_init,
  },
  sha512 => {
    BYTES => \&Crypt::Sodium::XS::hash::hash_sha512_BYTES,
    PRIMITIVE => sub { 'sha512' },
    hash => \&Crypt::Sodium::XS::hash::hash_sha512,
    init => \&Crypt::Sodium::XS::hash::hash_sha512_init,
  },
);

sub primitives { keys %methods }

sub BYTES { my $self = shift; goto $methods{$self->{primitive}}->{BYTES}; }
sub PRIMITIVE { my $self = shift; goto $methods{$self->{primitive}}->{PRIMITIVE}; }
sub hash { my $self = shift; goto $methods{$self->{primitive}}->{hash}; }
sub init { my $self = shift; goto $methods{$self->{primitive}}->{init}; }

1;

__END__

=encoding utf8

=head1 NAME

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

=head1 SYNOPSIS

  use Crypt::Sodium::XS;
  my $xs_hash = Crypt::Sodium::XS->hash;

  my $hash = $xs_hash->hash("arbitrary input data");

  my $multipart = $xs_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::OO::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::OO::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 CONSTRUCTOR

=head2 new

  my $xs_hash = Crypt::Sodium::XS::OO::hash->new;
  my $xs_hash = Crypt::Sodium::XS::OO::hash->new(primitive => 'sha256';
  my $xs_hash = Crypt::Sodium::XS->hash;

Returns a new hash object for the given primitive. If not given, the default
primitive is C<default>.

=head1 ATTRIBUTES

=head2 primitive

  my $primitive = $xs_hash->primitive;
  $xs_hash->primitive('sha256');

Gets or sets the primitive used for all operations by this object. Note this
can be C<default>.

=head1 METHODS

=head2 primitives

  my @primitives = Crypt::Sodium::XS::OO::hash->primitives;
  my @primitives = $xs_hash->primitives;

Returns a list of all supported primitive names, including C<default>.

Can be called as a class method.

=head2 PRIMITIVE

  my $primitive = $xs_hash->PRIMITIVE;

Returns the primitive used for all operations by this object. Note this will
never be C<default> but would instead be the primitive it represents.

=head2 hash

  my $hash = $xs_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</BYTES> bytes.

=head2 init

  my $multipart = $xs_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>.

=head2 BYTES

  my $xs_hash_size = $xs_hash->BYTES;

Returns the size, in bytes, of hash output.

=head1 MULTI-PART INTERFACE

A multipart hashing object is created by calling the L</init> method. 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 $xs_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 SEE ALSO

=over

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

=item L<Crypt::Sodium::XS::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
