package Crypt::secp256k1;

our $VERSION = '0.0_02';
$VERSION = eval $VERSION;

use 5.006000;
use strict;
use warnings;

=head1 NAME

Crypt::secp256k1 - Perl interface to libsecp256k1

=head1 SYNOPSIS

  use Crypt::secp256k1;
  my $ctx = Crypt::secp256k1->new(SECP256K1_CONTEXT_SIGN);
  $ctx->randomize($random_32byte_string);
  my $bad_secret = pack "C32", map { int rand 256 } 1..32;
  my $public = $ctx->pubkey_create($bad_secret);

=head1 DESCRIPTION

Handle keys, sign hashes and verify signatures using the secp256k1
protocol by extending Bitcoin Core's
L<libsecp256k1|https://github.com/bitcoin-core/secp256k1> to perl.

=head1 BUGS

... that I know of.

=over

=item * Scalars' lengths are not checked when mapping to C.

=item * Very little testing has been done.

=item * Makefile.PL makes no attempt to find the library or header
files.

=back

=head1 EXPORT

None by default. All exportable constants may be imported by using
this module with C<:all>.

=head2 Exportable constants

=over

=item SECP256K1_CONTEXT_NONE

=item SECP256K1_CONTEXT_SIGN

=item SECP256K1_CONTEXT_VERIFY

=item SECP256K1_EC_COMPRESSED

=item SECP256K1_EC_UNCOMPRESSED

=back

=cut

require Exporter;

our @ISA = qw(Exporter);

our %EXPORT_TAGS = ( 'all' => [ qw(
    SECP256K1_CONTEXT_NONE
    SECP256K1_CONTEXT_SIGN
    SECP256K1_CONTEXT_VERIFY
    SECP256K1_EC_COMPRESSED
    SECP256K1_EC_UNCOMPRESSED
) ] );

our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );

our @EXPORT = qw();

=head1 PERL/C API

Apart from making the method call/return signature more perl-like, the
API exactly follows the C API defined in L<secp256k1.h>. See that file
for more detail on each method's usage.

The changes made to fit into a perl-like model are:

=over

=item * Methods which can fail will C<croak()> if they do so.

=item * Methods which output a key/signature/etc. will return a simple
scalar.

=item * Methods which require a key/signature/etc. require a simple
scalar holding as many bytes as the specification requires.

=item * Methods which modified their arguments in-place now return a
new simple scalar and leave the original alone.

=item * C<randomize()> returns the context object so that it can be
chained in the constructor:

    my $context = Crypt::secp256k1->new($flags)->randomize($seed);

=back

=head1 CONSTRUCTION & CONTEXT METHODS

All operations require a context object to work on. Contexts are
created like a normal perl object and can be cloned. The model
nevertheless closely follows the C model.

=over

=item Crypt::secp256k1->new([flags]) => $context

Create a new context for secp256k1 operations. C<flags> can be any
combination of the C<SECP256K1_CONTEXT_*> constants. Some operations
require that a SIGN or VERIFY context (or both) be used.

=item $context->clone() => $context

Clone the context into a new context object.

=item $context->randomize(seed) => $context

Updates the context randomization to protect against side-channel
leakage.

This returns the context object it was called on so that it may be
called in-line in the constructor.

=item $context->set_error_callback($callback)

Set a callback function to be called when an internal consistency
check fails. The default is crashing.

=item $context->set_illegal_callback($callback)

Set a callback function to be called when an illegal argument is
passed to an API call. It will only trigger for violations that are
mentioned explicitly in the header.

=back

=head1 PRIVATE KEY METHODS

Yes there are 3 privkey_* methods and 1 seckey_* method. No I haven't
decided what to do about it.

There is no method for creating a secret key. Any means of creating 32
random bytes and stuffing them in a scalar will do. Beware
encoding/unicode issues.

For example to simply create a key from an unsafe random source, use:

    my $secret = pack "C32", map { int rand 256 } 1..32;

Which packs a list of 32 random integers (between 0 and 255) into a
32-byte simple scalar.

=over

=item $context->privkey_negate($seckey) => $seckey

Negates a private key in place.

=item $context->privkey_tweak_add($seckey, $tweak) => $seckey

Tweak a private key by adding tweak to it.

=item $context->privkey_tweak_mul($seckey, $tweak) => $seckey

Tweak a private key by multiplying it by a tweak.

=item $context->seckey_verify($seckey) => $boolean

Verify an ECDSA secret key.

=back

=head1 PUBLIC KEY METHODS

=over

=item $context->pubkey_combine(@pubkeys) => $pubkey

Add a number of public keys together.

=item $context->pubkey_create($seckey) => $pubkey

Compute the public key for a secret key.

=item $context->pubkey_negate($pubkey) => $pubkey

Negates a public key in place.

=item $context->pubkey_parse($variable_pubkey) => $pubkey

Parse a variable-length public key into the pubkey object.

=item $context->pubkey_serialize($pubkey, $flags) => $serialized_pubkey

Serialize a pubkey object into a serialized byte sequence.

=item $context->pubkey_tweak_add($pubkey, $tweak) => $pubkey

Tweak a public key by adding tweak times the generator to it.

=item $context->pubkey_tweak_mul($pubkey, $tweak) => $pubkey

Tweak a public key by multiplying it by a tweak value.

=back

=head1 SIGNATURE & VERIFICATION METHODS

=over

=item $context->sign($seckey, $hash, [$nonce_callback]) => $signature

Create an ECDSA signature.

=item $context->signature_normalize($abnormal_signature) => $signature

Convert a signature to a normalized lower-S form.

=item $context->signature_parse_compact($compact_signature) => $signature

Parse an ECDSA signature in compact (64 bytes) format.

=item $context->signature_parse_der($der_signature) => $signature

Parse a DER ECDSA signature.

=item $context->signature_serialize_compact($compact_signature) => $serialized_signature

Serialize an ECDSA signature in compact (64 byte) format.

=item $context->signature_serialize_der($der_signature) => $serialized_signature

Serialize an ECDSA signature in DER format.

=item $context->verify($signature, $hash, $pubkey) => $boolean

Verify an ECDSA signature.

=back

=cut

require XSLoader;
XSLoader::load('Crypt::secp256k1', $VERSION);

1;

=head1 SEE ALSO

L<https://github.com/bitcoin-core/secp256k1>

=head1 AUTHOR

Matthew King, E<lt>chohag@jtan.comE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2017 by Matthew King

This library is free software; you can redistribute it and/or modify
it under the terms of the WTFPL version 2 or, at your option, any
version of any license you may have available.

=cut
