#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "openssl/bn.h"

BIGNUM *bn_glb0, *bn_glb1, *bn_glb3, *bn_glb5, *bn_glb6, *bn_glb7;
BIGNUM *bn_glb_a, *bn_glb_b, *bn_glb_c, *bn_glb_d, *bn_glb_e, *bn_glb_f, *bn_glb_g;
BIGNUM *bn_glb_h, *bn_glb_i, *bn_glb_j, *bn_glb_k, *bn_glb_l, *bn_glb_m;
BIGNUM *glb2pow128, *mask128, *glb2pow64, *mask64;
BN_CTX *t1;

static void RotateBytes(unsigned char *in, int n)
{
  // loop is executed atleast once, so it's not a good idea to
  // call with n=0 !!
  unsigned char *e=in+n-1;
  do {
    unsigned char temp=*in;
    *in++=*e;
    *e-- =temp;
    } while(in<e);
}

void printx(BIGNUM *bn) {
  unsigned char data[256];
  int i, len;
  memset(data, 0, 256);
  len = BN_bn2bin(bn, data);
  if(len)
    RotateBytes(data, len);
  for(i = 0; i < len; i+=4) {
    if(i != 0 && i%4 == 0)
      printf(" ");
    printf("0x%08x", *(unsigned int *)(&data[i]));
  }
  printf("\n");
}

static char *bn2str(char *str, BIGNUM *bn) {
  unsigned char data[256];
  int i, len;
  memset(data, 0, 256);
  len = BN_bn2bin(bn, data);
  if(len)
    RotateBytes(data, len);
  str[0]=0;
  for(i = 0; i < 16; i+=4) {
    if(i != 0 && i%4 == 0)
      sprintf(str, "%s ", str);
    sprintf(str, "%s%08x", str, *(unsigned int *)(&data[i]));
  }
  return str;
}

static void dump_emu(char *str) {
  char data[80], data1[80];
  printf("%s:\n", str);
  printf("0:%s  e:%s\n", bn2str(data, bn_glb0),  bn2str(data1, bn_glb_e));
  printf("1:%s  f:%s\n", bn2str(data, bn_glb1),  bn2str(data1, bn_glb_f));
  printf("3:%s  g:%s\n", bn2str(data, bn_glb3),  bn2str(data1, bn_glb_g));
  printf("5:%s  h:%s\n", bn2str(data, bn_glb5),  bn2str(data1, bn_glb_h));
  printf("6:%s  i:%s\n", bn2str(data, bn_glb6),  bn2str(data1, bn_glb_i));
  printf("7:%s  j:%s\n", bn2str(data, bn_glb7),  bn2str(data1, bn_glb_j));
  printf("a:%s  k:%s\n", bn2str(data, bn_glb_a),  bn2str(data1, bn_glb_k));
  printf("b:%s  l:%s\n", bn2str(data, bn_glb_b),  bn2str(data1, bn_glb_l));
  printf("c:%s  m:%s\n", bn2str(data, bn_glb_c),  bn2str(data1, bn_glb_m));
  printf("d:%s\n", bn2str(data, bn_glb_d));
}

mod_add(BIGNUM *arg1, BIGNUM *arg2, BIGNUM *arg3, BIGNUM *arg4)
{
  BN_add(arg1, arg2, arg3);
  if(BN_cmp(arg1, arg4) >= 0) {
    BN_sub(arg1, arg1, arg4);
  }
  BN_mask_bits(arg1, 128);
}

bn_cmplx1(BIGNUM *arg1, BIGNUM *arg2, BIGNUM *arg3,
          BIGNUM *arg4, BIGNUM *arg5)
{
  int j;
  BIGNUM *var44, *var64, *var84, *vara4;
  var44 = BN_new();
  var64 = BN_new();
  var84 = BN_new();
  vara4 = BN_new();
  BN_copy(var44, arg2);
  BN_copy(var64, arg3);
  BN_clear(vara4);
  for(j=0; j<2; j++) {
    BN_copy(var84, var64);
    BN_mask_bits(var84, 64);
    BN_rshift(var64, var64, 64);
    BN_mul(var84, var84, var44, t1);
    BN_add(vara4, vara4, var84);
    BN_copy(var84, vara4);
    BN_mask_bits(var84, 128);
    BN_mul(var84, vara4, arg4, t1);
    BN_mask_bits(var84, 64);
    BN_mul(var84, var84, arg5, t1);
    BN_add(vara4, vara4, var84);
    BN_rshift(vara4, vara4, 64);
    if(BN_cmp(vara4, arg5) >= 0) {
      BN_sub(vara4, vara4, arg5);
    }
    BN_mask_bits(vara4, 128);
  }
  BN_copy(arg1, vara4);
  BN_free(var44);
  BN_free(var64);
  BN_free(var84);
  BN_free(vara4);
}

bn_cmplx1a(BIGNUM *arg1, BIGNUM *arg2, BIGNUM *arg3,
          BIGNUM *arg4, BIGNUM *arg5)
{
  int j;
  BIGNUM *var44, *var64, *var84, *vara4;
  var44 = BN_new();
  var64 = BN_new();
  var84 = BN_new();
  vara4 = BN_new();
  BN_copy(var44, arg2);
  BN_copy(var64, arg3);
  BN_clear(vara4);
  for(j=0; j<2; j++) {
    BN_copy(var84, var64);
    BN_mask_bits(var84, 64);
    BN_rshift(var64, var64, 64);
    BN_mul(var84, var84, var44, t1);
    BN_add(vara4, vara4, var84);
    BN_copy(var84, vara4);
    BN_mask_bits(var84, 128);
    BN_mul(var84, vara4, arg4, t1);
    BN_mask_bits(var84, 64);
    BN_mul(var84, var84, arg5, t1);
    BN_add(vara4, vara4, var84);
    BN_rshift(vara4, vara4, 64);
    if(j==0 && BN_cmp(vara4, arg5) >= 0) {
      BN_sub(vara4, vara4, arg5);
    }
    BN_mask_bits(vara4, 128);
  }
  BN_copy(arg1, vara4);
  BN_free(var44);
  BN_free(var64);
  BN_free(var84);
  BN_free(vara4);
}

//uses 3, 1, glb2pow128
//sets 1, 0 (unused)
mod_sub()
{
  BN_copy(bn_glb0, bn_glb3);
  BN_mod_sub(bn_glb1, bn_glb3, bn_glb1, glb2pow128, t1);
  BN_mask_bits(bn_glb1, 128);
}

//uses 1, 3, 6
//sets  1, 0 (unused), 7(unused)
bn_func1(BIGNUM *arg0) {
  unsigned int x;

  BIGNUM *var30 = BN_new();
  BIGNUM *var50 = BN_new();
  BN_copy(var30, arg0);
  BN_mask_bits(var30, 8);
  x = BN_get_word(var30);
  BN_copy(var30,arg0);

  if( x != 0) {
    BN_clear(var50);
    BN_set_word(var50, 2);
    BN_sub(var30, var30, var50);
  } else {
    BN_clear(var50);
    BN_set_word(var50, 0xfe);
    BN_add(var30, var30, var50);
  }
  BN_copy(bn_glb7, bn_glb1);
  if(BN_is_zero(arg0)) {
    BN_clear(bn_glb7);
    BN_set_word(bn_glb7, 1);
    BN_clear(bn_glb0);

    mod_add(bn_glb1, bn_glb7, bn_glb0, bn_glb3);
    BN_free(var30);
    BN_free(var50);
    return;
  } else {
    int msb = BN_num_bits(var30) -1;
    while (msb > 0) {

      bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);
      msb--;
      if(BN_is_bit_set(var30, msb)) {

        bn_cmplx1(bn_glb1, bn_glb1, bn_glb7, bn_glb6, bn_glb3);
      }
    }
    BN_clear(bn_glb7);
    BN_set_word(bn_glb7, 1);

    bn_cmplx1(bn_glb1, bn_glb1, bn_glb7, bn_glb6, bn_glb3);
    BN_clear(bn_glb0);
  }
  BN_free(var30);
  BN_free(var50);
}

//uses 3, 6, a, b, c, l, glb2pow128
//sets 0, 1, 5, 7, a, b, c, f, g
bn_func2(int arg0)
{
  BN_copy(bn_glb1, bn_glb_b);

  mod_add(bn_glb1, bn_glb1, bn_glb1, bn_glb3);
  BN_copy(bn_glb7, bn_glb1);
  BN_copy(bn_glb5, bn_glb_c);
  BN_mask_bits(bn_glb1, 128);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb5, bn_glb6, bn_glb3);
  BN_copy(bn_glb_g, bn_glb1);
  BN_copy(bn_glb1, bn_glb7);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);
  BN_copy(bn_glb7, bn_glb_a);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb7, bn_glb6, bn_glb3);
  mod_sub();
  BN_copy(bn_glb_f, bn_glb1);
  BN_copy(bn_glb1, bn_glb7);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);
  BN_copy(bn_glb7, bn_glb1);

  mod_add(bn_glb1, bn_glb1, bn_glb1, bn_glb3);

  mod_add(bn_glb1, bn_glb1, bn_glb7, bn_glb3);
  BN_copy(bn_glb7, bn_glb1);
  BN_copy(bn_glb1, bn_glb_c);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);
  BN_copy(bn_glb5, bn_glb_l);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb5, bn_glb6, bn_glb3);

  mod_add(bn_glb1, bn_glb1, bn_glb7, bn_glb3);
  BN_copy(bn_glb7, bn_glb1);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);
  BN_copy(bn_glb0, bn_glb_f);

  mod_add(bn_glb1, bn_glb0, bn_glb1, bn_glb3);
  mod_add(bn_glb1, bn_glb0, bn_glb1, bn_glb3);
  if(arg0 == 0) {
    BN_copy(bn_glb_a, bn_glb1);
  } else {
    BN_copy(bn_glb_f, bn_glb1);
  }

  mod_add(bn_glb1, bn_glb0, bn_glb1, bn_glb3);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb7, bn_glb6, bn_glb3);
  BN_copy(bn_glb7, bn_glb1);
  BN_copy(bn_glb1, bn_glb_b);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);

  mod_add(bn_glb1, bn_glb1, bn_glb1, bn_glb3);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);

  mod_add(bn_glb1, bn_glb1, bn_glb1, bn_glb3);

  mod_add(bn_glb1, bn_glb1, bn_glb7, bn_glb3);
  mod_sub();
  if(arg0 == 0) {
    BN_copy(bn_glb_b, bn_glb1);
    BN_copy(bn_glb_c, bn_glb_g);
  } else {
    BN_copy(bn_glb_f, bn_glb1);
    BN_copy(bn_glb_f, bn_glb_g);
  }
}

