Home Manual Reference Source Test Repository

src/sha256.js

import { get32 , add32 , big32 } from '@aureooms/js-uint32' ;

const k = [
	get32(0x428a2f98), get32(0x71374491), get32(0xb5c0fbcf), get32(0xe9b5dba5),
	get32(0x3956c25b), get32(0x59f111f1), get32(0x923f82a4), get32(0xab1c5ed5),
	get32(0xd807aa98), get32(0x12835b01), get32(0x243185be), get32(0x550c7dc3),
	get32(0x72be5d74), get32(0x80deb1fe), get32(0x9bdc06a7), get32(0xc19bf174),
	get32(0xe49b69c1), get32(0xefbe4786), get32(0x0fc19dc6), get32(0x240ca1cc),
	get32(0x2de92c6f), get32(0x4a7484aa), get32(0x5cb0a9dc), get32(0x76f988da),
	get32(0x983e5152), get32(0xa831c66d), get32(0xb00327c8), get32(0xbf597fc7),
	get32(0xc6e00bf3), get32(0xd5a79147), get32(0x06ca6351), get32(0x14292967),
	get32(0x27b70a85), get32(0x2e1b2138), get32(0x4d2c6dfc), get32(0x53380d13),
	get32(0x650a7354), get32(0x766a0abb), get32(0x81c2c92e), get32(0x92722c85),
	get32(0xa2bfe8a1), get32(0xa81a664b), get32(0xc24b8b70), get32(0xc76c51a3),
	get32(0xd192e819), get32(0xd6990624), get32(0xf40e3585), get32(0x106aa070),
	get32(0x19a4c116), get32(0x1e376c08), get32(0x2748774c), get32(0x34b0bcb5),
	get32(0x391c0cb3), get32(0x4ed8aa4a), get32(0x5b9cca4f), get32(0x682e6ff3),
	get32(0x748f82ee), get32(0x78a5636f), get32(0x84c87814), get32(0x8cc70208),
	get32(0x90befffa), get32(0xa4506ceb), get32(0xbef9a3f7), get32(0xc67178f2),
] ;

function cycle (state, w) {

	// initialize hash value for this chunk:
	let a = state[0];
	let b = state[1];
	let c = state[2];
	let d = state[3];
	let e = state[4];
	let f = state[5];
	let g = state[6];
	let h = state[7];

	//Main loop:
	//for j from 0 to 63
	for(let j = 0; j < 64; ++j){
		//S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
		const s1 = (e >>> 6 | e << 26) ^(e >>> 11 | e << 21) ^(e >>> 25 | e << 7);
		//ch := (e and f) xor ((not e) and g)
		const ch = (e & f) ^ ((~e) & g);
		//temp := h + S1 + ch + k[j] + w[j]
		let temp = add32(add32(h, s1), add32(add32(ch, k[j]), w[j]));
		//d := d + temp;
		d = add32(d, temp);
		//S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
		const s0 = (a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10);
		//maj := (a and (b xor c)) xor (b and c)
		const maj = (a & (b ^ c)) ^ (b & c);
		//temp := temp + S0 + maj
		temp = add32(add32(temp, s0), maj);

		h = g;
		g = f;
		f = e;
		e = d;
		d = c;
		c = b;
		b = a;
		a = temp;
	}

	// Add this chunk's hash to result so far:
	state[0] = add32(state[0], a);
	state[1] = add32(state[1], b);
	state[2] = add32(state[2], c);
	state[3] = add32(state[3], d);
	state[4] = add32(state[4], e);
	state[5] = add32(state[5], f);
	state[6] = add32(state[6], g);
	state[7] = add32(state[7], h);
}

function call (h, data, o) {

	const w = new Array(64);

	// break chunk into sixteen 32-bit big-endian words w[i], 0 ≤ i ≤ 15
	for (let j = 0; j < 16; ++j) {
		w[j] = big32(data, o + j * 4);
	}

	// Extend the sixteen 32-bit words into sixty-four 32-bit words:
	// for j from 16 to 63
	for (let j = 16; j < 64; ++j) {
		//s0 := (w[j-15] rightrotate 7) xor (w[j-15] rightrotate 18) xor (w[j-15] rightshift 3)
		const s0 = (w[j-15] >>> 7 | w[j-15] << 25) ^ (w[j-15] >>> 18 | w[j-15] << 14) ^ (w[j-15] >>> 3);
		//s1 := (w[j-2] rightrotate 17) xor (w[j-2] rightrotate 19) xor (w[j-2] rightshift 10)
		const s1 = (w[j-2] >>> 17 | w[j-2] << 15) ^ (w[j-2] >>> 19 | w[j-2] << 13) ^ (w[j-2] >>> 10);
		//w[j] := w[j-16] + s0 + w[j-7] + s1
		w[j] = add32(add32(w[j-16], s0), add32(w[j-7], s1));
	}

	cycle(h, w);

}

