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

nativeMain.fr.acinq.bitcoin.crypto.Sha256.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 Sha256Native : Digest {
    private val xBuf = ByteArray(4)
    private var xBufOff = 0

    private var byteCount: Long = 0

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

    private val X = IntArray(64)
    private var xOff = 0

    /**
     * Standard constructor
     */
    init {
        reset()
    }

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

    override fun getDigestSize(): Int {
        return DIGEST_LENGTH
    }

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

    override fun update(input: ByteArray, inputOffset: Int, len: Int) {
        val len1 = kotlin.math.max(0, len)

        //
        // fill the current word
        //
        var i = 0
        if (xBufOff != 0) {
            while (i < len1) {
                xBuf[xBufOff++] = input[inputOffset + i++]
                if (xBufOff == 4) {
                    processWord(xBuf, 0)
                    xBufOff = 0
                    break
                }
            }
        }

        //
        // process whole words.
        //
        val limit = (len1 - i and 3.inv()) + i
        while (i < limit) {
            processWord(input, inputOffset + i)
            i += 4
        }

        //
        // load in the remainder.
        //
        while (i < len1) {
            xBuf[xBufOff++] = input[inputOffset + i++]
        }
        byteCount += len1.toLong()
    }

    private fun processWord(`in`: ByteArray, inOff: Int) {
        // Note: Inlined for performance
//        X[xOff] = Pack.bigEndianToInt(in, inOff);
        var n: Int = (`in`[inOff].toInt() and 0xff) shl 24
        n = n or ((`in`[inOff + 1].toInt() and 0xff) shl 16)
        n = n or ((`in`[inOff + 2].toInt() and 0xff) shl 8)
        n = n or ((`in`[inOff + 3].toInt() and 0xff))
        X[xOff] = n
        if (++xOff == 16) {
            processBlock()
        }
    }

    private fun processLength(bitLength: Long) {
        if (xOff > 14) {
            processBlock()
        }
        X[14] = (bitLength ushr 32).toInt()
        X[15] = (bitLength and -0x1).toInt()
    }

    override fun doFinal(out: ByteArray, outOffset: Int): Int {
        finish()
        Pack.writeInt32BE(H1, out, outOffset)
        Pack.writeInt32BE(H2, out, outOffset + 4)
        Pack.writeInt32BE(H3, out, outOffset + 8)
        Pack.writeInt32BE(H4, out, outOffset + 12)
        Pack.writeInt32BE(H5, out, outOffset + 16)
        Pack.writeInt32BE(H6, out, outOffset + 20)
        Pack.writeInt32BE(H7, out, outOffset + 24)
        Pack.writeInt32BE(H8, out, outOffset + 28)
        reset()
        return DIGEST_LENGTH
    }

    /**
     * reset the chaining variables
     */
    override fun reset() {
        byteCount = 0

        xBufOff = 0
        for (i in xBuf.indices) {
            xBuf[i] = 0
        }

        /* SHA-256 initial hash value
         * The first 32 bits of the fractional parts of the square roots
         * of the first eight prime numbers
         */
        H1 = 0x6a09e667
        H2 = -0x4498517b
        H3 = 0x3c6ef372
        H4 = -0x5ab00ac6
        H5 = 0x510e527f
        H6 = -0x64fa9774
        H7 = 0x1f83d9ab
        H8 = 0x5be0cd19
        xOff = 0
        for (i in X.indices) {
            X[i] = 0
        }
    }

    private fun finish() {
        val bitLength: Long = byteCount shl 3

        //
        // add the pad bytes.
        //
        update(128.toByte())
        while (xBufOff != 0) {
            update(0.toByte())
        }
        processLength(bitLength)
        processBlock()
    }

    private fun processBlock() {
        //
        // expand 16 word block into 64 word blocks.
        //
        for (t in 16..63) {
            X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16]
        }

        //
        // set up working variables.
        //
        var a = H1
        var b: Int = H2
        var c: Int = H3
        var d: Int = H4
        var e: Int = H5
        var f: Int = H6
        var g: Int = H7
        var h: Int = H8
        var t = 0
        for (i in 0..7) {
            // t = 8 * i
            h += Sum1(e) + Ch(e, f, g) + K[t] + X[t]
            d += h
            h += Sum0(a) + Maj(a, b, c)
            ++t

            // t = 8 * i + 1
            g += Sum1(d) + Ch(d, e, f) + K[t] + X[t]
            c += g
            g += Sum0(h) + Maj(h, a, b)
            ++t

            // t = 8 * i + 2
            f += Sum1(c) + Ch(c, d, e) + K[t] + X[t]
            b += f
            f += Sum0(g) + Maj(g, h, a)
            ++t

            // t = 8 * i + 3
            e += Sum1(b) + Ch(b, c, d) + K[t] + X[t]
            a += e
            e += Sum0(f) + Maj(f, g, h)
            ++t

            // t = 8 * i + 4
            d += Sum1(a) + Ch(a, b, c) + K[t] + X[t]
            h += d
            d += Sum0(e) + Maj(e, f, g)
            ++t

            // t = 8 * i + 5
            c += Sum1(h) + Ch(h, a, b) + K[t] + X[t]
            g += c
            c += Sum0(d) + Maj(d, e, f)
            ++t

            // t = 8 * i + 6
            b += Sum1(g) + Ch(g, h, a) + K[t] + X[t]
            f += b
            b += Sum0(c) + Maj(c, d, e)
            ++t

            // t = 8 * i + 7
            a += Sum1(f) + Ch(f, g, h) + K[t] + X[t]
            e += a
            a += Sum0(b) + Maj(b, c, d)
            ++t
        }
        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.
        //
        xOff = 0
        for (i in 0..15) {
            X[i] = 0
        }
    }


    public companion object {
        private val DIGEST_LENGTH = 32

        /* SHA-256 functions */
        private fun Ch(x: Int, y: Int, z: Int): Int {
            return x and y xor (x.inv() and z)
//        return z ^ (x & (y ^ z));
        }

        private fun Maj(x: Int, y: Int, z: Int): Int {
//        return (x & y) ^ (x & z) ^ (y & z);
            return x and y or (z and (x xor y))
        }

        private fun Sum0(x: Int): Int {
            return x ushr 2 or (x shl 30) xor (x ushr 13 or (x shl 19)) xor (x ushr 22 or (x shl 10))
        }

        private fun Sum1(x: Int): Int {
            return x ushr 6 or (x shl 26) xor (x ushr 11 or (x shl 21)) xor (x ushr 25 or (x shl 7))
        }

        private fun Theta0(x: Int): Int {
            return x ushr 7 or (x shl 25) xor (x ushr 18 or (x shl 14)) xor (x ushr 3)
        }

        private fun Theta1(x: Int): Int {
            return x ushr 17 or (x shl 15) xor (x ushr 19 or (x shl 13)) xor (x ushr 10)
        }

        /* SHA-256 Constants
         * (represent the first 32 bits of the fractional parts of the
         * cube roots of the first sixty-four prime numbers)
         */
        public val K: IntArray = intArrayOf(
            0x428a2f98, 0x71374491, -0x4a3f0431, -0x164a245b, 0x3956c25b, 0x59f111f1, -0x6dc07d5c, -0x54e3a12b,
            -0x27f85568, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, -0x7f214e02, -0x6423f959, -0x3e640e8c,
            -0x1b64963f, -0x1041b87a, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
            -0x67c1aeae, -0x57ce3993, -0x4ffcd838, -0x40a68039, -0x391ff40d, -0x2a586eb9, 0x06ca6351, 0x14292967,
            0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, -0x7e3d36d2, -0x6d8dd37b,
            -0x5d40175f, -0x57e599b5, -0x3db47490, -0x3893ae5d, -0x2e6d17e7, -0x2966f9dc, -0xbf1ca7b, 0x106aa070,
            0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
            0x748f82ee, 0x78a5636f, -0x7b3787ec, -0x7338fdf8, -0x6f410006, -0x5baf9315, -0x41065c09, -0x398e870e
        )
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy