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

package org.bouncycastle.pqc.crypto.frodo;

import org.bouncycastle.util.Pack;
import org.bouncycastle.util.Arrays;
import java.security.SecureRandom;
import org.bouncycastle.crypto.Xof;

class FrodoEngine
{
    static final int nbar = 8;
    private static final int mbar = 8;
    private static final int len_seedA = 128;
    private static final int len_z = 128;
    private static final int len_chi = 16;
    private static final int len_seedA_bytes = 16;
    private static final int len_z_bytes = 16;
    private static final int len_chi_bytes = 2;
    private final int D;
    private final int q;
    private final int n;
    private final int B;
    private final int len_sk_bytes;
    private final int len_pk_bytes;
    private final int len_ct_bytes;
    private final short[] T_chi;
    private final int len_mu;
    private final int len_seedSE;
    private final int len_s;
    private final int len_k;
    private final int len_pkh;
    private final int len_ss;
    private final int len_mu_bytes;
    private final int len_seedSE_bytes;
    private final int len_s_bytes;
    private final int len_k_bytes;
    private final int len_pkh_bytes;
    private final int len_ss_bytes;
    private final Xof digest;
    private final FrodoMatrixGenerator gen;
    
    public int getCipherTextSize() {
        return this.len_ct_bytes;
    }
    
    public int getSessionKeySize() {
        return this.len_ss_bytes;
    }
    
    public int getPrivateKeySize() {
        return this.len_sk_bytes;
    }
    
    public int getPublicKeySize() {
        return this.len_pk_bytes;
    }
    
    public FrodoEngine(final int n, final int d, final int b, final short[] t_chi, final Xof digest, final FrodoMatrixGenerator gen) {
        this.n = n;
        this.D = d;
        this.q = 1 << d;
        this.B = b;
        this.len_mu = b * 8 * 8;
        this.len_seedSE = this.len_mu;
        this.len_s = this.len_mu;
        this.len_k = this.len_mu;
        this.len_pkh = this.len_mu;
        this.len_ss = this.len_mu;
        this.len_mu_bytes = this.len_mu / 8;
        this.len_seedSE_bytes = this.len_seedSE / 8;
        this.len_s_bytes = this.len_s / 8;
        this.len_k_bytes = this.len_k / 8;
        this.len_pkh_bytes = this.len_pkh / 8;
        this.len_ss_bytes = this.len_ss / 8;
        this.len_ct_bytes = d * n * 8 / 8 + d * 8 * 8 / 8;
        this.len_pk_bytes = 16 + d * n * 8 / 8;
        this.len_sk_bytes = this.len_s_bytes + this.len_pk_bytes + (2 * n * 8 + this.len_pkh_bytes);
        this.T_chi = t_chi;
        this.digest = digest;
        this.gen = gen;
    }
    
    private short sample(final short n) {
        final short n2 = (short)((n & 0xFFFF) >>> 1);
        short n3 = 0;
        for (int i = 0; i < this.T_chi.length; ++i) {
            if (n2 > this.T_chi[i]) {
                ++n3;
            }
        }
        if ((n & 0xFFFF) % 2 == 1) {
            n3 = (short)(n3 * -1 & 0xFFFF);
        }
        return n3;
    }
    
    private short[] sample_matrix(final short[] array, final int n, final int n2, final int n3) {
        final short[] array2 = new short[n2 * n3];
        for (int i = 0; i < n2; ++i) {
            for (int j = 0; j < n3; ++j) {
                array2[i * n3 + j] = this.sample(array[i * n3 + j + n]);
            }
        }
        return array2;
    }
    
    private short[] matrix_transpose(final short[] array, final int n, final int n2) {
        final short[] array2 = new short[n * n2];
        for (int i = 0; i < n2; ++i) {
            for (int j = 0; j < n; ++j) {
                array2[i * n + j] = array[j * n2 + i];
            }
        }
        return array2;
    }
    
