packages feed

ppad-sha512-0.2.2: cbits/sha512_arm.c

#include <stdint.h>
#include <string.h>

#if defined(__aarch64__) && defined(__ARM_FEATURE_SHA512)

#include <arm_neon.h>

static const uint64_t K[80] = {
    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
    0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
    0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
    0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
    0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
    0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
    0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
    0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
    0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
    0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
    0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
    0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
    0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
    0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
    0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
    0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
    0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
    0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
    0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
    0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
    0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
    0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
    0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
    0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
    0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
    0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
    0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
    0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
    0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
    0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
    0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
    0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
    0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
    0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
};

/*
 * Process one 128-byte block using ARM SHA512 crypto instructions.
 *
 * state: pointer to 8 uint64_t words (a,b,c,d,e,f,g,h)
 * block: pointer to 16 uint64_t words (already native endian)
 *
 * The state is updated in place.
 */
void sha512_block_arm(uint64_t *state, const uint64_t *block) {
    /* Load current hash state */
    uint64x2_t ab = vld1q_u64(&state[0]);
    uint64x2_t cd = vld1q_u64(&state[2]);
    uint64x2_t ef = vld1q_u64(&state[4]);
    uint64x2_t gh = vld1q_u64(&state[6]);

    /* Save original for final addition */
    uint64x2_t ab_orig = ab;
    uint64x2_t cd_orig = cd;
    uint64x2_t ef_orig = ef;
    uint64x2_t gh_orig = gh;

    /* Load message (already native endian) */
    uint64x2_t m0 = vld1q_u64(&block[0]);
    uint64x2_t m1 = vld1q_u64(&block[2]);
    uint64x2_t m2 = vld1q_u64(&block[4]);
    uint64x2_t m3 = vld1q_u64(&block[6]);
    uint64x2_t m4 = vld1q_u64(&block[8]);
    uint64x2_t m5 = vld1q_u64(&block[10]);
    uint64x2_t m6 = vld1q_u64(&block[12]);
    uint64x2_t m7 = vld1q_u64(&block[14]);

    uint64x2_t tmp;

    /* Rounds 0-1 */
    tmp = vaddq_u64(m0, vld1q_u64(&K[0]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(gh, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1));
    gh = vsha512h2q_u64(tmp, cd, ab);
    cd = vaddq_u64(cd, tmp);
    m0 = vsha512su1q_u64(vsha512su0q_u64(m0, m1), m7, vextq_u64(m4, m5, 1));

    /* Rounds 2-3 */
    tmp = vaddq_u64(m1, vld1q_u64(&K[2]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ef, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1));
    ef = vsha512h2q_u64(tmp, ab, gh);
    ab = vaddq_u64(ab, tmp);
    m1 = vsha512su1q_u64(vsha512su0q_u64(m1, m2), m0, vextq_u64(m5, m6, 1));

    /* Rounds 4-5 */
    tmp = vaddq_u64(m2, vld1q_u64(&K[4]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(cd, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1));
    cd = vsha512h2q_u64(tmp, gh, ef);
    gh = vaddq_u64(gh, tmp);
    m2 = vsha512su1q_u64(vsha512su0q_u64(m2, m3), m1, vextq_u64(m6, m7, 1));

    /* Rounds 6-7 */
    tmp = vaddq_u64(m3, vld1q_u64(&K[6]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ab, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1));
    ab = vsha512h2q_u64(tmp, ef, cd);
    ef = vaddq_u64(ef, tmp);
    m3 = vsha512su1q_u64(vsha512su0q_u64(m3, m4), m2, vextq_u64(m7, m0, 1));

    /* Rounds 8-9 */
    tmp = vaddq_u64(m4, vld1q_u64(&K[8]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(gh, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1));
    gh = vsha512h2q_u64(tmp, cd, ab);
    cd = vaddq_u64(cd, tmp);
    m4 = vsha512su1q_u64(vsha512su0q_u64(m4, m5), m3, vextq_u64(m0, m1, 1));

    /* Rounds 10-11 */
    tmp = vaddq_u64(m5, vld1q_u64(&K[10]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ef, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1));
    ef = vsha512h2q_u64(tmp, ab, gh);
    ab = vaddq_u64(ab, tmp);
    m5 = vsha512su1q_u64(vsha512su0q_u64(m5, m6), m4, vextq_u64(m1, m2, 1));

    /* Rounds 12-13 */
    tmp = vaddq_u64(m6, vld1q_u64(&K[12]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(cd, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1));
    cd = vsha512h2q_u64(tmp, gh, ef);
    gh = vaddq_u64(gh, tmp);
    m6 = vsha512su1q_u64(vsha512su0q_u64(m6, m7), m5, vextq_u64(m2, m3, 1));

    /* Rounds 14-15 */
    tmp = vaddq_u64(m7, vld1q_u64(&K[14]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ab, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1));
    ab = vsha512h2q_u64(tmp, ef, cd);
    ef = vaddq_u64(ef, tmp);
    m7 = vsha512su1q_u64(vsha512su0q_u64(m7, m0), m6, vextq_u64(m3, m4, 1));

    /* Rounds 16-17 */
    tmp = vaddq_u64(m0, vld1q_u64(&K[16]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(gh, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1));
    gh = vsha512h2q_u64(tmp, cd, ab);
    cd = vaddq_u64(cd, tmp);
    m0 = vsha512su1q_u64(vsha512su0q_u64(m0, m1), m7, vextq_u64(m4, m5, 1));

    /* Rounds 18-19 */
    tmp = vaddq_u64(m1, vld1q_u64(&K[18]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ef, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1));
    ef = vsha512h2q_u64(tmp, ab, gh);
    ab = vaddq_u64(ab, tmp);
    m1 = vsha512su1q_u64(vsha512su0q_u64(m1, m2), m0, vextq_u64(m5, m6, 1));

    /* Rounds 20-21 */
    tmp = vaddq_u64(m2, vld1q_u64(&K[20]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(cd, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1));
    cd = vsha512h2q_u64(tmp, gh, ef);
    gh = vaddq_u64(gh, tmp);
    m2 = vsha512su1q_u64(vsha512su0q_u64(m2, m3), m1, vextq_u64(m6, m7, 1));

    /* Rounds 22-23 */
    tmp = vaddq_u64(m3, vld1q_u64(&K[22]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ab, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1));
    ab = vsha512h2q_u64(tmp, ef, cd);
    ef = vaddq_u64(ef, tmp);
    m3 = vsha512su1q_u64(vsha512su0q_u64(m3, m4), m2, vextq_u64(m7, m0, 1));

    /* Rounds 24-25 */
    tmp = vaddq_u64(m4, vld1q_u64(&K[24]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(gh, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1));
    gh = vsha512h2q_u64(tmp, cd, ab);
    cd = vaddq_u64(cd, tmp);
    m4 = vsha512su1q_u64(vsha512su0q_u64(m4, m5), m3, vextq_u64(m0, m1, 1));

    /* Rounds 26-27 */
    tmp = vaddq_u64(m5, vld1q_u64(&K[26]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ef, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1));
    ef = vsha512h2q_u64(tmp, ab, gh);
    ab = vaddq_u64(ab, tmp);
    m5 = vsha512su1q_u64(vsha512su0q_u64(m5, m6), m4, vextq_u64(m1, m2, 1));

    /* Rounds 28-29 */
    tmp = vaddq_u64(m6, vld1q_u64(&K[28]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(cd, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1));
    cd = vsha512h2q_u64(tmp, gh, ef);
    gh = vaddq_u64(gh, tmp);
    m6 = vsha512su1q_u64(vsha512su0q_u64(m6, m7), m5, vextq_u64(m2, m3, 1));

    /* Rounds 30-31 */
    tmp = vaddq_u64(m7, vld1q_u64(&K[30]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ab, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1));
    ab = vsha512h2q_u64(tmp, ef, cd);
    ef = vaddq_u64(ef, tmp);
    m7 = vsha512su1q_u64(vsha512su0q_u64(m7, m0), m6, vextq_u64(m3, m4, 1));

    /* Rounds 32-33 */
    tmp = vaddq_u64(m0, vld1q_u64(&K[32]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(gh, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1));
    gh = vsha512h2q_u64(tmp, cd, ab);
    cd = vaddq_u64(cd, tmp);
    m0 = vsha512su1q_u64(vsha512su0q_u64(m0, m1), m7, vextq_u64(m4, m5, 1));

    /* Rounds 34-35 */
    tmp = vaddq_u64(m1, vld1q_u64(&K[34]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ef, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1));
    ef = vsha512h2q_u64(tmp, ab, gh);
    ab = vaddq_u64(ab, tmp);
    m1 = vsha512su1q_u64(vsha512su0q_u64(m1, m2), m0, vextq_u64(m5, m6, 1));

    /* Rounds 36-37 */
    tmp = vaddq_u64(m2, vld1q_u64(&K[36]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(cd, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1));
    cd = vsha512h2q_u64(tmp, gh, ef);
    gh = vaddq_u64(gh, tmp);
    m2 = vsha512su1q_u64(vsha512su0q_u64(m2, m3), m1, vextq_u64(m6, m7, 1));

    /* Rounds 38-39 */
    tmp = vaddq_u64(m3, vld1q_u64(&K[38]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ab, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1));
    ab = vsha512h2q_u64(tmp, ef, cd);
    ef = vaddq_u64(ef, tmp);
    m3 = vsha512su1q_u64(vsha512su0q_u64(m3, m4), m2, vextq_u64(m7, m0, 1));

    /* Rounds 40-41 */
    tmp = vaddq_u64(m4, vld1q_u64(&K[40]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(gh, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1));
    gh = vsha512h2q_u64(tmp, cd, ab);
    cd = vaddq_u64(cd, tmp);
    m4 = vsha512su1q_u64(vsha512su0q_u64(m4, m5), m3, vextq_u64(m0, m1, 1));

    /* Rounds 42-43 */
    tmp = vaddq_u64(m5, vld1q_u64(&K[42]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ef, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1));
    ef = vsha512h2q_u64(tmp, ab, gh);
    ab = vaddq_u64(ab, tmp);
    m5 = vsha512su1q_u64(vsha512su0q_u64(m5, m6), m4, vextq_u64(m1, m2, 1));

    /* Rounds 44-45 */
    tmp = vaddq_u64(m6, vld1q_u64(&K[44]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(cd, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1));
    cd = vsha512h2q_u64(tmp, gh, ef);
    gh = vaddq_u64(gh, tmp);
    m6 = vsha512su1q_u64(vsha512su0q_u64(m6, m7), m5, vextq_u64(m2, m3, 1));

    /* Rounds 46-47 */
    tmp = vaddq_u64(m7, vld1q_u64(&K[46]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ab, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1));
    ab = vsha512h2q_u64(tmp, ef, cd);
    ef = vaddq_u64(ef, tmp);
    m7 = vsha512su1q_u64(vsha512su0q_u64(m7, m0), m6, vextq_u64(m3, m4, 1));

    /* Rounds 48-49 */
    tmp = vaddq_u64(m0, vld1q_u64(&K[48]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(gh, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1));
    gh = vsha512h2q_u64(tmp, cd, ab);
    cd = vaddq_u64(cd, tmp);
    m0 = vsha512su1q_u64(vsha512su0q_u64(m0, m1), m7, vextq_u64(m4, m5, 1));

    /* Rounds 50-51 */
    tmp = vaddq_u64(m1, vld1q_u64(&K[50]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ef, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1));
    ef = vsha512h2q_u64(tmp, ab, gh);
    ab = vaddq_u64(ab, tmp);
    m1 = vsha512su1q_u64(vsha512su0q_u64(m1, m2), m0, vextq_u64(m5, m6, 1));

    /* Rounds 52-53 */
    tmp = vaddq_u64(m2, vld1q_u64(&K[52]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(cd, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1));
    cd = vsha512h2q_u64(tmp, gh, ef);
    gh = vaddq_u64(gh, tmp);
    m2 = vsha512su1q_u64(vsha512su0q_u64(m2, m3), m1, vextq_u64(m6, m7, 1));

    /* Rounds 54-55 */
    tmp = vaddq_u64(m3, vld1q_u64(&K[54]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ab, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1));
    ab = vsha512h2q_u64(tmp, ef, cd);
    ef = vaddq_u64(ef, tmp);
    m3 = vsha512su1q_u64(vsha512su0q_u64(m3, m4), m2, vextq_u64(m7, m0, 1));

    /* Rounds 56-57 */
    tmp = vaddq_u64(m4, vld1q_u64(&K[56]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(gh, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1));
    gh = vsha512h2q_u64(tmp, cd, ab);
    cd = vaddq_u64(cd, tmp);
    m4 = vsha512su1q_u64(vsha512su0q_u64(m4, m5), m3, vextq_u64(m0, m1, 1));

    /* Rounds 58-59 */
    tmp = vaddq_u64(m5, vld1q_u64(&K[58]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ef, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1));
    ef = vsha512h2q_u64(tmp, ab, gh);
    ab = vaddq_u64(ab, tmp);
    m5 = vsha512su1q_u64(vsha512su0q_u64(m5, m6), m4, vextq_u64(m1, m2, 1));

    /* Rounds 60-61 */
    tmp = vaddq_u64(m6, vld1q_u64(&K[60]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(cd, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1));
    cd = vsha512h2q_u64(tmp, gh, ef);
    gh = vaddq_u64(gh, tmp);
    m6 = vsha512su1q_u64(vsha512su0q_u64(m6, m7), m5, vextq_u64(m2, m3, 1));

    /* Rounds 62-63 */
    tmp = vaddq_u64(m7, vld1q_u64(&K[62]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ab, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1));
    ab = vsha512h2q_u64(tmp, ef, cd);
    ef = vaddq_u64(ef, tmp);
    m7 = vsha512su1q_u64(vsha512su0q_u64(m7, m0), m6, vextq_u64(m3, m4, 1));

    /* Rounds 64-65 */
    tmp = vaddq_u64(m0, vld1q_u64(&K[64]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(gh, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1));
    gh = vsha512h2q_u64(tmp, cd, ab);
    cd = vaddq_u64(cd, tmp);

    /* Rounds 66-67 */
    tmp = vaddq_u64(m1, vld1q_u64(&K[66]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ef, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1));
    ef = vsha512h2q_u64(tmp, ab, gh);
    ab = vaddq_u64(ab, tmp);

    /* Rounds 68-69 */
    tmp = vaddq_u64(m2, vld1q_u64(&K[68]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(cd, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1));
    cd = vsha512h2q_u64(tmp, gh, ef);
    gh = vaddq_u64(gh, tmp);

    /* Rounds 70-71 */
    tmp = vaddq_u64(m3, vld1q_u64(&K[70]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ab, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1));
    ab = vsha512h2q_u64(tmp, ef, cd);
    ef = vaddq_u64(ef, tmp);

    /* Rounds 72-73 */
    tmp = vaddq_u64(m4, vld1q_u64(&K[72]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(gh, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ef, gh, 1), vextq_u64(cd, ef, 1));
    gh = vsha512h2q_u64(tmp, cd, ab);
    cd = vaddq_u64(cd, tmp);

    /* Rounds 74-75 */
    tmp = vaddq_u64(m5, vld1q_u64(&K[74]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ef, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(cd, ef, 1), vextq_u64(ab, cd, 1));
    ef = vsha512h2q_u64(tmp, ab, gh);
    ab = vaddq_u64(ab, tmp);

    /* Rounds 76-77 */
    tmp = vaddq_u64(m6, vld1q_u64(&K[76]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(cd, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(ab, cd, 1), vextq_u64(gh, ab, 1));
    cd = vsha512h2q_u64(tmp, gh, ef);
    gh = vaddq_u64(gh, tmp);

    /* Rounds 78-79 */
    tmp = vaddq_u64(m7, vld1q_u64(&K[78]));
    tmp = vextq_u64(tmp, tmp, 1);
    tmp = vaddq_u64(ab, tmp);
    tmp = vsha512hq_u64(tmp, vextq_u64(gh, ab, 1), vextq_u64(ef, gh, 1));
    ab = vsha512h2q_u64(tmp, ef, cd);
    ef = vaddq_u64(ef, tmp);

    /* Add original state back */
    ab = vaddq_u64(ab, ab_orig);
    cd = vaddq_u64(cd, cd_orig);
    ef = vaddq_u64(ef, ef_orig);
    gh = vaddq_u64(gh, gh_orig);

    /* Store result */
    vst1q_u64(&state[0], ab);
    vst1q_u64(&state[2], cd);
    vst1q_u64(&state[4], ef);
    vst1q_u64(&state[6], gh);
}

/* Return 1 if ARM SHA512 is available, 0 otherwise */
int sha512_arm_available(void) {
    return 1;
}

#else

/* Stub implementations when ARM SHA512 is not available */
void sha512_block_arm(uint64_t *state, const uint64_t *block) {
    (void)state;
    (void)block;
    /* Should never be called - use pure Haskell fallback */
}

int sha512_arm_available(void) {
    return 0;
}

#endif