All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.math.ec.rfc7748.X448Field Maven / Gradle / Ivy

Go to download

The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.8 and up.

There is a newer version: 1.79
Show newest version
package org.bouncycastle.math.ec.rfc7748;

import org.bouncycastle.math.raw.Mod;

public abstract class X448Field
{
    public static final int SIZE = 16;

    private static final int M28 = 0x0FFFFFFF;
    private static final long U32 = 0xFFFFFFFFL;

    private static final int[] P32 = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
        0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };

    protected X448Field() {}

    public static void add(int[] x, int[] y, int[] z)
    {
        for (int i = 0; i < SIZE; ++i)
        {
            z[i] = x[i] + y[i];
        }
    }

    public static void addOne(int[] z)
    {
        z[0] += 1;
    }

    public static void addOne(int[] z, int zOff)
    {
        z[zOff] += 1;
    }

//    public static void apm(int[] x, int[] y, int[] zp, int[] zm)
//    {
//        for (int i = 0; i < SIZE; ++i)
//        {
//            int xi = x[i], yi = y[i];
//            zp[i] = xi + yi;
//            zm[i] = xi - yi;
//        }
//    }

    public static int areEqual(int[] x, int[] y)
    {
        int d = 0;
        for (int i = 0; i < SIZE; ++i)
        {
            d |= x[i] ^ y[i];
        }
        d = (d >>> 1) | (d & 1);
        return (d - 1) >> 31;
    }

    public static boolean areEqualVar(int[] x, int[] y)
    {
        return 0 != areEqual(x, y);
    }

    public static void carry(int[] z)
    {
        int z0 = z[0], z1 = z[1], z2 = z[2], z3 = z[3], z4 = z[4], z5 = z[5], z6 = z[6], z7 = z[7];
        int z8 = z[8], z9 = z[9], z10 = z[10], z11 = z[11], z12 = z[12], z13 = z[13], z14 = z[14], z15 = z[15];

        z1   += (z0 >>> 28); z0 &= M28;
        z5   += (z4 >>> 28); z4 &= M28;
        z9   += (z8 >>> 28); z8 &= M28;
        z13  += (z12 >>> 28); z12 &= M28;

        z2   += (z1 >>> 28); z1 &= M28;
        z6   += (z5 >>> 28); z5 &= M28;
        z10  += (z9 >>> 28); z9 &= M28;
        z14  += (z13 >>> 28); z13 &= M28;

        z3   += (z2 >>> 28); z2 &= M28;
        z7   += (z6 >>> 28); z6 &= M28;
        z11  += (z10 >>> 28); z10 &= M28;
        z15  += (z14 >>> 28); z14 &= M28;

        int t = z15 >>> 28; z15 &= M28;
        z0   += t;
        z8   += t;

        z4   += (z3 >>> 28); z3 &= M28;
        z8   += (z7 >>> 28); z7 &= M28;
        z12  += (z11 >>> 28); z11 &= M28;

        z1   += (z0 >>> 28); z0 &= M28;
        z5   += (z4 >>> 28); z4 &= M28;
        z9   += (z8 >>> 28); z8 &= M28;
        z13  += (z12 >>> 28); z12 &= M28;
        
        z[0] = z0; z[1] = z1; z[2] = z2; z[3] = z3; z[4] = z4; z[5] = z5; z[6] = z6; z[7] = z7;
        z[8] = z8; z[9] = z9; z[10] = z10; z[11] = z11; z[12] = z12; z[13] = z13; z[14] = z14; z[15] = z15;
    }

    public static void cmov(int cond, int[] x, int xOff, int[] z, int zOff)
    {
//        assert 0 == cond || -1 == cond;

        for (int i = 0; i < SIZE; ++i)
        {
            int z_i = z[zOff + i], diff = z_i ^ x[xOff + i];
            z_i ^= (diff & cond);
            z[zOff + i] = z_i;
        }
    }

    public static void cnegate(int negate, int[] z)
    {
//        assert negate >>> 1 == 0;

        int[] t = create();
        sub(t, z, t);

        cmov(-negate, t, 0, z, 0);
    }

    public static void copy(int[] x, int xOff, int[] z, int zOff)
    {
        for (int i = 0; i < SIZE; ++i)
        {
            z[zOff + i] = x[xOff + i];
        }
    }

    public static int[] create()
    {
        return new int[SIZE];
    }

    public static int[] createTable(int n)
    {
        return new int[SIZE * n];
    }

    public static void cswap(int swap, int[] a, int[] b)
    {
//        assert swap >>> 1 == 0;
//        assert a != b;

        int mask = 0 - swap;
        for (int i = 0; i < SIZE; ++i)
        {
            int ai = a[i], bi = b[i];
            int dummy = mask & (ai ^ bi);
            a[i] = ai ^ dummy; 
            b[i] = bi ^ dummy; 
        }
    }

    public static void decode(int[] x, int xOff, int[] z)
    {
        decode224(x, xOff, z, 0);
        decode224(x, xOff + 7, z, 8);
    }

    public static void decode(byte[] x, int[] z)
    {
        decode56(x, 0, z, 0);
        decode56(x, 7, z, 2);
        decode56(x, 14, z, 4);
        decode56(x, 21, z, 6);
        decode56(x, 28, z, 8);
        decode56(x, 35, z, 10);
        decode56(x, 42, z, 12);
        decode56(x, 49, z, 14);
    }

    public static void decode(byte[] x, int xOff, int[] z)
    {
        decode56(x, xOff, z, 0);
        decode56(x, xOff + 7, z, 2);
        decode56(x, xOff + 14, z, 4);
        decode56(x, xOff + 21, z, 6);
        decode56(x, xOff + 28, z, 8);
        decode56(x, xOff + 35, z, 10);
        decode56(x, xOff + 42, z, 12);
        decode56(x, xOff + 49, z, 14);
    }

    public static void decode(byte[] x, int xOff, int[] z, int zOff)
    {
        decode56(x, xOff, z, zOff);
        decode56(x, xOff + 7, z, zOff + 2);
        decode56(x, xOff + 14, z, zOff + 4);
        decode56(x, xOff + 21, z, zOff + 6);
        decode56(x, xOff + 28, z, zOff + 8);
        decode56(x, xOff + 35, z, zOff + 10);
        decode56(x, xOff + 42, z, zOff + 12);
        decode56(x, xOff + 49, z, zOff + 14);
    }

    private static void decode224(int[] x, int xOff, int[] z, int zOff)
    {
        int x0 = x[xOff + 0], x1 = x[xOff + 1], x2 = x[xOff + 2], x3 = x[xOff + 3];
        int x4 = x[xOff + 4], x5 = x[xOff + 5], x6 = x[xOff + 6];

        z[zOff + 0] =  x0                    & M28;
        z[zOff + 1] = (x0 >>> 28 | x1 <<  4) & M28;
        z[zOff + 2] = (x1 >>> 24 | x2 <<  8) & M28;
        z[zOff + 3] = (x2 >>> 20 | x3 << 12) & M28;
        z[zOff + 4] = (x3 >>> 16 | x4 << 16) & M28;
        z[zOff + 5] = (x4 >>> 12 | x5 << 20) & M28;
        z[zOff + 6] = (x5 >>>  8 | x6 << 24) & M28;
        z[zOff + 7] =  x6 >>>  4;
    }

    private static int decode24(byte[] bs, int off)
    {
        int n = bs[  off] & 0xFF;
        n |= (bs[++off] & 0xFF) << 8;
        n |= (bs[++off] & 0xFF) << 16;
        return n;
    }

    private static int decode32(byte[] bs, int off)
    {
        int n = bs[  off] & 0xFF;
        n |= (bs[++off] & 0xFF) << 8;
        n |= (bs[++off] & 0xFF) << 16;
        n |= bs[++off] << 24;
        return n;
    }

    private static void decode56(byte[] bs, int off, int[] z, int zOff)
    {
        int lo = decode32(bs, off);
        int hi = decode24(bs, off + 4);
        z[zOff] = lo & M28;
        z[zOff + 1] = (lo >>> 28) | (hi << 4);
    }

    public static void encode(int[] x, int[] z, int zOff)
    {
        encode224(x, 0, z, zOff);
        encode224(x, 8, z, zOff + 7);
    }

    public static void encode(int[] x, byte[] z)
    {
        encode56(x, 0, z, 0);
        encode56(x, 2, z, 7);
        encode56(x, 4, z, 14);
        encode56(x, 6, z, 21);
        encode56(x, 8, z, 28);
        encode56(x, 10, z, 35);
        encode56(x, 12, z, 42);
        encode56(x, 14, z, 49);
    }

    public static void encode(int[] x, byte[] z, int zOff)
    {
        encode56(x, 0, z, zOff);
        encode56(x, 2, z, zOff + 7);
        encode56(x, 4, z, zOff + 14);
        encode56(x, 6, z, zOff + 21);
        encode56(x, 8, z, zOff + 28);
        encode56(x, 10, z, zOff + 35);
        encode56(x, 12, z, zOff + 42);
        encode56(x, 14, z, zOff + 49);
    }

    public static void encode(int[] x, int xOff, byte[] z, int zOff)
    {
        encode56(x, xOff, z, zOff);
        encode56(x, xOff + 2, z, zOff + 7);
        encode56(x, xOff + 4, z, zOff + 14);
        encode56(x, xOff + 6, z, zOff + 21);
        encode56(x, xOff + 8, z, zOff + 28);
        encode56(x, xOff + 10, z, zOff + 35);
        encode56(x, xOff + 12, z, zOff + 42);
        encode56(x, xOff + 14, z, zOff + 49);
    }

    private static void encode224(int[] x, int xOff, int[] is, int off)
    {
        int x0 = x[xOff + 0], x1 = x[xOff + 1], x2 = x[xOff + 2], x3 = x[xOff + 3];
        int x4 = x[xOff + 4], x5 = x[xOff + 5], x6 = x[xOff + 6], x7 = x[xOff + 7];

        is[off + 0] =  x0         | (x1 << 28);
        is[off + 1] = (x1 >>>  4) | (x2 << 24);
        is[off + 2] = (x2 >>>  8) | (x3 << 20);
        is[off + 3] = (x3 >>> 12) | (x4 << 16);
        is[off + 4] = (x4 >>> 16) | (x5 << 12);
        is[off + 5] = (x5 >>> 20) | (x6 <<  8);
        is[off + 6] = (x6 >>> 24) | (x7 <<  4);
    }

    private static void encode24(int n, byte[] bs, int off)
    {
        bs[  off] = (byte)(n       );
        bs[++off] = (byte)(n >>>  8);
        bs[++off] = (byte)(n >>> 16);
    }

    private static void encode32(int n, byte[] bs, int off)
    {
        bs[  off] = (byte)(n       );
        bs[++off] = (byte)(n >>>  8);
        bs[++off] = (byte)(n >>> 16);
        bs[++off] = (byte)(n >>> 24);
    }

    private static void encode56(int[] x, int xOff, byte[] bs, int off)
    {
        int lo = x[xOff], hi = x[xOff + 1];
        encode32(lo | (hi << 28), bs, off);
        encode24(hi >>> 4, bs, off + 4);
    }

    public static void inv(int[] x, int[] z)
    {
//        int[] t = create();
//        powPm3d4(x, t);
//        sqr(t, 2, t);
//        mul(t, x, z);

        int[] t = create();
        int[] u = new int[14];

        copy(x, 0, t, 0);
        normalize(t);
        encode(t, u, 0);

        Mod.modOddInverse(P32, u, u);

        decode(u, 0, z);
    }

    public static void invVar(int[] x, int[] z)
    {
        int[] t = create();
        int[] u = new int[14];

        copy(x, 0, t, 0);
        normalize(t);
        encode(t, u, 0);

        Mod.modOddInverseVar(P32, u, u);

        decode(u, 0, z);
    }

    public static int isOne(int[] x)
    {
        int d = x[0] ^ 1;
        for (int i = 1; i < SIZE; ++i)
        {
            d |= x[i];
        }
        d = (d >>> 1) | (d & 1);
        return (d - 1) >> 31;
    }

    public static boolean isOneVar(int[] x)
    {
        return 0 != isOne(x);
    }

    public static int isZero(int[] x)
    {
        int d = 0;
        for (int i = 0; i < SIZE; ++i)
        {
            d |= x[i];
        }
        d = (d >>> 1) | (d & 1);
        return (d - 1) >> 31;
    }

    public static boolean isZeroVar(int[] x)
    {
        return 0 != isZero(x);
    }

    public static void mul(int[] x, int y, int[] z)
    {
        int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7];
        int x8 = x[8], x9 = x[9], x10 = x[10], x11 = x[11], x12 = x[12], x13 = x[13], x14 = x[14], x15 = x[15];

        int z1, z5, z9, z13;
        long c, d, e, f;

        c     = (long)x1 * y;
        z1    = (int)c & M28; c >>>= 28;
        d     = (long)x5 * y;
        z5    = (int)d & M28; d >>>= 28;
        e     = (long)x9 * y;
        z9    = (int)e & M28; e >>>= 28;
        f     = (long)x13 * y;
        z13   = (int)f & M28; f >>>= 28;

        c    += (long)x2 * y;
        z[2]  = (int)c & M28; c >>>= 28;
        d    += (long)x6 * y;
        z[6]  = (int)d & M28; d >>>= 28;
        e    += (long)x10 * y;
        z[10] = (int)e & M28; e >>>= 28;
        f    += (long)x14 * y;
        z[14] = (int)f & M28; f >>>= 28;

        c    += (long)x3 * y;
        z[3]  = (int)c & M28; c >>>= 28;
        d    += (long)x7 * y;
        z[7]  = (int)d & M28; d >>>= 28;
        e    += (long)x11 * y;
        z[11] = (int)e & M28; e >>>= 28;
        f    += (long)x15 * y;
        z[15] = (int)f & M28; f >>>= 28;

        d    += f;

        c    += (long)x4 * y;
        z[4]  = (int)c & M28; c >>>= 28;
        d    += (long)x8 * y;
        z[8]  = (int)d & M28; d >>>= 28;
        e    += (long)x12 * y;
        z[12] = (int)e & M28; e >>>= 28;
        f    += (long)x0 * y;
        z[0]  = (int)f & M28; f >>>= 28;

        z[1]  = z1 + (int)f;
        z[5]  = z5 + (int)c;
        z[9]  = z9 + (int)d;
        z[13] = z13 + (int)e;
    }

    public static void mul(int[] x, int[] y, int[] z)
    {
        int x0 = x[0];
        int x1 = x[1];
        int x2 = x[2];
        int x3 = x[3];
        int x4 = x[4];
        int x5 = x[5];
        int x6 = x[6];
        int x7 = x[7];

        int u0 = x[8];
        int u1 = x[9];
        int u2 = x[10];
        int u3 = x[11];
        int u4 = x[12];
        int u5 = x[13];
        int u6 = x[14];
        int u7 = x[15];

        int y0 = y[0];
        int y1 = y[1];
        int y2 = y[2];
        int y3 = y[3];
        int y4 = y[4];
        int y5 = y[5];
        int y6 = y[6];
        int y7 = y[7];

        int v0 = y[8];
        int v1 = y[9];
        int v2 = y[10];
        int v3 = y[11];
        int v4 = y[12];
        int v5 = y[13];
        int v6 = y[14];
        int v7 = y[15];

        int s0 = x0 + u0;
        int s1 = x1 + u1;
        int s2 = x2 + u2;
        int s3 = x3 + u3;
        int s4 = x4 + u4;
        int s5 = x5 + u5;
        int s6 = x6 + u6;
        int s7 = x7 + u7;

        int t0 = y0 + v0;
        int t1 = y1 + v1;
        int t2 = y2 + v2;
        int t3 = y3 + v3;
        int t4 = y4 + v4;
        int t5 = y5 + v5;
        int t6 = y6 + v6;
        int t7 = y7 + v7;

        int z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13, z14, z15;
        long c, d;

        long f0  = (long)x0 * y0;
        long f8  = (long)x7 * y1
                 + (long)x6 * y2
                 + (long)x5 * y3
                 + (long)x4 * y4
                 + (long)x3 * y5
                 + (long)x2 * y6
                 + (long)x1 * y7;
        long g0  = (long)u0 * v0;
        long g8  = (long)u7 * v1
                 + (long)u6 * v2
                 + (long)u5 * v3
                 + (long)u4 * v4
                 + (long)u3 * v5
                 + (long)u2 * v6
                 + (long)u1 * v7;
        long h0  = (long)s0 * t0;
        long h8  = (long)s7 * t1
                 + (long)s6 * t2
                 + (long)s5 * t3
                 + (long)s4 * t4
                 + (long)s3 * t5
                 + (long)s2 * t6
                 + (long)s1 * t7;

        c        = f0 + g0 + h8 - f8;
        z0       = (int)c & M28; c >>>= 28;
        d        = g8 + h0 - f0 + h8;
        z8       = (int)d & M28; d >>>= 28;

        long f1  = (long)x1 * y0
                 + (long)x0 * y1;
        long f9  = (long)x7 * y2
                 + (long)x6 * y3
                 + (long)x5 * y4
                 + (long)x4 * y5
                 + (long)x3 * y6
                 + (long)x2 * y7;
        long g1  = (long)u1 * v0
                 + (long)u0 * v1;
        long g9  = (long)u7 * v2
                 + (long)u6 * v3
                 + (long)u5 * v4
                 + (long)u4 * v5
                 + (long)u3 * v6
                 + (long)u2 * v7;
        long h1  = (long)s1 * t0
                 + (long)s0 * t1;
        long h9  = (long)s7 * t2
                 + (long)s6 * t3
                 + (long)s5 * t4
                 + (long)s4 * t5
                 + (long)s3 * t6
                 + (long)s2 * t7;

        c       += f1 + g1 + h9 - f9;
        z1       = (int)c & M28; c >>>= 28;
        d       += g9 + h1 - f1 + h9;
        z9       = (int)d & M28; d >>>= 28;

        long f2  = (long)x2 * y0
                 + (long)x1 * y1
                 + (long)x0 * y2;
        long f10 = (long)x7 * y3
                 + (long)x6 * y4
                 + (long)x5 * y5
                 + (long)x4 * y6
                 + (long)x3 * y7;
        long g2  = (long)u2 * v0
                 + (long)u1 * v1
                 + (long)u0 * v2;
        long g10 = (long)u7 * v3
                 + (long)u6 * v4
                 + (long)u5 * v5
                 + (long)u4 * v6
                 + (long)u3 * v7;
        long h2  = (long)s2 * t0
                 + (long)s1 * t1
                 + (long)s0 * t2;
        long h10 = (long)s7 * t3
                 + (long)s6 * t4
                 + (long)s5 * t5
                 + (long)s4 * t6
                 + (long)s3 * t7;

        c       += f2 + g2 + h10 - f10;
        z2       = (int)c & M28; c >>>= 28;
        d       += g10 + h2 - f2 + h10;
        z10      = (int)d & M28; d >>>= 28;

        long f3  = (long)x3 * y0
                 + (long)x2 * y1
                 + (long)x1 * y2
                 + (long)x0 * y3;
        long f11 = (long)x7 * y4
                 + (long)x6 * y5
                 + (long)x5 * y6
                 + (long)x4 * y7;
        long g3  = (long)u3 * v0
                 + (long)u2 * v1
                 + (long)u1 * v2
                 + (long)u0 * v3;
        long g11 = (long)u7 * v4
                 + (long)u6 * v5
                 + (long)u5 * v6
                 + (long)u4 * v7;
        long h3  = (long)s3 * t0
                 + (long)s2 * t1
                 + (long)s1 * t2
                 + (long)s0 * t3;
        long h11 = (long)s7 * t4
                 + (long)s6 * t5
                 + (long)s5 * t6
                 + (long)s4 * t7;

        c       += f3 + g3 + h11 - f11;
        z3       = (int)c & M28; c >>>= 28;
        d       += g11 + h3 - f3 + h11;
        z11      = (int)d & M28; d >>>= 28;

        long f4  = (long)x4 * y0
                 + (long)x3 * y1
                 + (long)x2 * y2
                 + (long)x1 * y3
                 + (long)x0 * y4;
        long f12 = (long)x7 * y5
                 + (long)x6 * y6
                 + (long)x5 * y7;
        long g4  = (long)u4 * v0
                 + (long)u3 * v1
                 + (long)u2 * v2
                 + (long)u1 * v3
                 + (long)u0 * v4;
        long g12 = (long)u7 * v5
                 + (long)u6 * v6
                 + (long)u5 * v7;
        long h4  = (long)s4 * t0
                 + (long)s3 * t1
                 + (long)s2 * t2
                 + (long)s1 * t3
                 + (long)s0 * t4;
        long h12 = (long)s7 * t5
                 + (long)s6 * t6
                 + (long)s5 * t7;

        c       += f4 + g4 + h12 - f12;
        z4       = (int)c & M28; c >>>= 28;
        d       += g12 + h4 - f4 + h12;
        z12      = (int)d & M28; d >>>= 28;

        long f5  = (long)x5 * y0
                 + (long)x4 * y1
                 + (long)x3 * y2
                 + (long)x2 * y3
                 + (long)x1 * y4
                 + (long)x0 * y5;
        long f13 = (long)x7 * y6
                 + (long)x6 * y7;
        long g5  = (long)u5 * v0
                 + (long)u4 * v1
                 + (long)u3 * v2
                 + (long)u2 * v3
                 + (long)u1 * v4
                 + (long)u0 * v5;
        long g13 = (long)u7 * v6
                 + (long)u6 * v7;
        long h5  = (long)s5 * t0
                 + (long)s4 * t1
                 + (long)s3 * t2
                 + (long)s2 * t3
                 + (long)s1 * t4
                 + (long)s0 * t5;
        long h13 = (long)s7 * t6
                 + (long)s6 * t7;

        c       += f5 + g5 + h13 - f13;
        z5       = (int)c & M28; c >>>= 28;
        d       += g13 + h5 - f5 + h13;
        z13      = (int)d & M28; d >>>= 28;

        long f6  = (long)x6 * y0
                 + (long)x5 * y1
                 + (long)x4 * y2
                 + (long)x3 * y3
                 + (long)x2 * y4
                 + (long)x1 * y5
                 + (long)x0 * y6;
        long f14 = (long)x7 * y7;
        long g6  = (long)u6 * v0
                 + (long)u5 * v1
                 + (long)u4 * v2
                 + (long)u3 * v3
                 + (long)u2 * v4
                 + (long)u1 * v5
                 + (long)u0 * v6;
        long g14 = (long)u7 * v7;
        long h6  = (long)s6 * t0
                 + (long)s5 * t1
                 + (long)s4 * t2
                 + (long)s3 * t3
                 + (long)s2 * t4
                 + (long)s1 * t5
                 + (long)s0 * t6;
        long h14 = (long)s7 * t7;

        c       += f6 + g6 + h14 - f14;
        z6       = (int)c & M28; c >>>= 28;
        d       += g14 + h6 - f6 + h14;
        z14      = (int)d & M28; d >>>= 28;

        long f7  = (long)x7 * y0
                 + (long)x6 * y1
                 + (long)x5 * y2
                 + (long)x4 * y3
                 + (long)x3 * y4
                 + (long)x2 * y5
                 + (long)x1 * y6
                 + (long)x0 * y7;
        long g7  = (long)u7 * v0
                 + (long)u6 * v1
                 + (long)u5 * v2
                 + (long)u4 * v3
                 + (long)u3 * v4
                 + (long)u2 * v5
                 + (long)u1 * v6
                 + (long)u0 * v7;
        long h7  = (long)s7 * t0
                 + (long)s6 * t1
                 + (long)s5 * t2
                 + (long)s4 * t3
                 + (long)s3 * t4
                 + (long)s2 * t5
                 + (long)s1 * t6
                 + (long)s0 * t7;

        c       += f7 + g7;
        z7       = (int)c & M28; c >>>= 28;
        d       += h7 - f7;
        z15      = (int)d & M28; d >>>= 28;

        c       += d;

        c       += z8;
        z8       = (int)c & M28; c >>>= 28;
        d       += z0;
        z0       = (int)d & M28; d >>>= 28;
        z9      += (int)c;
        z1      += (int)d;

        z[0] = z0;
        z[1] = z1;
        z[2] = z2;
        z[3] = z3;
        z[4] = z4;
        z[5] = z5;
        z[6] = z6;
        z[7] = z7;
        z[8] = z8;
        z[9] = z9;
        z[10] = z10;
        z[11] = z11;
        z[12] = z12;
        z[13] = z13;
        z[14] = z14;
        z[15] = z15;
    }

    public static void negate(int[] x, int[] z)
    {
        int[] zero = create();
        sub(zero, x, z);
    }

    public static void normalize(int[] z)
    {
//        int x = ((z[15] >>> (28 - 1)) & 1);
        reduce(z, 1);
        reduce(z, -1);
//        assert z[15] >>> 28 == 0;
    }

    public static void one(int[] z)
    {
        z[0] = 1;
        for (int i = 1; i < SIZE; ++i)
        {
            z[i] = 0;
        }
    }

    private static void powPm3d4(int[] x, int[] z)
    {
        // z = x^((p-3)/4) = x^(2^446 - 2^222 - 1)
        // (223 1s) (1 0s) (222 1s)
        // Addition chain: 1 2 3 6 9 18 19 37 74 111 [222] [223]
        int[] x2 = create();    sqr(x, x2);             mul(x, x2, x2);
        int[] x3 = create();    sqr(x2, x3);            mul(x, x3, x3);
        int[] x6 = create();    sqr(x3, 3, x6);         mul(x3, x6, x6);
        int[] x9 = create();    sqr(x6, 3, x9);         mul(x3, x9, x9);
        int[] x18 = create();   sqr(x9, 9, x18);        mul(x9, x18, x18);
        int[] x19 = create();   sqr(x18, x19);          mul(x, x19, x19);
        int[] x37 = create();   sqr(x19, 18, x37);      mul(x18, x37, x37);
        int[] x74 = create();   sqr(x37, 37, x74);      mul(x37, x74, x74);
        int[] x111 = create();  sqr(x74, 37, x111);     mul(x37, x111, x111);
        int[] x222 = create();  sqr(x111, 111, x222);   mul(x111, x222, x222);
        int[] x223 = create();  sqr(x222, x223);        mul(x, x223, x223);

        int[] t = create();
        sqr(x223, 223, t);
        mul(t, x222, z);
    }

    private static void reduce(int[] z, int x)
    {
        int t = z[15], z15 = t & M28;
        t = (t >>> 28) + x;

        long cc = t;
        for (int i = 0; i < 8; ++i)
        {
            cc += z[i] & U32; z[i] = (int)cc & M28; cc >>= 28;
        }
        cc += t;
        for (int i = 8; i < 15; ++i)
        {
            cc += z[i] & U32; z[i] = (int)cc & M28; cc >>= 28;
        }
        z[15] = z15 + (int)cc;
    }

    public static void sqr(int[] x, int[] z)
    {
        int x0 = x[0];
        int x1 = x[1];
        int x2 = x[2];
        int x3 = x[3];
        int x4 = x[4];
        int x5 = x[5];
        int x6 = x[6];
        int x7 = x[7];

        int u0 = x[8];
        int u1 = x[9];
        int u2 = x[10];
        int u3 = x[11];
        int u4 = x[12];
        int u5 = x[13];
        int u6 = x[14];
        int u7 = x[15];

        int x0_2 = x0 * 2;
        int x1_2 = x1 * 2;
        int x2_2 = x2 * 2;
        int x3_2 = x3 * 2;
        int x4_2 = x4 * 2;
        int x5_2 = x5 * 2;
        int x6_2 = x6 * 2;

        int u0_2 = u0 * 2;
        int u1_2 = u1 * 2;
        int u2_2 = u2 * 2;
        int u3_2 = u3 * 2;
        int u4_2 = u4 * 2;
        int u5_2 = u5 * 2;
        int u6_2 = u6 * 2;

        int s0 = x0 + u0;
        int s1 = x1 + u1;
        int s2 = x2 + u2;
        int s3 = x3 + u3;
        int s4 = x4 + u4;
        int s5 = x5 + u5;
        int s6 = x6 + u6;
        int s7 = x7 + u7;

        /*
         * NOTE: Currently s1_2 and/or s5_2 might reach 0x80000000 (because our carry chains land at
         * x[1], x[5], x[9], x[13]). So extra care is needed to ensure they are treated as unsigned
         * multiplicands below. To avoid depending on the precise carry chains, we assume this
         * affects all the s?_2 variables.
         */
        int s0_2 = s0 * 2;
        int s1_2 = s1 * 2;
        int s2_2 = s2 * 2;
        int s3_2 = s3 * 2;
        int s4_2 = s4 * 2;
        int s5_2 = s5 * 2;
        int s6_2 = s6 * 2;

        int z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13, z14, z15;
        long c, d;

        long f0  = (long)x0 * x0;
        long f8  = (long)x7 * x1_2
                 + (long)x6 * x2_2
                 + (long)x5 * x3_2
                 + (long)x4 * x4;
        long g0  = (long)u0 * u0;
        long g8  = (long)u7 * u1_2
                 + (long)u6 * u2_2
                 + (long)u5 * u3_2
                 + (long)u4 * u4;
        long h0  = (long)s0 * s0;
        long h8  = (long)s7 * (s1_2 & U32)
                 + (long)s6 * (s2_2 & U32)
                 + (long)s5 * (s3_2 & U32)
                 + (long)s4 * s4;

        c        = f0 + g0 + h8 - f8;
        z0       = (int)c & M28; c >>>= 28;
        d        = g8 + h0 - f0 + h8;
        z8       = (int)d & M28; d >>>= 28;

        long f1  = (long)x1 * x0_2;
        long f9  = (long)x7 * x2_2
                 + (long)x6 * x3_2
                 + (long)x5 * x4_2;
        long g1  = (long)u1 * u0_2;
        long g9  = (long)u7 * u2_2
                 + (long)u6 * u3_2
                 + (long)u5 * u4_2;
        long h1  = (long)s1 * (s0_2 & U32);
        long h9  = (long)s7 * (s2_2 & U32)
                 + (long)s6 * (s3_2 & U32)
                 + (long)s5 * (s4_2 & U32);

        c       += f1 + g1 + h9 - f9;
        z1       = (int)c & M28; c >>>= 28;
        d       += g9 + h1 - f1 + h9;
        z9       = (int)d & M28; d >>>= 28;

        long f2  = (long)x2 * x0_2
                 + (long)x1 * x1;
        long f10 = (long)x7 * x3_2
                 + (long)x6 * x4_2
                 + (long)x5 * x5;
        long g2  = (long)u2 * u0_2
                 + (long)u1 * u1;
        long g10 = (long)u7 * u3_2
                 + (long)u6 * u4_2
                 + (long)u5 * u5;
        long h2  = (long)s2 * (s0_2 & U32)
                 + (long)s1 * s1;
        long h10 = (long)s7 * (s3_2 & U32)
                 + (long)s6 * (s4_2 & U32)
                 + (long)s5 * s5;

        c       += f2 + g2 + h10 - f10;
        z2       = (int)c & M28; c >>>= 28;
        d       += g10 + h2 - f2 + h10;
        z10      = (int)d & M28; d >>>= 28;

        long f3  = (long)x3 * x0_2
                 + (long)x2 * x1_2;
        long f11 = (long)x7 * x4_2
                 + (long)x6 * x5_2;
        long g3  = (long)u3 * u0_2
                 + (long)u2 * u1_2;
        long g11 = (long)u7 * u4_2
                 + (long)u6 * u5_2;
        long h3  = (long)s3 * (s0_2 & U32)
                 + (long)s2 * (s1_2 & U32);
        long h11 = (long)s7 * (s4_2 & U32)
                 + (long)s6 * (s5_2 & U32);

        c       += f3 + g3 + h11 - f11;
        z3       = (int)c & M28; c >>>= 28;
        d       += g11 + h3 - f3 + h11;
        z11      = (int)d & M28; d >>>= 28;

        long f4  = (long)x4 * x0_2
                 + (long)x3 * x1_2
                 + (long)x2 * x2;
        long f12 = (long)x7 * x5_2
                 + (long)x6 * x6;
        long g4  = (long)u4 * u0_2
                 + (long)u3 * u1_2
                 + (long)u2 * u2;
        long g12 = (long)u7 * u5_2
                 + (long)u6 * u6;
        long h4  = (long)s4 * (s0_2 & U32)
                 + (long)s3 * (s1_2 & U32)
                 + (long)s2 * s2;
        long h12 = (long)s7 * (s5_2 & U32)
                 + (long)s6 * s6;

        c       += f4 + g4 + h12 - f12;
        z4       = (int)c & M28; c >>>= 28;
        d       += g12 + h4 - f4 + h12;
        z12      = (int)d & M28; d >>>= 28;

        long f5  = (long)x5 * x0_2
                 + (long)x4 * x1_2
                 + (long)x3 * x2_2;
        long f13 = (long)x7 * x6_2;
        long g5  = (long)u5 * u0_2
                 + (long)u4 * u1_2
                 + (long)u3 * u2_2;
        long g13 = (long)u7 * u6_2;
        long h5  = (long)s5 * (s0_2 & U32)
                 + (long)s4 * (s1_2 & U32)
                 + (long)s3 * (s2_2 & U32);
        long h13 = (long)s7 * (s6_2 & U32);

        c       += f5 + g5 + h13 - f13;
        z5       = (int)c & M28; c >>>= 28;
        d       += g13 + h5 - f5 + h13;
        z13      = (int)d & M28; d >>>= 28;

        long f6  = (long)x6 * x0_2
                 + (long)x5 * x1_2
                 + (long)x4 * x2_2
                 + (long)x3 * x3;
        long f14 = (long)x7 * x7;
        long g6  = (long)u6 * u0_2
                 + (long)u5 * u1_2
                 + (long)u4 * u2_2
                 + (long)u3 * u3;
        long g14 = (long)u7 * u7;
        long h6  = (long)s6 * (s0_2 & U32)
                 + (long)s5 * (s1_2 & U32)
                 + (long)s4 * (s2_2 & U32)
                 + (long)s3 * s3;
        long h14 = (long)s7 * s7;

        c       += f6 + g6 + h14 - f14;
        z6       = (int)c & M28; c >>>= 28;
        d       += g14 + h6 - f6 + h14;
        z14      = (int)d & M28; d >>>= 28;

        long f7  = (long)x7 * x0_2
                 + (long)x6 * x1_2
                 + (long)x5 * x2_2
                 + (long)x4 * x3_2;
        long g7  = (long)u7 * u0_2
                 + (long)u6 * u1_2
                 + (long)u5 * u2_2
                 + (long)u4 * u3_2;
        long h7  = (long)s7 * (s0_2 & U32)
                 + (long)s6 * (s1_2 & U32)
                 + (long)s5 * (s2_2 & U32)
                 + (long)s4 * (s3_2 & U32);

        c       += f7 + g7;
        z7       = (int)c & M28; c >>>= 28;
        d       += h7 - f7;
        z15      = (int)d & M28; d >>>= 28;

        c       += d;

        c       += z8;
        z8       = (int)c & M28; c >>>= 28;
        d       += z0;
        z0       = (int)d & M28; d >>>= 28;
        z9      += (int)c;
        z1      += (int)d;

        z[0] = z0;
        z[1] = z1;
        z[2] = z2;
        z[3] = z3;
        z[4] = z4;
        z[5] = z5;
        z[6] = z6;
        z[7] = z7;
        z[8] = z8;
        z[9] = z9;
        z[10] = z10;
        z[11] = z11;
        z[12] = z12;
        z[13] = z13;
        z[14] = z14;
        z[15] = z15;
    }

    public static void sqr(int[] x, int n, int[] z)
    {
//        assert n > 0;

        sqr(x, z);

        while (--n > 0)
        {
            sqr(z, z);
        }
    }

    public static boolean sqrtRatioVar(int[] u, int[] v, int[] z)
    {
        int[] u3v = create();
        int[] u5v3 = create();

        sqr(u, u3v);
        mul(u3v, v, u3v);
        sqr(u3v, u5v3);
        mul(u3v, u, u3v);
        mul(u5v3, u, u5v3);
        mul(u5v3, v, u5v3);

        int[] x = create();
        powPm3d4(u5v3, x);
        mul(x, u3v, x);

        int[] t = create();
        sqr(x, t);
        mul(t, v, t);

        sub(u, t, t);
        normalize(t);

        if (isZeroVar(t))
        {
            copy(x, 0, z, 0);
            return true;
        }

        return false;
    }

    public static void sub(int[] x, int[] y, int[] z)
    {
        int x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7];
        int x8 = x[8], x9 = x[9], x10 = x[10], x11 = x[11], x12 = x[12], x13 = x[13], x14 = x[14], x15 = x[15];
        int y0 = y[0], y1 = y[1], y2 = y[2], y3 = y[3], y4 = y[4], y5 = y[5], y6 = y[6], y7 = y[7];
        int y8 = y[8], y9 = y[9], y10 = y[10], y11 = y[11], y12 = y[12], y13 = y[13], y14 = y[14], y15 = y[15];

        int z0 = x0 + 0x1FFFFFFE - y0;
        int z1 = x1 + 0x1FFFFFFE - y1;
        int z2 = x2 + 0x1FFFFFFE - y2;
        int z3 = x3 + 0x1FFFFFFE - y3;
        int z4 = x4 + 0x1FFFFFFE - y4;
        int z5 = x5 + 0x1FFFFFFE - y5;
        int z6 = x6 + 0x1FFFFFFE - y6;
        int z7 = x7 + 0x1FFFFFFE - y7;
        int z8 = x8 + 0x1FFFFFFC - y8;
        int z9 = x9 + 0x1FFFFFFE - y9;
        int z10 = x10 + 0x1FFFFFFE - y10;
        int z11 = x11 + 0x1FFFFFFE - y11;
        int z12 = x12 + 0x1FFFFFFE - y12;
        int z13 = x13 + 0x1FFFFFFE - y13;
        int z14 = x14 + 0x1FFFFFFE - y14;
        int z15 = x15 + 0x1FFFFFFE - y15;

        z2   += z1 >>> 28; z1 &= M28;
        z6   += z5 >>> 28; z5 &= M28;
        z10  += z9 >>> 28; z9 &= M28;
        z14  += z13 >>> 28; z13 &= M28;

        z3   += z2 >>> 28; z2 &= M28;
        z7   += z6 >>> 28; z6 &= M28;
        z11  += z10 >>> 28; z10 &= M28;
        z15  += z14 >>> 28; z14 &= M28;

        int t = z15 >>> 28; z15 &= M28;
        z0   += t;
        z8   += t;

        z4   += z3 >>> 28; z3 &= M28;
        z8   += z7 >>> 28; z7 &= M28;
        z12  += z11 >>> 28; z11 &= M28;

        z1   += z0 >>> 28; z0 &= M28;
        z5   += z4 >>> 28; z4 &= M28;
        z9   += z8 >>> 28; z8 &= M28;
        z13  += z12 >>> 28; z12 &= M28;

        z[0] = z0;
        z[1] = z1;
        z[2] = z2;
        z[3] = z3;
        z[4] = z4;
        z[5] = z5;
        z[6] = z6;
        z[7] = z7;
        z[8] = z8;
        z[9] = z9;
        z[10] = z10;
        z[11] = z11;
        z[12] = z12;
        z[13] = z13;
        z[14] = z14;
        z[15] = z15;
    }

    public static void subOne(int[] z)
    {
        int[] one = create();
        one[0] = 1;

        sub(z, one, z);
    }

    public static void zero(int[] z)
    {
        for (int i = 0; i < SIZE; ++i)
        {
            z[i] = 0;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy