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

package org.bouncycastle.crypto.engines;

import org.bouncycastle.util.Integers;
import org.bouncycastle.util.Pack;

public class ChaChaEngine extends Salsa20Engine
{
    public ChaChaEngine() {
    }
    
    public ChaChaEngine(final int n) {
        super(n);
    }
    
    @Override
    public String getAlgorithmName() {
        return "ChaCha" + this.rounds;
    }
    
    @Override
    protected void advanceCounter(final long n) {
        final int n2 = (int)(n >>> 32);
        final int n3 = (int)n;
        if (n2 > 0) {
            final int[] engineState = this.engineState;
            final int n4 = 13;
            engineState[n4] += n2;
        }
        final int n5 = this.engineState[12];
        final int[] engineState2 = this.engineState;
        final int n6 = 12;
        engineState2[n6] += n3;
        if (n5 != 0 && this.engineState[12] < n5) {
            final int[] engineState3 = this.engineState;
            final int n7 = 13;
            ++engineState3[n7];
        }
    }
    
    @Override
    protected void advanceCounter() {
        if (++this.engineState[12] == 0) {
            final int[] engineState = this.engineState;
            final int n = 13;
            ++engineState[n];
        }
    }
    
    @Override
    protected void retreatCounter(final long n) {
        final int n2 = (int)(n >>> 32);
        final int n3 = (int)n;
        if (n2 != 0) {
            if (((long)this.engineState[13] & 0xFFFFFFFFL) < ((long)n2 & 0xFFFFFFFFL)) {
                throw new IllegalStateException("attempt to reduce counter past zero.");
            }
            final int[] engineState = this.engineState;
            final int n4 = 13;
            engineState[n4] -= n2;
        }
        if (((long)this.engineState[12] & 0xFFFFFFFFL) >= ((long)n3 & 0xFFFFFFFFL)) {
            final int[] engineState2 = this.engineState;
            final int n5 = 12;
            engineState2[n5] -= n3;
        }
        else {
            if (this.engineState[13] == 0) {
                throw new IllegalStateException("attempt to reduce counter past zero.");
            }
            final int[] engineState3 = this.engineState;
            final int n6 = 13;
            --engineState3[n6];
            final int[] engineState4 = this.engineState;
            final int n7 = 12;
            engineState4[n7] -= n3;
        }
    }
    
    @Override
    protected void retreatCounter() {
        if (this.engineState[12] == 0 && this.engineState[13] == 0) {
            throw new IllegalStateException("attempt to reduce counter past zero.");
        }
        final int[] engineState = this.engineState;
        final int n = 12;
        if (--engineState[n] == -1) {
            final int[] engineState2 = this.engineState;
            final int n2 = 13;
            --engineState2[n2];
        }
    }
    
    @Override
    protected long getCounter() {
        return (long)this.engineState[13] << 32 | ((long)this.engineState[12] & 0xFFFFFFFFL);
    }
    
    @Override
    protected void resetCounter() {
        this.engineState[12] = (this.engineState[13] = 0);
    }
    
    @Override
    protected void setKey(final byte[] array, final byte[] array2) {
        if (array != null) {
            if (array.length != 16 && array.length != 32) {
                throw new IllegalArgumentException(this.getAlgorithmName() + " requires 128 bit or 256 bit key");
            }
            this.packTauOrSigma(array.length, this.engineState, 0);
            Pack.littleEndianToInt(array, 0, this.engineState, 4, 4);
            Pack.littleEndianToInt(array, array.length - 16, this.engineState, 8, 4);
        }
        Pack.littleEndianToInt(array2, 0, this.engineState, 14, 2);
    }
    
    @Override
    protected void generateKeyStream(final byte[] array) {
        chachaCore(this.rounds, this.engineState, this.x);
        Pack.intToLittleEndian(this.x, array, 0);
    }
    
