=encoding utf8

=head1 NAME

Crypt::NaCl::Sodium::sign - Public-key signatures

=head1 SYNOPSIS

    use Crypt::NaCl::Sodium qw( :utils );

    my $crypto_sign = Crypt::NaCl::Sodium->sign();

    my ($a_skey, $a_pkey, $a_key, $b_skey,
        $b_pkey, $b_key, $msg, $opened, $sealed);

    ## Alice
    ########

    # Alice generates secret keypair
    ($a_pkey, $a_skey) = $crypto_sign->keypair();

    # ... and shares the public key with Bob
    send_to( Bob => { public_key => $a_pkey } );

    # now Alice can sign her messages
    # while Bob can verify that Alice has signed them

    # a message to Bob
    $msg = "Hi Bob!";

    # Alice signs and seals the message using combined mode
    $sealed = $crypto_sign->seal( $msg, $a_skey );

    # message is ready for Bob
    send_to( Bob => { sealed => $sealed } );

    ## Bob
    ########

    # Bob generates his secret keypair
    ($b_pkey, $b_skey) = $crypto_sign->keypair();

    # ... and shares his public key with Alice
    send_to( Alice => { public_key => $b_pkey } );

    # Bob receives the public key from Alice
    $a_key = receive_for( Bob => 'public_key' );

    # Bob is now ready to receive first message from Alice
    $sealed = receive_for( Bob => 'sealed' );

    # since Bob already has Alice's public key we have all information required
    # to verify and open a message
    $opened = $crypto_sign->open( $sealed, $a_key );

    # now it is time to reply
    $msg = "Hello Alice!";

    # this time we use detached mode
    $mac = $crypto_sign->mac( $msg, $b_skey );

    # Alice needs both to verify Bob's message
    send_to( Alice => { mac => $mac } );
    send_to( Alice => { msg => $msg } );

    ## Alice
    ########

    # Alice receives the public key from Bob
    $b_key = receive_for( Alice => 'public_key' );

    # Bob used the detached mode
    $mac = receive_for( Alice => 'mac' );
    $msg = receive_for( Alice => 'msg' );

    # since we already have the message, all left to do is to verify that Bob
    # indeed has sent it
    unless ( $crypto_sign->verify($mac, $msg, $b_key) ) {
        die "Impostor alert!";
    }

    # NOTE: send_to() and receive_for() and user functions providing transport of
    # messages

=head1 DESCRIPTION

C<crypto_sign> system provides the public-key signature scheme for message
signing and verification. It is designed to meet the standard notion of
unforgeability under chosen-message attacks.

The C<crypto_sign> allows public verifiability (or receiver-assisted public verifiability)
- any holder of the message, MAC and the sender's public key can verify its
authenticity.

=head1 METHODS

=head2 keypair

    my ($public_key, $secret_key) = $crypto_sign->keypair();

    # or deterministically derived from a single key seed
    my ($public_key, $secret_key) = $crypto_sign->keypair( $seed );

Helper method to generate a random secret key and corresponding public key
to be used by C<$crypto_sign>.

See L</seed> for more details when generating key pair using given C<$seed>.

The length of the C<$public_key> equals L</PUBLICKEYBYTES>.

The length of the C<$secret_key> equals L</SECRETKEYBYTES>.

B<NOTE:> keep the secret key confidential.

Returns L<Data::BytesLocker> objects.

=head2 public_key

    my $public_key = $crypto_sign->public_key( $secret_key );

Computes the public key for corresponding secret key.

The length of the C<$public_key> equals L</PUBLICKEYBYTES>.

Returns L<Data::BytesLocker> objects.

=head2 seed

    my $seed = $crypto_sign->seed();

    my ($public_key, $secret_key) = $crypto_sign->keypair( $seed );

Helper method to generate a random seed, that can be used to deterministically
compute the key pair derived from it.

The length of the C<$seed> equals L</SEEDBYTES>.

Returns L<Data::BytesLocker> objects.

=head2 extract_seed

    my $seed = $crypto_sign->extract_seed( $secret_key );

Returns the C<$seed> extracted from given C<$secret_key>. The seed is either
random one or the one given to L</keypair> method.

The length of the C<$seed> equals L</SEEDBYTES>.

Returns L<Data::BytesLocker> objects.

=head2 to_curve25519_keypair

    my ($pkey_c25519, $skey_c25519) = $crypto_sign->to_curve25519_keypair(
                                        $public_key, $secret_key );

Ed25519 keys generated by L</keypair> could be converted to Curve25519 keys,
so that the same key pair can be used both for authenticated encryption
L<crypto_box|Crypt::NaCl::Sodium::box> and for signatures
L<crypto_sign|Crypt::NaCl::Sodium::sign>.

The length of the C<$pkey_c25519> is equal to
L<$crypto_box-E<gt>PUBLICKEYBYTES|Crypt::NaCl::Sodium::box/PUBLICKEYBYTES>.

The length of the C<$skey_c25519> is equal to
L<$crypto_box-E<gt>SECRETKEYBYTES|Crypt::NaCl::Sodium::box/SECRETKEYBYTES>.

B<NOTE:> keep the secret key confidential.

Returns L<Data::BytesLocker> objects.

=head2 seal

    # combined mode - MAC and unencrypted message stored together
    my $sealed = $crypto_sign->seal($msg, $secret_key);

Seals the plaintext message using given C<$secret_key>.

The length of the C<$sealed> is up to the length of C<$msg> + L</BYTES>.

Returns L<Data::BytesLocker> object.

=head2 mac

    # detached mode - MAC of the message returned
    my $mac = $crypto_sign->mac($msg, $secret_key);

Returns the MAC without attaching a copy of the original message to it.

The length of the C<$mac> is up to the value of L</BYTES>.

Returns L<Data::BytesLocker> object.

=head2 open

    my $msg;
    eval {
        $msg = $crypto_sign->open($sealed, $sender_public_key);
    };
    if ( $@ ) {
        warn "Message forged!";
    } else {
        print "Verified message: $msg\n";
    }

Verifies the signature of sealed message C<$sealed> and extract the plaintext
message out of it using sender's given C<$sender_public_key>.

Function croaks if the verification fails.

The length of the C<$msg> is equal to the length of C<$sealed> - length of the
prepended signature.

Returns L<Data::BytesLocker> object.

=head2 verify

    unless ( $crypto_sign->verify( $mac, $msg, $sender_public_key ) ) {
        die "Impostor alert!";
    }

Verifies the integrity and authenticity of the C<$msg> using given C<$mac> and
C<$sender_public_key>.

Method returns true if message has been verified, false otherwise.

=head1 CONSTANTS

=head2 SECRETKEYBYTES

    my $skey_length = $crypto_sign->SECRETKEYBYTES;

Returns the length of secret key.

=head2 PUBLICKEYBYTES

    my $pkey_length = $crypto_sign->PUBLICKEYBYTES;

Returns the length of public key.

=head2 SEEDBYTES

    my $seed_length = $crypto_sign->SEEDBYTES;

Returns the length of seed key.

=head2 BYTES

    my $max_mac_length = $crypto_sign->BYTES;

Returns the maximum length of the MAC.

=head1 ALGORITHM DETAILS

C<crypto_sign> is implemented using Ed25519, which has several attractive
features: fast signing and verification, high security level comparable to
AES-128, small keys and signatures, and is immune to side-channel attacks.

=head1 SEE ALSO

=over 4

=item * L<Data::BytesLocker> - guarded data storage

=item * L<Crypt::Ed25519>

=item * L<Ed25519: high-speed high-security signatures|http://ed25519.cr.yp.to/>

=back

=head1 AUTHOR

Alex J. G. Burzyński <F<ajgb@cpan.org>>

=head1 COPYRIGHT & LICENSE

Copyright (c) 2015 Alex J. G. Burzyński. All rights reserved.

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

=cut
