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

package org.bouncycastle.crypto.engines;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.util.Bytes;

public class GiftCofbEngine extends AEADBaseEngine
{
    private byte[] npub;
    private byte[] k;
    private byte[] Y;
    private byte[] input;
    private byte[] offset;
    private static final byte[] GIFT_RC;
    
    public GiftCofbEngine() {
        final int aadBufferSize = 16;
        this.KEY_SIZE = aadBufferSize;
        this.IV_SIZE = aadBufferSize;
        this.MAC_SIZE = aadBufferSize;
        this.BlockSize = aadBufferSize;
        this.AADBufferSize = aadBufferSize;
        this.algorithmName = "GIFT-COFB AEAD";
        this.setInnerMembers(ProcessingBufferType.Buffered, AADOperatorType.Default, DataOperatorType.Counter);
    }
    
    private int rowperm(final int n, final int n2, final int n3, final int n4, final int n5) {
        int n6 = 0;
        for (int i = 0; i < 8; ++i) {
            n6 = (n6 | (n >>> 4 * i & 0x1) << i + 8 * n2 | (n >>> 4 * i + 1 & 0x1) << i + 8 * n3 | (n >>> 4 * i + 2 & 0x1) << i + 8 * n4 | (n >>> 4 * i + 3 & 0x1) << i + 8 * n5);
        }
        return n6;
    }
    
    private void giftb128(final byte[] array, final byte[] array2, final byte[] array3) {
        final int[] array4 = new int[4];
        final short[] array5 = new short[8];
        array4[0] = ((array[0] & 0xFF) << 24 | (array[1] & 0xFF) << 16 | (array[2] & 0xFF) << 8 | (array[3] & 0xFF));
        array4[1] = ((array[4] & 0xFF) << 24 | (array[5] & 0xFF) << 16 | (array[6] & 0xFF) << 8 | (array[7] & 0xFF));
        array4[2] = ((array[8] & 0xFF) << 24 | (array[9] & 0xFF) << 16 | (array[10] & 0xFF) << 8 | (array[11] & 0xFF));
        array4[3] = ((array[12] & 0xFF) << 24 | (array[13] & 0xFF) << 16 | (array[14] & 0xFF) << 8 | (array[15] & 0xFF));
        array5[0] = (short)((array2[0] & 0xFF) << 8 | (array2[1] & 0xFF));
        array5[1] = (short)((array2[2] & 0xFF) << 8 | (array2[3] & 0xFF));
        array5[2] = (short)((array2[4] & 0xFF) << 8 | (array2[5] & 0xFF));
        array5[3] = (short)((array2[6] & 0xFF) << 8 | (array2[7] & 0xFF));
        array5[4] = (short)((array2[8] & 0xFF) << 8 | (array2[9] & 0xFF));
        array5[5] = (short)((array2[10] & 0xFF) << 8 | (array2[11] & 0xFF));
        array5[6] = (short)((array2[12] & 0xFF) << 8 | (array2[13] & 0xFF));
        array5[7] = (short)((array2[14] & 0xFF) << 8 | (array2[15] & 0xFF));
        for (int i = 0; i < 40; ++i) {
            final int[] array6 = array4;
            final int n = 1;
            array6[n] ^= (array4[0] & array4[2]);
            final int[] array7 = array4;
            final int n2 = 0;
            array7[n2] ^= (array4[1] & array4[3]);
            final int[] array8 = array4;
            final int n3 = 2;
            array8[n3] ^= (array4[0] | array4[1]);
            final int[] array9 = array4;
            final int n4 = 3;
            array9[n4] ^= array4[2];
            final int[] array10 = array4;
            final int n5 = 1;
            array10[n5] ^= array4[3];
            final int[] array11 = array4;
            final int n6 = 3;
            array11[n6] ^= -1;
            final int[] array12 = array4;
            final int n7 = 2;
            array12[n7] ^= (array4[0] & array4[1]);
            final int n8 = array4[0];
            array4[0] = array4[3];
            array4[3] = n8;
            array4[0] = this.rowperm(array4[0], 0, 3, 2, 1);
            array4[1] = this.rowperm(array4[1], 1, 0, 3, 2);
            array4[2] = this.rowperm(array4[2], 2, 1, 0, 3);
            array4[3] = this.rowperm(array4[3], 3, 2, 1, 0);
            final int[] array13 = array4;
            final int n9 = 2;
            array13[n9] ^= ((array5[2] & 0xFFFF) << 16 | (array5[3] & 0xFFFF));
            final int[] array14 = array4;
            final int n10 = 1;
            array14[n10] ^= ((array5[6] & 0xFFFF) << 16 | (array5[7] & 0xFFFF));
            final int[] array15 = array4;
            final int n11 = 3;
            array15[n11] ^= (Integer.MIN_VALUE ^ (GiftCofbEngine.GIFT_RC[i] & 0xFF));
            final short n12 = (short)((array5[6] & 0xFFFF) >>> 2 | (array5[6] & 0xFFFF) << 14);
            final short n13 = (short)((array5[7] & 0xFFFF) >>> 12 | (array5[7] & 0xFFFF) << 4);
            array5[7] = array5[5];
            array5[6] = array5[4];
            array5[5] = array5[3];
            array5[4] = array5[2];
            array5[3] = array5[1];
            array5[2] = array5[0];
            array5[1] = n13;
            array5[0] = n12;
        }
        array3[0] = (byte)(array4[0] >>> 24);
        array3[1] = (byte)(array4[0] >>> 16);
        array3[2] = (byte)(array4[0] >>> 8);
        array3[3] = (byte)array4[0];
        array3[4] = (byte)(array4[1] >>> 24);
        array3[5] = (byte)(array4[1] >>> 16);
        array3[6] = (byte)(array4[1] >>> 8);
        array3[7] = (byte)array4[1];
        array3[8] = (byte)(array4[2] >>> 24);
        array3[9] = (byte)(array4[2] >>> 16);
        array3[10] = (byte)(array4[2] >>> 8);
        array3[11] = (byte)array4[2];
        array3[12] = (byte)(array4[3] >>> 24);
        array3[13] = (byte)(array4[3] >>> 16);
        array3[14] = (byte)(array4[3] >>> 8);
        array3[15] = (byte)array4[3];
    }
    
    private void double_half_block(final byte[] array) {
        final int n = ((array[0] & 0xFF) >>> 7) * 27;
        for (int i = 0; i < 7; ++i) {
            array[i] = (byte)((array[i] & 0xFF) << 1 | (array[i + 1] & 0xFF) >>> 7);
        }
        array[7] = (byte)((array[7] & 0xFF) << 1 ^ n);
    }
    
    private void triple_half_block(final byte[] array) {
        final byte[] array2 = new byte[8];
        for (int i = 0; i < 7; ++i) {
            array2[i] = (byte)((array[i] & 0xFF) << 1 | (array[i + 1] & 0xFF) >>> 7);
        }
        array2[7] = (byte)((array[7] & 0xFF) << 1 ^ ((array[0] & 0xFF) >>> 7) * 27);
        Bytes.xorTo(8, array2, array);
    }
    
    private void pho1(final byte[] array, final byte[] array2, final byte[] array3, final int n, final int n2) {
        final byte[] array4 = new byte[16];
        final byte[] array5 = new byte[16];
        if (n2 == 0) {
            array4[0] = -128;
        }
        else if (n2 < 16) {
            System.arraycopy(array3, n, array4, 0, n2);
            array4[n2] = -128;
        }
        else {
            System.arraycopy(array3, n, array4, 0, n2);
        }
        System.arraycopy(array2, 8, array5, 0, 8);
        for (int i = 0; i < 7; ++i) {
            array5[i + 8] = (byte)((array2[i] & 0xFF) << 1 | (array2[i + 1] & 0xFF) >>> 7);
        }
        array5[15] = (byte)((array2[7] & 0xFF) << 1 | (array2[0] & 0xFF) >>> 7);
        System.arraycopy(array5, 0, array2, 0, 16);
        Bytes.xor(16, array2, array4, array);
    }
    
    @Override
    protected void processBufferAAD(final byte[] array, final int n) {
        this.pho1(this.input, this.Y, array, n, 16);
        this.double_half_block(this.offset);
        Bytes.xorTo(8, this.offset, this.input);
        this.giftb128(this.input, this.k, this.Y);
    }
    
    @Override
    protected void processFinalAAD() {
        final int n = this.dataOperator.getLen() - (this.forEncryption ? 0 : this.MAC_SIZE);
        this.triple_half_block(this.offset);
        if ((this.m_aadPos & 0xF) != 0x0 || this.m_state == State.DecInit || this.m_state == State.EncInit) {
            this.triple_half_block(this.offset);
        }
        if (n == 0) {
            this.triple_half_block(this.offset);
            this.triple_half_block(this.offset);
        }
        this.pho1(this.input, this.Y, this.m_aad, 0, this.m_aadPos);
        Bytes.xorTo(8, this.offset, this.input);
        this.giftb128(this.input, this.k, this.Y);
    }
    
    @Override
    protected void finishAAD(final State state, final boolean b) {
        this.finishAAD3(state, b);
    }
    
    @Override
    protected void init(final byte[] k, final byte[] npub) {
        this.npub = npub;
        this.k = k;
        this.Y = new byte[this.BlockSize];
        this.input = new byte[16];
        this.offset = new byte[8];
    }
    
    @Override
    protected void processFinalBlock(final byte[] array, final int n) {
        final int n2 = this.dataOperator.getLen() - (this.forEncryption ? 0 : this.MAC_SIZE);
        if (n2 != 0) {
            this.triple_half_block(this.offset);
            if ((n2 & 0xF) != 0x0) {
                this.triple_half_block(this.offset);
            }
            Bytes.xor(this.m_bufPos, this.Y, this.m_buf, 0, array, n);
            if (this.forEncryption) {
                this.pho1(this.input, this.Y, this.m_buf, 0, this.m_bufPos);
            }
            else {
                this.pho1(this.input, this.Y, array, n, this.m_bufPos);
            }
            Bytes.xorTo(8, this.offset, this.input);
            this.giftb128(this.input, this.k, this.Y);
        }
        System.arraycopy(this.Y, 0, this.mac, 0, this.BlockSize);
    }
    
    @Override
    protected void processBufferEncrypt(final byte[] array, final int n, final byte[] array2, final int n2) {
        this.double_half_block(this.offset);
        Bytes.xor(this.BlockSize, this.Y, array, n, array2, n2);
        this.pho1(this.input, this.Y, array, n, this.BlockSize);
        Bytes.xorTo(8, this.offset, this.input);
        this.giftb128(this.input, this.k, this.Y);
    }
    
    @Override
    protected void processBufferDecrypt(final byte[] array, final int n, final byte[] array2, final int n2) {
        this.double_half_block(this.offset);
        Bytes.xor(this.BlockSize, this.Y, array, n, array2, n2);
        this.pho1(this.input, this.Y, array2, n2, this.BlockSize);
        Bytes.xorTo(8, this.offset, this.input);
        this.giftb128(this.input, this.k, this.Y);
    }
    
    @Override
    protected void reset(final boolean b) {
        super.reset(b);
        System.arraycopy(this.npub, 0, this.input, 0, this.IV_SIZE);
        this.giftb128(this.input, this.k, this.Y);
        System.arraycopy(this.Y, 0, this.offset, 0, 8);
    }
    
    static {
        GIFT_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 };
    }
}