    private short[] matrix_mul(final short[] array, final int n, final int n2, final short[] array2, final int n3, final int n4) {
        final int n5 = this.q - 1;
        final short[] array3 = new short[n * n4];
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n4; ++j) {
                int n6 = 0;
                for (int k = 0; k < n2; ++k) {
                    n6 += array[i * n2 + k] * array2[k * n4 + j];
                }
                array3[i * n4 + j] = (short)(n6 & n5);
            }
        }
        return array3;
    }
    
    private short[] matrix_add(final short[] array, final short[] array2, final int n, final int n2) {
        final int n3 = this.q - 1;
        final short[] array3 = new short[n * n2];
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n2; ++j) {
                array3[i * n2 + j] = (short)(array[i * n2 + j] + array2[i * n2 + j] & n3);
            }
        }
        return array3;
    }
    
    private byte[] pack(final short[] array) {
        final int length = array.length;
        final byte[] array2 = new byte[this.D * length / 8];
        int n = 0;
        int n2 = 0;
        int n3 = 0;
        for (int b = 0; n < array2.length && (n2 < length || (n2 == length && b > 0)); n = (short)(n + 1)) {
            int i = 0;
            while (i < 8) {
                final int min = Math.min(8 - i, b);
                array2[n] += (byte)((byte)(n3 >> b - min & (short)((1 << min) - 1)) << 8 - i - min);
                i = (byte)(i + min);
                b = (byte)(b - min);
                if (b == 0) {
                    if (n2 >= length) {
                        break;
                    }
                    n3 = array[n2];
                    b = (byte)this.D;
                    n2 = (short)(n2 + 1);
                }
            }
            if (i == 8) {}
        }
        return array2;
    }
    
    public void kem_keypair(final byte[] array, final byte[] array2, final SecureRandom secureRandom) {
        final byte[] bytes = new byte[this.len_s_bytes + this.len_seedSE_bytes + 16];
        secureRandom.nextBytes(bytes);
        final byte[] copyOfRange = Arrays.copyOfRange(bytes, 0, this.len_s_bytes);
        final byte[] copyOfRange2 = Arrays.copyOfRange(bytes, this.len_s_bytes, this.len_s_bytes + this.len_seedSE_bytes);
        final byte[] copyOfRange3 = Arrays.copyOfRange(bytes, this.len_s_bytes + this.len_seedSE_bytes, this.len_s_bytes + this.len_seedSE_bytes + 16);
        final byte[] array3 = new byte[16];
        this.digest.update(copyOfRange3, 0, copyOfRange3.length);
        this.digest.doFinal(array3, 0, array3.length);
        final short[] genMatrix = this.gen.genMatrix(array3);
        final byte[] array4 = new byte[2 * this.n * 8 * 2];
        this.digest.update((byte)95);
        this.digest.update(copyOfRange2, 0, copyOfRange2.length);
        this.digest.doFinal(array4, 0, array4.length);
        final short[] array5 = new short[2 * this.n * 8];
        for (int i = 0; i < array5.length; ++i) {
            array5[i] = Pack.littleEndianToShort(array4, i * 2);
        }
        final short[] sample_matrix = this.sample_matrix(array5, 0, 8, this.n);
        System.arraycopy(Arrays.concatenate(array3, this.pack(this.matrix_add(this.matrix_mul(genMatrix, this.n, this.n, this.matrix_transpose(sample_matrix, 8, this.n), this.n, 8), this.sample_matrix(array5, this.n * 8, this.n, 8), this.n, 8))), 0, array, 0, this.len_pk_bytes);
        final byte[] array6 = new byte[this.len_pkh_bytes];
        this.digest.update(array, 0, array.length);
        this.digest.doFinal(array6, 0, array6.length);
        System.arraycopy(Arrays.concatenate(copyOfRange, array), 0, array2, 0, this.len_s_bytes + this.len_pk_bytes);
        for (int j = 0; j < 8; ++j) {
            for (int k = 0; k < this.n; ++k) {
                System.arraycopy(Pack.shortToLittleEndian(sample_matrix[j * this.n + k]), 0, array2, this.len_s_bytes + this.len_pk_bytes + j * this.n * 2 + k * 2, 2);
            }
        }
        System.arraycopy(array6, 0, array2, this.len_sk_bytes - this.len_pkh_bytes, this.len_pkh_bytes);
    }
    
    private short[] unpack(final byte[] array, final int n, final int n2) {
        final short[] array2 = new short[n * n2];
        int n3 = 0;
        int n4 = 0;
        byte b = 0;
        for (int b2 = 0; n3 < array2.length && (n4 < array.length || (n4 == array.length && b2 > 0)); n3 = (short)(n3 + 1)) {
            int i = 0;
            while (i < this.D) {
                final int min = Math.min(this.D - i, b2);
                final short n5 = (short)((1 << min) - 1 & 0xFFFF);
                array2[n3] = (short)((array2[n3] & 0xFFFF) + (((byte)((b & 0xFF) >>> (b2 & 0xFF) - min & (n5 & 0xFFFF) & 0xFF) & 0xFF) << this.D - (i & 0xFF) - min) & 0xFFFF);
                i = (byte)(i + min);
                b2 = (byte)(b2 - min);
                b &= (byte)~(n5 << b2);
                if (b2 == 0) {
                    if (n4 >= array.length) {
                        break;
                    }
                    b = array[n4];
                    b2 = 8;
                    n4 = (short)(n4 + 1);
                }
            }
            if (i == this.D) {}
        }
        return array2;
    }
    
    private short[] encode(final byte[] array) {
        int n = 0;
        int n2 = 0;
        final short[] array2 = new short[64];
        for (int i = 0; i < 8; ++i) {
            for (int j = 0; j < 8; ++j) {
                int n3 = 0;
                for (int k = 0; k < this.B; ++k) {
                    n3 += (array[n] >>> n2 & 0x1) << k;
                    ++n2;
                    n += n2 >>> 3;
                    n2 &= 0x7;
                }
                array2[i * 8 + j] = (short)(n3 * (this.q / (1 << this.B)));
            }
        }
        return array2;
    }
    
    public void kem_enc(final byte[] array, final byte[] array2, final byte[] array3, final SecureRandom secureRandom) {
        final byte[] copyOfRange = Arrays.copyOfRange(array3, 0, 16);
        final byte[] copyOfRange2 = Arrays.copyOfRange(array3, 16, this.len_pk_bytes);
        final byte[] bytes = new byte[this.len_mu_bytes];
        secureRandom.nextBytes(bytes);
        final byte[] array4 = new byte[this.len_pkh_bytes];
        this.digest.update(array3, 0, this.len_pk_bytes);
        this.digest.doFinal(array4, 0, this.len_pkh_bytes);
        final byte[] array5 = new byte[this.len_seedSE + this.len_k];
        this.digest.update(array4, 0, this.len_pkh_bytes);
        this.digest.update(bytes, 0, this.len_mu_bytes);
        this.digest.doFinal(array5, 0, this.len_seedSE_bytes + this.len_k_bytes);
        final byte[] copyOfRange3 = Arrays.copyOfRange(array5, 0, this.len_seedSE_bytes);
        final byte[] copyOfRange4 = Arrays.copyOfRange(array5, this.len_seedSE_bytes, this.len_seedSE_bytes + this.len_k_bytes);
        final byte[] array6 = new byte[(16 * this.n + 64) * 2];
        this.digest.update((byte)(-106));
        this.digest.update(copyOfRange3, 0, copyOfRange3.length);
        this.digest.doFinal(array6, 0, array6.length);
        final short[] array7 = new short[array6.length / 2];
        for (int i = 0; i < array7.length; ++i) {
            array7[i] = Pack.littleEndianToShort(array6, i * 2);
        }
        final short[] sample_matrix = this.sample_matrix(array7, 0, 8, this.n);
        final byte[] pack = this.pack(this.matrix_add(this.matrix_mul(sample_matrix, 8, this.n, this.gen.genMatrix(copyOfRange), this.n, this.n), this.sample_matrix(array7, 8 * this.n, 8, this.n), 8, this.n));
        final byte[] pack2 = this.pack(this.matrix_add(this.matrix_add(this.matrix_mul(sample_matrix, 8, this.n, this.unpack(copyOfRange2, this.n, 8), this.n, 8), this.sample_matrix(array7, 16 * this.n, 8, 8), 8, 8), this.encode(bytes), 8, 8));
        System.arraycopy(Arrays.concatenate(pack, pack2), 0, array, 0, this.len_ct_bytes);
        this.digest.update(pack, 0, pack.length);
        this.digest.update(pack2, 0, pack2.length);
        this.digest.update(copyOfRange4, 0, this.len_k_bytes);
        this.digest.doFinal(array2, 0, this.len_s_bytes);
    }
    
    private short[] matrix_sub(final short[] array, final short[] array2, final int n, final int n2) {
        final int n3 = this.q - 1;
        final short[] array3 = new short[n * n2];
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n2; ++j) {
                array3[i * n2 + j] = (short)(array[i * n2 + j] - array2[i * n2 + j] & n3);
            }
        }
        return array3;
    }
    
    private byte[] decode(final short[] array) {
        int n = 0;
        final int n2 = 8;
        final int n3 = 8;
        final short n4 = (short)((1 << this.B) - 1);
        final short n5 = (short)((1 << this.D) - 1);
        final byte[] array2 = new byte[n2 * this.B];
        for (int i = 0; i < n3; ++i) {
            long n6 = 0L;
            for (int j = 0; j < n2; ++j) {
                n6 |= (long)((short)((array[n] & n5) + (1 << this.D - this.B - 1) >> this.D - this.B) & n4) << this.B * j;
                ++n;
            }
            for (int k = 0; k < this.B; ++k) {
                array2[i * this.B + k] = (byte)(n6 >> 8 * k & 0xFFL);
            }
        }
        return array2;
    }
    
    private short ctverify(final short[] array, final short[] array2, final short[] array3, final short[] array4) {
        short n = 0;
        for (int i = 0; i < array.length; i = (short)(i + 1)) {
            n |= (short)(array[i] ^ array3[i]);
        }
        for (int j = 0; j < array2.length; j = (short)(j + 1)) {
            n |= (short)(array2[j] ^ array4[j]);
        }
        if (n == 0) {
            return 0;
        }
        return -1;
    }
    
    private byte[] ctselect(final byte[] array, final byte[] array2, final short n) {
        final byte[] array3 = new byte[array.length];
        for (int i = 0; i < array.length; ++i) {
            array3[i] = (byte)((~n & array[i] & 0xFF) | (n & array2[i] & 0xFF));
        }
        return array3;
    }
    
    public void kem_dec(final byte[] array, final byte[] array2, final byte[] array3) {
        final int n = 0;
        final int n2 = 8 * this.n * this.D / 8;
        final byte[] copyOfRange = Arrays.copyOfRange(array2, n, n + n2);
        final int n3 = n + n2;
        final byte[] copyOfRange2 = Arrays.copyOfRange(array2, n3, n3 + 64 * this.D / 8);
        final int n4 = 0;
        final int len_s_bytes = this.len_s_bytes;
        final byte[] copyOfRange3 = Arrays.copyOfRange(array3, n4, n4 + len_s_bytes);
        final int n5 = n4 + len_s_bytes;
        final int n6 = 16;
        final byte[] copyOfRange4 = Arrays.copyOfRange(array3, n5, n5 + n6);
        final int n7 = n5 + n6;
        final int n8 = this.D * this.n * 8 / 8;
        final byte[] copyOfRange5 = Arrays.copyOfRange(array3, n7, n7 + n8);
        final int n9 = n7 + n8;
        final int n10 = this.n * 8 * 16 / 8;
        final byte[] copyOfRange6 = Arrays.copyOfRange(array3, n9, n9 + n10);
        final short[] array4 = new short[8 * this.n];
        for (int i = 0; i < 8; ++i) {
            for (int j = 0; j < this.n; ++j) {
                array4[i * this.n + j] = Pack.littleEndianToShort(copyOfRange6, i * this.n * 2 + j * 2);
            }
        }
        final short[] matrix_transpose = this.matrix_transpose(array4, 8, this.n);
        final int n11 = n9 + n10;
        final byte[] copyOfRange7 = Arrays.copyOfRange(array3, n11, n11 + this.len_pkh_bytes);
        final short[] unpack = this.unpack(copyOfRange, 8, this.n);
        final short[] unpack2 = this.unpack(copyOfRange2, 8, 8);
        final byte[] decode = this.decode(this.matrix_sub(unpack2, this.matrix_mul(unpack, 8, this.n, matrix_transpose, this.n, 8), 8, 8));
        final byte[] array5 = new byte[this.len_seedSE_bytes + this.len_k_bytes];
        this.digest.update(copyOfRange7, 0, this.len_pkh_bytes);
        this.digest.update(decode, 0, this.len_mu_bytes);
        this.digest.doFinal(array5, 0, this.len_seedSE_bytes + this.len_k_bytes);
        final byte[] copyOfRange8 = Arrays.copyOfRange(array5, this.len_seedSE_bytes, this.len_seedSE_bytes + this.len_k_bytes);
        final byte[] array6 = new byte[(16 * this.n + 64) * 2];
        this.digest.update((byte)(-106));
        this.digest.update(array5, 0, this.len_seedSE_bytes);
        this.digest.doFinal(array6, 0, array6.length);
        final short[] array7 = new short[16 * this.n + 64];
        for (int k = 0; k < array7.length; ++k) {
            array7[k] = Pack.littleEndianToShort(array6, k * 2);
        }
        final short[] sample_matrix = this.sample_matrix(array7, 0, 8, this.n);
        final byte[] ctselect = this.ctselect(copyOfRange8, copyOfRange3, this.ctverify(unpack, unpack2, this.matrix_add(this.matrix_mul(sample_matrix, 8, this.n, this.gen.genMatrix(copyOfRange4), this.n, this.n), this.sample_matrix(array7, 8 * this.n, 8, this.n), 8, this.n), this.matrix_add(this.matrix_add(this.matrix_mul(sample_matrix, 8, this.n, this.unpack(copyOfRange5, this.n, 8), this.n, 8), this.sample_matrix(array7, 16 * this.n, 8, 8), 8, 8), this.encode(decode), 8, 8)));
        this.digest.update(copyOfRange, 0, copyOfRange.length);
        this.digest.update(copyOfRange2, 0, copyOfRange2.length);
        this.digest.update(ctselect, 0, ctselect.length);
        this.digest.doFinal(array, 0, this.len_ss_bytes);
    }
}
