#ifndef SIMPLICITY_SHA256_H
#define SIMPLICITY_SHA256_H
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "bitstring.h"
typedef struct sha256_midstate {
uint32_t s[8];
} sha256_midstate;
static inline uint_fast64_t ReadBE64(const unsigned char* b) {
return (uint_fast64_t)(b[0] & 0xff) << 56
| (uint_fast64_t)(b[1] & 0xff) << 48
| (uint_fast64_t)(b[2] & 0xff) << 40
| (uint_fast64_t)(b[3] & 0xff) << 32
| (uint_fast64_t)(b[4] & 0xff) << 24
| (uint_fast64_t)(b[5] & 0xff) << 16
| (uint_fast64_t)(b[6] & 0xff) << 8
| (uint_fast64_t)(b[7] & 0xff);
}
static inline uint32_t ReadBE32(const unsigned char* b) {
return (uint32_t)(b[0]) << 24
| (uint32_t)(b[1] & 0xff) << 16
| (uint32_t)(b[2] & 0xff) << 8
| (uint32_t)(b[3] & 0xff);
}
static inline void WriteBE64(unsigned char* ptr, uint_fast64_t x) {
ptr[0] = (unsigned char)(0xff & x >> 56);
ptr[1] = 0xff & x >> 48;
ptr[2] = 0xff & x >> 40;
ptr[3] = 0xff & x >> 32;
ptr[4] = 0xff & x >> 24;
ptr[5] = 0xff & x >> 16;
ptr[6] = 0xff & x >> 8;
ptr[7] = 0xff & x;
}
static inline void WriteBE32(unsigned char* ptr, uint_fast32_t x) {
ptr[0] = (unsigned char)(x >> 24);
ptr[1] = (x >> 16) & 0xff;
ptr[2] = (x >> 8) & 0xff;
ptr[3] = x & 0xff;
}
static inline void WriteLE32(unsigned char* ptr, uint_fast32_t x) {
ptr[3] = (unsigned char)(0xff & x >> 24);
ptr[2] = 0xff & x >> 16;
ptr[1] = 0xff & x >> 8;
ptr[0] = 0xff & x;
}
static inline void sha256_fromMidstate(unsigned char* hash, const uint32_t* midstate) {
WriteBE32(hash + 0*4, midstate[0]);
WriteBE32(hash + 1*4, midstate[1]);
WriteBE32(hash + 2*4, midstate[2]);
WriteBE32(hash + 3*4, midstate[3]);
WriteBE32(hash + 4*4, midstate[4]);
WriteBE32(hash + 5*4, midstate[5]);
WriteBE32(hash + 6*4, midstate[6]);
WriteBE32(hash + 7*4, midstate[7]);
}
static inline void sha256_toMidstate(uint32_t* midstate, const unsigned char* hash) {
midstate[0] = ReadBE32(hash + 0*4);
midstate[1] = ReadBE32(hash + 1*4);
midstate[2] = ReadBE32(hash + 2*4);
midstate[3] = ReadBE32(hash + 3*4);
midstate[4] = ReadBE32(hash + 4*4);
midstate[5] = ReadBE32(hash + 5*4);
midstate[6] = ReadBE32(hash + 6*4);
midstate[7] = ReadBE32(hash + 7*4);
}
static inline void sha256_iv(uint32_t* iv) {
iv[0] = 0x6a09e667ul;
iv[1] = 0xbb67ae85ul;
iv[2] = 0x3c6ef372ul;
iv[3] = 0xa54ff53aul;
iv[4] = 0x510e527ful;
iv[5] = 0x9b05688cul;
iv[6] = 0x1f83d9abul;
iv[7] = 0x5be0cd19ul;
}
extern void (*rustsimplicity_0_6_sha256_compression)(uint32_t* midstate, const uint32_t* block);
bool rustsimplicity_0_6_sha256_compression_is_optimized(void);
void rustsimplicity_0_6_sha256_bitstring(uint32_t* h, const bitstring* s);
static void sha256_compression_uchar(uint32_t* s, const unsigned char* chunk) {
rustsimplicity_0_6_sha256_compression(s, (const uint32_t[16])
{ ReadBE32(chunk + 4*0)
, ReadBE32(chunk + 4*1)
, ReadBE32(chunk + 4*2)
, ReadBE32(chunk + 4*3)
, ReadBE32(chunk + 4*4)
, ReadBE32(chunk + 4*5)
, ReadBE32(chunk + 4*6)
, ReadBE32(chunk + 4*7)
, ReadBE32(chunk + 4*8)
, ReadBE32(chunk + 4*9)
, ReadBE32(chunk + 4*10)
, ReadBE32(chunk + 4*11)
, ReadBE32(chunk + 4*12)
, ReadBE32(chunk + 4*13)
, ReadBE32(chunk + 4*14)
, ReadBE32(chunk + 4*15)
});
}
typedef struct sha256_context {
uint32_t* const output;
uint_fast64_t counter;
unsigned char block[64];
bool overflow;
} sha256_context;
static const uint_fast64_t sha256_max_counter = 0x2000000000000000;
static inline sha256_context sha256_init(uint32_t* output) {
sha256_iv(output);
return (sha256_context){ .output = output };
}
static inline sha256_context sha256_tagged_init(uint32_t* output, const sha256_midstate* iv) {
memcpy(output, iv->s, sizeof(uint32_t[8]));
return (sha256_context){ .output = output, .counter = 64 };
}
static inline bool sha256_uchars(sha256_context* ctx, const unsigned char* arr, size_t len) {
size_t delta = 64 - ctx->counter % 64;
unsigned char *block = ctx->block + ctx->counter % 64;
ctx->overflow = ctx->overflow || sha256_max_counter - ctx->counter <= len;
ctx->counter += len;
while (delta <= len) {
memcpy(block, arr, delta);
arr += delta;
len -= delta;
sha256_compression_uchar(ctx->output, ctx->block);
block = ctx->block;
delta = 64;
}
if (len) memcpy(block, arr, len);
return !ctx->overflow;
}
static inline bool sha256_uchar(sha256_context* ctx, unsigned char x) {
return sha256_uchars(ctx, &x, 1);
}
static inline bool sha256_u64be(sha256_context* ctx, uint_fast64_t x) {
unsigned char buf[8];
WriteBE64(buf, x);
return sha256_uchars(ctx, buf, sizeof(buf));
}
static inline bool sha256_u32le(sha256_context* ctx, uint_fast32_t x) {
unsigned char buf[4];
WriteLE32(buf, x);
return sha256_uchars(ctx, buf, sizeof(buf));
}
static inline bool sha256_u32be(sha256_context* ctx, uint_fast32_t x) {
unsigned char buf[4];
WriteBE32(buf, x);
return sha256_uchars(ctx, buf, sizeof(buf));
}
static inline bool sha256_finalize(sha256_context* ctx) {
bool result = !ctx->overflow;
uint_fast64_t length = ctx->counter * 8;
sha256_uchars(ctx, (const unsigned char[64]){0x80}, 1 + (64 + 56 - ctx->counter % 64 - 1) % 64);
sha256_u64be(ctx, length);
return result;
}
static inline void sha256_hash(sha256_context* ctx, const sha256_midstate* h) {
unsigned char buf[32];
sha256_fromMidstate(buf, h->s);
sha256_uchars(ctx, buf, sizeof(buf));
}
static inline int sha256_cmp_be(const sha256_midstate* a, const sha256_midstate* b) {
if (a->s[0] != b->s[0]) return a->s[0] < b->s[0] ? -1 : 1;
if (a->s[1] != b->s[1]) return a->s[1] < b->s[1] ? -1 : 1;
if (a->s[2] != b->s[2]) return a->s[2] < b->s[2] ? -1 : 1;
if (a->s[3] != b->s[3]) return a->s[3] < b->s[3] ? -1 : 1;
if (a->s[4] != b->s[4]) return a->s[4] < b->s[4] ? -1 : 1;
if (a->s[5] != b->s[5]) return a->s[5] < b->s[5] ? -1 : 1;
if (a->s[6] != b->s[6]) return a->s[6] < b->s[6] ? -1 : 1;
if (a->s[7] != b->s[7]) return a->s[7] < b->s[7] ? -1 : 1;
return 0;
}
#endif