Source file: /~heha/hsn/esptool.zip/sha256.cpp

/********************************************************
* 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