Skip to content

Instantly share code, notes, and snippets.

@scoroberts
Created October 16, 2019 01:03
Show Gist options
  • Save scoroberts/a60d61a2cc3afba1e8813b338ecd1501 to your computer and use it in GitHub Desktop.
Save scoroberts/a60d61a2cc3afba1e8813b338ecd1501 to your computer and use it in GitHub Desktop.
Test of different Java based SHA-256 hash implementations
@Grab(group='com.google.guava', module='guava', version='19.0')
@Grab(group='commons-codec', module='commons-codec', version='1.13')
@Grab(group='bouncycastle', module='bcprov-jdk15', version='140')
import groovy.transform.CompileStatic
import java.security.MessageDigest
import java.nio.charset.StandardCharsets
import com.google.common.hash.Hashing
import org.apache.commons.codec.digest.DigestUtils
import org.bouncycastle.crypto.digests.SHA256Digest
//test string for all hashing implementations
String test = "lwkjt23uy45pojsdf;lnwo45y23po5i;lknwe;lknasdflnqw3uo5"
String hashJava(String str){
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] encodedhash = digest.digest(str.getBytes(StandardCharsets.UTF_8));
return bytesToHex(encodedhash)
}
@CompileStatic
String bytesToHex(byte[] hash) {
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if(hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
@CompileStatic
String groovyHash(String str){
str.digest('SHA-256')
}
@CompileStatic
String guavaHash(String str){
Hashing.sha256().hashString(str, StandardCharsets.UTF_8).toString();
}
@CompileStatic
String apacheHash(String str){
DigestUtils.sha256Hex(str)
}
@CompileStatic
String bouncyHash(String str){
SHA256Digest digest = new SHA256Digest();
byte[] keyByteArray = str.getBytes(StandardCharsets.UTF_8)
byte[] output = new byte[digest.getDigestSize()];
digest.update(keyByteArray, 0, keyByteArray.length);
digest.doFinal(output, 0);
bytesToHex(output)
}
long iterations = 100_0000
println "Hashing ${iterations} iterations of SHA-256"
//warm up, throw away
for (int x=0; x<1000; x++) hashJava(test)
long start = System.currentTimeMillis()
for (int x=0; x<iterations; x++) hashJava(test)
long end = System.currentTimeMillis()
println ("time java: ${end-start}\t\t${iterations*1000/(end-start)} hashes/sec")
for (int x=0; x<1000; x++) groovyHash(test)
start = System.currentTimeMillis()
for (int x=0; x<iterations; x++) groovyHash(test)
end = System.currentTimeMillis()
println ("time groovy: ${end-start}\t${iterations*1000/(end-start)} hashes/sec")
for (int x=0; x<1000; x++) apacheHash(test)
start = System.currentTimeMillis()
for (int x=0; x<iterations; x++) apacheHash(test)
end = System.currentTimeMillis()
println ("time apache: ${end-start}\t\t${iterations*1000/(end-start)} hashes/sec")
for (int x=0; x<1000; x++) guavaHash(test)
start = System.currentTimeMillis()
for (int x=0; x<iterations; x++) guavaHash(test)
end = System.currentTimeMillis()
println ("time guava: ${end-start}\t\t${iterations*1000/(end-start)} hashes/sec")
for (int x=0; x<1000; x++) bouncyHash(test)
start = System.currentTimeMillis()
for (int x=0; x<iterations; x++) bouncyHash(test)
end = System.currentTimeMillis()
println ("time bouncy: ${end-start}\t\t${iterations*1000/(end-start)} hashes/sec")
@defnull
Copy link

defnull commented Nov 6, 2019

Apache commons-codec does not implement its own MessageDigest algorithms, but uses the standard java implementation. Apache beeing more than twice as fast as java would not make any sense. Whatever your benchmark is measuring, it is not SHA256 performance.

Your warm-up phase is probably way too short. Switching around the order in which the tests are run will significantly change the results.

@scoroberts
Copy link
Author

I thought the same thing and moved them around. I ended up getting the same results -- and consistently the same results. I have also heard that Guava wraps standard, but there too I get better results. If you can find where they get similar results, that would be helpful.

@XZTDean
Copy link

XZTDean commented Jan 31, 2022

I think bytesToHex function makes the performance for MessageDigest and commons-codec different. If make both hashJava and apacheHash return byte[] to avoid transforming to hex string. Then they can get similar results.

@scoroberts
Copy link
Author

scoroberts commented Feb 1, 2022 via email

@scoroberts
Copy link
Author

Took advice to remove the String conversion portions here: https://gist.github.com/scoroberts/77cc2d5c28fa2faeb1626d8eb39ec8c8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment