SHA and Shake for scala

This is Secure Hash Algorithms family which is implemented for scala, scala-js and scala-native, without any dependencies.

This code base implements SHA-0, SHA-1, SHA-2 and SHA-3. Keep in mind that SHA-0 is broken and I've implemented it just for fun :)

The propose of this code to be fast enough to hash something up to a few megabytes at the worst case and at few kilobytes as usual case. Where? At any scala-based application where hashing isn't the bottleneck. This code hasn't got any CPU related optimizations, nor multithreading features for Keccak / SHA-3.

If you need very fast and secure hash function for scala I suggest to use blake3 which is 3 time faster.

You can use it as

libraryDependencies += "pt.kcry" %%% "sha" % "x.x.x"

The latest version is maven-central

API is pretty simple and quite limited :)

scala> import pt.kcry.sha._
import pt.kcry.sha._

scala> Sha2_256.hash("abc".getBytes())
val res1: Array[Byte] = Array(-70, 120, 22, -65, -113, 1, -49, -22, 65, 65, 64, -34, 93, -82, 34, 35, -80, 3, 97, -93, -106, 23, 122, -100, -76, 16, -1, 97, -14, 0, 21, -83)

scala> 

You may also create a new object from specified hash to update it, and at some point finish it like this:

scala> import pt.kcry.sha._
import pt.kcry.sha._

scala> val sha1 = new Sha1()
val sha1: pt.kcry.sha.Sha1 = pt.kcry.sha.Sha1@1224e1b6

scala> sha1.update("abc".getBytes(), 0, 2)

scala> sha1.update("abc".getBytes(), 2, 1)

scala> val hashed = new Array[Byte](20)
val hashed: Array[Byte] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

scala> sha1.finish(hashed, 0)

scala> hashed
val res3: Array[Byte] = Array(-87, -103, 62, 54, 71, 6, -127, 106, -70, 62, 37, 113, 120, 80, -62, 108, -100, -48, -40, -99)

scala> 

All these objects aren't thread safe. After finish it should be treated as broken.

Anyway, I did a few benchmarks to compare this implementation with JVM one which was run on JDK 11.0.11, OpenJDK 64-Bit Server VM, 11.0.11+9-LTS:

Benchmark                 (len)  Mode  Cnt    Score   Error  Units
ShaBenchmark.jvmSha1       1024  avgt    5    3,686 ± 0,005  us/op
ShaBenchmark.jvmSha1      16384  avgt    5   55,556 ± 1,103  us/op
ShaBenchmark.jvmSha256     1024  avgt    5    4,326 ± 0,012  us/op
ShaBenchmark.jvmSha256    16384  avgt    5   61,924 ± 0,025  us/op
ShaBenchmark.jvmSha3_256   1024  avgt    5    4,129 ± 0,045  us/op
ShaBenchmark.jvmSha3_256  16384  avgt    5   61,627 ± 1,422  us/op
ShaBenchmark.jvmSha3_512   1024  avgt    5    7,974 ± 0,091  us/op
ShaBenchmark.jvmSha3_512  16384  avgt    5  111,711 ± 0,372  us/op
ShaBenchmark.jvmSha512     1024  avgt    5    3,172 ± 0,001  us/op
ShaBenchmark.jvmSha512    16384  avgt    5   44,205 ± 0,024  us/op
ShaBenchmark.sha1          1024  avgt    5    4,285 ± 0,002  us/op
ShaBenchmark.sha1         16384  avgt    5   64,380 ± 0,022  us/op
ShaBenchmark.sha256        1024  avgt    5    4,330 ± 0,005  us/op
ShaBenchmark.sha256       16384  avgt    5   63,293 ± 0,024  us/op
ShaBenchmark.sha3_256      1024  avgt    5    5,919 ± 0,019  us/op
ShaBenchmark.sha3_256     16384  avgt    5   84,952 ± 0,468  us/op
ShaBenchmark.sha3_512      1024  avgt    5    8,114 ± 0,078  us/op
ShaBenchmark.sha3_512     16384  avgt    5  118,706 ± 0,924  us/op
ShaBenchmark.sha512        1024  avgt    5    3,168 ± 0,007  us/op
ShaBenchmark.sha512       16384  avgt    5   44,630 ± 0,017  us/op

for easy compare I've performed the same benchmark on blake3:

Benchmark                  (dataLen)  (hashLen)  Mode  Cnt   Score   Error  Units
Blake3Benchmark.newHasher       1024        256  avgt    5   2,143 ± 0,037  us/op
Blake3Benchmark.newHasher       1024        512  avgt    5   2,564 ± 0,019  us/op
Blake3Benchmark.newHasher      16384        256  avgt    5  26,472 ± 0,023  us/op
Blake3Benchmark.newHasher      16384        512  avgt    5  26,641 ± 0,131  us/op