Bignum.xs   [plain text]


#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include <openssl/ssl.h>
#include <openssl/bn.h>

#define checkOpenSslCall( result ) if( ! ( result ) ) \
  croak( "OpenSSL error: %s", ERR_reason_error_string( ERR_get_error() ) );

SV* new_obj( SV * p_proto, void* obj )
{
    return sv_2mortal( sv_bless( newRV_noinc( newSViv( (IV)obj ) ),
                                 ( SvROK( p_proto )
                                   ? SvSTASH( SvRV( p_proto ) )
                                   : gv_stashsv( p_proto, 1 ) ) ) );
}

#define proto_obj( obj ) new_obj( ST(0), obj )

BIGNUM* sv2bn( SV* sv )
{
    if( ! SvROK( sv ) )
    {
      croak( "argument is not a Crypt::OpenSSL::Bignum object" );
    }
    return (BIGNUM*) SvIV( SvRV( sv ) );
}

MODULE = Crypt::OpenSSL::Bignum      PACKAGE = Crypt::OpenSSL::Bignum   PREFIX=BN_

BOOT:
    ERR_load_crypto_strings();

void
_free_BN(self)
    BIGNUM* self;
  CODE:
    BN_clear_free( self );

BIGNUM*
new_from_word(p_proto, p_word)
    SV* p_proto;
    unsigned long p_word;
  PREINIT:
    BIGNUM* bn;
  CODE:
    checkOpenSslCall( bn = BN_new() );
    checkOpenSslCall( BN_set_word( bn, p_word ) );
    RETVAL = bn;
  OUTPUT:
    RETVAL

BIGNUM*
new_from_decimal(p_proto, p_dec_string)
    SV* p_proto;
    char* p_dec_string;
  PREINIT:
    BIGNUM* bn;
  CODE:
    bn = NULL;
    checkOpenSslCall( BN_dec2bn( &bn, p_dec_string ) );
    RETVAL = bn;
  OUTPUT:
    RETVAL

BIGNUM*
new_from_hex(p_proto, p_hex_string)
    SV* p_proto;
    char* p_hex_string;
  PREINIT:
    BIGNUM* bn;
  CODE:
    bn = NULL;
    checkOpenSslCall( BN_hex2bn( &bn, p_hex_string ) );
    RETVAL = bn;
  OUTPUT:
    RETVAL

BIGNUM*
new_from_bin(p_proto, p_bin_string_SV)
    SV* p_proto;
    SV* p_bin_string_SV;
  PREINIT:
    BIGNUM* bn;
    char* bin;
    STRLEN bin_length;
  CODE:
    bin = SvPV( p_bin_string_SV, bin_length );
    checkOpenSslCall( bn = BN_bin2bn( bin, bin_length, NULL ) );
    RETVAL = bn;
  OUTPUT:
    RETVAL

BIGNUM*
zero(p_proto)
    SV* p_proto;
  PREINIT:
    BIGNUM *bn;
  CODE:
    checkOpenSslCall( bn = BN_new() );
    checkOpenSslCall( BN_zero( bn ) );
    RETVAL = bn;
  OUTPUT:
    RETVAL

BIGNUM*
one(p_proto)
    SV* p_proto;
  PREINIT:
    BIGNUM *bn;
  CODE:
    checkOpenSslCall( bn = BN_new() );
    checkOpenSslCall( BN_one( bn ) );
    RETVAL = bn;
  OUTPUT:
    RETVAL



char*
to_decimal(self)
    BIGNUM* self;
  CODE:
    checkOpenSslCall( RETVAL = BN_bn2dec( self ) );
  OUTPUT:
    RETVAL
  CLEANUP:
    OPENSSL_free( RETVAL );


char*
to_hex(self)
    BIGNUM* self;
  CODE:
    checkOpenSslCall( RETVAL = BN_bn2hex( self ) );
  OUTPUT:
    RETVAL
  CLEANUP:
    OPENSSL_free( RETVAL );

SV*
to_bin(self)
    BIGNUM* self;
  PREINIT:
    char* bin;
    int length;
  CODE:
    length = BN_num_bytes( self );
    New( 0, bin, length, char );
    BN_bn2bin( self, bin );
    RETVAL = newSVpv( bin, length );
    Safefree( bin );
  OUTPUT:
    RETVAL

unsigned long
BN_get_word(self)
    BIGNUM* self;

PROTOTYPES: DISABLE

SV*
add(a, b, ...)
    BIGNUM* a;
    BIGNUM* b;
  PREINIT:
    BIGNUM *bn;
  PPCODE:
    if( items > 3 )
      croak( "usage: $bn->add( $bn2[, $target] )" );
    bn = ( items < 3 ) ? BN_new() : sv2bn( ST(2) );
    checkOpenSslCall( BN_add( bn, a, b ) );
    ST(0) = ( (items < 3 ) ? proto_obj( bn ) : ST(2) );
    XSRETURN(1);

SV*
sub(a, b, ...)
    BIGNUM* a;
    BIGNUM* b;
  PREINIT:
    BIGNUM *bn;
  PPCODE:
    if( items > 3 )
      croak( "usage: $bn->sub( $bn2[, $target] )" );
    bn = ( items < 3 ) ? BN_new() : sv2bn( ST(2) );
    checkOpenSslCall( BN_sub( bn, a, b ) );
    ST(0) = ( (items < 3 ) ? proto_obj( bn ) : ST(2) );
    XSRETURN(1);

SV*
mul(a, b, ctx, ...)
    BIGNUM* a;
    BIGNUM* b;
    BN_CTX* ctx;
  PREINIT:
    BIGNUM* bn;
  PPCODE:
    if( items > 4 )
      croak( "usage: $bn->mul( $bn2, $ctx, [, $target] )" );
    bn = ( items < 4 ) ? BN_new() : sv2bn( ST(3) );
    checkOpenSslCall( BN_mul( bn, a, b, ctx ) );
    ST(0) = ( (items < 4 ) ? proto_obj( bn ) : ST(3) );
    XSRETURN(1);

SV*
div(a, b, ctx, ...)
    BIGNUM* a;
    BIGNUM* b;
    BN_CTX* ctx;
  PREINIT:
    BIGNUM* quotient;
    BIGNUM* remainder;
  PPCODE:
    if( items > 5 )
      croak( "usage: $bn->add( $bn2, $ctx, [, $quotient [, $remainder ] ] )" );
    quotient = ( items < 4 ) ? BN_new() : sv2bn( ST(3) );
    remainder = ( items < 5 ) ? BN_new() : sv2bn( ST(4) );
    checkOpenSslCall( BN_div( quotient, remainder, a, b, ctx ) );
    ST(0) = ( (items < 4 ) ? proto_obj( quotient ) : ST(3) );
    ST(1) = ( (items < 5 ) ? proto_obj( remainder ) : ST(4) );
    XSRETURN(2);

BIGNUM*
sqr(a, ctx)
    BIGNUM* a;
    BN_CTX* ctx;
  PREINIT:
    BIGNUM* bn;
    SV* p_proto;
  CODE:
    p_proto = ST(0);
    bn = BN_new();
    checkOpenSslCall( BN_sqr( bn, a, ctx ) );
    RETVAL = bn;
  OUTPUT:
    RETVAL

SV*
mod(a, b, ctx, ...)
    BIGNUM* a;
    BIGNUM* b;
    BN_CTX* ctx;
  PREINIT:
    BIGNUM* bn;
  PPCODE:
    if( items > 4 )
      croak( "usage: $bn->add( $bn2, $ctx, [, $target] )" );
    bn = ( items < 4 ) ? BN_new() : sv2bn( ST(3) );
    checkOpenSslCall( BN_mod( bn, a, b, ctx ) );
    ST(0) = ( (items < 4 ) ? proto_obj( bn ) : ST(3) );
    XSRETURN(1);

BIGNUM*
mod_mul(a, b, m, ctx)
    BIGNUM* a;
    BIGNUM* b;
    BIGNUM* m;
    BN_CTX* ctx;
  PREINIT:
    BIGNUM* bn;
    SV* p_proto;
  CODE:
    p_proto = ST(0);
    bn = BN_new();
    checkOpenSslCall( BN_mod_mul( bn, a, b, m, ctx ) );
    RETVAL = bn;
  OUTPUT:
    RETVAL

BIGNUM*
exp(a, p, ctx)
    BIGNUM* a;
    BIGNUM* p;
    BN_CTX* ctx;
  PREINIT:
    BIGNUM* bn;
    SV* p_proto;
  CODE:
    p_proto = ST(0);
    bn = BN_new();
    checkOpenSslCall( BN_exp( bn, a, p, ctx ) );
    RETVAL = bn;
  OUTPUT:
    RETVAL

BIGNUM*
mod_exp(a, p, m, ctx)
    BIGNUM* a;
    BIGNUM* p;
    BIGNUM* m;
    BN_CTX* ctx;
  PREINIT:
    BIGNUM* bn;
    SV* p_proto;
  CODE:
    p_proto = ST(0);
    bn = BN_new();
    checkOpenSslCall( BN_mod_exp( bn, a, p, m, ctx ) );
    RETVAL = bn;
  OUTPUT:
    RETVAL

BIGNUM*
mod_inverse(a, n, ctx)
    BIGNUM* a;
    BIGNUM* n;
    BN_CTX* ctx;
  PREINIT:
    BIGNUM* bn;
    SV* p_proto;
  CODE:
    p_proto = ST(0);
    bn = BN_new();
    checkOpenSslCall( BN_mod_inverse( bn, a, n, ctx ) );
    RETVAL = bn;
  OUTPUT:
    RETVAL

BIGNUM*
gcd(a, b, ctx)
    BIGNUM* a;
    BIGNUM* b;
    BN_CTX* ctx;
  PREINIT:
    BIGNUM* bn;
    SV* p_proto;
  CODE:
    p_proto = ST(0);
    bn = BN_new();
    checkOpenSslCall( BN_gcd( bn, a, b, ctx ) );
    RETVAL = bn;
  OUTPUT:
    RETVAL

int
BN_cmp(a, b)
    BIGNUM* a;
    BIGNUM* b;

int
BN_is_zero(a)
    BIGNUM* a;

int
BN_is_one(a)
    BIGNUM* a;

int
BN_is_odd(a)
    BIGNUM* a;

BIGNUM*
copy(a)
    BIGNUM* a;
  PREINIT:
    SV* p_proto;
  CODE:
    p_proto = ST(0);
    checkOpenSslCall( RETVAL = BN_dup(a) );
  OUTPUT:
    RETVAL

IV
pointer_copy(a)
    BIGNUM* a;
  PREINIT:
  CODE:
    checkOpenSslCall( RETVAL = (IV) BN_dup(a) );
  OUTPUT:
    RETVAL

MODULE = Crypt::OpenSSL::Bignum  PACKAGE = Crypt::OpenSSL::Bignum::CTX PREFIX=BN_CTX_

BN_CTX*
BN_CTX_new(p_proto)
    SV* p_proto;
  C_ARGS:

void
_free_BN_CTX(self)
    BN_CTX* self;
  CODE:
    BN_CTX_free( self );