/* 
   borZoi - An Elliptic Curve Cryptography Library

   Copyright (C) 2001 Anthony Mulcahy

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   \You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  

*/


#include "borzoi_util.h"


#ifndef BORZOI_H
#define BORZOI_H

typedef unsigned char OCTET;
typedef std::vector<OCTET> OCTETSTR;

// Abstract base class
class borZoi {
public:
	virtual std::ostream& put (std::ostream&s) const = 0;
};

inline std::ostream& operator<< (std::ostream&s, borZoi& b) { return b.put (s); }


// Elliptic Curve Domain Parameters
class EC_Domain_Parameters : public borZoi{
public:
	unsigned long m; // a positive integer, specifying the field GF(2^m)
	int basis; // Gaussia(1), Trinomial(2), Pentanomial(3)
	unsigned long trinomial_k; // x^m + x^k +1
	unsigned long pentanomial_k3; // x^m + x^k3 + x^k2 + x^k1 +1
	unsigned long pentanomial_k2; // x^m + x^k3 + x^k2 + x^k1 +1
	unsigned long pentanomial_k1; // x^m + x^k3 + x^k2 + x^k1 +1
	F2M a; // an element of GF(2^m), E: y^2 + xy = x^3 + ax^2 + b
	F2M b; // an element of GF(2^m), E: y^2 + xy = x^3 + ax^2 + b
	BigInt r; // a positive prime integer dividing the number of points on E
	Point G; // a point on E of order r;
	BigInt k; // a positive prime integer, k = #E/r

	inline EC_Domain_Parameters () {}
	inline EC_Domain_Parameters (unsigned long m_val,
			int basis_val, unsigned long tri_k_val,
			const Curve& c_val, const BigInt& r_val,
			const Point& G_val, const BigInt& k_val) { m=m_val; basis=basis_val; trinomial_k = tri_k_val; a=c_val.a2; b=c_val.a6; r=r_val; G=G_val; k=k_val; }
	inline EC_Domain_Parameters (unsigned long m_val,
			int basis_val, unsigned long pen_k3_val,
			unsigned long pen_k2_val, 
			unsigned long pen_k1_val, const Curve& c_val, 
			const BigInt& r_val, const Point& G_val, const BigInt& k_val) { m=m_val; basis=basis_val; pentanomial_k3 = pen_k3_val; pentanomial_k2 = pen_k2_val; pentanomial_k1 = pen_k1_val; a=c_val.a2; b=c_val.a6; r=r_val; G=G_val; k=k_val; }

	bool valid ();

	EC_Domain_Parameters& operator= (const EC_Domain_Parameters& dp);
	std::ostream& put (std::ostream&s) const;
};


// Elliptic Curve Secret Key
class ECSecKey {
public:
	EC_Domain_Parameters dp;
	BigInt s; // the secret key

	ECSecKey (const EC_Domain_Parameters& ecdp); // generate a random secret key
	ECSecKey (const EC_Domain_Parameters& ecdp, const BigInt& ecs);

	ECSecKey& operator= (const ECSecKey& kp);
};


// Elliptic Curve Public Key
class ECPubKey {
public:
	EC_Domain_Parameters dp; // the EC domain parameters for this key pair
	Point W; // the public key

	inline ECPubKey () {};
	ECPubKey (const ECSecKey& sk);
	ECPubKey (const EC_Domain_Parameters& dp, const Point& W);

	bool valid (); // return true iff the public key is valid
	ECPubKey& operator= (const ECPubKey& kp);
};


// Hash Functions
OCTETSTR SHA1 (const OCTETSTR& x);
OCTETSTR SHA1 (const std::string& x);
OCTETSTR SHA1 (BigInt x);


// Key Derivation Function 2 from p1363 (FIXME not fully implemented yet)
// Throws borzoiException for invalid output lengths
OCTETSTR KDF2 (OCTETSTR Z, OCTETSTR::size_type oLen, OCTETSTR P);

//  HMAC message authentication code from p1363 (FIXME not fully implemented yet)
OCTETSTR MAC1 (OCTETSTR KB, OCTETSTR M);


/********** Symmetric Encryption / Decryption **********/

// Advanced Encryption Symmetric (AES) encryption algorithm in Cipher Block 
// Chaining (CBC) mode with a null initialization vector
// Returns the encrypted cipher text
OCTETSTR AES_CBC_IV0_Encrypt (OCTETSTR KB, OCTETSTR M, int keysize=128);


// Advanced Encryption Symmetric (AES) decryption algorithm in Cipher Block 
// Chaining (CBC) mode with a null initialization vector
// Returns the decrypted plain text or else throws borzoiException
OCTETSTR AES_CBC_IV0_Decrypt (OCTETSTR KB, OCTETSTR C, int keysize=128);


/********** Elliptic Curve Algorithms **********/


// Elliptic Curve Secret Value Derivation Primitive, Diffie-Hellman version
// Throws borzoiException if the point P is zero
F2M ECSVDP_DH (const EC_Domain_Parameters& dp, const BigInt& s, const Point& Wi);


// Elliptic Curve Key Agreement Scheme, Diffie-Hellman
OCTETSTR ECKAS_DH1 (const EC_Domain_Parameters& dp, const BigInt& s, const Point& Wi);
OCTETSTR ECKAS_DH1 (const EC_Domain_Parameters& dp, const BigInt& s, const Point& Wi, const OCTETSTR& P);


// Elliptic Curve Digital Signature Algorithm
class ECDSA : public borZoi {
public:
	BigInt c;
	BigInt d;

	inline ECDSA () {}
	ECDSA (const BigInt& cval, const BigInt& dval);
	ECDSA (const ECSecKey& sk, const BigInt& f);
	bool verify (const ECPubKey& pk, const BigInt& f);
	std::ostream& put (std::ostream&s) const;
	ECDSA& operator= (const ECDSA& esig);
};


// Elliptic Curve Integrated Encryption System
class ECIES : public borZoi {
public:
	ECPubKey V;
	OCTETSTR C; // Ciphertext
	OCTETSTR T; // Tag;

	inline ECIES () {}
	inline ECIES (ECPubKey V_val, OCTETSTR C_val, OCTETSTR T_val) { V=V_val; C=C_val; T=T_val;}
	ECIES (OCTETSTR& M, ECPubKey& pk);
	OCTETSTR decrypt (ECSecKey& sk); // Throws borzoiException if the tag is invalid
	std::ostream& put (std::ostream&s) const;
};


/********** Data Formats **********/
class DER : public borZoi {
public:
	inline DER (OCTETSTR vin) { v=vin; } // set v = to vin
	DER (ECPubKey pk); // encode a public key
	DER (ECSecKey sk); // encode a secret key
	DER (ECDSA sig); // encode a signature
	DER (ECIES ct); // encode an ECIES ciphertext FIXME 

	ECPubKey toECPubKey (); // convert a DER string to an EC public key
	ECSecKey toECSecKey (); // convert a DER string to an EC secret key
	ECDSA toECDSA (); // convert a DER string to an ECDSA signature
	ECIES toECIES (); // convert a DER string to an ECIES ciphertext FIXME 
	DER& operator= (const DER& d);
	std::ostream& put (std::ostream&s) const;
	OCTETSTR v;

private:
};


#endif	// BORZOI_H
