All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nativeMain.fr.acinq.bitcoin.crypto.Sha512.native.kt Maven / Gradle / Ivy

Go to download

A simple Kotlin Multiplatform library which implements most of the bitcoin protocol

The newest version!
/*
 * Copyright 2020 ACINQ SAS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package fr.acinq.bitcoin.crypto

public class Sha512Native : Digest {

    private val DIGEST_LENGTH = 64

    private val xBuf = ByteArray(8)
    private var xBufOff = 0

    private var byteCount1: Long = 0
    private var byteCount2: Long = 0

    private var H1: Long = 0
    private var H2: Long = 0
    private var H3: Long = 0
    private var H4: Long = 0
    private var H5: Long = 0
    private var H6: Long = 0
    private var H7: Long = 0
    private var H8: Long = 0

    private val W = LongArray(80)
    private var wOff = 0

    init {
        reset()
    }

    override fun getDigestSize(): Int {
        return DIGEST_LENGTH
    }

    override fun getAlgorithmName(): String {
        return "SHA-512"
    }

    override fun reset() {
        byteCount1 = 0
        byteCount2 = 0
        xBufOff = 0

        xBuf.fill(0.toByte())
        wOff = 0
        W.fill(0)

        H1 = 0x6a09e667f3bcc908L
        H2 = -0x4498517a7b3558c5L
        H3 = 0x3c6ef372fe94f82bL
        H4 = -0x5ab00ac5a0e2c90fL
        H5 = 0x510e527fade682d1L
        H6 = -0x64fa9773d4c193e1L
        H7 = 0x1f83d9abfb41bd6bL
        H8 = 0x5be0cd19137e2179L
    }

    override fun update(input: Byte) {
        xBuf[xBufOff++] = input
        if (xBufOff == xBuf.size) {
            processWord(xBuf, 0)
            xBufOff = 0
        }
        byteCount1++
    }

    override fun update(input: ByteArray, inputOffset: Int, len: Int) {
        // fill the current word
        var inOffset = inputOffset
        var length = len
        while (xBufOff != 0 && length > 0) {
            update(input[inOffset])
            inOffset++
            length--
        }

        // process whole words.
        while (length > xBuf.size) {
            processWord(input, inOffset)
            inOffset += xBuf.size
            length -= xBuf.size
            byteCount1 += xBuf.size.toLong()
        }

        // process the remainder.
        while (length > 0) {
            update(input[inOffset])
            inOffset++
            length--
        }
    }

    override fun doFinal(out: ByteArray, outOffset: Int): Int {
        finish()
        unpackWord(H1, out, outOffset)
        unpackWord(H2, out, outOffset + 8)
        unpackWord(H3, out, outOffset + 16)
        unpackWord(H4, out, outOffset + 24)
        unpackWord(H5, out, outOffset + 32)
        unpackWord(H6, out, outOffset + 40)
        unpackWord(H7, out, outOffset + 48)
        unpackWord(H8, out, outOffset + 56)
        reset()
        return DIGEST_LENGTH
    }

    private fun finish() {
        adjustByteCounts()
        val lowBitLength = byteCount1 shl 3
        val hiBitLength = byteCount2

        // add the pad bytes.
        update(128.toByte())
        while (xBufOff != 0) update(0.toByte())

        processLength(lowBitLength, hiBitLength)
        processBlock()
    }

    private fun processWord(`in`: ByteArray, inOff: Int) {
        W[wOff++] = ((`in`[inOff].toInt() and 0xff).toLong() shl 56
                or ((`in`[inOff + 1].toInt() and 0xff).toLong() shl 48)
                or ((`in`[inOff + 2].toInt() and 0xff).toLong() shl 40)
                or ((`in`[inOff + 3].toInt() and 0xff).toLong() shl 32)
                or ((`in`[inOff + 4].toInt() and 0xff).toLong() shl 24)
                or ((`in`[inOff + 5].toInt() and 0xff).toLong() shl 16)
                or ((`in`[inOff + 6].toInt() and 0xff).toLong() shl 8)
                or (`in`[inOff + 7].toInt() and 0xff).toLong())
        if (wOff == 16) processBlock()
    }

    private fun unpackWord(word: Long, out: ByteArray, outOff: Int) {
        out[outOff] = (word ushr 56).toByte()
        out[outOff + 1] = (word ushr 48).toByte()
        out[outOff + 2] = (word ushr 40).toByte()
        out[outOff + 3] = (word ushr 32).toByte()
        out[outOff + 4] = (word ushr 24).toByte()
        out[outOff + 5] = (word ushr 16).toByte()
        out[outOff + 6] = (word ushr 8).toByte()
        out[outOff + 7] = word.toByte()
    }

    /**
     * adjust the byte counts so that byteCount2 represents the
     * upper long (less 3 bits) word of the byte count.
     */
    private fun adjustByteCounts() {
        if (byteCount1 > 0x1fffffffffffffffL) {
            byteCount2 += byteCount1 ushr 61
            byteCount1 = byteCount1 and 0x1fffffffffffffffL
        }
    }

    private fun processLength(lowW: Long, hiW: Long) {
        if (wOff > 14) {
            processBlock()
        }
        W[14] = hiW
        W[15] = lowW
    }

    private fun processBlock() {
        adjustByteCounts()

        // expand 16 word block into 80 word blocks.
        for (t in 16..79) W[t] = Sigma1(W[t - 2]) + W[t - 7] + Sigma0(W[t - 15]) + W[t - 16]

        var a = H1
        var b: Long = H2
        var c: Long = H3
        var d: Long = H4
        var e: Long = H5
        var f: Long = H6
        var g: Long = H7
        var h: Long = H8
        for (t in 0..79) {
            val T1: Long = h + Sum1(e) + Ch(e, f, g) + K[t] + W[t]
            val T2: Long = Sum0(a) + Maj(a, b, c)
            h = g
            g = f
            f = e
            e = d + T1
            d = c
            c = b
            b = a
            a = T1 + T2
        }
        H1 += a
        H2 += b
        H3 += c
        H4 += d
        H5 += e
        H6 += f
        H7 += g
        H8 += h

        // reset the offset and clean out the word buffer.
        wOff = 0
        for (i in W.indices) W[i] = 0
    }

    private fun rotateRight(x: Long, n: Int): Long {
        return x ushr n or (x shl 64 - n)
    }

    /* sha-384 and sha-512 functions (as for sha-256 but for longs) */
    private fun Ch(x: Long, y: Long, z: Long): Long {
        return x and y xor (x.inv() and z)
    }

    private fun Maj(x: Long, y: Long, z: Long): Long {
        return x and y xor (x and z) xor (y and z)
    }

    private fun Sum0(x: Long): Long {
        return rotateRight(x, 28) xor rotateRight(x, 34) xor rotateRight(x, 39)
    }

    private fun Sum1(x: Long): Long {
        return rotateRight(x, 14) xor rotateRight(x, 18) xor rotateRight(x, 41)
    }

    private fun Sigma0(x: Long): Long {
        return rotateRight(x, 1) xor rotateRight(x, 8) xor (x ushr 7)
    }

    private fun Sigma1(x: Long): Long {
        return rotateRight(x, 19) xor rotateRight(x, 61) xor (x ushr 6)
    }

    public companion object {

        public val K: LongArray = longArrayOf(
            0x428a2f98d728ae22L, 0x7137449123ef65cdL, -0x4a3f043013b2c4d1L, -0x164a245a7e762444L,
            0x3956c25bf348b538L, 0x59f111f1b605d019L, -0x6dc07d5b50e6b065L, -0x54e3a12a25927ee8L,
            -0x27f855675cfcfdbeL, 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L,
            0x72be5d74f27b896fL, -0x7f214e01c4e9694fL, -0x6423f958da38edcbL, -0x3e640e8b3096d96cL,
            -0x1b64963e610eb52eL, -0x1041b879c7b0da1dL, 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L,
            0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L,
            -0x67c1aead11992055L, -0x57ce3992d24bcdf0L, -0x4ffcd8376704dec1L, -0x40a680384110f11cL,
            -0x391ff40cc257703eL, -0x2a586eb86cf558dbL, 0x06ca6351e003826fL, 0x142929670a0e6e70L,
            0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL,
            0x650a73548baf63deL, 0x766a0abb3c77b2a8L, -0x7e3d36d1b812511aL, -0x6d8dd37aeb7dcac5L,
            -0x5d40175eb30efc9cL, -0x57e599b443bdcfffL, -0x3db4748f2f07686fL, -0x3893ae5cf9ab41d0L,
            -0x2e6d17e62910ade8L, -0x2966f9dbaa9a56f0L, -0xbf1ca7aa88edfd6L, 0x106aa07032bbd1b8L,
            0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L,
            0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L,
            0x748f82ee5defb2fcL, 0x78a5636f43172f60L, -0x7b3787eb5e0f548eL, -0x7338fdf7e59bc614L,
            -0x6f410005dc9ce1d8L, -0x5baf9314217d4217L, -0x41065c084d3986ebL, -0x398e870d1c8dacd5L,
            -0x35d8c13115d99e64L, -0x2e794738de3f3df9L, -0x15258229321f14e2L, -0xa82b08011912e88L,
            0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL,
            0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL,
            0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L
        )
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy