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

package org.bouncycastle.crypto.digests;

import org.bouncycastle.util.Memoable;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.CryptoServiceProperties;
import org.bouncycastle.crypto.CryptoServicePurpose;
import org.bouncycastle.crypto.SavableDigest;
import org.bouncycastle.crypto.Xof;

public class SHAKEDigest extends KeccakDigest implements Xof, SavableDigest
{
    private static int checkBitLength(final int i) {
        switch (i) {
            case 128:
            case 256: {
                return i;
            }
            default: {
                throw new IllegalArgumentException("'bitStrength' " + i + " not supported for SHAKE");
            }
        }
    }
    
    public SHAKEDigest() {
        this(128);
    }
    
    public SHAKEDigest(final CryptoServicePurpose cryptoServicePurpose) {
        this(128, cryptoServicePurpose);
    }
    
    public SHAKEDigest(final int n) {
        super(checkBitLength(n), CryptoServicePurpose.ANY);
    }
    
    public SHAKEDigest(final int n, final CryptoServicePurpose cryptoServicePurpose) {
        super(checkBitLength(n), cryptoServicePurpose);
    }
    
    public SHAKEDigest(final SHAKEDigest shakeDigest) {
        super(shakeDigest);
    }
    
    public SHAKEDigest(final byte[] array) {
        super(array);
    }
    
    @Override
    public String getAlgorithmName() {
        return "SHAKE" + this.fixedOutputLength;
    }
    
    @Override
    public int getDigestSize() {
        return this.fixedOutputLength / 4;
    }
    
    @Override
    public int doFinal(final byte[] array, final int n) {
        return this.doFinal(array, n, this.getDigestSize());
    }
    
    @Override
    public int doFinal(final byte[] array, final int n, final int n2) {
        final int doOutput = this.doOutput(array, n, n2);
        this.reset();
        return doOutput;
    }
    
    @Override
    public int doOutput(final byte[] array, final int n, final int n2) {
        if (!this.squeezing) {
            this.absorbBits(15, 4);
        }
        this.squeeze(array, n, n2 * 8L);
        return n2;
    }
    
    @Override
    protected int doFinal(final byte[] array, final int n, final byte b, final int n2) {
        return this.doFinal(array, n, this.getDigestSize(), b, n2);
    }
    
    protected int doFinal(final byte[] array, final int n, final int n2, final byte b, final int n3) {
        if (n3 < 0 || n3 > 7) {
            throw new IllegalArgumentException("'partialBits' must be in the range [0,7]");
        }
        int n4 = (b & (1 << n3) - 1) | 15 << n3;
        int n5 = n3 + 4;
        if (n5 >= 8) {
            this.absorb((byte)n4);
            n5 -= 8;
            n4 >>>= 8;
        }
        if (n5 > 0) {
            this.absorbBits(n4, n5);
        }
        this.squeeze(array, n, n2 * 8L);
        this.reset();
        return n2;
    }
    
    @Override
    protected CryptoServiceProperties cryptoServiceProperties() {
        return Utils.getDefaultProperties(this, this.purpose);
    }
    
    @Override
    public byte[] getEncodedState() {
        final byte[] array = new byte[this.state.length * 8 + this.dataQueue.length + 12 + 2];
        super.getEncodedState(array);
        return array;
    }
    
    @Override
    public Memoable copy() {
        return new SHAKEDigest(this);
    }
    
    @Override
    public void reset(final Memoable memoable) {
        this.copyIn((KeccakDigest)memoable);
    }
}
