/*
 * This file was generated automatically by ExtUtils::ParseXS version 2.22 from the
 * contents of GMP.xs. Do not edit this file, edit GMP.xs instead.
 *
 *	ANY CHANGES MADE HERE WILL BE LOST! 
 *
 */

#line 1 "GMP.xs"
/* $Id$
 *
 * Copyright (c) 2008 Daisuke Maki <daisuke@endeworks.jp>
 */

#ifndef __CRYPT_DH_GMP_XS__
#define __CRYPT_DH_GMP_XS__

#include "dh_gmp.h"

#define DH_G(x)       *((x)->g)
#define DH_P(x)       *((x)->p)
#define DH_PRIVKEY(x) *((x)->priv_key)
#define DH_PUBKEY(x)  *((x)->pub_key)

#define DH_G_PTR(x)       (x)->g
#define DH_P_PTR(x)       (x)->p
#define DH_PRIVKEY_PTR(x) (x)->priv_key
#define DH_PUBKEY_PTR(x)  (x)->pub_key

static
void DH_mpz_rand_set(mpz_t *v, unsigned int bits)
{
    gmp_randstate_t state;
    gmp_randinit_default(state);
    gmp_randseed_ui(state, (unsigned long) time(NULL));
    mpz_urandomb(*v, state, bits);
    gmp_randclear(state);
}

static 
char *DH_mpz2sv_str(mpz_t *v, unsigned int base, unsigned int *length)
{
    STRLEN len = 0;
    char *buf, *buf_end;

    /* len is always >= 1, and might be off (greater) by one than real len */
    len = mpz_sizeinbase(*v, base);
    Newxz(buf, len + 2, char);
    buf_end = buf + len - 1; /* end of storage (-1) */
    mpz_get_str(buf, base, *v);
    if (*buf_end == 0) {
        Renew(buf, len - 1, char); /* got one shorter than expected */
    }

    if (length != NULL)
        *length = len;

    return buf;
}

static 
char *DH_mpz2sv_str_twoc(mpz_t *v)
{
    char *buf;
    unsigned int len = 0;
    unsigned int pad = 0;

    buf = DH_mpz2sv_str(v, 2, &len);
    pad = (8 - len % 8);
    if (pad <= 0 && *buf == '1') {
        pad = 8;
    }

    if (pad > 0) {
        unsigned int ipad = 0;
        char *tmp;
        Newxz(tmp, len + pad + 1, char);
        for (ipad = 0; ipad < pad; ipad++)
            *(tmp + ipad) = '0';
        Copy(buf, tmp + pad, len + 1, char);
        Safefree(buf);
        return tmp;
    }

    return buf;
}

#endif /* __CRYPT_DH_GMP_XS__ */

#line 91 "GMP.c"
#ifndef PERL_UNUSED_VAR
#  define PERL_UNUSED_VAR(var) if (0) var = var
#endif

#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)

/* prototype to pass -Wmissing-prototypes */
STATIC void
S_croak_xs_usage(pTHX_ const CV *const cv, const char *const params);

STATIC void
S_croak_xs_usage(pTHX_ const CV *const cv, const char *const params)
{
    const GV *const gv = CvGV(cv);

    PERL_ARGS_ASSERT_CROAK_XS_USAGE;

    if (gv) {
        const char *const gvname = GvNAME(gv);
        const HV *const stash = GvSTASH(gv);
        const char *const hvname = stash ? HvNAME(stash) : NULL;

        if (hvname)
            Perl_croak(aTHX_ "Usage: %s::%s(%s)", hvname, gvname, params);
        else
            Perl_croak(aTHX_ "Usage: %s(%s)", gvname, params);
    } else {
        /* Pants. I don't think that it should be possible to get here. */
        Perl_croak(aTHX_ "Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
    }
}
#undef  PERL_ARGS_ASSERT_CROAK_XS_USAGE

#ifdef PERL_IMPLICIT_CONTEXT
#define croak_xs_usage(a,b)	S_croak_xs_usage(aTHX_ a,b)
#else
#define croak_xs_usage		S_croak_xs_usage
#endif

#endif

/* NOTE: the prototype of newXSproto() is different in versions of perls,
 * so we define a portable version of newXSproto()
 */
#ifdef newXS_flags
#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
#else
#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv)
#endif /* !defined(newXS_flags) */

#line 143 "GMP.c"

XS(XS_Crypt__DH__GMP__xs_new); /* prototype to pass -Wmissing-prototypes */
XS(XS_Crypt__DH__GMP__xs_new)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items < 3 || items > 4)
       croak_xs_usage(cv,  "class, p, g, priv_key = NULL");
    {
	char *	class = (char *)SvPV_nolen(ST(0));
	char *	p = (char *)SvPV_nolen(ST(1));
	char *	g = (char *)SvPV_nolen(ST(2));
	char *	priv_key;
#line 92 "GMP.xs"
        DH_gmp_t *dh;
#line 162 "GMP.c"
	DH_gmp_t *	RETVAL;

	if (items < 4)
	    priv_key = NULL;
	else {
	    priv_key = (char *)SvPV_nolen(ST(3));
	}
#line 94 "GMP.xs"
        Newxz(dh, 1, DH_gmp_t);
        Newxz(DH_P_PTR(dh),       1, mpz_t);
        Newxz(DH_G_PTR(dh),       1, mpz_t);
        Newxz(DH_PRIVKEY_PTR(dh), 1, mpz_t);
        Newxz(DH_PUBKEY_PTR(dh),  1, mpz_t);

        mpz_init(DH_PUBKEY(dh));
        mpz_init_set_str(DH_P(dh), p, 0);
        mpz_init_set_str(DH_G(dh), g, 0);
        if (priv_key != NULL && sv_len(ST(3)) > 0) {
            mpz_init_set_str(DH_PRIVKEY(dh), priv_key, 10);
        } else {
            mpz_init_set_ui(DH_PRIVKEY(dh), 0);
        } 

        RETVAL = dh;
#line 187 "GMP.c"
	ST(0) = sv_newmortal();
        if (RETVAL == NULL) {
            croak("RETVAL is NULL?!");
        } else {
            sv_setref_pv(ST(0), class, INT2PTR(void *, RETVAL));
        }

    }
    XSRETURN(1);
}


XS(XS_Crypt__DH__GMP_generate_keys); /* prototype to pass -Wmissing-prototypes */
XS(XS_Crypt__DH__GMP_generate_keys)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items != 1)
       croak_xs_usage(cv,  "dh");
    {
	DH_gmp_t *	dh;

        if (sv_derived_from(ST(0), "Crypt::DH::GMP")) {
            IV tmp = SvIV((SV *) SvRV(ST(0)));
            dh = INT2PTR(DH_gmp_t *, tmp);
        } else {
            croak("dh is not of type Crypt::DH::GMP");
        };
#line 117 "GMP.xs"
        if (mpz_cmp_ui(DH_PRIVKEY(dh), 0) == 0) {
            mpz_t max;

            /* not initialized, eh? */
            mpz_init(max);
            mpz_sub_ui(max, DH_P(dh), 1);
            do {
                DH_mpz_rand_set(DH_PRIVKEY_PTR(dh), mpz_sizeinbase(DH_P(dh), 2));
            } while ( mpz_cmp(DH_PRIVKEY(dh), max) > 0 );
        }

        mpz_powm( DH_PUBKEY(dh), DH_G(dh), DH_PRIVKEY(dh), DH_P(dh) );
#line 232 "GMP.c"
    }
    XSRETURN_EMPTY;
}


XS(XS_Crypt__DH__GMP_compute_key); /* prototype to pass -Wmissing-prototypes */
XS(XS_Crypt__DH__GMP_compute_key)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items != 2)
       croak_xs_usage(cv,  "dh, pub_key");
    {
	DH_gmp_t *	dh;
	char *	pub_key = (char *)SvPV_nolen(ST(1));
#line 135 "GMP.xs"
        DH_mpz_t mpz_ret;
        DH_mpz_t mpz_pub_key;
#line 254 "GMP.c"
	char *	RETVAL;
	dXSTARG;

        if (sv_derived_from(ST(0), "Crypt::DH::GMP")) {
            IV tmp = SvIV((SV *) SvRV(ST(0)));
            dh = INT2PTR(DH_gmp_t *, tmp);
        } else {
            croak("dh is not of type Crypt::DH::GMP");
        };
#line 138 "GMP.xs"
        mpz_init(mpz_ret);
        mpz_init_set_str(mpz_pub_key, pub_key, 0);
        mpz_powm(mpz_ret, mpz_pub_key, DH_PRIVKEY(dh), DH_P(dh));
        RETVAL = DH_mpz2sv_str(&mpz_ret, 10, NULL);
        mpz_clear(mpz_ret);
        mpz_clear(mpz_pub_key);
#line 271 "GMP.c"
	sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
    }
    XSRETURN(1);
}


XS(XS_Crypt__DH__GMP_compute_key_twoc); /* prototype to pass -Wmissing-prototypes */
XS(XS_Crypt__DH__GMP_compute_key_twoc)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items != 2)
       croak_xs_usage(cv,  "dh, pub_key");
    {
	DH_gmp_t *	dh;
	char *	pub_key = (char *)SvPV_nolen(ST(1));
#line 152 "GMP.xs"
        DH_mpz_t mpz_ret;
        DH_mpz_t mpz_pub_key;
#line 294 "GMP.c"
	char *	RETVAL;
	dXSTARG;

        if (sv_derived_from(ST(0), "Crypt::DH::GMP")) {
            IV tmp = SvIV((SV *) SvRV(ST(0)));
            dh = INT2PTR(DH_gmp_t *, tmp);
        } else {
            croak("dh is not of type Crypt::DH::GMP");
        };
#line 155 "GMP.xs"
        mpz_init(mpz_ret);
        mpz_init_set_str(mpz_pub_key, pub_key, 0);
        mpz_powm(mpz_ret, mpz_pub_key, DH_PRIVKEY(dh), DH_P(dh));
        RETVAL = DH_mpz2sv_str_twoc(&mpz_ret);
        mpz_clear(mpz_ret);
        mpz_clear(mpz_pub_key);
#line 311 "GMP.c"
	sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
    }
    XSRETURN(1);
}


XS(XS_Crypt__DH__GMP_priv_key); /* prototype to pass -Wmissing-prototypes */
XS(XS_Crypt__DH__GMP_priv_key)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items != 1)
       croak_xs_usage(cv,  "dh");
    {
	DH_gmp_t *	dh;
	char *	RETVAL;
	dXSTARG;

        if (sv_derived_from(ST(0), "Crypt::DH::GMP")) {
            IV tmp = SvIV((SV *) SvRV(ST(0)));
            dh = INT2PTR(DH_gmp_t *, tmp);
        } else {
            croak("dh is not of type Crypt::DH::GMP");
        };
#line 168 "GMP.xs"
        RETVAL = DH_mpz2sv_str(DH_PRIVKEY_PTR(dh), 10, NULL);
#line 341 "GMP.c"
	sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
    }
    XSRETURN(1);
}


XS(XS_Crypt__DH__GMP_pub_key); /* prototype to pass -Wmissing-prototypes */
XS(XS_Crypt__DH__GMP_pub_key)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items != 1)
       croak_xs_usage(cv,  "dh");
    {
	DH_gmp_t *	dh;
	char *	RETVAL;
	dXSTARG;

        if (sv_derived_from(ST(0), "Crypt::DH::GMP")) {
            IV tmp = SvIV((SV *) SvRV(ST(0)));
            dh = INT2PTR(DH_gmp_t *, tmp);
        } else {
            croak("dh is not of type Crypt::DH::GMP");
        };
#line 176 "GMP.xs"
        RETVAL = DH_mpz2sv_str(DH_PUBKEY_PTR(dh), 10, NULL);
#line 371 "GMP.c"
	sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
    }
    XSRETURN(1);
}


XS(XS_Crypt__DH__GMP_pub_key_twoc); /* prototype to pass -Wmissing-prototypes */
XS(XS_Crypt__DH__GMP_pub_key_twoc)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items != 1)
       croak_xs_usage(cv,  "dh");
    {
	DH_gmp_t *	dh;
	char *	RETVAL;
	dXSTARG;

        if (sv_derived_from(ST(0), "Crypt::DH::GMP")) {
            IV tmp = SvIV((SV *) SvRV(ST(0)));
            dh = INT2PTR(DH_gmp_t *, tmp);
        } else {
            croak("dh is not of type Crypt::DH::GMP");
        };
#line 184 "GMP.xs"
        RETVAL = DH_mpz2sv_str_twoc(DH_PUBKEY_PTR(dh));
#line 401 "GMP.c"
	sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
    }
    XSRETURN(1);
}


XS(XS_Crypt__DH__GMP_g); /* prototype to pass -Wmissing-prototypes */
XS(XS_Crypt__DH__GMP_g)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items < 1)
       croak_xs_usage(cv,  "dh, ...");
    {
	DH_gmp_t *	dh;
#line 192 "GMP.xs"
        STRLEN n_a;
#line 422 "GMP.c"
	char *	RETVAL;
	dXSTARG;

        if (sv_derived_from(ST(0), "Crypt::DH::GMP")) {
            IV tmp = SvIV((SV *) SvRV(ST(0)));
            dh = INT2PTR(DH_gmp_t *, tmp);
        } else {
            croak("dh is not of type Crypt::DH::GMP");
        };
#line 194 "GMP.xs"
        RETVAL = DH_mpz2sv_str(DH_G_PTR(dh), 10, NULL);
        if (items > 1) {
            mpz_init_set_str( DH_G(dh), (char *) SvPV(ST(1), n_a), 0 );
        }
#line 437 "GMP.c"
	sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
    }
    XSRETURN(1);
}


