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

package org.bouncycastle.crypto.digests;

import org.bouncycastle.util.Integers;
import org.bouncycastle.crypto.engines.SparkleEngine;
import org.bouncycastle.util.Pack;
import org.bouncycastle.util.Arrays;

public class SparkleDigest extends BufferBaseDigest
{
    private static final int RATE_WORDS = 4;
    private final int[] state;
    private final int SPARKLE_STEPS_SLIM;
    private final int SPARKLE_STEPS_BIG;
    private final int STATE_WORDS;
    
    public SparkleDigest(final SparkleParameters sparkleParameters) {
        super(ProcessingBufferType.Buffered, 16);
        switch (sparkleParameters.ordinal()) {
            case 0: {
                this.algorithmName = "ESCH-256";
                this.DigestSize = 32;
                this.SPARKLE_STEPS_SLIM = 7;
                this.SPARKLE_STEPS_BIG = 11;
                this.STATE_WORDS = 12;
                break;
            }
            case 1: {
                this.algorithmName = "ESCH-384";
                this.DigestSize = 48;
                this.SPARKLE_STEPS_SLIM = 8;
                this.SPARKLE_STEPS_BIG = 12;
                this.STATE_WORDS = 16;
                break;
            }
            default: {
                throw new IllegalArgumentException("Invalid definition of SCHWAEMM instance");
            }
        }
        this.state = new int[this.STATE_WORDS];
    }
    
    @Override
    protected void processBytes(final byte[] array, final int n) {
        this.processBlock(array, n, this.SPARKLE_STEPS_SLIM);
    }
    
    @Override
    protected void finish(final byte[] array, final int n) {
        if (this.m_bufPos < this.BlockSize) {
            final int[] state = this.state;
            final int n2 = (this.STATE_WORDS >> 1) - 1;
            state[n2] ^= 0x1000000;
            this.m_buf[this.m_bufPos++] = -128;
            Arrays.fill(this.m_buf, this.m_bufPos, this.BlockSize, (byte)0);
        }
        else {
            final int[] state2 = this.state;
            final int n3 = (this.STATE_WORDS >> 1) - 1;
            state2[n3] ^= 0x2000000;
        }
        this.processBlock(this.m_buf, 0, this.SPARKLE_STEPS_BIG);
        Pack.intToLittleEndian(this.state, 0, 4, array, n);
        if (this.STATE_WORDS == 16) {
            SparkleEngine.sparkle_opt16(Friend.INSTANCE, this.state, this.SPARKLE_STEPS_SLIM);
            Pack.intToLittleEndian(this.state, 0, 4, array, n + 16);
            SparkleEngine.sparkle_opt16(Friend.INSTANCE, this.state, this.SPARKLE_STEPS_SLIM);
            Pack.intToLittleEndian(this.state, 0, 4, array, n + 32);
        }
        else {
            SparkleEngine.sparkle_opt12(Friend.INSTANCE, this.state, this.SPARKLE_STEPS_SLIM);
            Pack.intToLittleEndian(this.state, 0, 4, array, n + 16);
        }
    }
    
    @Override
    public void reset() {
        super.reset();
        Arrays.fill(this.state, 0);
    }
    
    private void processBlock(final byte[] array, final int n, final int n2) {
        final int littleEndianToInt = Pack.littleEndianToInt(array, n);
        final int littleEndianToInt2 = Pack.littleEndianToInt(array, n + 4);
        final int littleEndianToInt3 = Pack.littleEndianToInt(array, n + 8);
        final int littleEndianToInt4 = Pack.littleEndianToInt(array, n + 12);
        final int ell = ELL(littleEndianToInt ^ littleEndianToInt3);
        final int ell2 = ELL(littleEndianToInt2 ^ littleEndianToInt4);
        final int[] state = this.state;
        final int n3 = 0;
        state[n3] ^= (littleEndianToInt ^ ell2);
        final int[] state2 = this.state;
        final int n4 = 1;
        state2[n4] ^= (littleEndianToInt2 ^ ell);
        final int[] state3 = this.state;
        final int n5 = 2;
        state3[n5] ^= (littleEndianToInt3 ^ ell2);
        final int[] state4 = this.state;
        final int n6 = 3;
        state4[n6] ^= (littleEndianToInt4 ^ ell);
        final int[] state5 = this.state;
        final int n7 = 4;
        state5[n7] ^= ell2;
        final int[] state6 = this.state;
        final int n8 = 5;
        state6[n8] ^= ell;
        if (this.STATE_WORDS == 16) {
            final int[] state7 = this.state;
            final int n9 = 6;
            state7[n9] ^= ell2;
            final int[] state8 = this.state;
            final int n10 = 7;
            state8[n10] ^= ell;
            SparkleEngine.sparkle_opt16(Friend.INSTANCE, this.state, n2);
        }
        else {
            SparkleEngine.sparkle_opt12(Friend.INSTANCE, this.state, n2);
        }
    }
    
    private static int ELL(final int n) {
        return Integers.rotateRight(n, 16) ^ (n & 0xFFFF);
    }
    
    public static class Friend
    {
        private static final Friend INSTANCE;
        
        private Friend() {
        }
        
        static {
            INSTANCE = new Friend();
        }
    }
    
    public enum SparkleParameters
    {
        ESCH256, 
        ESCH384;
    }
}
