sha256.mx raw

   1  // Package sha256 implements SHA-256 in pure Go.
   2  // No stdlib crypto dependency — compiles cleanly through tinyjs.
   3  package sha256
   4  
   5  const (
   6  	Size      = 32
   7  	BlockSize = 64
   8  )
   9  
  10  var k = [64]uint32{
  11  	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
  12  	0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
  13  	0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
  14  	0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
  15  	0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
  16  	0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
  17  	0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
  18  	0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
  19  	0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
  20  	0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
  21  	0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
  22  	0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
  23  	0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
  24  	0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
  25  	0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
  26  	0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
  27  }
  28  
  29  var init0 = [8]uint32{
  30  	0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
  31  	0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
  32  }
  33  
  34  // Sum returns the SHA-256 checksum of data.
  35  func Sum(data []byte) [Size]byte {
  36  	var d digest
  37  	d.Reset()
  38  	d.Write(data)
  39  	return d.Sum()
  40  }
  41  
  42  // SumHex returns the SHA-256 checksum as a lowercase hex string.
  43  func SumHex(data []byte) string {
  44  	h := Sum(data)
  45  	return bytesToHex(h[:])
  46  }
  47  
  48  type digest struct {
  49  	h   [8]uint32
  50  	buf [BlockSize]byte
  51  	len int
  52  	tot uint64
  53  }
  54  
  55  func (d *digest) Reset() {
  56  	d.h = init0
  57  	d.len = 0
  58  	d.tot = 0
  59  }
  60  
  61  func (d *digest) Write(p []byte) {
  62  	d.tot += uint64(len(p))
  63  	// Fill buffer.
  64  	if d.len > 0 {
  65  		n := copy(d.buf[d.len:], p)
  66  		d.len += n
  67  		p = p[n:]
  68  		if d.len == BlockSize {
  69  			block(&d.h, d.buf[:])
  70  			d.len = 0
  71  		}
  72  	}
  73  	// Process full blocks.
  74  	for len(p) >= BlockSize {
  75  		block(&d.h, p[:BlockSize])
  76  		p = p[BlockSize:]
  77  	}
  78  	// Save remainder.
  79  	if len(p) > 0 {
  80  		d.len = copy(d.buf[:], p)
  81  	}
  82  }
  83  
  84  func (d *digest) Sum() [Size]byte {
  85  	// Padding.
  86  	var tmp [BlockSize]byte
  87  	tmp[0] = 0x80
  88  	bits := d.tot * 8
  89  
  90  	if d.len < 56 {
  91  		d.Write(tmp[:56-d.len])
  92  	} else {
  93  		d.Write(tmp[:64+56-d.len])
  94  	}
  95  
  96  	// Length in bits, big-endian.
  97  	var lb [8]byte
  98  	lb[0] = byte(bits >> 56)
  99  	lb[1] = byte(bits >> 48)
 100  	lb[2] = byte(bits >> 40)
 101  	lb[3] = byte(bits >> 32)
 102  	lb[4] = byte(bits >> 24)
 103  	lb[5] = byte(bits >> 16)
 104  	lb[6] = byte(bits >> 8)
 105  	lb[7] = byte(bits)
 106  	d.Write(lb[:])
 107  
 108  	var out [Size]byte
 109  	for i := 0; i < 8; i++ {
 110  		out[i*4] = byte(d.h[i] >> 24)
 111  		out[i*4+1] = byte(d.h[i] >> 16)
 112  		out[i*4+2] = byte(d.h[i] >> 8)
 113  		out[i*4+3] = byte(d.h[i])
 114  	}
 115  	return out
 116  }
 117  
 118  func block(h *[8]uint32, data []byte) {
 119  	var w [64]uint32
 120  
 121  	for i := 0; i < 16; i++ {
 122  		j := i * 4
 123  		w[i] = uint32(data[j])<<24 | uint32(data[j+1])<<16 |
 124  			uint32(data[j+2])<<8 | uint32(data[j+3])
 125  	}
 126  
 127  	for i := 16; i < 64; i++ {
 128  		s0 := rotr(w[i-15], 7) ^ rotr(w[i-15], 18) ^ (w[i-15] >> 3)
 129  		s1 := rotr(w[i-2], 17) ^ rotr(w[i-2], 19) ^ (w[i-2] >> 10)
 130  		w[i] = w[i-16] + s0 + w[i-7] + s1
 131  	}
 132  
 133  	a, b, c, d, e, f, g, hh := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]
 134  
 135  	for i := 0; i < 64; i++ {
 136  		S1 := rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)
 137  		ch := (e & f) ^ (^e & g)
 138  		temp1 := hh + S1 + ch + k[i] + w[i]
 139  		S0 := rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)
 140  		maj := (a & b) ^ (a & c) ^ (b & c)
 141  		temp2 := S0 + maj
 142  
 143  		hh = g
 144  		g = f
 145  		f = e
 146  		e = d + temp1
 147  		d = c
 148  		c = b
 149  		b = a
 150  		a = temp1 + temp2
 151  	}
 152  
 153  	h[0] += a
 154  	h[1] += b
 155  	h[2] += c
 156  	h[3] += d
 157  	h[4] += e
 158  	h[5] += f
 159  	h[6] += g
 160  	h[7] += hh
 161  }
 162  
 163  func rotr(x uint32, n uint) uint32 {
 164  	return (x >> n) | (x << (32 - n))
 165  }
 166  
 167  const hex = "0123456789abcdef"
 168  
 169  func bytesToHex(b []byte) string {
 170  	out := []byte{:len(b)*2}
 171  	for i, v := range b {
 172  		out[i*2] = hex[v>>4]
 173  		out[i*2+1] = hex[v&0x0f]
 174  	}
 175  	return string(out)
 176  }
 177