惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
GbyAI
GbyAI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 三生石上(FineUI控件)
美团技术团队
Last Week in AI
Last Week in AI
WordPress大学
WordPress大学
L
LangChain Blog
雷峰网
雷峰网
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 叶小钗
Engineering at Meta
Engineering at Meta
腾讯CDC
Recent Announcements
Recent Announcements
The Register - Security
The Register - Security
有赞技术团队
有赞技术团队
Blog — PlanetScale
Blog — PlanetScale
博客园 - Franky
博客园 - 司徒正美
The Cloudflare Blog
Google DeepMind News
Google DeepMind News
T
Tailwind CSS Blog
C
Check Point Blog
小众软件
小众软件
V
Visual Studio Blog
V
V2EX
F
Full Disclosure
J
Java Code Geeks
MongoDB | Blog
MongoDB | Blog
罗磊的独立博客
人人都是产品经理
人人都是产品经理
量子位
Apple Machine Learning Research
Apple Machine Learning Research
F
Fortinet All Blogs
Microsoft Security Blog
Microsoft Security Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
博客园_首页
Y
Y Combinator Blog
N
Netflix TechBlog - Medium
酷 壳 – CoolShell
酷 壳 – CoolShell
Stack Overflow Blog
Stack Overflow Blog
Recorded Future
Recorded Future
G
Google Developers Blog
Vercel News
Vercel News
大猫的无限游戏
大猫的无限游戏
Microsoft Azure Blog
Microsoft Azure Blog
U
Unit 42
爱范儿
爱范儿
Jina AI
Jina AI

ValeriaVG

Agentic Development Survival Guide Simplicity Police The sunset of Arrogance as a Service How do I delegate when I can do it faster myself? Implementing custom Calendar component Plug & Play Modular Architecture for Scalable and Maintainable Apps ES Modules & Import Maps: Back to the Future Me & React: 5 Years in 15 Minutes 10 Reasons NOT to Use Go for Your Next Project How Build a Web App in 11 Minutes and Fall in Love With Sveltekit Master Git in 7 Minutes Master Binary in Five Minutes Five Pro Tips to Master Promises in Js How to Use Custom Files as Modules in Nodejs How to Do Magic With Numbers 5 Ways to Use Redis in Your Next Project
Crc 32 Checksum in Wasm and Raw Js Tutorial and Benchmark
Valeria Viana Gusmao · 2021-07-08 · via ValeriaVG

In this tutorial we'll build a cyclic redundancy check (CRC) hashing function. More specifically, its 32 bit variant called "CRC-32". I bumped into it in the PNG specification, but it's also used in Gzip and bunch of other formats and protocols. In short, it makes a tiny (4 bytes) hash out of whatever binary data you feed to it and changes significantly if data changes even slightly. Of course, such a tiny function is not even close to be crypto secure, therefore it's only used to check if data was transferred correctly.

I love JavaScript, but writing binary algorithm implementations in it is a torture thanks to signed integers conversion in bitwise operations. So, I've decided to write implementation in a strongly typed system language, my other favourite, rust and compile it to WebAssembly.

What is WebAssembly

WebAssembly (a.k.a. WASM) provides a virtual machine that can be created from JavaScript environment (browser, nodejs or deno). This machine is super limited and runs only one binary program in a sandbox environment. It might sound boring, but, in fact, it can run almost anything: media manipulation software, AI, games - you name it.

Installing rust and wasm tooling

If you are on a MacOS/Linux/other Unix machine installing rust is as simple as running this command in a terminal and following interactive instructions:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

To install on other OS refer to rustup installation instructions

Once you're done this should work:

rustc --version # rustc 1.53.0 (53cb7b09b 2021-06-17)

Next step is to install wasm-pack, a tool that compiles your WebAssembly module, generates JavaScript glue and TypeScript types for it.

If you're on a Unix machine the command is:

curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

For other OS: refer to wasm-pack installation instructions.

Once again, make sure it's working:

wasm-pack --version # wasm-pack 0.10.0

Creating rust project

Rust comes with its own dependency manager cargo. It also helps with some routine operations, like project creation. Run this command to generate project folder and navigate into it:

