#ifndef OPOW_CRYPTO_HEAVYHASH_H
#define OPOW_CRYPTO_HEAVYHASH_H

#include <stdint.h>
#include <stdlib.h>
#include "sha3.h"

//#include <memory>
//#include "obtc.h"


#define OUTPUT_SIZE 32

typedef struct class_CSHA3_256 CSHA3_256;

struct class_CSHA3_256
{
    sha3_ctx_t context;

 //   static const size_t OUTPUT_SIZE = 32;
	
    //CSHA3_256& Write(const unsigned char* data, size_t len);
    void (*Write)(struct class_CSHA3_256 *p, const unsigned char* data, size_t len);
    void (*Finalize)(struct class_CSHA3_256 *p, unsigned char hash[OUTPUT_SIZE]);
	//CSHA3_256& Reset();
};


typedef struct class_CHeavyHash CHeavyHash;
struct class_CHeavyHash
{

    uint64_t matrix[64*64];
    CSHA3_256 hasher;

	//static const size_t OUTPUT_SIZE = 32;
    //explicit CHeavyHash(uint64_t matrix_[64*64]);
    //CHeavyHash& Reset(uint64_t matrix_[64*64]);
    //CHeavyHash& Write(const unsigned char* data, size_t len);
    //void Finalize(unsigned char hash[OUTPUT_SIZE]);
    void (*Reset)(struct class_CHeavyHash *p, uint64_t matrix_[64*64]);
    void (*Write)(struct class_CHeavyHash *p, const unsigned char* data, size_t len);
    void (*Finalize)(struct class_CHeavyHash *p, unsigned char hash[OUTPUT_SIZE]);
};

#if 0
/** A hasher class for SHA3-256. */
class CSHA3_256
{
private:
    sha3_ctx_t context;

public:
    static const size_t OUTPUT_SIZE = 32;

    CSHA3_256();
    CSHA3_256& Write(const unsigned char* data, size_t len);
    void Finalize(unsigned char hash[OUTPUT_SIZE]);
    CSHA3_256& Reset();
};

class CHeavyHash
{
private:
    uint64_t matrix[64*64];
    CSHA3_256 hasher;

public:
    static const size_t OUTPUT_SIZE = 32;
    explicit CHeavyHash(uint64_t matrix_[64*64]);
    CHeavyHash& Reset(uint64_t matrix_[64*64]);
    CHeavyHash& Write(const unsigned char* data, size_t len);
    void Finalize(unsigned char hash[OUTPUT_SIZE]);
};
#endif
uint256 MultiplyUsing4bitPrecision(uint64_t matrix[64*64], const uint256 hash);

void ConvertTo4BitPrecisionVector(uint256 bit_sequence, uint64_t vector[64]);

uint256 Convert4bitVectorToUint(const uint64_t x[64]);


//zzj add
/*extern void CSHA3_256_init(struct Obtc_opt *Obtc, CSHA3_256 *p);
void CSHA3_256_CSHA3_256(struct Obtc_opt *Obtc, CSHA3_256 *p);

void CSHA3_256_Write(CSHA3_256 *p, const unsigned char* data, size_t len);

void CSHA3_256_Finalize(CSHA3_256 *p, unsigned char hash[OUTPUT_SIZE]);
//

void CHeavyHash_init(struct Obtc_opt *Obtc, CHeavyHash *p, uint64_t matrix_[64*64]);
void CHeavyHash_Write(CHeavyHash *p, const unsigned char* data, size_t len);

void CHeavyHash_Finalize(struct Obtc_opt *Obtc, CHeavyHash *p, unsigned char hash[OUTPUT_SIZE]);
*/

#endif  // OPOW_CRYPTO_HEAVYHASH_H