#define CRYA_SHA_ADDRESS          0x02001900

typedef void (*crya_sha_process_t) (uint32_t hash_in_out[8], const uint8_t data[64], uint32_t ram_buf[64]);

/*** CRYA SHA function 
 *** param hash_in_out[In/out]:  A pointer to a hash location (hash input and output)
 *** param data[In]:             A pointer to a 512 bit data block
 *** param ram_buf[In]:          A pointer to a RAM buffer (256B needed for internal algorithm)
 ***/
#define crya_sha_process ((crya_sha_process_t ) (CRYA_SHA_ADDRESS | 0x1))

/*** CRYA SHA function 
 *** param message[In]:          A pointer to message to be hashed
 *** param message_length[In]:   message_length value in byte 
 *** param hash_in_out[In/out]:  A pointer to a hash (hash input and output)
 ***/
void secure_sha256_hash(const uint8_t *message, uint32_t message_length,uint32_t hash[8]) 
{
    uint32_t ram_buf[64],i,remainder;
    uint8_t block[64];

    /*** SHA process all plain blocks ***/
    for (i = 0; message_length - i >= 64; i += 64) {
        crya_sha_process(hash,(message+i),ram_buf);
    }

    /*** Pad and SHA process last block ***/ 
    remainder  = message_length - i;
    memcpy(block, message + i, remainder);
    /*** Add End Bit ***/
    block[remainder] = 0x80;
    remainder ++;
    if (64 - remainder  >= 8) {
        /*** Enough space for End Bit and Size ***/
        memset(block + remainder , 0, 56 - remainder );
    }
    else {
        /*** Missing space for padding, 
                 *** need to compute one more SHA256 Full block
                 ***/
        memset(block + remainder , 0, 64 - remainder );
        crya_sha_process( hash, block, ram_buf);
        memset(block, 0, 56);
    }
    /*** Store Length in bit in the last 8 word ***/
    uint64_t longLen = ((uint64_t)message_length) << 3;
    for (i = 0; i < 8; i++) {
        block[64 - 1 - i] = (uint8_t)(longLen >> (i * 8));
    }
    crya_sha_process( hash, block, ram_buf);
}