dcodeIO / bcrypt.js

Optimized bcrypt in plain JavaScript with zero dependencies.
Other
3.47k stars 264 forks source link

WebAssembly #103

Open lastmjs opened 4 years ago

lastmjs commented 4 years ago

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:

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

lastmjs commented 4 years ago

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

legowerewolf commented 4 years ago

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.

markhughes commented 3 years ago

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

But is this project even active?

knilink commented 3 years ago

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

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.

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

Uzlopak commented 2 years ago

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

legowerewolf commented 2 years ago

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

Uzlopak commented 2 years ago

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.

LinusU commented 1 year ago

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

Uzlopak commented 1 year ago

@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

LinusU commented 1 year ago

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...

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.

Uzlopak commented 1 year ago

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....

WadhahEssam commented 10 months ago

would that break servers or js running on mobiles?