]> git.ardis.lu - ens2hex/commitdiff
Initial commit
authorArdis Lu <ardisglu@gmail.com>
Sun, 21 Aug 2022 06:22:14 +0000 (23:22 -0700)
committerArdis Lu <ardisglu@gmail.com>
Sun, 21 Aug 2022 06:22:14 +0000 (23:22 -0700)
README.md [new file with mode: 0644]
index.html [new file with mode: 0644]
keccak256.js [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..c2538a5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# ens2hex
+
+Minimal website to look up the Ethereum hexadecimal (`0x`) address for every [ENS](https://ens.domains/) (`.eth`) name in a list.
+
+The keccak256 algorithm is from [Deno](https://deno.land/)'s `std/hash` library, slightly modified to be used in the web browser.
diff --git a/index.html b/index.html
new file mode 100644 (file)
index 0000000..d126cdb
--- /dev/null
@@ -0,0 +1,164 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <link rel="icon" href="data:,">
+  <style>
+    body {
+      inline-size: min(100% - 2rem, 720px);
+      margin-inline: auto;
+      font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
+      background: hsl(0deg 0% 90%);
+    }
+
+    header {
+      display: flex;
+      justify-content: center;
+    }
+
+    form {
+      display: flex;
+      flex-direction: column;
+      gap: 1rem;
+    }
+
+    p {
+      margin: 0;
+    }
+
+    div {
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      padding: 20px;
+      border: 2px dashed hsl(0deg 0% 70%);
+      border-radius: 20px;
+    }
+
+    button {
+      inline-size: fit-content;
+    }
+
+    output {
+      display: none;
+    }
+  </style>
+  <title>ens2hex</title>
+</head>
+
+<body>
+  <header>
+    <h1>ens2hex</h1>
+  </header>
+
+  <main>
+    <form>
+      <label for="text">Copy a list of names here:</label>
+      <textarea id="text" name="text" rows="10"></textarea>
+
+      <p>Or upload a list of names:</p>
+      <div>
+        <label for="file">Drag and drop a file to upload, or</label>
+        <input id="file" type="file" name="file">
+      </div>
+
+      <button>Fetch addresses</button>
+
+      <output>
+        <table>
+          <thead>
+            <tr>
+              <th>ENS name</th>
+              <th>Address</th>
+            </tr>
+          </thead>
+          <tbody></tbody>
+        </table>
+      </output>
+    </form>
+  </main>
+
+  <script type="module">
+    import { Keccak256 } from './keccak256.js'; // Converted to JS from Deno's std/hash library
+
+    function keccak256(byteArray) {
+      const k = new Keccak256();
+      k.update(byteArray);
+      return k.digest();
+    }
+
+    const form = document.querySelector('form');
+    const div = document.querySelector('div');
+    const input = document.querySelector('input');
+    const output = document.querySelector('output');
+    const table = document.querySelector('table');
+
+    // Implement drag and drop file upload
+    window.addEventListener('dragover', e => e.preventDefault());
+    window.addEventListener('drop', e => e.preventDefault());
+    div.addEventListener('drop', e => input.files = e.dataTransfer.files);
+    div.addEventListener('click', _ => input.click());
+    input.addEventListener('click', e => e.stopPropagation()); // Prevent 'click' from getting propagated to div (or else there will be two dialogs)
+
+    // Implement namehash as defined in https://eips.ethereum.org/EIPS/eip-137
+    // Does NOT include the '0x' prefix in the return value so it can be easily passed into JSON-RPC
+    function namehash(name) {
+      // Special hardcoded output for the '' value defined in EIP-137
+      if (name === '') {
+        return '0000000000000000000000000000000000000000000000000000000000000000';
+      }
+
+      const encoder = new TextEncoder();
+      const nameByteArrays = [new Uint8Array(32).fill(0)]; // Byte array equivalent of the hardcoded '' output. MUST be the last value
+      nameByteArrays.unshift(...name.split('.').map(n => encoder.encode(n))); // Results in an array of encoded Uint8Array for each ENS name part
+      const hash = nameByteArrays.reduceRight((acc, v) => keccak256(Uint8Array.from([...acc, ...keccak256(v)])));
+      return [...hash].map(v => v.toString(16).padStart(2, '0')).join(''); // Convert byte array into 0-padded string. Must spread typed array into non-typed array to allow .map() to output strings
+    }
+
+    form.addEventListener('submit', async event => {
+      event.preventDefault();
+
+      const formData = new FormData(event.target);
+      const combined = `${formData.get('text')}\n${await formData.get('file').text()}`; // Concatenate textarea and file inputs
+      const parsed = new Set(combined.split('\n').map(c => c.split(',')).flat().map(e => e.trim())); // Split on newline or comma, flatten, trim whitespace, de-duplicate
+      const cleaned = [...parsed].filter(name => name.slice(-4) === '.eth'); // Remove anything that does not end in '.eth'
+
+      const batchPayload = [];
+      for (const [index, name] of cleaned.entries()) {
+        batchPayload.push({
+          jsonrpc: '2.0',
+          method: 'eth_call',
+          params: [
+            {
+              to: '0x4976fb03c32e5b8cfe2b6ccb31c09ba78ebaba41', // ENS PublicResolver
+              data: `0x3b3b57de${namehash(name)}` // 0x3b3b57de is the byte signature for the function "addr(bytes32)" in ENS PublicResolver
+            },
+            'latest'
+          ],
+          id: index
+        });
+      }
+
+      const batchResponse = await fetch('https://cloudflare-eth.com/', {
+        method: 'POST',
+        headers: { 'Content-Type': 'application/json' },
+        body: JSON.stringify(batchPayload),
+      }).then(r => r.json());
+
+      for (const [index, response] of batchResponse.entries()) {
+        const row = table.insertRow();
+        const ens = row.insertCell();
+        const address = row.insertCell();
+
+        ens.textContent = cleaned[index]; // Assumes batchResponse is in the same order as cleaned
+        address.textContent = `0x${response.result.slice(26)}`;
+      }
+
+      output.style.display = 'block';
+    });
+  </script>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/keccak256.js b/keccak256.js
new file mode 100644 (file)
index 0000000..dc04097
--- /dev/null
@@ -0,0 +1,881 @@
+// https://github.com/denoland/deno_std/blob/main/hash/_sha3/keccakf.ts
+const KECCAK_ROUNDS = 24;
+const KECCAK_RC = [
+  0x1,
+  0x0,
+  0x8082,
+  0x0,
+  0x808a,
+  0x80000000,
+  0x80008000,
+  0x80000000,
+  0x808b,
+  0x0,
+  0x80000001,
+  0x0,
+  0x80008081,
+  0x80000000,
+  0x8009,
+  0x80000000,
+  0x8a,
+  0x0,
+  0x88,
+  0x0,
+  0x80008009,
+  0x0,
+  0x8000000a,
+  0x0,
+  0x8000808b,
+  0x0,
+  0x8b,
+  0x80000000,
+  0x8089,
+  0x80000000,
+  0x8003,
+  0x80000000,
+  0x8002,
+  0x80000000,
+  0x80,
+  0x80000000,
+  0x800a,
+  0x0,
+  0x8000000a,
+  0x80000000,
+  0x80008081,
+  0x80000000,
+  0x8080,
+  0x80000000,
+  0x80000001,
+  0x0,
+  0x80008008,
+  0x80000000,
+];
+
+function keccakf(state) {
+  const s = new Uint32Array(state.buffer);
+  let bc0 = 0;
+  let bc1 = 0;
+  let bc2 = 0;
+  let bc3 = 0;
+  let bc4 = 0;
+  let bc5 = 0;
+  let bc6 = 0;
+  let bc7 = 0;
+  let bc8 = 0;
+  let bc9 = 0;
+  let d0 = 0;
+  let d1 = 0;
+  let d2 = 0;
+  let d3 = 0;
+  let d4 = 0;
+  let d5 = 0;
+  let d6 = 0;
+  let d7 = 0;
+  let d8 = 0;
+  let d9 = 0;
+  let t0 = 0;
+  let t1 = 0;
+
+  for (let n = 0; n < KECCAK_ROUNDS * 2; n += 8) {
+    // Round 1
+    bc0 = s[0] ^ s[10] ^ s[20] ^ s[30] ^ s[40];
+    bc1 = s[1] ^ s[11] ^ s[21] ^ s[31] ^ s[41];
+    bc2 = s[2] ^ s[12] ^ s[22] ^ s[32] ^ s[42];
+    bc3 = s[3] ^ s[13] ^ s[23] ^ s[33] ^ s[43];
+    bc4 = s[4] ^ s[14] ^ s[24] ^ s[34] ^ s[44];
+    bc5 = s[5] ^ s[15] ^ s[25] ^ s[35] ^ s[45];
+    bc6 = s[6] ^ s[16] ^ s[26] ^ s[36] ^ s[46];
+    bc7 = s[7] ^ s[17] ^ s[27] ^ s[37] ^ s[47];
+    bc8 = s[8] ^ s[18] ^ s[28] ^ s[38] ^ s[48];
+    bc9 = s[9] ^ s[19] ^ s[29] ^ s[39] ^ s[49];
+
+    d0 = bc8 ^ ((bc2 << 1) | (bc3 >>> 31));
+    d1 = bc9 ^ ((bc3 << 1) | (bc2 >>> 31));
+    d2 = bc0 ^ ((bc4 << 1) | (bc5 >>> 31));
+    d3 = bc1 ^ ((bc5 << 1) | (bc4 >>> 31));
+    d4 = bc2 ^ ((bc6 << 1) | (bc7 >>> 31));
+    d5 = bc3 ^ ((bc7 << 1) | (bc6 >>> 31));
+    d6 = bc4 ^ ((bc8 << 1) | (bc9 >>> 31));
+    d7 = bc5 ^ ((bc9 << 1) | (bc8 >>> 31));
+    d8 = bc6 ^ ((bc0 << 1) | (bc1 >>> 31));
+    d9 = bc7 ^ ((bc1 << 1) | (bc0 >>> 31));
+
+    bc0 = s[0] ^ d0;
+    bc1 = s[1] ^ d1;
+    t0 = s[12] ^ d2;
+    t1 = s[13] ^ d3;
+    bc2 = (t1 << 12) | (t0 >>> 20);
+    bc3 = (t0 << 12) | (t1 >>> 20);
+    t0 = s[24] ^ d4;
+    t1 = s[25] ^ d5;
+    bc4 = (t1 << 11) | (t0 >>> 21);
+    bc5 = (t0 << 11) | (t1 >>> 21);
+    t0 = s[36] ^ d6;
+    t1 = s[37] ^ d7;
+    bc6 = (t0 << 21) | (t1 >>> 11);
+    bc7 = (t1 << 21) | (t0 >>> 11);
+    t0 = s[48] ^ d8;
+    t1 = s[49] ^ d9;
+    bc8 = (t0 << 14) | (t1 >>> 18);
+    bc9 = (t1 << 14) | (t0 >>> 18);
+    s[0] = bc0 ^ (bc4 & ~bc2) ^ KECCAK_RC[n];
+    s[1] = bc1 ^ (bc5 & ~bc3) ^ KECCAK_RC[n + 1];
+    s[12] = bc2 ^ (bc6 & ~bc4);
+    s[13] = bc3 ^ (bc7 & ~bc5);
+    s[24] = bc4 ^ (bc8 & ~bc6);
+    s[25] = bc5 ^ (bc9 & ~bc7);
+    s[36] = bc6 ^ (bc0 & ~bc8);
+    s[37] = bc7 ^ (bc1 & ~bc9);
+    s[48] = bc8 ^ (bc2 & ~bc0);
+    s[49] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[20] ^ d0;
+    t1 = s[21] ^ d1;
+    bc4 = (t0 << 3) | (t1 >>> 29);
+    bc5 = (t1 << 3) | (t0 >>> 29);
+    t0 = s[32] ^ d2;
+    t1 = s[33] ^ d3;
+    bc6 = (t1 << 13) | (t0 >>> 19);
+    bc7 = (t0 << 13) | (t1 >>> 19);
+    t0 = s[44] ^ d4;
+    t1 = s[45] ^ d5;
+    bc8 = (t1 << 29) | (t0 >>> 3);
+    bc9 = (t0 << 29) | (t1 >>> 3);
+    t0 = s[6] ^ d6;
+    t1 = s[7] ^ d7;
+    bc0 = (t0 << 28) | (t1 >>> 4);
+    bc1 = (t1 << 28) | (t0 >>> 4);
+    t0 = s[18] ^ d8;
+    t1 = s[19] ^ d9;
+    bc2 = (t0 << 20) | (t1 >>> 12);
+    bc3 = (t1 << 20) | (t0 >>> 12);
+    s[20] = bc0 ^ (bc4 & ~bc2);
+    s[21] = bc1 ^ (bc5 & ~bc3);
+    s[32] = bc2 ^ (bc6 & ~bc4);
+    s[33] = bc3 ^ (bc7 & ~bc5);
+    s[44] = bc4 ^ (bc8 & ~bc6);
+    s[45] = bc5 ^ (bc9 & ~bc7);
+    s[6] = bc6 ^ (bc0 & ~bc8);
+    s[7] = bc7 ^ (bc1 & ~bc9);
+    s[18] = bc8 ^ (bc2 & ~bc0);
+    s[19] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[40] ^ d0;
+    t1 = s[41] ^ d1;
+    bc8 = (t0 << 18) | (t1 >>> 14);
+    bc9 = (t1 << 18) | (t0 >>> 14);
+    t0 = s[2] ^ d2;
+    t1 = s[3] ^ d3;
+    bc0 = (t0 << 1) | (t1 >>> 31);
+    bc1 = (t1 << 1) | (t0 >>> 31);
+    t0 = s[14] ^ d4;
+    t1 = s[15] ^ d5;
+    bc2 = (t0 << 6) | (t1 >>> 26);
+    bc3 = (t1 << 6) | (t0 >>> 26);
+    t0 = s[26] ^ d6;
+    t1 = s[27] ^ d7;
+    bc4 = (t0 << 25) | (t1 >>> 7);
+    bc5 = (t1 << 25) | (t0 >>> 7);
+    t0 = s[38] ^ d8;
+    t1 = s[39] ^ d9;
+    bc6 = (t0 << 8) | (t1 >>> 24);
+    bc7 = (t1 << 8) | (t0 >>> 24);
+    s[40] = bc0 ^ (bc4 & ~bc2);
+    s[41] = bc1 ^ (bc5 & ~bc3);
+    s[2] = bc2 ^ (bc6 & ~bc4);
+    s[3] = bc3 ^ (bc7 & ~bc5);
+    s[14] = bc4 ^ (bc8 & ~bc6);
+    s[15] = bc5 ^ (bc9 & ~bc7);
+    s[26] = bc6 ^ (bc0 & ~bc8);
+    s[27] = bc7 ^ (bc1 & ~bc9);
+    s[38] = bc8 ^ (bc2 & ~bc0);
+    s[39] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[10] ^ d0;
+    t1 = s[11] ^ d1;
+    bc2 = (t1 << 4) | (t0 >>> 28);
+    bc3 = (t0 << 4) | (t1 >>> 28);
+    t0 = s[22] ^ d2;
+    t1 = s[23] ^ d3;
+    bc4 = (t0 << 10) | (t1 >>> 22);
+    bc5 = (t1 << 10) | (t0 >>> 22);
+    t0 = s[34] ^ d4;
+    t1 = s[35] ^ d5;
+    bc6 = (t0 << 15) | (t1 >>> 17);
+    bc7 = (t1 << 15) | (t0 >>> 17);
+    t0 = s[46] ^ d6;
+    t1 = s[47] ^ d7;
+    bc8 = (t1 << 24) | (t0 >>> 8);
+    bc9 = (t0 << 24) | (t1 >>> 8);
+    t0 = s[8] ^ d8;
+    t1 = s[9] ^ d9;
+    bc0 = (t0 << 27) | (t1 >>> 5);
+    bc1 = (t1 << 27) | (t0 >>> 5);
+    s[10] = bc0 ^ (bc4 & ~bc2);
+    s[11] = bc1 ^ (bc5 & ~bc3);
+    s[22] = bc2 ^ (bc6 & ~bc4);
+    s[23] = bc3 ^ (bc7 & ~bc5);
+    s[34] = bc4 ^ (bc8 & ~bc6);
+    s[35] = bc5 ^ (bc9 & ~bc7);
+    s[46] = bc6 ^ (bc0 & ~bc8);
+    s[47] = bc7 ^ (bc1 & ~bc9);
+    s[8] = bc8 ^ (bc2 & ~bc0);
+    s[9] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[30] ^ d0;
+    t1 = s[31] ^ d1;
+    bc6 = (t1 << 9) | (t0 >>> 23);
+    bc7 = (t0 << 9) | (t1 >>> 23);
+    t0 = s[42] ^ d2;
+    t1 = s[43] ^ d3;
+    bc8 = (t0 << 2) | (t1 >>> 30);
+    bc9 = (t1 << 2) | (t0 >>> 30);
+    t0 = s[4] ^ d4;
+    t1 = s[5] ^ d5;
+    bc0 = (t1 << 30) | (t0 >>> 2);
+    bc1 = (t0 << 30) | (t1 >>> 2);
+    t0 = s[16] ^ d6;
+    t1 = s[17] ^ d7;
+    bc2 = (t1 << 23) | (t0 >>> 9);
+    bc3 = (t0 << 23) | (t1 >>> 9);
+    t0 = s[28] ^ d8;
+    t1 = s[29] ^ d9;
+    bc4 = (t1 << 7) | (t0 >>> 25);
+    bc5 = (t0 << 7) | (t1 >>> 25);
+    s[30] = bc0 ^ (bc4 & ~bc2);
+    s[31] = bc1 ^ (bc5 & ~bc3);
+    s[42] = bc2 ^ (bc6 & ~bc4);
+    s[43] = bc3 ^ (bc7 & ~bc5);
+    s[4] = bc4 ^ (bc8 & ~bc6);
+    s[5] = bc5 ^ (bc9 & ~bc7);
+    s[16] = bc6 ^ (bc0 & ~bc8);
+    s[17] = bc7 ^ (bc1 & ~bc9);
+    s[28] = bc8 ^ (bc2 & ~bc0);
+    s[29] = bc9 ^ (bc3 & ~bc1);
+
+    // Round 2
+    bc0 = s[0] ^ s[10] ^ s[20] ^ s[30] ^ s[40];
+    bc1 = s[1] ^ s[11] ^ s[21] ^ s[31] ^ s[41];
+    bc2 = s[2] ^ s[12] ^ s[22] ^ s[32] ^ s[42];
+    bc3 = s[3] ^ s[13] ^ s[23] ^ s[33] ^ s[43];
+    bc4 = s[4] ^ s[14] ^ s[24] ^ s[34] ^ s[44];
+    bc5 = s[5] ^ s[15] ^ s[25] ^ s[35] ^ s[45];
+    bc6 = s[6] ^ s[16] ^ s[26] ^ s[36] ^ s[46];
+    bc7 = s[7] ^ s[17] ^ s[27] ^ s[37] ^ s[47];
+    bc8 = s[8] ^ s[18] ^ s[28] ^ s[38] ^ s[48];
+    bc9 = s[9] ^ s[19] ^ s[29] ^ s[39] ^ s[49];
+
+    d0 = bc8 ^ ((bc2 << 1) | (bc3 >>> 31));
+    d1 = bc9 ^ ((bc3 << 1) | (bc2 >>> 31));
+    d2 = bc0 ^ ((bc4 << 1) | (bc5 >>> 31));
+    d3 = bc1 ^ ((bc5 << 1) | (bc4 >>> 31));
+    d4 = bc2 ^ ((bc6 << 1) | (bc7 >>> 31));
+    d5 = bc3 ^ ((bc7 << 1) | (bc6 >>> 31));
+    d6 = bc4 ^ ((bc8 << 1) | (bc9 >>> 31));
+    d7 = bc5 ^ ((bc9 << 1) | (bc8 >>> 31));
+    d8 = bc6 ^ ((bc0 << 1) | (bc1 >>> 31));
+    d9 = bc7 ^ ((bc1 << 1) | (bc0 >>> 31));
+
+    bc0 = s[0] ^ d0;
+    bc1 = s[1] ^ d1;
+    t0 = s[32] ^ d2;
+    t1 = s[33] ^ d3;
+    bc2 = (t1 << 12) | (t0 >>> 20);
+    bc3 = (t0 << 12) | (t1 >>> 20);
+    t0 = s[14] ^ d4;
+    t1 = s[15] ^ d5;
+    bc4 = (t1 << 11) | (t0 >>> 21);
+    bc5 = (t0 << 11) | (t1 >>> 21);
+    t0 = s[46] ^ d6;
+    t1 = s[47] ^ d7;
+    bc6 = (t0 << 21) | (t1 >>> 11);
+    bc7 = (t1 << 21) | (t0 >>> 11);
+    t0 = s[28] ^ d8;
+    t1 = s[29] ^ d9;
+    bc8 = (t0 << 14) | (t1 >>> 18);
+    bc9 = (t1 << 14) | (t0 >>> 18);
+    s[0] = bc0 ^ (bc4 & ~bc2) ^ KECCAK_RC[n + 2];
+    s[1] = bc1 ^ (bc5 & ~bc3) ^ KECCAK_RC[n + 3];
+    s[32] = bc2 ^ (bc6 & ~bc4);
+    s[33] = bc3 ^ (bc7 & ~bc5);
+    s[14] = bc4 ^ (bc8 & ~bc6);
+    s[15] = bc5 ^ (bc9 & ~bc7);
+    s[46] = bc6 ^ (bc0 & ~bc8);
+    s[47] = bc7 ^ (bc1 & ~bc9);
+    s[28] = bc8 ^ (bc2 & ~bc0);
+    s[29] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[40] ^ d0;
+    t1 = s[41] ^ d1;
+    bc4 = (t0 << 3) | (t1 >>> 29);
+    bc5 = (t1 << 3) | (t0 >>> 29);
+    t0 = s[22] ^ d2;
+    t1 = s[23] ^ d3;
+    bc6 = (t1 << 13) | (t0 >>> 19);
+    bc7 = (t0 << 13) | (t1 >>> 19);
+    t0 = s[4] ^ d4;
+    t1 = s[5] ^ d5;
+    bc8 = (t1 << 29) | (t0 >>> 3);
+    bc9 = (t0 << 29) | (t1 >>> 3);
+    t0 = s[36] ^ d6;
+    t1 = s[37] ^ d7;
+    bc0 = (t0 << 28) | (t1 >>> 4);
+    bc1 = (t1 << 28) | (t0 >>> 4);
+    t0 = s[18] ^ d8;
+    t1 = s[19] ^ d9;
+    bc2 = (t0 << 20) | (t1 >>> 12);
+    bc3 = (t1 << 20) | (t0 >>> 12);
+    s[40] = bc0 ^ (bc4 & ~bc2);
+    s[41] = bc1 ^ (bc5 & ~bc3);
+    s[22] = bc2 ^ (bc6 & ~bc4);
+    s[23] = bc3 ^ (bc7 & ~bc5);
+    s[4] = bc4 ^ (bc8 & ~bc6);
+    s[5] = bc5 ^ (bc9 & ~bc7);
+    s[36] = bc6 ^ (bc0 & ~bc8);
+    s[37] = bc7 ^ (bc1 & ~bc9);
+    s[18] = bc8 ^ (bc2 & ~bc0);
+    s[19] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[30] ^ d0;
+    t1 = s[31] ^ d1;
+    bc8 = (t0 << 18) | (t1 >>> 14);
+    bc9 = (t1 << 18) | (t0 >>> 14);
+    t0 = s[12] ^ d2;
+    t1 = s[13] ^ d3;
+    bc0 = (t0 << 1) | (t1 >>> 31);
+    bc1 = (t1 << 1) | (t0 >>> 31);
+    t0 = s[44] ^ d4;
+    t1 = s[45] ^ d5;
+    bc2 = (t0 << 6) | (t1 >>> 26);
+    bc3 = (t1 << 6) | (t0 >>> 26);
+    t0 = s[26] ^ d6;
+    t1 = s[27] ^ d7;
+    bc4 = (t0 << 25) | (t1 >>> 7);
+    bc5 = (t1 << 25) | (t0 >>> 7);
+    t0 = s[8] ^ d8;
+    t1 = s[9] ^ d9;
+    bc6 = (t0 << 8) | (t1 >>> 24);
+    bc7 = (t1 << 8) | (t0 >>> 24);
+    s[30] = bc0 ^ (bc4 & ~bc2);
+    s[31] = bc1 ^ (bc5 & ~bc3);
+    s[12] = bc2 ^ (bc6 & ~bc4);
+    s[13] = bc3 ^ (bc7 & ~bc5);
+    s[44] = bc4 ^ (bc8 & ~bc6);
+    s[45] = bc5 ^ (bc9 & ~bc7);
+    s[26] = bc6 ^ (bc0 & ~bc8);
+    s[27] = bc7 ^ (bc1 & ~bc9);
+    s[8] = bc8 ^ (bc2 & ~bc0);
+    s[9] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[20] ^ d0;
+    t1 = s[21] ^ d1;
+    bc2 = (t1 << 4) | (t0 >>> 28);
+    bc3 = (t0 << 4) | (t1 >>> 28);
+    t0 = s[2] ^ d2;
+    t1 = s[3] ^ d3;
+    bc4 = (t0 << 10) | (t1 >>> 22);
+    bc5 = (t1 << 10) | (t0 >>> 22);
+    t0 = s[34] ^ d4;
+    t1 = s[35] ^ d5;
+    bc6 = (t0 << 15) | (t1 >>> 17);
+    bc7 = (t1 << 15) | (t0 >>> 17);
+    t0 = s[16] ^ d6;
+    t1 = s[17] ^ d7;
+    bc8 = (t1 << 24) | (t0 >>> 8);
+    bc9 = (t0 << 24) | (t1 >>> 8);
+    t0 = s[48] ^ d8;
+    t1 = s[49] ^ d9;
+    bc0 = (t0 << 27) | (t1 >>> 5);
+    bc1 = (t1 << 27) | (t0 >>> 5);
+    s[20] = bc0 ^ (bc4 & ~bc2);
+    s[21] = bc1 ^ (bc5 & ~bc3);
+    s[2] = bc2 ^ (bc6 & ~bc4);
+    s[3] = bc3 ^ (bc7 & ~bc5);
+    s[34] = bc4 ^ (bc8 & ~bc6);
+    s[35] = bc5 ^ (bc9 & ~bc7);
+    s[16] = bc6 ^ (bc0 & ~bc8);
+    s[17] = bc7 ^ (bc1 & ~bc9);
+    s[48] = bc8 ^ (bc2 & ~bc0);
+    s[49] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[10] ^ d0;
+    t1 = s[11] ^ d1;
+    bc6 = (t1 << 9) | (t0 >>> 23);
+    bc7 = (t0 << 9) | (t1 >>> 23);
+    t0 = s[42] ^ d2;
+    t1 = s[43] ^ d3;
+    bc8 = (t0 << 2) | (t1 >>> 30);
+    bc9 = (t1 << 2) | (t0 >>> 30);
+    t0 = s[24] ^ d4;
+    t1 = s[25] ^ d5;
+    bc0 = (t1 << 30) | (t0 >>> 2);
+    bc1 = (t0 << 30) | (t1 >>> 2);
+    t0 = s[6] ^ d6;
+    t1 = s[7] ^ d7;
+    bc2 = (t1 << 23) | (t0 >>> 9);
+    bc3 = (t0 << 23) | (t1 >>> 9);
+    t0 = s[38] ^ d8;
+    t1 = s[39] ^ d9;
+    bc4 = (t1 << 7) | (t0 >>> 25);
+    bc5 = (t0 << 7) | (t1 >>> 25);
+    s[10] = bc0 ^ (bc4 & ~bc2);
+    s[11] = bc1 ^ (bc5 & ~bc3);
+    s[42] = bc2 ^ (bc6 & ~bc4);
+    s[43] = bc3 ^ (bc7 & ~bc5);
+    s[24] = bc4 ^ (bc8 & ~bc6);
+    s[25] = bc5 ^ (bc9 & ~bc7);
+    s[6] = bc6 ^ (bc0 & ~bc8);
+    s[7] = bc7 ^ (bc1 & ~bc9);
+    s[38] = bc8 ^ (bc2 & ~bc0);
+    s[39] = bc9 ^ (bc3 & ~bc1);
+
+    // Round 3
+    bc0 = s[0] ^ s[10] ^ s[20] ^ s[30] ^ s[40];
+    bc1 = s[1] ^ s[11] ^ s[21] ^ s[31] ^ s[41];
+    bc2 = s[2] ^ s[12] ^ s[22] ^ s[32] ^ s[42];
+    bc3 = s[3] ^ s[13] ^ s[23] ^ s[33] ^ s[43];
+    bc4 = s[4] ^ s[14] ^ s[24] ^ s[34] ^ s[44];
+    bc5 = s[5] ^ s[15] ^ s[25] ^ s[35] ^ s[45];
+    bc6 = s[6] ^ s[16] ^ s[26] ^ s[36] ^ s[46];
+    bc7 = s[7] ^ s[17] ^ s[27] ^ s[37] ^ s[47];
+    bc8 = s[8] ^ s[18] ^ s[28] ^ s[38] ^ s[48];
+    bc9 = s[9] ^ s[19] ^ s[29] ^ s[39] ^ s[49];
+
+    d0 = bc8 ^ ((bc2 << 1) | (bc3 >>> 31));
+    d1 = bc9 ^ ((bc3 << 1) | (bc2 >>> 31));
+    d2 = bc0 ^ ((bc4 << 1) | (bc5 >>> 31));
+    d3 = bc1 ^ ((bc5 << 1) | (bc4 >>> 31));
+    d4 = bc2 ^ ((bc6 << 1) | (bc7 >>> 31));
+    d5 = bc3 ^ ((bc7 << 1) | (bc6 >>> 31));
+    d6 = bc4 ^ ((bc8 << 1) | (bc9 >>> 31));
+    d7 = bc5 ^ ((bc9 << 1) | (bc8 >>> 31));
+    d8 = bc6 ^ ((bc0 << 1) | (bc1 >>> 31));
+    d9 = bc7 ^ ((bc1 << 1) | (bc0 >>> 31));
+
+    bc0 = s[0] ^ d0;
+    bc1 = s[1] ^ d1;
+    t0 = s[22] ^ d2;
+    t1 = s[23] ^ d3;
+    bc2 = (t1 << 12) | (t0 >>> 20);
+    bc3 = (t0 << 12) | (t1 >>> 20);
+    t0 = s[44] ^ d4;
+    t1 = s[45] ^ d5;
+    bc4 = (t1 << 11) | (t0 >>> 21);
+    bc5 = (t0 << 11) | (t1 >>> 21);
+    t0 = s[16] ^ d6;
+    t1 = s[17] ^ d7;
+    bc6 = (t0 << 21) | (t1 >>> 11);
+    bc7 = (t1 << 21) | (t0 >>> 11);
+    t0 = s[38] ^ d8;
+    t1 = s[39] ^ d9;
+    bc8 = (t0 << 14) | (t1 >>> 18);
+    bc9 = (t1 << 14) | (t0 >>> 18);
+    s[0] = bc0 ^ (bc4 & ~bc2) ^ KECCAK_RC[n + 4];
+    s[1] = bc1 ^ (bc5 & ~bc3) ^ KECCAK_RC[n + 5];
+    s[22] = bc2 ^ (bc6 & ~bc4);
+    s[23] = bc3 ^ (bc7 & ~bc5);
+    s[44] = bc4 ^ (bc8 & ~bc6);
+    s[45] = bc5 ^ (bc9 & ~bc7);
+    s[16] = bc6 ^ (bc0 & ~bc8);
+    s[17] = bc7 ^ (bc1 & ~bc9);
+    s[38] = bc8 ^ (bc2 & ~bc0);
+    s[39] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[30] ^ d0;
+    t1 = s[31] ^ d1;
+    bc4 = (t0 << 3) | (t1 >>> 29);
+    bc5 = (t1 << 3) | (t0 >>> 29);
+    t0 = s[2] ^ d2;
+    t1 = s[3] ^ d3;
+    bc6 = (t1 << 13) | (t0 >>> 19);
+    bc7 = (t0 << 13) | (t1 >>> 19);
+    t0 = s[24] ^ d4;
+    t1 = s[25] ^ d5;
+    bc8 = (t1 << 29) | (t0 >>> 3);
+    bc9 = (t0 << 29) | (t1 >>> 3);
+    t0 = s[46] ^ d6;
+    t1 = s[47] ^ d7;
+    bc0 = (t0 << 28) | (t1 >>> 4);
+    bc1 = (t1 << 28) | (t0 >>> 4);
+    t0 = s[18] ^ d8;
+    t1 = s[19] ^ d9;
+    bc2 = (t0 << 20) | (t1 >>> 12);
+    bc3 = (t1 << 20) | (t0 >>> 12);
+    s[30] = bc0 ^ (bc4 & ~bc2);
+    s[31] = bc1 ^ (bc5 & ~bc3);
+    s[2] = bc2 ^ (bc6 & ~bc4);
+    s[3] = bc3 ^ (bc7 & ~bc5);
+    s[24] = bc4 ^ (bc8 & ~bc6);
+    s[25] = bc5 ^ (bc9 & ~bc7);
+    s[46] = bc6 ^ (bc0 & ~bc8);
+    s[47] = bc7 ^ (bc1 & ~bc9);
+    s[18] = bc8 ^ (bc2 & ~bc0);
+    s[19] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[10] ^ d0;
+    t1 = s[11] ^ d1;
+    bc8 = (t0 << 18) | (t1 >>> 14);
+    bc9 = (t1 << 18) | (t0 >>> 14);
+    t0 = s[32] ^ d2;
+    t1 = s[33] ^ d3;
+    bc0 = (t0 << 1) | (t1 >>> 31);
+    bc1 = (t1 << 1) | (t0 >>> 31);
+    t0 = s[4] ^ d4;
+    t1 = s[5] ^ d5;
+    bc2 = (t0 << 6) | (t1 >>> 26);
+    bc3 = (t1 << 6) | (t0 >>> 26);
+    t0 = s[26] ^ d6;
+    t1 = s[27] ^ d7;
+    bc4 = (t0 << 25) | (t1 >>> 7);
+    bc5 = (t1 << 25) | (t0 >>> 7);
+    t0 = s[48] ^ d8;
+    t1 = s[49] ^ d9;
+    bc6 = (t0 << 8) | (t1 >>> 24);
+    bc7 = (t1 << 8) | (t0 >>> 24);
+    s[10] = bc0 ^ (bc4 & ~bc2);
+    s[11] = bc1 ^ (bc5 & ~bc3);
+    s[32] = bc2 ^ (bc6 & ~bc4);
+    s[33] = bc3 ^ (bc7 & ~bc5);
+    s[4] = bc4 ^ (bc8 & ~bc6);
+    s[5] = bc5 ^ (bc9 & ~bc7);
+    s[26] = bc6 ^ (bc0 & ~bc8);
+    s[27] = bc7 ^ (bc1 & ~bc9);
+    s[48] = bc8 ^ (bc2 & ~bc0);
+    s[49] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[40] ^ d0;
+    t1 = s[41] ^ d1;
+    bc2 = (t1 << 4) | (t0 >>> 28);
+    bc3 = (t0 << 4) | (t1 >>> 28);
+    t0 = s[12] ^ d2;
+    t1 = s[13] ^ d3;
+    bc4 = (t0 << 10) | (t1 >>> 22);
+    bc5 = (t1 << 10) | (t0 >>> 22);
+    t0 = s[34] ^ d4;
+    t1 = s[35] ^ d5;
+    bc6 = (t0 << 15) | (t1 >>> 17);
+    bc7 = (t1 << 15) | (t0 >>> 17);
+    t0 = s[6] ^ d6;
+    t1 = s[7] ^ d7;
+    bc8 = (t1 << 24) | (t0 >>> 8);
+    bc9 = (t0 << 24) | (t1 >>> 8);
+    t0 = s[28] ^ d8;
+    t1 = s[29] ^ d9;
+    bc0 = (t0 << 27) | (t1 >>> 5);
+    bc1 = (t1 << 27) | (t0 >>> 5);
+    s[40] = bc0 ^ (bc4 & ~bc2);
+    s[41] = bc1 ^ (bc5 & ~bc3);
+    s[12] = bc2 ^ (bc6 & ~bc4);
+    s[13] = bc3 ^ (bc7 & ~bc5);
+    s[34] = bc4 ^ (bc8 & ~bc6);
+    s[35] = bc5 ^ (bc9 & ~bc7);
+    s[6] = bc6 ^ (bc0 & ~bc8);
+    s[7] = bc7 ^ (bc1 & ~bc9);
+    s[28] = bc8 ^ (bc2 & ~bc0);
+    s[29] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[20] ^ d0;
+    t1 = s[21] ^ d1;
+    bc6 = (t1 << 9) | (t0 >>> 23);
+    bc7 = (t0 << 9) | (t1 >>> 23);
+    t0 = s[42] ^ d2;
+    t1 = s[43] ^ d3;
+    bc8 = (t0 << 2) | (t1 >>> 30);
+    bc9 = (t1 << 2) | (t0 >>> 30);
+    t0 = s[14] ^ d4;
+    t1 = s[15] ^ d5;
+    bc0 = (t1 << 30) | (t0 >>> 2);
+    bc1 = (t0 << 30) | (t1 >>> 2);
+    t0 = s[36] ^ d6;
+    t1 = s[37] ^ d7;
+    bc2 = (t1 << 23) | (t0 >>> 9);
+    bc3 = (t0 << 23) | (t1 >>> 9);
+    t0 = s[8] ^ d8;
+    t1 = s[9] ^ d9;
+    bc4 = (t1 << 7) | (t0 >>> 25);
+    bc5 = (t0 << 7) | (t1 >>> 25);
+    s[20] = bc0 ^ (bc4 & ~bc2);
+    s[21] = bc1 ^ (bc5 & ~bc3);
+    s[42] = bc2 ^ (bc6 & ~bc4);
+    s[43] = bc3 ^ (bc7 & ~bc5);
+    s[14] = bc4 ^ (bc8 & ~bc6);
+    s[15] = bc5 ^ (bc9 & ~bc7);
+    s[36] = bc6 ^ (bc0 & ~bc8);
+    s[37] = bc7 ^ (bc1 & ~bc9);
+    s[8] = bc8 ^ (bc2 & ~bc0);
+    s[9] = bc9 ^ (bc3 & ~bc1);
+
+    // Round 4
+    bc0 = s[0] ^ s[10] ^ s[20] ^ s[30] ^ s[40];
+    bc1 = s[1] ^ s[11] ^ s[21] ^ s[31] ^ s[41];
+    bc2 = s[2] ^ s[12] ^ s[22] ^ s[32] ^ s[42];
+    bc3 = s[3] ^ s[13] ^ s[23] ^ s[33] ^ s[43];
+    bc4 = s[4] ^ s[14] ^ s[24] ^ s[34] ^ s[44];
+    bc5 = s[5] ^ s[15] ^ s[25] ^ s[35] ^ s[45];
+    bc6 = s[6] ^ s[16] ^ s[26] ^ s[36] ^ s[46];
+    bc7 = s[7] ^ s[17] ^ s[27] ^ s[37] ^ s[47];
+    bc8 = s[8] ^ s[18] ^ s[28] ^ s[38] ^ s[48];
+    bc9 = s[9] ^ s[19] ^ s[29] ^ s[39] ^ s[49];
+
+    d0 = bc8 ^ ((bc2 << 1) | (bc3 >>> 31));
+    d1 = bc9 ^ ((bc3 << 1) | (bc2 >>> 31));
+    d2 = bc0 ^ ((bc4 << 1) | (bc5 >>> 31));
+    d3 = bc1 ^ ((bc5 << 1) | (bc4 >>> 31));
+    d4 = bc2 ^ ((bc6 << 1) | (bc7 >>> 31));
+    d5 = bc3 ^ ((bc7 << 1) | (bc6 >>> 31));
+    d6 = bc4 ^ ((bc8 << 1) | (bc9 >>> 31));
+    d7 = bc5 ^ ((bc9 << 1) | (bc8 >>> 31));
+    d8 = bc6 ^ ((bc0 << 1) | (bc1 >>> 31));
+    d9 = bc7 ^ ((bc1 << 1) | (bc0 >>> 31));
+
+    bc0 = s[0] ^ d0;
+    bc1 = s[1] ^ d1;
+    t0 = s[2] ^ d2;
+    t1 = s[3] ^ d3;
+    bc2 = (t1 << 12) | (t0 >>> 20);
+    bc3 = (t0 << 12) | (t1 >>> 20);
+    t0 = s[4] ^ d4;
+    t1 = s[5] ^ d5;
+    bc4 = (t1 << 11) | (t0 >>> 21);
+    bc5 = (t0 << 11) | (t1 >>> 21);
+    t0 = s[6] ^ d6;
+    t1 = s[7] ^ d7;
+    bc6 = (t0 << 21) | (t1 >>> 11);
+    bc7 = (t1 << 21) | (t0 >>> 11);
+    t0 = s[8] ^ d8;
+    t1 = s[9] ^ d9;
+    bc8 = (t0 << 14) | (t1 >>> 18);
+    bc9 = (t1 << 14) | (t0 >>> 18);
+    s[0] = bc0 ^ (bc4 & ~bc2) ^ KECCAK_RC[n + 6];
+    s[1] = bc1 ^ (bc5 & ~bc3) ^ KECCAK_RC[n + 7];
+    s[2] = bc2 ^ (bc6 & ~bc4);
+    s[3] = bc3 ^ (bc7 & ~bc5);
+    s[4] = bc4 ^ (bc8 & ~bc6);
+    s[5] = bc5 ^ (bc9 & ~bc7);
+    s[6] = bc6 ^ (bc0 & ~bc8);
+    s[7] = bc7 ^ (bc1 & ~bc9);
+    s[8] = bc8 ^ (bc2 & ~bc0);
+    s[9] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[10] ^ d0;
+    t1 = s[11] ^ d1;
+    bc4 = (t0 << 3) | (t1 >>> 29);
+    bc5 = (t1 << 3) | (t0 >>> 29);
+    t0 = s[12] ^ d2;
+    t1 = s[13] ^ d3;
+    bc6 = (t1 << 13) | (t0 >>> 19);
+    bc7 = (t0 << 13) | (t1 >>> 19);
+    t0 = s[14] ^ d4;
+    t1 = s[15] ^ d5;
+    bc8 = (t1 << 29) | (t0 >>> 3);
+    bc9 = (t0 << 29) | (t1 >>> 3);
+    t0 = s[16] ^ d6;
+    t1 = s[17] ^ d7;
+    bc0 = (t0 << 28) | (t1 >>> 4);
+    bc1 = (t1 << 28) | (t0 >>> 4);
+    t0 = s[18] ^ d8;
+    t1 = s[19] ^ d9;
+    bc2 = (t0 << 20) | (t1 >>> 12);
+    bc3 = (t1 << 20) | (t0 >>> 12);
+    s[10] = bc0 ^ (bc4 & ~bc2);
+    s[11] = bc1 ^ (bc5 & ~bc3);
+    s[12] = bc2 ^ (bc6 & ~bc4);
+    s[13] = bc3 ^ (bc7 & ~bc5);
+    s[14] = bc4 ^ (bc8 & ~bc6);
+    s[15] = bc5 ^ (bc9 & ~bc7);
+    s[16] = bc6 ^ (bc0 & ~bc8);
+    s[17] = bc7 ^ (bc1 & ~bc9);
+    s[18] = bc8 ^ (bc2 & ~bc0);
+    s[19] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[20] ^ d0;
+    t1 = s[21] ^ d1;
+    bc8 = (t0 << 18) | (t1 >>> 14);
+    bc9 = (t1 << 18) | (t0 >>> 14);
+    t0 = s[22] ^ d2;
+    t1 = s[23] ^ d3;
+    bc0 = (t0 << 1) | (t1 >>> 31);
+    bc1 = (t1 << 1) | (t0 >>> 31);
+    t0 = s[24] ^ d4;
+    t1 = s[25] ^ d5;
+    bc2 = (t0 << 6) | (t1 >>> 26);
+    bc3 = (t1 << 6) | (t0 >>> 26);
+    t0 = s[26] ^ d6;
+    t1 = s[27] ^ d7;
+    bc4 = (t0 << 25) | (t1 >>> 7);
+    bc5 = (t1 << 25) | (t0 >>> 7);
+    t0 = s[28] ^ d8;
+    t1 = s[29] ^ d9;
+    bc6 = (t0 << 8) | (t1 >>> 24);
+    bc7 = (t1 << 8) | (t0 >>> 24);
+    s[20] = bc0 ^ (bc4 & ~bc2);
+    s[21] = bc1 ^ (bc5 & ~bc3);
+    s[22] = bc2 ^ (bc6 & ~bc4);
+    s[23] = bc3 ^ (bc7 & ~bc5);
+    s[24] = bc4 ^ (bc8 & ~bc6);
+    s[25] = bc5 ^ (bc9 & ~bc7);
+    s[26] = bc6 ^ (bc0 & ~bc8);
+    s[27] = bc7 ^ (bc1 & ~bc9);
+    s[28] = bc8 ^ (bc2 & ~bc0);
+    s[29] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[30] ^ d0;
+    t1 = s[31] ^ d1;
+    bc2 = (t1 << 4) | (t0 >>> 28);
+    bc3 = (t0 << 4) | (t1 >>> 28);
+    t0 = s[32] ^ d2;
+    t1 = s[33] ^ d3;
+    bc4 = (t0 << 10) | (t1 >>> 22);
+    bc5 = (t1 << 10) | (t0 >>> 22);
+    t0 = s[34] ^ d4;
+    t1 = s[35] ^ d5;
+    bc6 = (t0 << 15) | (t1 >>> 17);
+    bc7 = (t1 << 15) | (t0 >>> 17);
+    t0 = s[36] ^ d6;
+    t1 = s[37] ^ d7;
+    bc8 = (t1 << 24) | (t0 >>> 8);
+    bc9 = (t0 << 24) | (t1 >>> 8);
+    t0 = s[38] ^ d8;
+    t1 = s[39] ^ d9;
+    bc0 = (t0 << 27) | (t1 >>> 5);
+    bc1 = (t1 << 27) | (t0 >>> 5);
+    s[30] = bc0 ^ (bc4 & ~bc2);
+    s[31] = bc1 ^ (bc5 & ~bc3);
+    s[32] = bc2 ^ (bc6 & ~bc4);
+    s[33] = bc3 ^ (bc7 & ~bc5);
+    s[34] = bc4 ^ (bc8 & ~bc6);
+    s[35] = bc5 ^ (bc9 & ~bc7);
+    s[36] = bc6 ^ (bc0 & ~bc8);
+    s[37] = bc7 ^ (bc1 & ~bc9);
+    s[38] = bc8 ^ (bc2 & ~bc0);
+    s[39] = bc9 ^ (bc3 & ~bc1);
+
+    t0 = s[40] ^ d0;
+    t1 = s[41] ^ d1;
+    bc6 = (t1 << 9) | (t0 >>> 23);
+    bc7 = (t0 << 9) | (t1 >>> 23);
+    t0 = s[42] ^ d2;
+    t1 = s[43] ^ d3;
+    bc8 = (t0 << 2) | (t1 >>> 30);
+    bc9 = (t1 << 2) | (t0 >>> 30);
+    t0 = s[44] ^ d4;
+    t1 = s[45] ^ d5;
+    bc0 = (t1 << 30) | (t0 >>> 2);
+    bc1 = (t0 << 30) | (t1 >>> 2);
+    t0 = s[46] ^ d6;
+    t1 = s[47] ^ d7;
+    bc2 = (t1 << 23) | (t0 >>> 9);
+    bc3 = (t0 << 23) | (t1 >>> 9);
+    t0 = s[48] ^ d8;
+    t1 = s[49] ^ d9;
+    bc4 = (t1 << 7) | (t0 >>> 25);
+    bc5 = (t0 << 7) | (t1 >>> 25);
+    s[40] = bc0 ^ (bc4 & ~bc2);
+    s[41] = bc1 ^ (bc5 & ~bc3);
+    s[42] = bc2 ^ (bc6 & ~bc4);
+    s[43] = bc3 ^ (bc7 & ~bc5);
+    s[44] = bc4 ^ (bc8 & ~bc6);
+    s[45] = bc5 ^ (bc9 & ~bc7);
+    s[46] = bc6 ^ (bc0 & ~bc8);
+    s[47] = bc7 ^ (bc1 & ~bc9);
+    s[48] = bc8 ^ (bc2 & ~bc0);
+    s[49] = bc9 ^ (bc3 & ~bc1);
+  }
+}
+
+// https://github.com/denoland/deno_std/blob/main/hash/_sha3/sponge.ts
+const STATE_SIZE = 200;
+const TYPE_ERROR_MSG = "sha3: `data` is invalid type";
+
+class Sponge {
+  #option;
+  #state;
+  #rp;
+  #absorbing;
+
+  constructor(option) {
+    this.#option = option;
+    this.#state = new Uint8Array(STATE_SIZE);
+    this.#rp = 0;
+    this.#absorbing = true;
+  }
+
+  /** Applies padding to internal state */
+  pad() {
+    this.#state[this.#rp] ^= this.#option.dsbyte;
+    this.#state[this.#option.rate - 1] ^= 0x80;
+  }
+
+  /** Squeezes internal state */
+  squeeze(length) {
+    if (length < 0) {
+      throw new Error("sha3: length cannot be negative");
+    }
+
+    this.pad();
+
+    const hash = new Uint8Array(length);
+    let pos = 0;
+    while (length > 0) {
+      const r = length > this.#option.rate ? this.#option.rate : length;
+      this.#option.permutator(this.#state);
+      hash.set(this.#state.slice(0, r), pos);
+      length -= r;
+      pos += r;
+    }
+
+    this.#absorbing = false;
+    return hash;
+  }
+
+  /** Updates internal state by absorbing */
+  update(data) {
+    if (!this.#absorbing) {
+      throw new Error("sha3: cannot update already finalized hash");
+    }
+
+    let msg;
+
+    if (typeof data === "string") {
+      msg = new TextEncoder().encode(data);
+    } else if (typeof data === "object") {
+      if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
+        msg = new Uint8Array(data);
+      } else {
+        throw new Error(TYPE_ERROR_MSG);
+      }
+    } else {
+      throw new Error(TYPE_ERROR_MSG);
+    }
+
+    let rp = this.#rp;
+
+    for (let i = 0; i < msg.length; ++i) {
+      this.#state[rp++] ^= msg[i];
+      if (rp >= this.#option.rate) {
+        this.#option.permutator(this.#state);
+        rp = 0;
+      }
+    }
+
+    this.#rp = rp;
+    return this;
+  }
+
+  /** Returns the hash in ArrayBuffer */
+  digest() {
+    return this.squeeze(this.#option.bitsize >> 3);
+  }
+}
+
+// https://github.com/denoland/deno_std/blob/main/hash/_sha3/keccak.ts
+export class Keccak256 extends Sponge {
+  constructor() {
+    super({
+      bitsize: 256,
+      rate: 136,
+      dsbyte: 1,
+      permutator: keccakf,
+    });
+  }
+}
This page took 0.057409 seconds and 4 git commands to generate.