// 
// Decompiled by Procyon v0.6.0
// 

package org.bouncycastle.crypto.digests;

import org.bouncycastle.util.Pack;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.CryptoServicePurpose;
import org.bouncycastle.crypto.Xof;
import org.bouncycastle.crypto.ExtendedDigest;

public final class Kangaroo
{
    private static final int DIGESTLEN = 32;
    
    abstract static class KangarooBase implements ExtendedDigest, Xof
    {
        private static final int BLKSIZE = 8192;
        private static final byte[] SINGLE;
        private static final byte[] INTERMEDIATE;
        private static final byte[] FINAL;
        private static final byte[] FIRST;
        private final byte[] singleByte;
        private final KangarooSponge theTree;
        private final KangarooSponge theLeaf;
        private final int theChainLen;
        private byte[] thePersonal;
        private boolean squeezing;
        private int theCurrNode;
        private int theProcessed;
        
        KangarooBase(final int n, final int n2, final int n3, final CryptoServicePurpose cryptoServicePurpose) {
            this.singleByte = new byte[1];
            this.theTree = new KangarooSponge(n, n2);
            this.theLeaf = new KangarooSponge(n, n2);
            this.theChainLen = n >> 2;
            this.buildPersonal(null);
            CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties(this, n, cryptoServicePurpose));
        }
        
        private void buildPersonal(final byte[] array) {
            final int n = (array == null) ? 0 : array.length;
            final byte[] lengthEncode = lengthEncode(n);
            System.arraycopy(lengthEncode, 0, this.thePersonal = ((array == null) ? new byte[n + lengthEncode.length] : Arrays.copyOf(array, n + lengthEncode.length)), n, lengthEncode.length);
        }
        
        @Override
        public int getByteLength() {
            return this.theTree.theRateBytes;
        }
        
        @Override
        public int getDigestSize() {
            return this.theChainLen >> 1;
        }
        
        public void init(final KangarooParameters kangarooParameters) {
            this.buildPersonal(kangarooParameters.getPersonalisation());
            this.reset();
        }
        
        @Override
        public void update(final byte b) {
            this.singleByte[0] = b;
            this.update(this.singleByte, 0, 1);
        }
        
        @Override
        public void update(final byte[] array, final int n, final int n2) {
            this.processData(array, n, n2);
        }
        
        @Override
        public int doFinal(final byte[] array, final int n) {
            return this.doFinal(array, n, this.getDigestSize());
        }
        
        @Override
        public int doFinal(final byte[] array, final int n, final int n2) {
            if (this.squeezing) {
                throw new IllegalStateException("Already outputting");
            }
            final int doOutput = this.doOutput(array, n, n2);
            this.reset();
            return doOutput;
        }
        
        @Override
        public int doOutput(final byte[] array, final int n, final int n2) {
            if (!this.squeezing) {
                this.switchToSqueezing();
            }
            if (n2 < 0) {
                throw new IllegalArgumentException("Invalid output length");
            }
            this.theTree.squeeze(array, n, n2);
            return n2;
        }
        
        private void processData(final byte[] array, final int n, final int n2) {
            if (this.squeezing) {
                throw new IllegalStateException("attempt to absorb while squeezing");
            }
            final KangarooSponge kangarooSponge = (this.theCurrNode == 0) ? this.theTree : this.theLeaf;
            final int n3 = 8192 - this.theProcessed;
            if (n3 >= n2) {
                kangarooSponge.absorb(array, n, n2);
                this.theProcessed += n2;
                return;
            }
            if (n3 > 0) {
                kangarooSponge.absorb(array, n, n3);
                this.theProcessed += n3;
            }
            int min;
            for (int i = n3; i < n2; i += min) {
                if (this.theProcessed == 8192) {
                    this.switchLeaf(true);
                }
                min = Math.min(n2 - i, 8192);
                this.theLeaf.absorb(array, n + i, min);
                this.theProcessed += min;
            }
        }
        
        @Override
        public void reset() {
            this.theTree.initSponge();
            this.theLeaf.initSponge();
            this.theCurrNode = 0;
            this.theProcessed = 0;
            this.squeezing = false;
        }
        
        private void switchLeaf(final boolean b) {
            if (this.theCurrNode == 0) {
                this.theTree.absorb(KangarooBase.FIRST, 0, KangarooBase.FIRST.length);
            }
            else {
                this.theLeaf.absorb(KangarooBase.INTERMEDIATE, 0, KangarooBase.INTERMEDIATE.length);
                final byte[] array = new byte[this.theChainLen];
                this.theLeaf.squeeze(array, 0, this.theChainLen);
                this.theTree.absorb(array, 0, this.theChainLen);
                this.theLeaf.initSponge();
            }
            if (b) {
                ++this.theCurrNode;
            }
            this.theProcessed = 0;
        }
        
