// 
// 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.Arrays;
import org.bouncycastle.util.Pack;

public class AsconAEAD128 extends AsconBaseEngine
{
    public AsconAEAD128() {
        final int key_SIZE = 16;
        this.BlockSize = key_SIZE;
        this.AADBufferSize = key_SIZE;
        this.MAC_SIZE = key_SIZE;
        this.IV_SIZE = key_SIZE;
        this.KEY_SIZE = key_SIZE;
        this.ASCON_IV = 17594342703105L;
        this.algorithmName = "Ascon-AEAD128";
        this.nr = 8;
        this.dsep = Long.MIN_VALUE;
        this.macSizeLowerBound = 4;
        this.setInnerMembers(ProcessingBufferType.Immediate, AADOperatorType.DataLimit, DataOperatorType.DataLimit);
        this.dataLimitCounter.init(54);
        this.decryptionFailureCounter = new DecryptionFailureCounter();
    }
    
    @Override
    protected long pad(final int n) {
        return 1L << (n << 3);
    }
    
    @Override
    protected long loadBytes(final byte[] array, final int n) {
        return Pack.littleEndianToLong(array, n);
    }
    
    @Override
    protected void setBytes(final long n, final byte[] array, final int n2) {
        Pack.longToLittleEndian(n, array, n2);
    }
    
    @Override
    protected void ascon_aeadinit() {
        this.p.set(this.ASCON_IV, this.K0, this.K1, this.N0, this.N1);
        this.p.p(12);
        final AsconPermutationFriend.AsconPermutation p = this.p;
        p.x3 ^= this.K0;
        final AsconPermutationFriend.AsconPermutation p2 = this.p;
        p2.x4 ^= this.K1;
    }
    
    @Override
    protected void processFinalAAD() {
        if (this.m_aadPos == this.BlockSize) {
            final AsconPermutationFriend.AsconPermutation p = this.p;
            p.x0 ^= this.loadBytes(this.m_aad, 0);
            final AsconPermutationFriend.AsconPermutation p2 = this.p;
            p2.x1 ^= this.loadBytes(this.m_aad, 8);
            this.m_aadPos -= this.BlockSize;
            this.p.p(this.nr);
        }
        Arrays.fill(this.m_aad, this.m_aadPos, this.AADBufferSize, (byte)0);
        if (this.m_aadPos >= 8) {
            final AsconPermutationFriend.AsconPermutation p3 = this.p;
            p3.x0 ^= Pack.littleEndianToLong(this.m_aad, 0);
            final AsconPermutationFriend.AsconPermutation p4 = this.p;
            p4.x1 ^= (Pack.littleEndianToLong(this.m_aad, 8) ^ this.pad(this.m_aadPos));
        }
        else {
            final AsconPermutationFriend.AsconPermutation p5 = this.p;
            p5.x0 ^= (Pack.littleEndianToLong(this.m_aad, 0) ^ this.pad(this.m_aadPos));
        }
    }
    
    @Override
    protected void processFinalDecrypt(final byte[] array, int n, final byte[] array2, final int n2) {
        if (n >= 8) {
            final long littleEndianToLong = Pack.littleEndianToLong(array, 0);
            n -= 8;
            final long littleEndianToLong2 = Pack.littleEndianToLong(array, 8, n);
            Pack.longToLittleEndian(this.p.x0 ^ littleEndianToLong, array2, n2);
            Pack.longToLittleEndian(this.p.x1 ^ littleEndianToLong2, array2, n2 + 8, n);
            this.p.x0 = littleEndianToLong;
            final AsconPermutationFriend.AsconPermutation p4 = this.p;
            p4.x1 &= -(1L << (n << 3));
            final AsconPermutationFriend.AsconPermutation p5 = this.p;
            p5.x1 |= littleEndianToLong2;
            final AsconPermutationFriend.AsconPermutation p6 = this.p;
            p6.x1 ^= this.pad(n);
        }
        else {
            if (n != 0) {
                final long littleEndianToLong3 = Pack.littleEndianToLong(array, 0, n);
                Pack.longToLittleEndian(this.p.x0 ^ littleEndianToLong3, array2, n2, n);
                final AsconPermutationFriend.AsconPermutation p7 = this.p;
                p7.x0 &= -(1L << (n << 3));
                final AsconPermutationFriend.AsconPermutation p8 = this.p;
                p8.x0 |= littleEndianToLong3;
            }
            final AsconPermutationFriend.AsconPermutation p9 = this.p;
            p9.x0 ^= this.pad(n);
        }
        this.finishData(State.DecFinal);
    }
    
    @Override
    protected void processFinalEncrypt(final byte[] array, int n, final byte[] array2, final int n2) {
        if (n >= 8) {
            final AsconPermutationFriend.AsconPermutation p4 = this.p;
            p4.x0 ^= Pack.littleEndianToLong(array, 0);
            n -= 8;
            final AsconPermutationFriend.AsconPermutation p5 = this.p;
            p5.x1 ^= Pack.littleEndianToLong(array, 8, n);
            Pack.longToLittleEndian(this.p.x0, array2, n2);
            Pack.longToLittleEndian(this.p.x1, array2, n2 + 8);
            final AsconPermutationFriend.AsconPermutation p6 = this.p;
            p6.x1 ^= this.pad(n);
        }
        else {
            if (n != 0) {
                final AsconPermutationFriend.AsconPermutation p7 = this.p;
                p7.x0 ^= Pack.littleEndianToLong(array, 0, n);
                Pack.longToLittleEndian(this.p.x0, array2, n2, n);
            }
            final AsconPermutationFriend.AsconPermutation p8 = this.p;
            p8.x0 ^= this.pad(n);
        }
        this.finishData(State.EncFinal);
    }
    
    private void finishData(final State state) {
        final AsconPermutationFriend.AsconPermutation p = this.p;
        p.x2 ^= this.K0;
        final AsconPermutationFriend.AsconPermutation p2 = this.p;
        p2.x3 ^= this.K1;
        this.p.p(12);
        final AsconPermutationFriend.AsconPermutation p3 = this.p;
        p3.x3 ^= this.K0;
        final AsconPermutationFriend.AsconPermutation p4 = this.p;
        p4.x4 ^= this.K1;
        this.m_state = state;
    }
    
    @Override
    protected void init(final byte[] array, final byte[] array2) throws IllegalArgumentException {
        final int n = (this.MAC_SIZE << 3) - 32;
        final long littleEndianToLong = Pack.littleEndianToLong(array, 0);
        final long littleEndianToLong2 = Pack.littleEndianToLong(array, 8);
        this.decryptionFailureCounter.init(n);
        if (this.K0 != littleEndianToLong || this.K1 != littleEndianToLong2) {
            this.dataLimitCounter.reset();
            this.decryptionFailureCounter.reset();
            this.K0 = littleEndianToLong;
            this.K1 = littleEndianToLong2;
        }
        this.N0 = Pack.littleEndianToLong(array2, 0);
        this.N1 = Pack.littleEndianToLong(array2, 8);
    }
    
    @Override
    public String getAlgorithmVersion() {
        return "v1.3";
    }
}
