changeset 8842:3ca8785e4e0d

8208648: ECC Field Arithmetic Enhancements Summary: internal library enhancements to support ECC implementatation Reviewed-by: jnimeh, andrew Contributed-by: David Alvarez <alvdavi@amazon.com>
author andrew
date Sat, 13 Jul 2019 16:49:00 +0100
parents c82edcbdc73e
children e39cbf4c29c3
files src/share/classes/sun/security/util/ArrayUtil.java src/share/classes/sun/security/util/math/MutableIntegerModuloP.java src/share/classes/sun/security/util/math/intpoly/FieldGen.jsh src/share/classes/sun/security/util/math/intpoly/IntegerPolynomial.java src/share/classes/sun/security/util/math/intpoly/IntegerPolynomial1305.java src/share/classes/sun/security/util/math/intpoly/IntegerPolynomial25519.java src/share/classes/sun/security/util/math/intpoly/IntegerPolynomial448.java src/share/classes/sun/security/util/math/intpoly/IntegerPolynomialP256.java src/share/classes/sun/security/util/math/intpoly/IntegerPolynomialP384.java src/share/classes/sun/security/util/math/intpoly/IntegerPolynomialP521.java src/share/classes/sun/security/util/math/intpoly/P256OrderField.java src/share/classes/sun/security/util/math/intpoly/P384OrderField.java src/share/classes/sun/security/util/math/intpoly/P521OrderField.java src/share/classes/sun/security/util/math/intpoly/header.txt test/sun/security/util/math/BigIntegerModuloP.java test/sun/security/util/math/TestIntegerModuloP.java
diffstat 16 files changed, 5280 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/ArrayUtil.java	Sat Jul 13 16:49:00 2019 +0100
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.util;
+
+/**
+ * This class holds the various utility methods for array range checks.
+ */
+
+public final class ArrayUtil {
+
+    private static void swap(byte[] arr, int i, int j) {
+        byte tmp = arr[i];
+        arr[i] = arr[j];
+        arr[j] = tmp;
+    }
+
+    public static void reverse(byte [] arr) {
+        int i = 0;
+        int j = arr.length - 1;
+
+        while (i < j) {
+            swap(arr, i, j);
+            i++;
+            j--;
+        }
+    }
+}
+
--- a/src/share/classes/sun/security/util/math/MutableIntegerModuloP.java	Sat Jul 13 15:17:33 2019 +0100
+++ b/src/share/classes/sun/security/util/math/MutableIntegerModuloP.java	Sat Jul 13 16:49:00 2019 +0100
@@ -41,6 +41,18 @@
 public interface MutableIntegerModuloP extends IntegerModuloP {
 
     /**
+     * Set this value to the value of b when set has the value 1.
+     * No change is made to this element when set has the value 0. The
+     * result is undefined when set has a value other than 0 or 1. The set
+     * parameter is an int (rather than boolean) to allow the implementation
+     * to perform the assignment using branch-free integer arithmetic.
+     *
+     * @param b the element to conditionally swap with
+     * @param set an int that determines whether to set
+     */
+    void conditionalSet(IntegerModuloP b, int set);
+
+    /**
      * Swap the value of this with the value of b when swap has the value 1.
      * No change is made to either element when swap has the value 0. The
      * result is undefined when swap has a value other than 0 or 1. The swap
@@ -131,5 +143,20 @@
      * @return this
      */
     MutableIntegerModuloP setProduct(SmallValue v);
+
+    /**
+     * Set the value of this element equal to 0 - this.
+     *
+     * @return this
+     */
+    MutableIntegerModuloP setAdditiveInverse();
+
+    /**
+     * Some implementations required reduction operations to be requested
+     * by the client at certain times. This method reduces the representation.
+     *
+     * @return this
+     */
+    MutableIntegerModuloP setReduced();
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/math/intpoly/FieldGen.jsh	Sat Jul 13 16:49:00 2019 +0100
@@ -0,0 +1,851 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * This file is used to generated optimized finite field implementations.
+ * Required settings are included in the file. To generate, use jshell:
+ * jshell < FieldGen.jsh
+ */
+
+import java.io.*;
+import java.math.BigInteger;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+
+public class FieldGen {
+
+    static FieldParams Curve25519 = new FieldParams("IntegerPolynomial25519", 26, 10, 1, 255,
+    Arrays.asList(
+    new Term(0, -19)
+    ),
+    Curve25519CrSequence(), simpleSmallCrSequence(10)
+    );
+
+    private static List<CarryReduce> Curve25519CrSequence() {
+        List<CarryReduce> result = new ArrayList<CarryReduce>();
+
+        // reduce(7,2)
+        result.add(new Reduce(17));
+        result.add(new Reduce(18));
+
+        // carry(8,2)
+        result.add(new Carry(8));
+        result.add(new Carry(9));
+
+        // reduce(0,7)
+        for (int i = 10; i < 17; i++) {
+            result.add(new Reduce(i));
+        }
+
+        // carry(0,9)
+        result.addAll(fullCarry(10));
+
+        return result;
+    }
+
+    static FieldParams Curve448 = new FieldParams("IntegerPolynomial448", 28, 16, 1, 448,
+    Arrays.asList(
+    new Term(224, -1),
+    new Term(0, -1)
+    ),
+    Curve448CrSequence(), simpleSmallCrSequence(16)
+    );
+
+    private static List<CarryReduce> Curve448CrSequence() {
+        List<CarryReduce> result = new ArrayList<CarryReduce>();
+
+        // reduce(8, 7)
+        for (int i = 24; i < 31; i++) {
+            result.add(new Reduce(i));
+        }
+        // reduce(4, 4)
+        for (int i = 20; i < 24; i++) {
+            result.add(new Reduce(i));
+        }
+
+        //carry(14, 2)
+        result.add(new Carry(14));
+        result.add(new Carry(15));
+
+        // reduce(0, 4)
+        for (int i = 16; i < 20; i++) {
+            result.add(new Reduce(i));
+        }
+
+        // carry(0, 15)
+        result.addAll(fullCarry(16));
+
+        return result;
+    }
+
+    static FieldParams P256 = new FieldParams("IntegerPolynomialP256", 26, 10, 2, 256,
+    Arrays.asList(
+    new Term(224, -1),
+    new Term(192, 1),
+    new Term(96, 1),
+    new Term(0, -1)
+    ),
+    P256CrSequence(), simpleSmallCrSequence(10)
+    );
+
+    private static List<CarryReduce> P256CrSequence() {
+        List<CarryReduce> result = new ArrayList<CarryReduce>();
+        result.addAll(fullReduce(10));
+        result.addAll(simpleSmallCrSequence(10));
+        return result;
+    }
+
+    static FieldParams P384 = new FieldParams("IntegerPolynomialP384", 28, 14, 2, 384,
+    Arrays.asList(
+    new Term(128, -1),
+    new Term(96, -1),
+    new Term(32, 1),
+    new Term(0, -1)
+    ),
+    P384CrSequence(), simpleSmallCrSequence(14)
+    );
+
+    private static List<CarryReduce> P384CrSequence() {
+        List<CarryReduce> result = new ArrayList<CarryReduce>();
+        result.addAll(fullReduce(14));
+        result.addAll(simpleSmallCrSequence(14));
+        return result;
+    }
+
+    static FieldParams P521 = new FieldParams("IntegerPolynomialP521", 28, 19, 2, 521,
+    Arrays.asList(new Term(0, -1)), P521CrSequence(), simpleSmallCrSequence(19)
+    );
+
+    private static List<CarryReduce> P521CrSequence() {
+        List<CarryReduce> result = new ArrayList<CarryReduce>();
+        result.addAll(fullReduce(19));
+        result.addAll(simpleSmallCrSequence(19));
+        return result;
+    }
+
+    static FieldParams O256 = new FieldParams("P256OrderField", 26, 10, 1, 256,
+    new BigInteger("26959946660873538059280334323273029441504803697035324946844617595567"),
+    orderFieldCrSequence(10), orderFieldSmallCrSequence(10)
+    );
+
+    static FieldParams O384 = new FieldParams("P384OrderField", 28, 14, 1, 384,
+    new BigInteger("1388124618062372383947042015309946732620727252194336364173"),
+    orderFieldCrSequence(14), orderFieldSmallCrSequence(14)
+    );
+
+    static FieldParams O521 = new FieldParams("P521OrderField", 28, 19, 1, 521,
+    new BigInteger("657877501894328237357444332315020117536923257219387276263472201219398408051703"),
+    o521crSequence(19), orderFieldSmallCrSequence(19)
+    );
+
+    private static List<CarryReduce> o521crSequence(int numLimbs) {
+
+        // split the full reduce in half, with a carry in between
+        List<CarryReduce> result = new ArrayList<CarryReduce>();
+        result.addAll(fullCarry(2 * numLimbs));
+        for (int i = 2 * numLimbs - 1; i >= numLimbs + numLimbs/2; i--) {
+            result.add(new Reduce(i));
+        }
+        // carry
+        for (int i = numLimbs; i < numLimbs + numLimbs / 2 - 1; i++) {
+            result.add(new Carry(i));
+        }
+        // rest of reduce
+        for (int i = numLimbs + numLimbs/2 - 1; i >= numLimbs; i--) {
+            result.add(new Reduce(i));
+        }
+        result.addAll(orderFieldSmallCrSequence(numLimbs));
+
+        return result;
+    }
+
+    private static List<CarryReduce> orderFieldCrSequence(int numLimbs) {
+        List<CarryReduce> result = new ArrayList<CarryReduce>();
+        result.addAll(fullCarry(2 * numLimbs));
+        result.add(new Reduce(2 * numLimbs - 1));
+        result.addAll(fullReduce(numLimbs));
+        result.addAll(fullCarry(numLimbs + 1));
+        result.add(new Reduce(numLimbs));
+        result.addAll(fullCarry(numLimbs));
+
+        return result;
+    }
+   private static List<CarryReduce> orderFieldSmallCrSequence(int numLimbs) {
+        List<CarryReduce> result = new ArrayList<CarryReduce>();
+        result.addAll(fullCarry(numLimbs + 1));
+        result.add(new Reduce(numLimbs));
+        result.addAll(fullCarry(numLimbs));
+        return result;
+    }
+
+    static final FieldParams[] ALL_FIELDS = {P256, P384, P521, O256, O384, O521};
+
+    public static class Term {
+        private final int power;
+        private final int coefficient;
+
+        public Term(int power, int coefficient) {
+            this.power = power;
+            this.coefficient = coefficient;
+        }
+
+        public int getPower() {
+            return power;
+        }
+
+        public int getCoefficient() {
+            return coefficient;
+        }
+
+        public BigInteger getValue() {
+            return BigInteger.valueOf(2).pow(power).multiply(BigInteger.valueOf(coefficient));
+        }
+
+    }
+
+    static abstract class CarryReduce {
+        private final int index;
+
+        protected CarryReduce(int index) {
+            this.index = index;
+        }
+
+        public int getIndex() {
+            return index;
+        }
+
+        public abstract void write(CodeBuffer out, FieldParams params, String prefix, Iterable<CarryReduce> remaining);
+    }
+
+    static class Carry extends CarryReduce {
+        public Carry(int index) {
+            super(index);
+        }
+
+        public void write(CodeBuffer out, FieldParams params, String prefix, Iterable<CarryReduce> remaining) {
+            carry(out, params, prefix, getIndex());
+        }
+    }
+
+    static class Reduce extends CarryReduce {
+        public Reduce(int index) {
+            super(index);
+        }
+
+        public void write(CodeBuffer out, FieldParams params, String prefix, Iterable<CarryReduce> remaining) {
+            reduce(out, params, prefix, getIndex(), remaining);
+        }
+    }
+
+    static class FieldParams {
+        private final String className;
+        private final int bitsPerLimb;
+        private final int numLimbs;
+        private final int maxAdds;
+        private final int power;
+        private final Iterable<Term> terms;
+        private final List<CarryReduce> crSequence;
+        private final List<CarryReduce> smallCrSequence;
+
+        public FieldParams(String className, int bitsPerLimb, int numLimbs, int maxAdds, int power,
+                           Iterable<Term> terms, List<CarryReduce> crSequence, List<CarryReduce> smallCrSequence) {
+            this.className = className;
+            this.bitsPerLimb = bitsPerLimb;
+            this.numLimbs = numLimbs;
+            this.maxAdds = maxAdds;
+            this.power = power;
+            this.terms = terms;
+            this.crSequence = crSequence;
+            this.smallCrSequence = smallCrSequence;
+        }
+
+        public FieldParams(String className, int bitsPerLimb, int numLimbs, int maxAdds, int power,
+                           BigInteger term, List<CarryReduce> crSequence, List<CarryReduce> smallCrSequence) {
+            this.className = className;
+            this.bitsPerLimb = bitsPerLimb;
+            this.numLimbs = numLimbs;
+            this.maxAdds = maxAdds;
+            this.power = power;
+            this.crSequence = crSequence;
+            this.smallCrSequence = smallCrSequence;
+
+            terms = buildTerms(term);
+        }
+
+        private Iterable<Term> buildTerms(BigInteger sub) {
+            // split a large subtrahend into smaller terms that are aligned with limbs
+            List<Term> result = new ArrayList<Term>();
+            BigInteger mod = BigInteger.valueOf(1 << bitsPerLimb);
+            int termIndex = 0;
+            while (!sub.equals(BigInteger.ZERO)) {
+                int coef = sub.mod(mod).intValue();
+                boolean plusOne = false;
+                if (coef > (1 << (bitsPerLimb - 1))) {
+                    coef = coef - (1 << bitsPerLimb);
+                    plusOne = true;
+                }
+                if (coef != 0) {
+                    int pow = termIndex * bitsPerLimb;
+                    result.add(new Term(pow, -coef));
+                }
+                sub = sub.shiftRight(bitsPerLimb);
+                if (plusOne) {
+                   sub = sub.add(BigInteger.ONE);
+                }
+                ++termIndex;
+            }
+            return result;
+        }
+
+        public String getClassName() {
+            return className;
+        }
+
+        public int getBitsPerLimb() {
+            return bitsPerLimb;
+        }
+
+        public int getNumLimbs() {
+            return numLimbs;
+        }
+
+        public int getMaxAdds() {
+            return maxAdds;
+        }
+
+        public int getPower() {
+            return power;
+        }
+
+        public Iterable<Term> getTerms() {
+            return terms;
+        }
+
+        public List<CarryReduce> getCrSequence() {
+            return crSequence;
+        }
+
+        public List<CarryReduce> getSmallCrSequence() {
+            return smallCrSequence;
+        }
+    }
+
+    static Collection<Carry> fullCarry(int numLimbs) {
+        List<Carry> result = new ArrayList<Carry>();
+        for (int i = 0; i < numLimbs - 1; i++) {
+            result.add(new Carry(i));
+        }
+        return result;
+    }
+
+    static Collection<Reduce> fullReduce(int numLimbs) {
+        List<Reduce> result = new ArrayList<Reduce>();
+        for (int i = numLimbs - 2; i >= 0; i--) {
+            result.add(new Reduce(i + numLimbs));
+        }
+        return result;
+    }
+
+    static List<CarryReduce> simpleCrSequence(int numLimbs) {
+        List<CarryReduce> result = new ArrayList<CarryReduce>();
+        for(int i = 0; i < 4; i++) {
+            result.addAll(fullCarry(2 * numLimbs - 1));
+            result.addAll(fullReduce(numLimbs));
+        }
+
+        return result;
+    }
+
+    static List<CarryReduce> simpleSmallCrSequence(int numLimbs) {
+        List<CarryReduce> result = new ArrayList<CarryReduce>();
+        // carry a few positions at the end
+        for (int i = numLimbs - 2; i < numLimbs; i++) {
+            result.add(new Carry(i));
+        }
+        // this carries out a single value that must be reduced back in
+        result.add(new Reduce(numLimbs));
+        // finish with a full carry
+        result.addAll(fullCarry(numLimbs));
+        return result;
+    }
+
+    private final String packageName;
+    private final String parentName;
+
+    public FieldGen(String packageName, String parentName) {
+        this.packageName = packageName;
+        this.parentName = parentName;
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        FieldGen gen = new FieldGen("sun.security.util.math.intpoly", "IntegerPolynomial");
+        for(FieldParams p : ALL_FIELDS) {
+            gen.generateFile(p);
+        }
+    }
+
+    private void generateFile(FieldParams params) throws IOException {
+        String text = generate(params);
+        String fileName = params.getClassName() + ".java";
+        PrintWriter out = new PrintWriter(new FileWriter(fileName));
+        out.println(text);
+        out.close();
+    }
+
+    static class CodeBuffer {
+
+        private int nextTemporary = 0;
+        private Set<String> temporaries = new HashSet<String>();
+        private StringBuffer buffer = new StringBuffer();
+        private int indent = 0;
+        private Class lastCR;
+        private int lastCrCount = 0;
+        private int crMethodBreakCount = 0;
+        private int crNumLimbs = 0;
+
+        public void incrIndent() {
+            indent++;
+        }
+
+        public void decrIndent() {
+            indent--;
+        }
+
+        public void newTempScope() {
+            nextTemporary = 0;
+            temporaries.clear();
+        }
+
+        public void appendLine(String s) {
+            appendIndent();
+            buffer.append(s + "\n");
+        }
+
+        public void appendLine() {
+            buffer.append("\n");
+        }
+
+        public String toString() {
+            return buffer.toString();
+        }
+
+        public void startCrSequence(int numLimbs) {
+            this.crNumLimbs = numLimbs;
+            lastCrCount = 0;
+            crMethodBreakCount = 0;
+            lastCR = null;
+        }
+        /*
+         * Record a carry/reduce of the specified type. This method is used to
+         * break up large carry/reduce sequences into multiple methods to make
+         * JIT/optimization easier
+         */
+        public void record(Class type) {
+            if (type == lastCR) {
+                lastCrCount++;
+            } else {
+
+                if (lastCrCount >= 8) {
+                    insertCrMethodBreak();
+                }
+
+                lastCR = type;
+                lastCrCount = 0;
+            }
+        }
+
+        private void insertCrMethodBreak() {
+
+            appendLine();
+
+            // call the new method
+            appendIndent();
+            append("carryReduce" + crMethodBreakCount + "(r");
+            for(int i = 0; i < crNumLimbs; i++) {
+                append(", c" + i);
+            }
+            // temporaries are not live between operations, no need to send
+            append(");\n");
+
+            decrIndent();
+            appendLine("}");
+
+            // make the method
+            appendIndent();
+            append("void carryReduce" + crMethodBreakCount + "(long[] r");
+            for(int i = 0; i < crNumLimbs; i++) {
+                append (", long c" + i);
+            }
+            append(") {\n");
+            incrIndent();
+            // declare temporaries
+            for(String temp : temporaries) {
+                appendLine("long " + temp + ";");
+            }
+            append("\n");
+
+            crMethodBreakCount++;
+        }
+
+        public String getTemporary(String type, String value) {
+            Iterator<String> iter = temporaries.iterator();
+            if(iter.hasNext()) {
+                String result = iter.next();
+                iter.remove();
+                appendLine(result + " = " + value + ";");
+                return result;
+            } else {
+                String result = "t" + (nextTemporary++);
+                appendLine(type + " " + result + " = " + value + ";");
+                return result;
+            }
+        }
+
+        public void freeTemporary(String temp) {
+            temporaries.add(temp);
+        }
+
+        public void appendIndent() {
+            for(int i = 0; i < indent; i++) {
+                buffer.append("    ");
+            }
+        }
+
+        public void append(String s) {
+            buffer.append(s);
+        }
+    }
+
+    private String generate(FieldParams params) throws IOException {
+        CodeBuffer result = new CodeBuffer();
+        String header = readHeader();
+        result.appendLine(header);
+
+        if (packageName != null) {
+            result.appendLine("package " + packageName + ";");
+            result.appendLine();
+        }
+        result.appendLine("import java.math.BigInteger;");
+
+        result.appendLine("public class " + params.getClassName() + " extends " + this.parentName + " {");
+        result.incrIndent();
+
+        result.appendLine("private static final int BITS_PER_LIMB = " + params.getBitsPerLimb() + ";");
+        result.appendLine("private static final int NUM_LIMBS = " + params.getNumLimbs() + ";");
+        result.appendLine("private static final int MAX_ADDS = " + params.getMaxAdds() + ";");
+        result.appendLine("public static final BigInteger MODULUS = evaluateModulus();");
+        result.appendLine("private static final long CARRY_ADD = 1 << " + (params.getBitsPerLimb() - 1) + ";");
+        if (params.getBitsPerLimb() * params.getNumLimbs() != params.getPower()) {
+            result.appendLine("private static final int LIMB_MASK = -1 >>> (64 - BITS_PER_LIMB);");
+        }
+        int termIndex = 0;
+
+        result.appendLine("public " + params.getClassName() + "() {");
+        result.appendLine();
+        result.appendLine("    super(BITS_PER_LIMB, NUM_LIMBS, MAX_ADDS, MODULUS);");
+        result.appendLine();
+        result.appendLine("}");
+
+        result.appendLine("private static BigInteger evaluateModulus() {");
+        result.incrIndent();
+        result.appendLine("BigInteger result = BigInteger.valueOf(2).pow(" + params.getPower() + ");");
+        for(Term t : params.getTerms()) {
+            boolean subtract = false;
+            int coefValue = t.getCoefficient();
+            if (coefValue < 0) {
+                coefValue = 0 - coefValue;
+                subtract = true;
+            }
+            String coefExpr = "BigInteger.valueOf(" + coefValue + ")";
+            String powExpr = "BigInteger.valueOf(2).pow(" + t.getPower() + ")";
+            String termExpr = "ERROR";
+            if (t.getPower() == 0) {
+                termExpr = coefExpr;
+            } else if (coefValue == 1) {
+                termExpr = powExpr;
+            } else {
+                termExpr = powExpr + ".multiply(" + coefExpr + ")";
+            }
+            if (subtract) {
+                result.appendLine("result = result.subtract(" + termExpr + ");");
+            } else {
+                result.appendLine("result = result.add(" + termExpr + ");");
+            }
+        }
+        result.appendLine("return result;");
+        result.decrIndent();
+        result.appendLine("}");
+
+        result.appendLine("@Override");
+        result.appendLine("protected void finalCarryReduceLast(long[] limbs) {");
+        result.incrIndent();
+        int extraBits = params.getBitsPerLimb() * params.getNumLimbs() - params.getPower();
+        int highBits = params.getBitsPerLimb() - extraBits;
+        result.appendLine("long c = limbs[" + (params.getNumLimbs() - 1) + "] >> " + highBits + ";");
+        result.appendLine("limbs[" + (params.getNumLimbs() - 1) + "] -= c << " + highBits + ";");
+        for (Term t : params.getTerms()) {
+            int reduceBits = params.getPower() + extraBits - t.getPower();
+            int negatedCoefficient = -1 * t.getCoefficient();
+            modReduceInBits(result, params, true, "limbs", params.getNumLimbs(), reduceBits, negatedCoefficient, "c");
+        }
+        result.decrIndent();
+        result.appendLine("}");
+
+        // full carry/reduce sequence
+        result.appendIndent();
+        result.append("private void carryReduce(long[] r, ");
+        for(int i = 0; i < 2 * params.getNumLimbs() - 1; i++) {
+            result.append ("long c" + i);
+            if (i < 2 * params.getNumLimbs() - 2) {
+                result.append(", ");
+            }
+        }
+        result.append(") {\n");
+        result.newTempScope();
+        result.incrIndent();
+        result.appendLine("long c" + (2 * params.getNumLimbs() - 1) + " = 0;");
+        write(result, params.getCrSequence(), params, "c", 2 * params.getNumLimbs());
+        result.appendLine();
+        for (int i = 0; i < params.getNumLimbs(); i++) {
+            result.appendLine("r[" + i + "] = c" + i + ";");
+        }
+        result.decrIndent();
+        result.appendLine("}");
+
+        // small carry/reduce sequence
+        result.appendIndent();
+        result.append("private void carryReduce(long[] r, ");
+        for(int i = 0; i < params.getNumLimbs(); i++) {
+            result.append ("long c" + i);
+            if (i < params.getNumLimbs() - 1) {
+                result.append(", ");
+            }
+        }
+        result.append(") {\n");
+        result.newTempScope();
+        result.incrIndent();
+        result.appendLine("long c" + params.getNumLimbs() + " = 0;");
+        write(result, params.getSmallCrSequence(), params, "c", params.getNumLimbs() + 1);
+        result.appendLine();
+        for (int i = 0; i < params.getNumLimbs(); i++) {
+            result.appendLine("r[" + i + "] = c" + i + ";");
+        }
+        result.decrIndent();
+        result.appendLine("}");
+
+        result.appendLine("@Override");
+        result.appendLine("protected void mult(long[] a, long[] b, long[] r) {");
+        result.incrIndent();
+        for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) {
+            result.appendIndent();
+            result.append("long c" + i + " = ");
+            int startJ = Math.max(i + 1 - params.getNumLimbs(), 0);
+            int endJ = Math.min(params.getNumLimbs(), i + 1);
+            for (int j = startJ; j < endJ; j++) {
+                int bIndex = i - j;
+                result.append("(a[" + j + "] * b[" + bIndex + "])");
+                if (j < endJ - 1) {
+                    result.append(" + ");
+                }
+            }
+            result.append(";\n");
+        }
+        result.appendLine();
+        result.appendIndent();
+        result.append("carryReduce(r, ");
+        for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) {
+            result.append("c" + i);
+            if (i < 2 * params.getNumLimbs() - 2) {
+                result.append(", ");
+            }
+        }
+        result.append(");\n");
+        result.decrIndent();
+        result.appendLine("}");
+
+        result.appendLine("@Override");
+        result.appendLine("protected void reduce(long[] a) {");
+        result.incrIndent();
+        result.appendIndent();
+        result.append("carryReduce(a, ");
+        for (int i = 0; i < params.getNumLimbs(); i++) {
+            result.append("a[" + i + "]");
+            if (i < params.getNumLimbs() - 1) {
+                result.append(", ");
+            }
+        }
+        result.append(");\n");
+        result.decrIndent();
+        result.appendLine("}");
+
+        result.appendLine("@Override");
+        result.appendLine("protected void square(long[] a, long[] r) {");
+        result.incrIndent();
+        for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) {
+            result.appendIndent();
+            result.append("long c" + i + " = ");
+            int startJ = Math.max(i + 1 - params.getNumLimbs(), 0);
+            int endJ = Math.min(params.getNumLimbs(), i + 1);
+            int jDiff = endJ - startJ;
+            if (jDiff > 1) {
+                result.append("2 * (");
+            }
+            for (int j = 0; j < jDiff / 2; j++) {
+                int aIndex = j + startJ;
+                int bIndex = i - aIndex;
+                result.append("(a[" + aIndex + "] * a[" + bIndex + "])");
+                if (j < (jDiff / 2) - 1) {
+                    result.append(" + ");
+                }
+            }
+            if (jDiff > 1) {
+                result.append(")");
+            }
+            if (jDiff % 2 == 1) {
+                int aIndex = i / 2;
+                if (jDiff > 1) {
+                    result.append (" + ");
+                }
+                result.append("(a[" + aIndex + "] * a[" + aIndex + "])");
+            }
+            result.append(";\n");
+        }
+        result.appendLine();
+        result.appendIndent();
+        result.append("carryReduce(r, ");
+        for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) {
+            result.append("c" + i);
+            if (i < 2 * params.getNumLimbs() - 2) {
+                result.append(", ");
+            }
+        }
+        result.append(");\n");
+        result.decrIndent();
+        result.appendLine("}");
+
+        result.decrIndent();
+        result.appendLine("}"); // end class
+
+        return result.toString();
+    }
+
+    private static void write(CodeBuffer out, List<CarryReduce> sequence, FieldParams params, String prefix, int numLimbs) {
+
+        out.startCrSequence(numLimbs);
+        for (int i = 0; i < sequence.size(); i++) {
+            CarryReduce cr = sequence.get(i);
+            Iterator<CarryReduce> remainingIter = sequence.listIterator(i + 1);
+            List<CarryReduce> remaining = new ArrayList<CarryReduce>();
+            remainingIter.forEachRemaining(remaining::add);
+            cr.write(out, params, prefix, remaining);
+        }
+    }
+
+    private static void reduce(CodeBuffer out, FieldParams params, String prefix, int index, Iterable<CarryReduce> remaining) {
+
+        out.record(Reduce.class);
+
+        out.appendLine("//reduce from position " + index);
+        String reduceFrom = indexedExpr(false, prefix, index);
+        boolean referenced = false;
+        for (CarryReduce cr : remaining) {
+            if(cr.index == index) {
+                referenced = true;
+            }
+        }
+        for (Term t : params.getTerms()) {
+            int reduceBits = params.getPower() - t.getPower();
+            int negatedCoefficient = -1 * t.getCoefficient();
+            modReduceInBits(out, params, false, prefix, index, reduceBits, negatedCoefficient, reduceFrom);
+        }
+        if (referenced) {
+            out.appendLine(reduceFrom + " = 0;");
+        }
+    }
+
+    private static void carry(CodeBuffer out, FieldParams params, String prefix, int index) {
+
+        out.record(Carry.class);
+
+        out.appendLine("//carry from position " + index);
+        String carryFrom = prefix + index;
+        String carryTo = prefix + (index + 1);
+        String carry = "(" + carryFrom + " + CARRY_ADD) >> " + params.getBitsPerLimb();
+        String temp = out.getTemporary("long", carry);
+        out.appendLine(carryFrom + " -= (" + temp + " << " + params.getBitsPerLimb() + ");");
+        out.appendLine(carryTo + " += " + temp + ";");
+        out.freeTemporary(temp);
+    }
+
+    private static String indexedExpr(boolean isArray, String prefix, int index) {
+        String result = prefix + index;
+        if (isArray) {
+            result = prefix + "[" + index + "]";
+        }
+        return result;
+    }
+
+    private static void modReduceInBits(CodeBuffer result, FieldParams params, boolean isArray, String prefix, int index, int reduceBits, int coefficient, String c) {
+
+        String x = coefficient + " * " + c;
+        String accOp = "+=";
+        String temp = null;
+        if (coefficient == 1) {
+            x = c;
+        } else if (coefficient == -1) {
+            x = c;
+            accOp = "-=";
+        } else {
+            temp = result.getTemporary("long", x);
+            x = temp;
+        }
+
+        if (reduceBits % params.getBitsPerLimb() == 0) {
+            int pos = reduceBits / params.getBitsPerLimb();
+            result.appendLine(indexedExpr(isArray, prefix, (index - pos)) + " " + accOp + " " + x + ";");
+        } else {
+            int secondPos = reduceBits / params.getBitsPerLimb();
+            int bitOffset = (secondPos + 1) * params.getBitsPerLimb() - reduceBits;
+            int rightBitOffset = params.getBitsPerLimb() - bitOffset;
+            result.appendLine(indexedExpr(isArray, prefix, (index - (secondPos + 1))) + " " + accOp + " (" + x + " << " + bitOffset + ") & LIMB_MASK;");
+            result.appendLine(indexedExpr(isArray, prefix, (index - secondPos)) + " " + accOp + " " + x + " >> " + rightBitOffset + ";");
+        }
+
+        if (temp != null) {
+            result.freeTemporary(temp);
+        }
+    }
+
+    private String readHeader() throws IOException {
+        BufferedReader reader = Files.newBufferedReader(Paths.get("header.txt"));
+        StringBuffer result = new StringBuffer();
+        reader.lines().forEach(s -> result.append(s + "\n"));
+        return result.toString();
+    }
+}
+
+FieldGen.main(null);
+
--- a/src/share/classes/sun/security/util/math/intpoly/IntegerPolynomial.java	Sat Jul 13 15:17:33 2019 +0100
+++ b/src/share/classes/sun/security/util/math/intpoly/IntegerPolynomial.java	Sat Jul 13 16:49:00 2019 +0100
@@ -69,14 +69,25 @@
     private final BigInteger modulus;
     protected final int bitsPerLimb;
     private final long[] posModLimbs;
+    private final int maxAdds;
+
+    /**
+     * Reduce an IntegerPolynomial representation (a) and store the result
+     * in a. Requires that a.length == numLimbs.
+     */
+    protected abstract void reduce(long[] a);
 
     /**
      * Multiply an IntegerPolynomial representation (a) with a long (b) and
-     * store the result in an IntegerPolynomial representation (r). Requires
-     * that a.length == r.length == numLimbs. It is allowed for a and r to be
-     * the same array.
+     * store the result in an IntegerPolynomial representation in a. Requires
+     * that a.length == numLimbs.
      */
-    protected abstract void multByInt(long[] a, long b, long[] r);
+    protected void multByInt(long[] a, long b) {
+        for (int i = 0; i < a.length; i++) {
+            a[i] *= b;
+        }
+        reduce(a);
+    }
 
     /**
      * Multiply two IntegerPolynomial representations (a and b) and store the
@@ -96,12 +107,14 @@
 
     IntegerPolynomial(int bitsPerLimb,
                       int numLimbs,
+                      int maxAdds,
                       BigInteger modulus) {
 
 
         this.numLimbs = numLimbs;
         this.modulus = modulus;
         this.bitsPerLimb = bitsPerLimb;
+        this.maxAdds = maxAdds;
 
         posModLimbs = setPosModLimbs();
     }
@@ -116,6 +129,10 @@
         return numLimbs;
     }
 
+    public int getMaxAdds() {
+        return maxAdds;
+    }
+
     @Override
     public BigInteger getSize() {
         return modulus;
@@ -155,12 +172,22 @@
      */
     protected void encode(ByteBuffer buf, int length, byte highByte,
                           long[] result) {
+
         int numHighBits = 32 - Integer.numberOfLeadingZeros(highByte);
         int numBits = 8 * length + numHighBits;
-        int maxBits = bitsPerLimb * result.length;
-        if (numBits > maxBits) {
-            throw new ArithmeticException("Value is too large.");
+        int requiredLimbs = (numBits + bitsPerLimb - 1) / bitsPerLimb;
+        if (requiredLimbs > numLimbs) {
+            long[] temp = new long[requiredLimbs];
+            encodeSmall(buf, length, highByte, temp);
+            // encode does a full carry/reduce
+            System.arraycopy(temp, 0, result, 0, result.length);
+        } else {
+            encodeSmall(buf, length, highByte, result);
         }
+    }
+
+    protected void encodeSmall(ByteBuffer buf, int length, byte highByte,
+                               long[] result) {
 
         int limbIndex = 0;
         long curLimbValue = 0;
@@ -195,10 +222,10 @@
             }
         }
 
-        if (limbIndex < numLimbs) {
+        if (limbIndex < result.length) {
             result[limbIndex++] = curLimbValue;
         }
-        Arrays.fill(result, limbIndex, numLimbs, 0);
+        Arrays.fill(result, limbIndex, result.length, 0);
 
         postEncodeCarry(result);
     }
@@ -211,8 +238,10 @@
         encode(buf, length, highByte, result);
     }
 
+    // Encode does not produce compressed limbs. A simplified carry/reduce
+    // operation can be used to compress the limbs.
     protected void postEncodeCarry(long[] v) {
-        carry(v);
+        reduce(v);
     }
 
     @Override
@@ -227,7 +256,7 @@
 
         encode(v, offset, length, highByte, result);
 
