#include <crypto/crypto.h>
#include <crypto/sc.h>


NTL_CLIENT

void SC1 :: PrettyPrint(ostream& tofile)
{
	tofile << "SC1(BC=";
	b.PrettyPrint(tofile);
	tofile << ")";
}

ostring SC1 :: encrypt(const ostring& key, const ostring& mssg)
{
	if (key.size() != keylen)
		throw General_error();

	int i, len;
	int padlen;
	ostring p2, m, m1, m_i, c, c0;

	padlen = b.blocklen - (mssg.size() % b.blocklen);

	p2 = ostring(padlen, octet(padlen));

	m = mssg + p2;

	len = m.size();
	c.reserve(len);

	c0 = ostring(b.blocklen, octet(0));

	for (i = 0; i < len; i+= b.blocklen)
	{
		m_i = m.substr(i, b.blocklen);
		m1 = Xor(m_i, c0);
		c0 = b.encrypt(key, m1);
		c += c0;
	}

	return c;
}

ostring SC1 :: decrypt(const ostring& key, const ostring& cipher)
{
	if (key.size() != keylen)
		throw General_error();

	int i, len;
	int padlen;
	octet ch;
	ostring mssg, m, m1, m_i, p1, c0, c_i;

	len = cipher.size();
	if(len % b.blocklen != 0)
		throw Decrypt_error();

	mssg.reserve(len);

	c0 = ostring(b.blocklen, octet(0));

	// First l-1 decryptions
        for (i = 0; i < len - b.blocklen; i+= b.blocklen)
        {
		c_i = cipher.substr(i, b.blocklen);
		m1 = b.decrypt(key, c_i);
		m_i = Xor(m1, c0);
		c0 = c_i;
		mssg += m_i;
	}

	// last decryption. m_i is M(l')
	c_i = cipher.substr(i, b.blocklen);
        m1 = b.decrypt(key, c_i);
        m_i = Xor(m1, c0);

	// P1 (ch) is the last octet of M(l')
	ch = m_i[b.blocklen - 1];
	padlen = ch;

	if(padlen < 1 || padlen > b.blocklen)
		throw Decrypt_error();

	for (i = b.blocklen - padlen; i < b.blocklen - 1; i++)
		if(ch != m_i[i])
			throw Decrypt_error();

	// Forming M(l") i.e. m1
	m1 = m_i.substr(0, b.blocklen - padlen);

	mssg = mssg + m1;

	return mssg;
}