//uses 3, 6, a, b, c, d, e, k
//sets 0, 1, 5, 7, a, b, c, f, g, h, i, j
bn_func3(int arg0)
{
  BN_copy(bn_glb1, bn_glb_c);
  BN_copy(bn_glb7, bn_glb1);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);

  bn_cmplx1(bn_glb0, bn_glb1, bn_glb7, bn_glb6, bn_glb3);
  BN_copy(bn_glb_f, bn_glb0);
  BN_copy(bn_glb5, bn_glb_d);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb5, bn_glb6, bn_glb3);
  BN_copy(bn_glb7, bn_glb1);
  mod_sub();
  BN_copy(bn_glb0, bn_glb_a);

  mod_add(bn_glb1, bn_glb0, bn_glb1, bn_glb3);
  BN_copy(bn_glb_g, bn_glb1);
  BN_copy(bn_glb5, bn_glb_c);

  bn_cmplx1(bn_glb0, bn_glb1, bn_glb5, bn_glb6, bn_glb3);
  if(arg0 == 0) {
    BN_copy(bn_glb_c, bn_glb0);
  } else {
    BN_copy(bn_glb_g, bn_glb0);
  }

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);
  BN_copy(bn_glb_h, bn_glb1);
  BN_copy(bn_glb0, bn_glb_a);

  mod_add(bn_glb0, bn_glb0, bn_glb7, bn_glb3);
  BN_copy(bn_glb7, bn_glb0);

  //NOTE: don't 'mod' bn_glb1, but DO 'mod' glb_i
  bn_cmplx1(bn_glb7, bn_glb1, bn_glb7, bn_glb6, bn_glb3);
  bn_cmplx1a(bn_glb1, bn_glb1, bn_glb7, bn_glb6, bn_glb3);
  BN_copy(bn_glb_i, bn_glb7);
  BN_copy(bn_glb1, bn_glb_e);
  BN_copy(bn_glb5, bn_glb_f);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb5, bn_glb6, bn_glb3);
  BN_copy(bn_glb_f, bn_glb1);
  mod_sub();
  BN_copy(bn_glb0, bn_glb_b);

  mod_add(bn_glb1, bn_glb0, bn_glb1, bn_glb3);
  BN_copy(bn_glb_j, bn_glb1);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);
  BN_copy(bn_glb0, bn_glb1);
  BN_copy(bn_glb1, bn_glb7);
  BN_copy(bn_glb7, bn_glb0);
  mod_sub();

  mod_add(bn_glb1, bn_glb1, bn_glb7, bn_glb3);
  if(arg0 == 0) {
    BN_copy(bn_glb_a, bn_glb1);
  } else {
    BN_copy(bn_glb_f, bn_glb1);
  }

  mod_add(bn_glb1, bn_glb1, bn_glb1, bn_glb3);
  mod_sub();
  BN_copy(bn_glb7, bn_glb_i);

  mod_add(bn_glb1, bn_glb1, bn_glb7, bn_glb3);
  BN_copy(bn_glb5, bn_glb_j);

  bn_cmplx1(bn_glb0, bn_glb1, bn_glb5, bn_glb6, bn_glb3);
  BN_copy(bn_glb1, bn_glb_f);
  BN_copy(bn_glb_f, bn_glb0);
  BN_copy(bn_glb7, bn_glb_b);

  mod_add(bn_glb1, bn_glb1, bn_glb7, bn_glb3);
  BN_copy(bn_glb7, bn_glb1);
  BN_copy(bn_glb1, bn_glb_g);
  BN_copy(bn_glb5, bn_glb_h);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb5, bn_glb6, bn_glb3);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb7, bn_glb6, bn_glb3);
  mod_sub();
  BN_copy(bn_glb7, bn_glb_f);

  mod_add(bn_glb1, bn_glb1, bn_glb7, bn_glb3);
  BN_copy(bn_glb5, bn_glb_k);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb5, bn_glb6, bn_glb3);
  if(arg0 == 0) {
    BN_copy(bn_glb_b, bn_glb1);
  } else {
    BN_copy(bn_glb_f, bn_glb1);
  }
}

//uses c, d, e, m
//sets 0, a, b, c
bn_cmplx7()
{
  BIGNUM *var1;
  var1 = BN_new();
  BN_copy(bn_glb0, bn_glb_c);
  if(BN_is_zero(bn_glb_c)) {
    BN_copy(bn_glb_a, bn_glb_d);
    BN_copy(bn_glb_b, bn_glb_e);
    BN_copy(bn_glb_c, bn_glb_m);
    bn_func3(1);
  } else {
    BN_clear(var1);
    BN_set_word(var1, 0xFFFFFFFF);
    BN_mask_bits(bn_glb_a, 32);
    BN_lshift(var1, bn_glb_m, 0x20);
    BN_add(bn_glb_a, bn_glb_a, var1);
    BN_mask_bits(bn_glb_a, 128);
    bn_func3(0);
  }
  BN_free(var1);
}

bn_cmplx2(BIGNUM *var1, BIGNUM *var2, BIGNUM *var3, BIGNUM *var4,
          BIGNUM *var5, BIGNUM *var6) {
  BIGNUM *var48;
  int len = BN_num_bits(var6);
  int i;
  int x;
  if(len < 2)
    return;

  if(BN_is_zero(var2) && BN_is_zero(var3) && BN_is_zero(var4))
    return;
  var48 = BN_new();
  BN_copy(bn_glb3, var1);

  BN_copy(bn_glb6, bn_glb3);
  BN_set_bit(bn_glb6, 0);
  BN_sub(bn_glb6, glb2pow128, bn_glb6);
  BN_mod_inverse(bn_glb6, bn_glb6, glb2pow64, t1);
  BN_clear(bn_glb0);
  //
  if(! BN_is_zero(bn_glb3)) {
    BN_clear(bn_glb1);
    BN_set_word(bn_glb1, 2);
    BN_clear(bn_glb_k);
    BN_set_word(bn_glb_k, 0x88);
    BN_mod_exp(bn_glb1, bn_glb1, bn_glb_k, bn_glb3, t1);
  }
  //
  for(i=0; i < 4; i++) {

    bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);
  }
  //
  BN_clear(bn_glb7);
  BN_set_word(bn_glb7, 1);
  BN_add(bn_glb0, bn_glb3, bn_glb7);
  BN_copy(bn_glb_k, bn_glb0);
  BN_rshift(bn_glb_k, bn_glb_k, 1);
  BN_copy(bn_glb7, bn_glb1);
  BN_copy(bn_glb5, bn_glb_k);
  BN_mask_bits(bn_glb5, 128);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb5, bn_glb6, bn_glb3);
  BN_copy(bn_glb_k, bn_glb1);

  BN_copy(bn_glb1, var5);
  BN_mask_bits(bn_glb1, 128);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb7, bn_glb6, bn_glb3);
  BN_copy(bn_glb_l, bn_glb1);
  BN_copy(bn_glb1, bn_glb7);
  BN_clear(bn_glb5);
  BN_set_word(bn_glb5, 1);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb5, bn_glb6, bn_glb3);
  BN_copy(bn_glb_c, bn_glb1);
  BN_copy(bn_glb_m, bn_glb1);
  BN_copy(bn_glb1, bn_glb7);

  BN_copy(bn_glb5, var2);
  BN_mask_bits(bn_glb5, 128);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb5, bn_glb6, bn_glb3);
  BN_copy(bn_glb_a, bn_glb1);
  BN_copy(bn_glb1, bn_glb7);

  BN_copy(bn_glb5, var3);
  BN_mask_bits(bn_glb5, 128);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb5, bn_glb6, bn_glb3);
  BN_copy(bn_glb_b, bn_glb1);
  BN_copy(bn_glb_d, bn_glb_a);
  BN_copy(bn_glb_e, bn_glb_b);

  x = len -1;
  while(x > 0) {
    x--;
    bn_func2(0);
    if(BN_is_bit_set(var6, x)) {
      bn_cmplx7();
    }
  }

  BN_copy(bn_glb1, bn_glb_c);
  BN_mask_bits(bn_glb1, 128);
  BN_copy(bn_glb7, bn_glb1);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb1, bn_glb6, bn_glb3);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb7, bn_glb6, bn_glb3);
  BN_clear(bn_glb7);
  BN_set_word(bn_glb7, 1);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb7, bn_glb6, bn_glb3);
  BN_copy(bn_glb0, bn_glb1);
  BN_clear(bn_glb7);
  BN_set_word(bn_glb7, 1);
  BN_copy(bn_glb1, bn_glb0);
  BN_clear(bn_glb0);
  bn_func1(var1);
  BN_copy(bn_glb5, bn_glb_b);
  BN_mask_bits(bn_glb5, 128);

  bn_cmplx1(bn_glb0, bn_glb1, bn_glb5, bn_glb6, bn_glb3);

  BN_copy(bn_glb7, bn_glb0);
  BN_copy(bn_glb5, bn_glb_c);
  BN_mask_bits(bn_glb5, 128);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb5, bn_glb6, bn_glb3);

  BN_copy(bn_glb5, bn_glb_a);
  BN_mask_bits(bn_glb5, 128);

  bn_cmplx1(bn_glb1, bn_glb1, bn_glb5, bn_glb6, bn_glb3);

  BN_clear(bn_glb5);
  BN_set_word(bn_glb5, 1);

  bn_cmplx1(bn_glb0, bn_glb1, bn_glb5, bn_glb6, bn_glb3);
  BN_copy(bn_glb_a, bn_glb0);
  BN_copy(bn_glb1, bn_glb7);

  BN_clear(bn_glb5);
  BN_set_word(bn_glb5, 1);

  bn_cmplx1(bn_glb0, bn_glb1, bn_glb5, bn_glb6, bn_glb3);
  BN_copy(bn_glb_b, bn_glb0);
  BN_free(var48);
}

void Map57(unsigned char *data) {
  BIGNUM *var38, *var58, *var78, *var98, *varb8, *vard8;
  BN_CTX *t;
  unsigned char tmpdata[256];
  unsigned char res[256];
  unsigned int *dest = (unsigned int *)res;
  unsigned int *src = (unsigned int *)data;
  int len = 0;

  t = BN_CTX_new();
  t1 = BN_CTX_new();
  BN_CTX_init(t);

  glb2pow128 = BN_new();
  BN_clear(glb2pow128);
  BN_set_bit(glb2pow128, 128);
  mask128 = BN_new();
  BN_hex2bn(&mask128, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");

  glb2pow64 = BN_new();
  BN_clear(glb2pow64);
  BN_set_bit(glb2pow64, 64);
  mask64 = BN_new();
  BN_hex2bn(&mask64, "FFFFFFFFFFFFFFFF");
  
  bn_glb0=BN_new(); BN_clear(bn_glb0);
  bn_glb1=BN_new(); BN_clear(bn_glb1);
  bn_glb3=BN_new(); BN_clear(bn_glb3);
  bn_glb5=BN_new(); BN_clear(bn_glb5);
  bn_glb6=BN_new(); BN_clear(bn_glb6);
  bn_glb7=BN_new(); BN_clear(bn_glb7);

  bn_glb_a=BN_new(); BN_clear(bn_glb_a);
  bn_glb_b=BN_new(); BN_clear(bn_glb_b);
  bn_glb_c=BN_new(); BN_clear(bn_glb_c);
  bn_glb_d=BN_new(); BN_clear(bn_glb_d);
  bn_glb_e=BN_new(); BN_clear(bn_glb_e);
  bn_glb_f=BN_new(); BN_clear(bn_glb_f);
  bn_glb_g=BN_new(); BN_clear(bn_glb_g);
  bn_glb_h=BN_new(); BN_clear(bn_glb_h);
  bn_glb_i=BN_new(); BN_clear(bn_glb_i);
  bn_glb_j=BN_new(); BN_clear(bn_glb_j);
  bn_glb_k=BN_new(); BN_clear(bn_glb_k);
  bn_glb_l=BN_new(); BN_clear(bn_glb_l);
  bn_glb_m=BN_new(); BN_clear(bn_glb_m);

  var38=BN_new(); BN_clear(var38);
  var58=BN_new(); BN_clear(var58);
  var78=BN_new(); BN_clear(var78);
  var98=BN_new(); BN_clear(var98);
  varb8=BN_new(); BN_clear(varb8);
  vard8=BN_new(); BN_clear(vard8);

  memcpy(tmpdata, data, 0x80);
  RotateBytes(tmpdata, 0x80);
  BN_bin2bn(tmpdata, 16, var78);
  BN_bin2bn(tmpdata+0x10, 16, varb8);
  BN_bin2bn(tmpdata+0x20, 16, var98);
  BN_bin2bn(tmpdata+0x40, 16, vard8);
  BN_bin2bn(tmpdata+0x60, 16, var38);
  BN_bin2bn(tmpdata+0x70, 16, var58);

  bn_cmplx2(varb8, var58, vard8, var38, var78, var98);

  memset(res, 0, 0x80);
  *dest++ = src[0x03];
  *dest++ = src[0x02];
  *dest++ = src[0x01];
  *dest++ = src[0x00];
  *dest++ = src[0x07];
  *dest++ = src[0x06];
  *dest++ = src[0x05];
  *dest++ = src[0x04];

  memset(tmpdata, 0, 0x20);
  len = BN_bn2bin(bn_glb_a, tmpdata);
  if(len) {
    RotateBytes(tmpdata, len);
  }
  src = (unsigned int *)tmpdata;
  *dest++ = src[0x03];
  *dest++ = src[0x02];
  *dest++ = src[0x01];
  *dest++ = src[0x00];

  memset(tmpdata, 0, 0x20);
  len = BN_bn2bin(bn_glb_m, tmpdata);
  if(len) {
    RotateBytes(tmpdata, len);
  }
  *dest = src[0x03];
  dest+=4;

  memset(tmpdata, 0, 0x20);
  len = BN_bn2bin(bn_glb_b, tmpdata);
  if(len) {
    RotateBytes(tmpdata, len);
  }
  *dest++ = src[0x03];
  *dest++ = src[0x02];
  *dest++ = src[0x01];
  *dest++ = src[0x00];

  dest+=4;
  src = (unsigned int *)(data+0x60);
  *dest++ = src[0x03];
  *dest++ = src[0x01];
  *dest++ = src[0x01];
  *dest++ = src[0x00];
  *dest++ = src[0x07];
  *dest++ = src[0x06];
  *dest++ = src[0x05];
  *dest++ = src[0x04];

  *(unsigned int *)(data + (8<<2))= *(unsigned int *)(res + (11<<2));
  *(unsigned int *)(data + (9<<2))= *(unsigned int *)(res + (10<<2));
  *(unsigned int *)(data + (10<<2))= *(unsigned int *)(res + (9<<2));
  *(unsigned int *)(data + (11<<2))= *(unsigned int *)(res + (8<<2));
  *(unsigned int *)(data + (12<<2))= *(unsigned int *)(res + (12<<2));
  *(unsigned int *)(data + (13<<2))= *(unsigned int *)(res + (13<<2));
  *(unsigned int *)(data + (14<<2))= *(unsigned int *)(res + (14<<2));
  *(unsigned int *)(data + (15<<2))= *(unsigned int *)(res + (15<<2));
  *(unsigned int *)(data + (16<<2))= *(unsigned int *)(res + (19<<2));
  *(unsigned int *)(data + (17<<2))= *(unsigned int *)(res + (18<<2));
  *(unsigned int *)(data + (18<<2))= *(unsigned int *)(res + (17<<2));
  *(unsigned int *)(data + (19<<2))= *(unsigned int *)(res + (16<<2));
  *(unsigned int *)(data + (20<<2))= *(unsigned int *)(res + (20<<2));
  *(unsigned int *)(data + (21<<2))= *(unsigned int *)(res + (21<<2));
  *(unsigned int *)(data + (22<<2))= *(unsigned int *)(res + (22<<2));
  *(unsigned int *)(data + (23<<2))= *(unsigned int *)(res + (23<<2));

  BN_free(glb2pow128);
  BN_free(mask128);
  BN_free(glb2pow64);
  BN_free(mask64);
  
  BN_free(bn_glb0);
  BN_free(bn_glb1);
  BN_free(bn_glb3);
  BN_free(bn_glb5);
  BN_free(bn_glb6);
  BN_free(bn_glb7);

  BN_free(bn_glb_a);
  BN_free(bn_glb_b);
  BN_free(bn_glb_c);
  BN_free(bn_glb_d);
  BN_free(bn_glb_e);
  BN_free(bn_glb_f);
  BN_free(bn_glb_g);
  BN_free(bn_glb_h);
  BN_free(bn_glb_i);
  BN_free(bn_glb_j);
  BN_free(bn_glb_k);
  BN_free(bn_glb_l);
  BN_free(bn_glb_m);

  BN_free(var38);
  BN_free(var58);
  BN_free(var78);
  BN_free(var98);
  BN_free(varb8);
  BN_free(vard8);

  BN_CTX_free(t);
  BN_CTX_free(t1);
}
