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

package org.bouncycastle.crypto.engines;

import org.bouncycastle.util.Bytes;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.digests.RomulusDigest;
import org.bouncycastle.util.Arrays;

public class RomulusEngine extends AEADBaseEngine
{
    private byte[] k;
    private byte[] npub;
    private static final int AD_BLK_LEN_HALF = 16;
    private Instance instance;
    private final byte[] CNT;
    private static final byte[] sbox_8;
    private static final byte[] TWEAKEY_P;
    private static final byte[] RC;
    
    public RomulusEngine(final RomulusParameters romulusParameters) {
        final int key_SIZE = 16;
        this.AADBufferSize = key_SIZE;
        this.BlockSize = key_SIZE;
        this.MAC_SIZE = key_SIZE;
        this.IV_SIZE = key_SIZE;
        this.KEY_SIZE = key_SIZE;
        this.CNT = new byte[7];
        switch (romulusParameters.ord) {
            case 0: {
                this.algorithmName = "Romulus-M";
                this.instance = new RomulusM();
                break;
            }
            case 1: {
                this.algorithmName = "Romulus-N";
                this.instance = new RomulusN();
                break;
            }
            case 2: {
                this.algorithmName = "Romulus-T";
                this.AADBufferSize = 32;
                this.instance = new RomulusT();
                break;
            }
        }
        this.setInnerMembers((romulusParameters == RomulusParameters.RomulusN) ? ProcessingBufferType.Buffered : ProcessingBufferType.Immediate, AADOperatorType.Counter, (romulusParameters == RomulusParameters.RomulusM) ? DataOperatorType.Stream : DataOperatorType.Counter);
    }
    
    private static void skinny_128_384_plus_enc(final byte[] array, final byte[] array2) {
        final byte[][] array3 = new byte[4][4];
        final byte[][][] array4 = new byte[3][4][4];
        final byte[][][] array5 = new byte[3][4][4];
        for (int i = 0; i < 4; ++i) {
            final int n = i << 2;
            System.arraycopy(array, n, array3[i], 0, 4);
            System.arraycopy(array2, n, array4[0][i], 0, 4);
            System.arraycopy(array2, n + 16, array4[1][i], 0, 4);
            System.arraycopy(array2, n + 32, array4[2][i], 0, 4);
        }
        for (int j = 0; j < 40; ++j) {
            for (int k = 0; k < 4; ++k) {
                for (int l = 0; l < 4; ++l) {
                    array3[k][l] = RomulusEngine.sbox_8[array3[k][l] & 0xFF];
                }
            }
            final byte[] array6 = array3[0];
            final int n2 = 0;
            array6[n2] ^= (byte)(RomulusEngine.RC[j] & 0xF);
            final byte[] array7 = array3[1];
            final int n3 = 0;
            array7[n3] ^= (byte)(RomulusEngine.RC[j] >>> 4 & 0x3);
            final byte[] array8 = array3[2];
            final int n4 = 0;
            array8[n4] ^= 0x2;
            for (int n5 = 0; n5 <= 1; ++n5) {
                for (int n6 = 0; n6 < 4; ++n6) {
                    final byte[] array9 = array3[n5];
                    final int n7 = n6;
                    array9[n7] ^= (byte)(array4[0][n5][n6] ^ array4[1][n5][n6] ^ array4[2][n5][n6]);
                }
            }
            for (int n8 = 0; n8 < 4; ++n8) {
                for (int n9 = 0; n9 < 4; ++n9) {
                    final byte b = RomulusEngine.TWEAKEY_P[n9 + (n8 << 2)];
                    final int n10 = b >>> 2;
                    final int n11 = b & 0x3;
                    array5[0][n8][n9] = array4[0][n10][n11];
                    array5[1][n8][n9] = array4[1][n10][n11];
                    array5[2][n8][n9] = array4[2][n10][n11];
                }
            }
            int n12;
            for (n12 = 0; n12 <= 1; ++n12) {
                for (int n13 = 0; n13 < 4; ++n13) {
                    array4[0][n12][n13] = array5[0][n12][n13];
                    final byte b2 = array5[1][n12][n13];
                    array4[1][n12][n13] = (byte)((b2 << 1 & 0xFE) ^ (b2 >>> 7 & 0x1) ^ (b2 >>> 5 & 0x1));
                    final byte b3 = array5[2][n12][n13];
                    array4[2][n12][n13] = (byte)((b3 >>> 1 & 0x7F) ^ (b3 << 7 & 0x80) ^ (b3 << 1 & 0x80));
                }
            }
            while (n12 < 4) {
                for (int n14 = 0; n14 < 4; ++n14) {
                    array4[0][n12][n14] = array5[0][n12][n14];
                    array4[1][n12][n14] = array5[1][n12][n14];
                    array4[2][n12][n14] = array5[2][n12][n14];
                }
                ++n12;
            }
            final byte b4 = array3[1][3];
            array3[1][3] = array3[1][2];
            array3[1][2] = array3[1][1];
            array3[1][1] = array3[1][0];
            array3[1][0] = b4;
            final byte b5 = array3[2][0];
            array3[2][0] = array3[2][2];
            array3[2][2] = b5;
            final byte b6 = array3[2][1];
            array3[2][1] = array3[2][3];
            array3[2][3] = b6;
            final byte b7 = array3[3][0];
            array3[3][0] = array3[3][1];
            array3[3][1] = array3[3][2];
            array3[3][2] = array3[3][3];
            array3[3][3] = b7;
            for (int n15 = 0; n15 < 4; ++n15) {
                final byte[] array10 = array3[1];
                final int n16 = n15;
                array10[n16] ^= array3[2][n15];
                final byte[] array11 = array3[2];
                final int n17 = n15;
                array11[n17] ^= array3[0][n15];
                final byte[] array12 = array3[3];
                final int n18 = n15;
                array12[n18] ^= array3[2][n15];
                final byte b8 = array3[3][n15];
                array3[3][n15] = array3[2][n15];
                array3[2][n15] = array3[1][n15];
                array3[1][n15] = array3[0][n15];
                array3[0][n15] = b8;
            }
        }
        for (int n19 = 0; n19 < 16; ++n19) {
            array[n19] = (byte)(array3[n19 >>> 2][n19 & 0x3] & 0xFF);
        }
    }
    
    void pad(final byte[] array, final int n, final byte[] array2, final int n2, final int n3) {
        array2[n2 - 1] = (byte)(n3 & 0xF);
        System.arraycopy(array, n, array2, 0, n3);
    }
    
    void g8A(final byte[] array, final byte[] array2, final int n) {
        for (int min = Math.min(array2.length - n, 16), i = 0; i < min; ++i) {
            array2[i + n] = (byte)((array[i] & 0xFF) >>> 1 ^ (array[i] & 0x80) ^ (array[i] & 0x1) << 7);
        }
    }
    
    void rho(final byte[] array, final int n, final byte[] array2, final int n2, final byte[] array3, final int n3) {
        final byte[] array4 = new byte[16];
        this.pad(array, n, array4, 16, n3);
        this.g8A(array3, array2, n2);
        if (this.forEncryption) {
            for (int i = 0; i < 16; ++i) {
                final int n4 = i;
                array3[n4] ^= array4[i];
                if (i < n3) {
                    final int n5 = i + n2;
                    array2[n5] ^= array4[i];
                }
                else {
                    array2[i + n2] = 0;
                }
            }
        }
        else {
            for (int j = 0; j < 16; ++j) {
                final int n6 = j;
                array3[n6] ^= array4[j];
                if (j < n3 && j + n2 < array2.length) {
                    final int n7 = j;
                    array3[n7] ^= array2[j + n2];
                    final int n8 = j + n2;
                    array2[n8] ^= array4[j];
                }
            }
        }
    }
    
    void lfsr_gf56(final byte[] array) {
        final byte b = (byte)((array[6] & 0xFF) >>> 7);
        array[6] = (byte)((array[6] & 0xFF) << 1 | (array[5] & 0xFF) >>> 7);
        array[5] = (byte)((array[5] & 0xFF) << 1 | (array[4] & 0xFF) >>> 7);
        array[4] = (byte)((array[4] & 0xFF) << 1 | (array[3] & 0xFF) >>> 7);
        array[3] = (byte)((array[3] & 0xFF) << 1 | (array[2] & 0xFF) >>> 7);
        array[2] = (byte)((array[2] & 0xFF) << 1 | (array[1] & 0xFF) >>> 7);
        array[1] = (byte)((array[1] & 0xFF) << 1 | (array[0] & 0xFF) >>> 7);
        if (b == 1) {
            array[0] = (byte)((array[0] & 0xFF) << 1 ^ 0x95);
        }
        else {
            array[0] = (byte)((array[0] & 0xFF) << 1);
        }
    }
    
    void block_cipher(final byte[] array, final byte[] array2, final byte[] array3, final int n, final byte[] array4, final byte b) {
        final byte[] array5 = new byte[48];
        System.arraycopy(array4, 0, array5, 0, 7);
        array5[7] = b;
        System.arraycopy(array3, n, array5, 16, 16);
        System.arraycopy(array2, 0, array5, 32, 16);
        skinny_128_384_plus_enc(array, array5);
    }
    
    private void reset_lfsr_gf56(final byte[] array) {
        array[0] = 1;
        Arrays.fill(array, 1, 7, (byte)0);
    }
    
