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

package org.bouncycastle.crypto.digests;

import org.bouncycastle.util.Memoable;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.CryptoServicePurpose;

public class CSHAKEDigest extends SHAKEDigest
{
    private static final byte[] padding;
    private byte[] diff;
    
    public CSHAKEDigest(final int n, final byte[] array, final byte[] array2) {
        this(n, CryptoServicePurpose.ANY, array, array2);
    }
    
    public CSHAKEDigest(final int n, final CryptoServicePurpose cryptoServicePurpose, final byte[] array, final byte[] array2) {
        super(n, cryptoServicePurpose);
        if ((array == null || array.length == 0) && (array2 == null || array2.length == 0)) {
            this.diff = null;
        }
        else {
            this.diff = Arrays.concatenate(XofUtils.leftEncode(this.rate / 8), this.encodeString(array), this.encodeString(array2));
            this.diffPadAndAbsorb();
        }
    }
    
    public CSHAKEDigest(final CSHAKEDigest cshakeDigest) {
        super(cshakeDigest);
        this.diff = Arrays.clone(cshakeDigest.diff);
    }
    
    public CSHAKEDigest(final byte[] array) {
        super(array);
        final int n = this.state.length * 8 + this.dataQueue.length + 12 + 2;
        if (array.length != n) {
            System.arraycopy(array, n, this.diff = new byte[array.length - n], 0, this.diff.length);
        }
        else {
            this.diff = null;
        }
    }
    
    private void copyIn(final CSHAKEDigest cshakeDigest) {
        super.copyIn(cshakeDigest);
        this.diff = Arrays.clone(cshakeDigest.diff);
    }
    
    private void diffPadAndAbsorb() {
        final int n = this.rate / 8;
        this.absorb(this.diff, 0, this.diff.length);
        final int n2 = this.diff.length % n;
        if (n2 != 0) {
            int i;
            for (i = n - n2; i > CSHAKEDigest.padding.length; i -= CSHAKEDigest.padding.length) {
                this.absorb(CSHAKEDigest.padding, 0, CSHAKEDigest.padding.length);
            }
            this.absorb(CSHAKEDigest.padding, 0, i);
        }
    }
    
    private byte[] encodeString(final byte[] array) {
        if (array == null || array.length == 0) {
            return XofUtils.leftEncode(0L);
        }
        return Arrays.concatenate(XofUtils.leftEncode(array.length * 8L), array);
    }
    
    @Override
    public String getAlgorithmName() {
        return "CSHAKE" + this.fixedOutputLength;
    }
    
    @Override
    public int doOutput(final byte[] array, final int n, final int n2) {
        if (this.diff != null) {
            if (!this.squeezing) {
                this.absorbBits(0, 2);
            }
            this.squeeze(array, n, n2 * 8L);
            return n2;
        }
        return super.doOutput(array, n, n2);
    }
    
    @Override
    public void reset() {
        super.reset();
        if (this.diff != null) {
            this.diffPadAndAbsorb();
        }
    }
    
    @Override
    public byte[] getEncodedState() {
        final int n = this.state.length * 8 + this.dataQueue.length + 12 + 2;
        byte[] array;
        if (this.diff == null) {
            array = new byte[n];
            super.getEncodedState(array);
        }
        else {
            array = new byte[n + this.diff.length];
            super.getEncodedState(array);
            System.arraycopy(this.diff, 0, array, n, this.diff.length);
        }
        return array;
    }
    
    @Override
    public Memoable copy() {
        return new CSHAKEDigest(this);
    }
    
    @Override
    public void reset(final Memoable memoable) {
        this.copyIn((CSHAKEDigest)memoable);
    }
    
    static {
        padding = new byte[100];
    }
}
