Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize MD5 & SHA1 #77

Merged
merged 4 commits into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
@file:Suppress("ClassName")

package org.kotlincrypto.hash.benchmarks

import kotlinx.benchmark.*
import org.kotlincrypto.hash.md.MD5
import org.kotlincrypto.hash.sha1.SHA1
import org.kotlincrypto.hash.sha2.SHA256
import org.kotlincrypto.hash.sha2.SHA512
import org.kotlincrypto.hash.sha2.SHA512_224

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(BenchmarkTimeUnit.NANOSECONDS)
@Warmup(iterations = ITERATIONS, time = TIME_WARMUP)
@Measurement(iterations = ITERATIONS, time = TIME_MEASURE)
open class MD5Benchmark: DigestBenchmarkBase(MD5())

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(BenchmarkTimeUnit.NANOSECONDS)
@Warmup(iterations = ITERATIONS, time = TIME_WARMUP)
@Measurement(iterations = ITERATIONS, time = TIME_MEASURE)
open class SHA1Benchmark: DigestBenchmarkBase(SHA1())

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(BenchmarkTimeUnit.NANOSECONDS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
**/
@file:Suppress("ClassName")

package org.kotlincrypto.hash.benchmarks

import kotlinx.benchmark.*
import org.kotlincrypto.core.digest.Digest
import org.kotlincrypto.hash.sha3.ParallelHash128
import org.kotlincrypto.hash.sha3.SHA3_256
import org.kotlincrypto.hash.sha3.SHAKE128
Expand Down
132 changes: 71 additions & 61 deletions library/md/src/commonMain/kotlin/org/kotlincrypto/hash/md/MD5.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,54 +45,54 @@ public class MD5: Digest {
val s = S

val x = x
val state = state

var a = state[0]
var b = state[1]
var c = state[2]
var d = state[3]

for (i in 0..<blockSize()) {
when {
i < 16 -> {
var j = (i * 4) + offset
x[i] =
((input[j++].toInt() and 0xff) ) or
((input[j++].toInt() and 0xff) shl 8) or
((input[j++].toInt() and 0xff) shl 16) or
((input[j ].toInt() and 0xff) shl 24)

val g = i + 0
val f = ((b and c) or (b.inv() and d)) + a + k[i] + x[g]
a = d
d = c
c = b
b += f rotateLeft s[i]
}
i < 32 -> {
val g = ((5 * i) + 1) % 16
val f = ((d and b) or (d.inv() and c)) + a + k[i] + x[g]
a = d
d = c
c = b
b += f rotateLeft s[i]
}
i < 48 -> {
val g = ((3 * i) + 5) % 16
val f = (b xor c xor d) + a + k[i] + x[g]
a = d
d = c
c = b
b += f rotateLeft s[i]
}
else -> {
val g = (7 * i) % 16
val f = (c xor (b or d.inv())) + a + k[i] + x[g]
a = d
d = c
c = b
b += f rotateLeft s[i]
}
}
var j = offset
for (i in 0..<16) {
x[i] =
((input[j++].toInt() and 0xff) ) or
((input[j++].toInt() and 0xff) shl 8) or
((input[j++].toInt() and 0xff) shl 16) or
((input[j++].toInt() and 0xff) shl 24)

val g = i + 0
val f = ((b and c) or (b.inv() and d)) + a + k[i] + x[g]
a = d
d = c
c = b
b += f.rotateLeft(s[i])
}

for (i in 16..<32) {
val g = ((5 * i) + 1) % 16
val f = ((d and b) or (d.inv() and c)) + a + k[i] + x[g]
a = d
d = c
c = b
b += f.rotateLeft(s[i])
}

for (i in 32..<48) {
val g = ((3 * i) + 5) % 16
val f = (b xor c xor d) + a + k[i] + x[g]
a = d
d = c
c = b
b += f.rotateLeft(s[i])
}

for (i in 48..<64) {
val g = (7 * i) % 16
val f = (c xor (b or d.inv())) + a + k[i] + x[g]
a = d
d = c
c = b
b += f.rotateLeft(s[i])
}

state[0] += a
Expand All @@ -113,17 +113,21 @@ public class MD5: Digest {
buffer.fill(0, size, 56)
}

buffer[56] = (bitLength ).toByte()
buffer[57] = (bitLength ushr 8).toByte()
buffer[58] = (bitLength ushr 16).toByte()
buffer[59] = (bitLength ushr 24).toByte()
buffer[60] = (bitLength ushr 32).toByte()
buffer[61] = (bitLength ushr 40).toByte()
buffer[62] = (bitLength ushr 48).toByte()
buffer[63] = (bitLength ushr 56).toByte()
val lo = bitLength.toInt()
val hi = bitLength.rotateLeft(32).toInt()

buffer[56] = (lo ).toByte()
buffer[57] = (lo ushr 8).toByte()
buffer[58] = (lo ushr 16).toByte()
buffer[59] = (lo ushr 24).toByte()
buffer[60] = (hi ).toByte()
buffer[61] = (hi ushr 8).toByte()
buffer[62] = (hi ushr 16).toByte()
buffer[63] = (hi ushr 24).toByte()

compress(buffer, 0)

val state = state
val a = state[0]
val b = state[1]
val c = state[2]
Expand All @@ -150,16 +154,14 @@ public class MD5: Digest {
}

protected override fun resetDigest() {
val state = state
x.fill(0)
state[0] = 1732584193
state[1] = -271733879
state[2] = -1732584194
state[3] = 271733878
}

@Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
private inline infix fun Int.rotateLeft(n: Int): Int = (this shl n) or (this ushr (32 - n))

private companion object {
private val S = intArrayOf(
// round 1 left rotates
Expand All @@ -186,17 +188,25 @@ public class MD5: Digest {

private val K = intArrayOf(
// round 1
-680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426, -1473231341, -45705983,
1770035416, -1958414417, -42063, -1990404162, 1804603682, -40341101, -1502002290, 1236535329,
-680876936, -389564586, 606105819, -1044525330,
-176418897, 1200080426, -1473231341, -45705983,
1770035416, -1958414417, -42063, -1990404162,
1804603682, -40341101, -1502002290, 1236535329,
// round 2
-165796510, -1069501632, 643717713, -373897302, -701558691, 38016083, -660478335, -405537848,
568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784, 1735328473, -1926607734,
-165796510, -1069501632, 643717713, -373897302,
-701558691, 38016083, -660478335, -405537848,
568446438, -1019803690, -187363961, 1163531501,
-1444681467, -51403784, 1735328473, -1926607734,
// round 3
-378558, -2022574463, 1839030562, -35309556, -1530992060, 1272893353, -155497632, -1094730640,
681279174, -358537222, -722521979, 76029189, -640364487, -421815835, 530742520, -995338651,
-378558, -2022574463, 1839030562, -35309556,
-1530992060, 1272893353, -155497632, -1094730640,
681279174, -358537222, -722521979, 76029189,
-640364487, - 421815835, 530742520, -995338651,
// round 4
-198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606, -1051523, -2054922799,
1873313359, -30611744, -1560198380, 1309151649, -145523070, -1120210379, 718787259, -343485551,
-198630844, 1126891415, -1416354905, -57434055,
1700485571, -1894986606, -1051523, -2054922799,
1873313359, -30611744, -1560198380, 1309151649,
-145523070, -1120210379, 718787259, -343485551,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,42 +53,56 @@ public class SHA1: Digest {
}

for (i in 16..<80) {
x[i] = (x[i - 3] xor x[i - 8] xor x[i - 14] xor x[i - 16]) rotateLeft 1
x[i] = (x[i - 3] xor x[i - 8] xor x[i - 14] xor x[i - 16]).rotateLeft(1)
}

val state = state
var a = state[0]
var b = state[1]
var c = state[2]
var d = state[3]
var e = state[4]

for (i in 0..<80) {
val a2 = when {
i < 20 -> {
val f = d xor (b and (c xor d))
val k = 1518500249
(a rotateLeft 5) + f + e + k + x[i]
}
i < 40 -> {
val f = b xor c xor d
val k = 1859775393
(a rotateLeft 5) + f + e + k + x[i]
}
i < 60 -> {
val f = (b and c) or (b and d) or (c and d)
val k = -1894007588
(a rotateLeft 5) + f + e + k + x[i]
}
else -> {
val f = b xor c xor d
val k = -899497514
(a rotateLeft 5) + f + e + k + x[i]
}
}
for (i in 0..<20) {
val f = d xor (b and (c xor d))
val k = 1518500249
val a2 = (a.rotateLeft(5)) + f + e + k + x[i]
e = d
d = c
c = b.rotateLeft(30)
b = a
a = a2
}

for (i in 20..<40) {
val f = b xor c xor d
val k = 1859775393
val a2 = (a.rotateLeft(5)) + f + e + k + x[i]
e = d
d = c
c = b rotateLeft 30
c = b.rotateLeft(30)
b = a
a = a2
}

for (i in 40..<60) {
val f = (b and c) or (b and d) or (c and d)
val k = -1894007588
val a2 = (a.rotateLeft(5)) + f + e + k + x[i]
e = d
d = c
c = b.rotateLeft(30)
b = a
a = a2
}

for (i in 60..<80) {
val f = b xor c xor d
val k = -899497514
val a2 = (a.rotateLeft(5)) + f + e + k + x[i]
e = d
d = c
c = b.rotateLeft(30)
b = a
a = a2
}
Expand All @@ -112,17 +126,21 @@ public class SHA1: Digest {
buffer.fill(0, size, 56)
}

buffer[56] = (bitLength ushr 56).toByte()
buffer[57] = (bitLength ushr 48).toByte()
buffer[58] = (bitLength ushr 40).toByte()
buffer[59] = (bitLength ushr 32).toByte()
buffer[60] = (bitLength ushr 24).toByte()
buffer[61] = (bitLength ushr 16).toByte()
buffer[62] = (bitLength ushr 8).toByte()
buffer[63] = (bitLength ).toByte()
val lo = bitLength.toInt()
val hi = bitLength.rotateLeft(32).toInt()

buffer[56] = (hi ushr 24).toByte()
buffer[57] = (hi ushr 16).toByte()
buffer[58] = (hi ushr 8).toByte()
buffer[59] = (hi ).toByte()
buffer[60] = (lo ushr 24).toByte()
buffer[61] = (lo ushr 16).toByte()
buffer[62] = (lo ushr 8).toByte()
buffer[63] = (lo ).toByte()

compress(buffer, 0)

val state = state
val a = state[0]
val b = state[1]
val c = state[2]
Expand Down Expand Up @@ -154,14 +172,12 @@ public class SHA1: Digest {
}

protected override fun resetDigest() {
val state = state
x.fill(0)
state[0] = 1732584193
state[1] = -271733879
state[2] = -1732584194
state[3] = 271733878
state[4] = -1009589776
}

@Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
private inline infix fun Int.rotateLeft(n: Int): Int = (this shl n) or (this ushr (32 - n))
}
Loading
Loading