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;
}