        private void switchToSqueezing() {
            this.processData(this.thePersonal, 0, this.thePersonal.length);
            if (this.theCurrNode == 0) {
                this.switchSingle();
            }
            else {
                this.switchFinal();
            }
        }
        
        private void switchSingle() {
            this.theTree.absorb(KangarooBase.SINGLE, 0, 1);
            this.theTree.padAndSwitchToSqueezingPhase();
        }
        
        private void switchFinal() {
            this.switchLeaf(false);
            final byte[] lengthEncode = lengthEncode(this.theCurrNode);
            this.theTree.absorb(lengthEncode, 0, lengthEncode.length);
            this.theTree.absorb(KangarooBase.FINAL, 0, KangarooBase.FINAL.length);
            this.theTree.padAndSwitchToSqueezingPhase();
        }
        
        private static byte[] lengthEncode(final long n) {
            byte b = 0;
            long n2 = n;
            if (n2 != 0L) {
                b = 1;
                while ((n2 >>= 8) != 0L) {
                    ++b;
                }
            }
            final byte[] array = new byte[b + 1];
            array[b] = b;
            for (byte b2 = 0; b2 < b; ++b2) {
                array[b2] = (byte)(n >> 8 * (b - b2 - 1));
            }
            return array;
        }
        
        static {
            SINGLE = new byte[] { 7 };
            INTERMEDIATE = new byte[] { 11 };
            FINAL = new byte[] { -1, -1, 6 };
            FIRST = new byte[] { 3, 0, 0, 0, 0, 0, 0, 0 };
        }
    }
    
    public static class KangarooParameters implements CipherParameters
    {
        private byte[] thePersonal;
        
        public byte[] getPersonalisation() {
            return Arrays.clone(this.thePersonal);
        }
        
        public static class Builder
        {
            private byte[] thePersonal;
            
            public Builder setPersonalisation(final byte[] array) {
                this.thePersonal = Arrays.clone(array);
                return this;
            }
            
            public KangarooParameters build() {
                final KangarooParameters kangarooParameters = new KangarooParameters();
                if (this.thePersonal != null) {
                    kangarooParameters.thePersonal = this.thePersonal;
                }
                return kangarooParameters;
            }
        }
    }
    
    private static class KangarooSponge
    {
        private static final long[] KeccakRoundConstants;
        private final int theRounds;
        private final int theRateBytes;
        private final long[] theState;
        private final byte[] theQueue;
        private int bytesInQueue;
        private boolean squeezing;
        
        KangarooSponge(final int n, final int theRounds) {
            this.theState = new long[25];
            this.theRateBytes = 1600 - (n << 1) >> 3;
            this.theRounds = theRounds;
            this.theQueue = new byte[this.theRateBytes];
            this.initSponge();
        }
        
        private void initSponge() {
            Arrays.fill(this.theState, 0L);
            Arrays.fill(this.theQueue, (byte)0);
            this.bytesInQueue = 0;
            this.squeezing = false;
        }
        
        private void absorb(final byte[] array, final int n, final int n2) {
            if (this.squeezing) {
                throw new IllegalStateException("attempt to absorb while squeezing");
            }
            int min;
            for (int i = 0; i < n2; i += min) {
                if (this.bytesInQueue == this.theRateBytes) {
                    this.KangarooAbsorb(this.theQueue, 0);
                    this.bytesInQueue = 0;
                }
                if (this.bytesInQueue == 0 && i <= n2 - this.theRateBytes) {
                    do {
                        this.KangarooAbsorb(array, n + i);
                        i += this.theRateBytes;
                    } while (i <= n2 - this.theRateBytes);
                }
                else {
                    min = Math.min(this.theRateBytes - this.bytesInQueue, n2 - i);
                    System.arraycopy(array, n + i, this.theQueue, this.bytesInQueue, min);
                    this.bytesInQueue += min;
                }
            }
        }
        
        private void padAndSwitchToSqueezingPhase() {
            for (int i = this.bytesInQueue; i < this.theRateBytes; ++i) {
                this.theQueue[i] = 0;
            }
            final byte[] theQueue = this.theQueue;
            final int n = this.theRateBytes - 1;
            theQueue[n] ^= (byte)128;
            this.KangarooAbsorb(this.theQueue, 0);
            this.KangarooExtract();
            this.bytesInQueue = this.theRateBytes;
            this.squeezing = true;
        }
        
        private void squeeze(final byte[] array, final int n, final int n2) {
            if (!this.squeezing) {
                this.padAndSwitchToSqueezingPhase();
            }
            int min;
            for (int i = 0; i < n2; i += min) {
                if (this.bytesInQueue == 0) {
                    this.KangarooPermutation();
                    this.KangarooExtract();
                    this.bytesInQueue = this.theRateBytes;
                }
                min = Math.min(this.bytesInQueue, n2 - i);
                System.arraycopy(this.theQueue, this.theRateBytes - this.bytesInQueue, array, n + i, min);
                this.bytesInQueue -= min;
            }
        }
        
        private void KangarooAbsorb(final byte[] array, final int n) {
            final int n2 = this.theRateBytes >> 3;
            int n3 = n;
            for (int i = 0; i < n2; ++i) {
                final long[] theState = this.theState;
                final int n4 = i;
                theState[n4] ^= Pack.littleEndianToLong(array, n3);
                n3 += 8;
            }
            this.KangarooPermutation();
        }
        
        private void KangarooExtract() {
            Pack.longToLittleEndian(this.theState, 0, this.theRateBytes >> 3, this.theQueue, 0);
        }
        
        private void KangarooPermutation() {
            final long[] theState = this.theState;
            long n = theState[0];
            long n2 = theState[1];
            long n3 = theState[2];
            long n4 = theState[3];
            long n5 = theState[4];
            long n6 = theState[5];
            long n7 = theState[6];
            long n8 = theState[7];
            long n9 = theState[8];
            long n10 = theState[9];
            long n11 = theState[10];
            long n12 = theState[11];
            long n13 = theState[12];
            long n14 = theState[13];
            long n15 = theState[14];
            long n16 = theState[15];
            long n17 = theState[16];
            long n18 = theState[17];
            long n19 = theState[18];
            long n20 = theState[19];
            long n21 = theState[20];
            long n22 = theState[21];
            long n23 = theState[22];
            long n24 = theState[23];
            long n25 = theState[24];
            final int n26 = KangarooSponge.KeccakRoundConstants.length - this.theRounds;
            for (int i = 0; i < this.theRounds; ++i) {
                final long n27 = n ^ n6 ^ n11 ^ n16 ^ n21;
                final long n28 = n2 ^ n7 ^ n12 ^ n17 ^ n22;
                final long n29 = n3 ^ n8 ^ n13 ^ n18 ^ n23;
                final long n30 = n4 ^ n9 ^ n14 ^ n19 ^ n24;
                final long n31 = n5 ^ n10 ^ n15 ^ n20 ^ n25;
                final long n32 = (n28 << 1 | n28 >>> -1) ^ n31;
                final long n33 = (n29 << 1 | n29 >>> -1) ^ n27;
                final long n34 = (n30 << 1 | n30 >>> -1) ^ n28;
                final long n35 = (n31 << 1 | n31 >>> -1) ^ n29;
                final long n36 = (n27 << 1 | n27 >>> -1) ^ n30;
                final long n37 = n ^ n32;
                final long n38 = n6 ^ n32;
                final long n39 = n11 ^ n32;
                final long n40 = n16 ^ n32;
                final long n41 = n21 ^ n32;
                final long n42 = n2 ^ n33;
                final long n43 = n7 ^ n33;
                final long n44 = n12 ^ n33;
                final long n45 = n17 ^ n33;
                final long n46 = n22 ^ n33;
                final long n47 = n3 ^ n34;
                final long n48 = n8 ^ n34;
                final long n49 = n13 ^ n34;
                final long n50 = n18 ^ n34;
                final long n51 = n23 ^ n34;
                final long n52 = n4 ^ n35;
                final long n53 = n9 ^ n35;
                final long n54 = n14 ^ n35;
                final long n55 = n19 ^ n35;
                final long n56 = n24 ^ n35;
                final long n57 = n5 ^ n36;
                final long n58 = n10 ^ n36;
                final long n59 = n15 ^ n36;
                final long n60 = n20 ^ n36;
                final long n61 = n25 ^ n36;
                final long n62 = n42 << 1 | n42 >>> 63;
                final long n63 = n43 << 44 | n43 >>> 20;
                final long n64 = n58 << 20 | n58 >>> 44;
                final long n65 = n51 << 61 | n51 >>> 3;
                final long n66 = n59 << 39 | n59 >>> 25;
                final long n67 = n41 << 18 | n41 >>> 46;
                final long n68 = n47 << 62 | n47 >>> 2;
                final long n69 = n49 << 43 | n49 >>> 21;
                final long n70 = n54 << 25 | n54 >>> 39;
                final long n71 = n60 << 8 | n60 >>> 56;
                final long n72 = n56 << 56 | n56 >>> 8;
                final long n73 = n40 << 41 | n40 >>> 23;
                final long n74 = n57 << 27 | n57 >>> 37;
                final long n75 = n61 << 14 | n61 >>> 50;
                final long n76 = n46 << 2 | n46 >>> 62;
                final long n77 = n53 << 55 | n53 >>> 9;
                final long n78 = n45 << 45 | n45 >>> 19;
                final long n79 = n38 << 36 | n38 >>> 28;
                final long n80 = n52 << 28 | n52 >>> 36;
                final long n81 = n55 << 21 | n55 >>> 43;
                final long n82 = n50 << 15 | n50 >>> 49;
                final long n83 = n44 << 10 | n44 >>> 54;
                final long n84 = n48 << 6 | n48 >>> 58;
                final long n85 = n39 << 3 | n39 >>> 61;
                final long n86 = n62;
                final long n87 = n37 ^ (~n63 & n69);
                final long n88 = n63 ^ (~n69 & n81);
                n3 = (n69 ^ (~n81 & n75));
                n4 = (n81 ^ (~n75 & n37));
                n5 = (n75 ^ (~n37 & n63));
                final long n89 = n87;
                n2 = n88;
                final long n90 = n80 ^ (~n64 & n85);
                final long n91 = n64 ^ (~n85 & n78);
                n8 = (n85 ^ (~n78 & n65));
                n9 = (n78 ^ (~n65 & n80));
                n10 = (n65 ^ (~n80 & n64));
                n6 = n90;
                n7 = n91;
                final long n92 = n86 ^ (~n84 & n70);
                final long n93 = n84 ^ (~n70 & n71);
                n13 = (n70 ^ (~n71 & n67));
                n14 = (n71 ^ (~n67 & n86));
                n15 = (n67 ^ (~n86 & n84));
                n11 = n92;
                n12 = n93;
                final long n94 = n74 ^ (~n79 & n83);
                final long n95 = n79 ^ (~n83 & n82);
                n18 = (n83 ^ (~n82 & n72));
                n19 = (n82 ^ (~n72 & n74));
                n20 = (n72 ^ (~n74 & n79));
                n16 = n94;
                n17 = n95;
                final long n96 = n68 ^ (~n77 & n66);
                final long n97 = n77 ^ (~n66 & n73);
                n23 = (n66 ^ (~n73 & n76));
                n24 = (n73 ^ (~n76 & n68));
                n25 = (n76 ^ (~n68 & n77));
                n21 = n96;
                n22 = n97;
                n = (n89 ^ KangarooSponge.KeccakRoundConstants[n26 + i]);
            }
            theState[0] = n;
            theState[1] = n2;
            theState[2] = n3;
            theState[3] = n4;
            theState[4] = n5;
            theState[5] = n6;
            theState[6] = n7;
            theState[7] = n8;
            theState[8] = n9;
            theState[9] = n10;
            theState[10] = n11;
            theState[11] = n12;
            theState[12] = n13;
            theState[13] = n14;
            theState[14] = n15;
            theState[15] = n16;
            theState[16] = n17;
            theState[17] = n18;
            theState[18] = n19;
            theState[19] = n20;
            theState[20] = n21;
            theState[21] = n22;
            theState[22] = n23;
            theState[23] = n24;
            theState[24] = n25;
        }
        
        static {
            KeccakRoundConstants = new long[] { 1L, 32898L, -9223372036854742902L, -9223372034707259392L, 32907L, 2147483649L, -9223372034707259263L, -9223372036854743031L, 138L, 136L, 2147516425L, 2147483658L, 2147516555L, -9223372036854775669L, -9223372036854742903L, -9223372036854743037L, -9223372036854743038L, -9223372036854775680L, 32778L, -9223372034707292150L, -9223372034707259263L, -9223372036854742912L, 2147483649L, -9223372034707259384L };
        }
    }
    
    public static class KangarooTwelve extends KangarooBase
    {
        public KangarooTwelve() {
            this(32, CryptoServicePurpose.ANY);
        }
        
        public KangarooTwelve(final int n, final CryptoServicePurpose cryptoServicePurpose) {
            super(128, 12, n, cryptoServicePurpose);
        }
        
        public KangarooTwelve(final CryptoServicePurpose cryptoServicePurpose) {
            this(32, cryptoServicePurpose);
        }
        
        @Override
        public String getAlgorithmName() {
            return "KangarooTwelve";
        }
    }
    
    public static class MarsupilamiFourteen extends KangarooBase
    {
        public MarsupilamiFourteen() {
            this(32, CryptoServicePurpose.ANY);
        }
        
        public MarsupilamiFourteen(final int n, final CryptoServicePurpose cryptoServicePurpose) {
            super(256, 14, n, cryptoServicePurpose);
        }
        
        public MarsupilamiFourteen(final CryptoServicePurpose cryptoServicePurpose) {
            this(32, cryptoServicePurpose);
        }
        
        @Override
        public String getAlgorithmName() {
            return "MarsupilamiFourteen";
        }
    }
}