cargo new --lib wasm-test && cd wasm-test

We should add crate type (cdylib) and the wasm binding dependency (wasm-bindgen) in the generated Cargo.toml:

[package] name = "wasm-test" version = "0.1.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2"

Now let's add the CRC-32 algorithm implementation to src/lib.rs:

use wasm_bindgen::prelude::*; // Pre-computed, see tests const CRC_TABLE: [u32; 256] = [ 0, 1996959894, 3993919788, 2567524794, 124634137, 1886057615, 3915621685, 2657392035, 249268274, 2044508324, 3772115230, 2547177864, 162941995, 2125561021, 3887607047, 2428444049, 498536548, 1789927666, 4089016648, 2227061214, 450548861, 1843258603, 4107580753, 2211677639, 325883990, 1684777152, 4251122042, 2321926636, 335633487, 1661365465, 4195302755, 2366115317, 997073096, 1281953886, 3579855332, 2724688242, 1006888145, 1258607687, 3524101629, 2768942443, 901097722, 1119000684, 3686517206, 2898065728, 853044451, 1172266101, 3705015759, 2882616665, 651767980, 1373503546, 3369554304, 3218104598, 565507253, 1454621731, 3485111705, 3099436303, 671266974, 1594198024, 3322730930, 2970347812, 795835527, 1483230225, 3244367275, 3060149565, 1994146192, 31158534, 2563907772, 4023717930, 1907459465, 112637215, 2680153253, 3904427059, 2013776290, 251722036, 2517215374, 3775830040, 2137656763, 141376813, 2439277719, 3865271297, 1802195444, 476864866, 2238001368, 4066508878, 1812370925, 453092731, 2181625025, 4111451223, 1706088902, 314042704, 2344532202, 4240017532, 1658658271, 366619977, 2362670323, 4224994405, 1303535960, 984961486, 2747007092, 3569037538, 1256170817, 1037604311, 2765210733, 3554079995, 1131014506, 879679996, 2909243462, 3663771856, 1141124467, 855842277, 2852801631, 3708648649, 1342533948, 654459306, 3188396048, 3373015174, 1466479909, 544179635, 3110523913, 3462522015, 1591671054, 702138776, 2966460450, 3352799412, 1504918807, 783551873, 3082640443, 3233442989, 3988292384, 2596254646, 62317068, 1957810842, 3939845945, 2647816111, 81470997, 1943803523, 3814918930, 2489596804, 225274430, 2053790376, 3826175755, 2466906013, 167816743, 2097651377, 4027552580, 2265490386, 503444072, 1762050814, 4150417245, 2154129355, 426522225, 1852507879, 4275313526, 2312317920, 282753626, 1742555852, 4189708143, 2394877945, 397917763, 1622183637, 3604390888, 2714866558, 953729732, 1340076626, 3518719985, 2797360999, 1068828381, 1219638859, 3624741850, 2936675148, 906185462, 1090812512, 3747672003, 2825379669, 829329135, 1181335161, 3412177804, 3160834842, 628085408, 1382605366, 3423369109, 3138078467, 570562233, 1426400815, 3317316542, 2998733608, 733239954, 1555261956, 3268935591, 3050360625, 752459403, 1541320221, 2607071920, 3965973030, 1969922972, 40735498, 2617837225, 3943577151, 1913087877, 83908371, 2512341634, 3803740692, 2075208622, 213261112, 2463272603, 3855990285, 2094854071, 198958881, 2262029012, 4057260610, 1759359992, 534414190, 2176718541, 4139329115, 1873836001, 414664567, 2282248934, 4279200368, 1711684554, 285281116, 2405801727, 4167216745, 1634467795, 376229701, 2685067896, 3608007406, 1308918612, 956543938, 2808555105, 3495958263, 1231636301, 1047427035, 2932959818, 3654703836, 1088359270, 936918000, 2847714899, 3736837829, 1202900863, 817233897, 3183342108, 3401237130, 1404277552, 615818150, 3134207493, 3453421203, 1423857449, 601450431, 3009837614, 3294710456, 1567103746, 711928724, 3020668471, 3272380065, 1510334235, 755167117, ]; /** * Reference implementation * http://libpng.org/pub/png/spec/iso/index-object.html#D-CRCAppendix */ #[wasm_bindgen] pub fn crc(buf: Vec<u8>) -> u32 { let mut c: u32 = 0xffffffff; for v in buf { let idx: usize = (c as usize ^ v as usize) & 0xff; c = CRC_TABLE[idx] ^ (c >> 8); } c ^ 0xffffffff } #[cfg(test)] mod tests { use super::*; #[test] fn test_table() { let mut crc_table: [u32; 256] = [0; 256]; let mut c: usize; for n in 0..256 { c = n; for _ in 0..8 { c = if c & 1 == 1 { 0xedb88320 ^ (c >> 1) } else { c >> 1 } } crc_table[n] = c as u32; } assert_eq!(CRC_TABLE, crc_table); } #[test] fn test_iend() { assert_eq!(crc("IEND".as_bytes().to_vec()), 0xAE426082); } }

