/********************************************************
* Brad Conte <brad@bradconte.com> *
* 2024 heha object-oriented style *
* This implementation uses little endian byte order. *
********************************************************/
#include "sha.h"
#include <stdio.h> // _snprintf
#include <memory.h> // memset
#include "intrin.h"
static inline uint32 EP0 (uint32 x) {return std::rotr(x,2) ^ std::rotr(x,13) ^ std::rotr(x,22);}
static inline uint32 EP1 (uint32 x) {return std::rotr(x,6) ^ std::rotr(x,11) ^ std::rotr(x,25);}
static inline uint32 SIG0(uint32 x) {return std::rotr(x,7) ^ std::rotr(x,18) ^ x>>3;}
static inline uint32 SIG1(uint32 x) {return std::rotr(x,17)^ std::rotr(x,19) ^ x>>10;}
static inline uint32 CH (uint32 a,uint32 b,uint32 c) {return a&b ^~a&c;}
static inline uint32 MAJ (uint32 a,uint32 b,uint32 c) {return a&b ^ a&c ^ b&c;}
void Sha256::transform() {
static const uvector<64> k = {
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};
uint32 i, m[64];
for (i=0; i<16; ++i) m[i] = std::byteswap(Y[i]);
for ( ; i<64; ++i) m[i] = SIG1(m[i-2]) + m[i-7] + SIG0(m[i-15]) + m[i-16];
uint32 a=X[0], b=X[1], c=X[2], d=X[3],
e=X[4], f=X[5], g=X[6], h=X[7];
for (i=0; i<64; ++i) {
uint32 t1 = h + EP1(e) + CH (e,f,g) + k[i] + m[i],
t2 = EP0(a) + MAJ(a,b,c);
h=g; g=f; f=e; e = d + t1;
d=c; c=b; b=a; a = t1+ t2;
}
X[0]+=a; X[1]+=b; X[2]+=c; X[3]+=d;
X[4]+=e; X[5]+=f; X[6]+=g; X[7]+=h;
}
void Sha::init() {
Ycnt = Yfill = 0;
}
void Sha256::init() {
Sha::init();
static const uvector<8> Xinit={
0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,
0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19};
X=Xinit;
}
bool Sha256::selftest() {
static const uvector<8>expect={
0x42c4b0e3,0x141cfc98,0xc8f4fb9a,0x24b96f99,
0xe441ae27,0x4c939b64,0x1b9995a4,0x55b85278};
return final()==expect;
}
void Sha::update(const void*data, size_t len) {
const byte*da=reinterpret_cast<const byte*>(data);
for (uint32 i=0; i<len; ++i) {
Y.b[Yfill] = *da++;
if (++Yfill == 64) {
transform();
Yfill = 0;
Ycnt++;
}
}
}
void Sha::padlen(bool bswap) {
uint32 i = Yfill;
uint64 bits = ((uint64)Ycnt<<9) + (i<<3);
Y.b[i++] = 0x80; // Pad with one 1-bit, then all zero bits
// Pad all data left in the buffer.
memset(Y.b+i,0,64-i);
// if there is too less space for bit count, transform and make new padded buffer
if (i > 56) {
transform();
memset(Y.b,0,56);
}
// Append the total message's length in bits and transform.
*(uint64*)(Y+14) = bswap?std::byteswap(bits):bits;
transform();
}
Sha256::Digest Sha256::final() {
padlen(true);
// Since this implementation uses little endian byte ordering and SHA uses big endian,
// reverse all the bytes when copying the final state to the output hash.
Digest ret;
for (int i=0; i<8;i++) ret[i] = std::byteswap(X[i]);
return ret;
}
String<8*8+1>ShaN<8>::Digest::toString() const{
MAKEPRINTBUF(8*8+1)
for (int i=0; i<sizeof b; i++) print("%02x",b[i]);
return buf;
}
Detected encoding: ASCII (7 bit) | 2
|