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

package org.bouncycastle.pqc.math.ntru;

import org.bouncycastle.pqc.math.ntru.parameters.NTRUParameterSet;

public abstract class Polynomial
{
    public short[] coeffs;
    protected NTRUParameterSet params;
    
    public Polynomial(final NTRUParameterSet params) {
        this.coeffs = new short[params.n()];
        this.params = params;
    }
    
    static short bothNegativeMask(final short n, final short n2) {
        return (short)((n & n2) >>> 15);
    }
    
    static short mod3(final short n) {
        return (short)((n & 0xFFFF) % 3);
    }
    
    static byte mod3(final byte b) {
        return (byte)((b & 0xFF) % 3);
    }
    
    static int modQ(final int n, final int n2) {
        return n % n2;
    }
    
    public void mod3PhiN() {
        for (int n = this.params.n(), i = 0; i < n; ++i) {
            this.coeffs[i] = mod3((short)(this.coeffs[i] + 2 * this.coeffs[n - 1]));
        }
    }
    
    public void modQPhiN() {
        for (int n = this.params.n(), i = 0; i < n; ++i) {
            this.coeffs[i] -= this.coeffs[n - 1];
        }
    }
    
    public abstract byte[] sqToBytes(final int p0);
    
    public abstract void sqFromBytes(final byte[] p0);
    
    public byte[] rqSumZeroToBytes(final int n) {
        return this.sqToBytes(n);
    }
    
    public void rqSumZeroFromBytes(final byte[] array) {
        final int length = this.coeffs.length;
        this.sqFromBytes(array);
        this.coeffs[length - 1] = 0;
        for (int i = 0; i < this.params.packDegree(); ++i) {
            final short[] coeffs = this.coeffs;
            final int n = length - 1;
            coeffs[n] -= this.coeffs[i];
        }
    }
    
    public byte[] s3ToBytes(final int n) {
        final byte[] array = new byte[n];
        this.s3ToBytes(array, 0);
        return array;
    }
    
    public void s3ToBytes(final byte[] array, int n) {
        final int packDegree = this.params.packDegree();
        int n2;
        int i;
        for (n2 = packDegree - 5, i = 0; i <= n2; i += 5) {
            array[n++] = (byte)((this.coeffs[i + 0] & 0xFF) + (this.coeffs[i + 1] & 0xFF) * 3 + (this.coeffs[i + 2] & 0xFF) * 9 + (this.coeffs[i + 3] & 0xFF) * 27 + (this.coeffs[i + 4] & 0xFF) * 81);
        }
        if (i < packDegree) {
            int n3 = packDegree - 1;
            int n4 = this.coeffs[n3] & 0xFF;
            while (--n3 >= i) {
                n4 = n4 * 3 + (this.coeffs[n3] & 0xFF);
            }
            array[n++] = (byte)n4;
        }
    }
    
    public void s3FromBytes(final byte[] array) {
        final int length = this.coeffs.length;
        for (int i = 0; i < this.params.packDegree() / 5; ++i) {
            final byte b = array[i];
            this.coeffs[5 * i + 0] = b;
            this.coeffs[5 * i + 1] = (short)((b & 0xFF) * 171 >>> 9);
            this.coeffs[5 * i + 2] = (short)((b & 0xFF) * 57 >>> 9);
            this.coeffs[5 * i + 3] = (short)((b & 0xFF) * 19 >>> 9);
            this.coeffs[5 * i + 4] = (short)((b & 0xFF) * 203 >>> 14);
        }
        if (this.params.packDegree() > this.params.packDegree() / 5 * 5) {
            final int n = this.params.packDegree() / 5;
            byte b2 = array[n];
            for (int n2 = 0; 5 * n + n2 < this.params.packDegree(); ++n2) {
                this.coeffs[5 * n + n2] = b2;
                b2 = (byte)((b2 & 0xFF) * 171 >> 9);
            }
        }
        this.coeffs[length - 1] = 0;
        this.mod3PhiN();
    }
    
    public void sqMul(final Polynomial polynomial, final Polynomial polynomial2) {
        this.rqMul(polynomial, polynomial2);
        this.modQPhiN();
    }
    
    public void rqMul(final Polynomial polynomial, final Polynomial polynomial2) {
        for (int length = this.coeffs.length, i = 0; i < length; ++i) {
            this.coeffs[i] = 0;
            for (int j = 1; j < length - i; ++j) {
                final short[] coeffs = this.coeffs;
                final int n = i;
                coeffs[n] += (short)(polynomial.coeffs[i + j] * polynomial2.coeffs[length - j]);
            }
            for (int k = 0; k < i + 1; ++k) {
                final short[] coeffs2 = this.coeffs;
                final int n2 = i;
                coeffs2[n2] += (short)(polynomial.coeffs[i - k] * polynomial2.coeffs[k]);
            }
        }
    }
    
