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

package org.bouncycastle.pqc.crypto.rainbow;

import org.bouncycastle.util.Pack;

class GF2Field
{
    static final byte[][] gfMulTable;
    static final byte[] gfInvTable;
    public static final int MASK = 255;
    
    private static short gf4Mul2(final short n) {
        return (short)((n << 1 ^ (n >>> 1) * 7) & 0xFF);
    }
    
    private static short gf4Mul3(final short n) {
        final int n2 = n - 2 >>> 1;
        return (short)(((n2 & n * 3) | (~n2 & n - 1)) & 0xFF);
    }
    
    private static short gf4Mul(final short n, final short n2) {
        return (short)((n * (n2 & 0x1) ^ gf4Mul2(n) * (n2 >>> 1)) & 0xFF);
    }
    
    private static short gf4Squ(final short n) {
        return (short)((n ^ n >>> 1) & 0xFF);
    }
    
    private static short gf16Mul(final short n, final short n2) {
        final short n3 = (short)(n & 0x3 & 0xFF);
        final short n4 = (short)(n >>> 2 & 0xFF);
        final short n5 = (short)(n2 & 0x3 & 0xFF);
        final short n6 = (short)(n2 >>> 2 & 0xFF);
        final short gf4Mul = gf4Mul(n3, n5);
        return (short)(((short)(gf4Mul((short)(n3 ^ n4), (short)(n5 ^ n6)) ^ gf4Mul) << 2 ^ gf4Mul ^ gf4Mul2(gf4Mul(n4, n6))) & 0xFF);
    }
    
    private static short gf16Squ(final short n) {
        final short n2 = (short)(n & 0x3 & 0xFF);
        final short gf4Squ = gf4Squ((short)(n >>> 2 & 0xFF));
        return (short)((gf4Squ << 2 ^ gf4Mul2(gf4Squ) ^ gf4Squ(n2)) & 0xFF);
    }
    
    private static short gf16Mul8(final short n) {
        final short n2 = (short)(n & 0x3 & 0xFF);
        final short n3 = (short)(n >>> 2 & 0xFF);
        return (short)((gf4Mul2((short)(n2 ^ n3)) << 2 | gf4Mul3(n3)) & 0xFF);
    }
    
    private static short gf256Mul(final short n, final short n2) {
        final short n3 = (short)(n & 0xF & 0xFF);
        final short n4 = (short)(n >>> 4 & 0xFF);
        final short n5 = (short)(n2 & 0xF & 0xFF);
        final short n6 = (short)(n2 >>> 4 & 0xFF);
        final short gf16Mul = gf16Mul(n3, n5);
        return (short)(((short)(gf16Mul((short)(n3 ^ n4), (short)(n5 ^ n6)) ^ gf16Mul) << 4 ^ gf16Mul ^ gf16Mul8(gf16Mul(n4, n6))) & 0xFF);
    }
    
    private static short gf256Squ(final short n) {
        final short n2 = (short)(n & 0xF & 0xFF);
        final short gf16Squ = gf16Squ((short)(n >>> 4 & 0xFF));
        return (short)((gf16Squ << 4 ^ gf16Mul8(gf16Squ) ^ gf16Squ(n2)) & 0xFF);
    }
    
    private static short gf256Inv(final short n) {
        final short gf256Squ = gf256Squ(n);
        final short gf256Squ2 = gf256Squ(gf256Squ);
        final short gf256Mul = gf256Mul(gf256Mul(gf256Squ2, gf256Squ), gf256Squ(gf256Squ2));
        return gf256Mul(gf256Squ, gf256Squ(gf256Mul(gf256Squ(gf256Squ(gf256Squ(gf256Mul))), gf256Mul)));
    }
    
    public static short addElem(final short n, final short n2) {
        return (short)(n ^ n2);
    }
    
    public static long addElem_64(final long n, final long n2) {
        return n ^ n2;
    }
    
    public static short invElem(final short n) {
        return (short)(GF2Field.gfInvTable[n] & 0xFF);
    }
    
    public static long invElem_64(final long n) {
        return gf256Inv_64(n);
    }
    
    public static short multElem(final short n, final short n2) {
        return (short)(GF2Field.gfMulTable[n][n2] & 0xFF);
    }
    
