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

package org.bouncycastle.crypto.engines;

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

public abstract class SerpentEngineBase implements BlockCipher
{
    protected static final int BLOCK_SIZE = 16;
    static final int ROUNDS = 32;
    static final int PHI = -1640531527;
    protected boolean encrypting;
    protected int[] wKey;
    protected int keyBits;
    
    SerpentEngineBase() {
        CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties(this.getAlgorithmName(), 256));
    }
    
    @Override
    public void init(final boolean encrypting, final CipherParameters cipherParameters) {
        if (cipherParameters instanceof KeyParameter) {
            this.encrypting = encrypting;
            final byte[] key = ((KeyParameter)cipherParameters).getKey();
            this.wKey = this.makeWorkingKey(key);
            CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties(this.getAlgorithmName(), key.length * 8, cipherParameters, this.getPurpose()));
            return;
        }
        throw new IllegalArgumentException("invalid parameter passed to " + this.getAlgorithmName() + " init - " + cipherParameters.getClass().getName());
    }
    
    @Override
    public String getAlgorithmName() {
        return "Serpent";
    }
    
    @Override
    public int getBlockSize() {
        return 16;
    }
    
    @Override
    public final int processBlock(final byte[] array, final int n, final byte[] array2, final int n2) {
        if (this.wKey == null) {
            throw new IllegalStateException(this.getAlgorithmName() + " not initialised");
        }
        if (n + 16 > array.length) {
            throw new DataLengthException("input buffer too short");
        }
        if (n2 + 16 > array2.length) {
            throw new OutputLengthException("output buffer too short");
        }
        if (this.encrypting) {
            this.encryptBlock(array, n, array2, n2);
        }
        else {
            this.decryptBlock(array, n, array2, n2);
        }
        return 16;
    }
    
    @Override
    public void reset() {
    }
    
    protected static int rotateLeft(final int n, final int n2) {
        return n << n2 | n >>> -n2;
    }
    
    protected static int rotateRight(final int n, final int n2) {
        return n >>> n2 | n << -n2;
    }
    
    protected final void sb0(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = n ^ n4;
        final int n6 = n3 ^ n5;
        final int n7 = n2 ^ n6;
        array[3] = ((n & n4) ^ n7);
        final int n8 = n ^ (n2 & n5);
        array[2] = (n7 ^ (n3 | n8));
        final int n9 = array[3] & (n6 ^ n8);
        array[1] = (~n6 ^ n9);
        array[0] = (n9 ^ ~n8);
    }
    
    protected final void ib0(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = ~n;
        final int n6 = n ^ n2;
        final int n7 = n4 ^ (n5 | n6);
        final int n8 = n3 ^ n7;
        array[2] = (n6 ^ n8);
        final int n9 = n5 ^ (n4 & n6);
        array[1] = (n7 ^ (array[2] & n9));
        array[3] = ((n & n7) ^ (n8 | array[1]));
        array[0] = (array[3] ^ (n8 ^ n9));
    }
    
    protected final void sb1(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = n2 ^ ~n;
        final int n6 = n3 ^ (n | n5);
        array[2] = (n4 ^ n6);
        final int n7 = n2 ^ (n4 | n5);
        final int n8 = n5 ^ array[2];
        array[3] = (n8 ^ (n6 & n7));
        final int n9 = n6 ^ n7;
        array[1] = (array[3] ^ n9);
        array[0] = (n6 ^ (n8 & n9));
    }
    
    protected final void ib1(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = n2 ^ n4;
        final int n6 = n ^ (n2 & n5);
        final int n7 = n5 ^ n6;
        array[3] = (n3 ^ n7);
        final int n8 = n2 ^ (n5 & n6);
        array[1] = (n6 ^ (array[3] | n8));
        final int n9 = ~array[1];
        final int n10 = array[3] ^ n8;
        array[0] = (n9 ^ n10);
        array[2] = (n7 ^ (n9 | n10));
    }
    
    protected final void sb2(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = ~n;
        final int n6 = n2 ^ n4;
        array[0] = (n6 ^ (n3 & n5));
        final int n7 = n3 ^ n5;
        final int n8 = n2 & (n3 ^ array[0]);
        array[3] = (n7 ^ n8);
        array[2] = (n ^ ((n4 | n8) & (array[0] | n7)));
        array[1] = (n6 ^ array[3] ^ (array[2] ^ (n4 | n5)));
    }
    
    protected final void ib2(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = n2 ^ n4;
        final int n6 = ~n5;
        final int n7 = n ^ n3;
        final int n8 = n3 ^ n5;
        array[0] = (n7 ^ (n2 & n8));
        array[3] = (n5 ^ (n7 | (n4 ^ (n | n6))));
        final int n9 = ~n8;
        final int n10 = array[0] | array[3];
        array[1] = (n9 ^ n10);
        array[2] = ((n4 & n9) ^ (n7 ^ n10));
    }
    
    protected final void sb3(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = n ^ n2;
        final int n6 = n & n3;
        final int n7 = n | n4;
        final int n8 = n3 ^ n4;
        final int n9 = n6 | (n5 & n7);
        array[2] = (n8 ^ n9);
        final int n10 = n9 ^ (n2 ^ n7);
        array[0] = (n5 ^ (n8 & n10));
        final int n11 = array[2] & array[0];
        array[1] = (n10 ^ n11);
        array[3] = ((n2 | n4) ^ (n8 ^ n11));
    }
    
    protected final void ib3(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = n | n2;
        final int n6 = n2 ^ n3;
        final int n7 = n ^ (n2 & n6);
        final int n8 = n3 ^ n7;
        final int n9 = n4 | n7;
        array[0] = (n6 ^ n9);
        final int n10 = n4 ^ (n6 | n9);
        array[2] = (n8 ^ n10);
        final int n11 = n5 ^ n10;
        array[3] = (n7 ^ (array[0] & n11));
        array[1] = (array[3] ^ (array[0] ^ n11));
    }
    
    protected final void sb4(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = n ^ n4;
        final int n6 = n3 ^ (n4 & n5);
        final int n7 = n2 | n6;
        array[3] = (n5 ^ n7);
        final int n8 = ~n2;
        array[0] = (n6 ^ (n5 | n8));
        final int n9 = n & array[0];
        final int n10 = n5 ^ n8;
        array[2] = (n9 ^ (n7 & n10));
        array[1] = (n ^ n6 ^ (n10 & array[2]));
    }
    
    protected final void ib4(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = n2 ^ (n & (n3 | n4));
        final int n6 = n3 ^ (n & n5);
        array[1] = (n4 ^ n6);
        final int n7 = ~n;
        array[3] = (n5 ^ (n6 & array[1]));
        final int n8 = n4 ^ (array[1] | n7);
        array[0] = (array[3] ^ n8);
        array[2] = ((n5 & n8) ^ (array[1] ^ n7));
    }
    
    protected final void sb5(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = ~n;
        final int n6 = n ^ n2;
        final int n7 = n ^ n4;
        array[0] = (n3 ^ n5 ^ (n6 | n7));
        final int n8 = n4 & array[0];
        array[1] = (n8 ^ (n6 ^ array[0]));
        final int n9 = n5 | array[0];
        final int n10 = n6 | n8;
        final int n11 = n7 ^ n9;
        array[2] = (n10 ^ n11);
        array[3] = (n2 ^ n8 ^ (array[1] & n11));
    }
    
    protected final void ib5(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = ~n3;
        final int n6 = n4 ^ (n2 & n5);
        final int n7 = n & n6;
        array[3] = (n7 ^ (n2 ^ n5));
        final int n8 = n2 | array[3];
        array[1] = (n6 ^ (n & n8));
        final int n9 = n | n4;
        array[0] = (n9 ^ (n5 ^ n8));
        array[2] = ((n2 & n9) ^ (n7 | (n ^ n3)));
    }
    
    protected final void sb6(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = ~n;
        final int n6 = n ^ n4;
        final int n7 = n2 ^ n6;
        final int n8 = n3 ^ (n5 | n6);
        array[1] = (n2 ^ n8);
        final int n9 = n4 ^ (n6 | array[1]);
        array[2] = (n7 ^ (n8 & n9));
        final int n10 = n8 ^ n9;
        array[0] = (array[2] ^ n10);
        array[3] = (~n8 ^ (n7 & n10));
    }
    
    protected final void ib6(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = ~n;
        final int n6 = n ^ n2;
        final int n7 = n3 ^ n6;
        final int n8 = n4 ^ (n3 | n5);
        array[1] = (n7 ^ n8);
        final int n9 = n6 ^ (n7 & n8);
        array[3] = (n8 ^ (n2 | n9));
        final int n10 = n2 | array[3];
        array[0] = (n9 ^ n10);
        array[2] = ((n4 & n5) ^ (n7 ^ n10));
    }
    
    protected final void sb7(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = n2 ^ n3;
        final int n6 = n4 ^ (n3 & n5);
        final int n7 = n ^ n6;
        array[1] = (n2 ^ (n7 & (n4 | n5)));
        final int n8 = n6 | array[1];
        array[3] = (n5 ^ (n & n7));
        final int n9 = n7 ^ n8;
        array[2] = (n6 ^ (array[3] & n9));
        array[0] = (~n9 ^ (array[3] & array[2]));
    }
    
    protected final void ib7(final int[] array, final int n, final int n2, final int n3, final int n4) {
        final int n5 = n3 | (n & n2);
        final int n6 = n4 & (n | n2);
        array[3] = (n5 ^ n6);
        final int n7 = ~n4;
        final int n8 = n2 ^ n6;
        array[1] = (n ^ (n8 | (array[3] ^ n7)));
        array[0] = (n3 ^ n8 ^ (n4 | array[1]));
        array[2] = (n5 ^ array[1] ^ (array[0] ^ (n & array[3])));
    }
    
    protected final void LT(final int[] array) {
        final int rotateLeft = rotateLeft(array[0], 13);
        final int rotateLeft2 = rotateLeft(array[2], 3);
        final int n = array[1] ^ rotateLeft ^ rotateLeft2;
        final int n2 = array[3] ^ rotateLeft2 ^ rotateLeft << 3;
        array[1] = rotateLeft(n, 1);
        array[3] = rotateLeft(n2, 7);
        array[0] = rotateLeft(rotateLeft ^ array[1] ^ array[3], 5);
        array[2] = rotateLeft(rotateLeft2 ^ array[3] ^ array[1] << 7, 22);
    }
    
    protected final void inverseLT(final int[] array) {
        final int n = rotateRight(array[2], 22) ^ array[3] ^ array[1] << 7;
        final int n2 = rotateRight(array[0], 5) ^ array[1] ^ array[3];
        final int rotateRight = rotateRight(array[3], 7);
        final int rotateRight2 = rotateRight(array[1], 1);
        array[3] = (rotateRight ^ n ^ n2 << 3);
        array[1] = (rotateRight2 ^ n2 ^ n);
        array[2] = rotateRight(n, 3);
        array[0] = rotateRight(n2, 13);
    }
    
    protected abstract int[] makeWorkingKey(final byte[] p0);
    
    protected abstract void encryptBlock(final byte[] p0, final int p1, final byte[] p2, final int p3);
    
    protected abstract void decryptBlock(final byte[] p0, final int p1, final byte[] p2, final int p3);
    
    private CryptoServicePurpose getPurpose() {
        if (this.wKey == null) {
            return CryptoServicePurpose.ANY;
        }
        return this.encrypting ? CryptoServicePurpose.ENCRYPTION : CryptoServicePurpose.DECRYPTION;
    }
}
