Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <meta name="author" content="TransparentLC">
  <title>WebAssembly RC4 Benchmark</title>
</head>
<body>
  <h1>WebAssembly RC4 Benchmark</h1>
  Data Length (Bytes):
  <input id="length" type="number" value="16777216">
  <button id="run">Run</button>
  <pre id="result"></pre>
  <script>
    (async () => {
      const wasmMemory = new WebAssembly.Memory({ initial: 1 });
      const wasmModule = (await WebAssembly.instantiateStreaming(
        fetch('data:application/wasm;base64,AGFzbQEAAAAADQZkeWxpbmuAAgQAAAAADQZkeWxpbmuAAgQAAAABCwJgAABgBH9/f38AAiQCA2Vudg1fX21lbW9yeV9iYXNlA38AA2VudgZtZW1vcnkCAAADAwIAAQYGAX8AQQALB0EEE19fd2FzbV9hcHBseV9yZWxvY3MAAANyYzQAAQxfX2Rzb19oYW5kbGUDARJfX3Bvc3RfaW5zdGFudGlhdGUAAAr1AQIDAAEL7gEBBX8DQCMAIAVqIAQ6AAAgBEEBaiEEIAVBAWoiBUGAAkcNAAtBACEFA0AjACIEIAZqIgcgBCAAIAYgAnBqLQAAIActAAAiByAFQf8BcWpqIgVB/wFxaiIELQAAOgAAIAQgBzoAACAGQQFqIgZBgAJHDQALIAMEQEEAIQZBACEAQQAhAgNAIwAiBSACQQFqQf8BcSICaiIEIAUgBC0AACIHIABB/wFxaiIAQf8BcWoiCC0AADoAACAIIAc6AAAgASAGaiIIIAgtAAAgBSAHIAQtAABqQf8BcWotAABzOgAAIAZBAWoiBiADRw0ACwsLC4cCAQAjAAuAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='),
        {
          env: {
            memory: wasmMemory,
            __memory_base: 0,
          },
        }
      )).instance;
      /**
       * @param {Uint8Array} key
       * @param {Uint8Array} input
       * @returns {Uint8Array}
       */
      const wasmRc4 = (key, input) => {
        const sboxOffset = 256;
        const memoryRequired = key.length + input.length + sboxOffset;
        if (memoryRequired > wasmMemory.buffer.byteLength) {
          wasmMemory.grow(Math.ceil((memoryRequired - wasmMemory.buffer.byteLength) / 65536));
        }
        const wasmBuffer = new Uint8Array(wasmMemory.buffer);
        wasmBuffer.set(key, sboxOffset);
        wasmBuffer.set(input, sboxOffset + key.length);
        wasmModule.exports.rc4(sboxOffset, sboxOffset + key.length, key.length, input.length);
        return new Uint8Array(wasmBuffer.slice(sboxOffset + key.length, sboxOffset + key.length + input.length));
      }
      /**
       * @param {Uint8Array} key
       * @param {Uint8Array} input
       * @returns {Uint8Array}
       */
      const jsRc4 = (key, input) => {
        let i = 0;
        let j = 0;
        const keyLength = key.length;
        const inputLength = input.length;
        const sbox = new Uint8Array(256);
        for (i = 0; i < 256; ++i) sbox[i] = i;
        for (i = 0; i < 256; ++i) {
          j = (j + sbox[i] + key[i % keyLength]) & 0xFF;
          [sbox[i], sbox[j]] = [sbox[j], sbox[i]];
        }
        const output = new Uint8Array(inputLength);
        i = j = 0;
        for (let k = 0; k < inputLength; ++k) {
          i = (i + 1) & 0xFF;
          j = (j + sbox[i]) & 0xFF;
          [sbox[i], sbox[j]] = [sbox[j], sbox[i]];
          output[k] = input[k] ^ sbox[(sbox[i] + sbox[j]) & 0xFF];
        }
        return output;
      }
      document.getElementById('run').onclick = () => {
        const inputLength = parseInt(document.getElementById('length').value);
        if (inputLength <= 0) return;
        const rc4Key = new Uint8Array(1024).map(() => Math.random() * 256);
        const rc4Input = new Uint8Array(inputLength).map(() => Math.random() * 256);
        performance.mark('wasm-start');
        const wasmEncrypted = wasmRc4(rc4Key, rc4Input);
        performance.mark('wasm-end');
        performance.mark('js-start');
        const jsEncrypted = jsRc4(rc4Key, rc4Input);
        performance.mark('js-end');
        performance.measure('wasm', 'wasm-start', 'wasm-end');
        performance.measure('js', 'js-start', 'js-end');
        for (let j = 0; j < inputLength; j++) if (wasmEncrypted[j] !== jsEncrypted[j]) throw 'Not equal';
        const result = {
          length: inputLength,
          wasmTime: performance.getEntriesByName('wasm')[0].duration,
          jsTime: performance.getEntriesByName('js')[0].duration,
        };
        result.wasmSpeed = result.length / result.wasmTime;
        result.jsSpeed = result.length / result.jsTime;
        result.ratio = result.wasmSpeed / result.jsSpeed;
        const r2 = x => Math.round(x * 100) / 100;
        document.getElementById('result').innerText = [
          'Length: ' + result.length + ' Bytes',
          'WASM time: ' + r2(result.wasmTime) + ' ms',
          'JS time (ms): ' + r2(result.jsTime) + ' ms',
          'WASM speed: ' + r2(result.wasmSpeed) + ' Bytes/ms',
          'JS speed: ' + r2(result.jsSpeed) + ' Bytes/ms',
          'Speed up: ' + r2(result.ratio) + 'x',
        ].join('\n');
        performance.clearMarks();
        performance.clearMeasures();
      }
    })()
  </script>
</body>
</html>
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
anonymouspro
0viewers