    public void s3Mul(final Polynomial polynomial, final Polynomial polynomial2) {
        this.rqMul(polynomial, polynomial2);
        this.mod3PhiN();
    }
    
    public abstract void lift(final Polynomial p0);
    
    public void rqToS3(final Polynomial polynomial) {
        for (int length = this.coeffs.length, i = 0; i < length; ++i) {
            this.coeffs[i] = (short)modQ(polynomial.coeffs[i] & 0xFFFF, this.params.q());
            final short n = (short)(this.coeffs[i] >>> this.params.logQ() - 1);
            final short[] coeffs = this.coeffs;
            final int n2 = i;
            coeffs[n2] += (short)(n << 1 - (this.params.logQ() & 0x1));
        }
        this.mod3PhiN();
    }
    
    public void r2Inv(final Polynomial polynomial) {
        this.r2Inv(polynomial, this.params.createPolynomial(), this.params.createPolynomial(), this.params.createPolynomial(), this.params.createPolynomial());
    }
    
    public void rqInv(final Polynomial polynomial) {
        this.rqInv(polynomial, this.params.createPolynomial(), this.params.createPolynomial(), this.params.createPolynomial(), this.params.createPolynomial());
    }
    
    public void s3Inv(final Polynomial polynomial) {
        this.s3Inv(polynomial, this.params.createPolynomial(), this.params.createPolynomial(), this.params.createPolynomial(), this.params.createPolynomial());
    }
    
    void r2Inv(final Polynomial polynomial, final Polynomial polynomial2, final Polynomial polynomial3, final Polynomial polynomial4, final Polynomial polynomial5) {
        final int length = this.coeffs.length;
        polynomial5.coeffs[0] = 1;
        for (int i = 0; i < length; ++i) {
            polynomial2.coeffs[i] = 1;
        }
        for (int j = 0; j < length - 1; ++j) {
            polynomial3.coeffs[length - 2 - j] = (short)((polynomial.coeffs[j] ^ polynomial.coeffs[length - 1]) & 0x1);
        }
        polynomial3.coeffs[length - 1] = 0;
        short n = 1;
        for (int k = 0; k < 2 * (length - 1) - 1; ++k) {
            for (int l = length - 1; l > 0; --l) {
                polynomial4.coeffs[l] = polynomial4.coeffs[l - 1];
            }
            polynomial4.coeffs[0] = 0;
            final short n2 = (short)(polynomial3.coeffs[0] & polynomial2.coeffs[0]);
            final short bothNegativeMask = bothNegativeMask((short)(-n), (short)(-polynomial3.coeffs[0]));
            n = (short)((short)(n ^ (bothNegativeMask & (n ^ -n))) + 1);
            for (int n3 = 0; n3 < length; ++n3) {
                final short n4 = (short)(bothNegativeMask & (polynomial2.coeffs[n3] ^ polynomial3.coeffs[n3]));
                final short[] coeffs = polynomial2.coeffs;
                final int n5 = n3;
                coeffs[n5] ^= n4;
                final short[] coeffs2 = polynomial3.coeffs;
                final int n6 = n3;
                coeffs2[n6] ^= n4;
                final short n7 = (short)(bothNegativeMask & (polynomial4.coeffs[n3] ^ polynomial5.coeffs[n3]));
                final short[] coeffs3 = polynomial4.coeffs;
                final int n8 = n3;
                coeffs3[n8] ^= n7;
                final short[] coeffs4 = polynomial5.coeffs;
                final int n9 = n3;
                coeffs4[n9] ^= n7;
            }
            for (int n10 = 0; n10 < length; ++n10) {
                polynomial3.coeffs[n10] ^= (short)(n2 & polynomial2.coeffs[n10]);
            }
            for (int n11 = 0; n11 < length; ++n11) {
                polynomial5.coeffs[n11] ^= (short)(n2 & polynomial4.coeffs[n11]);
            }
            for (int n12 = 0; n12 < length - 1; ++n12) {
                polynomial3.coeffs[n12] = polynomial3.coeffs[n12 + 1];
            }
            polynomial3.coeffs[length - 1] = 0;
        }
        for (int n13 = 0; n13 < length - 1; ++n13) {
            this.coeffs[n13] = polynomial4.coeffs[length - 2 - n13];
        }
        this.coeffs[length - 1] = 0;
    }
    
    void rqInv(final Polynomial polynomial, final Polynomial polynomial2, final Polynomial polynomial3, final Polynomial polynomial4, final Polynomial polynomial5) {
        polynomial2.r2Inv(polynomial);
        this.r2InvToRqInv(polynomial2, polynomial, polynomial3, polynomial4, polynomial5);
    }
    
