GordianJHDigest.java

/*
 * GordianKnot: Security Suite
 * Copyright 2012-2026. Tony Washer
 *
 * 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 io.github.tonywasher.joceanus.gordianknot.impl.ext.digests;

import org.bouncycastle.crypto.ExtendedDigest;
import org.bouncycastle.util.Memoable;

import java.util.Arrays;

/**
 * JH Digest.
 * <p>
 * The embedded JHFastDigest is ported from the C implementation in jh_bitslice_ref64.h in the Round
 * 3 submission package at http://www3.ntu.edu.sg with tweaks to interface to the BouncyCastle
 * libraries
 */
@SuppressWarnings({"checkstyle:MagicNumber", "checkstyle:JavadocVariable"})
public class GordianJHDigest
        implements ExtendedDigest, Memoable {
    /**
     * The underlying digest.
     */
    private final GordianJHFastDigest theDigest;

    /**
     * The digest length.
     */
    private final int theDigestLen;

    /**
     * Constructor.
     *
     * @param pHashBitLen the hash bit length
     */
    public GordianJHDigest(final int pHashBitLen) {
        theDigest = new GordianJHFastDigest(pHashBitLen);
        theDigestLen = pHashBitLen / Byte.SIZE;
    }

    /**
     * Constructor.
     *
     * @param pDigest the digest to copy
     */
    public GordianJHDigest(final GordianJHDigest pDigest) {
        theDigestLen = pDigest.theDigestLen;
        theDigest = new GordianJHFastDigest(theDigestLen * Byte.SIZE);
        theDigest.copyIn(pDigest.theDigest);
    }

    @Override
    public int doFinal(final byte[] pHash, final int pOffset) {
        theDigest.finalise(pHash, pOffset);
        return getDigestSize();
    }

    @Override
    public String getAlgorithmName() {
        return "JH";
    }

    @Override
    public int getDigestSize() {
        return theDigestLen;
    }

    @Override
    public void reset() {
        theDigest.reset();
    }

    @Override
    public void update(final byte arg0) {
        final byte[] myByte = new byte[]
                {arg0};
        update(myByte, 0, 1);
    }

    @Override
    public void update(final byte[] pData, final int pOffset, final int pLength) {
        theDigest.update(pData, pOffset, ((long) pLength) * Byte.SIZE);
    }

    @Override
    public int getByteLength() {
        return theDigest.getBufferSize();
    }

    @Override
    public GordianJHDigest copy() {
        return new GordianJHDigest(this);
    }

    @Override
    public void reset(final Memoable pState) {
        final GordianJHDigest d = (GordianJHDigest) pState;
        theDigest.copyIn(d.theDigest);
    }

    /**
     * JH Digest Fast version.
     * <p>
     * Ported from the C implementation in jh_bitslice_ref64.h in the Round 3 submission package at
     * http://www3.ntu.edu.sg with tweaks to interface to the BouncyCastle libraries
     */
    private static class GordianJHFastDigest {
        /**
         * The state.
         */
        private int hashbitlen; /* the message digest size */
        private boolean initialised;
        private long databitlen; /* the message size in bits */
        private long datasizeInBuffer; /* the size of the message remained in buffer; */
        /* assumed to be multiple of 8bits except for the last partial block at the end of the message */

        private long[][] x = new long[8][2]; // the 1024-bit state, ( x[i][0] || x[i][1] ) is the ith row of the state in the pseudocode */
        private byte[] buffer = new byte[64]; // the 512-bit message block to be hashed; */

        /* The initial hash value H(0) */
        private static final byte[] JH224_H0 = {
                (byte) 0x2d, (byte) 0xfe, (byte) 0xdd, (byte) 0x62, (byte) 0xf9, (byte) 0x9a, (byte) 0x98, (byte) 0xac, (byte) 0xae, (byte) 0x7c, (byte) 0xac, (byte) 0xd6, (byte) 0x19, (byte) 0xd6,
                (byte) 0x34, (byte) 0xe7, (byte) 0xa4, (byte) 0x83, (byte) 0x10, (byte) 0x5, (byte) 0xbc, (byte) 0x30, (byte) 0x12, (byte) 0x16, (byte) 0xb8, (byte) 0x60, (byte) 0x38, (byte) 0xc6,
                (byte) 0xc9, (byte) 0x66, (byte) 0x14, (byte) 0x94, (byte) 0x66, (byte) 0xd9, (byte) 0x89, (byte) 0x9f, (byte) 0x25, (byte) 0x80, (byte) 0x70, (byte) 0x6f, (byte) 0xce, (byte) 0x9e,
                (byte) 0xa3, (byte) 0x1b, (byte) 0x1d, (byte) 0x9b, (byte) 0x1a, (byte) 0xdc, (byte) 0x11, (byte) 0xe8, (byte) 0x32, (byte) 0x5f, (byte) 0x7b, (byte) 0x36, (byte) 0x6e, (byte) 0x10,
                (byte) 0xf9, (byte) 0x94, (byte) 0x85, (byte) 0x7f, (byte) 0x2, (byte) 0xfa, (byte) 0x6, (byte) 0xc1, (byte) 0x1b, (byte) 0x4f, (byte) 0x1b, (byte) 0x5c, (byte) 0xd8, (byte) 0xc8,
                (byte) 0x40, (byte) 0xb3, (byte) 0x97, (byte) 0xf6, (byte) 0xa1, (byte) 0x7f, (byte) 0x6e, (byte) 0x73, (byte) 0x80, (byte) 0x99, (byte) 0xdc, (byte) 0xdf, (byte) 0x93, (byte) 0xa5,
                (byte) 0xad, (byte) 0xea, (byte) 0xa3, (byte) 0xd3, (byte) 0xa4, (byte) 0x31, (byte) 0xe8, (byte) 0xde, (byte) 0xc9, (byte) 0x53, (byte) 0x9a, (byte) 0x68, (byte) 0x22, (byte) 0xb4,
                (byte) 0xa9, (byte) 0x8a, (byte) 0xec, (byte) 0x86, (byte) 0xa1, (byte) 0xe4, (byte) 0xd5, (byte) 0x74, (byte) 0xac, (byte) 0x95, (byte) 0x9c, (byte) 0xe5, (byte) 0x6c, (byte) 0xf0,
                (byte) 0x15, (byte) 0x96, (byte) 0xd, (byte) 0xea, (byte) 0xb5, (byte) 0xab, (byte) 0x2b, (byte) 0xbf, (byte) 0x96, (byte) 0x11, (byte) 0xdc, (byte) 0xf0, (byte) 0xdd, (byte) 0x64,
                (byte) 0xea, (byte) 0x6e
        };
        private static final byte[] JH256_H0 = {
                (byte) 0xeb, (byte) 0x98, (byte) 0xa3, (byte) 0x41, (byte) 0x2c, (byte) 0x20, (byte) 0xd3, (byte) 0xeb, (byte) 0x92, (byte) 0xcd, (byte) 0xbe, (byte) 0x7b, (byte) 0x9c, (byte) 0xb2,
                (byte) 0x45, (byte) 0xc1, (byte) 0x1c, (byte) 0x93, (byte) 0x51, (byte) 0x91, (byte) 0x60, (byte) 0xd4, (byte) 0xc7, (byte) 0xfa, (byte) 0x26, (byte) 0x0, (byte) 0x82, (byte) 0xd6,
                (byte) 0x7e, (byte) 0x50, (byte) 0x8a, (byte) 0x3, (byte) 0xa4, (byte) 0x23, (byte) 0x9e, (byte) 0x26, (byte) 0x77, (byte) 0x26, (byte) 0xb9, (byte) 0x45, (byte) 0xe0, (byte) 0xfb,
                (byte) 0x1a, (byte) 0x48, (byte) 0xd4, (byte) 0x1a, (byte) 0x94, (byte) 0x77, (byte) 0xcd, (byte) 0xb5, (byte) 0xab, (byte) 0x26, (byte) 0x2, (byte) 0x6b, (byte) 0x17, (byte) 0x7a,
                (byte) 0x56, (byte) 0xf0, (byte) 0x24, (byte) 0x42, (byte) 0xf, (byte) 0xff, (byte) 0x2f, (byte) 0xa8, (byte) 0x71, (byte) 0xa3, (byte) 0x96, (byte) 0x89, (byte) 0x7f, (byte) 0x2e,
                (byte) 0x4d, (byte) 0x75, (byte) 0x1d, (byte) 0x14, (byte) 0x49, (byte) 0x8, (byte) 0xf7, (byte) 0x7d, (byte) 0xe2, (byte) 0x62, (byte) 0x27, (byte) 0x76, (byte) 0x95, (byte) 0xf7,
                (byte) 0x76, (byte) 0x24, (byte) 0x8f, (byte) 0x94, (byte) 0x87, (byte) 0xd5, (byte) 0xb6, (byte) 0x57, (byte) 0x47, (byte) 0x80, (byte) 0x29, (byte) 0x6c, (byte) 0x5c, (byte) 0x5e,
                (byte) 0x27, (byte) 0x2d, (byte) 0xac, (byte) 0x8e, (byte) 0xd, (byte) 0x6c, (byte) 0x51, (byte) 0x84, (byte) 0x50, (byte) 0xc6, (byte) 0x57, (byte) 0x5, (byte) 0x7a, (byte) 0xf,
                (byte) 0x7b, (byte) 0xe4, (byte) 0xd3, (byte) 0x67, (byte) 0x70, (byte) 0x24, (byte) 0x12, (byte) 0xea, (byte) 0x89, (byte) 0xe3, (byte) 0xab, (byte) 0x13, (byte) 0xd3, (byte) 0x1c,
                (byte) 0xd7, (byte) 0x69
        };
        private static final byte[] JH384_H0 = {
                (byte) 0x48, (byte) 0x1e, (byte) 0x3b, (byte) 0xc6, (byte) 0xd8, (byte) 0x13, (byte) 0x39, (byte) 0x8a, (byte) 0x6d, (byte) 0x3b, (byte) 0x5e, (byte) 0x89, (byte) 0x4a, (byte) 0xde,
                (byte) 0x87, (byte) 0x9b, (byte) 0x63, (byte) 0xfa, (byte) 0xea, (byte) 0x68, (byte) 0xd4, (byte) 0x80, (byte) 0xad, (byte) 0x2e, (byte) 0x33, (byte) 0x2c, (byte) 0xcb, (byte) 0x21,
                (byte) 0x48, (byte) 0xf, (byte) 0x82, (byte) 0x67, (byte) 0x98, (byte) 0xae, (byte) 0xc8, (byte) 0x4d, (byte) 0x90, (byte) 0x82, (byte) 0xb9, (byte) 0x28, (byte) 0xd4, (byte) 0x55,
                (byte) 0xea, (byte) 0x30, (byte) 0x41, (byte) 0x11, (byte) 0x42, (byte) 0x49, (byte) 0x36, (byte) 0xf5, (byte) 0x55, (byte) 0xb2, (byte) 0x92, (byte) 0x48, (byte) 0x47, (byte) 0xec,
                (byte) 0xc7, (byte) 0x25, (byte) 0xa, (byte) 0x93, (byte) 0xba, (byte) 0xf4, (byte) 0x3c, (byte) 0xe1, (byte) 0x56, (byte) 0x9b, (byte) 0x7f, (byte) 0x8a, (byte) 0x27, (byte) 0xdb,
                (byte) 0x45, (byte) 0x4c, (byte) 0x9e, (byte) 0xfc, (byte) 0xbd, (byte) 0x49, (byte) 0x63, (byte) 0x97, (byte) 0xaf, (byte) 0xe, (byte) 0x58, (byte) 0x9f, (byte) 0xc2, (byte) 0x7d,
                (byte) 0x26, (byte) 0xaa, (byte) 0x80, (byte) 0xcd, (byte) 0x80, (byte) 0xc0, (byte) 0x8b, (byte) 0x8c, (byte) 0x9d, (byte) 0xeb, (byte) 0x2e, (byte) 0xda, (byte) 0x8a, (byte) 0x79,
                (byte) 0x81, (byte) 0xe8, (byte) 0xf8, (byte) 0xd5, (byte) 0x37, (byte) 0x3a, (byte) 0xf4, (byte) 0x39, (byte) 0x67, (byte) 0xad, (byte) 0xdd, (byte) 0xd1, (byte) 0x7a, (byte) 0x71,
                (byte) 0xa9, (byte) 0xb4, (byte) 0xd3, (byte) 0xbd, (byte) 0xa4, (byte) 0x75, (byte) 0xd3, (byte) 0x94, (byte) 0x97, (byte) 0x6c, (byte) 0x3f, (byte) 0xba, (byte) 0x98, (byte) 0x42,
                (byte) 0x73, (byte) 0x7f
        };
        private static final byte[] JH512_H0 = {
                (byte) 0x6f, (byte) 0xd1, (byte) 0x4b, (byte) 0x96, (byte) 0x3e, (byte) 0x0, (byte) 0xaa, (byte) 0x17, (byte) 0x63, (byte) 0x6a, (byte) 0x2e, (byte) 0x5, (byte) 0x7a, (byte) 0x15,
                (byte) 0xd5, (byte) 0x43, (byte) 0x8a, (byte) 0x22, (byte) 0x5e, (byte) 0x8d, (byte) 0xc, (byte) 0x97, (byte) 0xef, (byte) 0xb, (byte) 0xe9, (byte) 0x34, (byte) 0x12, (byte) 0x59,
                (byte) 0xf2, (byte) 0xb3, (byte) 0xc3, (byte) 0x61, (byte) 0x89, (byte) 0x1d, (byte) 0xa0, (byte) 0xc1, (byte) 0x53, (byte) 0x6f, (byte) 0x80, (byte) 0x1e, (byte) 0x2a, (byte) 0xa9,
                (byte) 0x5, (byte) 0x6b, (byte) 0xea, (byte) 0x2b, (byte) 0x6d, (byte) 0x80, (byte) 0x58, (byte) 0x8e, (byte) 0xcc, (byte) 0xdb, (byte) 0x20, (byte) 0x75, (byte) 0xba, (byte) 0xa6,
                (byte) 0xa9, (byte) 0xf, (byte) 0x3a, (byte) 0x76, (byte) 0xba, (byte) 0xf8, (byte) 0x3b, (byte) 0xf7, (byte) 0x1, (byte) 0x69, (byte) 0xe6, (byte) 0x5, (byte) 0x41, (byte) 0xe3,
                (byte) 0x4a, (byte) 0x69, (byte) 0x46, (byte) 0xb5, (byte) 0x8a, (byte) 0x8e, (byte) 0x2e, (byte) 0x6f, (byte) 0xe6, (byte) 0x5a, (byte) 0x10, (byte) 0x47, (byte) 0xa7, (byte) 0xd0,
                (byte) 0xc1, (byte) 0x84, (byte) 0x3c, (byte) 0x24, (byte) 0x3b, (byte) 0x6e, (byte) 0x71, (byte) 0xb1, (byte) 0x2d, (byte) 0x5a, (byte) 0xc1, (byte) 0x99, (byte) 0xcf, (byte) 0x57,
                (byte) 0xf6, (byte) 0xec, (byte) 0x9d, (byte) 0xb1, (byte) 0xf8, (byte) 0x56, (byte) 0xa7, (byte) 0x6, (byte) 0x88, (byte) 0x7c, (byte) 0x57, (byte) 0x16, (byte) 0xb1, (byte) 0x56,
                (byte) 0xe3, (byte) 0xc2, (byte) 0xfc, (byte) 0xdf, (byte) 0xe6, (byte) 0x85, (byte) 0x17, (byte) 0xfb, (byte) 0x54, (byte) 0x5a, (byte) 0x46, (byte) 0x78, (byte) 0xcc, (byte) 0x8c,
                (byte) 0xdd, (byte) 0x4b
        };

        /* 42 round constants, each round constant is 32-byte (256-bit) */
        private static final byte[][] E_8_BITSLICE_ROUNDCONSTANT = {
                {(byte) 0x72, (byte) 0xd5, (byte) 0xde, (byte) 0xa2, (byte) 0xdf, (byte) 0x15, (byte) 0xf8, (byte) 0x67, (byte) 0x7b, (byte) 0x84, (byte) 0x15, (byte) 0xa, (byte) 0xb7, (byte) 0x23,
                        (byte) 0x15, (byte) 0x57, (byte) 0x81, (byte) 0xab, (byte) 0xd6, (byte) 0x90, (byte) 0x4d, (byte) 0x5a, (byte) 0x87, (byte) 0xf6, (byte) 0x4e, (byte) 0x9f, (byte) 0x4f,
                        (byte) 0xc5, (byte) 0xc3, (byte) 0xd1, (byte) 0x2b, (byte) 0x40},
                {(byte) 0xea, (byte) 0x98, (byte) 0x3a, (byte) 0xe0, (byte) 0x5c, (byte) 0x45, (byte) 0xfa, (byte) 0x9c, (byte) 0x3, (byte) 0xc5, (byte) 0xd2, (byte) 0x99, (byte) 0x66, (byte) 0xb2,
                        (byte) 0x99, (byte) 0x9a, (byte) 0x66, (byte) 0x2, (byte) 0x96, (byte) 0xb4, (byte) 0xf2, (byte) 0xbb, (byte) 0x53, (byte) 0x8a, (byte) 0xb5, (byte) 0x56, (byte) 0x14,
                        (byte) 0x1a, (byte) 0x88, (byte) 0xdb, (byte) 0xa2, (byte) 0x31},
                {(byte) 0x3, (byte) 0xa3, (byte) 0x5a, (byte) 0x5c, (byte) 0x9a, (byte) 0x19, (byte) 0xe, (byte) 0xdb, (byte) 0x40, (byte) 0x3f, (byte) 0xb2, (byte) 0xa, (byte) 0x87, (byte) 0xc1,
                        (byte) 0x44, (byte) 0x10, (byte) 0x1c, (byte) 0x5, (byte) 0x19, (byte) 0x80, (byte) 0x84, (byte) 0x9e, (byte) 0x95, (byte) 0x1d, (byte) 0x6f, (byte) 0x33, (byte) 0xeb,
                        (byte) 0xad, (byte) 0x5e, (byte) 0xe7, (byte) 0xcd, (byte) 0xdc},
                {(byte) 0x10, (byte) 0xba, (byte) 0x13, (byte) 0x92, (byte) 0x2, (byte) 0xbf, (byte) 0x6b, (byte) 0x41, (byte) 0xdc, (byte) 0x78, (byte) 0x65, (byte) 0x15, (byte) 0xf7, (byte) 0xbb,
                        (byte) 0x27, (byte) 0xd0, (byte) 0xa, (byte) 0x2c, (byte) 0x81, (byte) 0x39, (byte) 0x37, (byte) 0xaa, (byte) 0x78, (byte) 0x50, (byte) 0x3f, (byte) 0x1a, (byte) 0xbf,
                        (byte) 0xd2, (byte) 0x41, (byte) 0x0, (byte) 0x91, (byte) 0xd3},
                {(byte) 0x42, (byte) 0x2d, (byte) 0x5a, (byte) 0xd, (byte) 0xf6, (byte) 0xcc, (byte) 0x7e, (byte) 0x90, (byte) 0xdd, (byte) 0x62, (byte) 0x9f, (byte) 0x9c, (byte) 0x92, (byte) 0xc0,
                        (byte) 0x97, (byte) 0xce, (byte) 0x18, (byte) 0x5c, (byte) 0xa7, (byte) 0xb, (byte) 0xc7, (byte) 0x2b, (byte) 0x44, (byte) 0xac, (byte) 0xd1, (byte) 0xdf, (byte) 0x65,
                        (byte) 0xd6, (byte) 0x63, (byte) 0xc6, (byte) 0xfc, (byte) 0x23},
                {(byte) 0x97, (byte) 0x6e, (byte) 0x6c, (byte) 0x3, (byte) 0x9e, (byte) 0xe0, (byte) 0xb8, (byte) 0x1a, (byte) 0x21, (byte) 0x5, (byte) 0x45, (byte) 0x7e, (byte) 0x44, (byte) 0x6c,
                        (byte) 0xec, (byte) 0xa8, (byte) 0xee, (byte) 0xf1, (byte) 0x3, (byte) 0xbb, (byte) 0x5d, (byte) 0x8e, (byte) 0x61, (byte) 0xfa, (byte) 0xfd, (byte) 0x96, (byte) 0x97,
                        (byte) 0xb2, (byte) 0x94, (byte) 0x83, (byte) 0x81, (byte) 0x97},
                {(byte) 0x4a, (byte) 0x8e, (byte) 0x85, (byte) 0x37, (byte) 0xdb, (byte) 0x3, (byte) 0x30, (byte) 0x2f, (byte) 0x2a, (byte) 0x67, (byte) 0x8d, (byte) 0x2d, (byte) 0xfb, (byte) 0x9f,
                        (byte) 0x6a, (byte) 0x95, (byte) 0x8a, (byte) 0xfe, (byte) 0x73, (byte) 0x81, (byte) 0xf8, (byte) 0xb8, (byte) 0x69, (byte) 0x6c, (byte) 0x8a, (byte) 0xc7, (byte) 0x72,
                        (byte) 0x46, (byte) 0xc0, (byte) 0x7f, (byte) 0x42, (byte) 0x14},
                {(byte) 0xc5, (byte) 0xf4, (byte) 0x15, (byte) 0x8f, (byte) 0xbd, (byte) 0xc7, (byte) 0x5e, (byte) 0xc4, (byte) 0x75, (byte) 0x44, (byte) 0x6f, (byte) 0xa7, (byte) 0x8f, (byte) 0x11,
                        (byte) 0xbb, (byte) 0x80, (byte) 0x52, (byte) 0xde, (byte) 0x75, (byte) 0xb7, (byte) 0xae, (byte) 0xe4, (byte) 0x88, (byte) 0xbc, (byte) 0x82, (byte) 0xb8, (byte) 0x0,
                        (byte) 0x1e, (byte) 0x98, (byte) 0xa6, (byte) 0xa3, (byte) 0xf4},
                {(byte) 0x8e, (byte) 0xf4, (byte) 0x8f, (byte) 0x33, (byte) 0xa9, (byte) 0xa3, (byte) 0x63, (byte) 0x15, (byte) 0xaa, (byte) 0x5f, (byte) 0x56, (byte) 0x24, (byte) 0xd5, (byte) 0xb7,
                        (byte) 0xf9, (byte) 0x89, (byte) 0xb6, (byte) 0xf1, (byte) 0xed, (byte) 0x20, (byte) 0x7c, (byte) 0x5a, (byte) 0xe0, (byte) 0xfd, (byte) 0x36, (byte) 0xca, (byte) 0xe9,
                        (byte) 0x5a, (byte) 0x6, (byte) 0x42, (byte) 0x2c, (byte) 0x36},
                {(byte) 0xce, (byte) 0x29, (byte) 0x35, (byte) 0x43, (byte) 0x4e, (byte) 0xfe, (byte) 0x98, (byte) 0x3d, (byte) 0x53, (byte) 0x3a, (byte) 0xf9, (byte) 0x74, (byte) 0x73, (byte) 0x9a,
                        (byte) 0x4b, (byte) 0xa7, (byte) 0xd0, (byte) 0xf5, (byte) 0x1f, (byte) 0x59, (byte) 0x6f, (byte) 0x4e, (byte) 0x81, (byte) 0x86, (byte) 0xe, (byte) 0x9d, (byte) 0xad,
                        (byte) 0x81, (byte) 0xaf, (byte) 0xd8, (byte) 0x5a, (byte) 0x9f},
                {(byte) 0xa7, (byte) 0x5, (byte) 0x6, (byte) 0x67, (byte) 0xee, (byte) 0x34, (byte) 0x62, (byte) 0x6a, (byte) 0x8b, (byte) 0xb, (byte) 0x28, (byte) 0xbe, (byte) 0x6e, (byte) 0xb9,
                        (byte) 0x17, (byte) 0x27, (byte) 0x47, (byte) 0x74, (byte) 0x7, (byte) 0x26, (byte) 0xc6, (byte) 0x80, (byte) 0x10, (byte) 0x3f, (byte) 0xe0, (byte) 0xa0, (byte) 0x7e,
                        (byte) 0x6f, (byte) 0xc6, (byte) 0x7e, (byte) 0x48, (byte) 0x7b},
                {(byte) 0xd, (byte) 0x55, (byte) 0xa, (byte) 0xa5, (byte) 0x4a, (byte) 0xf8, (byte) 0xa4, (byte) 0xc0, (byte) 0x91, (byte) 0xe3, (byte) 0xe7, (byte) 0x9f, (byte) 0x97, (byte) 0x8e,
                        (byte) 0xf1, (byte) 0x9e, (byte) 0x86, (byte) 0x76, (byte) 0x72, (byte) 0x81, (byte) 0x50, (byte) 0x60, (byte) 0x8d, (byte) 0xd4, (byte) 0x7e, (byte) 0x9e, (byte) 0x5a,
                        (byte) 0x41, (byte) 0xf3, (byte) 0xe5, (byte) 0xb0, (byte) 0x62},
                {(byte) 0xfc, (byte) 0x9f, (byte) 0x1f, (byte) 0xec, (byte) 0x40, (byte) 0x54, (byte) 0x20, (byte) 0x7a, (byte) 0xe3, (byte) 0xe4, (byte) 0x1a, (byte) 0x0, (byte) 0xce, (byte) 0xf4,
                        (byte) 0xc9, (byte) 0x84, (byte) 0x4f, (byte) 0xd7, (byte) 0x94, (byte) 0xf5, (byte) 0x9d, (byte) 0xfa, (byte) 0x95, (byte) 0xd8, (byte) 0x55, (byte) 0x2e, (byte) 0x7e,
                        (byte) 0x11, (byte) 0x24, (byte) 0xc3, (byte) 0x54, (byte) 0xa5},
                {(byte) 0x5b, (byte) 0xdf, (byte) 0x72, (byte) 0x28, (byte) 0xbd, (byte) 0xfe, (byte) 0x6e, (byte) 0x28, (byte) 0x78, (byte) 0xf5, (byte) 0x7f, (byte) 0xe2, (byte) 0xf, (byte) 0xa5,
                        (byte) 0xc4, (byte) 0xb2, (byte) 0x5, (byte) 0x89, (byte) 0x7c, (byte) 0xef, (byte) 0xee, (byte) 0x49, (byte) 0xd3, (byte) 0x2e, (byte) 0x44, (byte) 0x7e, (byte) 0x93,
                        (byte) 0x85, (byte) 0xeb, (byte) 0x28, (byte) 0x59, (byte) 0x7f},
                {(byte) 0x70, (byte) 0x5f, (byte) 0x69, (byte) 0x37, (byte) 0xb3, (byte) 0x24, (byte) 0x31, (byte) 0x4a, (byte) 0x5e, (byte) 0x86, (byte) 0x28, (byte) 0xf1, (byte) 0x1d, (byte) 0xd6,
                        (byte) 0xe4, (byte) 0x65, (byte) 0xc7, (byte) 0x1b, (byte) 0x77, (byte) 0x4, (byte) 0x51, (byte) 0xb9, (byte) 0x20, (byte) 0xe7, (byte) 0x74, (byte) 0xfe, (byte) 0x43,
                        (byte) 0xe8, (byte) 0x23, (byte) 0xd4, (byte) 0x87, (byte) 0x8a},
                {(byte) 0x7d, (byte) 0x29, (byte) 0xe8, (byte) 0xa3, (byte) 0x92, (byte) 0x76, (byte) 0x94, (byte) 0xf2, (byte) 0xdd, (byte) 0xcb, (byte) 0x7a, (byte) 0x9, (byte) 0x9b, (byte) 0x30,
                        (byte) 0xd9, (byte) 0xc1, (byte) 0x1d, (byte) 0x1b, (byte) 0x30, (byte) 0xfb, (byte) 0x5b, (byte) 0xdc, (byte) 0x1b, (byte) 0xe0, (byte) 0xda, (byte) 0x24, (byte) 0x49,
                        (byte) 0x4f, (byte) 0xf2, (byte) 0x9c, (byte) 0x82, (byte) 0xbf},
                {(byte) 0xa4, (byte) 0xe7, (byte) 0xba, (byte) 0x31, (byte) 0xb4, (byte) 0x70, (byte) 0xbf, (byte) 0xff, (byte) 0xd, (byte) 0x32, (byte) 0x44, (byte) 0x5, (byte) 0xde, (byte) 0xf8,
                        (byte) 0xbc, (byte) 0x48, (byte) 0x3b, (byte) 0xae, (byte) 0xfc, (byte) 0x32, (byte) 0x53, (byte) 0xbb, (byte) 0xd3, (byte) 0x39, (byte) 0x45, (byte) 0x9f, (byte) 0xc3,
                        (byte) 0xc1, (byte) 0xe0, (byte) 0x29, (byte) 0x8b, (byte) 0xa0},
                {(byte) 0xe5, (byte) 0xc9, (byte) 0x5, (byte) 0xfd, (byte) 0xf7, (byte) 0xae, (byte) 0x9, (byte) 0xf, (byte) 0x94, (byte) 0x70, (byte) 0x34, (byte) 0x12, (byte) 0x42, (byte) 0x90,
                        (byte) 0xf1, (byte) 0x34, (byte) 0xa2, (byte) 0x71, (byte) 0xb7, (byte) 0x1, (byte) 0xe3, (byte) 0x44, (byte) 0xed, (byte) 0x95, (byte) 0xe9, (byte) 0x3b, (byte) 0x8e,
                        (byte) 0x36, (byte) 0x4f, (byte) 0x2f, (byte) 0x98, (byte) 0x4a},
                {(byte) 0x88, (byte) 0x40, (byte) 0x1d, (byte) 0x63, (byte) 0xa0, (byte) 0x6c, (byte) 0xf6, (byte) 0x15, (byte) 0x47, (byte) 0xc1, (byte) 0x44, (byte) 0x4b, (byte) 0x87, (byte) 0x52,
                        (byte) 0xaf, (byte) 0xff, (byte) 0x7e, (byte) 0xbb, (byte) 0x4a, (byte) 0xf1, (byte) 0xe2, (byte) 0xa, (byte) 0xc6, (byte) 0x30, (byte) 0x46, (byte) 0x70, (byte) 0xb6,
                        (byte) 0xc5, (byte) 0xcc, (byte) 0x6e, (byte) 0x8c, (byte) 0xe6},
                {(byte) 0xa4, (byte) 0xd5, (byte) 0xa4, (byte) 0x56, (byte) 0xbd, (byte) 0x4f, (byte) 0xca, (byte) 0x0, (byte) 0xda, (byte) 0x9d, (byte) 0x84, (byte) 0x4b, (byte) 0xc8, (byte) 0x3e,
                        (byte) 0x18, (byte) 0xae, (byte) 0x73, (byte) 0x57, (byte) 0xce, (byte) 0x45, (byte) 0x30, (byte) 0x64, (byte) 0xd1, (byte) 0xad, (byte) 0xe8, (byte) 0xa6, (byte) 0xce,
                        (byte) 0x68, (byte) 0x14, (byte) 0x5c, (byte) 0x25, (byte) 0x67},
                {(byte) 0xa3, (byte) 0xda, (byte) 0x8c, (byte) 0xf2, (byte) 0xcb, (byte) 0xe, (byte) 0xe1, (byte) 0x16, (byte) 0x33, (byte) 0xe9, (byte) 0x6, (byte) 0x58, (byte) 0x9a, (byte) 0x94,
                        (byte) 0x99, (byte) 0x9a, (byte) 0x1f, (byte) 0x60, (byte) 0xb2, (byte) 0x20, (byte) 0xc2, (byte) 0x6f, (byte) 0x84, (byte) 0x7b, (byte) 0xd1, (byte) 0xce, (byte) 0xac,
                        (byte) 0x7f, (byte) 0xa0, (byte) 0xd1, (byte) 0x85, (byte) 0x18},
                {(byte) 0x32, (byte) 0x59, (byte) 0x5b, (byte) 0xa1, (byte) 0x8d, (byte) 0xdd, (byte) 0x19, (byte) 0xd3, (byte) 0x50, (byte) 0x9a, (byte) 0x1c, (byte) 0xc0, (byte) 0xaa, (byte) 0xa5,
                        (byte) 0xb4, (byte) 0x46, (byte) 0x9f, (byte) 0x3d, (byte) 0x63, (byte) 0x67, (byte) 0xe4, (byte) 0x4, (byte) 0x6b, (byte) 0xba, (byte) 0xf6, (byte) 0xca, (byte) 0x19,
                        (byte) 0xab, (byte) 0xb, (byte) 0x56, (byte) 0xee, (byte) 0x7e},
                {(byte) 0x1f, (byte) 0xb1, (byte) 0x79, (byte) 0xea, (byte) 0xa9, (byte) 0x28, (byte) 0x21, (byte) 0x74, (byte) 0xe9, (byte) 0xbd, (byte) 0xf7, (byte) 0x35, (byte) 0x3b, (byte) 0x36,
                        (byte) 0x51, (byte) 0xee, (byte) 0x1d, (byte) 0x57, (byte) 0xac, (byte) 0x5a, (byte) 0x75, (byte) 0x50, (byte) 0xd3, (byte) 0x76, (byte) 0x3a, (byte) 0x46, (byte) 0xc2,
                        (byte) 0xfe, (byte) 0xa3, (byte) 0x7d, (byte) 0x70, (byte) 0x1},
                {(byte) 0xf7, (byte) 0x35, (byte) 0xc1, (byte) 0xaf, (byte) 0x98, (byte) 0xa4, (byte) 0xd8, (byte) 0x42, (byte) 0x78, (byte) 0xed, (byte) 0xec, (byte) 0x20, (byte) 0x9e, (byte) 0x6b,
                        (byte) 0x67, (byte) 0x79, (byte) 0x41, (byte) 0x83, (byte) 0x63, (byte) 0x15, (byte) 0xea, (byte) 0x3a, (byte) 0xdb, (byte) 0xa8, (byte) 0xfa, (byte) 0xc3, (byte) 0x3b,
                        (byte) 0x4d, (byte) 0x32, (byte) 0x83, (byte) 0x2c, (byte) 0x83},
                {(byte) 0xa7, (byte) 0x40, (byte) 0x3b, (byte) 0x1f, (byte) 0x1c, (byte) 0x27, (byte) 0x47, (byte) 0xf3, (byte) 0x59, (byte) 0x40, (byte) 0xf0, (byte) 0x34, (byte) 0xb7, (byte) 0x2d,
                        (byte) 0x76, (byte) 0x9a, (byte) 0xe7, (byte) 0x3e, (byte) 0x4e, (byte) 0x6c, (byte) 0xd2, (byte) 0x21, (byte) 0x4f, (byte) 0xfd, (byte) 0xb8, (byte) 0xfd, (byte) 0x8d,
                        (byte) 0x39, (byte) 0xdc, (byte) 0x57, (byte) 0x59, (byte) 0xef},
                {(byte) 0x8d, (byte) 0x9b, (byte) 0xc, (byte) 0x49, (byte) 0x2b, (byte) 0x49, (byte) 0xeb, (byte) 0xda, (byte) 0x5b, (byte) 0xa2, (byte) 0xd7, (byte) 0x49, (byte) 0x68, (byte) 0xf3,
                        (byte) 0x70, (byte) 0xd, (byte) 0x7d, (byte) 0x3b, (byte) 0xae, (byte) 0xd0, (byte) 0x7a, (byte) 0x8d, (byte) 0x55, (byte) 0x84, (byte) 0xf5, (byte) 0xa5, (byte) 0xe9,
                        (byte) 0xf0, (byte) 0xe4, (byte) 0xf8, (byte) 0x8e, (byte) 0x65},
                {(byte) 0xa0, (byte) 0xb8, (byte) 0xa2, (byte) 0xf4, (byte) 0x36, (byte) 0x10, (byte) 0x3b, (byte) 0x53, (byte) 0xc, (byte) 0xa8, (byte) 0x7, (byte) 0x9e, (byte) 0x75, (byte) 0x3e,
                        (byte) 0xec, (byte) 0x5a, (byte) 0x91, (byte) 0x68, (byte) 0x94, (byte) 0x92, (byte) 0x56, (byte) 0xe8, (byte) 0x88, (byte) 0x4f, (byte) 0x5b, (byte) 0xb0, (byte) 0x5c,
                        (byte) 0x55, (byte) 0xf8, (byte) 0xba, (byte) 0xbc, (byte) 0x4c},
                {(byte) 0xe3, (byte) 0xbb, (byte) 0x3b, (byte) 0x99, (byte) 0xf3, (byte) 0x87, (byte) 0x94, (byte) 0x7b, (byte) 0x75, (byte) 0xda, (byte) 0xf4, (byte) 0xd6, (byte) 0x72, (byte) 0x6b,
                        (byte) 0x1c, (byte) 0x5d, (byte) 0x64, (byte) 0xae, (byte) 0xac, (byte) 0x28, (byte) 0xdc, (byte) 0x34, (byte) 0xb3, (byte) 0x6d, (byte) 0x6c, (byte) 0x34, (byte) 0xa5,
                        (byte) 0x50, (byte) 0xb8, (byte) 0x28, (byte) 0xdb, (byte) 0x71},
                {(byte) 0xf8, (byte) 0x61, (byte) 0xe2, (byte) 0xf2, (byte) 0x10, (byte) 0x8d, (byte) 0x51, (byte) 0x2a, (byte) 0xe3, (byte) 0xdb, (byte) 0x64, (byte) 0x33, (byte) 0x59, (byte) 0xdd,
                        (byte) 0x75, (byte) 0xfc, (byte) 0x1c, (byte) 0xac, (byte) 0xbc, (byte) 0xf1, (byte) 0x43, (byte) 0xce, (byte) 0x3f, (byte) 0xa2, (byte) 0x67, (byte) 0xbb, (byte) 0xd1,
                        (byte) 0x3c, (byte) 0x2, (byte) 0xe8, (byte) 0x43, (byte) 0xb0},
                {(byte) 0x33, (byte) 0xa, (byte) 0x5b, (byte) 0xca, (byte) 0x88, (byte) 0x29, (byte) 0xa1, (byte) 0x75, (byte) 0x7f, (byte) 0x34, (byte) 0x19, (byte) 0x4d, (byte) 0xb4, (byte) 0x16,
                        (byte) 0x53, (byte) 0x5c, (byte) 0x92, (byte) 0x3b, (byte) 0x94, (byte) 0xc3, (byte) 0xe, (byte) 0x79, (byte) 0x4d, (byte) 0x1e, (byte) 0x79, (byte) 0x74, (byte) 0x75,
                        (byte) 0xd7, (byte) 0xb6, (byte) 0xee, (byte) 0xaf, (byte) 0x3f},
                {(byte) 0xea, (byte) 0xa8, (byte) 0xd4, (byte) 0xf7, (byte) 0xbe, (byte) 0x1a, (byte) 0x39, (byte) 0x21, (byte) 0x5c, (byte) 0xf4, (byte) 0x7e, (byte) 0x9, (byte) 0x4c, (byte) 0x23,
                        (byte) 0x27, (byte) 0x51, (byte) 0x26, (byte) 0xa3, (byte) 0x24, (byte) 0x53, (byte) 0xba, (byte) 0x32, (byte) 0x3c, (byte) 0xd2, (byte) 0x44, (byte) 0xa3, (byte) 0x17,
                        (byte) 0x4a, (byte) 0x6d, (byte) 0xa6, (byte) 0xd5, (byte) 0xad},
                {(byte) 0xb5, (byte) 0x1d, (byte) 0x3e, (byte) 0xa6, (byte) 0xaf, (byte) 0xf2, (byte) 0xc9, (byte) 0x8, (byte) 0x83, (byte) 0x59, (byte) 0x3d, (byte) 0x98, (byte) 0x91, (byte) 0x6b,
                        (byte) 0x3c, (byte) 0x56, (byte) 0x4c, (byte) 0xf8, (byte) 0x7c, (byte) 0xa1, (byte) 0x72, (byte) 0x86, (byte) 0x60, (byte) 0x4d, (byte) 0x46, (byte) 0xe2, (byte) 0x3e,
                        (byte) 0xcc, (byte) 0x8, (byte) 0x6e, (byte) 0xc7, (byte) 0xf6},
                {(byte) 0x2f, (byte) 0x98, (byte) 0x33, (byte) 0xb3, (byte) 0xb1, (byte) 0xbc, (byte) 0x76, (byte) 0x5e, (byte) 0x2b, (byte) 0xd6, (byte) 0x66, (byte) 0xa5, (byte) 0xef, (byte) 0xc4,
                        (byte) 0xe6, (byte) 0x2a, (byte) 0x6, (byte) 0xf4, (byte) 0xb6, (byte) 0xe8, (byte) 0xbe, (byte) 0xc1, (byte) 0xd4, (byte) 0x36, (byte) 0x74, (byte) 0xee, (byte) 0x82,
                        (byte) 0x15, (byte) 0xbc, (byte) 0xef, (byte) 0x21, (byte) 0x63},
                {(byte) 0xfd, (byte) 0xc1, (byte) 0x4e, (byte) 0xd, (byte) 0xf4, (byte) 0x53, (byte) 0xc9, (byte) 0x69, (byte) 0xa7, (byte) 0x7d, (byte) 0x5a, (byte) 0xc4, (byte) 0x6, (byte) 0x58,
                        (byte) 0x58, (byte) 0x26, (byte) 0x7e, (byte) 0xc1, (byte) 0x14, (byte) 0x16, (byte) 0x6, (byte) 0xe0, (byte) 0xfa, (byte) 0x16, (byte) 0x7e, (byte) 0x90, (byte) 0xaf,
                        (byte) 0x3d, (byte) 0x28, (byte) 0x63, (byte) 0x9d, (byte) 0x3f},
                {(byte) 0xd2, (byte) 0xc9, (byte) 0xf2, (byte) 0xe3, (byte) 0x0, (byte) 0x9b, (byte) 0xd2, (byte) 0xc, (byte) 0x5f, (byte) 0xaa, (byte) 0xce, (byte) 0x30, (byte) 0xb7, (byte) 0xd4,
                        (byte) 0xc, (byte) 0x30, (byte) 0x74, (byte) 0x2a, (byte) 0x51, (byte) 0x16, (byte) 0xf2, (byte) 0xe0, (byte) 0x32, (byte) 0x98, (byte) 0xd, (byte) 0xeb, (byte) 0x30,
                        (byte) 0xd8, (byte) 0xe3, (byte) 0xce, (byte) 0xf8, (byte) 0x9a},
                {(byte) 0x4b, (byte) 0xc5, (byte) 0x9e, (byte) 0x7b, (byte) 0xb5, (byte) 0xf1, (byte) 0x79, (byte) 0x92, (byte) 0xff, (byte) 0x51, (byte) 0xe6, (byte) 0x6e, (byte) 0x4, (byte) 0x86,
                        (byte) 0x68, (byte) 0xd3, (byte) 0x9b, (byte) 0x23, (byte) 0x4d, (byte) 0x57, (byte) 0xe6, (byte) 0x96, (byte) 0x67, (byte) 0x31, (byte) 0xcc, (byte) 0xe6, (byte) 0xa6,
                        (byte) 0xf3, (byte) 0x17, (byte) 0xa, (byte) 0x75, (byte) 0x5},
                {(byte) 0xb1, (byte) 0x76, (byte) 0x81, (byte) 0xd9, (byte) 0x13, (byte) 0x32, (byte) 0x6c, (byte) 0xce, (byte) 0x3c, (byte) 0x17, (byte) 0x52, (byte) 0x84, (byte) 0xf8, (byte) 0x5,
                        (byte) 0xa2, (byte) 0x62, (byte) 0xf4, (byte) 0x2b, (byte) 0xcb, (byte) 0xb3, (byte) 0x78, (byte) 0x47, (byte) 0x15, (byte) 0x47, (byte) 0xff, (byte) 0x46, (byte) 0x54,
                        (byte) 0x82, (byte) 0x23, (byte) 0x93, (byte) 0x6a, (byte) 0x48},
                {(byte) 0x38, (byte) 0xdf, (byte) 0x58, (byte) 0x7, (byte) 0x4e, (byte) 0x5e, (byte) 0x65, (byte) 0x65, (byte) 0xf2, (byte) 0xfc, (byte) 0x7c, (byte) 0x89, (byte) 0xfc, (byte) 0x86,
                        (byte) 0x50, (byte) 0x8e, (byte) 0x31, (byte) 0x70, (byte) 0x2e, (byte) 0x44, (byte) 0xd0, (byte) 0xb, (byte) 0xca, (byte) 0x86, (byte) 0xf0, (byte) 0x40, (byte) 0x9,
                        (byte) 0xa2, (byte) 0x30, (byte) 0x78, (byte) 0x47, (byte) 0x4e},
                {(byte) 0x65, (byte) 0xa0, (byte) 0xee, (byte) 0x39, (byte) 0xd1, (byte) 0xf7, (byte) 0x38, (byte) 0x83, (byte) 0xf7, (byte) 0x5e, (byte) 0xe9, (byte) 0x37, (byte) 0xe4, (byte) 0x2c,
                        (byte) 0x3a, (byte) 0xbd, (byte) 0x21, (byte) 0x97, (byte) 0xb2, (byte) 0x26, (byte) 0x1, (byte) 0x13, (byte) 0xf8, (byte) 0x6f, (byte) 0xa3, (byte) 0x44, (byte) 0xed,
                        (byte) 0xd1, (byte) 0xef, (byte) 0x9f, (byte) 0xde, (byte) 0xe7},
                {(byte) 0x8b, (byte) 0xa0, (byte) 0xdf, (byte) 0x15, (byte) 0x76, (byte) 0x25, (byte) 0x92, (byte) 0xd9, (byte) 0x3c, (byte) 0x85, (byte) 0xf7, (byte) 0xf6, (byte) 0x12, (byte) 0xdc,
                        (byte) 0x42, (byte) 0xbe, (byte) 0xd8, (byte) 0xa7, (byte) 0xec, (byte) 0x7c, (byte) 0xab, (byte) 0x27, (byte) 0xb0, (byte) 0x7e, (byte) 0x53, (byte) 0x8d, (byte) 0x7d,
                        (byte) 0xda, (byte) 0xaa, (byte) 0x3e, (byte) 0xa8, (byte) 0xde},
                {(byte) 0xaa, (byte) 0x25, (byte) 0xce, (byte) 0x93, (byte) 0xbd, (byte) 0x2, (byte) 0x69, (byte) 0xd8, (byte) 0x5a, (byte) 0xf6, (byte) 0x43, (byte) 0xfd, (byte) 0x1a, (byte) 0x73,
                        (byte) 0x8, (byte) 0xf9, (byte) 0xc0, (byte) 0x5f, (byte) 0xef, (byte) 0xda, (byte) 0x17, (byte) 0x4a, (byte) 0x19, (byte) 0xa5, (byte) 0x97, (byte) 0x4d, (byte) 0x66,
                        (byte) 0x33, (byte) 0x4c, (byte) 0xfd, (byte) 0x21, (byte) 0x6a},
                {(byte) 0x35, (byte) 0xb4, (byte) 0x98, (byte) 0x31, (byte) 0xdb, (byte) 0x41, (byte) 0x15, (byte) 0x70, (byte) 0xea, (byte) 0x1e, (byte) 0xf, (byte) 0xbb, (byte) 0xed, (byte) 0xcd,
                        (byte) 0x54, (byte) 0x9b, (byte) 0x9a, (byte) 0xd0, (byte) 0x63, (byte) 0xa1, (byte) 0x51, (byte) 0x97, (byte) 0x40, (byte) 0x72, (byte) 0xf6, (byte) 0x75, (byte) 0x9d,
                        (byte) 0xbf, (byte) 0x91, (byte) 0x47, (byte) 0x6f, (byte) 0xe2}
        };

        /**
         * Constructor.
         *
         * @param pHashBitLen the hash bit length
         */
        GordianJHFastDigest(final int pHashBitLen) {
            /* Check the hashBitLength */
            switch (pHashBitLen) {
                case 224:
                case 256:
                case 384:
                case 512:
                    break;
                default:
                    throw new IllegalArgumentException("JH digest restricted to one of [224, 256, 384, 512]");
            }

            /* Store value and initialise */
            hashbitlen = pHashBitLen;
        }

        /**
         * Ensure that the digest is initialised.
         */
        private void ensureInitialised() {
            if (!initialised) {
                init();
                initialised = true;
            }
        }

        /**
         * Obtain the buffer size.
         *
         * @return the bufferSize
         */
        int getBufferSize() {
            return buffer.length;
        }

        /* swapping bit 2i with bit 2i+1 of 64-bit x */
        private static long swap1(final long x) {
            return (((x & 0x5555555555555555L) << 1) | ((x & 0xaaaaaaaaaaaaaaaaL) >>> 1));
        }

        /* swapping bits 4i||4i+1 with bits 4i+2||4i+3 of 64-bit x */
        private static long swap2(final long x) {
            return (((x & 0x3333333333333333L) << 2) | ((x & 0xccccccccccccccccL) >>> 2));
        }

        /* swapping bits 8i||8i+1||8i+2||8i+3 with bits 8i+4||8i+5||8i+6||8i+7 of 64-bit x */
        private static long swap4(final long x) {
            return (((x & 0x0f0f0f0f0f0f0f0fL) << 4) | ((x & 0xf0f0f0f0f0f0f0f0L) >>> 4));
        }

        /*
         * swapping bits 16i||16i+1||......||16i+7 with bits 16i+8||16i+9||......||16i+15 of 64-bit
         * x
         */
        private static long swap8(final long x) {
            return (((x & 0x00ff00ff00ff00ffL) << 8) | ((x & 0xff00ff00ff00ff00L) >>> 8));
        }

        /*
         * swapping bits 32i||32i+1||......||32i+15 with bits 32i+16||32i+17||......||32i+31 of
         * 64-bit x
         */
        private static long swap16(final long x) {
            return (((x & 0x0000ffff0000ffffL) << 16) | ((x & 0xffff0000ffff0000L) >>> 16));
        }

        /*
         * swapping bits 64i||64i+1||......||64i+31 with bits 64i+32||64i+33||......||64i+63 of
         * 64-bit x
         */
        private static long swap32(final long x) {
            return ((x << 32) | (x >>> 32));
        }

        /* The MDS transform */
        private void l(final int i) {
            x[1][i] ^= x[2][i];
            x[3][i] ^= x[4][i];
            x[5][i] ^= x[0][i] ^ x[6][i];
            x[7][i] ^= x[0][i];
            x[0][i] ^= x[3][i];
            x[2][i] ^= x[5][i];
            x[4][i] ^= x[1][i] ^ x[7][i];
            x[6][i] ^= x[1][i];
        }

        /* littleEndianBytes to long */
        private static long leBytesToLong(final byte[] pBuffer, final int pIndex) {
            int myIndex = pIndex;
            myIndex *= 8;
            long value = 0;
            int i = 7;
            while (i > 0) {
                value += pBuffer[myIndex + i--] & 0xff;
                value <<= 8;
            }
            value += pBuffer[myIndex] & 0xff;
            return value;
        }

        /* long to littleEndianBytes */
        private static void longToLeBytes(final long pValue, final byte[] pBuffer, final int pOffset, final int pLength) {
            long myValue = pValue;
            int i = 8;
            while (i > pLength) {
                myValue >>= 8;
                i--;
            }

            int pos = pOffset + pLength - i;
            while (i-- > 0) {
                pBuffer[pos++] = (byte) (myValue & 0xff);
                myValue >>= 8;
            }
        }

        /* The Sbox */
        private void sBox(final int i, final int j, final int roundnumber) {
            final byte[] round = E_8_BITSLICE_ROUNDCONSTANT[roundnumber];
            final int index = i + (j * 2);
            final long cc = leBytesToLong(round, index);
            x[6 + j][i] = ~x[6 + j][i];
            x[0 + j][i] ^= ((~x[4 + j][i]) & (cc));
            final long temp0 = (cc) ^ (x[0 + j][i] & x[2 + j][i]);
            x[0 + j][i] ^= (x[4 + j][i] & x[6 + j][i]);
            x[6 + j][i] ^= ((~x[2 + j][i]) & x[4 + j][i]);
            x[2 + j][i] ^= (x[0 + j][i] & x[4 + j][i]);
            x[4 + j][i] ^= (x[0 + j][i] & (~x[6 + j][i]));
            x[0 + j][i] ^= (x[2 + j][i] | x[6 + j][i]);
            x[6 + j][i] ^= (x[2 + j][i] & x[4 + j][i]);
            x[2 + j][i] ^= (temp0 & x[0 + j][i]);
            x[4 + j][i] ^= temp0;
        }

        /* The round function of E8, in bitslice form */
        private void roundFunction(final int roundnumber) {
            long temp0;

            /* Sbox and MDS layer */
            for (int i = 0; i < 2; i++) {
                sBox(i, 0, roundnumber);
                sBox(i, 1, roundnumber);
                l(i);
            }

            /* swapping layer */
            switch (roundnumber % 7) {
                case 0:
                    for (int j = 1; j < 8; j = j + 2) {
                        for (int i = 0; i < 2; i++) {
                            x[j][i] = swap1(x[j][i]);
                        }
                    }
                    break;
                case 1:
                    for (int j = 1; j < 8; j = j + 2) {
                        for (int i = 0; i < 2; i++) {
                            x[j][i] = swap2(x[j][i]);
                        }
                    }
                    break;
                case 2:
                    for (int j = 1; j < 8; j = j + 2) {
                        for (int i = 0; i < 2; i++) {
                            x[j][i] = swap4(x[j][i]);
                        }
                    }
                    break;
                case 3:
                    for (int j = 1; j < 8; j = j + 2) {
                        for (int i = 0; i < 2; i++) {
                            x[j][i] = swap8(x[j][i]);
                        }
                    }
                    break;
                case 4:
                    for (int j = 1; j < 8; j = j + 2) {
                        for (int i = 0; i < 2; i++) {
                            x[j][i] = swap16(x[j][i]);
                        }
                    }
                    break;
                case 5:
                    for (int j = 1; j < 8; j = j + 2) {
                        for (int i = 0; i < 2; i++) {
                            x[j][i] = swap32(x[j][i]);
                        }
                    }
                    break;
                case 6:
                    for (int j = 1; j < 8; j = j + 2) {
                        temp0 = x[j][0];
                        x[j][0] = x[j][1];
                        x[j][1] = temp0;
                    }
                    break;
                default:
                    break;
            }
        }

        /* The bijective function E8, in bitslice form */
        private void e8() {
            /* perform 42 rounds */
            for (int i = 0; i < 42; i++) {
                roundFunction(i);
            }
        }

        /* The compression function F8 */
        private void f8() {
            /* xor the 512-bit message with the first half of the 1024-bit hash state */
            for (int i = 0; i < 8; i++) {
                x[i >> 1][i & 1] ^= leBytesToLong(buffer, i);
            }

            /* the bijective function E8 */
            e8();

            /* xor the 512-bit message with the second half of the 1024-bit hash state */
            for (int i = 0; i < 8; i++) {
                x[(8 + i) >> 1][(8 + i) & 1] ^= leBytesToLong(buffer, i);
            }
        }

        /* Build state from byte buffer */
        private void buildStateFromBytes(final byte[] pBytes) {
            int index = 0;
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 2; j++) {
                    x[i][j] = leBytesToLong(pBytes, index++);
                }
            }
        }

        /* before hashing a message, initialize the hash state as H0 */
        private void init() {
            databitlen = 0;
            datasizeInBuffer = 0;

            /* load the initial hash value into state */
            switch (hashbitlen) {
                case 224:
                    buildStateFromBytes(JH224_H0);
                    break;
                case 256:
                    buildStateFromBytes(JH256_H0);
                    break;
                case 384:
                    buildStateFromBytes(JH384_H0);
                    break;
                case 512:
                    buildStateFromBytes(JH512_H0);
                    break;
                default:
                    break;
            }
        }

        /* CopyIn a state */
        void copyIn(final GordianJHFastDigest pState) {
            /* Ensure that we are copying similar digest */
            if (this.hashbitlen != pState.hashbitlen) {
                throw new IllegalArgumentException();
            }

            /* Copy state */
            initialised = pState.initialised;
            databitlen = pState.databitlen;
            datasizeInBuffer = pState.datasizeInBuffer;
            System.arraycopy(pState.buffer, 0, buffer, 0, buffer.length);
            for (int i = 0; i < 8; i++) {
                for (int j = 0; j < 2; j++) {
                    x[i][j] = pState.x[i][j];
                }
            }
        }

        /**
         * Reset the digest.
         */
        void reset() {
            /* Clear the initialised flag */
            initialised = false;
        }

        /* hash each 512-bit message block, except the last partial block */
        void update(final byte[] data, final int pOffset, final long pDatabitlen) {
            int index; /* the starting address of the data to be compressed */
            long myDatabitlen = pDatabitlen;

            /* Ensure that we are initialised */
            ensureInitialised();

            databitlen += myDatabitlen;
            index = 0;

            /* if there is remaining data in the buffer, fill it to a full message block first */
            /*
             * we assume that the size of the data in the buffer is the multiple of 8 bits if it is
             * not at the end of a message
             */

            /*
             * There is data in the buffer, but the incoming data is insufficient for a full block
             */
            if ((datasizeInBuffer > 0) && ((datasizeInBuffer + myDatabitlen) < 512)) {
                int copyDataLen = (int) (myDatabitlen >> 3);
                if ((myDatabitlen & 7) != 0) {
                    copyDataLen++;
                }
                System.arraycopy(data, pOffset, buffer, (int) (datasizeInBuffer >> 3), copyDataLen);
                datasizeInBuffer += myDatabitlen;
                myDatabitlen = 0;
            }

            /* There is data in the buffer, and the incoming data is sufficient for a full block */
            if ((datasizeInBuffer > 0) && ((datasizeInBuffer + myDatabitlen) >= 512)) {
                System.arraycopy(data, pOffset, buffer, (int) (datasizeInBuffer >> 3), (int) (64 - (datasizeInBuffer >> 3)));
                index = (int) (64 - (datasizeInBuffer >> 3));
                myDatabitlen = myDatabitlen - (512 - (int) datasizeInBuffer);
                f8();
                datasizeInBuffer = 0;
            }

            /* hash the remaining full message blocks */
            for (; myDatabitlen >= 512; index = index + 64, myDatabitlen = myDatabitlen - 512) {
                System.arraycopy(data, pOffset + index, buffer, 0, 64);
                f8();
            }

            /*
             * store the partial block into buffer, assume that -- if part of the last byte is not
             * part of the message, then that part consists of 0 bits
             */
            if (myDatabitlen > 0) {
                if ((myDatabitlen & 7) == 0) {
                    System.arraycopy(data, pOffset + index, buffer, 0, (int) ((databitlen & 0x1ff) >> 3));
                } else {
                    System.arraycopy(data, pOffset + index, buffer, 0, (int) (((databitlen & 0x1ff) >> 3) + 1));
                }
                datasizeInBuffer = myDatabitlen;
            }
        }

        /* Build hash from state buffer */
        private void buildHashFromState(final byte[] pHashVal, final int pOffset, final int pLength) {
            int myLength = pLength;
            for (int i = 7; i >= 0 && myLength > 0; i--) {
                for (int j = 1; j >= 0 && myLength > 0; j--) {
                    longToLeBytes(x[i][j], pHashVal, pOffset, myLength);
                    myLength -= 8;
                }
            }
        }

        /*
         * pad the message, process the padded block(s), truncate the hash value H to obtain the
         * message digest
         */
        void finalise(final byte[] hashval, final int pOffset) {
            /* Ensure that we are initialised */
            ensureInitialised();

            if ((databitlen & 0x1ff) == 0) {
                /*
                 * pad the message when databitlen is multiple of 512 bits, then process the padded
                 * block
                 */
                Arrays.fill(buffer, (byte) 0);
                buffer[0] = (byte) 0x80;
                buffer[63] = (byte) (databitlen & 0xff);
                buffer[62] = (byte) ((databitlen >> 8) & 0xff);
                buffer[61] = (byte) ((databitlen >> 16) & 0xff);
                buffer[60] = (byte) ((databitlen >> 24) & 0xff);
                buffer[59] = (byte) ((databitlen >> 32) & 0xff);
                buffer[58] = (byte) ((databitlen >> 40) & 0xff);
                buffer[57] = (byte) ((databitlen >> 48) & 0xff);
                buffer[56] = (byte) ((databitlen >> 56) & 0xff);
                f8();
            } else {
                /* set the rest of the bytes in the buffer to 0 */
                if ((datasizeInBuffer & 7) == 0) {
                    for (int i = (int) (databitlen & 0x1ff) >> 3; i < 64; i++) {
                        buffer[i] = 0;
                    }
                } else {
                    for (int i = (int) ((databitlen & 0x1ff) >> 3) + 1; i < 64; i++) {
                        buffer[i] = 0;
                    }
                }

                /*
                 * pad and process the partial block when databitlen is not multiple of 512 bits,
                 * then hash the padded blocks
                 */
                buffer[(int) ((databitlen & 0x1ff) >> 3)] |= 1 << (7 - (databitlen & 7));
                f8();
                Arrays.fill(buffer, (byte) 0);
                buffer[63] = (byte) (databitlen & 0xff);
                buffer[62] = (byte) ((databitlen >> 8) & 0xff);
                buffer[61] = (byte) ((databitlen >> 16) & 0xff);
                buffer[60] = (byte) ((databitlen >> 24) & 0xff);
                buffer[59] = (byte) ((databitlen >> 32) & 0xff);
                buffer[58] = (byte) ((databitlen >> 40) & 0xff);
                buffer[57] = (byte) ((databitlen >> 48) & 0xff);
                buffer[56] = (byte) ((databitlen >> 56) & 0xff);
                f8();
            }

            /* truncating the final hash value to generate the message digest */
            switch (hashbitlen) {
                case 224:
                    buildHashFromState(hashval, pOffset, 28);
                    break;
                case 256:
                    buildHashFromState(hashval, pOffset, 32);
                    break;
                case 384:
                    buildHashFromState(hashval, pOffset, 48);
                    break;
                case 512:
                    buildHashFromState(hashval, pOffset, 64);
                    break;
                default:
                    break;
            }

            /* Reset the digest */
            reset();
        }
    }
}