#include <crypto/crypto.h>

NTL_CLIENT


ostring i2osp(const ZZ& x, long l)
{
        ostring s;

        if(x < 0 || NumBytes(x) > l)
		throw Int_overflow_error();

	s.resize(l);

        BytesFromZZ(s.data(), x, l);

	reverse(s);

        return s;
}

ZZ os2ip(const ostring& str)
{
	ZZ res;
	ostring s;

	s = str;
	reverse(s);

	res = ZZFromBytes(s.data(), s.size());	

	return res;
}


ostring poly2osp(const GF2X& x, long l)
{
        ostring s;

        if(NumBytes(x) > l)
		throw Int_overflow_error();

	s.resize(l);

        BytesFromGF2X(s.data(), x, l);

	reverse(s);

	return s;
}

GF2X os2polyp(const ostring& str)
{
	GF2X res;
	ostring s;

	s = str;
	reverse(s);

	res = GF2XFromBytes(s.data(), s.size());	

	return res;
}


void dump(const ostring& s)
{
   int i, n;

   n = s.size();

   cout << "[ ";
   for (i = 0; i < n; i++)
      cout << ((int) s[i]) << " ";
   cout << "]";

}

static const char
hex_digits[] = "0123456789abcdef";

void dumphex(const ostring& s)
{
        int i,n;
        unsigned int x;

        n = s.size();

        cout << "[ ";
        for(i = 0;i < n; i++)
        {
                x = (((unsigned int)s[i]) & 0xf0);
                x >>= 4;
                cout << hex_digits[x];
                x = (((unsigned int)s[i]) & 0x0f);
                cout << hex_digits[x] << " ";
        }
        cout << "]" << endl;
}

void prettyprint(ostream& f, const ostring& s)
{
        int i,n;
        unsigned int x;

        n = s.size();

	if (n == 0) {
		f << "null";
		return;
	}

	f << "0x";

        for(i = 0;i < n; i++)
        {
                x = (((unsigned int)s[i]) & 0xf0);
                x >>= 4;
                f << hex_digits[x];
                x = (((unsigned int)s[i]) & 0x0f);
                f << hex_digits[x];
        }
}

void prettyprint(ostream& f, const ZZ& s)
{
	ZZ t;

	if (s < 0) {
		f << "-";
		t = -s;
	}
	else
		t = s;

	if (t == 0)
		f << "0x0";
	else 
		prettyprint(f, i2osp(t, NumBytes(t)));
}

void prettyprint(ostream& f, const GF2X& s)
{
	if (s == 0)
		f << "0x0";
	else 
		prettyprint(f, poly2osp(s, NumBytes(s)));
}


// Works only when str1 and str2 have same lengths
ostring Xor(const ostring& str1, const ostring& str2)
{
	int i;
	long len;
	ostring retstr;

	// Could throw an exception here
	if(str1.size() != str2.size())
		throw General_error();

	len = str1.size();

	retstr.resize(len);
	for(i = 0;i < len; i++)
		retstr[i] = str1[i] ^ str2[i];

	return retstr;
}


ZZ hex_to_ZZ(const ostring& val)
{
        int i;
        octet ch;
        ZZ x; 

        x = 0;

        for(i = 0; i < val.size(); i++)
        {
                ch = val[i];
		x <<= 4;
		x += hex_to_int(ch);
        }

        return x;
}


int hex_to_int(octet ch)
{
        if(ch >= '0' && ch <= '9')
                return ch - '0';
        if(ch >= 'A' && ch <= 'F')
                return 10 + ch - 'A';
        if(ch >= 'a' && ch <= 'f')
                return 10 + ch - 'a';

	throw General_error();
}

void printostring(ostream& f, const ostring& s)
{
        int i,n;
        unsigned int x;

        n = s.size();

        if (n == 0) {
                f << "Empty string";
                return;
        }

        for(i = 0;i < n; i++)
                f << s[i];
}