    private void r2InvToRqInv(final Polynomial polynomial, final Polynomial polynomial2, final Polynomial polynomial3, final Polynomial polynomial4, final Polynomial polynomial5) {
        final int length = this.coeffs.length;
        for (int i = 0; i < length; ++i) {
            polynomial3.coeffs[i] = (short)(-polynomial2.coeffs[i]);
        }
        for (int j = 0; j < length; ++j) {
            this.coeffs[j] = polynomial.coeffs[j];
        }
        polynomial4.rqMul(this, polynomial3);
        final short[] coeffs = polynomial4.coeffs;
        final int n = 0;
        coeffs[n] += 2;
        polynomial5.rqMul(polynomial4, this);
        polynomial4.rqMul(polynomial5, polynomial3);
        final short[] coeffs2 = polynomial4.coeffs;
        final int n2 = 0;
        coeffs2[n2] += 2;
        this.rqMul(polynomial4, polynomial5);
        polynomial4.rqMul(this, polynomial3);
        final short[] coeffs3 = polynomial4.coeffs;
        final int n3 = 0;
        coeffs3[n3] += 2;
        polynomial5.rqMul(polynomial4, this);
        polynomial4.rqMul(polynomial5, polynomial3);
        final short[] coeffs4 = polynomial4.coeffs;
        final int n4 = 0;
        coeffs4[n4] += 2;
        this.rqMul(polynomial4, polynomial5);
    }
    
    void s3Inv(final Polynomial polynomial, final Polynomial polynomial2, final Polynomial polynomial3, final Polynomial polynomial4, final Polynomial polynomial5) {
        final int length = this.coeffs.length;
        polynomial5.coeffs[0] = 1;
        for (int i = 0; i < length; ++i) {
            polynomial2.coeffs[i] = 1;
        }
        for (int j = 0; j < length - 1; ++j) {
            polynomial3.coeffs[length - 2 - j] = mod3((short)((polynomial.coeffs[j] & 0x3) + 2 * (polynomial.coeffs[length - 1] & 0x3)));
        }
        polynomial3.coeffs[length - 1] = 0;
        short n = 1;
        for (int k = 0; k < 2 * (length - 1) - 1; ++k) {
            for (int l = length - 1; l > 0; --l) {
                polynomial4.coeffs[l] = polynomial4.coeffs[l - 1];
            }
            polynomial4.coeffs[0] = 0;
            final short n2 = mod3((byte)(2 * polynomial3.coeffs[0] * polynomial2.coeffs[0]));
            final short bothNegativeMask = bothNegativeMask((short)(-n), (short)(-polynomial3.coeffs[0]));
            n = (short)((short)(n ^ (bothNegativeMask & (n ^ -n))) + 1);
            for (int n3 = 0; n3 < length; ++n3) {
                final short n4 = (short)(bothNegativeMask & (polynomial2.coeffs[n3] ^ polynomial3.coeffs[n3]));
                final short[] coeffs = polynomial2.coeffs;
                final int n5 = n3;
                coeffs[n5] ^= n4;
                final short[] coeffs2 = polynomial3.coeffs;
                final int n6 = n3;
                coeffs2[n6] ^= n4;
                final short n7 = (short)(bothNegativeMask & (polynomial4.coeffs[n3] ^ polynomial5.coeffs[n3]));
                final short[] coeffs3 = polynomial4.coeffs;
                final int n8 = n3;
                coeffs3[n8] ^= n7;
                final short[] coeffs4 = polynomial5.coeffs;
                final int n9 = n3;
                coeffs4[n9] ^= n7;
            }
            for (int n10 = 0; n10 < length; ++n10) {
                polynomial3.coeffs[n10] = mod3((byte)(polynomial3.coeffs[n10] + n2 * polynomial2.coeffs[n10]));
            }
            for (int n11 = 0; n11 < length; ++n11) {
                polynomial5.coeffs[n11] = mod3((byte)(polynomial5.coeffs[n11] + n2 * polynomial4.coeffs[n11]));
            }
            for (int n12 = 0; n12 < length - 1; ++n12) {
                polynomial3.coeffs[n12] = polynomial3.coeffs[n12 + 1];
            }
            polynomial3.coeffs[length - 1] = 0;
        }
        final short n13 = polynomial2.coeffs[0];
        for (int n14 = 0; n14 < length - 1; ++n14) {
            this.coeffs[n14] = mod3((byte)(n13 * polynomial4.coeffs[length - 2 - n14]));
        }
        this.coeffs[length - 1] = 0;
    }
    
    public void z3ToZq() {
        for (int length = this.coeffs.length, i = 0; i < length; ++i) {
            this.coeffs[i] |= (short)(-(this.coeffs[i] >>> 1) & this.params.q() - 1);
        }
    }
    
    public void trinaryZqToZ3() {
        for (int length = this.coeffs.length, i = 0; i < length; ++i) {
            this.coeffs[i] = (short)modQ(this.coeffs[i] & 0xFFFF, this.params.q());
            this.coeffs[i] = (short)(0x3 & (this.coeffs[i] ^ this.coeffs[i] >>> this.params.logQ() - 1));
        }
    }
}