-        return new ImmutableElement(result, true);
+        return new ImmutableElement(result, 0);
     }
 
     protected BigInteger evaluate(long[] limbs) {
@@ -392,6 +421,20 @@
     }
 
     /**
+     * Branch-free conditional assignment of b to a. Requires that set is 0 or
+     * 1, and that a.length == b.length. If set==0, then the values of a and b
+     * will be unchanged. If set==1, then the values of b will be assigned to a.
+     * The behavior is undefined if swap has any value other than 0 or 1.
+     */
+    protected static void conditionalAssign(int set, long[] a, long[] b) {
+        int maskValue = 0 - set;
+        for (int i = 0; i < a.length; i++) {
+            long dummyLimbs = maskValue & (a[i] ^ b[i]);
+            a[i] = dummyLimbs ^ a[i];
+        }
+    }
+
+    /**
      * Branch-free conditional swap of a and b. Requires that swap is 0 or 1,
      * and that a.length == b.length. If swap==0, then the values of a and b
      * will be unchanged. If swap==1, then the values of a and b will be
@@ -447,7 +490,7 @@
     private abstract class Element extends AbstractElement {
 
         protected long[] limbs;
-        protected boolean summand = false;
+        protected int numAdds;
 
         public Element(BigInteger v) {
             limbs = new long[numLimbs];
@@ -455,19 +498,19 @@
         }
 
         public Element(boolean v) {
-            limbs = new long[numLimbs];
-            limbs[0] = v ? 1l : 0l;
-            summand = true;
+            this.limbs = new long[numLimbs];
+            this.limbs[0] = v ? 1l : 0l;
+            this.numAdds = 0;
         }
 
-        private Element(long[] limbs, boolean summand) {
+        private Element(long[] limbs, int numAdds) {
             this.limbs = limbs;
-            this.summand = summand;
+            this.numAdds = numAdds;
         }
 
         private void setValue(BigInteger v) {
             setLimbsValue(v, limbs);
-            summand = true;
+            this.numAdds = 0;
         }
 
         @Override
@@ -482,14 +525,18 @@
 
         @Override
         public MutableElement mutable() {
-            return new MutableElement(limbs.clone(), summand);
+            return new MutableElement(limbs.clone(), numAdds);
+        }
+
+        protected boolean isSummand() {
+            return numAdds < maxAdds;
         }
 
         @Override
         public ImmutableElement add(IntegerModuloP genB) {
 
             Element b = (Element) genB;
-            if (!(summand && b.summand)) {
+            if (!(isSummand() && b.isSummand())) {
                 throw new ArithmeticException("Not a valid summand");
             }
 
@@ -498,7 +545,8 @@
                 newLimbs[i] = limbs[i] + b.limbs[i];
             }
 
-            return new ImmutableElement(newLimbs, false);
+            int newNumAdds = Math.max(numAdds, b.numAdds) + 1;
+            return new ImmutableElement(newLimbs, newNumAdds);
         }
 
         @Override
@@ -509,7 +557,7 @@
                 newLimbs[i] = -limbs[i];
             }
 
-            ImmutableElement result = new ImmutableElement(newLimbs, summand);
+            ImmutableElement result = new ImmutableElement(newLimbs, numAdds);
             return result;
         }
 
@@ -529,43 +577,52 @@
 
             long[] newLimbs = new long[limbs.length];
             mult(limbs, b.limbs, newLimbs);
-            return new ImmutableElement(newLimbs, true);
+            return new ImmutableElement(newLimbs, 0);
         }
 
         @Override
         public ImmutableElement square() {
             long[] newLimbs = new long[limbs.length];
             IntegerPolynomial.this.square(limbs, newLimbs);
-            return new ImmutableElement(newLimbs, true);
+            return new ImmutableElement(newLimbs, 0);
         }
 
         public void addModPowerTwo(IntegerModuloP arg, byte[] result) {
 
             Element other = (Element) arg;
-            if (!(summand && other.summand)) {
+            if (!(isSummand() && other.isSummand())) {
                 throw new ArithmeticException("Not a valid summand");
             }
             addLimbsModPowerTwo(limbs, other.limbs, result);
         }
 
         public void asByteArray(byte[] result) {
-            if (!summand) {
+            if (!isSummand()) {
                 throw new ArithmeticException("Not a valid summand");
             }
             limbsToByteArray(limbs, result);
         }
     }
 
-    private class MutableElement extends Element
+    protected class MutableElement extends Element
         implements MutableIntegerModuloP {
 
-        protected MutableElement(long[] limbs, boolean summand) {
-            super(limbs, summand);
+        protected MutableElement(long[] limbs, int numAdds) {
+            super(limbs, numAdds);
         }
 
         @Override
         public ImmutableElement fixed() {
-            return new ImmutableElement(limbs.clone(), summand);
+            return new ImmutableElement(limbs.clone(), numAdds);
+        }
+
+        @Override
+        public void conditionalSet(IntegerModuloP b, int set) {
+
+            Element other = (Element) b;
+
+            conditionalAssign(set, limbs, other.limbs);
+            numAdds = other.numAdds;
         }
 
         @Override
@@ -574,9 +631,9 @@
             MutableElement other = (MutableElement) b;
 
             conditionalSwap(swap, limbs, other.limbs);
-            boolean summandTemp = summand;
-            summand = other.summand;
-            other.summand = summandTemp;
+            int numAddsTemp = numAdds;
+            numAdds = other.numAdds;
+            other.numAdds = numAddsTemp;
         }
 
         @Override
@@ -584,7 +641,7 @@
             Element other = (Element) v;
 
             System.arraycopy(other.limbs, 0, limbs, 0, other.limbs.length);
-            summand = other.summand;
+            numAdds = other.numAdds;
             return this;
         }
 
@@ -593,7 +650,7 @@
                                        int length, byte highByte) {
 
             encode(arr, offset, length, highByte, limbs);
-            summand = true;
+            this.numAdds = 0;
 
             return this;
         }
@@ -603,7 +660,7 @@
                                        byte highByte) {
 
             encode(buf, length, highByte, limbs);
-            summand = true;
+            numAdds = 0;
 
             return this;
         }
@@ -612,15 +669,15 @@
         public MutableElement setProduct(IntegerModuloP genB) {
             Element b = (Element) genB;
             mult(limbs, b.limbs, limbs);
-            summand = true;
+            numAdds = 0;
             return this;
         }
 
         @Override
         public MutableElement setProduct(SmallValue v) {
             int value = ((Limb) v).value;
-            multByInt(limbs, value, limbs);
-            summand = true;
+            multByInt(limbs, value);
+            numAdds = 0;
             return this;
         }
 
@@ -628,7 +685,7 @@
         public MutableElement setSum(IntegerModuloP genB) {
 
             Element b = (Element) genB;
-            if (!(summand && b.summand)) {
+            if (!(isSummand() && b.isSummand())) {
                 throw new ArithmeticException("Not a valid summand");
             }
 
@@ -636,7 +693,7 @@
                 limbs[i] = limbs[i] + b.limbs[i];
             }
 
-            summand = false;
+            numAdds = Math.max(numAdds, b.numAdds) + 1;
             return this;
         }
 
@@ -644,7 +701,7 @@
         public MutableElement setDifference(IntegerModuloP genB) {
 
             Element b = (Element) genB;
-            if (!(summand && b.summand)) {
+            if (!(isSummand() && b.isSummand())) {
                 throw new ArithmeticException("Not a valid summand");
             }
 
@@ -652,16 +709,33 @@
                 limbs[i] = limbs[i] - b.limbs[i];
             }
 
+            numAdds = Math.max(numAdds, b.numAdds) + 1;
             return this;
         }
 
         @Override
         public MutableElement setSquare() {
             IntegerPolynomial.this.square(limbs, limbs);
-            summand = true;
+            numAdds = 0;
             return this;
         }
 
+        @Override
+        public MutableElement setAdditiveInverse() {
+
+            for (int i = 0; i < limbs.length; i++) {
+                limbs[i] = -limbs[i];
+            }
+            return this;
+        }
+
+        @Override
+        public MutableElement setReduced() {
+
+            reduce(limbs);
+            numAdds = 0;
+            return this;
+        }
     }
 
     class ImmutableElement extends Element implements ImmutableIntegerModuloP {
@@ -674,8 +748,8 @@
             super(v);
         }
 
-        protected ImmutableElement(long[] limbs, boolean summand) {
-            super(limbs, summand);
+        protected ImmutableElement(long[] limbs, int numAdds) {
+            super(limbs, numAdds);
         }
 
         @Override
--- a/src/share/classes/sun/security/util/math/intpoly/IntegerPolynomial1305.java	Sat Jul 13 15:17:33 2019 +0100
+++ b/src/share/classes/sun/security/util/math/intpoly/IntegerPolynomial1305.java	Sat Jul 13 16:49:00 2019 +0100
@@ -44,7 +44,7 @@
         = TWO.pow(POWER).subtract(BigInteger.valueOf(SUBTRAHEND));
 
     public IntegerPolynomial1305() {
-        super(BITS_PER_LIMB, NUM_LIMBS, MODULUS);
+        super(BITS_PER_LIMB, NUM_LIMBS, 1, MODULUS);
     }
 
     protected void mult(long[] a, long[] b, long[] r) {
@@ -95,15 +95,6 @@
         carry(r);
     }
 
-    protected void multByInt(long[] a, long b, long[] r) {
-
-        for (int i = 0; i < a.length; i++) {
-            r[i] = a[i] * b;
-        }
-
-        reduce(r);
-    }
-
     @Override
     protected void square(long[] a, long[] r) {
         // Use grade-school multiplication with a simple squaring optimization.
@@ -197,7 +188,12 @@
         return x >> BITS_PER_LIMB;
     }
 
+    @Override
+    protected void postEncodeCarry(long[] v) {
+        // not needed because carry is unsigned
+    }
 
+    @Override
     protected void reduce(long[] limbs) {
         long carry3 = carryOut(limbs, 3);
         long new4 = carry3 + limbs[4];
--- a/src/share/classes/sun/security/util/math/intpoly/IntegerPolynomial25519.java	Sat Jul 13 15:17:33 2019 +0100
+++ b/src/share/classes/sun/security/util/math/intpoly/IntegerPolynomial25519.java	Sat Jul 13 16:49:00 2019 +0100
@@ -48,7 +48,7 @@
     private static final int RIGHT_BIT_OFFSET = BITS_PER_LIMB - BIT_OFFSET;
 
     public IntegerPolynomial25519() {
-        super(BITS_PER_LIMB, NUM_LIMBS, MODULUS);
+        super(BITS_PER_LIMB, NUM_LIMBS, 1, MODULUS);
     }
 
     @Override
@@ -60,6 +60,26 @@
     }
 
     @Override
+    protected void reduce(long[] a) {
+
+        // carry(8, 2)
+        long carry8 = carryValue(a[8]);
+        a[8] -= (carry8 << BITS_PER_LIMB);
+        a[9] += carry8;
+
+        long carry9 = carryValue(a[9]);
+        a[9] -= (carry9 << BITS_PER_LIMB);
+
+        // reduce(0, 1)
+        long reducedValue10 = (carry9 * SUBTRAHEND);
+        a[0] += ((reducedValue10 << BIT_OFFSET) & LIMB_MASK);
+        a[1] += reducedValue10 >> RIGHT_BIT_OFFSET;
+
+        // carry(0, 9)
+        carry(a, 0, 9);
+    }
+
+    @Override
     protected void mult(long[] a, long[] b, long[] r) {
 
         // Use grade-school multiplication into primitives to avoid the
@@ -153,28 +173,6 @@
         carry(r, 0, 9);
     }
 
-    protected void multByInt(long[] a, long b, long[] r) {
-        for (int i = 0; i < a.length; i++) {
-            r[i] = a[i] * b;
-        }
-
-        // carry(8, 2)
-        long carry8 = carryValue(r[8]);
-        r[8] -= (carry8 << BITS_PER_LIMB);
-        r[9] += carry8;
-
-        long carry9 = carryValue(r[9]);
-        r[9] -= (carry9 << BITS_PER_LIMB);
-
-        // reduce(0, 1)
-        long reducedValue10 = (carry9 * SUBTRAHEND);
-        r[0] += ((reducedValue10 << BIT_OFFSET) & LIMB_MASK);
-        r[1] += reducedValue10 >> RIGHT_BIT_OFFSET;
-
-        // carry(0, 9)
-        carry(r, 0, 9);
-    }
-
     @Override
     protected void square(long[] a, long[] r) {
 
--- a/src/share/classes/sun/security/util/math/intpoly/IntegerPolynomial448.java	Sat Jul 13 15:17:33 2019 +0100
+++ b/src/share/classes/sun/security/util/math/intpoly/IntegerPolynomial448.java	Sat Jul 13 16:49:00 2019 +0100
@@ -42,7 +42,7 @@
             .subtract(BigInteger.valueOf(1));
 
     public IntegerPolynomial448() {
-        super(BITS_PER_LIMB, NUM_LIMBS, MODULUS);
+        super(BITS_PER_LIMB, NUM_LIMBS, 1, MODULUS);
     }
 
     private void modReduceIn(long[] limbs, int index, long x) {
@@ -58,6 +58,25 @@
     }
 
     @Override
+    protected void reduce(long[] a) {
+
+        // carry(14, 2)
+        long carry14 = carryValue(a[14]);
+        a[14] -= (carry14 << BITS_PER_LIMB);
+        a[15] += carry14;
+
+        long carry15 = carryValue(a[15]);
+        a[15] -= (carry15 << BITS_PER_LIMB);
+
+        // reduce(0, 1)
+        a[0] += carry15;
+        a[8] += carry15;
+
+        // carry(0, 15)
+        carry(a, 0, 15);
+    }
+
+    @Override
     protected void mult(long[] a, long[] b, long[] r) {
 
         // Use grade-school multiplication into primitives to avoid the
@@ -176,27 +195,6 @@
         carry(r, 0, 15);
     }
 
-    protected void multByInt(long[] a, long b, long[] r) {
-        for (int i = 0; i < a.length; i++) {
-            r[i] = a[i] * b;
-        }
-
-        // carry(14, 2)
-        long carry14 = carryValue(r[14]);
-        r[14] -= (carry14 << BITS_PER_LIMB);
-        r[15] += carry14;
-
-        long carry15 = carryValue(r[15]);
-        r[15] -= (carry15 << BITS_PER_LIMB);
-
-        // reduce(0, 1)
-        r[0] += carry15;
-        r[8] += carry15;
-
-        // carry(0, 15)
-        carry(r, 0, 15);
-    }
-
     @Override
     protected void square(long[] a, long[] r) {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/math/intpoly/IntegerPolynomialP256.java	Sat Jul 13 16:49:00 2019 +0100
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is generated by FieldGen.jsh. Do not modify it directly.
+ */
+
+package sun.security.util.math.intpoly;
+
+import java.math.BigInteger;
+public class IntegerPolynomialP256 extends IntegerPolynomial {
+    private static final int BITS_PER_LIMB = 26;
+    private static final int NUM_LIMBS = 10;
+    private static final int MAX_ADDS = 2;
+    public static final BigInteger MODULUS = evaluateModulus();
+    private static final long CARRY_ADD = 1 << 25;
+    private static final int LIMB_MASK = -1 >>> (64 - BITS_PER_LIMB);
+    public IntegerPolynomialP256() {
+
+        super(BITS_PER_LIMB, NUM_LIMBS, MAX_ADDS, MODULUS);
+
+    }
+    private static BigInteger evaluateModulus() {
+        BigInteger result = BigInteger.valueOf(2).pow(256);
+        result = result.subtract(BigInteger.valueOf(2).pow(224));
+        result = result.add(BigInteger.valueOf(2).pow(192));
+        result = result.add(BigInteger.valueOf(2).pow(96));
+        result = result.subtract(BigInteger.valueOf(1));
+        return result;
+    }
+    @Override
+    protected void finalCarryReduceLast(long[] limbs) {
+        long c = limbs[9] >> 22;
+        limbs[9] -= c << 22;
+        limbs[8] += (c << 16) & LIMB_MASK;
+        limbs[9] += c >> 10;
+        limbs[7] -= (c << 10) & LIMB_MASK;
+        limbs[8] -= c >> 16;
+        limbs[3] -= (c << 18) & LIMB_MASK;
+        limbs[4] -= c >> 8;
+        limbs[0] += c;
+    }
+    private void carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18) {
+        long c19 = 0;
+        //reduce from position 18
+        c16 += (c18 << 20) & LIMB_MASK;
+        c17 += c18 >> 6;
+        c15 -= (c18 << 14) & LIMB_MASK;
+        c16 -= c18 >> 12;
+        c11 -= (c18 << 22) & LIMB_MASK;
+        c12 -= c18 >> 4;
+        c8 += (c18 << 4) & LIMB_MASK;
+        c9 += c18 >> 22;
+        //reduce from position 17
+        c15 += (c17 << 20) & LIMB_MASK;
+        c16 += c17 >> 6;
+        c14 -= (c17 << 14) & LIMB_MASK;
+        c15 -= c17 >> 12;
+        c10 -= (c17 << 22) & LIMB_MASK;
+        c11 -= c17 >> 4;
+        c7 += (c17 << 4) & LIMB_MASK;
+        c8 += c17 >> 22;
+        //reduce from position 16
+        c14 += (c16 << 20) & LIMB_MASK;
+        c15 += c16 >> 6;
+        c13 -= (c16 << 14) & LIMB_MASK;
+        c14 -= c16 >> 12;
+        c9 -= (c16 << 22) & LIMB_MASK;
+        c10 -= c16 >> 4;
+        c6 += (c16 << 4) & LIMB_MASK;
+        c7 += c16 >> 22;
+        //reduce from position 15
+        c13 += (c15 << 20) & LIMB_MASK;
+        c14 += c15 >> 6;
+        c12 -= (c15 << 14) & LIMB_MASK;
+        c13 -= c15 >> 12;
+        c8 -= (c15 << 22) & LIMB_MASK;
+        c9 -= c15 >> 4;
+        c5 += (c15 << 4) & LIMB_MASK;
+        c6 += c15 >> 22;
+        //reduce from position 14
+        c12 += (c14 << 20) & LIMB_MASK;
+        c13 += c14 >> 6;
+        c11 -= (c14 << 14) & LIMB_MASK;
+        c12 -= c14 >> 12;
+        c7 -= (c14 << 22) & LIMB_MASK;
+        c8 -= c14 >> 4;
+        c4 += (c14 << 4) & LIMB_MASK;
+        c5 += c14 >> 22;
+        //reduce from position 13
+        c11 += (c13 << 20) & LIMB_MASK;
+        c12 += c13 >> 6;
+        c10 -= (c13 << 14) & LIMB_MASK;
+        c11 -= c13 >> 12;
+        c6 -= (c13 << 22) & LIMB_MASK;
+        c7 -= c13 >> 4;
+        c3 += (c13 << 4) & LIMB_MASK;
+        c4 += c13 >> 22;
+        //reduce from position 12
+        c10 += (c12 << 20) & LIMB_MASK;
+        c11 += c12 >> 6;
+        c9 -= (c12 << 14) & LIMB_MASK;
+        c10 -= c12 >> 12;
+        c5 -= (c12 << 22) & LIMB_MASK;
+        c6 -= c12 >> 4;
+        c2 += (c12 << 4) & LIMB_MASK;
+        c3 += c12 >> 22;
+        //reduce from position 11
+        c9 += (c11 << 20) & LIMB_MASK;
+        c10 += c11 >> 6;
+        c8 -= (c11 << 14) & LIMB_MASK;
+        c9 -= c11 >> 12;
+        c4 -= (c11 << 22) & LIMB_MASK;
+        c5 -= c11 >> 4;
+        c1 += (c11 << 4) & LIMB_MASK;
+        c2 += c11 >> 22;
+        //reduce from position 10
+        c8 += (c10 << 20) & LIMB_MASK;
+        c9 += c10 >> 6;
+        c7 -= (c10 << 14) & LIMB_MASK;
+        c8 -= c10 >> 12;
+        c3 -= (c10 << 22) & LIMB_MASK;
+        c4 -= c10 >> 4;
+        c0 += (c10 << 4) & LIMB_MASK;
+        c1 += c10 >> 22;
+        c10 = 0;
+
+        carryReduce0(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19);
+    }
+    void carryReduce0(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19) {
+
+        //carry from position 8
+        long t0 = (c8 + CARRY_ADD) >> 26;
+        c8 -= (t0 << 26);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 26;
+        c9 -= (t0 << 26);
+        c10 += t0;
+        //reduce from position 10
+        c8 += (c10 << 20) & LIMB_MASK;
+        c9 += c10 >> 6;
+        c7 -= (c10 << 14) & LIMB_MASK;
+        c8 -= c10 >> 12;
+        c3 -= (c10 << 22) & LIMB_MASK;
+        c4 -= c10 >> 4;
+        c0 += (c10 << 4) & LIMB_MASK;
+        c1 += c10 >> 22;
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 26;
+        c0 -= (t0 << 26);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 26;
+        c1 -= (t0 << 26);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 26;
+        c2 -= (t0 << 26);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 26;
+        c3 -= (t0 << 26);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 26;
+        c4 -= (t0 << 26);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 26;
+        c5 -= (t0 << 26);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 26;
+        c6 -= (t0 << 26);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 26;
+        c7 -= (t0 << 26);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 26;
+        c8 -= (t0 << 26);
+        c9 += t0;
+
+        r[0] = c0;
+        r[1] = c1;
+        r[2] = c2;
+        r[3] = c3;
+        r[4] = c4;
+        r[5] = c5;
+        r[6] = c6;
+        r[7] = c7;
+        r[8] = c8;
+        r[9] = c9;
+    }
+    private void carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9) {
+        long c10 = 0;
+        //carry from position 8
+        long t0 = (c8 + CARRY_ADD) >> 26;
+        c8 -= (t0 << 26);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 26;
+        c9 -= (t0 << 26);
+        c10 += t0;
+        //reduce from position 10
+        c8 += (c10 << 20) & LIMB_MASK;
+        c9 += c10 >> 6;
+        c7 -= (c10 << 14) & LIMB_MASK;
+        c8 -= c10 >> 12;
+        c3 -= (c10 << 22) & LIMB_MASK;
+        c4 -= c10 >> 4;
+        c0 += (c10 << 4) & LIMB_MASK;
+        c1 += c10 >> 22;
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 26;
+        c0 -= (t0 << 26);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 26;
+        c1 -= (t0 << 26);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 26;
+        c2 -= (t0 << 26);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 26;
+        c3 -= (t0 << 26);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 26;
+        c4 -= (t0 << 26);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 26;
+        c5 -= (t0 << 26);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 26;
+        c6 -= (t0 << 26);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 26;
+        c7 -= (t0 << 26);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 26;
+        c8 -= (t0 << 26);
+        c9 += t0;
+
+        r[0] = c0;
+        r[1] = c1;
+        r[2] = c2;
+        r[3] = c3;
+        r[4] = c4;
+        r[5] = c5;
+        r[6] = c6;
+        r[7] = c7;
+        r[8] = c8;
+        r[9] = c9;
+    }
+    @Override
+    protected void mult(long[] a, long[] b, long[] r) {
+        long c0 = (a[0] * b[0]);
+        long c1 = (a[0] * b[1]) + (a[1] * b[0]);
+        long c2 = (a[0] * b[2]) + (a[1] * b[1]) + (a[2] * b[0]);
+        long c3 = (a[0] * b[3]) + (a[1] * b[2]) + (a[2] * b[1]) + (a[3] * b[0]);
+        long c4 = (a[0] * b[4]) + (a[1] * b[3]) + (a[2] * b[2]) + (a[3] * b[1]) + (a[4] * b[0]);
+        long c5 = (a[0] * b[5]) + (a[1] * b[4]) + (a[2] * b[3]) + (a[3] * b[2]) + (a[4] * b[1]) + (a[5] * b[0]);
+        long c6 = (a[0] * b[6]) + (a[1] * b[5]) + (a[2] * b[4]) + (a[3] * b[3]) + (a[4] * b[2]) + (a[5] * b[1]) + (a[6] * b[0]);
+        long c7 = (a[0] * b[7]) + (a[1] * b[6]) + (a[2] * b[5]) + (a[3] * b[4]) + (a[4] * b[3]) + (a[5] * b[2]) + (a[6] * b[1]) + (a[7] * b[0]);
+        long c8 = (a[0] * b[8]) + (a[1] * b[7]) + (a[2] * b[6]) + (a[3] * b[5]) + (a[4] * b[4]) + (a[5] * b[3]) + (a[6] * b[2]) + (a[7] * b[1]) + (a[8] * b[0]);
+        long c9 = (a[0] * b[9]) + (a[1] * b[8]) + (a[2] * b[7]) + (a[3] * b[6]) + (a[4] * b[5]) + (a[5] * b[4]) + (a[6] * b[3]) + (a[7] * b[2]) + (a[8] * b[1]) + (a[9] * b[0]);
+        long c10 = (a[1] * b[9]) + (a[2] * b[8]) + (a[3] * b[7]) + (a[4] * b[6]) + (a[5] * b[5]) + (a[6] * b[4]) + (a[7] * b[3]) + (a[8] * b[2]) + (a[9] * b[1]);
+        long c11 = (a[2] * b[9]) + (a[3] * b[8]) + (a[4] * b[7]) + (a[5] * b[6]) + (a[6] * b[5]) + (a[7] * b[4]) + (a[8] * b[3]) + (a[9] * b[2]);
+        long c12 = (a[3] * b[9]) + (a[4] * b[8]) + (a[5] * b[7]) + (a[6] * b[6]) + (a[7] * b[5]) + (a[8] * b[4]) + (a[9] * b[3]);
+        long c13 = (a[4] * b[9]) + (a[5] * b[8]) + (a[6] * b[7]) + (a[7] * b[6]) + (a[8] * b[5]) + (a[9] * b[4]);
+        long c14 = (a[5] * b[9]) + (a[6] * b[8]) + (a[7] * b[7]) + (a[8] * b[6]) + (a[9] * b[5]);
+        long c15 = (a[6] * b[9]) + (a[7] * b[8]) + (a[8] * b[7]) + (a[9] * b[6]);
+        long c16 = (a[7] * b[9]) + (a[8] * b[8]) + (a[9] * b[7]);
+        long c17 = (a[8] * b[9]) + (a[9] * b[8]);
+        long c18 = (a[9] * b[9]);
+
+        carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18);
+    }
+    @Override
+    protected void reduce(long[] a) {
+        carryReduce(a, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
+    }
+    @Override
+    protected void square(long[] a, long[] r) {
+        long c0 = (a[0] * a[0]);
+        long c1 = 2 * ((a[0] * a[1]));
+        long c2 = 2 * ((a[0] * a[2])) + (a[1] * a[1]);
+        long c3 = 2 * ((a[0] * a[3]) + (a[1] * a[2]));
+        long c4 = 2 * ((a[0] * a[4]) + (a[1] * a[3])) + (a[2] * a[2]);
+        long c5 = 2 * ((a[0] * a[5]) + (a[1] * a[4]) + (a[2] * a[3]));
+        long c6 = 2 * ((a[0] * a[6]) + (a[1] * a[5]) + (a[2] * a[4])) + (a[3] * a[3]);
+        long c7 = 2 * ((a[0] * a[7]) + (a[1] * a[6]) + (a[2] * a[5]) + (a[3] * a[4]));
+        long c8 = 2 * ((a[0] * a[8]) + (a[1] * a[7]) + (a[2] * a[6]) + (a[3] * a[5])) + (a[4] * a[4]);
+        long c9 = 2 * ((a[0] * a[9]) + (a[1] * a[8]) + (a[2] * a[7]) + (a[3] * a[6]) + (a[4] * a[5]));
+        long c10 = 2 * ((a[1] * a[9]) + (a[2] * a[8]) + (a[3] * a[7]) + (a[4] * a[6])) + (a[5] * a[5]);
+        long c11 = 2 * ((a[2] * a[9]) + (a[3] * a[8]) + (a[4] * a[7]) + (a[5] * a[6]));
+        long c12 = 2 * ((a[3] * a[9]) + (a[4] * a[8]) + (a[5] * a[7])) + (a[6] * a[6]);
+        long c13 = 2 * ((a[4] * a[9]) + (a[5] * a[8]) + (a[6] * a[7]));
+        long c14 = 2 * ((a[5] * a[9]) + (a[6] * a[8])) + (a[7] * a[7]);
+        long c15 = 2 * ((a[6] * a[9]) + (a[7] * a[8]));
+        long c16 = 2 * ((a[7] * a[9])) + (a[8] * a[8]);
+        long c17 = 2 * ((a[8] * a[9]));
+        long c18 = (a[9] * a[9]);
+
+        carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/math/intpoly/IntegerPolynomialP384.java	Sat Jul 13 16:49:00 2019 +0100
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is generated by FieldGen.jsh. Do not modify it directly.
+ */
+
+package sun.security.util.math.intpoly;
+
+import java.math.BigInteger;
+public class IntegerPolynomialP384 extends IntegerPolynomial {
+    private static final int BITS_PER_LIMB = 28;
+    private static final int NUM_LIMBS = 14;
+    private static final int MAX_ADDS = 2;
+    public static final BigInteger MODULUS = evaluateModulus();
+    private static final long CARRY_ADD = 1 << 27;
+    private static final int LIMB_MASK = -1 >>> (64 - BITS_PER_LIMB);
+    public IntegerPolynomialP384() {
+
+        super(BITS_PER_LIMB, NUM_LIMBS, MAX_ADDS, MODULUS);
+
+    }
+    private static BigInteger evaluateModulus() {
+        BigInteger result = BigInteger.valueOf(2).pow(384);
+        result = result.subtract(BigInteger.valueOf(2).pow(128));
+        result = result.subtract(BigInteger.valueOf(2).pow(96));
+        result = result.add(BigInteger.valueOf(2).pow(32));
+        result = result.subtract(BigInteger.valueOf(1));
+        return result;
+    }
+    @Override
+    protected void finalCarryReduceLast(long[] limbs) {
+        long c = limbs[13] >> 20;
+        limbs[13] -= c << 20;
+        limbs[4] += (c << 16) & LIMB_MASK;
+        limbs[5] += c >> 12;
+        limbs[3] += (c << 12) & LIMB_MASK;
+        limbs[4] += c >> 16;
+        limbs[1] -= (c << 4) & LIMB_MASK;
+        limbs[2] -= c >> 24;
+        limbs[0] += c;
+    }
+    private void carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26) {
+        long c27 = 0;
+        //reduce from position 26
+        c16 += (c26 << 24) & LIMB_MASK;
+        c17 += c26 >> 4;
+        c15 += (c26 << 20) & LIMB_MASK;
+        c16 += c26 >> 8;
+        c13 -= (c26 << 12) & LIMB_MASK;
+        c14 -= c26 >> 16;
+        c12 += (c26 << 8) & LIMB_MASK;
+        c13 += c26 >> 20;
+        //reduce from position 25
+        c15 += (c25 << 24) & LIMB_MASK;
+        c16 += c25 >> 4;
+        c14 += (c25 << 20) & LIMB_MASK;
+        c15 += c25 >> 8;
+        c12 -= (c25 << 12) & LIMB_MASK;
+        c13 -= c25 >> 16;
+        c11 += (c25 << 8) & LIMB_MASK;
+        c12 += c25 >> 20;
+        //reduce from position 24
+        c14 += (c24 << 24) & LIMB_MASK;
+        c15 += c24 >> 4;
+        c13 += (c24 << 20) & LIMB_MASK;
+        c14 += c24 >> 8;
+        c11 -= (c24 << 12) & LIMB_MASK;
+        c12 -= c24 >> 16;
+        c10 += (c24 << 8) & LIMB_MASK;
+        c11 += c24 >> 20;
+        //reduce from position 23
+        c13 += (c23 << 24) & LIMB_MASK;
+        c14 += c23 >> 4;
+        c12 += (c23 << 20) & LIMB_MASK;
+        c13 += c23 >> 8;
+        c10 -= (c23 << 12) & LIMB_MASK;
+        c11 -= c23 >> 16;
+        c9 += (c23 << 8) & LIMB_MASK;
+        c10 += c23 >> 20;
+        //reduce from position 22
+        c12 += (c22 << 24) & LIMB_MASK;
+        c13 += c22 >> 4;
+        c11 += (c22 << 20) & LIMB_MASK;
+        c12 += c22 >> 8;
+        c9 -= (c22 << 12) & LIMB_MASK;
+        c10 -= c22 >> 16;
+        c8 += (c22 << 8) & LIMB_MASK;
+        c9 += c22 >> 20;
+        //reduce from position 21
+        c11 += (c21 << 24) & LIMB_MASK;
+        c12 += c21 >> 4;
+        c10 += (c21 << 20) & LIMB_MASK;
+        c11 += c21 >> 8;
+        c8 -= (c21 << 12) & LIMB_MASK;
+        c9 -= c21 >> 16;
+        c7 += (c21 << 8) & LIMB_MASK;
+        c8 += c21 >> 20;
+        //reduce from position 20
+        c10 += (c20 << 24) & LIMB_MASK;
+        c11 += c20 >> 4;
+        c9 += (c20 << 20) & LIMB_MASK;
+        c10 += c20 >> 8;
+        c7 -= (c20 << 12) & LIMB_MASK;
+        c8 -= c20 >> 16;
+        c6 += (c20 << 8) & LIMB_MASK;
+        c7 += c20 >> 20;
+        //reduce from position 19
+        c9 += (c19 << 24) & LIMB_MASK;
+        c10 += c19 >> 4;
+        c8 += (c19 << 20) & LIMB_MASK;
+        c9 += c19 >> 8;
+        c6 -= (c19 << 12) & LIMB_MASK;
+        c7 -= c19 >> 16;
+        c5 += (c19 << 8) & LIMB_MASK;
+        c6 += c19 >> 20;
+        //reduce from position 18
+        c8 += (c18 << 24) & LIMB_MASK;
+        c9 += c18 >> 4;
+        c7 += (c18 << 20) & LIMB_MASK;
+        c8 += c18 >> 8;
+        c5 -= (c18 << 12) & LIMB_MASK;
+        c6 -= c18 >> 16;
+        c4 += (c18 << 8) & LIMB_MASK;
+        c5 += c18 >> 20;
+        //reduce from position 17
+        c7 += (c17 << 24) & LIMB_MASK;
+        c8 += c17 >> 4;
+        c6 += (c17 << 20) & LIMB_MASK;
+        c7 += c17 >> 8;
+        c4 -= (c17 << 12) & LIMB_MASK;
+        c5 -= c17 >> 16;
+        c3 += (c17 << 8) & LIMB_MASK;
+        c4 += c17 >> 20;
+        //reduce from position 16
+        c6 += (c16 << 24) & LIMB_MASK;
+        c7 += c16 >> 4;
+        c5 += (c16 << 20) & LIMB_MASK;
+        c6 += c16 >> 8;
+        c3 -= (c16 << 12) & LIMB_MASK;
+        c4 -= c16 >> 16;
+        c2 += (c16 << 8) & LIMB_MASK;
+        c3 += c16 >> 20;
+        //reduce from position 15
+        c5 += (c15 << 24) & LIMB_MASK;
+        c6 += c15 >> 4;
+        c4 += (c15 << 20) & LIMB_MASK;
+        c5 += c15 >> 8;
+        c2 -= (c15 << 12) & LIMB_MASK;
+        c3 -= c15 >> 16;
+        c1 += (c15 << 8) & LIMB_MASK;
+        c2 += c15 >> 20;
+        //reduce from position 14
+        c4 += (c14 << 24) & LIMB_MASK;
+        c5 += c14 >> 4;
+        c3 += (c14 << 20) & LIMB_MASK;
+        c4 += c14 >> 8;
+        c1 -= (c14 << 12) & LIMB_MASK;
+        c2 -= c14 >> 16;
+        c0 += (c14 << 8) & LIMB_MASK;
+        c1 += c14 >> 20;
+        c14 = 0;
+
+        carryReduce0(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27);
+    }
+    void carryReduce0(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26, long c27) {
+
+        //carry from position 12
+        long t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 28;
+        c13 -= (t0 << 28);
+        c14 += t0;
+        //reduce from position 14
+        c4 += (c14 << 24) & LIMB_MASK;
+        c5 += c14 >> 4;
+        c3 += (c14 << 20) & LIMB_MASK;
+        c4 += c14 >> 8;
+        c1 -= (c14 << 12) & LIMB_MASK;
+        c2 -= c14 >> 16;
+        c0 += (c14 << 8) & LIMB_MASK;
+        c1 += c14 >> 20;
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+
+        r[0] = c0;
+        r[1] = c1;
+        r[2] = c2;
+        r[3] = c3;
+        r[4] = c4;
+        r[5] = c5;
+        r[6] = c6;
+        r[7] = c7;
+        r[8] = c8;
+        r[9] = c9;
+        r[10] = c10;
+        r[11] = c11;
+        r[12] = c12;
+        r[13] = c13;
+    }
+    private void carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13) {
+        long c14 = 0;
+        //carry from position 12
+        long t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 28;
+        c13 -= (t0 << 28);
+        c14 += t0;
+        //reduce from position 14
+        c4 += (c14 << 24) & LIMB_MASK;
+        c5 += c14 >> 4;
+        c3 += (c14 << 20) & LIMB_MASK;
+        c4 += c14 >> 8;
+        c1 -= (c14 << 12) & LIMB_MASK;
+        c2 -= c14 >> 16;
+        c0 += (c14 << 8) & LIMB_MASK;
+        c1 += c14 >> 20;
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+
+        r[0] = c0;
+        r[1] = c1;
+        r[2] = c2;
+        r[3] = c3;
+        r[4] = c4;
+        r[5] = c5;
+        r[6] = c6;
+        r[7] = c7;
+        r[8] = c8;
+        r[9] = c9;
+        r[10] = c10;
+        r[11] = c11;
+        r[12] = c12;
+        r[13] = c13;
+    }
+    @Override
+    protected void mult(long[] a, long[] b, long[] r) {
+        long c0 = (a[0] * b[0]);
+        long c1 = (a[0] * b[1]) + (a[1] * b[0]);
+        long c2 = (a[0] * b[2]) + (a[1] * b[1]) + (a[2] * b[0]);
+        long c3 = (a[0] * b[3]) + (a[1] * b[2]) + (a[2] * b[1]) + (a[3] * b[0]);
+        long c4 = (a[0] * b[4]) + (a[1] * b[3]) + (a[2] * b[2]) + (a[3] * b[1]) + (a[4] * b[0]);
+        long c5 = (a[0] * b[5]) + (a[1] * b[4]) + (a[2] * b[3]) + (a[3] * b[2]) + (a[4] * b[1]) + (a[5] * b[0]);
+        long c6 = (a[0] * b[6]) + (a[1] * b[5]) + (a[2] * b[4]) + (a[3] * b[3]) + (a[4] * b[2]) + (a[5] * b[1]) + (a[6] * b[0]);
+        long c7 = (a[0] * b[7]) + (a[1] * b[6]) + (a[2] * b[5]) + (a[3] * b[4]) + (a[4] * b[3]) + (a[5] * b[2]) + (a[6] * b[1]) + (a[7] * b[0]);
+        long c8 = (a[0] * b[8]) + (a[1] * b[7]) + (a[2] * b[6]) + (a[3] * b[5]) + (a[4] * b[4]) + (a[5] * b[3]) + (a[6] * b[2]) + (a[7] * b[1]) + (a[8] * b[0]);
+        long c9 = (a[0] * b[9]) + (a[1] * b[8]) + (a[2] * b[7]) + (a[3] * b[6]) + (a[4] * b[5]) + (a[5] * b[4]) + (a[6] * b[3]) + (a[7] * b[2]) + (a[8] * b[1]) + (a[9] * b[0]);
+        long c10 = (a[0] * b[10]) + (a[1] * b[9]) + (a[2] * b[8]) + (a[3] * b[7]) + (a[4] * b[6]) + (a[5] * b[5]) + (a[6] * b[4]) + (a[7] * b[3]) + (a[8] * b[2]) + (a[9] * b[1]) + (a[10] * b[0]);
+        long c11 = (a[0] * b[11]) + (a[1] * b[10]) + (a[2] * b[9]) + (a[3] * b[8]) + (a[4] * b[7]) + (a[5] * b[6]) + (a[6] * b[5]) + (a[7] * b[4]) + (a[8] * b[3]) + (a[9] * b[2]) + (a[10] * b[1]) + (a[11] * b[0]);
+        long c12 = (a[0] * b[12]) + (a[1] * b[11]) + (a[2] * b[10]) + (a[3] * b[9]) + (a[4] * b[8]) + (a[5] * b[7]) + (a[6] * b[6]) + (a[7] * b[5]) + (a[8] * b[4]) + (a[9] * b[3]) + (a[10] * b[2]) + (a[11] * b[1]) + (a[12] * b[0]);
+        long c13 = (a[0] * b[13]) + (a[1] * b[12]) + (a[2] * b[11]) + (a[3] * b[10]) + (a[4] * b[9]) + (a[5] * b[8]) + (a[6] * b[7]) + (a[7] * b[6]) + (a[8] * b[5]) + (a[9] * b[4]) + (a[10] * b[3]) + (a[11] * b[2]) + (a[12] * b[1]) + (a[13] * b[0]);
+        long c14 = (a[1] * b[13]) + (a[2] * b[12]) + (a[3] * b[11]) + (a[4] * b[10]) + (a[5] * b[9]) + (a[6] * b[8]) + (a[7] * b[7]) + (a[8] * b[6]) + (a[9] * b[5]) + (a[10] * b[4]) + (a[11] * b[3]) + (a[12] * b[2]) + (a[13] * b[1]);
+        long c15 = (a[2] * b[13]) + (a[3] * b[12]) + (a[4] * b[11]) + (a[5] * b[10]) + (a[6] * b[9]) + (a[7] * b[8]) + (a[8] * b[7]) + (a[9] * b[6]) + (a[10] * b[5]) + (a[11] * b[4]) + (a[12] * b[3]) + (a[13] * b[2]);
+        long c16 = (a[3] * b[13]) + (a[4] * b[12]) + (a[5] * b[11]) + (a[6] * b[10]) + (a[7] * b[9]) + (a[8] * b[8]) + (a[9] * b[7]) + (a[10] * b[6]) + (a[11] * b[5]) + (a[12] * b[4]) + (a[13] * b[3]);
+        long c17 = (a[4] * b[13]) + (a[5] * b[12]) + (a[6] * b[11]) + (a[7] * b[10]) + (a[8] * b[9]) + (a[9] * b[8]) + (a[10] * b[7]) + (a[11] * b[6]) + (a[12] * b[5]) + (a[13] * b[4]);
+        long c18 = (a[5] * b[13]) + (a[6] * b[12]) + (a[7] * b[11]) + (a[8] * b[10]) + (a[9] * b[9]) + (a[10] * b[8]) + (a[11] * b[7]) + (a[12] * b[6]) + (a[13] * b[5]);
+        long c19 = (a[6] * b[13]) + (a[7] * b[12]) + (a[8] * b[11]) + (a[9] * b[10]) + (a[10] * b[9]) + (a[11] * b[8]) + (a[12] * b[7]) + (a[13] * b[6]);
+        long c20 = (a[7] * b[13]) + (a[8] * b[12]) + (a[9] * b[11]) + (a[10] * b[10]) + (a[11] * b[9]) + (a[12] * b[8]) + (a[13] * b[7]);
+        long c21 = (a[8] * b[13]) + (a[9] * b[12]) + (a[10] * b[11]) + (a[11] * b[10]) + (a[12] * b[9]) + (a[13] * b[8]);
+        long c22 = (a[9] * b[13]) + (a[10] * b[12]) + (a[11] * b[11]) + (a[12] * b[10]) + (a[13] * b[9]);
+        long c23 = (a[10] * b[13]) + (a[11] * b[12]) + (a[12] * b[11]) + (a[13] * b[10]);
+        long c24 = (a[11] * b[13]) + (a[12] * b[12]) + (a[13] * b[11]);
+        long c25 = (a[12] * b[13]) + (a[13] * b[12]);
+        long c26 = (a[13] * b[13]);
+
+        carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26);
+    }
+    @Override
+    protected void reduce(long[] a) {
+        carryReduce(a, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13]);
+    }
+    @Override
+    protected void square(long[] a, long[] r) {
+        long c0 = (a[0] * a[0]);
+        long c1 = 2 * ((a[0] * a[1]));
+        long c2 = 2 * ((a[0] * a[2])) + (a[1] * a[1]);
+        long c3 = 2 * ((a[0] * a[3]) + (a[1] * a[2]));
+        long c4 = 2 * ((a[0] * a[4]) + (a[1] * a[3])) + (a[2] * a[2]);
+        long c5 = 2 * ((a[0] * a[5]) + (a[1] * a[4]) + (a[2] * a[3]));
+        long c6 = 2 * ((a[0] * a[6]) + (a[1] * a[5]) + (a[2] * a[4])) + (a[3] * a[3]);
+        long c7 = 2 * ((a[0] * a[7]) + (a[1] * a[6]) + (a[2] * a[5]) + (a[3] * a[4]));
+        long c8 = 2 * ((a[0] * a[8]) + (a[1] * a[7]) + (a[2] * a[6]) + (a[3] * a[5])) + (a[4] * a[4]);
+        long c9 = 2 * ((a[0] * a[9]) + (a[1] * a[8]) + (a[2] * a[7]) + (a[3] * a[6]) + (a[4] * a[5]));
+        long c10 = 2 * ((a[0] * a[10]) + (a[1] * a[9]) + (a[2] * a[8]) + (a[3] * a[7]) + (a[4] * a[6])) + (a[5] * a[5]);
+        long c11 = 2 * ((a[0] * a[11]) + (a[1] * a[10]) + (a[2] * a[9]) + (a[3] * a[8]) + (a[4] * a[7]) + (a[5] * a[6]));
+        long c12 = 2 * ((a[0] * a[12]) + (a[1] * a[11]) + (a[2] * a[10]) + (a[3] * a[9]) + (a[4] * a[8]) + (a[5] * a[7])) + (a[6] * a[6]);
+        long c13 = 2 * ((a[0] * a[13]) + (a[1] * a[12]) + (a[2] * a[11]) + (a[3] * a[10]) + (a[4] * a[9]) + (a[5] * a[8]) + (a[6] * a[7]));
+        long c14 = 2 * ((a[1] * a[13]) + (a[2] * a[12]) + (a[3] * a[11]) + (a[4] * a[10]) + (a[5] * a[9]) + (a[6] * a[8])) + (a[7] * a[7]);
+        long c15 = 2 * ((a[2] * a[13]) + (a[3] * a[12]) + (a[4] * a[11]) + (a[5] * a[10]) + (a[6] * a[9]) + (a[7] * a[8]));
+        long c16 = 2 * ((a[3] * a[13]) + (a[4] * a[12]) + (a[5] * a[11]) + (a[6] * a[10]) + (a[7] * a[9])) + (a[8] * a[8]);
+        long c17 = 2 * ((a[4] * a[13]) + (a[5] * a[12]) + (a[6] * a[11]) + (a[7] * a[10]) + (a[8] * a[9]));
+        long c18 = 2 * ((a[5] * a[13]) + (a[6] * a[12]) + (a[7] * a[11]) + (a[8] * a[10])) + (a[9] * a[9]);
+        long c19 = 2 * ((a[6] * a[13]) + (a[7] * a[12]) + (a[8] * a[11]) + (a[9] * a[10]));
+        long c20 = 2 * ((a[7] * a[13]) + (a[8] * a[12]) + (a[9] * a[11])) + (a[10] * a[10]);
+        long c21 = 2 * ((a[8] * a[13]) + (a[9] * a[12]) + (a[10] * a[11]));
+        long c22 = 2 * ((a[9] * a[13]) + (a[10] * a[12])) + (a[11] * a[11]);
+        long c23 = 2 * ((a[10] * a[13]) + (a[11] * a[12]));
+        long c24 = 2 * ((a[11] * a[13])) + (a[12] * a[12]);
+        long c25 = 2 * ((a[12] * a[13]));
+        long c26 = (a[13] * a[13]);
+
+        carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/math/intpoly/IntegerPolynomialP521.java	Sat Jul 13 16:49:00 2019 +0100
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is generated by FieldGen.jsh. Do not modify it directly.
+ */
+
+package sun.security.util.math.intpoly;
+
+import java.math.BigInteger;
+public class IntegerPolynomialP521 extends IntegerPolynomial {
+    private static final int BITS_PER_LIMB = 28;
+    private static final int NUM_LIMBS = 19;
+    private static final int MAX_ADDS = 2;
+    public static final BigInteger MODULUS = evaluateModulus();
+    private static final long CARRY_ADD = 1 << 27;
+    private static final int LIMB_MASK = -1 >>> (64 - BITS_PER_LIMB);
+    public IntegerPolynomialP521() {
+
+        super(BITS_PER_LIMB, NUM_LIMBS, MAX_ADDS, MODULUS);
+
+    }
+    private static BigInteger evaluateModulus() {
+        BigInteger result = BigInteger.valueOf(2).pow(521);
+        result = result.subtract(BigInteger.valueOf(1));
+        return result;
+    }
+    @Override
+    protected void finalCarryReduceLast(long[] limbs) {
+        long c = limbs[18] >> 17;
+        limbs[18] -= c << 17;
+        limbs[0] += c;
+    }
+    private void carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26, long c27, long c28, long c29, long c30, long c31, long c32, long c33, long c34, long c35, long c36) {
+        long c37 = 0;
+        //reduce from position 36
+        c17 += (c36 << 11) & LIMB_MASK;
+        c18 += c36 >> 17;
+        //reduce from position 35
+        c16 += (c35 << 11) & LIMB_MASK;
+        c17 += c35 >> 17;
+        //reduce from position 34
+        c15 += (c34 << 11) & LIMB_MASK;
+        c16 += c34 >> 17;
+        //reduce from position 33
+        c14 += (c33 << 11) & LIMB_MASK;
+        c15 += c33 >> 17;
+        //reduce from position 32
+        c13 += (c32 << 11) & LIMB_MASK;
+        c14 += c32 >> 17;
+        //reduce from position 31
+        c12 += (c31 << 11) & LIMB_MASK;
+        c13 += c31 >> 17;
+        //reduce from position 30
+        c11 += (c30 << 11) & LIMB_MASK;
+        c12 += c30 >> 17;
+        //reduce from position 29
+        c10 += (c29 << 11) & LIMB_MASK;
+        c11 += c29 >> 17;
+        //reduce from position 28
+        c9 += (c28 << 11) & LIMB_MASK;
+        c10 += c28 >> 17;
+        //reduce from position 27
+        c8 += (c27 << 11) & LIMB_MASK;
+        c9 += c27 >> 17;
+        //reduce from position 26
+        c7 += (c26 << 11) & LIMB_MASK;
+        c8 += c26 >> 17;
+        //reduce from position 25
+        c6 += (c25 << 11) & LIMB_MASK;
+        c7 += c25 >> 17;
+        //reduce from position 24
+        c5 += (c24 << 11) & LIMB_MASK;
+        c6 += c24 >> 17;
+        //reduce from position 23
+        c4 += (c23 << 11) & LIMB_MASK;
+        c5 += c23 >> 17;
+        //reduce from position 22
+        c3 += (c22 << 11) & LIMB_MASK;
+        c4 += c22 >> 17;
+        //reduce from position 21
+        c2 += (c21 << 11) & LIMB_MASK;
+        c3 += c21 >> 17;
+        //reduce from position 20
+        c1 += (c20 << 11) & LIMB_MASK;
+        c2 += c20 >> 17;
+        //reduce from position 19
+        c0 += (c19 << 11) & LIMB_MASK;
+        c1 += c19 >> 17;
+        c19 = 0;
+
+        carryReduce0(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c36, c37);
+    }
+    void carryReduce0(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26, long c27, long c28, long c29, long c30, long c31, long c32, long c33, long c34, long c35, long c36, long c37) {
+
+        //carry from position 17
+        long t0 = (c17 + CARRY_ADD) >> 28;
+        c17 -= (t0 << 28);
+        c18 += t0;
+        //carry from position 18
+        t0 = (c18 + CARRY_ADD) >> 28;
+        c18 -= (t0 << 28);
+        c19 += t0;
+        //reduce from position 19
+        c0 += (c19 << 11) & LIMB_MASK;
+        c1 += c19 >> 17;
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 28;
+        c13 -= (t0 << 28);
+        c14 += t0;
+        //carry from position 14
+        t0 = (c14 + CARRY_ADD) >> 28;
+        c14 -= (t0 << 28);
+        c15 += t0;
+        //carry from position 15
+        t0 = (c15 + CARRY_ADD) >> 28;
+        c15 -= (t0 << 28);
+        c16 += t0;
+        //carry from position 16
+        t0 = (c16 + CARRY_ADD) >> 28;
+        c16 -= (t0 << 28);
+        c17 += t0;
+        //carry from position 17
+        t0 = (c17 + CARRY_ADD) >> 28;
+        c17 -= (t0 << 28);
+        c18 += t0;
+
+        r[0] = c0;
+        r[1] = c1;
+        r[2] = c2;
+        r[3] = c3;
+        r[4] = c4;
+        r[5] = c5;
+        r[6] = c6;
+        r[7] = c7;
+        r[8] = c8;
+        r[9] = c9;
+        r[10] = c10;
+        r[11] = c11;
+        r[12] = c12;
+        r[13] = c13;
+        r[14] = c14;
+        r[15] = c15;
+        r[16] = c16;
+        r[17] = c17;
+        r[18] = c18;
+    }
+    private void carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18) {
+        long c19 = 0;
+        //carry from position 17
+        long t0 = (c17 + CARRY_ADD) >> 28;
+        c17 -= (t0 << 28);
+        c18 += t0;
+        //carry from position 18
+        t0 = (c18 + CARRY_ADD) >> 28;
+        c18 -= (t0 << 28);
+        c19 += t0;
+        //reduce from position 19
+        c0 += (c19 << 11) & LIMB_MASK;
+        c1 += c19 >> 17;
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 28;
+        c13 -= (t0 << 28);
+        c14 += t0;
+        //carry from position 14
+        t0 = (c14 + CARRY_ADD) >> 28;
+        c14 -= (t0 << 28);
+        c15 += t0;
+        //carry from position 15
+        t0 = (c15 + CARRY_ADD) >> 28;
+        c15 -= (t0 << 28);
+        c16 += t0;
+        //carry from position 16
+        t0 = (c16 + CARRY_ADD) >> 28;
+        c16 -= (t0 << 28);
+        c17 += t0;
+        //carry from position 17
+        t0 = (c17 + CARRY_ADD) >> 28;
+        c17 -= (t0 << 28);
+        c18 += t0;
+
+        r[0] = c0;
+        r[1] = c1;
+        r[2] = c2;
+        r[3] = c3;
+        r[4] = c4;
+        r[5] = c5;
+        r[6] = c6;
+        r[7] = c7;
+        r[8] = c8;
+        r[9] = c9;
+        r[10] = c10;
+        r[11] = c11;
+        r[12] = c12;
+        r[13] = c13;
+        r[14] = c14;
+        r[15] = c15;
+        r[16] = c16;
+        r[17] = c17;
+        r[18] = c18;
+    }
+    @Override
+    protected void mult(long[] a, long[] b, long[] r) {
+        long c0 = (a[0] * b[0]);
+        long c1 = (a[0] * b[1]) + (a[1] * b[0]);
+        long c2 = (a[0] * b[2]) + (a[1] * b[1]) + (a[2] * b[0]);
+        long c3 = (a[0] * b[3]) + (a[1] * b[2]) + (a[2] * b[1]) + (a[3] * b[0]);
+        long c4 = (a[0] * b[4]) + (a[1] * b[3]) + (a[2] * b[2]) + (a[3] * b[1]) + (a[4] * b[0]);
+        long c5 = (a[0] * b[5]) + (a[1] * b[4]) + (a[2] * b[3]) + (a[3] * b[2]) + (a[4] * b[1]) + (a[5] * b[0]);
+        long c6 = (a[0] * b[6]) + (a[1] * b[5]) + (a[2] * b[4]) + (a[3] * b[3]) + (a[4] * b[2]) + (a[5] * b[1]) + (a[6] * b[0]);
+        long c7 = (a[0] * b[7]) + (a[1] * b[6]) + (a[2] * b[5]) + (a[3] * b[4]) + (a[4] * b[3]) + (a[5] * b[2]) + (a[6] * b[1]) + (a[7] * b[0]);
+        long c8 = (a[0] * b[8]) + (a[1] * b[7]) + (a[2] * b[6]) + (a[3] * b[5]) + (a[4] * b[4]) + (a[5] * b[3]) + (a[6] * b[2]) + (a[7] * b[1]) + (a[8] * b[0]);
+        long c9 = (a[0] * b[9]) + (a[1] * b[8]) + (a[2] * b[7]) + (a[3] * b[6]) + (a[4] * b[5]) + (a[5] * b[4]) + (a[6] * b[3]) + (a[7] * b[2]) + (a[8] * b[1]) + (a[9] * b[0]);
+        long c10 = (a[0] * b[10]) + (a[1] * b[9]) + (a[2] * b[8]) + (a[3] * b[7]) + (a[4] * b[6]) + (a[5] * b[5]) + (a[6] * b[4]) + (a[7] * b[3]) + (a[8] * b[2]) + (a[9] * b[1]) + (a[10] * b[0]);
+        long c11 = (a[0] * b[11]) + (a[1] * b[10]) + (a[2] * b[9]) + (a[3] * b[8]) + (a[4] * b[7]) + (a[5] * b[6]) + (a[6] * b[5]) + (a[7] * b[4]) + (a[8] * b[3]) + (a[9] * b[2]) + (a[10] * b[1]) + (a[11] * b[0]);
+        long c12 = (a[0] * b[12]) + (a[1] * b[11]) + (a[2] * b[10]) + (a[3] * b[9]) + (a[4] * b[8]) + (a[5] * b[7]) + (a[6] * b[6]) + (a[7] * b[5]) + (a[8] * b[4]) + (a[9] * b[3]) + (a[10] * b[2]) + (a[11] * b[1]) + (a[12] * b[0]);
+        long c13 = (a[0] * b[13]) + (a[1] * b[12]) + (a[2] * b[11]) + (a[3] * b[10]) + (a[4] * b[9]) + (a[5] * b[8]) + (a[6] * b[7]) + (a[7] * b[6]) + (a[8] * b[5]) + (a[9] * b[4]) + (a[10] * b[3]) + (a[11] * b[2]) + (a[12] * b[1]) + (a[13] * b[0]);
+        long c14 = (a[0] * b[14]) + (a[1] * b[13]) + (a[2] * b[12]) + (a[3] * b[11]) + (a[4] * b[10]) + (a[5] * b[9]) + (a[6] * b[8]) + (a[7] * b[7]) + (a[8] * b[6]) + (a[9] * b[5]) + (a[10] * b[4]) + (a[11] * b[3]) + (a[12] * b[2]) + (a[13] * b[1]) + (a[14] * b[0]);
+        long c15 = (a[0] * b[15]) + (a[1] * b[14]) + (a[2] * b[13]) + (a[3] * b[12]) + (a[4] * b[11]) + (a[5] * b[10]) + (a[6] * b[9]) + (a[7] * b[8]) + (a[8] * b[7]) + (a[9] * b[6]) + (a[10] * b[5]) + (a[11] * b[4]) + (a[12] * b[3]) + (a[13] * b[2]) + (a[14] * b[1]) + (a[15] * b[0]);
+        long c16 = (a[0] * b[16]) + (a[1] * b[15]) + (a[2] * b[14]) + (a[3] * b[13]) + (a[4] * b[12]) + (a[5] * b[11]) + (a[6] * b[10]) + (a[7] * b[9]) + (a[8] * b[8]) + (a[9] * b[7]) + (a[10] * b[6]) + (a[11] * b[5]) + (a[12] * b[4]) + (a[13] * b[3]) + (a[14] * b[2]) + (a[15] * b[1]) + (a[16] * b[0]);
+        long c17 = (a[0] * b[17]) + (a[1] * b[16]) + (a[2] * b[15]) + (a[3] * b[14]) + (a[4] * b[13]) + (a[5] * b[12]) + (a[6] * b[11]) + (a[7] * b[10]) + (a[8] * b[9]) + (a[9] * b[8]) + (a[10] * b[7]) + (a[11] * b[6]) + (a[12] * b[5]) + (a[13] * b[4]) + (a[14] * b[3]) + (a[15] * b[2]) + (a[16] * b[1]) + (a[17] * b[0]);
+        long c18 = (a[0] * b[18]) + (a[1] * b[17]) + (a[2] * b[16]) + (a[3] * b[15]) + (a[4] * b[14]) + (a[5] * b[13]) + (a[6] * b[12]) + (a[7] * b[11]) + (a[8] * b[10]) + (a[9] * b[9]) + (a[10] * b[8]) + (a[11] * b[7]) + (a[12] * b[6]) + (a[13] * b[5]) + (a[14] * b[4]) + (a[15] * b[3]) + (a[16] * b[2]) + (a[17] * b[1]) + (a[18] * b[0]);
+        long c19 = (a[1] * b[18]) + (a[2] * b[17]) + (a[3] * b[16]) + (a[4] * b[15]) + (a[5] * b[14]) + (a[6] * b[13]) + (a[7] * b[12]) + (a[8] * b[11]) + (a[9] * b[10]) + (a[10] * b[9]) + (a[11] * b[8]) + (a[12] * b[7]) + (a[13] * b[6]) + (a[14] * b[5]) + (a[15] * b[4]) + (a[16] * b[3]) + (a[17] * b[2]) + (a[18] * b[1]);
+        long c20 = (a[2] * b[18]) + (a[3] * b[17]) + (a[4] * b[16]) + (a[5] * b[15]) + (a[6] * b[14]) + (a[7] * b[13]) + (a[8] * b[12]) + (a[9] * b[11]) + (a[10] * b[10]) + (a[11] * b[9]) + (a[12] * b[8]) + (a[13] * b[7]) + (a[14] * b[6]) + (a[15] * b[5]) + (a[16] * b[4]) + (a[17] * b[3]) + (a[18] * b[2]);
+        long c21 = (a[3] * b[18]) + (a[4] * b[17]) + (a[5] * b[16]) + (a[6] * b[15]) + (a[7] * b[14]) + (a[8] * b[13]) + (a[9] * b[12]) + (a[10] * b[11]) + (a[11] * b[10]) + (a[12] * b[9]) + (a[13] * b[8]) + (a[14] * b[7]) + (a[15] * b[6]) + (a[16] * b[5]) + (a[17] * b[4]) + (a[18] * b[3]);
+        long c22 = (a[4] * b[18]) + (a[5] * b[17]) + (a[6] * b[16]) + (a[7] * b[15]) + (a[8] * b[14]) + (a[9] * b[13]) + (a[10] * b[12]) + (a[11] * b[11]) + (a[12] * b[10]) + (a[13] * b[9]) + (a[14] * b[8]) + (a[15] * b[7]) + (a[16] * b[6]) + (a[17] * b[5]) + (a[18] * b[4]);
+        long c23 = (a[5] * b[18]) + (a[6] * b[17]) + (a[7] * b[16]) + (a[8] * b[15]) + (a[9] * b[14]) + (a[10] * b[13]) + (a[11] * b[12]) + (a[12] * b[11]) + (a[13] * b[10]) + (a[14] * b[9]) + (a[15] * b[8]) + (a[16] * b[7]) + (a[17] * b[6]) + (a[18] * b[5]);
+        long c24 = (a[6] * b[18]) + (a[7] * b[17]) + (a[8] * b[16]) + (a[9] * b[15]) + (a[10] * b[14]) + (a[11] * b[13]) + (a[12] * b[12]) + (a[13] * b[11]) + (a[14] * b[10]) + (a[15] * b[9]) + (a[16] * b[8]) + (a[17] * b[7]) + (a[18] * b[6]);
+        long c25 = (a[7] * b[18]) + (a[8] * b[17]) + (a[9] * b[16]) + (a[10] * b[15]) + (a[11] * b[14]) + (a[12] * b[13]) + (a[13] * b[12]) + (a[14] * b[11]) + (a[15] * b[10]) + (a[16] * b[9]) + (a[17] * b[8]) + (a[18] * b[7]);
+        long c26 = (a[8] * b[18]) + (a[9] * b[17]) + (a[10] * b[16]) + (a[11] * b[15]) + (a[12] * b[14]) + (a[13] * b[13]) + (a[14] * b[12]) + (a[15] * b[11]) + (a[16] * b[10]) + (a[17] * b[9]) + (a[18] * b[8]);
+        long c27 = (a[9] * b[18]) + (a[10] * b[17]) + (a[11] * b[16]) + (a[12] * b[15]) + (a[13] * b[14]) + (a[14] * b[13]) + (a[15] * b[12]) + (a[16] * b[11]) + (a[17] * b[10]) + (a[18] * b[9]);
+        long c28 = (a[10] * b[18]) + (a[11] * b[17]) + (a[12] * b[16]) + (a[13] * b[15]) + (a[14] * b[14]) + (a[15] * b[13]) + (a[16] * b[12]) + (a[17] * b[11]) + (a[18] * b[10]);
+        long c29 = (a[11] * b[18]) + (a[12] * b[17]) + (a[13] * b[16]) + (a[14] * b[15]) + (a[15] * b[14]) + (a[16] * b[13]) + (a[17] * b[12]) + (a[18] * b[11]);
+        long c30 = (a[12] * b[18]) + (a[13] * b[17]) + (a[14] * b[16]) + (a[15] * b[15]) + (a[16] * b[14]) + (a[17] * b[13]) + (a[18] * b[12]);
+        long c31 = (a[13] * b[18]) + (a[14] * b[17]) + (a[15] * b[16]) + (a[16] * b[15]) + (a[17] * b[14]) + (a[18] * b[13]);
+        long c32 = (a[14] * b[18]) + (a[15] * b[17]) + (a[16] * b[16]) + (a[17] * b[15]) + (a[18] * b[14]);
+        long c33 = (a[15] * b[18]) + (a[16] * b[17]) + (a[17] * b[16]) + (a[18] * b[15]);
+        long c34 = (a[16] * b[18]) + (a[17] * b[17]) + (a[18] * b[16]);
+        long c35 = (a[17] * b[18]) + (a[18] * b[17]);
+        long c36 = (a[18] * b[18]);
+
+        carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c36);
+    }
+    @Override
+    protected void reduce(long[] a) {
+        carryReduce(a, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], a[17], a[18]);
+    }
+    @Override
+    protected void square(long[] a, long[] r) {
+        long c0 = (a[0] * a[0]);
+        long c1 = 2 * ((a[0] * a[1]));
+        long c2 = 2 * ((a[0] * a[2])) + (a[1] * a[1]);
+        long c3 = 2 * ((a[0] * a[3]) + (a[1] * a[2]));
+        long c4 = 2 * ((a[0] * a[4]) + (a[1] * a[3])) + (a[2] * a[2]);
+        long c5 = 2 * ((a[0] * a[5]) + (a[1] * a[4]) + (a[2] * a[3]));
+        long c6 = 2 * ((a[0] * a[6]) + (a[1] * a[5]) + (a[2] * a[4])) + (a[3] * a[3]);
+        long c7 = 2 * ((a[0] * a[7]) + (a[1] * a[6]) + (a[2] * a[5]) + (a[3] * a[4]));
+        long c8 = 2 * ((a[0] * a[8]) + (a[1] * a[7]) + (a[2] * a[6]) + (a[3] * a[5])) + (a[4] * a[4]);
+        long c9 = 2 * ((a[0] * a[9]) + (a[1] * a[8]) + (a[2] * a[7]) + (a[3] * a[6]) + (a[4] * a[5]));
+        long c10 = 2 * ((a[0] * a[10]) + (a[1] * a[9]) + (a[2] * a[8]) + (a[3] * a[7]) + (a[4] * a[6])) + (a[5] * a[5]);
+        long c11 = 2 * ((a[0] * a[11]) + (a[1] * a[10]) + (a[2] * a[9]) + (a[3] * a[8]) + (a[4] * a[7]) + (a[5] * a[6]));
+        long c12 = 2 * ((a[0] * a[12]) + (a[1] * a[11]) + (a[2] * a[10]) + (a[3] * a[9]) + (a[4] * a[8]) + (a[5] * a[7])) + (a[6] * a[6]);
+        long c13 = 2 * ((a[0] * a[13]) + (a[1] * a[12]) + (a[2] * a[11]) + (a[3] * a[10]) + (a[4] * a[9]) + (a[5] * a[8]) + (a[6] * a[7]));
+        long c14 = 2 * ((a[0] * a[14]) + (a[1] * a[13]) + (a[2] * a[12]) + (a[3] * a[11]) + (a[4] * a[10]) + (a[5] * a[9]) + (a[6] * a[8])) + (a[7] * a[7]);
+        long c15 = 2 * ((a[0] * a[15]) + (a[1] * a[14]) + (a[2] * a[13]) + (a[3] * a[12]) + (a[4] * a[11]) + (a[5] * a[10]) + (a[6] * a[9]) + (a[7] * a[8]));
+        long c16 = 2 * ((a[0] * a[16]) + (a[1] * a[15]) + (a[2] * a[14]) + (a[3] * a[13]) + (a[4] * a[12]) + (a[5] * a[11]) + (a[6] * a[10]) + (a[7] * a[9])) + (a[8] * a[8]);
+        long c17 = 2 * ((a[0] * a[17]) + (a[1] * a[16]) + (a[2] * a[15]) + (a[3] * a[14]) + (a[4] * a[13]) + (a[5] * a[12]) + (a[6] * a[11]) + (a[7] * a[10]) + (a[8] * a[9]));
+        long c18 = 2 * ((a[0] * a[18]) + (a[1] * a[17]) + (a[2] * a[16]) + (a[3] * a[15]) + (a[4] * a[14]) + (a[5] * a[13]) + (a[6] * a[12]) + (a[7] * a[11]) + (a[8] * a[10])) + (a[9] * a[9]);
+        long c19 = 2 * ((a[1] * a[18]) + (a[2] * a[17]) + (a[3] * a[16]) + (a[4] * a[15]) + (a[5] * a[14]) + (a[6] * a[13]) + (a[7] * a[12]) + (a[8] * a[11]) + (a[9] * a[10]));
+        long c20 = 2 * ((a[2] * a[18]) + (a[3] * a[17]) + (a[4] * a[16]) + (a[5] * a[15]) + (a[6] * a[14]) + (a[7] * a[13]) + (a[8] * a[12]) + (a[9] * a[11])) + (a[10] * a[10]);
+        long c21 = 2 * ((a[3] * a[18]) + (a[4] * a[17]) + (a[5] * a[16]) + (a[6] * a[15]) + (a[7] * a[14]) + (a[8] * a[13]) + (a[9] * a[12]) + (a[10] * a[11]));
+        long c22 = 2 * ((a[4] * a[18]) + (a[5] * a[17]) + (a[6] * a[16]) + (a[7] * a[15]) + (a[8] * a[14]) + (a[9] * a[13]) + (a[10] * a[12])) + (a[11] * a[11]);
+        long c23 = 2 * ((a[5] * a[18]) + (a[6] * a[17]) + (a[7] * a[16]) + (a[8] * a[15]) + (a[9] * a[14]) + (a[10] * a[13]) + (a[11] * a[12]));
+        long c24 = 2 * ((a[6] * a[18]) + (a[7] * a[17]) + (a[8] * a[16]) + (a[9] * a[15]) + (a[10] * a[14]) + (a[11] * a[13])) + (a[12] * a[12]);
+        long c25 = 2 * ((a[7] * a[18]) + (a[8] * a[17]) + (a[9] * a[16]) + (a[10] * a[15]) + (a[11] * a[14]) + (a[12] * a[13]));
+        long c26 = 2 * ((a[8] * a[18]) + (a[9] * a[17]) + (a[10] * a[16]) + (a[11] * a[15]) + (a[12] * a[14])) + (a[13] * a[13]);
+        long c27 = 2 * ((a[9] * a[18]) + (a[10] * a[17]) + (a[11] * a[16]) + (a[12] * a[15]) + (a[13] * a[14]));
+        long c28 = 2 * ((a[10] * a[18]) + (a[11] * a[17]) + (a[12] * a[16]) + (a[13] * a[15])) + (a[14] * a[14]);
+        long c29 = 2 * ((a[11] * a[18]) + (a[12] * a[17]) + (a[13] * a[16]) + (a[14] * a[15]));
+        long c30 = 2 * ((a[12] * a[18]) + (a[13] * a[17]) + (a[14] * a[16])) + (a[15] * a[15]);
+        long c31 = 2 * ((a[13] * a[18]) + (a[14] * a[17]) + (a[15] * a[16]));
+        long c32 = 2 * ((a[14] * a[18]) + (a[15] * a[17])) + (a[16] * a[16]);
+        long c33 = 2 * ((a[15] * a[18]) + (a[16] * a[17]));
+        long c34 = 2 * ((a[16] * a[18])) + (a[17] * a[17]);
+        long c35 = 2 * ((a[17] * a[18]));
+        long c36 = (a[18] * a[18]);
+
+        carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c36);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/math/intpoly/P256OrderField.java	Sat Jul 13 16:49:00 2019 +0100
@@ -0,0 +1,673 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is generated by FieldGen.jsh. Do not modify it directly.
+ */
+
+package sun.security.util.math.intpoly;
+
+import java.math.BigInteger;
+public class P256OrderField extends IntegerPolynomial {
+    private static final int BITS_PER_LIMB = 26;
+    private static final int NUM_LIMBS = 10;
+    private static final int MAX_ADDS = 1;
+    public static final BigInteger MODULUS = evaluateModulus();
+    private static final long CARRY_ADD = 1 << 25;
+    private static final int LIMB_MASK = -1 >>> (64 - BITS_PER_LIMB);
+    public P256OrderField() {
+
+        super(BITS_PER_LIMB, NUM_LIMBS, MAX_ADDS, MODULUS);
+
+    }
+    private static BigInteger evaluateModulus() {
+        BigInteger result = BigInteger.valueOf(2).pow(256);
+        result = result.add(BigInteger.valueOf(6497617));
+        result = result.subtract(BigInteger.valueOf(2).pow(26).multiply(BigInteger.valueOf(26038081)));
+        result = result.add(BigInteger.valueOf(2).pow(52).multiply(BigInteger.valueOf(32001852)));
+        result = result.subtract(BigInteger.valueOf(2).pow(78).multiply(BigInteger.valueOf(21586850)));
+        result = result.subtract(BigInteger.valueOf(2).pow(104).multiply(BigInteger.valueOf(4397317)));
+        result = result.add(BigInteger.valueOf(2).pow(182).multiply(BigInteger.valueOf(1024)));
+        result = result.subtract(BigInteger.valueOf(2).pow(208).multiply(BigInteger.valueOf(65536)));
+        return result;
+    }
+    @Override
+    protected void finalCarryReduceLast(long[] limbs) {
+        long c = limbs[9] >> 22;
+        limbs[9] -= c << 22;
+        long t0 = -6497617 * c;
+        limbs[0] += t0;
+        t0 = 26038081 * c;
+        limbs[1] += t0;
+        t0 = -32001852 * c;
+        limbs[2] += t0;
+        t0 = 21586850 * c;
+        limbs[3] += t0;
+        t0 = 4397317 * c;
+        limbs[4] += t0;
+        t0 = -1024 * c;
+        limbs[7] += t0;
+        t0 = 65536 * c;
+        limbs[8] += t0;
+    }
+    private void carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18) {
+        long c19 = 0;
+        //carry from position 0
+        long t0 = (c0 + CARRY_ADD) >> 26;
+        c0 -= (t0 << 26);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 26;
+        c1 -= (t0 << 26);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 26;
+        c2 -= (t0 << 26);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 26;
+        c3 -= (t0 << 26);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 26;
+        c4 -= (t0 << 26);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 26;
+        c5 -= (t0 << 26);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 26;
+        c6 -= (t0 << 26);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 26;
+        c7 -= (t0 << 26);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 26;
+        c8 -= (t0 << 26);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 26;
+        c9 -= (t0 << 26);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 26;
+        c10 -= (t0 << 26);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 26;
+        c11 -= (t0 << 26);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 26;
+        c12 -= (t0 << 26);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 26;
+        c13 -= (t0 << 26);
+        c14 += t0;
+        //carry from position 14
+        t0 = (c14 + CARRY_ADD) >> 26;
+        c14 -= (t0 << 26);
+        c15 += t0;
+        //carry from position 15
+        t0 = (c15 + CARRY_ADD) >> 26;
+        c15 -= (t0 << 26);
+        c16 += t0;
+        //carry from position 16
+        t0 = (c16 + CARRY_ADD) >> 26;
+        c16 -= (t0 << 26);
+        c17 += t0;
+        //carry from position 17
+        t0 = (c17 + CARRY_ADD) >> 26;
+        c17 -= (t0 << 26);
+        c18 += t0;
+        //carry from position 18
+        t0 = (c18 + CARRY_ADD) >> 26;
+        c18 -= (t0 << 26);
+        c19 += t0;
+
+        carryReduce0(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19);
+    }
+    void carryReduce0(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19) {
+        long t0;
+
+        //reduce from position 19
+        t0 = -6497617 * c19;
+        c9 += (t0 << 4) & LIMB_MASK;
+        c10 += t0 >> 22;
+        t0 = 26038081 * c19;
+        c10 += (t0 << 4) & LIMB_MASK;
+        c11 += t0 >> 22;
+        t0 = -32001852 * c19;
+        c11 += (t0 << 4) & LIMB_MASK;
+        c12 += t0 >> 22;
+        t0 = 21586850 * c19;
+        c12 += (t0 << 4) & LIMB_MASK;
+        c13 += t0 >> 22;
+        t0 = 4397317 * c19;
+        c13 += (t0 << 4) & LIMB_MASK;
+        c14 += t0 >> 22;
+        t0 = -1024 * c19;
+        c16 += (t0 << 4) & LIMB_MASK;
+        c17 += t0 >> 22;
+        t0 = 65536 * c19;
+        c17 += (t0 << 4) & LIMB_MASK;
+        c18 += t0 >> 22;
+        //reduce from position 18
+        t0 = -6497617 * c18;
+        c8 += (t0 << 4) & LIMB_MASK;
+        c9 += t0 >> 22;
+        t0 = 26038081 * c18;
+        c9 += (t0 << 4) & LIMB_MASK;
+        c10 += t0 >> 22;
+        t0 = -32001852 * c18;
+        c10 += (t0 << 4) & LIMB_MASK;
+        c11 += t0 >> 22;
+        t0 = 21586850 * c18;
+        c11 += (t0 << 4) & LIMB_MASK;
+        c12 += t0 >> 22;
+        t0 = 4397317 * c18;
+        c12 += (t0 << 4) & LIMB_MASK;
+        c13 += t0 >> 22;
+        t0 = -1024 * c18;
+        c15 += (t0 << 4) & LIMB_MASK;
+        c16 += t0 >> 22;
+        t0 = 65536 * c18;
+        c16 += (t0 << 4) & LIMB_MASK;
+        c17 += t0 >> 22;
+        //reduce from position 17
+        t0 = -6497617 * c17;
+        c7 += (t0 << 4) & LIMB_MASK;
+        c8 += t0 >> 22;
+        t0 = 26038081 * c17;
+        c8 += (t0 << 4) & LIMB_MASK;
+        c9 += t0 >> 22;
+        t0 = -32001852 * c17;
+        c9 += (t0 << 4) & LIMB_MASK;
+        c10 += t0 >> 22;
+        t0 = 21586850 * c17;
+        c10 += (t0 << 4) & LIMB_MASK;
+        c11 += t0 >> 22;
+        t0 = 4397317 * c17;
+        c11 += (t0 << 4) & LIMB_MASK;
+        c12 += t0 >> 22;
+        t0 = -1024 * c17;
+        c14 += (t0 << 4) & LIMB_MASK;
+        c15 += t0 >> 22;
+        t0 = 65536 * c17;
+        c15 += (t0 << 4) & LIMB_MASK;
+        c16 += t0 >> 22;
+        //reduce from position 16
+        t0 = -6497617 * c16;
+        c6 += (t0 << 4) & LIMB_MASK;
+        c7 += t0 >> 22;
+        t0 = 26038081 * c16;
+        c7 += (t0 << 4) & LIMB_MASK;
+        c8 += t0 >> 22;
+        t0 = -32001852 * c16;
+        c8 += (t0 << 4) & LIMB_MASK;
+        c9 += t0 >> 22;
+        t0 = 21586850 * c16;
+        c9 += (t0 << 4) & LIMB_MASK;
+        c10 += t0 >> 22;
+        t0 = 4397317 * c16;
+        c10 += (t0 << 4) & LIMB_MASK;
+        c11 += t0 >> 22;
+        t0 = -1024 * c16;
+        c13 += (t0 << 4) & LIMB_MASK;
+        c14 += t0 >> 22;
+        t0 = 65536 * c16;
+        c14 += (t0 << 4) & LIMB_MASK;
+        c15 += t0 >> 22;
+        //reduce from position 15
+        t0 = -6497617 * c15;
+        c5 += (t0 << 4) & LIMB_MASK;
+        c6 += t0 >> 22;
+        t0 = 26038081 * c15;
+        c6 += (t0 << 4) & LIMB_MASK;
+        c7 += t0 >> 22;
+        t0 = -32001852 * c15;
+        c7 += (t0 << 4) & LIMB_MASK;
+        c8 += t0 >> 22;
+        t0 = 21586850 * c15;
+        c8 += (t0 << 4) & LIMB_MASK;
+        c9 += t0 >> 22;
+        t0 = 4397317 * c15;
+        c9 += (t0 << 4) & LIMB_MASK;
+        c10 += t0 >> 22;
+        t0 = -1024 * c15;
+        c12 += (t0 << 4) & LIMB_MASK;
+        c13 += t0 >> 22;
+        t0 = 65536 * c15;
+        c13 += (t0 << 4) & LIMB_MASK;
+        c14 += t0 >> 22;
+        //reduce from position 14
+        t0 = -6497617 * c14;
+        c4 += (t0 << 4) & LIMB_MASK;
+        c5 += t0 >> 22;
+        t0 = 26038081 * c14;
+        c5 += (t0 << 4) & LIMB_MASK;
+        c6 += t0 >> 22;
+        t0 = -32001852 * c14;
+        c6 += (t0 << 4) & LIMB_MASK;
+        c7 += t0 >> 22;
+        t0 = 21586850 * c14;
+        c7 += (t0 << 4) & LIMB_MASK;
+        c8 += t0 >> 22;
+        t0 = 4397317 * c14;
+        c8 += (t0 << 4) & LIMB_MASK;
+        c9 += t0 >> 22;
+        t0 = -1024 * c14;
+        c11 += (t0 << 4) & LIMB_MASK;
+        c12 += t0 >> 22;
+        t0 = 65536 * c14;
+        c12 += (t0 << 4) & LIMB_MASK;
+        c13 += t0 >> 22;
+        //reduce from position 13
+        t0 = -6497617 * c13;
+        c3 += (t0 << 4) & LIMB_MASK;
+        c4 += t0 >> 22;
+        t0 = 26038081 * c13;
+        c4 += (t0 << 4) & LIMB_MASK;
+        c5 += t0 >> 22;
+        t0 = -32001852 * c13;
+        c5 += (t0 << 4) & LIMB_MASK;
+        c6 += t0 >> 22;
+        t0 = 21586850 * c13;
+        c6 += (t0 << 4) & LIMB_MASK;
+        c7 += t0 >> 22;
+        t0 = 4397317 * c13;
+        c7 += (t0 << 4) & LIMB_MASK;
+        c8 += t0 >> 22;
+        t0 = -1024 * c13;
+        c10 += (t0 << 4) & LIMB_MASK;
+        c11 += t0 >> 22;
+        t0 = 65536 * c13;
+        c11 += (t0 << 4) & LIMB_MASK;
+        c12 += t0 >> 22;
+        //reduce from position 12
+        t0 = -6497617 * c12;
+        c2 += (t0 << 4) & LIMB_MASK;
+        c3 += t0 >> 22;
+        t0 = 26038081 * c12;
+        c3 += (t0 << 4) & LIMB_MASK;
+        c4 += t0 >> 22;
+        t0 = -32001852 * c12;
+        c4 += (t0 << 4) & LIMB_MASK;
+        c5 += t0 >> 22;
+        t0 = 21586850 * c12;
+        c5 += (t0 << 4) & LIMB_MASK;
+        c6 += t0 >> 22;
+        t0 = 4397317 * c12;
+        c6 += (t0 << 4) & LIMB_MASK;
+        c7 += t0 >> 22;
+        t0 = -1024 * c12;
+        c9 += (t0 << 4) & LIMB_MASK;
+        c10 += t0 >> 22;
+        t0 = 65536 * c12;
+        c10 += (t0 << 4) & LIMB_MASK;
+        c11 += t0 >> 22;
+        //reduce from position 11
+        t0 = -6497617 * c11;
+        c1 += (t0 << 4) & LIMB_MASK;
+        c2 += t0 >> 22;
+        t0 = 26038081 * c11;
+        c2 += (t0 << 4) & LIMB_MASK;
+        c3 += t0 >> 22;
+        t0 = -32001852 * c11;
+        c3 += (t0 << 4) & LIMB_MASK;
+        c4 += t0 >> 22;
+        t0 = 21586850 * c11;
+        c4 += (t0 << 4) & LIMB_MASK;
+        c5 += t0 >> 22;
+        t0 = 4397317 * c11;
+        c5 += (t0 << 4) & LIMB_MASK;
+        c6 += t0 >> 22;
+        t0 = -1024 * c11;
+        c8 += (t0 << 4) & LIMB_MASK;
+        c9 += t0 >> 22;
+        t0 = 65536 * c11;
+        c9 += (t0 << 4) & LIMB_MASK;
+        c10 += t0 >> 22;
+        //reduce from position 10
+        t0 = -6497617 * c10;
+        c0 += (t0 << 4) & LIMB_MASK;
+        c1 += t0 >> 22;
+        t0 = 26038081 * c10;
+        c1 += (t0 << 4) & LIMB_MASK;
+        c2 += t0 >> 22;
+        t0 = -32001852 * c10;
+        c2 += (t0 << 4) & LIMB_MASK;
+        c3 += t0 >> 22;
+        t0 = 21586850 * c10;
+        c3 += (t0 << 4) & LIMB_MASK;
+        c4 += t0 >> 22;
+        t0 = 4397317 * c10;
+        c4 += (t0 << 4) & LIMB_MASK;
+        c5 += t0 >> 22;
+        t0 = -1024 * c10;
+        c7 += (t0 << 4) & LIMB_MASK;
+        c8 += t0 >> 22;
+        t0 = 65536 * c10;
+        c8 += (t0 << 4) & LIMB_MASK;
+        c9 += t0 >> 22;
+        c10 = 0;
+
+        carryReduce1(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19);
+    }
+    void carryReduce1(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19) {
+        long t0;
+
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 26;
+        c0 -= (t0 << 26);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 26;
+        c1 -= (t0 << 26);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 26;
+        c2 -= (t0 << 26);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 26;
+        c3 -= (t0 << 26);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 26;
+        c4 -= (t0 << 26);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 26;
+        c5 -= (t0 << 26);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 26;
+        c6 -= (t0 << 26);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 26;
+        c7 -= (t0 << 26);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 26;
+        c8 -= (t0 << 26);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 26;
+        c9 -= (t0 << 26);
+        c10 += t0;
+
+        carryReduce2(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19);
+    }
+    void carryReduce2(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19) {
+        long t0;
+
+        //reduce from position 10
+        t0 = -6497617 * c10;
+        c0 += (t0 << 4) & LIMB_MASK;
+        c1 += t0 >> 22;
+        t0 = 26038081 * c10;
+        c1 += (t0 << 4) & LIMB_MASK;
+        c2 += t0 >> 22;
+        t0 = -32001852 * c10;
+        c2 += (t0 << 4) & LIMB_MASK;
+        c3 += t0 >> 22;
+        t0 = 21586850 * c10;
+        c3 += (t0 << 4) & LIMB_MASK;
+        c4 += t0 >> 22;
+        t0 = 4397317 * c10;
+        c4 += (t0 << 4) & LIMB_MASK;
+        c5 += t0 >> 22;
+        t0 = -1024 * c10;
+        c7 += (t0 << 4) & LIMB_MASK;
+        c8 += t0 >> 22;
+        t0 = 65536 * c10;
+        c8 += (t0 << 4) & LIMB_MASK;
+        c9 += t0 >> 22;
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 26;
+        c0 -= (t0 << 26);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 26;
+        c1 -= (t0 << 26);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 26;
+        c2 -= (t0 << 26);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 26;
+        c3 -= (t0 << 26);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 26;
+        c4 -= (t0 << 26);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 26;
+        c5 -= (t0 << 26);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 26;
+        c6 -= (t0 << 26);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 26;
+        c7 -= (t0 << 26);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 26;
+        c8 -= (t0 << 26);
+        c9 += t0;
+
+        r[0] = c0;
+        r[1] = c1;
+        r[2] = c2;
+        r[3] = c3;
+        r[4] = c4;
+        r[5] = c5;
+        r[6] = c6;
+        r[7] = c7;
+        r[8] = c8;
+        r[9] = c9;
+    }
+    private void carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9) {
+        long c10 = 0;
+        //carry from position 0
+        long t0 = (c0 + CARRY_ADD) >> 26;
+        c0 -= (t0 << 26);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 26;
+        c1 -= (t0 << 26);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 26;
+        c2 -= (t0 << 26);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 26;
+        c3 -= (t0 << 26);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 26;
+        c4 -= (t0 << 26);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 26;
+        c5 -= (t0 << 26);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 26;
+        c6 -= (t0 << 26);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 26;
+        c7 -= (t0 << 26);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 26;
+        c8 -= (t0 << 26);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 26;
+        c9 -= (t0 << 26);
+        c10 += t0;
+
+        carryReduce0(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10);
+    }
+    void carryReduce0(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10) {
+        long t0;
+
+        //reduce from position 10
+        t0 = -6497617 * c10;
+        c0 += (t0 << 4) & LIMB_MASK;
+        c1 += t0 >> 22;
+        t0 = 26038081 * c10;
+        c1 += (t0 << 4) & LIMB_MASK;
+        c2 += t0 >> 22;
+        t0 = -32001852 * c10;
+        c2 += (t0 << 4) & LIMB_MASK;
+        c3 += t0 >> 22;
+        t0 = 21586850 * c10;
+        c3 += (t0 << 4) & LIMB_MASK;
+        c4 += t0 >> 22;
+        t0 = 4397317 * c10;
+        c4 += (t0 << 4) & LIMB_MASK;
+        c5 += t0 >> 22;
+        t0 = -1024 * c10;
+        c7 += (t0 << 4) & LIMB_MASK;
+        c8 += t0 >> 22;
+        t0 = 65536 * c10;
+        c8 += (t0 << 4) & LIMB_MASK;
+        c9 += t0 >> 22;
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 26;
+        c0 -= (t0 << 26);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 26;
+        c1 -= (t0 << 26);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 26;
+        c2 -= (t0 << 26);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 26;
+        c3 -= (t0 << 26);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 26;
+        c4 -= (t0 << 26);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 26;
+        c5 -= (t0 << 26);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 26;
+        c6 -= (t0 << 26);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 26;
+        c7 -= (t0 << 26);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 26;
+        c8 -= (t0 << 26);
+        c9 += t0;
+
+        r[0] = c0;
+        r[1] = c1;
+        r[2] = c2;
+        r[3] = c3;
+        r[4] = c4;
+        r[5] = c5;
+        r[6] = c6;
+        r[7] = c7;
+        r[8] = c8;
+        r[9] = c9;
+    }
+    @Override
+    protected void mult(long[] a, long[] b, long[] r) {
+        long c0 = (a[0] * b[0]);
+        long c1 = (a[0] * b[1]) + (a[1] * b[0]);
+        long c2 = (a[0] * b[2]) + (a[1] * b[1]) + (a[2] * b[0]);
+        long c3 = (a[0] * b[3]) + (a[1] * b[2]) + (a[2] * b[1]) + (a[3] * b[0]);
+        long c4 = (a[0] * b[4]) + (a[1] * b[3]) + (a[2] * b[2]) + (a[3] * b[1]) + (a[4] * b[0]);
+        long c5 = (a[0] * b[5]) + (a[1] * b[4]) + (a[2] * b[3]) + (a[3] * b[2]) + (a[4] * b[1]) + (a[5] * b[0]);
+        long c6 = (a[0] * b[6]) + (a[1] * b[5]) + (a[2] * b[4]) + (a[3] * b[3]) + (a[4] * b[2]) + (a[5] * b[1]) + (a[6] * b[0]);
+        long c7 = (a[0] * b[7]) + (a[1] * b[6]) + (a[2] * b[5]) + (a[3] * b[4]) + (a[4] * b[3]) + (a[5] * b[2]) + (a[6] * b[1]) + (a[7] * b[0]);
+        long c8 = (a[0] * b[8]) + (a[1] * b[7]) + (a[2] * b[6]) + (a[3] * b[5]) + (a[4] * b[4]) + (a[5] * b[3]) + (a[6] * b[2]) + (a[7] * b[1]) + (a[8] * b[0]);
+        long c9 = (a[0] * b[9]) + (a[1] * b[8]) + (a[2] * b[7]) + (a[3] * b[6]) + (a[4] * b[5]) + (a[5] * b[4]) + (a[6] * b[3]) + (a[7] * b[2]) + (a[8] * b[1]) + (a[9] * b[0]);
+        long c10 = (a[1] * b[9]) + (a[2] * b[8]) + (a[3] * b[7]) + (a[4] * b[6]) + (a[5] * b[5]) + (a[6] * b[4]) + (a[7] * b[3]) + (a[8] * b[2]) + (a[9] * b[1]);
+        long c11 = (a[2] * b[9]) + (a[3] * b[8]) + (a[4] * b[7]) + (a[5] * b[6]) + (a[6] * b[5]) + (a[7] * b[4]) + (a[8] * b[3]) + (a[9] * b[2]);
+        long c12 = (a[3] * b[9]) + (a[4] * b[8]) + (a[5] * b[7]) + (a[6] * b[6]) + (a[7] * b[5]) + (a[8] * b[4]) + (a[9] * b[3]);
+        long c13 = (a[4] * b[9]) + (a[5] * b[8]) + (a[6] * b[7]) + (a[7] * b[6]) + (a[8] * b[5]) + (a[9] * b[4]);
+        long c14 = (a[5] * b[9]) + (a[6] * b[8]) + (a[7] * b[7]) + (a[8] * b[6]) + (a[9] * b[5]);
+        long c15 = (a[6] * b[9]) + (a[7] * b[8]) + (a[8] * b[7]) + (a[9] * b[6]);
+        long c16 = (a[7] * b[9]) + (a[8] * b[8]) + (a[9] * b[7]);
+        long c17 = (a[8] * b[9]) + (a[9] * b[8]);
+        long c18 = (a[9] * b[9]);
+
+        carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18);
+    }
+    @Override
+    protected void reduce(long[] a) {
+        carryReduce(a, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
+    }
+    @Override
+    protected void square(long[] a, long[] r) {
+        long c0 = (a[0] * a[0]);
+        long c1 = 2 * ((a[0] * a[1]));
+        long c2 = 2 * ((a[0] * a[2])) + (a[1] * a[1]);
+        long c3 = 2 * ((a[0] * a[3]) + (a[1] * a[2]));
+        long c4 = 2 * ((a[0] * a[4]) + (a[1] * a[3])) + (a[2] * a[2]);
+        long c5 = 2 * ((a[0] * a[5]) + (a[1] * a[4]) + (a[2] * a[3]));
+        long c6 = 2 * ((a[0] * a[6]) + (a[1] * a[5]) + (a[2] * a[4])) + (a[3] * a[3]);
+        long c7 = 2 * ((a[0] * a[7]) + (a[1] * a[6]) + (a[2] * a[5]) + (a[3] * a[4]));
+        long c8 = 2 * ((a[0] * a[8]) + (a[1] * a[7]) + (a[2] * a[6]) + (a[3] * a[5])) + (a[4] * a[4]);
+        long c9 = 2 * ((a[0] * a[9]) + (a[1] * a[8]) + (a[2] * a[7]) + (a[3] * a[6]) + (a[4] * a[5]));
+        long c10 = 2 * ((a[1] * a[9]) + (a[2] * a[8]) + (a[3] * a[7]) + (a[4] * a[6])) + (a[5] * a[5]);
+        long c11 = 2 * ((a[2] * a[9]) + (a[3] * a[8]) + (a[4] * a[7]) + (a[5] * a[6]));
+        long c12 = 2 * ((a[3] * a[9]) + (a[4] * a[8]) + (a[5] * a[7])) + (a[6] * a[6]);
+        long c13 = 2 * ((a[4] * a[9]) + (a[5] * a[8]) + (a[6] * a[7]));
+        long c14 = 2 * ((a[5] * a[9]) + (a[6] * a[8])) + (a[7] * a[7]);
+        long c15 = 2 * ((a[6] * a[9]) + (a[7] * a[8]));
+        long c16 = 2 * ((a[7] * a[9])) + (a[8] * a[8]);
+        long c17 = 2 * ((a[8] * a[9]));
+        long c18 = (a[9] * a[9]);
+
+        carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/math/intpoly/P384OrderField.java	Sat Jul 13 16:49:00 2019 +0100
@@ -0,0 +1,881 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is generated by FieldGen.jsh. Do not modify it directly.
+ */
+
+package sun.security.util.math.intpoly;
+
+import java.math.BigInteger;
+public class P384OrderField extends IntegerPolynomial {
+    private static final int BITS_PER_LIMB = 28;
+    private static final int NUM_LIMBS = 14;
+    private static final int MAX_ADDS = 1;
+    public static final BigInteger MODULUS = evaluateModulus();
+    private static final long CARRY_ADD = 1 << 27;
+    private static final int LIMB_MASK = -1 >>> (64 - BITS_PER_LIMB);
+    public P384OrderField() {
+
+        super(BITS_PER_LIMB, NUM_LIMBS, MAX_ADDS, MODULUS);
+
+    }
+    private static BigInteger evaluateModulus() {
+        BigInteger result = BigInteger.valueOf(2).pow(384);
+        result = result.subtract(BigInteger.valueOf(54187661));
+        result = result.subtract(BigInteger.valueOf(2).pow(28).multiply(BigInteger.valueOf(20867411)));
+        result = result.add(BigInteger.valueOf(2).pow(56).multiply(BigInteger.valueOf(10975981)));
+        result = result.add(BigInteger.valueOf(2).pow(84).multiply(BigInteger.valueOf(14361739)));
+        result = result.subtract(BigInteger.valueOf(2).pow(112).multiply(BigInteger.valueOf(35694566)));
+        result = result.subtract(BigInteger.valueOf(2).pow(140).multiply(BigInteger.valueOf(132168845)));
+        result = result.subtract(BigInteger.valueOf(2).pow(168).multiply(BigInteger.valueOf(3710130)));
+        return result;
+    }
+    @Override
+    protected void finalCarryReduceLast(long[] limbs) {
+        long c = limbs[13] >> 20;
+        limbs[13] -= c << 20;
+        long t0 = 54187661 * c;
+        limbs[0] += t0;
+        t0 = 20867411 * c;
+        limbs[1] += t0;
+        t0 = -10975981 * c;
+        limbs[2] += t0;
+        t0 = -14361739 * c;
+        limbs[3] += t0;
+        t0 = 35694566 * c;
+        limbs[4] += t0;
+        t0 = 132168845 * c;
+        limbs[5] += t0;
+        t0 = 3710130 * c;
+        limbs[6] += t0;
+    }
+    private void carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26) {
+        long c27 = 0;
+        //carry from position 0
+        long t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 28;
+        c13 -= (t0 << 28);
+        c14 += t0;
+        //carry from position 14
+        t0 = (c14 + CARRY_ADD) >> 28;
+        c14 -= (t0 << 28);
+        c15 += t0;
+        //carry from position 15
+        t0 = (c15 + CARRY_ADD) >> 28;
+        c15 -= (t0 << 28);
+        c16 += t0;
+        //carry from position 16
+        t0 = (c16 + CARRY_ADD) >> 28;
+        c16 -= (t0 << 28);
+        c17 += t0;
+        //carry from position 17
+        t0 = (c17 + CARRY_ADD) >> 28;
+        c17 -= (t0 << 28);
+        c18 += t0;
+        //carry from position 18
+        t0 = (c18 + CARRY_ADD) >> 28;
+        c18 -= (t0 << 28);
+        c19 += t0;
+        //carry from position 19
+        t0 = (c19 + CARRY_ADD) >> 28;
+        c19 -= (t0 << 28);
+        c20 += t0;
+        //carry from position 20
+        t0 = (c20 + CARRY_ADD) >> 28;
+        c20 -= (t0 << 28);
+        c21 += t0;
+        //carry from position 21
+        t0 = (c21 + CARRY_ADD) >> 28;
+        c21 -= (t0 << 28);
+        c22 += t0;
+        //carry from position 22
+        t0 = (c22 + CARRY_ADD) >> 28;
+        c22 -= (t0 << 28);
+        c23 += t0;
+        //carry from position 23
+        t0 = (c23 + CARRY_ADD) >> 28;
+        c23 -= (t0 << 28);
+        c24 += t0;
+        //carry from position 24
+        t0 = (c24 + CARRY_ADD) >> 28;
+        c24 -= (t0 << 28);
+        c25 += t0;
+        //carry from position 25
+        t0 = (c25 + CARRY_ADD) >> 28;
+        c25 -= (t0 << 28);
+        c26 += t0;
+        //carry from position 26
+        t0 = (c26 + CARRY_ADD) >> 28;
+        c26 -= (t0 << 28);
+        c27 += t0;
+
+        carryReduce0(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27);
+    }
+    void carryReduce0(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26, long c27) {
+        long t0;
+
+        //reduce from position 27
+        t0 = 54187661 * c27;
+        c13 += (t0 << 8) & LIMB_MASK;
+        c14 += t0 >> 20;
+        t0 = 20867411 * c27;
+        c14 += (t0 << 8) & LIMB_MASK;
+        c15 += t0 >> 20;
+        t0 = -10975981 * c27;
+        c15 += (t0 << 8) & LIMB_MASK;
+        c16 += t0 >> 20;
+        t0 = -14361739 * c27;
+        c16 += (t0 << 8) & LIMB_MASK;
+        c17 += t0 >> 20;
+        t0 = 35694566 * c27;
+        c17 += (t0 << 8) & LIMB_MASK;
+        c18 += t0 >> 20;
+        t0 = 132168845 * c27;
+        c18 += (t0 << 8) & LIMB_MASK;
+        c19 += t0 >> 20;
+        t0 = 3710130 * c27;
+        c19 += (t0 << 8) & LIMB_MASK;
+        c20 += t0 >> 20;
+        //reduce from position 26
+        t0 = 54187661 * c26;
+        c12 += (t0 << 8) & LIMB_MASK;
+        c13 += t0 >> 20;
+        t0 = 20867411 * c26;
+        c13 += (t0 << 8) & LIMB_MASK;
+        c14 += t0 >> 20;
+        t0 = -10975981 * c26;
+        c14 += (t0 << 8) & LIMB_MASK;
+        c15 += t0 >> 20;
+        t0 = -14361739 * c26;
+        c15 += (t0 << 8) & LIMB_MASK;
+        c16 += t0 >> 20;
+        t0 = 35694566 * c26;
+        c16 += (t0 << 8) & LIMB_MASK;
+        c17 += t0 >> 20;
+        t0 = 132168845 * c26;
+        c17 += (t0 << 8) & LIMB_MASK;
+        c18 += t0 >> 20;
+        t0 = 3710130 * c26;
+        c18 += (t0 << 8) & LIMB_MASK;
+        c19 += t0 >> 20;
+        //reduce from position 25
+        t0 = 54187661 * c25;
+        c11 += (t0 << 8) & LIMB_MASK;
+        c12 += t0 >> 20;
+        t0 = 20867411 * c25;
+        c12 += (t0 << 8) & LIMB_MASK;
+        c13 += t0 >> 20;
+        t0 = -10975981 * c25;
+        c13 += (t0 << 8) & LIMB_MASK;
+        c14 += t0 >> 20;
+        t0 = -14361739 * c25;
+        c14 += (t0 << 8) & LIMB_MASK;
+        c15 += t0 >> 20;
+        t0 = 35694566 * c25;
+        c15 += (t0 << 8) & LIMB_MASK;
+        c16 += t0 >> 20;
+        t0 = 132168845 * c25;
+        c16 += (t0 << 8) & LIMB_MASK;
+        c17 += t0 >> 20;
+        t0 = 3710130 * c25;
+        c17 += (t0 << 8) & LIMB_MASK;
+        c18 += t0 >> 20;
+        //reduce from position 24
+        t0 = 54187661 * c24;
+        c10 += (t0 << 8) & LIMB_MASK;
+        c11 += t0 >> 20;
+        t0 = 20867411 * c24;
+        c11 += (t0 << 8) & LIMB_MASK;
+        c12 += t0 >> 20;
+        t0 = -10975981 * c24;
+        c12 += (t0 << 8) & LIMB_MASK;
+        c13 += t0 >> 20;
+        t0 = -14361739 * c24;
+        c13 += (t0 << 8) & LIMB_MASK;
+        c14 += t0 >> 20;
+        t0 = 35694566 * c24;
+        c14 += (t0 << 8) & LIMB_MASK;
+        c15 += t0 >> 20;
+        t0 = 132168845 * c24;
+        c15 += (t0 << 8) & LIMB_MASK;
+        c16 += t0 >> 20;
+        t0 = 3710130 * c24;
+        c16 += (t0 << 8) & LIMB_MASK;
+        c17 += t0 >> 20;
+        //reduce from position 23
+        t0 = 54187661 * c23;
+        c9 += (t0 << 8) & LIMB_MASK;
+        c10 += t0 >> 20;
+        t0 = 20867411 * c23;
+        c10 += (t0 << 8) & LIMB_MASK;
+        c11 += t0 >> 20;
+        t0 = -10975981 * c23;
+        c11 += (t0 << 8) & LIMB_MASK;
+        c12 += t0 >> 20;
+        t0 = -14361739 * c23;
+        c12 += (t0 << 8) & LIMB_MASK;
+        c13 += t0 >> 20;
+        t0 = 35694566 * c23;
+        c13 += (t0 << 8) & LIMB_MASK;
+        c14 += t0 >> 20;
+        t0 = 132168845 * c23;
+        c14 += (t0 << 8) & LIMB_MASK;
+        c15 += t0 >> 20;
+        t0 = 3710130 * c23;
+        c15 += (t0 << 8) & LIMB_MASK;
+        c16 += t0 >> 20;
+        //reduce from position 22
+        t0 = 54187661 * c22;
+        c8 += (t0 << 8) & LIMB_MASK;
+        c9 += t0 >> 20;
+        t0 = 20867411 * c22;
+        c9 += (t0 << 8) & LIMB_MASK;
+        c10 += t0 >> 20;
+        t0 = -10975981 * c22;
+        c10 += (t0 << 8) & LIMB_MASK;
+        c11 += t0 >> 20;
+        t0 = -14361739 * c22;
+        c11 += (t0 << 8) & LIMB_MASK;
+        c12 += t0 >> 20;
+        t0 = 35694566 * c22;
+        c12 += (t0 << 8) & LIMB_MASK;
+        c13 += t0 >> 20;
+        t0 = 132168845 * c22;
+        c13 += (t0 << 8) & LIMB_MASK;
+        c14 += t0 >> 20;
+        t0 = 3710130 * c22;
+        c14 += (t0 << 8) & LIMB_MASK;
+        c15 += t0 >> 20;
+        //reduce from position 21
+        t0 = 54187661 * c21;
+        c7 += (t0 << 8) & LIMB_MASK;
+        c8 += t0 >> 20;
+        t0 = 20867411 * c21;
+        c8 += (t0 << 8) & LIMB_MASK;
+        c9 += t0 >> 20;
+        t0 = -10975981 * c21;
+        c9 += (t0 << 8) & LIMB_MASK;
+        c10 += t0 >> 20;
+        t0 = -14361739 * c21;
+        c10 += (t0 << 8) & LIMB_MASK;
+        c11 += t0 >> 20;
+        t0 = 35694566 * c21;
+        c11 += (t0 << 8) & LIMB_MASK;
+        c12 += t0 >> 20;
+        t0 = 132168845 * c21;
+        c12 += (t0 << 8) & LIMB_MASK;
+        c13 += t0 >> 20;
+        t0 = 3710130 * c21;
+        c13 += (t0 << 8) & LIMB_MASK;
+        c14 += t0 >> 20;
+        //reduce from position 20
+        t0 = 54187661 * c20;
+        c6 += (t0 << 8) & LIMB_MASK;
+        c7 += t0 >> 20;
+        t0 = 20867411 * c20;
+        c7 += (t0 << 8) & LIMB_MASK;
+        c8 += t0 >> 20;
+        t0 = -10975981 * c20;
+        c8 += (t0 << 8) & LIMB_MASK;
+        c9 += t0 >> 20;
+        t0 = -14361739 * c20;
+        c9 += (t0 << 8) & LIMB_MASK;
+        c10 += t0 >> 20;
+        t0 = 35694566 * c20;
+        c10 += (t0 << 8) & LIMB_MASK;
+        c11 += t0 >> 20;
+        t0 = 132168845 * c20;
+        c11 += (t0 << 8) & LIMB_MASK;
+        c12 += t0 >> 20;
+        t0 = 3710130 * c20;
+        c12 += (t0 << 8) & LIMB_MASK;
+        c13 += t0 >> 20;
+        //reduce from position 19
+        t0 = 54187661 * c19;
+        c5 += (t0 << 8) & LIMB_MASK;
+        c6 += t0 >> 20;
+        t0 = 20867411 * c19;
+        c6 += (t0 << 8) & LIMB_MASK;
+        c7 += t0 >> 20;
+        t0 = -10975981 * c19;
+        c7 += (t0 << 8) & LIMB_MASK;
+        c8 += t0 >> 20;
+        t0 = -14361739 * c19;
+        c8 += (t0 << 8) & LIMB_MASK;
+        c9 += t0 >> 20;
+        t0 = 35694566 * c19;
+        c9 += (t0 << 8) & LIMB_MASK;
+        c10 += t0 >> 20;
+        t0 = 132168845 * c19;
+        c10 += (t0 << 8) & LIMB_MASK;
+        c11 += t0 >> 20;
+        t0 = 3710130 * c19;
+        c11 += (t0 << 8) & LIMB_MASK;
+        c12 += t0 >> 20;
+        //reduce from position 18
+        t0 = 54187661 * c18;
+        c4 += (t0 << 8) & LIMB_MASK;
+        c5 += t0 >> 20;
+        t0 = 20867411 * c18;
+        c5 += (t0 << 8) & LIMB_MASK;
+        c6 += t0 >> 20;
+        t0 = -10975981 * c18;
+        c6 += (t0 << 8) & LIMB_MASK;
+        c7 += t0 >> 20;
+        t0 = -14361739 * c18;
+        c7 += (t0 << 8) & LIMB_MASK;
+        c8 += t0 >> 20;
+        t0 = 35694566 * c18;
+        c8 += (t0 << 8) & LIMB_MASK;
+        c9 += t0 >> 20;
+        t0 = 132168845 * c18;
+        c9 += (t0 << 8) & LIMB_MASK;
+        c10 += t0 >> 20;
+        t0 = 3710130 * c18;
+        c10 += (t0 << 8) & LIMB_MASK;
+        c11 += t0 >> 20;
+        //reduce from position 17
+        t0 = 54187661 * c17;
+        c3 += (t0 << 8) & LIMB_MASK;
+        c4 += t0 >> 20;
+        t0 = 20867411 * c17;
+        c4 += (t0 << 8) & LIMB_MASK;
+        c5 += t0 >> 20;
+        t0 = -10975981 * c17;
+        c5 += (t0 << 8) & LIMB_MASK;
+        c6 += t0 >> 20;
+        t0 = -14361739 * c17;
+        c6 += (t0 << 8) & LIMB_MASK;
+        c7 += t0 >> 20;
+        t0 = 35694566 * c17;
+        c7 += (t0 << 8) & LIMB_MASK;
+        c8 += t0 >> 20;
+        t0 = 132168845 * c17;
+        c8 += (t0 << 8) & LIMB_MASK;
+        c9 += t0 >> 20;
+        t0 = 3710130 * c17;
+        c9 += (t0 << 8) & LIMB_MASK;
+        c10 += t0 >> 20;
+        //reduce from position 16
+        t0 = 54187661 * c16;
+        c2 += (t0 << 8) & LIMB_MASK;
+        c3 += t0 >> 20;
+        t0 = 20867411 * c16;
+        c3 += (t0 << 8) & LIMB_MASK;
+        c4 += t0 >> 20;
+        t0 = -10975981 * c16;
+        c4 += (t0 << 8) & LIMB_MASK;
+        c5 += t0 >> 20;
+        t0 = -14361739 * c16;
+        c5 += (t0 << 8) & LIMB_MASK;
+        c6 += t0 >> 20;
+        t0 = 35694566 * c16;
+        c6 += (t0 << 8) & LIMB_MASK;
+        c7 += t0 >> 20;
+        t0 = 132168845 * c16;
+        c7 += (t0 << 8) & LIMB_MASK;
+        c8 += t0 >> 20;
+        t0 = 3710130 * c16;
+        c8 += (t0 << 8) & LIMB_MASK;
+        c9 += t0 >> 20;
+        //reduce from position 15
+        t0 = 54187661 * c15;
+        c1 += (t0 << 8) & LIMB_MASK;
+        c2 += t0 >> 20;
+        t0 = 20867411 * c15;
+        c2 += (t0 << 8) & LIMB_MASK;
+        c3 += t0 >> 20;
+        t0 = -10975981 * c15;
+        c3 += (t0 << 8) & LIMB_MASK;
+        c4 += t0 >> 20;
+        t0 = -14361739 * c15;
+        c4 += (t0 << 8) & LIMB_MASK;
+        c5 += t0 >> 20;
+        t0 = 35694566 * c15;
+        c5 += (t0 << 8) & LIMB_MASK;
+        c6 += t0 >> 20;
+        t0 = 132168845 * c15;
+        c6 += (t0 << 8) & LIMB_MASK;
+        c7 += t0 >> 20;
+        t0 = 3710130 * c15;
+        c7 += (t0 << 8) & LIMB_MASK;
+        c8 += t0 >> 20;
+        //reduce from position 14
+        t0 = 54187661 * c14;
+        c0 += (t0 << 8) & LIMB_MASK;
+        c1 += t0 >> 20;
+        t0 = 20867411 * c14;
+        c1 += (t0 << 8) & LIMB_MASK;
+        c2 += t0 >> 20;
+        t0 = -10975981 * c14;
+        c2 += (t0 << 8) & LIMB_MASK;
+        c3 += t0 >> 20;
+        t0 = -14361739 * c14;
+        c3 += (t0 << 8) & LIMB_MASK;
+        c4 += t0 >> 20;
+        t0 = 35694566 * c14;
+        c4 += (t0 << 8) & LIMB_MASK;
+        c5 += t0 >> 20;
+        t0 = 132168845 * c14;
+        c5 += (t0 << 8) & LIMB_MASK;
+        c6 += t0 >> 20;
+        t0 = 3710130 * c14;
+        c6 += (t0 << 8) & LIMB_MASK;
+        c7 += t0 >> 20;
+        c14 = 0;
+
+        carryReduce1(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27);
+    }
+    void carryReduce1(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26, long c27) {
+        long t0;
+
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 28;
+        c13 -= (t0 << 28);
+        c14 += t0;
+
+        carryReduce2(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27);
+    }
+    void carryReduce2(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26, long c27) {
+        long t0;
+
+        //reduce from position 14
+        t0 = 54187661 * c14;
+        c0 += (t0 << 8) & LIMB_MASK;
+        c1 += t0 >> 20;
+        t0 = 20867411 * c14;
+        c1 += (t0 << 8) & LIMB_MASK;
+        c2 += t0 >> 20;
+        t0 = -10975981 * c14;
+        c2 += (t0 << 8) & LIMB_MASK;
+        c3 += t0 >> 20;
+        t0 = -14361739 * c14;
+        c3 += (t0 << 8) & LIMB_MASK;
+        c4 += t0 >> 20;
+        t0 = 35694566 * c14;
+        c4 += (t0 << 8) & LIMB_MASK;
+        c5 += t0 >> 20;
+        t0 = 132168845 * c14;
+        c5 += (t0 << 8) & LIMB_MASK;
+        c6 += t0 >> 20;
+        t0 = 3710130 * c14;
+        c6 += (t0 << 8) & LIMB_MASK;
+        c7 += t0 >> 20;
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+
+        r[0] = c0;
+        r[1] = c1;
+        r[2] = c2;
+        r[3] = c3;
+        r[4] = c4;
+        r[5] = c5;
+        r[6] = c6;
+        r[7] = c7;
+        r[8] = c8;
+        r[9] = c9;
+        r[10] = c10;
+        r[11] = c11;
+        r[12] = c12;
+        r[13] = c13;
+    }
+    private void carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13) {
+        long c14 = 0;
+        //carry from position 0
+        long t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 28;
+        c13 -= (t0 << 28);
+        c14 += t0;
+
+        carryReduce0(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14);
+    }
+    void carryReduce0(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14) {
+        long t0;
+
+        //reduce from position 14
+        t0 = 54187661 * c14;
+        c0 += (t0 << 8) & LIMB_MASK;
+        c1 += t0 >> 20;
+        t0 = 20867411 * c14;
+        c1 += (t0 << 8) & LIMB_MASK;
+        c2 += t0 >> 20;
+        t0 = -10975981 * c14;
+        c2 += (t0 << 8) & LIMB_MASK;
+        c3 += t0 >> 20;
+        t0 = -14361739 * c14;
+        c3 += (t0 << 8) & LIMB_MASK;
+        c4 += t0 >> 20;
+        t0 = 35694566 * c14;
+        c4 += (t0 << 8) & LIMB_MASK;
+        c5 += t0 >> 20;
+        t0 = 132168845 * c14;
+        c5 += (t0 << 8) & LIMB_MASK;
+        c6 += t0 >> 20;
+        t0 = 3710130 * c14;
+        c6 += (t0 << 8) & LIMB_MASK;
+        c7 += t0 >> 20;
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+
+        r[0] = c0;
+        r[1] = c1;
+        r[2] = c2;
+        r[3] = c3;
+        r[4] = c4;
+        r[5] = c5;
+        r[6] = c6;
+        r[7] = c7;
+        r[8] = c8;
+        r[9] = c9;
+        r[10] = c10;
+        r[11] = c11;
+        r[12] = c12;
+        r[13] = c13;
+    }
+    @Override
+    protected void mult(long[] a, long[] b, long[] r) {
+        long c0 = (a[0] * b[0]);
+        long c1 = (a[0] * b[1]) + (a[1] * b[0]);
+        long c2 = (a[0] * b[2]) + (a[1] * b[1]) + (a[2] * b[0]);
+        long c3 = (a[0] * b[3]) + (a[1] * b[2]) + (a[2] * b[1]) + (a[3] * b[0]);
+        long c4 = (a[0] * b[4]) + (a[1] * b[3]) + (a[2] * b[2]) + (a[3] * b[1]) + (a[4] * b[0]);
+        long c5 = (a[0] * b[5]) + (a[1] * b[4]) + (a[2] * b[3]) + (a[3] * b[2]) + (a[4] * b[1]) + (a[5] * b[0]);
+        long c6 = (a[0] * b[6]) + (a[1] * b[5]) + (a[2] * b[4]) + (a[3] * b[3]) + (a[4] * b[2]) + (a[5] * b[1]) + (a[6] * b[0]);
+        long c7 = (a[0] * b[7]) + (a[1] * b[6]) + (a[2] * b[5]) + (a[3] * b[4]) + (a[4] * b[3]) + (a[5] * b[2]) + (a[6] * b[1]) + (a[7] * b[0]);
+        long c8 = (a[0] * b[8]) + (a[1] * b[7]) + (a[2] * b[6]) + (a[3] * b[5]) + (a[4] * b[4]) + (a[5] * b[3]) + (a[6] * b[2]) + (a[7] * b[1]) + (a[8] * b[0]);
+        long c9 = (a[0] * b[9]) + (a[1] * b[8]) + (a[2] * b[7]) + (a[3] * b[6]) + (a[4] * b[5]) + (a[5] * b[4]) + (a[6] * b[3]) + (a[7] * b[2]) + (a[8] * b[1]) + (a[9] * b[0]);
+        long c10 = (a[0] * b[10]) + (a[1] * b[9]) + (a[2] * b[8]) + (a[3] * b[7]) + (a[4] * b[6]) + (a[5] * b[5]) + (a[6] * b[4]) + (a[7] * b[3]) + (a[8] * b[2]) + (a[9] * b[1]) + (a[10] * b[0]);
+        long c11 = (a[0] * b[11]) + (a[1] * b[10]) + (a[2] * b[9]) + (a[3] * b[8]) + (a[4] * b[7]) + (a[5] * b[6]) + (a[6] * b[5]) + (a[7] * b[4]) + (a[8] * b[3]) + (a[9] * b[2]) + (a[10] * b[1]) + (a[11] * b[0]);
+        long c12 = (a[0] * b[12]) + (a[1] * b[11]) + (a[2] * b[10]) + (a[3] * b[9]) + (a[4] * b[8]) + (a[5] * b[7]) + (a[6] * b[6]) + (a[7] * b[5]) + (a[8] * b[4]) + (a[9] * b[3]) + (a[10] * b[2]) + (a[11] * b[1]) + (a[12] * b[0]);
+        long c13 = (a[0] * b[13]) + (a[1] * b[12]) + (a[2] * b[11]) + (a[3] * b[10]) + (a[4] * b[9]) + (a[5] * b[8]) + (a[6] * b[7]) + (a[7] * b[6]) + (a[8] * b[5]) + (a[9] * b[4]) + (a[10] * b[3]) + (a[11] * b[2]) + (a[12] * b[1]) + (a[13] * b[0]);
+        long c14 = (a[1] * b[13]) + (a[2] * b[12]) + (a[3] * b[11]) + (a[4] * b[10]) + (a[5] * b[9]) + (a[6] * b[8]) + (a[7] * b[7]) + (a[8] * b[6]) + (a[9] * b[5]) + (a[10] * b[4]) + (a[11] * b[3]) + (a[12] * b[2]) + (a[13] * b[1]);
+        long c15 = (a[2] * b[13]) + (a[3] * b[12]) + (a[4] * b[11]) + (a[5] * b[10]) + (a[6] * b[9]) + (a[7] * b[8]) + (a[8] * b[7]) + (a[9] * b[6]) + (a[10] * b[5]) + (a[11] * b[4]) + (a[12] * b[3]) + (a[13] * b[2]);
+        long c16 = (a[3] * b[13]) + (a[4] * b[12]) + (a[5] * b[11]) + (a[6] * b[10]) + (a[7] * b[9]) + (a[8] * b[8]) + (a[9] * b[7]) + (a[10] * b[6]) + (a[11] * b[5]) + (a[12] * b[4]) + (a[13] * b[3]);
+        long c17 = (a[4] * b[13]) + (a[5] * b[12]) + (a[6] * b[11]) + (a[7] * b[10]) + (a[8] * b[9]) + (a[9] * b[8]) + (a[10] * b[7]) + (a[11] * b[6]) + (a[12] * b[5]) + (a[13] * b[4]);
+        long c18 = (a[5] * b[13]) + (a[6] * b[12]) + (a[7] * b[11]) + (a[8] * b[10]) + (a[9] * b[9]) + (a[10] * b[8]) + (a[11] * b[7]) + (a[12] * b[6]) + (a[13] * b[5]);
+        long c19 = (a[6] * b[13]) + (a[7] * b[12]) + (a[8] * b[11]) + (a[9] * b[10]) + (a[10] * b[9]) + (a[11] * b[8]) + (a[12] * b[7]) + (a[13] * b[6]);
+        long c20 = (a[7] * b[13]) + (a[8] * b[12]) + (a[9] * b[11]) + (a[10] * b[10]) + (a[11] * b[9]) + (a[12] * b[8]) + (a[13] * b[7]);
+        long c21 = (a[8] * b[13]) + (a[9] * b[12]) + (a[10] * b[11]) + (a[11] * b[10]) + (a[12] * b[9]) + (a[13] * b[8]);
+        long c22 = (a[9] * b[13]) + (a[10] * b[12]) + (a[11] * b[11]) + (a[12] * b[10]) + (a[13] * b[9]);
+        long c23 = (a[10] * b[13]) + (a[11] * b[12]) + (a[12] * b[11]) + (a[13] * b[10]);
+        long c24 = (a[11] * b[13]) + (a[12] * b[12]) + (a[13] * b[11]);
+        long c25 = (a[12] * b[13]) + (a[13] * b[12]);
+        long c26 = (a[13] * b[13]);
+
+        carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26);
+    }
+    @Override
+    protected void reduce(long[] a) {
+        carryReduce(a, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13]);
+    }
+    @Override
+    protected void square(long[] a, long[] r) {
+        long c0 = (a[0] * a[0]);
+        long c1 = 2 * ((a[0] * a[1]));
+        long c2 = 2 * ((a[0] * a[2])) + (a[1] * a[1]);
+        long c3 = 2 * ((a[0] * a[3]) + (a[1] * a[2]));
+        long c4 = 2 * ((a[0] * a[4]) + (a[1] * a[3])) + (a[2] * a[2]);
+        long c5 = 2 * ((a[0] * a[5]) + (a[1] * a[4]) + (a[2] * a[3]));
+        long c6 = 2 * ((a[0] * a[6]) + (a[1] * a[5]) + (a[2] * a[4])) + (a[3] * a[3]);
+        long c7 = 2 * ((a[0] * a[7]) + (a[1] * a[6]) + (a[2] * a[5]) + (a[3] * a[4]));
+        long c8 = 2 * ((a[0] * a[8]) + (a[1] * a[7]) + (a[2] * a[6]) + (a[3] * a[5])) + (a[4] * a[4]);
+        long c9 = 2 * ((a[0] * a[9]) + (a[1] * a[8]) + (a[2] * a[7]) + (a[3] * a[6]) + (a[4] * a[5]));
+        long c10 = 2 * ((a[0] * a[10]) + (a[1] * a[9]) + (a[2] * a[8]) + (a[3] * a[7]) + (a[4] * a[6])) + (a[5] * a[5]);
+        long c11 = 2 * ((a[0] * a[11]) + (a[1] * a[10]) + (a[2] * a[9]) + (a[3] * a[8]) + (a[4] * a[7]) + (a[5] * a[6]));
+        long c12 = 2 * ((a[0] * a[12]) + (a[1] * a[11]) + (a[2] * a[10]) + (a[3] * a[9]) + (a[4] * a[8]) + (a[5] * a[7])) + (a[6] * a[6]);
+        long c13 = 2 * ((a[0] * a[13]) + (a[1] * a[12]) + (a[2] * a[11]) + (a[3] * a[10]) + (a[4] * a[9]) + (a[5] * a[8]) + (a[6] * a[7]));
+        long c14 = 2 * ((a[1] * a[13]) + (a[2] * a[12]) + (a[3] * a[11]) + (a[4] * a[10]) + (a[5] * a[9]) + (a[6] * a[8])) + (a[7] * a[7]);
+        long c15 = 2 * ((a[2] * a[13]) + (a[3] * a[12]) + (a[4] * a[11]) + (a[5] * a[10]) + (a[6] * a[9]) + (a[7] * a[8]));
+        long c16 = 2 * ((a[3] * a[13]) + (a[4] * a[12]) + (a[5] * a[11]) + (a[6] * a[10]) + (a[7] * a[9])) + (a[8] * a[8]);
+        long c17 = 2 * ((a[4] * a[13]) + (a[5] * a[12]) + (a[6] * a[11]) + (a[7] * a[10]) + (a[8] * a[9]));
+        long c18 = 2 * ((a[5] * a[13]) + (a[6] * a[12]) + (a[7] * a[11]) + (a[8] * a[10])) + (a[9] * a[9]);
+        long c19 = 2 * ((a[6] * a[13]) + (a[7] * a[12]) + (a[8] * a[11]) + (a[9] * a[10]));
+        long c20 = 2 * ((a[7] * a[13]) + (a[8] * a[12]) + (a[9] * a[11])) + (a[10] * a[10]);
+        long c21 = 2 * ((a[8] * a[13]) + (a[9] * a[12]) + (a[10] * a[11]));
+        long c22 = 2 * ((a[9] * a[13]) + (a[10] * a[12])) + (a[11] * a[11]);
+        long c23 = 2 * ((a[10] * a[13]) + (a[11] * a[12]));
+        long c24 = 2 * ((a[11] * a[13])) + (a[12] * a[12]);
+        long c25 = 2 * ((a[12] * a[13]));
+        long c26 = (a[13] * a[13]);
+
+        carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/math/intpoly/P521OrderField.java	Sat Jul 13 16:49:00 2019 +0100
@@ -0,0 +1,1377 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is generated by FieldGen.jsh. Do not modify it directly.
+ */
+
+package sun.security.util.math.intpoly;
+
+import java.math.BigInteger;
+public class P521OrderField extends IntegerPolynomial {
+    private static final int BITS_PER_LIMB = 28;
+    private static final int NUM_LIMBS = 19;
+    private static final int MAX_ADDS = 1;
+    public static final BigInteger MODULUS = evaluateModulus();
+    private static final long CARRY_ADD = 1 << 27;
+    private static final int LIMB_MASK = -1 >>> (64 - BITS_PER_LIMB);
+    public P521OrderField() {
+
+        super(BITS_PER_LIMB, NUM_LIMBS, MAX_ADDS, MODULUS);
+
+    }
+    private static BigInteger evaluateModulus() {
+        BigInteger result = BigInteger.valueOf(2).pow(521);
+        result = result.add(BigInteger.valueOf(20472841));
+        result = result.add(BigInteger.valueOf(2).pow(28).multiply(BigInteger.valueOf(117141993)));
+        result = result.subtract(BigInteger.valueOf(2).pow(56).multiply(BigInteger.valueOf(62411077)));
+        result = result.subtract(BigInteger.valueOf(2).pow(84).multiply(BigInteger.valueOf(56915814)));
+        result = result.add(BigInteger.valueOf(2).pow(112).multiply(BigInteger.valueOf(97532854)));
+        result = result.add(BigInteger.valueOf(2).pow(140).multiply(BigInteger.valueOf(76509338)));
+        result = result.subtract(BigInteger.valueOf(2).pow(168).multiply(BigInteger.valueOf(75510783)));
+        result = result.subtract(BigInteger.valueOf(2).pow(196).multiply(BigInteger.valueOf(67962521)));
+        result = result.add(BigInteger.valueOf(2).pow(224).multiply(BigInteger.valueOf(25593732)));
+        result = result.subtract(BigInteger.valueOf(2).pow(252).multiply(BigInteger.valueOf(91)));
+        return result;
+    }
+    @Override
+    protected void finalCarryReduceLast(long[] limbs) {
+        long c = limbs[18] >> 17;
+        limbs[18] -= c << 17;
+        long t0 = -20472841 * c;
+        limbs[0] += t0;
+        t0 = -117141993 * c;
+        limbs[1] += t0;
+        t0 = 62411077 * c;
+        limbs[2] += t0;
+        t0 = 56915814 * c;
+        limbs[3] += t0;
+        t0 = -97532854 * c;
+        limbs[4] += t0;
+        t0 = -76509338 * c;
+        limbs[5] += t0;
+        t0 = 75510783 * c;
+        limbs[6] += t0;
+        t0 = 67962521 * c;
+        limbs[7] += t0;
+        t0 = -25593732 * c;
+        limbs[8] += t0;
+        t0 = 91 * c;
+        limbs[9] += t0;
+    }
+    private void carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26, long c27, long c28, long c29, long c30, long c31, long c32, long c33, long c34, long c35, long c36) {
+        long c37 = 0;
+        //carry from position 0
+        long t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 28;
+        c13 -= (t0 << 28);
+        c14 += t0;
+        //carry from position 14
+        t0 = (c14 + CARRY_ADD) >> 28;
+        c14 -= (t0 << 28);
+        c15 += t0;
+        //carry from position 15
+        t0 = (c15 + CARRY_ADD) >> 28;
+        c15 -= (t0 << 28);
+        c16 += t0;
+        //carry from position 16
+        t0 = (c16 + CARRY_ADD) >> 28;
+        c16 -= (t0 << 28);
+        c17 += t0;
+        //carry from position 17
+        t0 = (c17 + CARRY_ADD) >> 28;
+        c17 -= (t0 << 28);
+        c18 += t0;
+        //carry from position 18
+        t0 = (c18 + CARRY_ADD) >> 28;
+        c18 -= (t0 << 28);
+        c19 += t0;
+        //carry from position 19
+        t0 = (c19 + CARRY_ADD) >> 28;
+        c19 -= (t0 << 28);
+        c20 += t0;
+        //carry from position 20
+        t0 = (c20 + CARRY_ADD) >> 28;
+        c20 -= (t0 << 28);
+        c21 += t0;
+        //carry from position 21
+        t0 = (c21 + CARRY_ADD) >> 28;
+        c21 -= (t0 << 28);
+        c22 += t0;
+        //carry from position 22
+        t0 = (c22 + CARRY_ADD) >> 28;
+        c22 -= (t0 << 28);
+        c23 += t0;
+        //carry from position 23
+        t0 = (c23 + CARRY_ADD) >> 28;
+        c23 -= (t0 << 28);
+        c24 += t0;
+        //carry from position 24
+        t0 = (c24 + CARRY_ADD) >> 28;
+        c24 -= (t0 << 28);
+        c25 += t0;
+        //carry from position 25
+        t0 = (c25 + CARRY_ADD) >> 28;
+        c25 -= (t0 << 28);
+        c26 += t0;
+        //carry from position 26
+        t0 = (c26 + CARRY_ADD) >> 28;
+        c26 -= (t0 << 28);
+        c27 += t0;
+        //carry from position 27
+        t0 = (c27 + CARRY_ADD) >> 28;
+        c27 -= (t0 << 28);
+        c28 += t0;
+        //carry from position 28
+        t0 = (c28 + CARRY_ADD) >> 28;
+        c28 -= (t0 << 28);
+        c29 += t0;
+        //carry from position 29
+        t0 = (c29 + CARRY_ADD) >> 28;
+        c29 -= (t0 << 28);
+        c30 += t0;
+        //carry from position 30
+        t0 = (c30 + CARRY_ADD) >> 28;
+        c30 -= (t0 << 28);
+        c31 += t0;
+        //carry from position 31
+        t0 = (c31 + CARRY_ADD) >> 28;
+        c31 -= (t0 << 28);
+        c32 += t0;
+        //carry from position 32
+        t0 = (c32 + CARRY_ADD) >> 28;
+        c32 -= (t0 << 28);
+        c33 += t0;
+        //carry from position 33
+        t0 = (c33 + CARRY_ADD) >> 28;
+        c33 -= (t0 << 28);
+        c34 += t0;
+        //carry from position 34
+        t0 = (c34 + CARRY_ADD) >> 28;
+        c34 -= (t0 << 28);
+        c35 += t0;
+        //carry from position 35
+        t0 = (c35 + CARRY_ADD) >> 28;
+        c35 -= (t0 << 28);
+        c36 += t0;
+        //carry from position 36
+        t0 = (c36 + CARRY_ADD) >> 28;
+        c36 -= (t0 << 28);
+        c37 += t0;
+
+        carryReduce0(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c36, c37);
+    }
+    void carryReduce0(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26, long c27, long c28, long c29, long c30, long c31, long c32, long c33, long c34, long c35, long c36, long c37) {
+        long t0;
+
+        //reduce from position 37
+        t0 = -20472841 * c37;
+        c18 += (t0 << 11) & LIMB_MASK;
+        c19 += t0 >> 17;
+        t0 = -117141993 * c37;
+        c19 += (t0 << 11) & LIMB_MASK;
+        c20 += t0 >> 17;
+        t0 = 62411077 * c37;
+        c20 += (t0 << 11) & LIMB_MASK;
+        c21 += t0 >> 17;
+        t0 = 56915814 * c37;
+        c21 += (t0 << 11) & LIMB_MASK;
+        c22 += t0 >> 17;
+        t0 = -97532854 * c37;
+        c22 += (t0 << 11) & LIMB_MASK;
+        c23 += t0 >> 17;
+        t0 = -76509338 * c37;
+        c23 += (t0 << 11) & LIMB_MASK;
+        c24 += t0 >> 17;
+        t0 = 75510783 * c37;
+        c24 += (t0 << 11) & LIMB_MASK;
+        c25 += t0 >> 17;
+        t0 = 67962521 * c37;
+        c25 += (t0 << 11) & LIMB_MASK;
+        c26 += t0 >> 17;
+        t0 = -25593732 * c37;
+        c26 += (t0 << 11) & LIMB_MASK;
+        c27 += t0 >> 17;
+        t0 = 91 * c37;
+        c27 += (t0 << 11) & LIMB_MASK;
+        c28 += t0 >> 17;
+        //reduce from position 36
+        t0 = -20472841 * c36;
+        c17 += (t0 << 11) & LIMB_MASK;
+        c18 += t0 >> 17;
+        t0 = -117141993 * c36;
+        c18 += (t0 << 11) & LIMB_MASK;
+        c19 += t0 >> 17;
+        t0 = 62411077 * c36;
+        c19 += (t0 << 11) & LIMB_MASK;
+        c20 += t0 >> 17;
+        t0 = 56915814 * c36;
+        c20 += (t0 << 11) & LIMB_MASK;
+        c21 += t0 >> 17;
+        t0 = -97532854 * c36;
+        c21 += (t0 << 11) & LIMB_MASK;
+        c22 += t0 >> 17;
+        t0 = -76509338 * c36;
+        c22 += (t0 << 11) & LIMB_MASK;
+        c23 += t0 >> 17;
+        t0 = 75510783 * c36;
+        c23 += (t0 << 11) & LIMB_MASK;
+        c24 += t0 >> 17;
+        t0 = 67962521 * c36;
+        c24 += (t0 << 11) & LIMB_MASK;
+        c25 += t0 >> 17;
+        t0 = -25593732 * c36;
+        c25 += (t0 << 11) & LIMB_MASK;
+        c26 += t0 >> 17;
+        t0 = 91 * c36;
+        c26 += (t0 << 11) & LIMB_MASK;
+        c27 += t0 >> 17;
+        //reduce from position 35
+        t0 = -20472841 * c35;
+        c16 += (t0 << 11) & LIMB_MASK;
+        c17 += t0 >> 17;
+        t0 = -117141993 * c35;
+        c17 += (t0 << 11) & LIMB_MASK;
+        c18 += t0 >> 17;
+        t0 = 62411077 * c35;
+        c18 += (t0 << 11) & LIMB_MASK;
+        c19 += t0 >> 17;
+        t0 = 56915814 * c35;
+        c19 += (t0 << 11) & LIMB_MASK;
+        c20 += t0 >> 17;
+        t0 = -97532854 * c35;
+        c20 += (t0 << 11) & LIMB_MASK;
+        c21 += t0 >> 17;
+        t0 = -76509338 * c35;
+        c21 += (t0 << 11) & LIMB_MASK;
+        c22 += t0 >> 17;
+        t0 = 75510783 * c35;
+        c22 += (t0 << 11) & LIMB_MASK;
+        c23 += t0 >> 17;
+        t0 = 67962521 * c35;
+        c23 += (t0 << 11) & LIMB_MASK;
+        c24 += t0 >> 17;
+        t0 = -25593732 * c35;
+        c24 += (t0 << 11) & LIMB_MASK;
+        c25 += t0 >> 17;
+        t0 = 91 * c35;
+        c25 += (t0 << 11) & LIMB_MASK;
+        c26 += t0 >> 17;
+        //reduce from position 34
+        t0 = -20472841 * c34;
+        c15 += (t0 << 11) & LIMB_MASK;
+        c16 += t0 >> 17;
+        t0 = -117141993 * c34;
+        c16 += (t0 << 11) & LIMB_MASK;
+        c17 += t0 >> 17;
+        t0 = 62411077 * c34;
+        c17 += (t0 << 11) & LIMB_MASK;
+        c18 += t0 >> 17;
+        t0 = 56915814 * c34;
+        c18 += (t0 << 11) & LIMB_MASK;
+        c19 += t0 >> 17;
+        t0 = -97532854 * c34;
+        c19 += (t0 << 11) & LIMB_MASK;
+        c20 += t0 >> 17;
+        t0 = -76509338 * c34;
+        c20 += (t0 << 11) & LIMB_MASK;
+        c21 += t0 >> 17;
+        t0 = 75510783 * c34;
+        c21 += (t0 << 11) & LIMB_MASK;
+        c22 += t0 >> 17;
+        t0 = 67962521 * c34;
+        c22 += (t0 << 11) & LIMB_MASK;
+        c23 += t0 >> 17;
+        t0 = -25593732 * c34;
+        c23 += (t0 << 11) & LIMB_MASK;
+        c24 += t0 >> 17;
+        t0 = 91 * c34;
+        c24 += (t0 << 11) & LIMB_MASK;
+        c25 += t0 >> 17;
+        //reduce from position 33
+        t0 = -20472841 * c33;
+        c14 += (t0 << 11) & LIMB_MASK;
+        c15 += t0 >> 17;
+        t0 = -117141993 * c33;
+        c15 += (t0 << 11) & LIMB_MASK;
+        c16 += t0 >> 17;
+        t0 = 62411077 * c33;
+        c16 += (t0 << 11) & LIMB_MASK;
+        c17 += t0 >> 17;
+        t0 = 56915814 * c33;
+        c17 += (t0 << 11) & LIMB_MASK;
+        c18 += t0 >> 17;
+        t0 = -97532854 * c33;
+        c18 += (t0 << 11) & LIMB_MASK;
+        c19 += t0 >> 17;
+        t0 = -76509338 * c33;
+        c19 += (t0 << 11) & LIMB_MASK;
+        c20 += t0 >> 17;
+        t0 = 75510783 * c33;
+        c20 += (t0 << 11) & LIMB_MASK;
+        c21 += t0 >> 17;
+        t0 = 67962521 * c33;
+        c21 += (t0 << 11) & LIMB_MASK;
+        c22 += t0 >> 17;
+        t0 = -25593732 * c33;
+        c22 += (t0 << 11) & LIMB_MASK;
+        c23 += t0 >> 17;
+        t0 = 91 * c33;
+        c23 += (t0 << 11) & LIMB_MASK;
+        c24 += t0 >> 17;
+        //reduce from position 32
+        t0 = -20472841 * c32;
+        c13 += (t0 << 11) & LIMB_MASK;
+        c14 += t0 >> 17;
+        t0 = -117141993 * c32;
+        c14 += (t0 << 11) & LIMB_MASK;
+        c15 += t0 >> 17;
+        t0 = 62411077 * c32;
+        c15 += (t0 << 11) & LIMB_MASK;
+        c16 += t0 >> 17;
+        t0 = 56915814 * c32;
+        c16 += (t0 << 11) & LIMB_MASK;
+        c17 += t0 >> 17;
+        t0 = -97532854 * c32;
+        c17 += (t0 << 11) & LIMB_MASK;
+        c18 += t0 >> 17;
+        t0 = -76509338 * c32;
+        c18 += (t0 << 11) & LIMB_MASK;
+        c19 += t0 >> 17;
+        t0 = 75510783 * c32;
+        c19 += (t0 << 11) & LIMB_MASK;
+        c20 += t0 >> 17;
+        t0 = 67962521 * c32;
+        c20 += (t0 << 11) & LIMB_MASK;
+        c21 += t0 >> 17;
+        t0 = -25593732 * c32;
+        c21 += (t0 << 11) & LIMB_MASK;
+        c22 += t0 >> 17;
+        t0 = 91 * c32;
+        c22 += (t0 << 11) & LIMB_MASK;
+        c23 += t0 >> 17;
+        //reduce from position 31
+        t0 = -20472841 * c31;
+        c12 += (t0 << 11) & LIMB_MASK;
+        c13 += t0 >> 17;
+        t0 = -117141993 * c31;
+        c13 += (t0 << 11) & LIMB_MASK;
+        c14 += t0 >> 17;
+        t0 = 62411077 * c31;
+        c14 += (t0 << 11) & LIMB_MASK;
+        c15 += t0 >> 17;
+        t0 = 56915814 * c31;
+        c15 += (t0 << 11) & LIMB_MASK;
+        c16 += t0 >> 17;
+        t0 = -97532854 * c31;
+        c16 += (t0 << 11) & LIMB_MASK;
+        c17 += t0 >> 17;
+        t0 = -76509338 * c31;
+        c17 += (t0 << 11) & LIMB_MASK;
+        c18 += t0 >> 17;
+        t0 = 75510783 * c31;
+        c18 += (t0 << 11) & LIMB_MASK;
+        c19 += t0 >> 17;
+        t0 = 67962521 * c31;
+        c19 += (t0 << 11) & LIMB_MASK;
+        c20 += t0 >> 17;
+        t0 = -25593732 * c31;
+        c20 += (t0 << 11) & LIMB_MASK;
+        c21 += t0 >> 17;
+        t0 = 91 * c31;
+        c21 += (t0 << 11) & LIMB_MASK;
+        c22 += t0 >> 17;
+        //reduce from position 30
+        t0 = -20472841 * c30;
+        c11 += (t0 << 11) & LIMB_MASK;
+        c12 += t0 >> 17;
+        t0 = -117141993 * c30;
+        c12 += (t0 << 11) & LIMB_MASK;
+        c13 += t0 >> 17;
+        t0 = 62411077 * c30;
+        c13 += (t0 << 11) & LIMB_MASK;
+        c14 += t0 >> 17;
+        t0 = 56915814 * c30;
+        c14 += (t0 << 11) & LIMB_MASK;
+        c15 += t0 >> 17;
+        t0 = -97532854 * c30;
+        c15 += (t0 << 11) & LIMB_MASK;
+        c16 += t0 >> 17;
+        t0 = -76509338 * c30;
+        c16 += (t0 << 11) & LIMB_MASK;
+        c17 += t0 >> 17;
+        t0 = 75510783 * c30;
+        c17 += (t0 << 11) & LIMB_MASK;
+        c18 += t0 >> 17;
+        t0 = 67962521 * c30;
+        c18 += (t0 << 11) & LIMB_MASK;
+        c19 += t0 >> 17;
+        t0 = -25593732 * c30;
+        c19 += (t0 << 11) & LIMB_MASK;
+        c20 += t0 >> 17;
+        t0 = 91 * c30;
+        c20 += (t0 << 11) & LIMB_MASK;
+        c21 += t0 >> 17;
+        //reduce from position 29
+        t0 = -20472841 * c29;
+        c10 += (t0 << 11) & LIMB_MASK;
+        c11 += t0 >> 17;
+        t0 = -117141993 * c29;
+        c11 += (t0 << 11) & LIMB_MASK;
+        c12 += t0 >> 17;
+        t0 = 62411077 * c29;
+        c12 += (t0 << 11) & LIMB_MASK;
+        c13 += t0 >> 17;
+        t0 = 56915814 * c29;
+        c13 += (t0 << 11) & LIMB_MASK;
+        c14 += t0 >> 17;
+        t0 = -97532854 * c29;
+        c14 += (t0 << 11) & LIMB_MASK;
+        c15 += t0 >> 17;
+        t0 = -76509338 * c29;
+        c15 += (t0 << 11) & LIMB_MASK;
+        c16 += t0 >> 17;
+        t0 = 75510783 * c29;
+        c16 += (t0 << 11) & LIMB_MASK;
+        c17 += t0 >> 17;
+        t0 = 67962521 * c29;
+        c17 += (t0 << 11) & LIMB_MASK;
+        c18 += t0 >> 17;
+        t0 = -25593732 * c29;
+        c18 += (t0 << 11) & LIMB_MASK;
+        c19 += t0 >> 17;
+        t0 = 91 * c29;
+        c19 += (t0 << 11) & LIMB_MASK;
+        c20 += t0 >> 17;
+        //reduce from position 28
+        t0 = -20472841 * c28;
+        c9 += (t0 << 11) & LIMB_MASK;
+        c10 += t0 >> 17;
+        t0 = -117141993 * c28;
+        c10 += (t0 << 11) & LIMB_MASK;
+        c11 += t0 >> 17;
+        t0 = 62411077 * c28;
+        c11 += (t0 << 11) & LIMB_MASK;
+        c12 += t0 >> 17;
+        t0 = 56915814 * c28;
+        c12 += (t0 << 11) & LIMB_MASK;
+        c13 += t0 >> 17;
+        t0 = -97532854 * c28;
+        c13 += (t0 << 11) & LIMB_MASK;
+        c14 += t0 >> 17;
+        t0 = -76509338 * c28;
+        c14 += (t0 << 11) & LIMB_MASK;
+        c15 += t0 >> 17;
+        t0 = 75510783 * c28;
+        c15 += (t0 << 11) & LIMB_MASK;
+        c16 += t0 >> 17;
+        t0 = 67962521 * c28;
+        c16 += (t0 << 11) & LIMB_MASK;
+        c17 += t0 >> 17;
+        t0 = -25593732 * c28;
+        c17 += (t0 << 11) & LIMB_MASK;
+        c18 += t0 >> 17;
+        t0 = 91 * c28;
+        c18 += (t0 << 11) & LIMB_MASK;
+        c19 += t0 >> 17;
+
+        carryReduce1(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c36, c37);
+    }
+    void carryReduce1(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26, long c27, long c28, long c29, long c30, long c31, long c32, long c33, long c34, long c35, long c36, long c37) {
+        long t0;
+
+        //carry from position 19
+        t0 = (c19 + CARRY_ADD) >> 28;
+        c19 -= (t0 << 28);
+        c20 += t0;
+        //carry from position 20
+        t0 = (c20 + CARRY_ADD) >> 28;
+        c20 -= (t0 << 28);
+        c21 += t0;
+        //carry from position 21
+        t0 = (c21 + CARRY_ADD) >> 28;
+        c21 -= (t0 << 28);
+        c22 += t0;
+        //carry from position 22
+        t0 = (c22 + CARRY_ADD) >> 28;
+        c22 -= (t0 << 28);
+        c23 += t0;
+        //carry from position 23
+        t0 = (c23 + CARRY_ADD) >> 28;
+        c23 -= (t0 << 28);
+        c24 += t0;
+        //carry from position 24
+        t0 = (c24 + CARRY_ADD) >> 28;
+        c24 -= (t0 << 28);
+        c25 += t0;
+        //carry from position 25
+        t0 = (c25 + CARRY_ADD) >> 28;
+        c25 -= (t0 << 28);
+        c26 += t0;
+        //carry from position 26
+        t0 = (c26 + CARRY_ADD) >> 28;
+        c26 -= (t0 << 28);
+        c27 += t0;
+        //reduce from position 27
+        t0 = -20472841 * c27;
+        c8 += (t0 << 11) & LIMB_MASK;
+        c9 += t0 >> 17;
+        t0 = -117141993 * c27;
+        c9 += (t0 << 11) & LIMB_MASK;
+        c10 += t0 >> 17;
+        t0 = 62411077 * c27;
+        c10 += (t0 << 11) & LIMB_MASK;
+        c11 += t0 >> 17;
+        t0 = 56915814 * c27;
+        c11 += (t0 << 11) & LIMB_MASK;
+        c12 += t0 >> 17;
+        t0 = -97532854 * c27;
+        c12 += (t0 << 11) & LIMB_MASK;
+        c13 += t0 >> 17;
+        t0 = -76509338 * c27;
+        c13 += (t0 << 11) & LIMB_MASK;
+        c14 += t0 >> 17;
+        t0 = 75510783 * c27;
+        c14 += (t0 << 11) & LIMB_MASK;
+        c15 += t0 >> 17;
+        t0 = 67962521 * c27;
+        c15 += (t0 << 11) & LIMB_MASK;
+        c16 += t0 >> 17;
+        t0 = -25593732 * c27;
+        c16 += (t0 << 11) & LIMB_MASK;
+        c17 += t0 >> 17;
+        t0 = 91 * c27;
+        c17 += (t0 << 11) & LIMB_MASK;
+        c18 += t0 >> 17;
+        //reduce from position 26
+        t0 = -20472841 * c26;
+        c7 += (t0 << 11) & LIMB_MASK;
+        c8 += t0 >> 17;
+        t0 = -117141993 * c26;
+        c8 += (t0 << 11) & LIMB_MASK;
+        c9 += t0 >> 17;
+        t0 = 62411077 * c26;
+        c9 += (t0 << 11) & LIMB_MASK;
+        c10 += t0 >> 17;
+        t0 = 56915814 * c26;
+        c10 += (t0 << 11) & LIMB_MASK;
+        c11 += t0 >> 17;
+        t0 = -97532854 * c26;
+        c11 += (t0 << 11) & LIMB_MASK;
+        c12 += t0 >> 17;
+        t0 = -76509338 * c26;
+        c12 += (t0 << 11) & LIMB_MASK;
+        c13 += t0 >> 17;
+        t0 = 75510783 * c26;
+        c13 += (t0 << 11) & LIMB_MASK;
+        c14 += t0 >> 17;
+        t0 = 67962521 * c26;
+        c14 += (t0 << 11) & LIMB_MASK;
+        c15 += t0 >> 17;
+        t0 = -25593732 * c26;
+        c15 += (t0 << 11) & LIMB_MASK;
+        c16 += t0 >> 17;
+        t0 = 91 * c26;
+        c16 += (t0 << 11) & LIMB_MASK;
+        c17 += t0 >> 17;
+        //reduce from position 25
+        t0 = -20472841 * c25;
+        c6 += (t0 << 11) & LIMB_MASK;
+        c7 += t0 >> 17;
+        t0 = -117141993 * c25;
+        c7 += (t0 << 11) & LIMB_MASK;
+        c8 += t0 >> 17;
+        t0 = 62411077 * c25;
+        c8 += (t0 << 11) & LIMB_MASK;
+        c9 += t0 >> 17;
+        t0 = 56915814 * c25;
+        c9 += (t0 << 11) & LIMB_MASK;
+        c10 += t0 >> 17;
+        t0 = -97532854 * c25;
+        c10 += (t0 << 11) & LIMB_MASK;
+        c11 += t0 >> 17;
+        t0 = -76509338 * c25;
+        c11 += (t0 << 11) & LIMB_MASK;
+        c12 += t0 >> 17;
+        t0 = 75510783 * c25;
+        c12 += (t0 << 11) & LIMB_MASK;
+        c13 += t0 >> 17;
+        t0 = 67962521 * c25;
+        c13 += (t0 << 11) & LIMB_MASK;
+        c14 += t0 >> 17;
+        t0 = -25593732 * c25;
+        c14 += (t0 << 11) & LIMB_MASK;
+        c15 += t0 >> 17;
+        t0 = 91 * c25;
+        c15 += (t0 << 11) & LIMB_MASK;
+        c16 += t0 >> 17;
+        //reduce from position 24
+        t0 = -20472841 * c24;
+        c5 += (t0 << 11) & LIMB_MASK;
+        c6 += t0 >> 17;
+        t0 = -117141993 * c24;
+        c6 += (t0 << 11) & LIMB_MASK;
+        c7 += t0 >> 17;
+        t0 = 62411077 * c24;
+        c7 += (t0 << 11) & LIMB_MASK;
+        c8 += t0 >> 17;
+        t0 = 56915814 * c24;
+        c8 += (t0 << 11) & LIMB_MASK;
+        c9 += t0 >> 17;
+        t0 = -97532854 * c24;
+        c9 += (t0 << 11) & LIMB_MASK;
+        c10 += t0 >> 17;
+        t0 = -76509338 * c24;
+        c10 += (t0 << 11) & LIMB_MASK;
+        c11 += t0 >> 17;
+        t0 = 75510783 * c24;
+        c11 += (t0 << 11) & LIMB_MASK;
+        c12 += t0 >> 17;
+        t0 = 67962521 * c24;
+        c12 += (t0 << 11) & LIMB_MASK;
+        c13 += t0 >> 17;
+        t0 = -25593732 * c24;
+        c13 += (t0 << 11) & LIMB_MASK;
+        c14 += t0 >> 17;
+        t0 = 91 * c24;
+        c14 += (t0 << 11) & LIMB_MASK;
+        c15 += t0 >> 17;
+        //reduce from position 23
+        t0 = -20472841 * c23;
+        c4 += (t0 << 11) & LIMB_MASK;
+        c5 += t0 >> 17;
+        t0 = -117141993 * c23;
+        c5 += (t0 << 11) & LIMB_MASK;
+        c6 += t0 >> 17;
+        t0 = 62411077 * c23;
+        c6 += (t0 << 11) & LIMB_MASK;
+        c7 += t0 >> 17;
+        t0 = 56915814 * c23;
+        c7 += (t0 << 11) & LIMB_MASK;
+        c8 += t0 >> 17;
+        t0 = -97532854 * c23;
+        c8 += (t0 << 11) & LIMB_MASK;
+        c9 += t0 >> 17;
+        t0 = -76509338 * c23;
+        c9 += (t0 << 11) & LIMB_MASK;
+        c10 += t0 >> 17;
+        t0 = 75510783 * c23;
+        c10 += (t0 << 11) & LIMB_MASK;
+        c11 += t0 >> 17;
+        t0 = 67962521 * c23;
+        c11 += (t0 << 11) & LIMB_MASK;
+        c12 += t0 >> 17;
+        t0 = -25593732 * c23;
+        c12 += (t0 << 11) & LIMB_MASK;
+        c13 += t0 >> 17;
+        t0 = 91 * c23;
+        c13 += (t0 << 11) & LIMB_MASK;
+        c14 += t0 >> 17;
+        //reduce from position 22
+        t0 = -20472841 * c22;
+        c3 += (t0 << 11) & LIMB_MASK;
+        c4 += t0 >> 17;
+        t0 = -117141993 * c22;
+        c4 += (t0 << 11) & LIMB_MASK;
+        c5 += t0 >> 17;
+        t0 = 62411077 * c22;
+        c5 += (t0 << 11) & LIMB_MASK;
+        c6 += t0 >> 17;
+        t0 = 56915814 * c22;
+        c6 += (t0 << 11) & LIMB_MASK;
+        c7 += t0 >> 17;
+        t0 = -97532854 * c22;
+        c7 += (t0 << 11) & LIMB_MASK;
+        c8 += t0 >> 17;
+        t0 = -76509338 * c22;
+        c8 += (t0 << 11) & LIMB_MASK;
+        c9 += t0 >> 17;
+        t0 = 75510783 * c22;
+        c9 += (t0 << 11) & LIMB_MASK;
+        c10 += t0 >> 17;
+        t0 = 67962521 * c22;
+        c10 += (t0 << 11) & LIMB_MASK;
+        c11 += t0 >> 17;
+        t0 = -25593732 * c22;
+        c11 += (t0 << 11) & LIMB_MASK;
+        c12 += t0 >> 17;
+        t0 = 91 * c22;
+        c12 += (t0 << 11) & LIMB_MASK;
+        c13 += t0 >> 17;
+        //reduce from position 21
+        t0 = -20472841 * c21;
+        c2 += (t0 << 11) & LIMB_MASK;
+        c3 += t0 >> 17;
+        t0 = -117141993 * c21;
+        c3 += (t0 << 11) & LIMB_MASK;
+        c4 += t0 >> 17;
+        t0 = 62411077 * c21;
+        c4 += (t0 << 11) & LIMB_MASK;
+        c5 += t0 >> 17;
+        t0 = 56915814 * c21;
+        c5 += (t0 << 11) & LIMB_MASK;
+        c6 += t0 >> 17;
+        t0 = -97532854 * c21;
+        c6 += (t0 << 11) & LIMB_MASK;
+        c7 += t0 >> 17;
+        t0 = -76509338 * c21;
+        c7 += (t0 << 11) & LIMB_MASK;
+        c8 += t0 >> 17;
+        t0 = 75510783 * c21;
+        c8 += (t0 << 11) & LIMB_MASK;
+        c9 += t0 >> 17;
+        t0 = 67962521 * c21;
+        c9 += (t0 << 11) & LIMB_MASK;
+        c10 += t0 >> 17;
+        t0 = -25593732 * c21;
+        c10 += (t0 << 11) & LIMB_MASK;
+        c11 += t0 >> 17;
+        t0 = 91 * c21;
+        c11 += (t0 << 11) & LIMB_MASK;
+        c12 += t0 >> 17;
+        //reduce from position 20
+        t0 = -20472841 * c20;
+        c1 += (t0 << 11) & LIMB_MASK;
+        c2 += t0 >> 17;
+        t0 = -117141993 * c20;
+        c2 += (t0 << 11) & LIMB_MASK;
+        c3 += t0 >> 17;
+        t0 = 62411077 * c20;
+        c3 += (t0 << 11) & LIMB_MASK;
+        c4 += t0 >> 17;
+        t0 = 56915814 * c20;
+        c4 += (t0 << 11) & LIMB_MASK;
+        c5 += t0 >> 17;
+        t0 = -97532854 * c20;
+        c5 += (t0 << 11) & LIMB_MASK;
+        c6 += t0 >> 17;
+        t0 = -76509338 * c20;
+        c6 += (t0 << 11) & LIMB_MASK;
+        c7 += t0 >> 17;
+        t0 = 75510783 * c20;
+        c7 += (t0 << 11) & LIMB_MASK;
+        c8 += t0 >> 17;
+        t0 = 67962521 * c20;
+        c8 += (t0 << 11) & LIMB_MASK;
+        c9 += t0 >> 17;
+        t0 = -25593732 * c20;
+        c9 += (t0 << 11) & LIMB_MASK;
+        c10 += t0 >> 17;
+        t0 = 91 * c20;
+        c10 += (t0 << 11) & LIMB_MASK;
+        c11 += t0 >> 17;
+        //reduce from position 19
+        t0 = -20472841 * c19;
+        c0 += (t0 << 11) & LIMB_MASK;
+        c1 += t0 >> 17;
+        t0 = -117141993 * c19;
+        c1 += (t0 << 11) & LIMB_MASK;
+        c2 += t0 >> 17;
+        t0 = 62411077 * c19;
+        c2 += (t0 << 11) & LIMB_MASK;
+        c3 += t0 >> 17;
+        t0 = 56915814 * c19;
+        c3 += (t0 << 11) & LIMB_MASK;
+        c4 += t0 >> 17;
+        t0 = -97532854 * c19;
+        c4 += (t0 << 11) & LIMB_MASK;
+        c5 += t0 >> 17;
+        t0 = -76509338 * c19;
+        c5 += (t0 << 11) & LIMB_MASK;
+        c6 += t0 >> 17;
+        t0 = 75510783 * c19;
+        c6 += (t0 << 11) & LIMB_MASK;
+        c7 += t0 >> 17;
+        t0 = 67962521 * c19;
+        c7 += (t0 << 11) & LIMB_MASK;
+        c8 += t0 >> 17;
+        t0 = -25593732 * c19;
+        c8 += (t0 << 11) & LIMB_MASK;
+        c9 += t0 >> 17;
+        t0 = 91 * c19;
+        c9 += (t0 << 11) & LIMB_MASK;
+        c10 += t0 >> 17;
+        c19 = 0;
+
+        carryReduce2(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c36, c37);
+    }
+    void carryReduce2(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26, long c27, long c28, long c29, long c30, long c31, long c32, long c33, long c34, long c35, long c36, long c37) {
+        long t0;
+
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 28;
+        c13 -= (t0 << 28);
+        c14 += t0;
+        //carry from position 14
+        t0 = (c14 + CARRY_ADD) >> 28;
+        c14 -= (t0 << 28);
+        c15 += t0;
+        //carry from position 15
+        t0 = (c15 + CARRY_ADD) >> 28;
+        c15 -= (t0 << 28);
+        c16 += t0;
+        //carry from position 16
+        t0 = (c16 + CARRY_ADD) >> 28;
+        c16 -= (t0 << 28);
+        c17 += t0;
+        //carry from position 17
+        t0 = (c17 + CARRY_ADD) >> 28;
+        c17 -= (t0 << 28);
+        c18 += t0;
+        //carry from position 18
+        t0 = (c18 + CARRY_ADD) >> 28;
+        c18 -= (t0 << 28);
+        c19 += t0;
+
+        carryReduce3(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c36, c37);
+    }
+    void carryReduce3(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19, long c20, long c21, long c22, long c23, long c24, long c25, long c26, long c27, long c28, long c29, long c30, long c31, long c32, long c33, long c34, long c35, long c36, long c37) {
+        long t0;
+
+        //reduce from position 19
+        t0 = -20472841 * c19;
+        c0 += (t0 << 11) & LIMB_MASK;
+        c1 += t0 >> 17;
+        t0 = -117141993 * c19;
+        c1 += (t0 << 11) & LIMB_MASK;
+        c2 += t0 >> 17;
+        t0 = 62411077 * c19;
+        c2 += (t0 << 11) & LIMB_MASK;
+        c3 += t0 >> 17;
+        t0 = 56915814 * c19;
+        c3 += (t0 << 11) & LIMB_MASK;
+        c4 += t0 >> 17;
+        t0 = -97532854 * c19;
+        c4 += (t0 << 11) & LIMB_MASK;
+        c5 += t0 >> 17;
+        t0 = -76509338 * c19;
+        c5 += (t0 << 11) & LIMB_MASK;
+        c6 += t0 >> 17;
+        t0 = 75510783 * c19;
+        c6 += (t0 << 11) & LIMB_MASK;
+        c7 += t0 >> 17;
+        t0 = 67962521 * c19;
+        c7 += (t0 << 11) & LIMB_MASK;
+        c8 += t0 >> 17;
+        t0 = -25593732 * c19;
+        c8 += (t0 << 11) & LIMB_MASK;
+        c9 += t0 >> 17;
+        t0 = 91 * c19;
+        c9 += (t0 << 11) & LIMB_MASK;
+        c10 += t0 >> 17;
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 28;
+        c13 -= (t0 << 28);
+        c14 += t0;
+        //carry from position 14
+        t0 = (c14 + CARRY_ADD) >> 28;
+        c14 -= (t0 << 28);
+        c15 += t0;
+        //carry from position 15
+        t0 = (c15 + CARRY_ADD) >> 28;
+        c15 -= (t0 << 28);
+        c16 += t0;
+        //carry from position 16
+        t0 = (c16 + CARRY_ADD) >> 28;
+        c16 -= (t0 << 28);
+        c17 += t0;
+        //carry from position 17
+        t0 = (c17 + CARRY_ADD) >> 28;
+        c17 -= (t0 << 28);
+        c18 += t0;
+
+        r[0] = c0;
+        r[1] = c1;
+        r[2] = c2;
+        r[3] = c3;
+        r[4] = c4;
+        r[5] = c5;
+        r[6] = c6;
+        r[7] = c7;
+        r[8] = c8;
+        r[9] = c9;
+        r[10] = c10;
+        r[11] = c11;
+        r[12] = c12;
+        r[13] = c13;
+        r[14] = c14;
+        r[15] = c15;
+        r[16] = c16;
+        r[17] = c17;
+        r[18] = c18;
+    }
+    private void carryReduce(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18) {
+        long c19 = 0;
+        //carry from position 0
+        long t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 28;
+        c13 -= (t0 << 28);
+        c14 += t0;
+        //carry from position 14
+        t0 = (c14 + CARRY_ADD) >> 28;
+        c14 -= (t0 << 28);
+        c15 += t0;
+        //carry from position 15
+        t0 = (c15 + CARRY_ADD) >> 28;
+        c15 -= (t0 << 28);
+        c16 += t0;
+        //carry from position 16
+        t0 = (c16 + CARRY_ADD) >> 28;
+        c16 -= (t0 << 28);
+        c17 += t0;
+        //carry from position 17
+        t0 = (c17 + CARRY_ADD) >> 28;
+        c17 -= (t0 << 28);
+        c18 += t0;
+        //carry from position 18
+        t0 = (c18 + CARRY_ADD) >> 28;
+        c18 -= (t0 << 28);
+        c19 += t0;
+
+        carryReduce0(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19);
+    }
+    void carryReduce0(long[] r, long c0, long c1, long c2, long c3, long c4, long c5, long c6, long c7, long c8, long c9, long c10, long c11, long c12, long c13, long c14, long c15, long c16, long c17, long c18, long c19) {
+        long t0;
+
+        //reduce from position 19
+        t0 = -20472841 * c19;
+        c0 += (t0 << 11) & LIMB_MASK;
+        c1 += t0 >> 17;
+        t0 = -117141993 * c19;
+        c1 += (t0 << 11) & LIMB_MASK;
+        c2 += t0 >> 17;
+        t0 = 62411077 * c19;
+        c2 += (t0 << 11) & LIMB_MASK;
+        c3 += t0 >> 17;
+        t0 = 56915814 * c19;
+        c3 += (t0 << 11) & LIMB_MASK;
+        c4 += t0 >> 17;
+        t0 = -97532854 * c19;
+        c4 += (t0 << 11) & LIMB_MASK;
+        c5 += t0 >> 17;
+        t0 = -76509338 * c19;
+        c5 += (t0 << 11) & LIMB_MASK;
+        c6 += t0 >> 17;
+        t0 = 75510783 * c19;
+        c6 += (t0 << 11) & LIMB_MASK;
+        c7 += t0 >> 17;
+        t0 = 67962521 * c19;
+        c7 += (t0 << 11) & LIMB_MASK;
+        c8 += t0 >> 17;
+        t0 = -25593732 * c19;
+        c8 += (t0 << 11) & LIMB_MASK;
+        c9 += t0 >> 17;
+        t0 = 91 * c19;
+        c9 += (t0 << 11) & LIMB_MASK;
+        c10 += t0 >> 17;
+        //carry from position 0
+        t0 = (c0 + CARRY_ADD) >> 28;
+        c0 -= (t0 << 28);
+        c1 += t0;
+        //carry from position 1
+        t0 = (c1 + CARRY_ADD) >> 28;
+        c1 -= (t0 << 28);
+        c2 += t0;
+        //carry from position 2
+        t0 = (c2 + CARRY_ADD) >> 28;
+        c2 -= (t0 << 28);
+        c3 += t0;
+        //carry from position 3
+        t0 = (c3 + CARRY_ADD) >> 28;
+        c3 -= (t0 << 28);
+        c4 += t0;
+        //carry from position 4
+        t0 = (c4 + CARRY_ADD) >> 28;
+        c4 -= (t0 << 28);
+        c5 += t0;
+        //carry from position 5
+        t0 = (c5 + CARRY_ADD) >> 28;
+        c5 -= (t0 << 28);
+        c6 += t0;
+        //carry from position 6
+        t0 = (c6 + CARRY_ADD) >> 28;
+        c6 -= (t0 << 28);
+        c7 += t0;
+        //carry from position 7
+        t0 = (c7 + CARRY_ADD) >> 28;
+        c7 -= (t0 << 28);
+        c8 += t0;
+        //carry from position 8
+        t0 = (c8 + CARRY_ADD) >> 28;
+        c8 -= (t0 << 28);
+        c9 += t0;
+        //carry from position 9
+        t0 = (c9 + CARRY_ADD) >> 28;
+        c9 -= (t0 << 28);
+        c10 += t0;
+        //carry from position 10
+        t0 = (c10 + CARRY_ADD) >> 28;
+        c10 -= (t0 << 28);
+        c11 += t0;
+        //carry from position 11
+        t0 = (c11 + CARRY_ADD) >> 28;
+        c11 -= (t0 << 28);
+        c12 += t0;
+        //carry from position 12
+        t0 = (c12 + CARRY_ADD) >> 28;
+        c12 -= (t0 << 28);
+        c13 += t0;
+        //carry from position 13
+        t0 = (c13 + CARRY_ADD) >> 28;
+        c13 -= (t0 << 28);
+        c14 += t0;
+        //carry from position 14
+        t0 = (c14 + CARRY_ADD) >> 28;
+        c14 -= (t0 << 28);
+        c15 += t0;
+        //carry from position 15
+        t0 = (c15 + CARRY_ADD) >> 28;
+        c15 -= (t0 << 28);
+        c16 += t0;
+        //carry from position 16
+        t0 = (c16 + CARRY_ADD) >> 28;
+        c16 -= (t0 << 28);
+        c17 += t0;
+        //carry from position 17
+        t0 = (c17 + CARRY_ADD) >> 28;
+        c17 -= (t0 << 28);
+        c18 += t0;
+
+        r[0] = c0;
+        r[1] = c1;
+        r[2] = c2;
+        r[3] = c3;
+        r[4] = c4;
+        r[5] = c5;
+        r[6] = c6;
+        r[7] = c7;
+        r[8] = c8;
+        r[9] = c9;
+        r[10] = c10;
+        r[11] = c11;
+        r[12] = c12;
+        r[13] = c13;
+        r[14] = c14;
+        r[15] = c15;
+        r[16] = c16;
+        r[17] = c17;
+        r[18] = c18;
+    }
+    @Override
+    protected void mult(long[] a, long[] b, long[] r) {
+        long c0 = (a[0] * b[0]);
+        long c1 = (a[0] * b[1]) + (a[1] * b[0]);
+        long c2 = (a[0] * b[2]) + (a[1] * b[1]) + (a[2] * b[0]);
+        long c3 = (a[0] * b[3]) + (a[1] * b[2]) + (a[2] * b[1]) + (a[3] * b[0]);
+        long c4 = (a[0] * b[4]) + (a[1] * b[3]) + (a[2] * b[2]) + (a[3] * b[1]) + (a[4] * b[0]);
+        long c5 = (a[0] * b[5]) + (a[1] * b[4]) + (a[2] * b[3]) + (a[3] * b[2]) + (a[4] * b[1]) + (a[5] * b[0]);
+        long c6 = (a[0] * b[6]) + (a[1] * b[5]) + (a[2] * b[4]) + (a[3] * b[3]) + (a[4] * b[2]) + (a[5] * b[1]) + (a[6] * b[0]);
+        long c7 = (a[0] * b[7]) + (a[1] * b[6]) + (a[2] * b[5]) + (a[3] * b[4]) + (a[4] * b[3]) + (a[5] * b[2]) + (a[6] * b[1]) + (a[7] * b[0]);
+        long c8 = (a[0] * b[8]) + (a[1] * b[7]) + (a[2] * b[6]) + (a[3] * b[5]) + (a[4] * b[4]) + (a[5] * b[3]) + (a[6] * b[2]) + (a[7] * b[1]) + (a[8] * b[0]);
+        long c9 = (a[0] * b[9]) + (a[1] * b[8]) + (a[2] * b[7]) + (a[3] * b[6]) + (a[4] * b[5]) + (a[5] * b[4]) + (a[6] * b[3]) + (a[7] * b[2]) + (a[8] * b[1]) + (a[9] * b[0]);
+        long c10 = (a[0] * b[10]) + (a[1] * b[9]) + (a[2] * b[8]) + (a[3] * b[7]) + (a[4] * b[6]) + (a[5] * b[5]) + (a[6] * b[4]) + (a[7] * b[3]) + (a[8] * b[2]) + (a[9] * b[1]) + (a[10] * b[0]);
+        long c11 = (a[0] * b[11]) + (a[1] * b[10]) + (a[2] * b[9]) + (a[3] * b[8]) + (a[4] * b[7]) + (a[5] * b[6]) + (a[6] * b[5]) + (a[7] * b[4]) + (a[8] * b[3]) + (a[9] * b[2]) + (a[10] * b[1]) + (a[11] * b[0]);
+        long c12 = (a[0] * b[12]) + (a[1] * b[11]) + (a[2] * b[10]) + (a[3] * b[9]) + (a[4] * b[8]) + (a[5] * b[7]) + (a[6] * b[6]) + (a[7] * b[5]) + (a[8] * b[4]) + (a[9] * b[3]) + (a[10] * b[2]) + (a[11] * b[1]) + (a[12] * b[0]);
+        long c13 = (a[0] * b[13]) + (a[1] * b[12]) + (a[2] * b[11]) + (a[3] * b[10]) + (a[4] * b[9]) + (a[5] * b[8]) + (a[6] * b[7]) + (a[7] * b[6]) + (a[8] * b[5]) + (a[9] * b[4]) + (a[10] * b[3]) + (a[11] * b[2]) + (a[12] * b[1]) + (a[13] * b[0]);
+        long c14 = (a[0] * b[14]) + (a[1] * b[13]) + (a[2] * b[12]) + (a[3] * b[11]) + (a[4] * b[10]) + (a[5] * b[9]) + (a[6] * b[8]) + (a[7] * b[7]) + (a[8] * b[6]) + (a[9] * b[5]) + (a[10] * b[4]) + (a[11] * b[3]) + (a[12] * b[2]) + (a[13] * b[1]) + (a[14] * b[0]);
+        long c15 = (a[0] * b[15]) + (a[1] * b[14]) + (a[2] * b[13]) + (a[3] * b[12]) + (a[4] * b[11]) + (a[5] * b[10]) + (a[6] * b[9]) + (a[7] * b[8]) + (a[8] * b[7]) + (a[9] * b[6]) + (a[10] * b[5]) + (a[11] * b[4]) + (a[12] * b[3]) + (a[13] * b[2]) + (a[14] * b[1]) + (a[15] * b[0]);
+        long c16 = (a[0] * b[16]) + (a[1] * b[15]) + (a[2] * b[14]) + (a[3] * b[13]) + (a[4] * b[12]) + (a[5] * b[11]) + (a[6] * b[10]) + (a[7] * b[9]) + (a[8] * b[8]) + (a[9] * b[7]) + (a[10] * b[6]) + (a[11] * b[5]) + (a[12] * b[4]) + (a[13] * b[3]) + (a[14] * b[2]) + (a[15] * b[1]) + (a[16] * b[0]);
+        long c17 = (a[0] * b[17]) + (a[1] * b[16]) + (a[2] * b[15]) + (a[3] * b[14]) + (a[4] * b[13]) + (a[5] * b[12]) + (a[6] * b[11]) + (a[7] * b[10]) + (a[8] * b[9]) + (a[9] * b[8]) + (a[10] * b[7]) + (a[11] * b[6]) + (a[12] * b[5]) + (a[13] * b[4]) + (a[14] * b[3]) + (a[15] * b[2]) + (a[16] * b[1]) + (a[17] * b[0]);
+        long c18 = (a[0] * b[18]) + (a[1] * b[17]) + (a[2] * b[16]) + (a[3] * b[15]) + (a[4] * b[14]) + (a[5] * b[13]) + (a[6] * b[12]) + (a[7] * b[11]) + (a[8] * b[10]) + (a[9] * b[9]) + (a[10] * b[8]) + (a[11] * b[7]) + (a[12] * b[6]) + (a[13] * b[5]) + (a[14] * b[4]) + (a[15] * b[3]) + (a[16] * b[2]) + (a[17] * b[1]) + (a[18] * b[0]);
+        long c19 = (a[1] * b[18]) + (a[2] * b[17]) + (a[3] * b[16]) + (a[4] * b[15]) + (a[5] * b[14]) + (a[6] * b[13]) + (a[7] * b[12]) + (a[8] * b[11]) + (a[9] * b[10]) + (a[10] * b[9]) + (a[11] * b[8]) + (a[12] * b[7]) + (a[13] * b[6]) + (a[14] * b[5]) + (a[15] * b[4]) + (a[16] * b[3]) + (a[17] * b[2]) + (a[18] * b[1]);
+        long c20 = (a[2] * b[18]) + (a[3] * b[17]) + (a[4] * b[16]) + (a[5] * b[15]) + (a[6] * b[14]) + (a[7] * b[13]) + (a[8] * b[12]) + (a[9] * b[11]) + (a[10] * b[10]) + (a[11] * b[9]) + (a[12] * b[8]) + (a[13] * b[7]) + (a[14] * b[6]) + (a[15] * b[5]) + (a[16] * b[4]) + (a[17] * b[3]) + (a[18] * b[2]);
+        long c21 = (a[3] * b[18]) + (a[4] * b[17]) + (a[5] * b[16]) + (a[6] * b[15]) + (a[7] * b[14]) + (a[8] * b[13]) + (a[9] * b[12]) + (a[10] * b[11]) + (a[11] * b[10]) + (a[12] * b[9]) + (a[13] * b[8]) + (a[14] * b[7]) + (a[15] * b[6]) + (a[16] * b[5]) + (a[17] * b[4]) + (a[18] * b[3]);
+        long c22 = (a[4] * b[18]) + (a[5] * b[17]) + (a[6] * b[16]) + (a[7] * b[15]) + (a[8] * b[14]) + (a[9] * b[13]) + (a[10] * b[12]) + (a[11] * b[11]) + (a[12] * b[10]) + (a[13] * b[9]) + (a[14] * b[8]) + (a[15] * b[7]) + (a[16] * b[6]) + (a[17] * b[5]) + (a[18] * b[4]);
+        long c23 = (a[5] * b[18]) + (a[6] * b[17]) + (a[7] * b[16]) + (a[8] * b[15]) + (a[9] * b[14]) + (a[10] * b[13]) + (a[11] * b[12]) + (a[12] * b[11]) + (a[13] * b[10]) + (a[14] * b[9]) + (a[15] * b[8]) + (a[16] * b[7]) + (a[17] * b[6]) + (a[18] * b[5]);
+        long c24 = (a[6] * b[18]) + (a[7] * b[17]) + (a[8] * b[16]) + (a[9] * b[15]) + (a[10] * b[14]) + (a[11] * b[13]) + (a[12] * b[12]) + (a[13] * b[11]) + (a[14] * b[10]) + (a[15] * b[9]) + (a[16] * b[8]) + (a[17] * b[7]) + (a[18] * b[6]);
+        long c25 = (a[7] * b[18]) + (a[8] * b[17]) + (a[9] * b[16]) + (a[10] * b[15]) + (a[11] * b[14]) + (a[12] * b[13]) + (a[13] * b[12]) + (a[14] * b[11]) + (a[15] * b[10]) + (a[16] * b[9]) + (a[17] * b[8]) + (a[18] * b[7]);
+        long c26 = (a[8] * b[18]) + (a[9] * b[17]) + (a[10] * b[16]) + (a[11] * b[15]) + (a[12] * b[14]) + (a[13] * b[13]) + (a[14] * b[12]) + (a[15] * b[11]) + (a[16] * b[10]) + (a[17] * b[9]) + (a[18] * b[8]);
+        long c27 = (a[9] * b[18]) + (a[10] * b[17]) + (a[11] * b[16]) + (a[12] * b[15]) + (a[13] * b[14]) + (a[14] * b[13]) + (a[15] * b[12]) + (a[16] * b[11]) + (a[17] * b[10]) + (a[18] * b[9]);
+        long c28 = (a[10] * b[18]) + (a[11] * b[17]) + (a[12] * b[16]) + (a[13] * b[15]) + (a[14] * b[14]) + (a[15] * b[13]) + (a[16] * b[12]) + (a[17] * b[11]) + (a[18] * b[10]);
+        long c29 = (a[11] * b[18]) + (a[12] * b[17]) + (a[13] * b[16]) + (a[14] * b[15]) + (a[15] * b[14]) + (a[16] * b[13]) + (a[17] * b[12]) + (a[18] * b[11]);
+        long c30 = (a[12] * b[18]) + (a[13] * b[17]) + (a[14] * b[16]) + (a[15] * b[15]) + (a[16] * b[14]) + (a[17] * b[13]) + (a[18] * b[12]);
+        long c31 = (a[13] * b[18]) + (a[14] * b[17]) + (a[15] * b[16]) + (a[16] * b[15]) + (a[17] * b[14]) + (a[18] * b[13]);
+        long c32 = (a[14] * b[18]) + (a[15] * b[17]) + (a[16] * b[16]) + (a[17] * b[15]) + (a[18] * b[14]);
+        long c33 = (a[15] * b[18]) + (a[16] * b[17]) + (a[17] * b[16]) + (a[18] * b[15]);
+        long c34 = (a[16] * b[18]) + (a[17] * b[17]) + (a[18] * b[16]);
+        long c35 = (a[17] * b[18]) + (a[18] * b[17]);
+        long c36 = (a[18] * b[18]);
+
+        carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c36);
+    }
+    @Override
+    protected void reduce(long[] a) {
+        carryReduce(a, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], a[16], a[17], a[18]);
+    }
+    @Override
+    protected void square(long[] a, long[] r) {
+        long c0 = (a[0] * a[0]);
+        long c1 = 2 * ((a[0] * a[1]));
+        long c2 = 2 * ((a[0] * a[2])) + (a[1] * a[1]);
+        long c3 = 2 * ((a[0] * a[3]) + (a[1] * a[2]));
+        long c4 = 2 * ((a[0] * a[4]) + (a[1] * a[3])) + (a[2] * a[2]);
+        long c5 = 2 * ((a[0] * a[5]) + (a[1] * a[4]) + (a[2] * a[3]));
+        long c6 = 2 * ((a[0] * a[6]) + (a[1] * a[5]) + (a[2] * a[4])) + (a[3] * a[3]);
+        long c7 = 2 * ((a[0] * a[7]) + (a[1] * a[6]) + (a[2] * a[5]) + (a[3] * a[4]));
+        long c8 = 2 * ((a[0] * a[8]) + (a[1] * a[7]) + (a[2] * a[6]) + (a[3] * a[5])) + (a[4] * a[4]);
+        long c9 = 2 * ((a[0] * a[9]) + (a[1] * a[8]) + (a[2] * a[7]) + (a[3] * a[6]) + (a[4] * a[5]));
+        long c10 = 2 * ((a[0] * a[10]) + (a[1] * a[9]) + (a[2] * a[8]) + (a[3] * a[7]) + (a[4] * a[6])) + (a[5] * a[5]);
+        long c11 = 2 * ((a[0] * a[11]) + (a[1] * a[10]) + (a[2] * a[9]) + (a[3] * a[8]) + (a[4] * a[7]) + (a[5] * a[6]));
+        long c12 = 2 * ((a[0] * a[12]) + (a[1] * a[11]) + (a[2] * a[10]) + (a[3] * a[9]) + (a[4] * a[8]) + (a[5] * a[7])) + (a[6] * a[6]);
+        long c13 = 2 * ((a[0] * a[13]) + (a[1] * a[12]) + (a[2] * a[11]) + (a[3] * a[10]) + (a[4] * a[9]) + (a[5] * a[8]) + (a[6] * a[7]));
+        long c14 = 2 * ((a[0] * a[14]) + (a[1] * a[13]) + (a[2] * a[12]) + (a[3] * a[11]) + (a[4] * a[10]) + (a[5] * a[9]) + (a[6] * a[8])) + (a[7] * a[7]);
+        long c15 = 2 * ((a[0] * a[15]) + (a[1] * a[14]) + (a[2] * a[13]) + (a[3] * a[12]) + (a[4] * a[11]) + (a[5] * a[10]) + (a[6] * a[9]) + (a[7] * a[8]));
+        long c16 = 2 * ((a[0] * a[16]) + (a[1] * a[15]) + (a[2] * a[14]) + (a[3] * a[13]) + (a[4] * a[12]) + (a[5] * a[11]) + (a[6] * a[10]) + (a[7] * a[9])) + (a[8] * a[8]);
+        long c17 = 2 * ((a[0] * a[17]) + (a[1] * a[16]) + (a[2] * a[15]) + (a[3] * a[14]) + (a[4] * a[13]) + (a[5] * a[12]) + (a[6] * a[11]) + (a[7] * a[10]) + (a[8] * a[9]));
+        long c18 = 2 * ((a[0] * a[18]) + (a[1] * a[17]) + (a[2] * a[16]) + (a[3] * a[15]) + (a[4] * a[14]) + (a[5] * a[13]) + (a[6] * a[12]) + (a[7] * a[11]) + (a[8] * a[10])) + (a[9] * a[9]);
+        long c19 = 2 * ((a[1] * a[18]) + (a[2] * a[17]) + (a[3] * a[16]) + (a[4] * a[15]) + (a[5] * a[14]) + (a[6] * a[13]) + (a[7] * a[12]) + (a[8] * a[11]) + (a[9] * a[10]));
+        long c20 = 2 * ((a[2] * a[18]) + (a[3] * a[17]) + (a[4] * a[16]) + (a[5] * a[15]) + (a[6] * a[14]) + (a[7] * a[13]) + (a[8] * a[12]) + (a[9] * a[11])) + (a[10] * a[10]);
+        long c21 = 2 * ((a[3] * a[18]) + (a[4] * a[17]) + (a[5] * a[16]) + (a[6] * a[15]) + (a[7] * a[14]) + (a[8] * a[13]) + (a[9] * a[12]) + (a[10] * a[11]));
+        long c22 = 2 * ((a[4] * a[18]) + (a[5] * a[17]) + (a[6] * a[16]) + (a[7] * a[15]) + (a[8] * a[14]) + (a[9] * a[13]) + (a[10] * a[12])) + (a[11] * a[11]);
+        long c23 = 2 * ((a[5] * a[18]) + (a[6] * a[17]) + (a[7] * a[16]) + (a[8] * a[15]) + (a[9] * a[14]) + (a[10] * a[13]) + (a[11] * a[12]));
+        long c24 = 2 * ((a[6] * a[18]) + (a[7] * a[17]) + (a[8] * a[16]) + (a[9] * a[15]) + (a[10] * a[14]) + (a[11] * a[13])) + (a[12] * a[12]);
+        long c25 = 2 * ((a[7] * a[18]) + (a[8] * a[17]) + (a[9] * a[16]) + (a[10] * a[15]) + (a[11] * a[14]) + (a[12] * a[13]));
+        long c26 = 2 * ((a[8] * a[18]) + (a[9] * a[17]) + (a[10] * a[16]) + (a[11] * a[15]) + (a[12] * a[14])) + (a[13] * a[13]);
+        long c27 = 2 * ((a[9] * a[18]) + (a[10] * a[17]) + (a[11] * a[16]) + (a[12] * a[15]) + (a[13] * a[14]));
+        long c28 = 2 * ((a[10] * a[18]) + (a[11] * a[17]) + (a[12] * a[16]) + (a[13] * a[15])) + (a[14] * a[14]);
+        long c29 = 2 * ((a[11] * a[18]) + (a[12] * a[17]) + (a[13] * a[16]) + (a[14] * a[15]));
+        long c30 = 2 * ((a[12] * a[18]) + (a[13] * a[17]) + (a[14] * a[16])) + (a[15] * a[15]);
+        long c31 = 2 * ((a[13] * a[18]) + (a[14] * a[17]) + (a[15] * a[16]));
+        long c32 = 2 * ((a[14] * a[18]) + (a[15] * a[17])) + (a[16] * a[16]);
+        long c33 = 2 * ((a[15] * a[18]) + (a[16] * a[17]));
+        long c34 = 2 * ((a[16] * a[18])) + (a[17] * a[17]);
+        long c35 = 2 * ((a[17] * a[18]));
+        long c36 = (a[18] * a[18]);
+
+        carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c36);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/math/intpoly/header.txt	Sat Jul 13 16:49:00 2019 +0100
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is generated by FieldGen.jsh. Do not modify it directly.
+ */
--- a/test/sun/security/util/math/BigIntegerModuloP.java	Sat Jul 13 15:17:33 2019 +0100
+++ b/test/sun/security/util/math/BigIntegerModuloP.java	Sat Jul 13 16:49:00 2019 +0100
@@ -27,6 +27,7 @@
 
 import java.math.BigInteger;
 import java.nio.ByteBuffer;
+import java.util.Arrays;
 
 /**
  * Arithmetic in the field of integers modulo a prime value implemented using
@@ -175,6 +176,13 @@
         }
 
         @Override
+        public void conditionalSet(IntegerModuloP b, int set) {
+            if (set == 1) {
+                v = b.asBigInteger();
+            }
+        }
+
+        @Override
         public void conditionalSwapWith(MutableIntegerModuloP b, int swap) {
             if (swap == 1) {
                 BigInteger temp = v;
@@ -248,6 +256,18 @@
             return this;
         }
 
+        @Override
+        public MutableElement setAdditiveInverse() {
+            v = BigInteger.ZERO.subtract(v);
+            return this;
+        }
+
+        @Override
+        public MutableElement setReduced() {
+            // do nothing
+            return this;
+        }
+
     }
 
     private class SmallElement extends ImmutableElement implements SmallValue {
--- a/test/sun/security/util/math/TestIntegerModuloP.java	Sat Jul 13 15:17:33 2019 +0100
+++ b/test/sun/security/util/math/TestIntegerModuloP.java	Sat Jul 13 16:49:00 2019 +0100
@@ -23,15 +23,22 @@
 
 /*
  * @test
- * @bug 8181594
+ * @bug 8181594 8208648
  * @summary Test proper operation of integer field arithmetic
  * @build BigIntegerModuloP
  * @run main TestIntegerModuloP sun.security.util.math.intpoly.IntegerPolynomial25519 32 0
  * @run main TestIntegerModuloP sun.security.util.math.intpoly.IntegerPolynomial448 56 1
  * @run main TestIntegerModuloP sun.security.util.math.intpoly.IntegerPolynomial1305 16 2
+ * @run main TestIntegerModuloP sun.security.util.math.intpoly.IntegerPolynomialP256 32 5
+ * @run main TestIntegerModuloP sun.security.util.math.intpoly.IntegerPolynomialP384 48 6
+ * @run main TestIntegerModuloP sun.security.util.math.intpoly.IntegerPolynomialP521 66 7
+ * @run main TestIntegerModuloP sun.security.util.math.intpoly.P256OrderField 32 8
+ * @run main TestIntegerModuloP sun.security.util.math.intpoly.P384OrderField 48 9
+ * @run main TestIntegerModuloP sun.security.util.math.intpoly.P521OrderField 66 10
  */
 
 import sun.security.util.math.*;
