#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <stdio.h>
#include <openssl/rsa.h>
#include <openssl/bn.h>
#include <gmp.h>
#include <string.h>

using namespace std;

void mympz_set_bn(mpz_t z, BIGNUM *bn)
//z = bn
		{
	int i;
	mpz_set_ui(z, 0);
	i = BN_num_bits(bn) - 1;
	while (i >= 0) {
		if (BN_is_bit_set(bn, i))
			mpz_setbit(z, i);
		i--;
	}
}

int main() {
	char *nc;
	BIGNUM *nn = NULL;

	unsigned long long ur, umr;

	nn =  BN_new();
	BN_hex2bn(&nn, "D5F67582105D561E2D76FDCF01DD1F8EE7F06BA22D36DFAD78B943DF37BBEBA7230CD966EEC349EBFA9B7CBE89EF3F10101864AD7C61E34F70786C28C15A5417");
	nc = BN_bn2hex(nn);
	printf("   n =  0x%s\n", nc);
	mpz_t mn, mt;
	mpz_init(mn);
	mpz_init(mt);
	mympz_set_bn(mn, nn);
	cout << "   n =    ";
	mpz_out_str(stdout, -16, mn);
	cout << endl;

	int j = 0;
	for (unsigned long i = 0xfff0ffff ; i < 0x200000000; i++)
	{
		ur = BN_mod_word(nn, (BN_ULONG) i);
		mpz_mod_ui(mt, mn, i);
		umr = mpz_get_ui(mt);
		if ( ur != umr)
		{
		cout << " n%i BN " << std::hex << std::setw(12) << ur;
		cout << " i " << std::hex << std::setw(8) << i;

		cout << " n%i MPZ " << std::hex << std::setw(14 ) << umr;
		cout << endl;
			ur = BN_mod_word(nn, (BN_ULONG) i+1L);
			mpz_mod_ui(mt, mn, i+1L);
			umr = mpz_get_ui(mt);
		cout << " n%i BN " << std::hex << std::setw(12) << ur;
		cout << " i " << std::hex << std::setw(8) << i+1L;

		cout << " n%i MPZ " << std::hex << std::setw(14 ) << umr;
		cout << endl;
		cout << endl;
			j++;
			if (j>5) break;

		}
	}

}