22

I need to use bcrypt in Node, and as usual, there are 27 gazillion libraries to choose from.

The two top packages on npm are

  • bcrypt 247k downloads /month
  • bcryptjs 337k downloads /month
  • (anything else to be considered?)

How do they differ? Is there a compelling reason or use case to use one or the other?

Apparently the one is pure JS, and the other has bindings to a native C++ crypto library. And so the latter is faster than the former.

I've read that one should choose the fastest implementation of the slowest algorithm. So that means I should choose the non-JS one. However the JS one is even more popular. Why is that the case in node - is there a reason a "pure js" package is preferable to one that binds to a native library using node-gyp?

lonix
  • 14,255
  • 23
  • 85
  • 176
  • bcryptjs explicitly says *"Optimized bcrypt in JavaScript with zero dependencies."* So, yes, it's a pure Javascript implementation of bcrypt, which purportedly even "runs in the browser". bcrypt on the other hands list a number of dependencies. bcryptjs purports to be compatible with bcrypt. – deceze Feb 13 '19 at 16:04
  • 1
    The description page of bcryptjs states that it has no dependencies, is written in pure ja and is as of that 30% slower then the native binding. – t.niese Feb 13 '19 at 16:04
  • Your "fastest of the slowest algorithm" should actually say the "fastest _implementation_ of the slowest algorithm". In this case, that just means choose the better-performing library since they implement the same algorithms. – Patrick Roberts Feb 13 '19 at 17:17
  • @PatrickRoberts Why would one choose a pure JS library if it's slower? I'm new to node so I don't get it. There are many "pure js" libraries and they seem popular because of that. What is the reason for that? – lonix Feb 13 '19 at 17:19
  • 1
    They're more portable. If you're writing an isomorphic JavaScript program, you'll need a pure js implementation for all your dependencies, or you'll need to figure out how to compile them with Web Assembly. Doing the latter is sometimes very difficult or even impossible. – Patrick Roberts Feb 13 '19 at 17:22
  • 3
    I'm kind of amazed that there is only a 30% drop down in speed. Either JS compilers have become really good, or the implementation is fantastically performant (I guess it is), or the native lib sucks. Or possibly a combination of the three I guess. – Maarten Bodewes Feb 13 '19 at 18:24
  • Unless I'm mistaken, I think more important than the 30% speed increase is that the C++ implementation runs on a thread from the threadpool rather than the main JS thread – Cameron Sima Jul 27 '23 at 14:17

1 Answers1

16

When considering dependencies being run in Node.js only, there's no reason not to follow the advice given to you about choosing the fastest implementation, which in this case is demonstrated to be the native binding of bcrypt.

For isomorphic JavaScript, where you expect it to be run in the browser as well, you can't use native bindings. So in this case, bcryptjs is the fastest implementation available in pure JavaScript.

Your alternative in order to use bcrypt in an isomorphic setting would be to compile your native binding into WebAssembly if that's even possible. Some native bindings cannot currently be compiled to WebAssembly yet, but this package appears to have at least a subset of bcrypt implemented in WASM, though I cannot vet its performance or security in comparison to your current two options.

The drawback to using WebAssembly is significantly more development time especially if you're unfamiliar with the API, and that's hard to justify when bcryptjs is a drop-in replacement within the same ballpark of performance already.

elimerl
  • 3
  • 4
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153