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

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

_define_constants();

my @constant_bases = qw(
  BYTES
  KEYBYTES
);

my @bases = qw(
  init
  keygen
  verify
);

my $default = [
  "onetimeauth",
  (map { "onetimeauth_$_" } @bases),
  (map { "onetimeauth_$_" } @constant_bases, "PRIMITIVE"),
];
my $poly1305 = [
  "onetimeauth_poly1305",
  (map { "onetimeauth_poly1305_$_" } @bases),
  (map { "onetimeauth_poly1305_$_" } @constant_bases),
];

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

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

1;

__END__

=encoding utf8

=head1 NAME

Crypt::Sodium::XS::onetimeauth - Single-use secret key message authentication

=head1 SYNOPSIS

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

  # NOTE: use a new key for every message
  my $key = onetimeauth_keygen();
  my $msg = "authenticate me";

  my $tag = onetimeauth($msg, $key);
  die "message tampered!" unless onetimeauth_verify($tag, $msg, $key);

=head1 DESCRIPTION

L<Crypt::Sodium::XS::onetimeauth> uses Poly1305, a Wegman-Carter authenticator
designed by D. J. Bernstein. Poly1305 takes a 32-byte, one-time key and a
message and produces a 16-byte tag that authenticates the message such that an
attacker has a negligible chance of producing a valid tag for a inauthentic
message.

Poly1305 keys have to be:

=over 4

=item * secret

An attacker can compute a valid authentication tag for any message, for any
given key. The security of Poly1305 relies on the fact that attackers don't
know the key being used to compute the tag. This implies that they have to be:

=item * unpredictable

Do not use timestamps or counters.

=item * unique

Never reuse a key. A new key is required for every single message. The key can
be recovered if two messages are authenticated with the same key.

=back

The standard way to use Poly1305's is to derive a dedicated subkey from a (key,
nonce) tuple, for example by taking the first bytes generated by a stream
cipher.

Due to its output size, Poly1305 is recommended for online protocols,
exchanging many small messages, rather than for authenticating very large
files.

Finally, Poly1305 is not a replacement for a hash function.

=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<onetimeauth_E<lt>primitiveE<gt>_*> functions and constants for that
primitive. A C<:all> tag imports everything.

=head2 onetimeauth

=head2 onetimeauth_E<lt>primitiveE<gt>

  my $tag = onetimeauth($message, $key);

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

C<$key> is a secret key. It must be L</onetimeauth_KEYBYTES> bytes. It may be a
L<Crypt::Sodium::XS::MemVault>.

Returns an authentication tag of L</onetimeauth_BYTES> bytes.

=head2 onetimeauth_init

=head2 onetimeauth_E<lt>primitiveE<gt>_init

  my $multipart = onetimeauth_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 onetimeauth object. See L</MULTI-PART INTERFACE>.

=head2 onetimeauth_keygen

=head2 onetimeauth_E<lt>primitiveE<gt>_keygen

  my $key = onetimeauth_keygen($flags);

C<$flags> is optional. It is the flags used for the C<$key>
L<Crypt::Sodium::XS::MemVault>. See L<Crypt::Sodium::XS::ProtMem>.

Returns a L<Crypt::Sodium::XS::MemVault>: a secret key of
L</onetimeauth_KEYBYTES> bytes.

=head2 onetimeauth_verify

=head2 onetimeauth_E<lt>primitiveE<gt>_verify

  my $is_valid = onetimeauth_verify($tag, $message, $key);

C<$tag> is the authentication tag to verify. It must be L</BYTES> bytes.

C<$message> is the message to authenticate.

C<$key> is the secret key to use for authentication of the tag. It must be
L</KEYBYTES> bytes. It may be a L<Crypt::Sodium::XS::MemVault>.

Returns true if the authentication tag C<$tag> validly authenticates
C<$message> with C<$key>, false otherwise.

=head1 MULTI-PART INTERFACE

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

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

=head2 clone

  my $multipart_copy = $multipart->clone;

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

=head2 final

  my $tag = $multipart->final;

Returns an authentication tag of L</BYTES> bytes.

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 authenticated data. Any argument may
be a L<Crypt::Sodium::XS::MemVault>.

=head1 CONSTANTS

=head2 onetimeauth_PRIMITIVE

  my $default_primitive = onetimeauth_PRIMITIVE();

Returns the name of the default primitive.

=head2 onetimeauth_BYTES

=head2 onetimeauth_E<lt>primitiveE<gt>_BYTES

  my $tag_size = onetimeauth_BYTES();

Returns the size, in bytes, of an authentication tag.

=head2 onetimeauth_KEYBYTES

=head2 onetimeauth_E<lt>primitiveE<gt>_KEYBYTES

  my $key_size = onetimeauth_KEYBYTES();

Returns the size, in bytes, of a secret key.

=head1 PRIMITIVES

All constants (except _PRIMITIVE) and functions have
C<onetimeauth_E<lt>primitiveE<gt>>-prefixed couterparts (e.g.,
onetimeauth_poly1305_keypair, onetimeauth_poly1305_KEYBYTES).

=over 4

=item * poly1305 (default)

=back

=head1 SEE ALSO

=over 4

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

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

=item L<https://doc.libsodium.org/advanced/poly1305>

=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