    public static void hirose_128_128_256(final RomulusDigest.Friend friend, final byte[] array, final byte[] array2, final byte[] array3, final int n) {
        if (null == friend) {
            throw new NullPointerException("This method is only for use by RomulusDigest");
        }
        hirose_128_128_256(array, array2, array3, n);
    }
    
    static void hirose_128_128_256(final byte[] array, final byte[] array2, final byte[] array3, final int n) {
        final byte[] array4 = new byte[48];
        final byte[] array5 = new byte[16];
        System.arraycopy(array2, 0, array4, 0, 16);
        System.arraycopy(array, 0, array2, 0, 16);
        System.arraycopy(array, 0, array5, 0, 16);
        final int n2 = 0;
        array2[n2] ^= 0x1;
        System.arraycopy(array3, n, array4, 16, 32);
        skinny_128_384_plus_enc(array, array4);
        skinny_128_384_plus_enc(array2, array4);
        for (int i = 0; i < 16; ++i) {
            final int n3 = i;
            array[n3] ^= array5[i];
            final int n4 = i;
            array2[n4] ^= array5[i];
        }
        final int n5 = 0;
        array2[n5] ^= 0x1;
    }
    
    @Override
    protected void init(final byte[] k, final byte[] npub) throws IllegalArgumentException {
        this.npub = npub;
        this.k = k;
    }
    
    @Override
    protected void finishAAD(final State state, final boolean b) {
        this.finishAAD1(state);
    }
    
    @Override
    protected void processBufferAAD(final byte[] array, final int n) {
        this.instance.processBufferAAD(array, n);
    }
    
    @Override
    protected void processFinalAAD() {
        this.instance.processFinalAAD();
    }
    
    @Override
    protected void processFinalBlock(final byte[] array, final int n) {
        this.instance.processFinalBlock(array, n);
    }
    
    @Override
    protected void processBufferEncrypt(final byte[] array, final int n, final byte[] array2, final int n2) {
        this.instance.processBufferEncrypt(array, n, array2, n2);
    }
    
    @Override
    protected void processBufferDecrypt(final byte[] array, final int n, final byte[] array2, final int n2) {
        this.instance.processBufferDecrypt(array, n, array2, n2);
    }
    
    @Override
    protected void reset(final boolean b) {
        super.reset(b);
        this.instance.reset();
    }
    
    static {
        sbox_8 = new byte[] { 101, 76, 106, 66, 75, 99, 67, 107, 85, 117, 90, 122, 83, 115, 91, 123, 53, -116, 58, -127, -119, 51, -128, 59, -107, 37, -104, 42, -112, 35, -103, 43, -27, -52, -24, -63, -55, -32, -64, -23, -43, -11, -40, -8, -48, -16, -39, -7, -91, 28, -88, 18, 27, -96, 19, -87, 5, -75, 10, -72, 3, -80, 11, -71, 50, -120, 60, -123, -115, 52, -124, 61, -111, 34, -100, 44, -108, 36, -99, 45, 98, 74, 108, 69, 77, 100, 68, 109, 82, 114, 92, 124, 84, 116, 93, 125, -95, 26, -84, 21, 29, -92, 20, -83, 2, -79, 12, -68, 4, -76, 13, -67, -31, -56, -20, -59, -51, -28, -60, -19, -47, -15, -36, -4, -44, -12, -35, -3, 54, -114, 56, -126, -117, 48, -125, 57, -106, 38, -102, 40, -109, 32, -101, 41, 102, 78, 104, 65, 73, 96, 64, 105, 86, 118, 88, 120, 80, 112, 89, 121, -90, 30, -86, 17, 25, -93, 16, -85, 6, -74, 8, -70, 0, -77, 9, -69, -26, -50, -22, -62, -53, -29, -61, -21, -42, -10, -38, -6, -45, -13, -37, -5, 49, -118, 62, -122, -113, 55, -121, 63, -110, 33, -98, 46, -105, 39, -97, 47, 97, 72, 110, 70, 79, 103, 71, 111, 81, 113, 94, 126, 87, 119, 95, 127, -94, 24, -82, 22, 31, -89, 23, -81, 1, -78, 14, -66, 7, -73, 15, -65, -30, -54, -18, -58, -49, -25, -57, -17, -46, -14, -34, -2, -41, -9, -33, -1 };
        TWEAKEY_P = new byte[] { 9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7 };
        RC = new byte[] { 1, 3, 7, 15, 31, 62, 61, 59, 55, 47, 30, 60, 57, 51, 39, 14, 29, 58, 53, 43, 22, 44, 24, 48, 33, 2, 5, 11, 23, 46, 28, 56, 49, 35, 6, 13, 27, 54, 45, 26 };
    }
    
    private interface Instance
    {
        void processFinalBlock(final byte[] p0, final int p1);
        
        void processBufferAAD(final byte[] p0, final int p1);
        
        void processFinalAAD();
        
        void processBufferEncrypt(final byte[] p0, final int p1, final byte[] p2, final int p3);
        
        void processBufferDecrypt(final byte[] p0, final int p1, final byte[] p2, final int p3);
        
        void reset();
    }
    
    private class RomulusM implements Instance
    {
        private final byte[] mac_s;
        private final byte[] mac_CNT;
        private final byte[] s;
        private int offset;
        private boolean twist;
        
        public RomulusM() {
            this.mac_s = new byte[16];
            this.mac_CNT = new byte[7];
            this.s = new byte[16];
            this.twist = true;
        }
        
        @Override
        public void processFinalBlock(final byte[] array, int n) {
            byte b = 48;
            final int len = RomulusEngine.this.aadOperator.getLen();
            int i = RomulusEngine.this.dataOperator.getLen() - (RomulusEngine.this.forEncryption ? 0 : RomulusEngine.this.MAC_SIZE);
            final byte[] bytes = ((StreamDataOperator)RomulusEngine.this.dataOperator).getBytes();
            int offset = 0;
            int offset2 = n;
            int j = i;
            if ((len & 0x1F) == 0x0 && len != 0) {
                b ^= 0x8;
            }
            else if ((len & 0x1F) < 16) {
                b ^= 0x2;
            }
            else if ((len & 0x1F) != 0x10) {
                b ^= 0xA;
            }
            if ((i & 0x1F) == 0x0 && i != 0) {
                b ^= 0x4;
            }
            else if ((i & 0x1F) < 16) {
                b ^= 0x1;
            }
            else if ((i & 0x1F) != 0x10) {
                b ^= 0x5;
            }
            if (RomulusEngine.this.forEncryption) {
                if ((b & 0x8) == 0x0) {
                    final byte[] array2 = new byte[16];
                    final int min = Math.min(j, 16);
                    j -= min;
                    RomulusEngine.this.pad(bytes, offset, array2, 16, min);
                    RomulusEngine.this.block_cipher(this.mac_s, RomulusEngine.this.k, array2, 0, this.mac_CNT, (byte)44);
                    RomulusEngine.this.lfsr_gf56(this.mac_CNT);
                    offset += min;
                }
                else if (i == 0) {
                    RomulusEngine.this.lfsr_gf56(this.mac_CNT);
                }
                while (j > 0) {
                    this.offset = offset;
                    j = this.ad_encryption(bytes, offset, this.mac_s, RomulusEngine.this.k, j, this.mac_CNT);
                    offset = this.offset;
                }
                RomulusEngine.this.block_cipher(this.mac_s, RomulusEngine.this.k, RomulusEngine.this.npub, 0, this.mac_CNT, b);
                RomulusEngine.this.g8A(this.mac_s, RomulusEngine.this.mac, 0);
                offset -= i;
            }
            else {
                System.arraycopy(bytes, i, RomulusEngine.this.mac, 0, RomulusEngine.this.MAC_SIZE);
            }
            RomulusEngine.this.reset_lfsr_gf56(RomulusEngine.this.CNT);
            System.arraycopy(RomulusEngine.this.mac, 0, this.s, 0, 16);
            if (i > 0) {
                RomulusEngine.this.block_cipher(this.s, RomulusEngine.this.k, RomulusEngine.this.npub, 0, RomulusEngine.this.CNT, (byte)36);
                while (i > 16) {
                    i -= 16;
                    RomulusEngine.this.rho(bytes, offset, array, n, this.s, 16);
                    n += 16;
                    offset += 16;
                    RomulusEngine.this.lfsr_gf56(RomulusEngine.this.CNT);
                    RomulusEngine.this.block_cipher(this.s, RomulusEngine.this.k, RomulusEngine.this.npub, 0, RomulusEngine.this.CNT, (byte)36);
                }
                RomulusEngine.this.rho(bytes, offset, array, n, this.s, i);
            }
            if (!RomulusEngine.this.forEncryption) {
                if ((b & 0x8) == 0x0) {
                    final byte[] array3 = new byte[16];
                    final int min2 = Math.min(j, 16);
                    j -= min2;
                    RomulusEngine.this.pad(array, offset2, array3, 16, min2);
                    RomulusEngine.this.block_cipher(this.mac_s, RomulusEngine.this.k, array3, 0, this.mac_CNT, (byte)44);
                    RomulusEngine.this.lfsr_gf56(this.mac_CNT);
                    offset2 += min2;
                }
                else if (i == 0) {
                    RomulusEngine.this.lfsr_gf56(this.mac_CNT);
                }
                while (j > 0) {
                    this.offset = offset2;
                    j = this.ad_encryption(array, offset2, this.mac_s, RomulusEngine.this.k, j, this.mac_CNT);
                    offset2 = this.offset;
                }
                RomulusEngine.this.block_cipher(this.mac_s, RomulusEngine.this.k, RomulusEngine.this.npub, 0, this.mac_CNT, b);
                RomulusEngine.this.g8A(this.mac_s, RomulusEngine.this.mac, 0);
                System.arraycopy(bytes, RomulusEngine.this.dataOperator.getLen() - RomulusEngine.this.MAC_SIZE, RomulusEngine.this.m_buf, 0, RomulusEngine.this.MAC_SIZE);
                RomulusEngine.this.m_bufPos = 0;
            }
        }
        