/**
 * SHA-256
 */
export function sha256 (bytes, n, digest) {

	// PREPARE

	const q = n / 8 | 0;
	const z = q * 8;
	const u = n - z;

	// append the bit '1' to the message
	let last ;
	if (u > 0) {
		last = bytes[q] & (~0) << (7-u);
	}
	else {
		last = 0x80;
	}

	// Note 1: All variables are unsigned 32 bits and wrap modulo 2^32 when calculating
	// Note 2: All constants in this pseudo code are in big endian.
	// Within each word, the most significant byte is stored in the leftmost byte position

	// Initialize state:
	const h = [
		get32(0x6a09e667),
		get32(0xbb67ae85),
		get32(0x3c6ef372),
		get32(0xa54ff53a),
		get32(0x510e527f),
		get32(0x9b05688c),
		get32(0x1f83d9ab),
		get32(0x5be0cd19),
	] ;

	// Process the message in successive 512-bit chunks:
	// break message into 512-bit chunks

	const m = n / 512 | 0;
	const y = (n - 512 * m) / 8 | 0;

	// offset in data
	let o = 0;

	// for each chunk
	for (let j = 0; j < m; ++j, o += 64) {
		call(h, bytes, o);
	}

	// last bytes + padding + length
	let tail = [];

	// last bytes
	for (let j = 0; j < y; ++j) {
		tail.push(bytes[o + j]);
	}

	// special care taken for the very last byte which could
	// have been modified if n is not a multiple of 8
	tail.push(last);


	// append 0 ≤ k < 512 bits '0', so that the resulting
	// message length (in bits) is congruent to 448 (mod 512)
	let zeroes = (448 - (n + 1) % 512) / 8 | 0;

	if (zeroes < 0) {
		// we need an additional block as there is
		// not enough space left to append
		// the length of the data in bits

		for (let j = 0; j < -zeroes; ++j) {
			tail.push(0);
		}

		call(h, tail, 0);

		zeroes = 448 / 8;
		tail = [];
	}


	// pad with zeroes
	for (let j = 0; j < zeroes; ++j) {
		tail.push(0);
	}

	// append length of message (before preparation), in bits,
	// as 64-bit big-endian integer

	// JavaScript works with 32 bit integers.
	// tail.push((n >>> 56) & 0xff);
	// tail.push((n >>> 48) & 0xff);
	// tail.push((n >>> 40) & 0xff);
	// tail.push((n >>> 32) & 0xff);
	tail.push(0);
	tail.push(0);
	tail.push(0);
	tail.push(0);

	tail.push((n >>> 24) & 0xff);
	tail.push((n >>> 16) & 0xff);
	tail.push((n >>>  8) & 0xff);
	tail.push((n >>>  0) & 0xff);

	call(h, tail, 0);

	digest[0]  = (h[0] >>> 24) & 0xff;
	digest[1]  = (h[0] >>> 16) & 0xff;
	digest[2]  = (h[0] >>>  8) & 0xff;
	digest[3]  = (h[0] >>>  0) & 0xff;
	digest[4]  = (h[1] >>> 24) & 0xff;
	digest[5]  = (h[1] >>> 16) & 0xff;
	digest[6]  = (h[1] >>>  8) & 0xff;
	digest[7]  = (h[1] >>>  0) & 0xff;
	digest[8]  = (h[2] >>> 24) & 0xff;
	digest[9]  = (h[2] >>> 16) & 0xff;
	digest[10] = (h[2] >>>  8) & 0xff;
	digest[11] = (h[2] >>>  0) & 0xff;
	digest[12] = (h[3] >>> 24) & 0xff;
	digest[13] = (h[3] >>> 16) & 0xff;
	digest[14] = (h[3] >>>  8) & 0xff;
	digest[15] = (h[3] >>>  0) & 0xff;
	digest[16] = (h[4] >>> 24) & 0xff;
	digest[17] = (h[4] >>> 16) & 0xff;
	digest[18] = (h[4] >>>  8) & 0xff;
	digest[19] = (h[4] >>>  0) & 0xff;
	digest[20] = (h[5] >>> 24) & 0xff;
	digest[21] = (h[5] >>> 16) & 0xff;
	digest[22] = (h[5] >>>  8) & 0xff;
	digest[23] = (h[5] >>>  0) & 0xff;
	digest[24] = (h[6] >>> 24) & 0xff;
	digest[25] = (h[6] >>> 16) & 0xff;
	digest[26] = (h[6] >>>  8) & 0xff;
	digest[27] = (h[6] >>>  0) & 0xff;
	digest[28] = (h[7] >>> 24) & 0xff;
	digest[29] = (h[7] >>> 16) & 0xff;
	digest[30] = (h[7] >>>  8) & 0xff;
	digest[31] = (h[7] >>>  0) & 0xff;

	return digest;

}