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

package org.bouncycastle.crypto.digests;

import org.bouncycastle.util.Pack;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.ExtendedDigest;

public class Blake2bpDigest implements ExtendedDigest
{
    private int bufferPos;
    private int keyLength;
    private int digestLength;
    private int fanout;
    private int depth;
    private int nodeOffset;
    private long innerHashLength;
    private Blake2bDigest[] S;
    private Blake2bDigest root;
    private byte[] buffer;
    private byte[] salt;
    private byte[] param;
    private byte[] key;
    private final int BLAKE2B_BLOCKBYTES = 128;
    private final int BLAKE2B_KEYBYTES = 64;
    private final int BLAKE2B_OUTBYTES = 64;
    private final int PARALLELISM_DEGREE = 4;
    private final byte[] singleByte;
    
    public Blake2bpDigest(final byte[] array) {
        this.bufferPos = 0;
        this.keyLength = 0;
        this.nodeOffset = 0;
        this.S = new Blake2bDigest[4];
        this.buffer = null;
        this.salt = null;
        this.param = null;
        this.key = null;
        this.singleByte = new byte[1];
        this.param = new byte[64];
        this.buffer = new byte[512];
        this.init(array);
    }
    
    @Override
    public String getAlgorithmName() {
        return "BLAKE2bp";
    }
    
    @Override
    public int getDigestSize() {
        return this.digestLength;
    }
    
    @Override
    public void update(final byte b) {
        this.singleByte[0] = b;
        this.update(this.singleByte, 0, 1);
    }
    
    @Override
    public void update(final byte[] array, int n, int n2) {
        int bufferPos = this.bufferPos;
        final int n3 = 1024 - bufferPos;
        if (bufferPos != 0 && n2 >= n3) {
            System.arraycopy(array, n, this.buffer, bufferPos, n3);
            for (int i = 0; i < 4; ++i) {
                this.S[i].update(this.buffer, i * 128, 128);
            }
            n += n3;
            n2 -= n3;
            bufferPos = 0;
        }
        for (int j = 0; j < 4; ++j) {
            int k = n2;
            int n4 = n + j * 128;
            while (k >= 512) {
                this.S[j].update(array, n4, 128);
                n4 += 512;
                k -= 512;
            }
        }
        n += n2 - n2 % 512;
        n2 %= 512;
        if (n2 > 0) {
            System.arraycopy(array, n, this.buffer, bufferPos, n2);
        }
        this.bufferPos = bufferPos + n2;
    }
    
    @Override
    public int doFinal(final byte[] array, final int n) {
        final byte[][] array2 = new byte[4][64];
        for (int i = 0; i < 4; ++i) {
            if (this.bufferPos > i * 128) {
                int n2 = this.bufferPos - i * 128;
                if (n2 > 128) {
                    n2 = 128;
                }
                this.S[i].update(this.buffer, i * 128, n2);
            }
            this.S[i].doFinal(array2[i], 0);
        }
        for (int j = 0; j < 4; ++j) {
            this.root.update(array2[j], 0, 64);
        }
        final int doFinal = this.root.doFinal(array, n);
        this.reset();
        return doFinal;
    }
    
    @Override
    public void reset() {
        this.bufferPos = 0;
        this.digestLength = 64;
        this.root.reset();
        for (int i = 0; i < 4; ++i) {
            this.S[i].reset();
        }
        this.root.setAsLastNode();
        this.S[3].setAsLastNode();
        if (this.key != null) {
            final byte[] array = new byte[128];
            System.arraycopy(this.key, 0, array, 0, this.keyLength);
            for (int j = 0; j < 4; ++j) {
                this.S[j].update(array, 0, 128);
            }
        }
    }
    
    @Override
    public int getByteLength() {
        return 0;
    }
    
    private void init(final byte[] array) {
        if (array != null && array.length > 0) {
            this.keyLength = array.length;
            if (this.keyLength > 64) {
                throw new IllegalArgumentException("Keys > 64 bytes are not supported");
            }
            this.key = Arrays.clone(array);
        }
        this.bufferPos = 0;
        this.digestLength = 64;
        this.fanout = 4;
        this.depth = 2;
        this.innerHashLength = 64L;
        this.param[0] = (byte)this.digestLength;
        this.param[1] = (byte)this.keyLength;
        this.param[2] = (byte)this.fanout;
        this.param[3] = (byte)this.depth;
        this.param[16] = 1;
        this.param[17] = (byte)this.innerHashLength;
        this.root = new Blake2bDigest(null, this.param);
        Pack.intToLittleEndian(this.nodeOffset, this.param, 8);
        this.param[16] = 0;
        for (int i = 0; i < 4; ++i) {
            Pack.intToLittleEndian(i, this.param, 8);
            this.S[i] = new Blake2bDigest(null, this.param);
        }
        this.root.setAsLastNode();
        this.S[3].setAsLastNode();
        if (array != null && this.keyLength > 0) {
            final byte[] array2 = new byte[128];
            System.arraycopy(array, 0, array2, 0, this.keyLength);
            for (int j = 0; j < 4; ++j) {
                this.S[j].update(array2, 0, 128);
            }
        }
    }
}