The implementation uses pre-computed table for each byte value from 0x00 to 0xff and boils down to couple bitwise operations.

Macros #[wasm_bindgen] marks the function we want to export.

The unit tests in the end of the file can be run with:

cargo test # running 2 tests # test tests::test_iend ... ok # test tests::test_table ... ok # test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Compiling WASM for Web Browser

Run this command:

wasm-pack build --target web --release

It creates a pkg folder with WASM module, TypeScript types, package.json and the main wasm_test.js file.

Let's create index.html file in the project root and import the generated script from there:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>WASM Test</title> </head> <body> <div> <textarea id="input" placeholder="Place your data here"> Hello,WASM!</textarea > <br /> <textarea id="output" readonly placeholder="Resulting HEX will be displayed here" ></textarea> <br /> <button disabled id="btn">Calculate CRC-32</button> </div> <script type="module"> import init, { crc } from "./pkg/wasm_test.js"; const btn = document.getElementById("btn"); const input = document.getElementById("input"); const output = document.getElementById("output"); init().then(() => { btn.disabled = false; btn.onclick = () => { const buffer = new TextEncoder().encode(input.value); output.value = crc(buffer).toString(16); }; }); </script> </body> </html>

For security reasons you won't be able to test this html file by simply opening it, but you can start a simple file server with:

npx serve . # npx: installed 88 in 6.469s # # ┌────────────────────────────────────────┐ # │ │ # │ Serving! │ # │ │ # │ Local: http://localhost:5000 │ # │ │ # │ Copied local address to clipboard! │ # │ │ # └────────────────────────────────────────┘ #

If you can't run this command, that probably means that either NodeJS or NPM is not installed.

Navigate your browser to http://localhost:5000 and click the "Calculate CRC-32" button to see something like this: CRC-32 of "Hello,WASM!" is "ce9e250b"

Comparing JS and WASM performance

Let's create nearly identical JavaScript implementation of CRC-32 in crc.js:

const CRC_TABLE = new Uint32Array([ 0, 1996959894, 3993919788, 2567524794, 124634137, 1886057615, 3915621685, 2657392035, 249268274, 2044508324, 3772115230, 2547177864, 162941995, 2125561021, 3887607047, 2428444049, 498536548, 1789927666, 4089016648, 2227061214, 450548861, 1843258603, 4107580753, 2211677639, 325883990, 1684777152, 4251122042, 2321926636, 335633487, 1661365465, 4195302755, 2366115317, 997073096, 1281953886, 3579855332, 2724688242, 1006888145, 1258607687, 3524101629, 2768942443, 901097722, 1119000684, 3686517206, 2898065728, 853044451, 1172266101, 3705015759, 2882616665, 651767980, 1373503546, 3369554304, 3218104598, 565507253, 1454621731, 3485111705, 3099436303, 671266974, 1594198024, 3322730930, 2970347812, 795835527, 1483230225, 3244367275, 3060149565, 1994146192, 31158534, 2563907772, 4023717930, 1907459465, 112637215, 2680153253, 3904427059, 2013776290, 251722036, 2517215374, 3775830040, 2137656763, 141376813, 2439277719, 3865271297, 1802195444, 476864866, 2238001368, 4066508878, 1812370925, 453092731, 2181625025, 4111451223, 1706088902, 314042704, 2344532202, 4240017532, 1658658271, 366619977, 2362670323, 4224994405, 1303535960, 984961486, 2747007092, 3569037538, 1256170817, 1037604311, 2765210733, 3554079995, 1131014506, 879679996, 2909243462, 3663771856, 1141124467, 855842277, 2852801631, 3708648649, 1342533948, 654459306, 3188396048, 3373015174, 1466479909, 544179635, 3110523913, 3462522015, 1591671054, 702138776, 2966460450, 3352799412, 1504918807, 783551873, 3082640443, 3233442989, 3988292384, 2596254646, 62317068, 1957810842, 3939845945, 2647816111, 81470997, 1943803523, 3814918930, 2489596804, 225274430, 2053790376, 3826175755, 2466906013, 167816743, 2097651377, 4027552580, 2265490386, 503444072, 1762050814, 4150417245, 2154129355, 426522225, 1852507879, 4275313526, 2312317920, 282753626, 1742555852, 4189708143, 2394877945, 397917763, 1622183637, 3604390888, 2714866558, 953729732, 1340076626, 3518719985, 2797360999, 1068828381, 1219638859, 3624741850, 2936675148, 906185462, 1090812512, 3747672003, 2825379669, 829329135, 1181335161, 3412177804, 3160834842, 628085408, 1382605366, 3423369109, 3138078467, 570562233, 1426400815, 3317316542, 2998733608, 733239954, 1555261956, 3268935591, 3050360625, 752459403, 1541320221, 2607071920, 3965973030, 1969922972, 40735498, 2617837225, 3943577151, 1913087877, 83908371, 2512341634, 3803740692, 2075208622, 213261112, 2463272603, 3855990285, 2094854071, 198958881, 2262029012, 4057260610, 1759359992, 534414190, 2176718541, 4139329115, 1873836001, 414664567, 2282248934, 4279200368, 1711684554, 285281116, 2405801727, 4167216745, 1634467795, 376229701, 2685067896, 3608007406, 1308918612, 956543938, 2808555105, 3495958263, 1231636301, 1047427035, 2932959818, 3654703836, 1088359270, 936918000, 2847714899, 3736837829, 1202900863, 817233897, 3183342108, 3401237130, 1404277552, 615818150, 3134207493, 3453421203, 1423857449, 601450431, 3009837614, 3294710456, 1567103746, 711928724, 3020668471, 3272380065, 1510334235, 755167117, ]); function update_crc(crc, buf) { let c = crc; for (const v of buf) { const idx = ((c ^ v) & 0xff) >>> 0; c = (CRC_TABLE[idx] ^ (c >>> 8)) >>> 0; } return c; } export default (buf) => (update_crc(0xffffffff, buf) ^ 0xffffffff) >>> 0;

The only thing that differs is the unsigned right shift (>>>) we added to get rid of signs in JS numbers.

We can now include this implementation along with some performance measurements in index.html:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>WASM Test</title> </head> <body> <div> <textarea id="input" placeholder="Place your data here"> Hello,WASM!</textarea > <br /> <textarea id="output" readonly placeholder="Resulting HEX will be displayed here" ></textarea> <br /> <button disabled id="btn-wasm">Calculate CRC-32 (WASM)</button ><button id="btn-js">Calculate CRC-32 ( JS )</button> </div> <script type="module"> import init, { crc } from "./pkg/wasm_test.js"; import crcjs from "./crc.js"; const input = document.getElementById("input"); const output = document.getElementById("output"); const calculate = (fn, name) => { const buffer = new TextEncoder().encode(input.value); const t0 = performance.now(); output.value = fn(buffer).toString(16); const t1 = performance.now(); console.log(`${name}: ${t1 - t0} ms`); }; document.getElementById("btn-js").onclick = () => calculate(crcjs, "js"); init().then(() => { const btnWASM = document.getElementById("btn-wasm"); btnWASM.disabled = false; btnWASM.onclick = () => calculate(crc, "wasm"); }); </script> </body> </html>

Reload the page and check it out (open console to see performance information): 5 paragraphs of "Lorem Ipsum" took wasm: 0.10 ms vs js: 0.30 ms

Not bad, WASM is nearly three times faster on 5 paragraphs of text, but both of them are still very fast. How about a bigger challenge?

Update index.html one last time:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>WASM Test</title> </head> <body> <div> <textarea id="input" placeholder="Place your data here"> Hello,WASM!</textarea > <br /> <textarea id="output" readonly placeholder="Resulting HEX will be displayed here" ></textarea> <br /> <button disabled id="btn-wasm">Calculate CRC-32 (WASM)</button ><button id="btn-js">Calculate CRC-32 ( JS )</button> <hr /> <button id="btn-test" disabled>Compare Performance</button> <div id="result"></div> </div> <script type="module"> import init, { crc } from "./pkg/wasm_test.js"; import crcjs from "./crc.js"; const input = document.getElementById("input"); const output = document.getElementById("output"); const calculate = (fn, name) => { const buffer = new TextEncoder().encode(input.value); const t0 = performance.now(); output.value = fn(buffer).toString(16); const t1 = performance.now(); console.log(`${name}: ${t1 - t0} ms`); }; document.getElementById("btn-js").onclick = () => calculate(crcjs, "js"); init().then(() => { const btnWASM = document.getElementById("btn-wasm"); btnWASM.disabled = false; btnWASM.onclick = () => calculate(crc, "wasm"); const btnTest = document.getElementById("btn-test"); btnTest.disabled = false; const result = document.getElementById("result"); btnTest.onclick = () => { // Max random buffer result.innerHTML = ""; const data = window.crypto.getRandomValues(new Uint8Array(65536)); console.info("Test data", data); const t10 = performance.now(); const hash1 = crcjs(data).toString(16); const t11 = performance.now(); result.innerHTML += `<b>js</b>: ${(t11 - t10).toFixed(2)} ms<br/>`; console.info("JS hash", hash1.toString(16)); const t00 = performance.now(); const hash2 = crc(data).toString(16); const t01 = performance.now(); result.innerHTML += `<b>wasm</b>: ${(t01 - t00).toFixed(2)} ms<br/>`; console.info("WASM hash", hash2.toString(16)); }; }); </script> </body> </html>

I've added the third button that creates a big random binary array (65.5Kb), marks time, runs JS and WASM CRC-32 implementation over that buffer and shares the findings.

Here are the results I got in Edge, Safari and Firefox: Edge (js:6.70ms, wasm:0.60ms), Safari: (js: 10.00ms, wasm: 1.00ms) and Firefox (js: 7.00ms, 2.00ms)

Using WASM from NodeJS

Similarly to web target, we can build NodeJS-friendly package by running:

wasm-pack build --target nodejs --out-dir pkg-node --release

The contents of pkg-node are mostly the same as web pkg, except for wasm_test.js, that now reads WASM module from the file system.

Create index.js with:

const { PerformanceObserver, performance } = require("perf_hooks"); const crypto = require("crypto"); const { crc } = require("./pkg-node/wasm_test.js"); const crcJS = require("./crc.cjs"); const perfObserver = new PerformanceObserver((items) => { items.getEntries().forEach((entry) => { console.log(entry.name, entry.duration, "ms"); }); }); perfObserver.observe({ entryTypes: ["measure"], buffer: true }); const size = 10_000_000; crypto.randomBytes(size, (err, data) => { if (err) throw err; console.log(`Generated random ${(size / 1_000_000).toFixed(0)}MB of data`); performance.mark("wasm-start"); const crcwasm = crc(data); performance.mark("wasm-end"); performance.mark("js-start"); const crcjs = crcJS(data); performance.mark("js-end"); console.assert(crcjs, crcwasm, "CRC values differ!"); performance.measure("js ", "js-start", "js-end"); performance.measure("wasm", "wasm-start", "wasm-end"); });

The imported CommonJS script crc.cjs is identical to crc.js apart from the last line ( export default => module.exports):

const CRC_TABLE = new Uint32Array([ 0, 1996959894, 3993919788, 2567524794, 124634137, 1886057615, 3915621685, 2657392035, 249268274, 2044508324, 3772115230, 2547177864, 162941995, 2125561021, 3887607047, 2428444049, 498536548, 1789927666, 4089016648, 2227061214, 450548861, 1843258603, 4107580753, 2211677639, 325883990, 1684777152, 4251122042, 2321926636, 335633487, 1661365465, 4195302755, 2366115317, 997073096, 1281953886, 3579855332, 2724688242, 1006888145, 1258607687, 3524101629, 2768942443, 901097722, 1119000684, 3686517206, 2898065728, 853044451, 1172266101, 3705015759, 2882616665, 651767980, 1373503546, 3369554304, 3218104598, 565507253, 1454621731, 3485111705, 3099436303, 671266974, 1594198024, 3322730930, 2970347812, 795835527, 1483230225, 3244367275, 3060149565, 1994146192, 31158534, 2563907772, 4023717930, 1907459465, 112637215, 2680153253, 3904427059, 2013776290, 251722036, 2517215374, 3775830040, 2137656763, 141376813, 2439277719, 3865271297, 1802195444, 476864866, 2238001368, 4066508878, 1812370925, 453092731, 2181625025, 4111451223, 1706088902, 314042704, 2344532202, 4240017532, 1658658271, 366619977, 2362670323, 4224994405, 1303535960, 984961486, 2747007092, 3569037538, 1256170817, 1037604311, 2765210733, 3554079995, 1131014506, 879679996, 2909243462, 3663771856, 1141124467, 855842277, 2852801631, 3708648649, 1342533948, 654459306, 3188396048, 3373015174, 1466479909, 544179635, 3110523913, 3462522015, 1591671054, 702138776, 2966460450, 3352799412, 1504918807, 783551873, 3082640443, 3233442989, 3988292384, 2596254646, 62317068, 1957810842, 3939845945, 2647816111, 81470997, 1943803523, 3814918930, 2489596804, 225274430, 2053790376, 3826175755, 2466906013, 167816743, 2097651377, 4027552580, 2265490386, 503444072, 1762050814, 4150417245, 2154129355, 426522225, 1852507879, 4275313526, 2312317920, 282753626, 1742555852, 4189708143, 2394877945, 397917763, 1622183637, 3604390888, 2714866558, 953729732, 1340076626, 3518719985, 2797360999, 1068828381, 1219638859, 3624741850, 2936675148, 906185462, 1090812512, 3747672003, 2825379669, 829329135, 1181335161, 3412177804, 3160834842, 628085408, 1382605366, 3423369109, 3138078467, 570562233, 1426400815, 3317316542, 2998733608, 733239954, 1555261956, 3268935591, 3050360625, 752459403, 1541320221, 2607071920, 3965973030, 1969922972, 40735498, 2617837225, 3943577151, 1913087877, 83908371, 2512341634, 3803740692, 2075208622, 213261112, 2463272603, 3855990285, 2094854071, 198958881, 2262029012, 4057260610, 1759359992, 534414190, 2176718541, 4139329115, 1873836001, 414664567, 2282248934, 4279200368, 1711684554, 285281116, 2405801727, 4167216745, 1634467795, 376229701, 2685067896, 3608007406, 1308918612, 956543938, 2808555105, 3495958263, 1231636301, 1047427035, 2932959818, 3654703836, 1088359270, 936918000, 2847714899, 3736837829, 1202900863, 817233897, 3183342108, 3401237130, 1404277552, 615818150, 3134207493, 3453421203, 1423857449, 601450431, 3009837614, 3294710456, 1567103746, 711928724, 3020668471, 3272380065, 1510334235, 755167117, ]); function update_crc(crc, buf) { let c = crc; for (const v of buf) { const idx = ((c ^ v) & 0xff) >>> 0; c = (CRC_TABLE[idx] ^ (c >>> 8)) >>> 0; } return c; } module.exports = (buf) => (update_crc(0xffffffff, buf) ^ 0xffffffff) >>> 0;

Finally, run the script:

node index # Generated random 10MB of data # js 253.875679 ms # wasm 39.126159 ms

The bigger the size of the data to hash, the bigger is the gap between JS and WASM speeds:

# Generated random 100MB of data js 2461.758713 ms wasm 389.698142 ms # Generated random 1000MB of data js 25945.486315 ms wasm 3763.860294 ms