    public static void chachaCore(final int n, final int[] array, final int[] array2) {
        if (array.length != 16) {
            throw new IllegalArgumentException();
        }
        if (array2.length != 16) {
            throw new IllegalArgumentException();
        }
        if (n % 2 != 0) {
            throw new IllegalArgumentException("Number of rounds must be even");
        }
        int n2 = array[0];
        int n3 = array[1];
        int n4 = array[2];
        int n5 = array[3];
        int rotateLeft = array[4];
        int rotateLeft2 = array[5];
        int rotateLeft3 = array[6];
        int rotateLeft4 = array[7];
        int n6 = array[8];
        int n7 = array[9];
        int n8 = array[10];
        int n9 = array[11];
        int rotateLeft5 = array[12];
        int rotateLeft6 = array[13];
        int rotateLeft7 = array[14];
        int rotateLeft8 = array[15];
        for (int i = n; i > 0; i -= 2) {
            final int n10 = n2 + rotateLeft;
            final int rotateLeft9 = Integers.rotateLeft(rotateLeft5 ^ n10, 16);
            final int n11 = n6 + rotateLeft9;
            final int rotateLeft10 = Integers.rotateLeft(rotateLeft ^ n11, 12);
            final int n12 = n10 + rotateLeft10;
            final int rotateLeft11 = Integers.rotateLeft(rotateLeft9 ^ n12, 8);
            final int n13 = n11 + rotateLeft11;
            final int rotateLeft12 = Integers.rotateLeft(rotateLeft10 ^ n13, 7);
            final int n14 = n3 + rotateLeft2;
            final int rotateLeft13 = Integers.rotateLeft(rotateLeft6 ^ n14, 16);
            final int n15 = n7 + rotateLeft13;
            final int rotateLeft14 = Integers.rotateLeft(rotateLeft2 ^ n15, 12);
            final int n16 = n14 + rotateLeft14;
            final int rotateLeft15 = Integers.rotateLeft(rotateLeft13 ^ n16, 8);
            final int n17 = n15 + rotateLeft15;
            final int rotateLeft16 = Integers.rotateLeft(rotateLeft14 ^ n17, 7);
            final int n18 = n4 + rotateLeft3;
            final int rotateLeft17 = Integers.rotateLeft(rotateLeft7 ^ n18, 16);
            final int n19 = n8 + rotateLeft17;
            final int rotateLeft18 = Integers.rotateLeft(rotateLeft3 ^ n19, 12);
            final int n20 = n18 + rotateLeft18;
            final int rotateLeft19 = Integers.rotateLeft(rotateLeft17 ^ n20, 8);
            final int n21 = n19 + rotateLeft19;
            final int rotateLeft20 = Integers.rotateLeft(rotateLeft18 ^ n21, 7);
            final int n22 = n5 + rotateLeft4;
            final int rotateLeft21 = Integers.rotateLeft(rotateLeft8 ^ n22, 16);
            final int n23 = n9 + rotateLeft21;
            final int rotateLeft22 = Integers.rotateLeft(rotateLeft4 ^ n23, 12);
            final int n24 = n22 + rotateLeft22;
            final int rotateLeft23 = Integers.rotateLeft(rotateLeft21 ^ n24, 8);
            final int n25 = n23 + rotateLeft23;
            final int rotateLeft24 = Integers.rotateLeft(rotateLeft22 ^ n25, 7);
            final int n26 = n12 + rotateLeft16;
            final int rotateLeft25 = Integers.rotateLeft(rotateLeft23 ^ n26, 16);
            final int n27 = n21 + rotateLeft25;
            final int rotateLeft26 = Integers.rotateLeft(rotateLeft16 ^ n27, 12);
            n2 = n26 + rotateLeft26;
            rotateLeft8 = Integers.rotateLeft(rotateLeft25 ^ n2, 8);
            n8 = n27 + rotateLeft8;
            rotateLeft2 = Integers.rotateLeft(rotateLeft26 ^ n8, 7);
            final int n28 = n16 + rotateLeft20;
            final int rotateLeft27 = Integers.rotateLeft(rotateLeft11 ^ n28, 16);
            final int n29 = n25 + rotateLeft27;
            final int rotateLeft28 = Integers.rotateLeft(rotateLeft20 ^ n29, 12);
            n3 = n28 + rotateLeft28;
            rotateLeft5 = Integers.rotateLeft(rotateLeft27 ^ n3, 8);
            n9 = n29 + rotateLeft5;
            rotateLeft3 = Integers.rotateLeft(rotateLeft28 ^ n9, 7);
            final int n30 = n20 + rotateLeft24;
            final int rotateLeft29 = Integers.rotateLeft(rotateLeft15 ^ n30, 16);
            final int n31 = n13 + rotateLeft29;
            final int rotateLeft30 = Integers.rotateLeft(rotateLeft24 ^ n31, 12);
            n4 = n30 + rotateLeft30;
            rotateLeft6 = Integers.rotateLeft(rotateLeft29 ^ n4, 8);
            n6 = n31 + rotateLeft6;
            rotateLeft4 = Integers.rotateLeft(rotateLeft30 ^ n6, 7);
            final int n32 = n24 + rotateLeft12;
            final int rotateLeft31 = Integers.rotateLeft(rotateLeft19 ^ n32, 16);
            final int n33 = n17 + rotateLeft31;
            final int rotateLeft32 = Integers.rotateLeft(rotateLeft12 ^ n33, 12);
            n5 = n32 + rotateLeft32;
            rotateLeft7 = Integers.rotateLeft(rotateLeft31 ^ n5, 8);
            n7 = n33 + rotateLeft7;
            rotateLeft = Integers.rotateLeft(rotateLeft32 ^ n7, 7);
        }
        array2[0] = n2 + array[0];
        array2[1] = n3 + array[1];
        array2[2] = n4 + array[2];
        array2[3] = n5 + array[3];
        array2[4] = rotateLeft + array[4];
        array2[5] = rotateLeft2 + array[5];
        array2[6] = rotateLeft3 + array[6];
        array2[7] = rotateLeft4 + array[7];
        array2[8] = n6 + array[8];
        array2[9] = n7 + array[9];
        array2[10] = n8 + array[10];
        array2[11] = n9 + array[11];
        array2[12] = rotateLeft5 + array[12];
        array2[13] = rotateLeft6 + array[13];
        array2[14] = rotateLeft7 + array[14];
        array2[15] = rotateLeft8 + array[15];
    }
}
