diff options
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java')
-rw-r--r-- | bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java | 871 |
1 files changed, 217 insertions, 654 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java index 87608eb..5943882 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java @@ -3,6 +3,8 @@ package org.bouncycastle.math.ec; import java.math.BigInteger; import java.util.Random; +import org.bouncycastle.math.raw.Mod; +import org.bouncycastle.math.raw.Nat; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.BigIntegers; @@ -27,11 +29,36 @@ public abstract class ECFieldElement return toBigInteger().bitLength(); } + public boolean isOne() + { + return bitLength() == 1; + } + public boolean isZero() { return 0 == toBigInteger().signum(); } + public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + return multiply(b).subtract(x.multiply(y)); + } + + public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + return multiply(b).add(x.multiply(y)); + } + + public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y) + { + return square().subtract(x.multiply(y)); + } + + public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y) + { + return square().add(x.multiply(y)); + } + public boolean testBitZero() { return toBigInteger().testBit(0); @@ -51,42 +78,10 @@ public abstract class ECFieldElement { BigInteger q, r, x; -// static int[] calculateNaf(BigInteger p) -// { -// int[] naf = WNafUtil.generateCompactNaf(p); -// -// int bit = 0; -// for (int i = 0; i < naf.length; ++i) -// { -// int ni = naf[i]; -// int digit = ni >> 16, zeroes = ni & 0xFFFF; -// -// bit += zeroes; -// naf[i] = digit < 0 ? ~bit : bit; -// ++bit; -// } -// -// int last = naf.length - 1; -// if (last > 0 && last <= 16) -// { -// int top = naf[last], top2 = naf[last - 1]; -// if (top2 < 0) -// { -// top2 = ~top2; -// } -// if (top - top2 >= 64) -// { -// return naf; -// } -// } -// -// return null; -// } - static BigInteger calculateResidue(BigInteger p) { int bitLength = p.bitLength(); - if (bitLength > 128) + if (bitLength >= 96) { BigInteger firstWord = p.shiftRight(bitLength - 64); if (firstWord.longValue() == -1L) @@ -159,13 +154,7 @@ public abstract class ECFieldElement public ECFieldElement subtract(ECFieldElement b) { - BigInteger x2 = b.toBigInteger(); - BigInteger x3 = x.subtract(x2); - if (x3.signum() < 0) - { - x3 = x3.add(q); - } - return new Fp(q, r, x3); + return new Fp(q, r, modSubtract(x, b.toBigInteger())); } public ECFieldElement multiply(ECFieldElement b) @@ -173,27 +162,30 @@ public abstract class ECFieldElement return new Fp(q, r, modMult(x, b.toBigInteger())); } + public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + BigInteger ax = this.x, bx = b.toBigInteger(), xx = x.toBigInteger(), yx = y.toBigInteger(); + BigInteger ab = ax.multiply(bx); + BigInteger xy = xx.multiply(yx); + return new Fp(q, r, modReduce(ab.subtract(xy))); + } + + public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + BigInteger ax = this.x, bx = b.toBigInteger(), xx = x.toBigInteger(), yx = y.toBigInteger(); + BigInteger ab = ax.multiply(bx); + BigInteger xy = xx.multiply(yx); + return new Fp(q, r, modReduce(ab.add(xy))); + } + public ECFieldElement divide(ECFieldElement b) { - return new Fp(q, modMult(x, b.toBigInteger().modInverse(q))); + return new Fp(q, r, modMult(x, modInverse(b.toBigInteger()))); } public ECFieldElement negate() { - BigInteger x2; - if (x.signum() == 0) - { - x2 = x; - } - else if (ONE.equals(r)) - { - x2 = q.xor(x); - } - else - { - x2 = q.subtract(x); - } - return new Fp(q, r, x2); + return x.signum() == 0 ? this : new Fp(q, r, q.subtract(x)); } public ECFieldElement square() @@ -201,10 +193,26 @@ public abstract class ECFieldElement return new Fp(q, r, modMult(x, x)); } + public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y) + { + BigInteger ax = this.x, xx = x.toBigInteger(), yx = y.toBigInteger(); + BigInteger aa = ax.multiply(ax); + BigInteger xy = xx.multiply(yx); + return new Fp(q, r, modReduce(aa.subtract(xy))); + } + + public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y) + { + BigInteger ax = this.x, xx = x.toBigInteger(), yx = y.toBigInteger(); + BigInteger aa = ax.multiply(ax); + BigInteger xy = xx.multiply(yx); + return new Fp(q, r, modReduce(aa.add(xy))); + } + public ECFieldElement invert() { // TODO Modular inversion can be faster for a (Generalized) Mersenne Prime. - return new Fp(q, r, x.modInverse(q)); + return new Fp(q, r, modInverse(x)); } // D.1.4 91 @@ -214,6 +222,11 @@ public abstract class ECFieldElement */ public ECFieldElement sqrt() { + if (this.isZero() || this.isOne()) // earlier JDK compatibility + { + return this; + } + if (!q.testBit(0)) { throw new RuntimeException("not done yet"); @@ -221,29 +234,44 @@ public abstract class ECFieldElement // note: even though this class implements ECConstants don't be tempted to // remove the explicit declaration, some J2ME environments don't cope. - // p mod 4 == 3 - if (q.testBit(1)) + + if (q.testBit(1)) // q == 4m + 3 + { + BigInteger e = q.shiftRight(2).add(ECConstants.ONE); + return checkSqrt(new Fp(q, r, x.modPow(e, q))); + } + + if (q.testBit(2)) // q == 8m + 5 { - // z = g^(u+1) + p, p = 4u + 3 - ECFieldElement z = new Fp(q, r, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q)); + BigInteger t1 = x.modPow(q.shiftRight(3), q); + BigInteger t2 = modMult(t1, x); + BigInteger t3 = modMult(t2, t1); + + if (t3.equals(ECConstants.ONE)) + { + return checkSqrt(new Fp(q, r, t2)); + } + + // TODO This is constant and could be precomputed + BigInteger t4 = ECConstants.TWO.modPow(q.shiftRight(2), q); - return z.square().equals(this) ? z : null; + BigInteger y = modMult(t2, t4); + + return checkSqrt(new Fp(q, r, y)); } - // p mod 4 == 1 - BigInteger qMinusOne = q.subtract(ECConstants.ONE); + // q == 8m + 1 - BigInteger legendreExponent = qMinusOne.shiftRight(1); + BigInteger legendreExponent = q.shiftRight(1); if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE))) { return null; } - BigInteger u = qMinusOne.shiftRight(2); - BigInteger k = u.shiftLeft(1).add(ECConstants.ONE); + BigInteger X = this.x; + BigInteger fourX = modDouble(modDouble(X)); - BigInteger Q = this.x; - BigInteger fourQ = modDouble(modDouble(Q)); + BigInteger k = legendreExponent.add(ECConstants.ONE), qMinusOne = q.subtract(ECConstants.ONE); BigInteger U, V; Random rand = new Random(); @@ -255,94 +283,39 @@ public abstract class ECFieldElement P = new BigInteger(q.bitLength(), rand); } while (P.compareTo(q) >= 0 - || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, q).equals(qMinusOne))); + || !modReduce(P.multiply(P).subtract(fourX)).modPow(legendreExponent, q).equals(qMinusOne)); - BigInteger[] result = lucasSequence(P, Q, k); + BigInteger[] result = lucasSequence(P, X, k); U = result[0]; V = result[1]; - if (modMult(V, V).equals(fourQ)) + if (modMult(V, V).equals(fourX)) { - // Integer division by 2, mod q - if (V.testBit(0)) - { - V = V.add(q); - } - - V = V.shiftRight(1); - - //assert V.multiply(V).mod(q).equals(x); - - return new ECFieldElement.Fp(q, r, V); + return new ECFieldElement.Fp(q, r, modHalfAbs(V)); } } while (U.equals(ECConstants.ONE) || U.equals(qMinusOne)); return null; - -// BigInteger qMinusOne = q.subtract(ECConstants.ONE); -// BigInteger legendreExponent = qMinusOne.shiftRight(1); //divide(ECConstants.TWO); -// if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE))) -// { -// return null; -// } -// -// Random rand = new Random(); -// BigInteger fourX = x.shiftLeft(2); -// -// BigInteger r; -// do -// { -// r = new BigInteger(q.bitLength(), rand); -// } -// while (r.compareTo(q) >= 0 -// || !(r.multiply(r).subtract(fourX).modPow(legendreExponent, q).equals(qMinusOne))); -// -// BigInteger n1 = qMinusOne.shiftRight(2); //.divide(ECConstants.FOUR); -// BigInteger n2 = n1.add(ECConstants.ONE); //q.add(ECConstants.THREE).divide(ECConstants.FOUR); -// -// BigInteger wOne = WOne(r, x, q); -// BigInteger wSum = W(n1, wOne, q).add(W(n2, wOne, q)).mod(q); -// BigInteger twoR = r.shiftLeft(1); //ECConstants.TWO.multiply(r); -// -// BigInteger root = twoR.modPow(q.subtract(ECConstants.TWO), q) -// .multiply(x).mod(q) -// .multiply(wSum).mod(q); -// -// return new Fp(q, root); } -// private static BigInteger W(BigInteger n, BigInteger wOne, BigInteger p) -// { -// if (n.equals(ECConstants.ONE)) -// { -// return wOne; -// } -// boolean isEven = !n.testBit(0); -// n = n.shiftRight(1);//divide(ECConstants.TWO); -// if (isEven) -// { -// BigInteger w = W(n, wOne, p); -// return w.multiply(w).subtract(ECConstants.TWO).mod(p); -// } -// BigInteger w1 = W(n.add(ECConstants.ONE), wOne, p); -// BigInteger w2 = W(n, wOne, p); -// return w1.multiply(w2).subtract(wOne).mod(p); -// } -// -// private BigInteger WOne(BigInteger r, BigInteger x, BigInteger p) -// { -// return r.multiply(r).multiply(x.modPow(q.subtract(ECConstants.TWO), q)).subtract(ECConstants.TWO).mod(p); -// } + private ECFieldElement checkSqrt(ECFieldElement z) + { + return z.square().equals(this) ? z : null; + } private BigInteger[] lucasSequence( BigInteger P, BigInteger Q, BigInteger k) { + // TODO Research and apply "common-multiplicand multiplication here" + int n = k.bitLength(); int s = k.getLowestSetBit(); + // assert k.testBit(s); + BigInteger Uh = ECConstants.ONE; BigInteger Vl = ECConstants.TWO; BigInteger Vh = P; @@ -405,6 +378,35 @@ public abstract class ECFieldElement return _2x; } + protected BigInteger modHalf(BigInteger x) + { + if (x.testBit(0)) + { + x = q.add(x); + } + return x.shiftRight(1); + } + + protected BigInteger modHalfAbs(BigInteger x) + { + if (x.testBit(0)) + { + x = q.subtract(x); + } + return x.shiftRight(1); + } + + protected BigInteger modInverse(BigInteger x) + { + int bits = getFieldSize(); + int len = (bits + 31) >> 5; + int[] p = Nat.fromBigInteger(bits, q); + int[] n = Nat.fromBigInteger(bits, x); + int[] z = Nat.create(len); + Mod.invert(p, n, z); + return Nat.toBigInteger(len, z); + } + protected BigInteger modMult(BigInteger x1, BigInteger x2) { return modReduce(x1.multiply(x2)); @@ -412,44 +414,20 @@ public abstract class ECFieldElement protected BigInteger modReduce(BigInteger x) { -// if (naf != null) -// { -// int last = naf.length - 1; -// int bits = naf[last]; -// while (x.bitLength() > (bits + 1)) -// { -// BigInteger u = x.shiftRight(bits); -// BigInteger v = x.subtract(u.shiftLeft(bits)); -// -// x = v; -// -// for (int i = 0; i < last; ++i) -// { -// int ni = naf[i]; -// if (ni < 0) -// { -// x = x.add(u.shiftLeft(~ni)); -// } -// else -// { -// x = x.subtract(u.shiftLeft(ni)); -// } -// } -// } -// while (x.compareTo(q) >= 0) -// { -// x = x.subtract(q); -// } -// } -// else if (r != null) { + boolean negative = x.signum() < 0; + if (negative) + { + x = x.abs(); + } int qLen = q.bitLength(); + boolean rIsOne = r.equals(ECConstants.ONE); while (x.bitLength() > (qLen + 1)) { BigInteger u = x.shiftRight(qLen); BigInteger v = x.subtract(u.shiftLeft(qLen)); - if (!r.equals(ONE)) + if (!rIsOne) { u = u.multiply(r); } @@ -459,6 +437,10 @@ public abstract class ECFieldElement { x = x.subtract(q); } + if (negative && x.signum() != 0) + { + x = q.subtract(x); + } } else { @@ -467,6 +449,16 @@ public abstract class ECFieldElement return x; } + protected BigInteger modSubtract(BigInteger x1, BigInteger x2) + { + BigInteger x3 = x1.subtract(x2); + if (x3.signum() < 0) + { + x3 = x3.add(q); + } + return x3; + } + public boolean equals(Object other) { if (other == this) @@ -489,467 +481,6 @@ public abstract class ECFieldElement } } -// /** -// * Class representing the Elements of the finite field -// * <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB) -// * representation. Both trinomial (TPB) and pentanomial (PPB) polynomial -// * basis representations are supported. Gaussian normal basis (GNB) -// * representation is not supported. -// */ -// public static class F2m extends ECFieldElement -// { -// BigInteger x; -// -// /** -// * Indicates gaussian normal basis representation (GNB). Number chosen -// * according to X9.62. GNB is not implemented at present. -// */ -// public static final int GNB = 1; -// -// /** -// * Indicates trinomial basis representation (TPB). Number chosen -// * according to X9.62. -// */ -// public static final int TPB = 2; -// -// /** -// * Indicates pentanomial basis representation (PPB). Number chosen -// * according to X9.62. -// */ -// public static final int PPB = 3; -// -// /** -// * TPB or PPB. -// */ -// private int representation; -// -// /** -// * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>. -// */ -// private int m; -// -// /** -// * TPB: The integer <code>k</code> where <code>x<sup>m</sup> + -// * x<sup>k</sup> + 1</code> represents the reduction polynomial -// * <code>f(z)</code>.<br> -// * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> + -// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> -// * represents the reduction polynomial <code>f(z)</code>.<br> -// */ -// private int k1; -// -// /** -// * TPB: Always set to <code>0</code><br> -// * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> + -// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> -// * represents the reduction polynomial <code>f(z)</code>.<br> -// */ -// private int k2; -// -// /** -// * TPB: Always set to <code>0</code><br> -// * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> + -// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> -// * represents the reduction polynomial <code>f(z)</code>.<br> -// */ -// private int k3; -// -// /** -// * Constructor for PPB. -// * @param m The exponent <code>m</code> of -// * <code>F<sub>2<sup>m</sup></sub></code>. -// * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> + -// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> -// * represents the reduction polynomial <code>f(z)</code>. -// * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> + -// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> -// * represents the reduction polynomial <code>f(z)</code>. -// * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> + -// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> -// * represents the reduction polynomial <code>f(z)</code>. -// * @param x The BigInteger representing the value of the field element. -// */ -// public F2m( -// int m, -// int k1, -// int k2, -// int k3, -// BigInteger x) -// { -//// super(x); -// this.x = x; -// -// if ((k2 == 0) && (k3 == 0)) -// { -// this.representation = TPB; -// } -// else -// { -// if (k2 >= k3) -// { -// throw new IllegalArgumentException( -// "k2 must be smaller than k3"); -// } -// if (k2 <= 0) -// { -// throw new IllegalArgumentException( -// "k2 must be larger than 0"); -// } -// this.representation = PPB; -// } -// -// if (x.signum() < 0) -// { -// throw new IllegalArgumentException("x value cannot be negative"); -// } -// -// this.m = m; -// this.k1 = k1; -// this.k2 = k2; -// this.k3 = k3; -// } -// -// /** -// * Constructor for TPB. -// * @param m The exponent <code>m</code> of -// * <code>F<sub>2<sup>m</sup></sub></code>. -// * @param k The integer <code>k</code> where <code>x<sup>m</sup> + -// * x<sup>k</sup> + 1</code> represents the reduction -// * polynomial <code>f(z)</code>. -// * @param x The BigInteger representing the value of the field element. -// */ -// public F2m(int m, int k, BigInteger x) -// { -// // Set k1 to k, and set k2 and k3 to 0 -// this(m, k, 0, 0, x); -// } -// -// public BigInteger toBigInteger() -// { -// return x; -// } -// -// public String getFieldName() -// { -// return "F2m"; -// } -// -// public int getFieldSize() -// { -// return m; -// } -// -// /** -// * Checks, if the ECFieldElements <code>a</code> and <code>b</code> -// * are elements of the same field <code>F<sub>2<sup>m</sup></sub></code> -// * (having the same representation). -// * @param a field element. -// * @param b field element to be compared. -// * @throws IllegalArgumentException if <code>a</code> and <code>b</code> -// * are not elements of the same field -// * <code>F<sub>2<sup>m</sup></sub></code> (having the same -// * representation). -// */ -// public static void checkFieldElements( -// ECFieldElement a, -// ECFieldElement b) -// { -// if ((!(a instanceof F2m)) || (!(b instanceof F2m))) -// { -// throw new IllegalArgumentException("Field elements are not " -// + "both instances of ECFieldElement.F2m"); -// } -// -// if ((a.toBigInteger().signum() < 0) || (b.toBigInteger().signum() < 0)) -// { -// throw new IllegalArgumentException( -// "x value may not be negative"); -// } -// -// ECFieldElement.F2m aF2m = (ECFieldElement.F2m)a; -// ECFieldElement.F2m bF2m = (ECFieldElement.F2m)b; -// -// if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1) -// || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3)) -// { -// throw new IllegalArgumentException("Field elements are not " -// + "elements of the same field F2m"); -// } -// -// if (aF2m.representation != bF2m.representation) -// { -// // Should never occur -// throw new IllegalArgumentException( -// "One of the field " -// + "elements are not elements has incorrect representation"); -// } -// } -// -// /** -// * Computes <code>z * a(z) mod f(z)</code>, where <code>f(z)</code> is -// * the reduction polynomial of <code>this</code>. -// * @param a The polynomial <code>a(z)</code> to be multiplied by -// * <code>z mod f(z)</code>. -// * @return <code>z * a(z) mod f(z)</code> -// */ -// private BigInteger multZModF(final BigInteger a) -// { -// // Left-shift of a(z) -// BigInteger az = a.shiftLeft(1); -// if (az.testBit(this.m)) -// { -// // If the coefficient of z^m in a(z) equals 1, reduction -// // modulo f(z) is performed: Add f(z) to to a(z): -// // Step 1: Unset mth coeffient of a(z) -// az = az.clearBit(this.m); -// -// // Step 2: Add r(z) to a(z), where r(z) is defined as -// // f(z) = z^m + r(z), and k1, k2, k3 are the positions of -// // the non-zero coefficients in r(z) -// az = az.flipBit(0); -// az = az.flipBit(this.k1); -// if (this.representation == PPB) -// { -// az = az.flipBit(this.k2); -// az = az.flipBit(this.k3); -// } -// } -// return az; -// } -// -// public ECFieldElement add(final ECFieldElement b) -// { -// // No check performed here for performance reasons. Instead the -// // elements involved are checked in ECPoint.F2m -// // checkFieldElements(this, b); -// if (b.toBigInteger().signum() == 0) -// { -// return this; -// } -// -// return new F2m(this.m, this.k1, this.k2, this.k3, this.x.xor(b.toBigInteger())); -// } -// -// public ECFieldElement subtract(final ECFieldElement b) -// { -// // Addition and subtraction are the same in F2m -// return add(b); -// } -// -// -// public ECFieldElement multiply(final ECFieldElement b) -// { -// // Left-to-right shift-and-add field multiplication in F2m -// // Input: Binary polynomials a(z) and b(z) of degree at most m-1 -// // Output: c(z) = a(z) * b(z) mod f(z) -// -// // No check performed here for performance reasons. Instead the -// // elements involved are checked in ECPoint.F2m -// // checkFieldElements(this, b); -// final BigInteger az = this.x; -// BigInteger bz = b.toBigInteger(); -// BigInteger cz; -// -// // Compute c(z) = a(z) * b(z) mod f(z) -// if (az.testBit(0)) -// { -// cz = bz; -// } -// else -// { -// cz = ECConstants.ZERO; -// } -// -// for (int i = 1; i < this.m; i++) -// { -// // b(z) := z * b(z) mod f(z) -// bz = multZModF(bz); -// -// if (az.testBit(i)) -// { -// // If the coefficient of x^i in a(z) equals 1, b(z) is added -// // to c(z) -// cz = cz.xor(bz); -// } -// } -// return new ECFieldElement.F2m(m, this.k1, this.k2, this.k3, cz); -// } -// -// -// public ECFieldElement divide(final ECFieldElement b) -// { -// // There may be more efficient implementations -// ECFieldElement bInv = b.invert(); -// return multiply(bInv); -// } -// -// public ECFieldElement negate() -// { -// // -x == x holds for all x in F2m -// return this; -// } -// -// public ECFieldElement square() -// { -// // Naive implementation, can probably be speeded up using modular -// // reduction -// return multiply(this); -// } -// -// public ECFieldElement invert() -// { -// // Inversion in F2m using the extended Euclidean algorithm -// // Input: A nonzero polynomial a(z) of degree at most m-1 -// // Output: a(z)^(-1) mod f(z) -// -// // u(z) := a(z) -// BigInteger uz = this.x; -// if (uz.signum() <= 0) -// { -// throw new ArithmeticException("x is zero or negative, " + -// "inversion is impossible"); -// } -// -// // v(z) := f(z) -// BigInteger vz = ECConstants.ZERO.setBit(m); -// vz = vz.setBit(0); -// vz = vz.setBit(this.k1); -// if (this.representation == PPB) -// { -// vz = vz.setBit(this.k2); -// vz = vz.setBit(this.k3); -// } -// -// // g1(z) := 1, g2(z) := 0 -// BigInteger g1z = ECConstants.ONE; -// BigInteger g2z = ECConstants.ZERO; -// -// // while u != 1 -// while (!(uz.equals(ECConstants.ZERO))) -// { -// // j := deg(u(z)) - deg(v(z)) -// int j = uz.bitLength() - vz.bitLength(); -// -// // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j -// if (j < 0) -// { -// final BigInteger uzCopy = uz; -// uz = vz; -// vz = uzCopy; -// -// final BigInteger g1zCopy = g1z; -// g1z = g2z; -// g2z = g1zCopy; -// -// j = -j; -// } -// -// // u(z) := u(z) + z^j * v(z) -// // Note, that no reduction modulo f(z) is required, because -// // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z))) -// // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z)) -// // = deg(u(z)) -// uz = uz.xor(vz.shiftLeft(j)); -// -// // g1(z) := g1(z) + z^j * g2(z) -// g1z = g1z.xor(g2z.shiftLeft(j)); -//// if (g1z.bitLength() > this.m) { -//// throw new ArithmeticException( -//// "deg(g1z) >= m, g1z = " + g1z.toString(16)); -//// } -// } -// return new ECFieldElement.F2m( -// this.m, this.k1, this.k2, this.k3, g2z); -// } -// -// public ECFieldElement sqrt() -// { -// throw new RuntimeException("Not implemented"); -// } -// -// /** -// * @return the representation of the field -// * <code>F<sub>2<sup>m</sup></sub></code>, either of -// * TPB (trinomial -// * basis representation) or -// * PPB (pentanomial -// * basis representation). -// */ -// public int getRepresentation() -// { -// return this.representation; -// } -// -// /** -// * @return the degree <code>m</code> of the reduction polynomial -// * <code>f(z)</code>. -// */ -// public int getM() -// { -// return this.m; -// } -// -// /** -// * @return TPB: The integer <code>k</code> where <code>x<sup>m</sup> + -// * x<sup>k</sup> + 1</code> represents the reduction polynomial -// * <code>f(z)</code>.<br> -// * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> + -// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> -// * represents the reduction polynomial <code>f(z)</code>.<br> -// */ -// public int getK1() -// { -// return this.k1; -// } -// -// /** -// * @return TPB: Always returns <code>0</code><br> -// * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> + -// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> -// * represents the reduction polynomial <code>f(z)</code>.<br> -// */ -// public int getK2() -// { -// return this.k2; -// } -// -// /** -// * @return TPB: Always set to <code>0</code><br> -// * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> + -// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> -// * represents the reduction polynomial <code>f(z)</code>.<br> -// */ -// public int getK3() -// { -// return this.k3; -// } -// -// public boolean equals(Object anObject) -// { -// if (anObject == this) -// { -// return true; -// } -// -// if (!(anObject instanceof ECFieldElement.F2m)) -// { -// return false; -// } -// -// ECFieldElement.F2m b = (ECFieldElement.F2m)anObject; -// -// return ((this.m == b.m) && (this.k1 == b.k1) && (this.k2 == b.k2) -// && (this.k3 == b.k3) -// && (this.representation == b.representation) -// && (this.x.equals(b.x))); -// } -// -// public int hashCode() -// { -// return x.hashCode() ^ m ^ k1 ^ k2 ^ k3; -// } -// } - /** * Class representing the Elements of the finite field * <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB) @@ -987,32 +518,6 @@ public abstract class ECFieldElement */ private int m; -// /** -// * TPB: The integer <code>k</code> where <code>x<sup>m</sup> + -// * x<sup>k</sup> + 1</code> represents the reduction polynomial -// * <code>f(z)</code>.<br> -// * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> + -// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> -// * represents the reduction polynomial <code>f(z)</code>.<br> -// */ -// private int k1; -// -// /** -// * TPB: Always set to <code>0</code><br> -// * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> + -// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> -// * represents the reduction polynomial <code>f(z)</code>.<br> -// */ -// private int k2; -// -// /** -// * TPB: Always set to <code>0</code><br> -// * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> + -// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code> -// * represents the reduction polynomial <code>f(z)</code>.<br> -// */ -// private int k3; - private int[] ks; /** @@ -1097,6 +602,11 @@ public abstract class ECFieldElement return x.degree(); } + public boolean isOne() + { + return x.isOne(); + } + public boolean isZero() { return x.isZero(); @@ -1192,6 +702,29 @@ public abstract class ECFieldElement return new F2m(m, ks, x.modMultiply(((F2m)b).x, m, ks)); } + public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + return multiplyPlusProduct(b, x, y); + } + + public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + LongArray ax = this.x, bx = ((F2m)b).x, xx = ((F2m)x).x, yx = ((F2m)y).x; + + LongArray ab = ax.multiply(bx, m, ks); + LongArray xy = xx.multiply(yx, m, ks); + + if (ab == ax || ab == bx) + { + ab = (LongArray)ab.clone(); + } + + ab.addShiftedByWords(xy, 0); + ab.reduce(m, ks); + + return new F2m(m, ks, ab); + } + public ECFieldElement divide(final ECFieldElement b) { // There may be more efficient implementations @@ -1210,6 +743,29 @@ public abstract class ECFieldElement return new F2m(m, ks, x.modSquare(m, ks)); } + public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y) + { + return squarePlusProduct(x, y); + } + + public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y) + { + LongArray ax = this.x, xx = ((F2m)x).x, yx = ((F2m)y).x; + + LongArray aa = ax.square(m, ks); + LongArray xy = xx.multiply(yx, m, ks); + + if (aa == ax) + { + aa = (LongArray)aa.clone(); + } + + aa.addShiftedByWords(xy, 0); + aa.reduce(m, ks); + + return new F2m(m, ks, aa); + } + public ECFieldElement invert() { return new ECFieldElement.F2m(this.m, this.ks, this.x.modInverse(m, ks)); @@ -1217,7 +773,14 @@ public abstract class ECFieldElement public ECFieldElement sqrt() { - throw new RuntimeException("Not implemented"); + LongArray x1 = this.x; + if (x1.isOne() || x1.isZero()) + { + return this; + } + + LongArray x2 = x1.modSquareN(m - 1, m, ks); + return new ECFieldElement.F2m(m, ks, x2); } /** |