+import sun.security.util.math.intpoly.*;
 
 import java.util.*;
 import java.math.*;
@@ -186,11 +193,9 @@
         } catch (Exception ex) {
             throw new RuntimeException(ex);
         }
-
         System.out.println("All tests passed");
     }
 
-
     static void assertEqual(IntegerModuloP e1, IntegerModuloP e2) {
 
         if (!e1.asBigInteger().equals(e2.asBigInteger())) {
@@ -363,6 +368,17 @@
             TestPair<IntegerModuloP> result2 =
                 applyAndCheck(addFunc2, left, right);
 
+            if (elem.test.getField() instanceof IntegerPolynomial) {
+                IntegerPolynomial field =
+                    (IntegerPolynomial) elem.test.getField();
+                int numAdds = field.getMaxAdds();
+                for (int j = 1; j < numAdds; j++) {
+                    ElemFunction addFunc3 = ADD_FUNCTIONS.
+                        get(random.nextInt(ADD_FUNCTIONS.size()));
+                    result2 = applyAndCheck(addFunc3, left, right);
+                }
+            }
+
             ElemFunction multFunc2 =
                 MULT_FUNCTIONS.get(random.nextInt(MULT_FUNCTIONS.size()));
             TestPair<MutableIntegerModuloP> multResult =