        int ad_encryption(final byte[] array, int n, final byte[] array2, final byte[] array3, int n2, final byte[] array4) {
            final byte[] array5 = new byte[16];
            final byte[] array6 = new byte[16];
            final int n3 = 16;
            final int min = Math.min(n2, n3);
            n2 -= min;
            RomulusEngine.this.pad(array, n, array6, n3, min);
            Bytes.xorTo(n3, array6, array2);
            n = (this.offset = n + min);
            RomulusEngine.this.lfsr_gf56(array4);
            if (n2 != 0) {
                final int min2 = Math.min(n2, n3);
                n2 -= min2;
                RomulusEngine.this.pad(array, n, array5, n3, min2);
                this.offset = n + min2;
                RomulusEngine.this.block_cipher(array2, array3, array5, 0, array4, (byte)44);
                RomulusEngine.this.lfsr_gf56(array4);
            }
            return n2;
        }
        
        @Override
        public void processBufferAAD(final byte[] array, final int n) {
            if (this.twist) {
                Bytes.xorTo(RomulusEngine.this.MAC_SIZE, array, n, this.mac_s);
            }
            else {
                RomulusEngine.this.block_cipher(this.mac_s, RomulusEngine.this.k, array, n, this.mac_CNT, (byte)40);
            }
            this.twist = !this.twist;
            RomulusEngine.this.lfsr_gf56(this.mac_CNT);
        }
        
        @Override
        public void processFinalAAD() {
            if (RomulusEngine.this.aadOperator.getLen() == 0) {
                RomulusEngine.this.lfsr_gf56(this.mac_CNT);
            }
            else if (RomulusEngine.this.m_aadPos != 0) {
                Arrays.fill(RomulusEngine.this.m_aad, RomulusEngine.this.m_aadPos, RomulusEngine.this.BlockSize - 1, (byte)0);
                RomulusEngine.this.m_aad[RomulusEngine.this.BlockSize - 1] = (byte)(RomulusEngine.this.m_aadPos & 0xF);
                if (this.twist) {
                    Bytes.xorTo(RomulusEngine.this.BlockSize, RomulusEngine.this.m_aad, this.mac_s);
                }
                else {
                    RomulusEngine.this.block_cipher(this.mac_s, RomulusEngine.this.k, RomulusEngine.this.m_aad, 0, this.mac_CNT, (byte)40);
                }
                RomulusEngine.this.lfsr_gf56(this.mac_CNT);
            }
            RomulusEngine.this.m_aadPos = 0;
            RomulusEngine.this.m_bufPos = RomulusEngine.this.dataOperator.getLen();
        }
        
        @Override
        public void processBufferEncrypt(final byte[] array, final int n, final byte[] array2, final int n2) {
        }
        
        @Override
        public void processBufferDecrypt(final byte[] array, final int n, final byte[] array2, final int n2) {
        }
        
        @Override
        public void reset() {
            Arrays.clear(this.s);
            Arrays.clear(this.mac_s);
            RomulusEngine.this.reset_lfsr_gf56(this.mac_CNT);
            RomulusEngine.this.reset_lfsr_gf56(RomulusEngine.this.CNT);
            this.twist = true;
        }
    }
    
    private class RomulusN implements Instance
    {
        private final byte[] s;
        boolean twist;
        
        public RomulusN() {
            this.s = new byte[16];
        }
        
        @Override
        public void processFinalBlock(final byte[] array, final int n) {
            if (RomulusEngine.this.dataOperator.getLen() - (RomulusEngine.this.forEncryption ? 0 : RomulusEngine.this.MAC_SIZE) == 0) {
                RomulusEngine.this.lfsr_gf56(RomulusEngine.this.CNT);
                RomulusEngine.this.block_cipher(this.s, RomulusEngine.this.k, RomulusEngine.this.npub, 0, RomulusEngine.this.CNT, (byte)21);
            }
            else if (RomulusEngine.this.m_bufPos != 0) {
                RomulusEngine.this.rho(RomulusEngine.this.m_buf, 0, array, n, this.s, Math.min(RomulusEngine.this.m_bufPos, 16));
                RomulusEngine.this.lfsr_gf56(RomulusEngine.this.CNT);
                RomulusEngine.this.block_cipher(this.s, RomulusEngine.this.k, RomulusEngine.this.npub, 0, RomulusEngine.this.CNT, (byte)((RomulusEngine.this.m_bufPos == 16) ? 20 : 21));
            }
            RomulusEngine.this.g8A(this.s, RomulusEngine.this.mac, 0);
        }
        
        @Override
        public void processBufferAAD(final byte[] array, final int n) {
            if (this.twist) {
                Bytes.xorTo(16, array, n, this.s);
            }
            else {
                RomulusEngine.this.block_cipher(this.s, RomulusEngine.this.k, array, n, RomulusEngine.this.CNT, (byte)8);
            }
            RomulusEngine.this.lfsr_gf56(RomulusEngine.this.CNT);
            this.twist = !this.twist;
        }
        
        @Override
        public void processFinalAAD() {
            if (RomulusEngine.this.m_aadPos != 0) {
                final byte[] array = new byte[16];
                RomulusEngine.this.pad(RomulusEngine.this.m_aad, 0, array, 16, Math.min(RomulusEngine.this.m_aadPos, 16));
                if (this.twist) {
                    Bytes.xorTo(16, array, this.s);
                }
                else {
                    RomulusEngine.this.block_cipher(this.s, RomulusEngine.this.k, array, 0, RomulusEngine.this.CNT, (byte)8);
                }
                RomulusEngine.this.lfsr_gf56(RomulusEngine.this.CNT);
            }
            if (RomulusEngine.this.aadOperator.getLen() == 0) {
                RomulusEngine.this.lfsr_gf56(RomulusEngine.this.CNT);
                RomulusEngine.this.block_cipher(this.s, RomulusEngine.this.k, RomulusEngine.this.npub, 0, RomulusEngine.this.CNT, (byte)26);
            }
            else if ((RomulusEngine.this.m_aadPos & 0xF) != 0x0) {
                RomulusEngine.this.block_cipher(this.s, RomulusEngine.this.k, RomulusEngine.this.npub, 0, RomulusEngine.this.CNT, (byte)26);
            }
            else {
                RomulusEngine.this.block_cipher(this.s, RomulusEngine.this.k, RomulusEngine.this.npub, 0, RomulusEngine.this.CNT, (byte)24);
            }
            RomulusEngine.this.reset_lfsr_gf56(RomulusEngine.this.CNT);
        }
        
        @Override
        public void processBufferEncrypt(final byte[] array, final int n, final byte[] array2, final int n2) {
            RomulusEngine.this.g8A(this.s, array2, n2);
            for (int i = 0; i < 16; ++i) {
                final byte[] s = this.s;
                final int n3 = i;
                s[n3] ^= array[i + n];
                final int n4 = i + n2;
                array2[n4] ^= array[i + n];
            }
            RomulusEngine.this.lfsr_gf56(RomulusEngine.this.CNT);
            RomulusEngine.this.block_cipher(this.s, RomulusEngine.this.k, RomulusEngine.this.npub, 0, RomulusEngine.this.CNT, (byte)4);
        }
        
        @Override
        public void processBufferDecrypt(final byte[] array, final int n, final byte[] array2, final int n2) {
            RomulusEngine.this.g8A(this.s, array2, n2);
            for (int i = 0; i < 16; ++i) {
                final int n3 = i + n2;
                array2[n3] ^= array[i + n];
                final byte[] s = this.s;
                final int n4 = i;
                s[n4] ^= array2[i + n2];
            }
            RomulusEngine.this.lfsr_gf56(RomulusEngine.this.CNT);
            RomulusEngine.this.block_cipher(this.s, RomulusEngine.this.k, RomulusEngine.this.npub, 0, RomulusEngine.this.CNT, (byte)4);
        }
        
        @Override
        public void reset() {
            Arrays.clear(this.s);
            RomulusEngine.this.reset_lfsr_gf56(RomulusEngine.this.CNT);
            this.twist = true;
        }
    }
    
    public static class RomulusParameters
    {
        public static final int ROMULUS_M = 0;
        public static final int ROMULUS_N = 1;
        public static final int ROMULUS_T = 2;
        public static final RomulusParameters RomulusM;
        public static final RomulusParameters RomulusN;
        public static final RomulusParameters RomulusT;
        private final int ord;
        
        RomulusParameters(final int ord) {
            this.ord = ord;
        }
        
        static {
            RomulusM = new RomulusParameters(0);
            RomulusN = new RomulusParameters(1);
            RomulusT = new RomulusParameters(2);
        }
    }
    
    private class RomulusT implements Instance
    {
        private final byte[] h;
        private final byte[] g;
        byte[] Z;
        byte[] CNT_Z;
        byte[] LR;
        byte[] T;
        byte[] S;
        
        private RomulusT() {
            this.h = new byte[16];
            this.g = new byte[16];
            this.Z = new byte[16];
            this.CNT_Z = new byte[7];
            this.LR = new byte[32];
            this.T = new byte[16];
            this.S = new byte[16];
        }
        
        @Override
        public void processFinalBlock(final byte[] array, final int n) {
            int n2 = 16;
            final int n3 = RomulusEngine.this.dataOperator.getLen() - (RomulusEngine.this.forEncryption ? 0 : RomulusEngine.this.MAC_SIZE);
            if (RomulusEngine.this.m_bufPos != 0) {
                final int min = Math.min(RomulusEngine.this.m_bufPos, 16);
                System.arraycopy(RomulusEngine.this.npub, 0, this.S, 0, 16);
                RomulusEngine.this.block_cipher(this.S, this.Z, this.T, 0, RomulusEngine.this.CNT, (byte)64);
                Bytes.xor(min, RomulusEngine.this.m_buf, this.S, array, n);
                System.arraycopy(RomulusEngine.this.npub, 0, this.S, 0, 16);
                RomulusEngine.this.lfsr_gf56(RomulusEngine.this.CNT);
                byte[] buf;
                int n4;
                if (RomulusEngine.this.forEncryption) {
                    buf = array;
                    n4 = n;
                }
                else {
                    buf = RomulusEngine.this.m_buf;
                    n4 = 0;
                }
                System.arraycopy(buf, n4, RomulusEngine.this.m_aad, RomulusEngine.this.m_aadPos, RomulusEngine.this.m_bufPos);
                Arrays.fill(RomulusEngine.this.m_aad, RomulusEngine.this.m_aadPos + RomulusEngine.this.m_bufPos, RomulusEngine.this.AADBufferSize - 1, (byte)0);
                RomulusEngine.this.m_aad[RomulusEngine.this.m_aadPos + RomulusEngine.this.BlockSize - 1] = (byte)(RomulusEngine.this.m_bufPos & 0xF);
                if (RomulusEngine.this.m_aadPos == 0) {
                    System.arraycopy(RomulusEngine.this.npub, 0, RomulusEngine.this.m_aad, RomulusEngine.this.BlockSize, RomulusEngine.this.BlockSize);
                    n2 = 0;
                }
                RomulusEngine.hirose_128_128_256(this.h, this.g, RomulusEngine.this.m_aad, 0);
                RomulusEngine.this.lfsr_gf56(this.CNT_Z);
            }
            else if (RomulusEngine.this.m_aadPos != 0) {
                if (n3 > 0) {
                    Arrays.fill(RomulusEngine.this.m_aad, RomulusEngine.this.BlockSize, RomulusEngine.this.AADBufferSize, (byte)0);
                }
                else if (RomulusEngine.this.aadOperator.getLen() != 0) {
                    System.arraycopy(RomulusEngine.this.npub, 0, RomulusEngine.this.m_aad, RomulusEngine.this.m_aadPos, 16);
                    n2 = 0;
                    RomulusEngine.this.m_aadPos = 0;
                }
                RomulusEngine.hirose_128_128_256(this.h, this.g, RomulusEngine.this.m_aad, 0);
            }
            else if (n3 > 0) {
                Arrays.fill(RomulusEngine.this.m_aad, 0, RomulusEngine.this.BlockSize, (byte)0);
                System.arraycopy(RomulusEngine.this.npub, 0, RomulusEngine.this.m_aad, RomulusEngine.this.BlockSize, RomulusEngine.this.BlockSize);
                n2 = 0;
                RomulusEngine.hirose_128_128_256(this.h, this.g, RomulusEngine.this.m_aad, 0);
            }
            if (n2 == 16) {
                System.arraycopy(RomulusEngine.this.npub, 0, RomulusEngine.this.m_aad, 0, 16);
                System.arraycopy(RomulusEngine.this.CNT, 0, RomulusEngine.this.m_aad, 16, 7);
                Arrays.fill(RomulusEngine.this.m_aad, 23, 31, (byte)0);
                RomulusEngine.this.m_aad[31] = 23;
            }
            else {
                System.arraycopy(this.CNT_Z, 0, RomulusEngine.this.m_aad, 0, 7);
                Arrays.fill(RomulusEngine.this.m_aad, 7, 31, (byte)0);
                RomulusEngine.this.m_aad[31] = 7;
            }
            final byte[] h = this.h;
            final int n5 = 0;
            h[n5] ^= 0x2;
            RomulusEngine.hirose_128_128_256(this.h, this.g, RomulusEngine.this.m_aad, 0);
            System.arraycopy(this.h, 0, this.LR, 0, 16);
            System.arraycopy(this.g, 0, this.LR, 16, 16);
            Arrays.clear(this.CNT_Z);
            RomulusEngine.this.block_cipher(this.LR, RomulusEngine.this.k, this.LR, 16, this.CNT_Z, (byte)68);
            System.arraycopy(this.LR, 0, RomulusEngine.this.mac, 0, RomulusEngine.this.MAC_SIZE);
        }
        
