// 
// 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 Blake2spDigest implements ExtendedDigest
{
    private int bufferPos;
    private int keyLength;
    private int digestLength;
    private int fanout;
    private int depth;
    private int nodeOffset;
    private long innerHashLength;
    private Blake2sDigest[] S;
    private Blake2sDigest root;
    private byte[] buffer;
    private byte[] salt;
    private byte[] param;
    private byte[] key;
    private final int BLAKE2S_BLOCKBYTES = 64;
    private final int BLAKE2S_KEYBYTES = 32;
    private final int BLAKE2S_OUTBYTES = 32;
    private final int PARALLELISM_DEGREE = 8;
    private final byte[] singleByte;
    
    public Blake2spDigest(final byte[] array) {
        this.bufferPos = 0;
        this.keyLength = 0;
        this.nodeOffset = 0;
        this.S = new Blake2sDigest[8];
        this.buffer = null;
        this.salt = null;
        this.param = null;
        this.key = null;
        this.singleByte = new byte[1];
        this.param = new byte[32];
        this.buffer = new byte[512];
        this.init(array);
    }
    
    @Override
    public String getAlgorithmName() {
        return "BLAKE2sp";
    }
    
    @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 = 512 - bufferPos;
        if (bufferPos != 0 && n2 >= n3) {
            System.arraycopy(array, n, this.buffer, bufferPos, n3);
            for (int i = 0; i < 8; ++i) {
                this.S[i].update(this.buffer, i * 64, 64);
            }
            n += n3;
            n2 -= n3;
            bufferPos = 0;
        }
        for (int j = 0; j < 8; ++j) {
            int k = n2;
            int n4 = n + j * 64;
            while (k >= 512) {
                this.S[j].update(array, n4, 64);
                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[8][32];
        for (int i = 0; i < 8; ++i) {
            if (this.bufferPos > i * 64) {
                int n2 = this.bufferPos - i * 64;
                if (n2 > 64) {
                    n2 = 64;
                }
                this.S[i].update(this.buffer, i * 64, n2);
            }
            this.S[i].doFinal(array2[i], 0);
        }
        for (int j = 0; j < 8; ++j) {
            this.root.update(array2[j], 0, 32);
        }
        final int doFinal = this.root.doFinal(array, n);
        this.reset();
        return doFinal;
    }
    
    @Override
    public void reset() {
        this.bufferPos = 0;
        this.digestLength = 32;
        this.root.reset();
        for (int i = 0; i < 8; ++i) {
            this.S[i].reset();
        }
        this.root.setAsLastNode();
        this.S[7].setAsLastNode();
        if (this.key != null) {
            final byte[] array = new byte[64];
            System.arraycopy(this.key, 0, array, 0, this.keyLength);
            for (int j = 0; j < 8; ++j) {
                this.S[j].update(array, 0, 64);
            }
        }
    }
    
    @Override
    public int getByteLength() {
        return 64;
    }
    
    private void init(final byte[] array) {
        if (array != null && array.length > 0) {
            this.keyLength = array.length;
            if (this.keyLength > 32) {
                throw new IllegalArgumentException("Keys > 32 bytes are not supported");
            }
            this.key = Arrays.clone(array);
        }
        this.bufferPos = 0;
        this.digestLength = 32;
        this.fanout = 8;
        this.depth = 2;
        this.innerHashLength = 32L;
        this.param[0] = (byte)this.digestLength;
        this.param[1] = (byte)this.keyLength;
        this.param[2] = (byte)this.fanout;
        this.param[3] = (byte)this.depth;
        Pack.intToLittleEndian(0, this.param, 8);
        this.param[14] = 1;
        this.param[15] = (byte)this.innerHashLength;
        this.root = new Blake2sDigest(null, this.param);
        Pack.intToLittleEndian(this.nodeOffset, this.param, 8);
        this.param[14] = 0;
        for (int i = 0; i < 8; ++i) {
            Pack.intToLittleEndian(i, this.param, 8);
            this.S[i] = new Blake2sDigest(null, this.param);
        }
        this.root.setAsLastNode();
        this.S[7].setAsLastNode();
        if (array != null && this.keyLength > 0) {
            final byte[] array2 = new byte[64];
            System.arraycopy(array, 0, array2, 0, this.keyLength);
            for (int j = 0; j < 8; ++j) {
                this.S[j].update(array2, 0, 64);
            }
        }
    }
}