    public static long multElem_64(final long n, final long n2) {
        return gf256Mul_64(n, n2);
    }
    
    private static long gf4Mul2_64(final long n) {
        final long n2 = n & 0x5555555555555555L;
        final long n3 = n & 0xAAAAAAAAAAAAAAAAL;
        return n3 ^ n2 << 1 ^ n3 >>> 1;
    }
    
    private static long gf4Mul_64(final long n, final long n2) {
        final long n3 = ((n << 1 & n2) ^ (n2 << 1 & n)) & 0xAAAAAAAAAAAAAAAAL;
        final long n4 = n & n2;
        return n4 ^ n3 ^ (n4 & 0xAAAAAAAAAAAAAAAAL) >>> 1;
    }
    
    private static long gf4Squ_64(final long n) {
        return n ^ (n & 0xAAAAAAAAAAAAAAAAL) >>> 1;
    }
    
    private static long gf16Mul_64(final long n, final long n2) {
        final long gf4Mul_64 = gf4Mul_64(n, n2);
        final long n3 = gf4Mul_64 & 0x3333333333333333L;
        return gf4Mul_64(((n << 2 ^ n) & 0xCCCCCCCCCCCCCCCCL) ^ (gf4Mul_64 & 0xCCCCCCCCCCCCCCCCL) >>> 2, ((n2 << 2 ^ n2) & 0xCCCCCCCCCCCCCCCCL) ^ 0x2222222222222222L) ^ n3 << 2 ^ n3;
    }
    
    private static long gf16Squ_64(final long n) {
        final long gf4Squ_64 = gf4Squ_64(n);
        return gf4Squ_64 ^ gf4Mul2_64(gf4Squ_64 & 0xCCCCCCCCCCCCCCCCL) >>> 2;
    }
    
    private static long gf16Mul8_64(final long n) {
        final long n2 = n & 0x3333333333333333L;
        final long n3 = n & 0xCCCCCCCCCCCCCCCCL;
        return gf4Mul2_64(n2 << 2 ^ n3 ^ n3 >>> 2) ^ n3 >>> 2;
    }
    
    private static long gf256Mul_64(final long n, final long n2) {
        final long gf16Mul_64 = gf16Mul_64(n, n2);
        final long n3 = gf16Mul_64 & 0xF0F0F0F0F0F0F0FL;
        return gf16Mul_64(((n << 4 ^ n) & 0xF0F0F0F0F0F0F0F0L) ^ (gf16Mul_64 & 0xF0F0F0F0F0F0F0F0L) >>> 4, ((n2 << 4 ^ n2) & 0xF0F0F0F0F0F0F0F0L) ^ 0x808080808080808L) ^ n3 << 4 ^ n3;
    }
    
    private static long gf256Squ_64(final long n) {
        final long gf16Squ_64 = gf16Squ_64(n);
        return gf16Squ_64 ^ gf16Mul8_64(gf16Squ_64 & 0xF0F0F0F0F0F0F0F0L) >>> 4;
    }
    
    private static long gf256Inv_64(final long n) {
        final long gf256Squ_64 = gf256Squ_64(n);
        final long gf256Squ_65 = gf256Squ_64(gf256Squ_64);
        final long gf256Mul_64 = gf256Mul_64(gf256Mul_64(gf256Squ_65, gf256Squ_64), gf256Squ_64(gf256Squ_65));
        return gf256Mul_64(gf256Squ_64, gf256Squ_64(gf256Mul_64(gf256Squ_64(gf256Squ_64(gf256Squ_64(gf256Mul_64))), gf256Mul_64)));
    }
    
    static {
        gfMulTable = new byte[256][256];
        gfInvTable = new byte[256];
        long n = 72340172838076673L;
        for (int i = 1; i <= 255; ++i) {
            long n2 = 506097522914230528L;
            for (int j = 0; j < 256; j += 8) {
                Pack.longToLittleEndian(gf256Mul_64(n, n2), GF2Field.gfMulTable[i], j);
                n2 += 578721382704613384L;
            }
            n += 72340172838076673L;
        }
        long n3 = 506097522914230528L;
        for (int k = 0; k < 256; k += 8) {
            Pack.longToLittleEndian(gf256Inv_64(n3), GF2Field.gfInvTable, k);
            n3 += 578721382704613384L;
        }
    }
}
