/**
 * \file parsing.c
 * \brief Implementation of parsing.h
 */

#include "parameters.h"
#include "parsing.h"
#include "ffi_vec.h"
#include "ffi_mat.h"

/**
 * \fn void piglet1_secret_key_to_string(unsigned char* sk, const unsigned char* seed1, const unsigned char* seed2, const unsigned char* pk)
 * \brief This function parses a secret key into a string
 *
 * The secret key is composed of the the vector <b>g</b> and matrix <b>X</b>.
 *
 * \param[out] sk String containing the secret key
 * \param[in] seed1 Seed for matrix X
 * \param[in] seed2 Seed for vector g
 */
void piglet1_secret_key_to_string(unsigned char* sk, const unsigned char* seed1, const unsigned char* seed2, const unsigned char* pk)
{
	memcpy(sk, seed1, SK_SEED_LEN);	
    memcpy(sk + SK_SEED_LEN, seed2, GD_SEED_LEN);
	memcpy(sk + SK_SEED_LEN + GD_SEED_LEN, pk, PUBLIC_KEY_BYTES);
}

/**
 * \fn void piglet1_secret_key_from_string(ffi_mat& X, ffi_vec& g, const unsigned char* sk)
 * \brief This function parses a secret key from a string
 *
 * The secret key is composed of the seed used to generate matrix <b>X</b> and vector <b>g</b>.
 * \param[out] X Matrix for decryption
 * \param[out] g Vector to generate code
 * \param[in] sk String containing the secret key
 */
void piglet1_secret_key_from_string(ffi_vec* x, ffi_vec* y, ffi_vec& g, const unsigned char* sk)
{
  unsigned char sk_seed[SK_SEED_LEN];
  memcpy(sk_seed, sk, SK_SEED_LEN);
  AES_XOF_struct* sk_seedexpander = (AES_XOF_struct*) malloc(sizeof(AES_XOF_struct));
  seedexpander_init(sk_seedexpander, sk_seed, sk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
  ffi_vec F;
  F.SetLength(PARAM_W);
  ffi_vec_set_random_full_rank_with_one_using_seedexpander(F, PARAM_W, sk_seedexpander);
  for(int i = 0; i < PARAM_K; i++)
  {
	ffi_vec_set_random_from_support_using_seedexpander(x[i], PARAM_R, F, PARAM_W, sk_seedexpander);
	ffi_vec_set_random_from_support_using_seedexpander(y[i], PARAM_R, F, PARAM_W, sk_seedexpander);
  }

  unsigned char g_seed[SK_SEED_LEN];
  memcpy(g_seed, sk + SK_SEED_LEN, GD_SEED_LEN);

  ffi_vec_set_random_full_rank_using_shake256(g, PARAM_R, g_seed, GD_SEED_LEN);

  free(sk_seedexpander);
}

/**
 * \fn void piglet1_public_key_to_string(unsigned char* pk, const unsigned char* seed, const ffi_mat m, const unsigned char* vec_seed)
 * \brief This function parses a public key into a string
 *
 * The public key is composed of matrix <b>Q</b> as well as the seed used to generate vector <b>g</b> and matrix <b>H</b>.
 *
 * \param[out] pk String containing the public key
 * \param[in] seed Seed for H
 * \param[in] vec_seed Seed to generate code
 * \param[in] m Matrix Q=H*X+Y
 */
void piglet1_public_key_to_string(unsigned char* pk, const unsigned char* seed, const ffi_vec* s, const unsigned char* g_seed)
{
	for(int i = 0; i < PARAM_K; i++)
	{
		ffi_vec_to_string(pk + VEC_R_BYTES*i, s[i], PARAM_R);
	}
    memcpy(pk + VEC_R_BYTES*PARAM_K, g_seed, GD_SEED_LEN);
    memcpy(pk + VEC_R_BYTES*PARAM_K + GD_SEED_LEN, seed, PK_SEED_LEN);
}

/**
 * \fn void piglet1_public_key_from_string(unsigned char* seed, ffi_mat& m, unsigned char* vec_seed, const unsigned char* pk)
 * \brief This function parses a public key from a string
 *
 * The public key is composed of matrix <b>Q</b> as well as the seed used to generate vector <b>g</b> and matrix <b>H</b>.
 *
 * \param[out] seed Seed for H
 * \param[out] vec_seed Seed to generate code
 * \param[out] m Matrix Q=H*X+Y
 * \param[in] pk String containing the public key
 */
void piglet1_public_key_from_string(ffi_vec* H, ffi_vec* s, unsigned char* vec_seed, const unsigned char* pk)
{
	for(int i = 0; i < PARAM_K; i++)
	{
		ffi_vec_from_string(pk + VEC_R_BYTES*i, s[i], PARAM_R);
	}
    memcpy(vec_seed, pk + VEC_R_BYTES*PARAM_K, GD_SEED_LEN);

	unsigned char pk_seed[SK_SEED_LEN];
	memcpy(pk_seed, pk + VEC_R_BYTES*PARAM_K + GD_SEED_LEN, SK_SEED_LEN);
	AES_XOF_struct* pk_seedexpander = (AES_XOF_struct*) malloc(sizeof(AES_XOF_struct));
	seedexpander_init(pk_seedexpander, pk_seed, pk_seed + 32, SEEDEXPANDER_MAX_LENGTH);
	for(int i = 0; i < PARAM_K; i++)
	{
		for(int j = 0; j < PARAM_K; j++)
		{
			ffi_vec_set_random_using_seedexpander(H[i*PARAM_K + j], PARAM_R, pk_seedexpander); 
		}
	}
	free(pk_seedexpander);
}

/**
 * \fn void piglet1_kem_ciphertext_to_string(unsigned char* ct, const ffi_mat& c1, const ffi_mat& c2, const unsigned char *d)
 * \brief This function parses a ciphertext into a string
 *
 * The ciphertext is composed of matrices C1 and C2.
 *
 * \param[out] ct String containing the ciphertext
 * \param[in] c1 ffi_mat representation of matrix C1
 * \param[in] c2 ffi_mat representation of matrix C2
 */
void piglet1_kem_ciphertext_to_string(unsigned char* ct, const ffi_vec* u, const ffi_vec v, const unsigned char *d)
{
	for(int i = 0; i < PARAM_K; i++)
	{
		ffi_vec_to_string(ct + i * VEC_R_BYTES, u[i], PARAM_R);
	}
	ffi_vec_to_string(ct + PARAM_K * VEC_R_BYTES, v, PARAM_R);
	memcpy(ct + PARAM_K * VEC_R_BYTES + VEC_R_BYTES, d, SHA512_BYTES);
}

/**
 * \fn void piglet1_kem_ciphertext_from_string(const unsigned char* ct, ffi_mat& c1, ffi_mat& c2, unsigned char* d)
 * \brief This function parses a ciphertext from a string
 *
 * The ciphertext is composed of matrices C1 and C2.
 *
 * \param[out] c1 ffi_mat representation of matrix C1
 * \param[out] c2 ffi_mat representation of matrix C2
 * \param[in] ct String containing the ciphertext
 */

void piglet1_kem_ciphertext_from_string(const unsigned char* ct, ffi_vec* u, ffi_vec& v, unsigned char* d)
{
	for(int i = 0; i < PARAM_K; i++)
	{
		ffi_vec_from_string(ct + i * VEC_R_BYTES, u[i], PARAM_R);
	}
	ffi_vec_from_string(ct + PARAM_K * VEC_R_BYTES, v, PARAM_R);
	memcpy(d, ct + PARAM_K * VEC_R_BYTES + VEC_R_BYTES, SHA512_BYTES);
}

