bcrypt.js icon indicating copy to clipboard operation
bcrypt.js copied to clipboard

WebAssembly

Open lastmjs opened this issue 4 years ago • 12 comments

I've searched through the issues in this repository and the bcrypt repository: https://github.com/kelektiv/node.bcrypt.js, and it seems like no one is discussing this.

I think it could be useful to compile bcrypt to WebAssembly. Benefits:

  • Combine bcrypt for Node.js and bcryptjs, one universal binary for all popular JS engines
  • Remove requirement to compile for individual CPU architectures
  • Near native performance

WebAssembly could simplify a lot of installation and distribution requirements, and still maintain good performance. I hope it will be considered.

lastmjs avatar Jul 29 '19 18:07 lastmjs

@cekvenich Curious about the thumbs down, do you think this is a bad idea?

lastmjs avatar Aug 08 '19 16:08 lastmjs

Part of the reason I haven't tried to build anything requiring security in JS is I haven't wanted to deal with external dependencies (as in node.bcrypt.js) but I don't want the slowness of a pure JS implementation (like this). WASM is the future for things like this.

legowerewolf avatar Mar 10 '20 03:03 legowerewolf

WASM with a fallback to js would be amazing (https://caniuse.com/?search=wasm).

But is this project even active?

markhughes avatar Oct 06 '20 23:10 markhughes

in terms of performance, I found this wasm library https://github.com/styladev/bcrypt-fast-wasm and tested it under node@14 by comparing pwd B9qY1mIQYqmUZSeuoPD7 and hash $2a$18$7FBSfQmfL/xxL5i6SGmAKOafa/9RduerptAbTDQcFHEvet5lDuYrm

const bcryptfast = require('bcrypt-fast');
const bcryptjs = require('bcryptjs');
const bcrypt = require('bcrypt');

const pwd = 'B9qY1mIQYqmUZSeuoPD7';
const hash = '$2a$18$7FBSfQmfL/xxL5i6SGmAKOafa/9RduerptAbTDQcFHEvet5lDuYrm';

console.time('bcrypt-fast');
console.log(bcryptfast.verify(pwd, hash));
console.timeEnd('bcrypt-fast');

console.time('bcrypt');
console.log(bcrypt.compareSync(pwd, hash));
console.timeEnd('bcrypt');

console.time('bcryptjs');
console.log(bcryptjs.compareSync(pwd, hash));
console.timeEnd('bcryptjs');

the result I got was

  • bcrypt-fast: 24.787s
  • bcrypt: 19.775s
  • bcryptjs: 26.943s

I also compiled the bcrypt library used by bcrypt-fast in to native binary, the time it took for comparing was around 17s.

The original bcrypt-fast was built for nodejs so, I built it with --target=web and tested it in browsers. I upgraded dependencies to wasm-bindgen:0.2.69 and bcrypt:0.7.0 in order to build it successfully with my local tool chain. The result I got is the wasm one was actually slower in browser.

  • chrome
    • bcrypt-fast: 27.029s
    • bcryptjs: 24.603s
  • firefox
    • bcrypt-fast: 103.693s
    • bcryptjs: 30.040s

So probably it's not worth that much using wasm, in terms of performance.

knilink avatar Dec 06 '20 06:12 knilink

It would probably make a difference, if you use a c++ implementation instead of importing a rust module, which has probably some additional overhead?!

Uzlopak avatar Jan 08 '22 22:01 Uzlopak

Rust is the same sort of compiled language that C/C++ are. There won't be any overhead.

legowerewolf avatar Jan 09 '22 02:01 legowerewolf

Yeah, I am aware of that. But read the code of bcrypt-fast. It just imports the crate of bcrypt in rust. Compare this with https://www.npmjs.com/package/@node-rs/bcrypt where they have their own implementation of bcrypt in rust. So I assume, that importing the crate and having your own implementation as source code makes a difference.

Uzlopak avatar Jan 09 '22 02:01 Uzlopak

Yeah, I am aware of that. But read the code of bcrypt-fast. It just imports the crate of bcrypt in rust. Compare this with https://www.npmjs.com/package/@node-rs/bcrypt where they have their own implementation of bcrypt in rust. So I assume, that importing the crate and having your own implementation as source code makes a difference.

@node-rs/bcrypt also uses the create bcrypt from Crates.io, they don't have their own implementation

ref: https://github.com/napi-rs/node-rs/blob/d6cf2b6d7fb5ff1022799f5aac2dfcffd5784d9a/packages/bcrypt/Cargo.toml#L11

LinusU avatar Sep 26 '22 18:09 LinusU

@LinusU

What we could actually do is to use wasm and use simd support to improve the blowfish calculations.

See: https://www.cs1.tf.fau.de/research/system-security-group/avx-crypto/ https://faui1-files.cs.fau.de/filepool/projects/avx.crypto/blowfish-avx2-x86_64-asm_64.S

Back in january I tried to do it but my wasm skills are not that great to figure it out how to migrate that asm code to simd of wasm. Even paid some people on fiver to integrate the code into c++, but basically got only scammed by shabby devs. LOL

Uzlopak avatar Sep 28 '22 12:09 Uzlopak

I actually compiled two bcrypt libraries to wasm the other day, the OpenBSD and Openwall ones. The bcrypt native Node.js module uses the OpenBSD source as well, although it's modified...

  • https://github.com/LinusU/cwasm-openbsd-bcrypt
  • https://github.com/LinusU/cwasm-openwall-bcrypt

On my M1 MacBook Air, the OpenBSD library in WASM is almost exactly as fast as this package. And the Openwall version is almost as fast as the @node-rs/bcrypt one. The bcrypt native module is still fastest though. Note that this is probably different on maybe Linux x86_64 since @nodoe-rs/bcrypt claims to be the fastest.

Here is the raw data from my machine:

@node-rs/bcrypt x 4.14 ops/sec ±0.27% (15 runs sampled)
node bcrypt x 4.55 ops/sec ±0.06% (16 runs sampled)
bcryptjs x 3.70 ops/sec ±0.09% (14 runs sampled)
wasm OpenBSD x 3.70 ops/sec ±0.04% (14 runs sampled)
wasm Openwall x 4.12 ops/sec ±0.06% (15 runs sampled)
Hash round 12 bench suite: Fastest is node bcrypt

There is a PR to add these two new libraries to the benchmark here: https://github.com/napi-rs/node-rs/pull/649


Regarding SIMD, it would certainly be interesting to use that to speed up the process. Are you aware of any C/C++/Rust code that does this? The code you linked is x86 assembly that requires AVX2, and I'm not too familiar with it in order to be able to map it over to WASM SIMD instincts without some serious work. It would probably be fun to take a crack at it though 😄


As of right now, if you want an ~11% speed increase, you can use the @cwasm/openbsd-bcrypt package.

LinusU avatar Sep 28 '22 19:09 LinusU

There is even a avx version of the blowfish algorithm https://faui1-files.cs.fau.de/filepool/projects/avx.crypto/blowfish-avx-x86_64-asm_64.S

wasm simd is 128 bit but avx is afaik 256 bit. But still. Maybe someone with assembler avx skills can do a wasm simd port.

If you want we can try it together....

Uzlopak avatar Sep 29 '22 08:09 Uzlopak

would that break servers or js running on mobiles?

WadhahEssam avatar Aug 30 '23 17:08 WadhahEssam