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

package org.bouncycastle.crypto.engines;

import org.bouncycastle.crypto.OutputLengthException;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.CryptoServiceProperties;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.constraints.DefaultServiceProperties;
import org.bouncycastle.util.Integers;
import org.bouncycastle.util.Pack;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.BlockCipher;

public class NoekeonEngine implements BlockCipher
{
    private static final int SIZE = 16;
    private static final byte[] roundConstants;
    private final int[] k;
    private boolean _initialised;
    private boolean _forEncryption;
    
    public NoekeonEngine() {
        this.k = new int[4];
        this._initialised = false;
    }
    
    @Override
    public String getAlgorithmName() {
        return "Noekeon";
    }
    
    @Override
    public int getBlockSize() {
        return 16;
    }
    
    @Override
    public void init(final boolean forEncryption, final CipherParameters cipherParameters) {
        if (!(cipherParameters instanceof KeyParameter)) {
            throw new IllegalArgumentException("invalid parameter passed to Noekeon init - " + cipherParameters.getClass().getName());
        }
        final byte[] key = ((KeyParameter)cipherParameters).getKey();
        if (key.length != 16) {
            throw new IllegalArgumentException("Key length not 128 bits.");
        }
        Pack.bigEndianToInt(key, 0, this.k, 0, 4);
        if (!forEncryption) {
            final int n = this.k[0];
            final int n2 = this.k[1];
            final int n3 = this.k[2];
            final int n4 = this.k[3];
            final int n5 = n ^ n3;
            final int n6 = n5 ^ (Integers.rotateLeft(n5, 8) ^ Integers.rotateLeft(n5, 24));
            final int n7 = n2 ^ n4;
            final int n8 = n7 ^ (Integers.rotateLeft(n7, 8) ^ Integers.rotateLeft(n7, 24));
            final int n9 = n ^ n8;
            final int n10 = n2 ^ n6;
            final int n11 = n3 ^ n8;
            final int n12 = n4 ^ n6;
            this.k[0] = n9;
            this.k[1] = n10;
            this.k[2] = n11;
            this.k[3] = n12;
        }
        this._forEncryption = forEncryption;
        this._initialised = true;
        CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties(this.getAlgorithmName(), 128, cipherParameters, Utils.getPurpose(forEncryption)));
    }
    
    @Override
    public int processBlock(final byte[] array, final int n, final byte[] array2, final int n2) {
        if (!this._initialised) {
            throw new IllegalStateException(this.getAlgorithmName() + " not initialised");
        }
        if (n > array.length - 16) {
            throw new DataLengthException("input buffer too short");
        }
        if (n2 > array2.length - 16) {
            throw new OutputLengthException("output buffer too short");
        }
        return this._forEncryption ? this.encryptBlock(array, n, array2, n2) : this.decryptBlock(array, n, array2, n2);
    }
    
    @Override
    public void reset() {
    }
    
    private int encryptBlock(final byte[] array, final int n, final byte[] array2, final int n2) {
        int bigEndianToInt = Pack.bigEndianToInt(array, n);
        int n3 = Pack.bigEndianToInt(array, n + 4);
        int n4 = Pack.bigEndianToInt(array, n + 8);
        int n5 = Pack.bigEndianToInt(array, n + 12);
        final int n6 = this.k[0];
        final int n7 = this.k[1];
        final int n8 = this.k[2];
        final int n9 = this.k[3];
        int n10 = 0;
        int n20;
        int n21;
        int n22;
        int n23;
        while (true) {
            final int n11 = bigEndianToInt ^ (NoekeonEngine.roundConstants[n10] & 0xFF);
            final int n12 = n11 ^ n4;
            final int n13 = n12 ^ (Integers.rotateLeft(n12, 8) ^ Integers.rotateLeft(n12, 24));
            final int n14 = n11 ^ n6;
            final int n15 = n3 ^ n7;
            final int n16 = n4 ^ n8;
            final int n17 = n5 ^ n9;
            final int n18 = n15 ^ n17;
            final int n19 = n18 ^ (Integers.rotateLeft(n18, 8) ^ Integers.rotateLeft(n18, 24));
            n20 = (n14 ^ n19);
            n21 = (n15 ^ n13);
            n22 = (n16 ^ n19);
            n23 = (n17 ^ n13);
            if (++n10 > 16) {
                break;
            }
            final int rotateLeft = Integers.rotateLeft(n21, 1);
            final int rotateLeft2 = Integers.rotateLeft(n22, 5);
            final int rotateLeft3;
            final int n24 = rotateLeft ^ ((rotateLeft3 = Integers.rotateLeft(n23, 2)) | rotateLeft2);
            final int n25 = n20 ^ (rotateLeft2 & ~n24);
            final int n26 = rotateLeft3 ^ ~n24 ^ rotateLeft2 ^ n25;
            final int n27 = n24 ^ (n25 | n26);
            bigEndianToInt = (rotateLeft3 ^ (n26 & n27));
            n3 = Integers.rotateLeft(n27, 31);
            n4 = Integers.rotateLeft(n26, 27);
            n5 = Integers.rotateLeft(n25, 30);
        }
        Pack.intToBigEndian(n20, array2, n2);
        Pack.intToBigEndian(n21, array2, n2 + 4);
        Pack.intToBigEndian(n22, array2, n2 + 8);
        Pack.intToBigEndian(n23, array2, n2 + 12);
        return 16;
    }
    
    private int decryptBlock(final byte[] array, final int n, final byte[] array2, final int n2) {
        int bigEndianToInt = Pack.bigEndianToInt(array, n);
        int n3 = Pack.bigEndianToInt(array, n + 4);
        int n4 = Pack.bigEndianToInt(array, n + 8);
        int n5 = Pack.bigEndianToInt(array, n + 12);
        final int n6 = this.k[0];
        final int n7 = this.k[1];
        final int n8 = this.k[2];
        final int n9 = this.k[3];
        int n10 = 16;
        int n20;
        int n21;
        int n22;
        int n23;
        while (true) {
            final int n11 = bigEndianToInt ^ n4;
            final int n12 = n11 ^ (Integers.rotateLeft(n11, 8) ^ Integers.rotateLeft(n11, 24));
            final int n13 = bigEndianToInt ^ n6;
            final int n14 = n3 ^ n7;
            final int n15 = n4 ^ n8;
            final int n16 = n5 ^ n9;
            final int n17 = n14 ^ n16;
            final int n18 = n17 ^ (Integers.rotateLeft(n17, 8) ^ Integers.rotateLeft(n17, 24));
            final int n19 = n13 ^ n18;
            n20 = (n14 ^ n12);
            n21 = (n15 ^ n18);
            n22 = (n16 ^ n12);
            n23 = (n19 ^ (NoekeonEngine.roundConstants[n10] & 0xFF));
            if (--n10 < 0) {
                break;
            }
            final int rotateLeft = Integers.rotateLeft(n20, 1);
            final int rotateLeft2 = Integers.rotateLeft(n21, 5);
            final int rotateLeft3;
            final int n24 = rotateLeft ^ ((rotateLeft3 = Integers.rotateLeft(n22, 2)) | rotateLeft2);
            final int n25 = n23 ^ (rotateLeft2 & ~n24);
            final int n26 = rotateLeft3 ^ ~n24 ^ rotateLeft2 ^ n25;
            final int n27 = n24 ^ (n25 | n26);
            bigEndianToInt = (rotateLeft3 ^ (n26 & n27));
            n3 = Integers.rotateLeft(n27, 31);
            n4 = Integers.rotateLeft(n26, 27);
            n5 = Integers.rotateLeft(n25, 30);
        }
        Pack.intToBigEndian(n23, array2, n2);
        Pack.intToBigEndian(n20, array2, n2 + 4);
        Pack.intToBigEndian(n21, array2, n2 + 8);
        Pack.intToBigEndian(n22, array2, n2 + 12);
        return 16;
    }
    
    static {
        roundConstants = new byte[] { -128, 27, 54, 108, -40, -85, 77, -102, 47, 94, -68, 99, -58, -105, 53, 106, -44 };
    }
}
