wg / scrypt

Java implementation of scrypt
Apache License 2.0
426 stars 144 forks source link

Simply "clone" the Mac for SHA256 Hashing #15

Open pfumagalli opened 10 years ago

pfumagalli commented 10 years ago

Hey Will,

On "Scrypt.java" you're calling every time:

public static byte[] scryptJ(byte[] passwd, byte[] salt, ...) {
    ....
    Mac mac = Mac.getInstance("HmacSHA256");
    ...
}

For whatever reason (bad karma on JSSE?) that call roughly takes 50% of the entire SCrypt calculation. Initialise the Mac statically and then call .clone() on it, you get double the performance (according to JProfiler).

private static final Mac SHARED_MAC = Mac.getInstance("HmacSHA256");
public static byte[] scryptJ(byte[] passwd, byte[] salt, ...) {
    ....
    Mac mac = (Mac) SHARED_MAC.clone();
    ...
}
wg commented 10 years ago

Hi @pfumagalli, thanks! I haven't actually profiled the Java impl as the native SSE2 impl was ~4x faster (not to mention the GC pressure) last time I checked. Are you using it server-side and the native impl isn't loading? I'd definitely like to fix that if so.

pfumagalli commented 10 years ago

I just want to run it as pure Java, I don't need raw speed at this moment, so avoiding the various non-trivialities of loading the native library (I'm actually just copying and pasting your code into something I'm working on, not using it directly).

For the GC pressure, you can pre-allocate your buffers (all those new int[...] and new byte[...]) with ThreadLocals, you won't gain performance, but the GC will be a lot happier!

rlubbat commented 8 years ago

Cloning may not work. It depends on the underlying JCE implementation. For example, we ran into this in a project that was using BouncyCastle. We had Mac.clone() and it blew up. If you want to clone the Mac for performance reasons, make sure you don't do it blindly. You will need to check if it is possible and proceed as appropriate. We ended up attempting the clone in the class constructor and used a boolean to indicate if cloning is possible. We check the boolean to decide to clone or get an instance in the code.