#include <stdlib.h>
#include "com_scytl_math_NativeMultiExponentiator.h"
#include "mpz_jni.h"
#include "mpz_multi_powm.h"

/*
 * Class:     com_scytl_math_NativeMultiExponentiator
 * Method:    doExponentiateNative
 * Signature: ([[B[[B[BI)[B
 *
 * Performs multi exponentiation modulo the specified modulus.
 *
 * @param env the JNI environment
 * @param class the calling Java class
 * @param bases the bases, non-negative
 * @param exponents the exponents, non-negative
 * @param modulus the modulus, positive
 * @return the modMultiPow value.
 */
JNIEXPORT jbyteArray JNICALL Java_com_scytl_math_NativeMultiExponentiator_doExponentiateNative
  (JNIEnv *env, jclass class, jobjectArray bases, jobjectArray exponents, jbyteArray modulus)
{
    size_t length = (size_t)(*env)->GetArrayLength(env, bases);
    mpz_t *mbases = calloc(length, sizeof(mpz_t));
    int i;
    for (i = 0; i < length; i++)
    {
        jbyteArray array = (*env)->GetObjectArrayElement(env, bases, i);
        mpz_init_set_jbyteArray(mbases[i], env, array);
    }
    mpz_t *mexponents = calloc(length, sizeof(mpz_t));
    for (i = 0; i < length; i++)
    {
        jbyteArray array = (*env)->GetObjectArrayElement(env, exponents, i);
        mpz_init_set_jbyteArray(mexponents[i], env, array);
    }
    mpz_t mmodulus;
    mpz_init_set_jbyteArray(mmodulus, env, modulus);
    mpz_t mvalue;
    mpz_init2(mvalue, mpz_sizeinbase(mmodulus, 2));

    mpz_multi_powm(mvalue, mbases, mexponents, length, mmodulus);

    jbyteArray value = mpz_get_jbyteArray(env, mvalue);

    for (i = 0; i < length; i++)
    {
        mpz_clear(mbases[i]);
    }
    free(mbases);
    for (i = 0; i < length; i++)
    {
        mpz_clear(mexponents[i]);
    }
    free(mexponents);
    mpz_clear(mmodulus);
    mpz_clear(mvalue);

    return value;
}
