JSFiddle - React, Tailwind, and code Playground

HTML

<div>Rule 30 Hash</div>
<input id="message" style="width:300px" onchange="calculateHash()" />
<button onclick="calculateHash()">Calculate</button>
<div><br /><code id="result"></code></div>

JavaScript

var RULE_30 = [0, 1, 1, 1, 1, 0, 0, 0];
var MAX_KEY = 80;
var MAX_HASH_BYTES = 32;

function getHash(message) {
    var hash = new Uint8Array(MAX_HASH_BYTES);
    var key = new Uint8Array(MAX_KEY);
	for (var i = 0; i < message.length; i++) {
        var c = message.charCodeAt(i);
		key[i % MAX_KEY] ^= (c & 0xff) ^ (i % (c + 1));
	}
    var skipRows = MAX_KEY * 32;
    var maxCells = skipRows * 2;
    maxCells += MAX_KEY * 8;
    maxCells += MAX_HASH_BYTES * 8 * 2;
    var cellsMid = maxCells / 2;
    var cells = new Int8Array(maxCells);
    var keyStart = (maxCells - MAX_KEY * 8) / 2;
    for (var i = 0; i < key.length; i++) {
        var keyChar = key[i];
        var bitPos = 1;
        for (var j = 0; j < 8; j++) {
            var b = (keyChar & bitPos) >>> j; 
            cells[keyStart + i * 8 + j] = b;
            bitPos <<= 1;
        }
    }
	var bitCount = 0;
	var mid = 0;
	for (var row = 0; row < maxCells; row++) {
		var tmp = 0;
		for (var i = 0; i < cells.length - 2; i++) {
			if (i == cellsMid) {
				mid = cells[i];
			}
			var pattern = tmp * 4 + cells[i + 1] * 2 + cells[i + 2];
			tmp = cells[i + 1];
			var bit = RULE_30[pattern];
			cells[i + 1] = bit;
		}
		if (row < skipRows) {
			continue;
		}
		if (row % 2 == 1) {
			if (mid == 1) {
				var bufPos = bitCount >>> 3;
				hash[bufPos] ^= 1 << (bitCount % 8);
			}
			bitCount++;
		}
	}
    return hash;
}

function calculateHash() {
    var message = document.getElementById('message').value;
	var hash = getHash(message);
  	var hashString = '';
	for (i = 0; i < hash.length; i++) {
		var s = '0' + hash[i].toString(16);
        hashString += s.length > 2 ? s.substring(1) : s;
	}
    var span = document.getElementById('result');
    span.innerHTML = hashString;
}