        @Override
        public void processBufferAAD(final byte[] array, final int n) {
            RomulusEngine.hirose_128_128_256(this.h, this.g, array, n);
        }
        
        @Override
        public void processFinalAAD() {
            Arrays.fill(RomulusEngine.this.m_aad, RomulusEngine.this.m_aadPos, RomulusEngine.this.AADBufferSize - 1, (byte)0);
            if (RomulusEngine.this.m_aadPos >= 16) {
                RomulusEngine.this.m_aad[RomulusEngine.this.AADBufferSize - 1] = (byte)(RomulusEngine.this.m_aadPos & 0xF);
                RomulusEngine.hirose_128_128_256(this.h, this.g, RomulusEngine.this.m_aad, 0);
                RomulusEngine.this.m_aadPos = 0;
            }
            else if (RomulusEngine.this.m_aadPos >= 0 && RomulusEngine.this.aadOperator.getLen() != 0) {
                RomulusEngine.this.m_aad[RomulusEngine.this.BlockSize - 1] = (byte)(RomulusEngine.this.m_aadPos & 0xF);
                RomulusEngine.this.m_aadPos = RomulusEngine.this.BlockSize;
            }
        }
        
        private void processBuffer(final byte[] array, final int n, final byte[] array2, final int n2) {
            System.arraycopy(RomulusEngine.this.npub, 0, this.S, 0, 16);
            RomulusEngine.this.block_cipher(this.S, this.Z, this.T, 0, RomulusEngine.this.CNT, (byte)64);
            Bytes.xor(16, this.S, array, n, array2, n2);
            System.arraycopy(RomulusEngine.this.npub, 0, this.S, 0, 16);
            RomulusEngine.this.block_cipher(this.S, this.Z, this.T, 0, RomulusEngine.this.CNT, (byte)65);
            System.arraycopy(this.S, 0, this.Z, 0, 16);
            RomulusEngine.this.lfsr_gf56(RomulusEngine.this.CNT);
        }
        
        private void processAfterAbsorbCiphertext() {
            if (RomulusEngine.this.m_aadPos == RomulusEngine.this.BlockSize) {
                RomulusEngine.hirose_128_128_256(this.h, this.g, RomulusEngine.this.m_aad, 0);
                RomulusEngine.this.m_aadPos = 0;
            }
            else {
                RomulusEngine.this.m_aadPos = RomulusEngine.this.BlockSize;
            }
            RomulusEngine.this.lfsr_gf56(this.CNT_Z);
        }
        
        @Override
        public void processBufferEncrypt(final byte[] array, final int n, final byte[] array2, final int n2) {
            this.processBuffer(array, n, array2, n2);
            System.arraycopy(array2, n2, RomulusEngine.this.m_aad, RomulusEngine.this.m_aadPos, RomulusEngine.this.BlockSize);
            this.processAfterAbsorbCiphertext();
        }
        
        @Override
        public void processBufferDecrypt(final byte[] array, final int n, final byte[] array2, final int n2) {
            this.processBuffer(array, n, array2, n2);
            System.arraycopy(array, n, RomulusEngine.this.m_aad, RomulusEngine.this.m_aadPos, RomulusEngine.this.BlockSize);
            this.processAfterAbsorbCiphertext();
        }
        
        @Override
        public void reset() {
            Arrays.clear(this.h);
            Arrays.clear(this.g);
            Arrays.clear(this.LR);
            Arrays.clear(this.T);
            Arrays.clear(this.S);
            Arrays.clear(this.CNT_Z);
            RomulusEngine.this.reset_lfsr_gf56(RomulusEngine.this.CNT);
            System.arraycopy(RomulusEngine.this.npub, 0, this.Z, 0, RomulusEngine.this.IV_SIZE);
            RomulusEngine.this.block_cipher(this.Z, RomulusEngine.this.k, this.T, 0, this.CNT_Z, (byte)66);
            RomulusEngine.this.reset_lfsr_gf56(this.CNT_Z);
        }
    }
}