XS(XS_Crypt__DH__GMP_p); /* prototype to pass -Wmissing-prototypes */
XS(XS_Crypt__DH__GMP_p)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items < 1)
       croak_xs_usage(cv,  "dh, ...");
    {
	DH_gmp_t *	dh;
#line 205 "GMP.xs"
        STRLEN n_a;
#line 458 "GMP.c"
	char *	RETVAL;
	dXSTARG;

        if (sv_derived_from(ST(0), "Crypt::DH::GMP")) {
            IV tmp = SvIV((SV *) SvRV(ST(0)));
            dh = INT2PTR(DH_gmp_t *, tmp);
        } else {
            croak("dh is not of type Crypt::DH::GMP");
        };
#line 207 "GMP.xs"
        RETVAL = DH_mpz2sv_str(DH_P_PTR(dh), 10, NULL);
        if (items > 1) {
            mpz_init_set_str( DH_P(dh), (char *) SvPV(ST(1), n_a), 0 );
        }
#line 473 "GMP.c"
	sv_setpv(TARG, RETVAL); XSprePUSH; PUSHTARG;
    }
    XSRETURN(1);
}


XS(XS_Crypt__DH__GMP_DESTROY); /* prototype to pass -Wmissing-prototypes */
XS(XS_Crypt__DH__GMP_DESTROY)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
    if (items != 1)
       croak_xs_usage(cv,  "dh");
    {
	DH_gmp_t *	dh;

        if (sv_derived_from(ST(0), "Crypt::DH::GMP")) {
            IV tmp = SvIV((SV *) SvRV(ST(0)));
            dh = INT2PTR(DH_gmp_t *, tmp);
        } else {
            croak("dh is not of type Crypt::DH::GMP");
        };
#line 218 "GMP.xs"
#ifdef VERY_VERBOSE
        PerlIO_printf(PerlIO_stderr(), "DH->DESTROY called\n" );
#endif
        mpz_clear(DH_P(dh));
        mpz_clear(DH_G(dh));
        mpz_clear(DH_PUBKEY(dh));
        mpz_clear(DH_PRIVKEY(dh));
#ifdef VERY_VERBOSE
        PerlIO_printf(PerlIO_stderr(), "cleared mpz_t\n" );
#endif
        Safefree(DH_P_PTR(dh));
        Safefree(DH_G_PTR(dh));
        Safefree(DH_PRIVKEY_PTR(dh));
        Safefree(DH_PUBKEY_PTR(dh));
#ifdef VERY_VERBOSE
        PerlIO_printf(PerlIO_stderr(), "freed mpz_t\n" );
#endif
        Safefree(dh);
#ifdef VERY_VERBOSE
        PerlIO_printf(PerlIO_stderr(), "DH->DESTROY done\n" );
#endif
#line 521 "GMP.c"
    }
    XSRETURN_EMPTY;
}

#ifdef __cplusplus
extern "C"
#endif
XS(boot_Crypt__DH__GMP); /* prototype to pass -Wmissing-prototypes */
XS(boot_Crypt__DH__GMP)
{
#ifdef dVAR
    dVAR; dXSARGS;
#else
    dXSARGS;
#endif
#if (PERL_REVISION == 5 && PERL_VERSION < 9)
    char* file = __FILE__;
#else
    const char* file = __FILE__;
#endif

    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
    XS_VERSION_BOOTCHECK ;

        newXS("Crypt::DH::GMP::_xs_new", XS_Crypt__DH__GMP__xs_new, file);
        newXS("Crypt::DH::GMP::generate_keys", XS_Crypt__DH__GMP_generate_keys, file);
        newXS("Crypt::DH::GMP::compute_key", XS_Crypt__DH__GMP_compute_key, file);
        newXS("Crypt::DH::GMP::compute_key_twoc", XS_Crypt__DH__GMP_compute_key_twoc, file);
        newXS("Crypt::DH::GMP::priv_key", XS_Crypt__DH__GMP_priv_key, file);
        newXS("Crypt::DH::GMP::pub_key", XS_Crypt__DH__GMP_pub_key, file);
        newXS("Crypt::DH::GMP::pub_key_twoc", XS_Crypt__DH__GMP_pub_key_twoc, file);
        newXS("Crypt::DH::GMP::g", XS_Crypt__DH__GMP_g, file);
        newXS("Crypt::DH::GMP::p", XS_Crypt__DH__GMP_p, file);
        newXS("Crypt::DH::GMP::DESTROY", XS_Crypt__DH__GMP_DESTROY, file);
#if (PERL_REVISION == 5 && PERL_VERSION >= 9)
  if (PL_unitcheckav)
       call_list(PL_scopestack_ix, PL_unitcheckav);
#endif
    XSRETURN_YES;
}

