blob: 4824b78ed614e69dec7aff06f7a8778e37030c2b [file] [log] [blame]
/*
* 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);