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

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

my %methods = (
  default => {
    BYTES => \&Crypt::Sodium::XS::onetimeauth::onetimeauth_BYTES,
    KEYBYTES => \&Crypt::Sodium::XS::onetimeauth::onetimeauth_KEYBYTES,
    PRIMITIVE => \&Crypt::Sodium::XS::onetimeauth::onetimeauth_PRIMITIVE,
    init => \&Crypt::Sodium::XS::onetimeauth::onetimeauth_init,
    keygen => \&Crypt::Sodium::XS::onetimeauth::onetimeauth_keygen,
    onetimeauth => \&Crypt::Sodium::XS::onetimeauth::onetimeauth,
    verify => \&Crypt::Sodium::XS::onetimeauth::onetimeauth_verify,
  },
  poly1305 => {
    BYTES => \&Crypt::Sodium::XS::onetimeauth::onetimeauth_poly1305_BYTES,
    KEYBYTES => \&Crypt::Sodium::XS::onetimeauth::onetimeauth_poly1305_KEYBYTES,
    PRIMITIVE => sub { 'poly1305' },
    init => \&Crypt::Sodium::XS::onetimeauth::onetimeauth_poly1305_init,
    keygen => \&Crypt::Sodium::XS::onetimeauth::onetimeauth_poly1305_keygen,
    onetimeauth => \&Crypt::Sodium::XS::onetimeauth::onetimeauth_poly1305,
    verify => \&Crypt::Sodium::XS::onetimeauth::onetimeauth_poly1305_verify,
  },
);

sub primitives { keys %methods }

sub BYTES { my $self = shift; goto $methods{$self->{primitive}}->{BYTES}; }
sub KEYBYTES { my $self = shift; goto $methods{$self->{primitive}}->{KEYBYTES}; }
sub PRIMITIVE { my $self = shift; goto $methods{$self->{primitive}}->{PRIMITIVE}; }
sub init { my $self = shift; goto $methods{$self->{primitive}}->{init}; }
sub keygen { my $self = shift; goto $methods{$self->{primitive}}->{keygen}; }
sub onetimeauth { my $self = shift; goto $methods{$self->{primitive}}->{onetimeauth}; }
sub verify { my $self = shift; goto $methods{$self->{primitive}}->{verify}; }

1;

__END__

=encoding utf8

=head1 NAME

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

=head1 SYNOPSIS

  use Crypt::Sodium::XS;
  my $ota = Crypt::Sodium::XS->onetimeauth;

  # NOTE: use a new key for every message
  my $key = $ota->keygen;
  my $msg = "authenticate me";

  my $tag = $ota->onetimeauth($msg, $key);
  die "message tampered!" unless $ota->verify($tag, $msg, $key);

=head1 DESCRIPTION

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

=over 4

=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 CONSTRUCTOR

=head2 new

  my $ota = Crypt::Sodium::XS::OO::onetimeauth->new(primitive => 'poly1305');
  my $ota = Crypt::Sodium::XS->onetimeauth;

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

=head1 ATTRIBUTES

=head2 primitive

  my $primitive = $ota->primitive;
  $ota->primitive('poly1305');

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::onetimeauth->primitives;
  my @primitives = $ota->primitives;

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

Can be called as a class method.

=head2 PRIMITIVE

  my $primitive = $ota->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 init

  my $multipart = $ota->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 keygen

  my $key = $ota->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</KEYBYTES> bytes.

=head2 verify

  my $is_valid = $ota->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.

=head2 onetimeauth

  my $tag = $ota->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 of L</KEYBYTES> bytes. It may be a
L<Crypt::Sodium::XS::MemVault>.

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

=head2 BYTES

  my $tag_size = $ota->BYTES;

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

=head2 KEYBYTES

  my $key_size = $ota->KEYBYTES;

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

=head1 MULTI-PART INTERFACE

A multipart onetimeauth object is created by calling the L</init> method. 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

=head1 SEE ALSO

=over 4

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

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