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 | 493 |
1 files changed, 301 insertions, 192 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 b5e9aa5..87608eb 100644 --- a/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java +++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java @@ -3,14 +3,17 @@ package org.bouncycastle.math.ec; import java.math.BigInteger; import java.util.Random; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; + public abstract class ECFieldElement implements ECConstants { - public abstract BigInteger toBigInteger(); public abstract String getFieldName(); public abstract int getFieldSize(); public abstract ECFieldElement add(ECFieldElement b); + public abstract ECFieldElement addOne(); public abstract ECFieldElement subtract(ECFieldElement b); public abstract ECFieldElement multiply(ECFieldElement b); public abstract ECFieldElement divide(ECFieldElement b); @@ -19,27 +22,99 @@ public abstract class ECFieldElement public abstract ECFieldElement invert(); public abstract ECFieldElement sqrt(); + public int bitLength() + { + return toBigInteger().bitLength(); + } + + public boolean isZero() + { + return 0 == toBigInteger().signum(); + } + + public boolean testBitZero() + { + return toBigInteger().testBit(0); + } + public String toString() { - return this.toBigInteger().toString(2); + return this.toBigInteger().toString(16); + } + + public byte[] getEncoded() + { + return BigIntegers.asUnsignedByteArray((getFieldSize() + 7) / 8, toBigInteger()); } public static class Fp extends ECFieldElement { - BigInteger x; + BigInteger q, r, x; - BigInteger q; - +// 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) + { + BigInteger firstWord = p.shiftRight(bitLength - 64); + if (firstWord.longValue() == -1L) + { + return ONE.shiftLeft(bitLength).subtract(p); + } + } + return null; + } + + /** + * @deprecated Use ECCurve.fromBigInteger to construct field elements + */ public Fp(BigInteger q, BigInteger x) { - this.x = x; - - if (x.compareTo(q) >= 0) + this(q, calculateResidue(q), x); + } + + Fp(BigInteger q, BigInteger r, BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(q) >= 0) { - throw new IllegalArgumentException("x value too large in field element"); + throw new IllegalArgumentException("x value invalid in Fp field element"); } this.q = q; + this.r = r; + this.x = x; } public BigInteger toBigInteger() @@ -66,40 +141,70 @@ public abstract class ECFieldElement { return q; } - + public ECFieldElement add(ECFieldElement b) { - return new Fp(q, x.add(b.toBigInteger()).mod(q)); + return new Fp(q, r, modAdd(x, b.toBigInteger())); + } + + public ECFieldElement addOne() + { + BigInteger x2 = x.add(ECConstants.ONE); + if (x2.compareTo(q) == 0) + { + x2 = ECConstants.ZERO; + } + return new Fp(q, r, x2); } public ECFieldElement subtract(ECFieldElement b) { - return new Fp(q, x.subtract(b.toBigInteger()).mod(q)); + BigInteger x2 = b.toBigInteger(); + BigInteger x3 = x.subtract(x2); + if (x3.signum() < 0) + { + x3 = x3.add(q); + } + return new Fp(q, r, x3); } public ECFieldElement multiply(ECFieldElement b) { - return new Fp(q, x.multiply(b.toBigInteger()).mod(q)); + return new Fp(q, r, modMult(x, b.toBigInteger())); } public ECFieldElement divide(ECFieldElement b) { - return new Fp(q, x.multiply(b.toBigInteger().modInverse(q)).mod(q)); + return new Fp(q, modMult(x, b.toBigInteger().modInverse(q))); } public ECFieldElement negate() { - return new Fp(q, x.negate().mod(q)); + 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); } public ECFieldElement square() { - return new Fp(q, x.multiply(x).mod(q)); + return new Fp(q, r, modMult(x, x)); } public ECFieldElement invert() { - return new Fp(q, x.modInverse(q)); + // TODO Modular inversion can be faster for a (Generalized) Mersenne Prime. + return new Fp(q, r, x.modInverse(q)); } // D.1.4 91 @@ -120,7 +225,7 @@ public abstract class ECFieldElement if (q.testBit(1)) { // z = g^(u+1) + p, p = 4u + 3 - ECFieldElement z = new Fp(q, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q)); + ECFieldElement z = new Fp(q, r, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q)); return z.square().equals(this) ? z : null; } @@ -138,7 +243,7 @@ public abstract class ECFieldElement BigInteger k = u.shiftLeft(1).add(ECConstants.ONE); BigInteger Q = this.x; - BigInteger fourQ = Q.shiftLeft(2).mod(q); + BigInteger fourQ = modDouble(modDouble(Q)); BigInteger U, V; Random rand = new Random(); @@ -152,11 +257,11 @@ public abstract class ECFieldElement while (P.compareTo(q) >= 0 || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, q).equals(qMinusOne))); - BigInteger[] result = lucasSequence(q, P, Q, k); + BigInteger[] result = lucasSequence(P, Q, k); U = result[0]; V = result[1]; - if (V.multiply(V).mod(q).equals(fourQ)) + if (modMult(V, V).equals(fourQ)) { // Integer division by 2, mod q if (V.testBit(0)) @@ -168,7 +273,7 @@ public abstract class ECFieldElement //assert V.multiply(V).mod(q).equals(x); - return new ECFieldElement.Fp(q, V); + return new ECFieldElement.Fp(q, r, V); } } while (U.equals(ECConstants.ONE) || U.equals(qMinusOne)); @@ -230,8 +335,7 @@ public abstract class ECFieldElement // return r.multiply(r).multiply(x.modPow(q.subtract(ECConstants.TWO), q)).subtract(ECConstants.TWO).mod(p); // } - private static BigInteger[] lucasSequence( - BigInteger p, + private BigInteger[] lucasSequence( BigInteger P, BigInteger Q, BigInteger k) @@ -247,40 +351,122 @@ public abstract class ECFieldElement for (int j = n - 1; j >= s + 1; --j) { - Ql = Ql.multiply(Qh).mod(p); + Ql = modMult(Ql, Qh); if (k.testBit(j)) { - Qh = Ql.multiply(Q).mod(p); - Uh = Uh.multiply(Vh).mod(p); - Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p); - Vh = Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p); + Qh = modMult(Ql, Q); + Uh = modMult(Uh, Vh); + Vl = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql))); + Vh = modReduce(Vh.multiply(Vh).subtract(Qh.shiftLeft(1))); } else { Qh = Ql; - Uh = Uh.multiply(Vl).subtract(Ql).mod(p); - Vh = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p); - Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p); + Uh = modReduce(Uh.multiply(Vl).subtract(Ql)); + Vh = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql))); + Vl = modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1))); } } - Ql = Ql.multiply(Qh).mod(p); - Qh = Ql.multiply(Q).mod(p); - Uh = Uh.multiply(Vl).subtract(Ql).mod(p); - Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p); - Ql = Ql.multiply(Qh).mod(p); + Ql = modMult(Ql, Qh); + Qh = modMult(Ql, Q); + Uh = modReduce(Uh.multiply(Vl).subtract(Ql)); + Vl = modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql))); + Ql = modMult(Ql, Qh); for (int j = 1; j <= s; ++j) { - Uh = Uh.multiply(Vl).mod(p); - Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p); - Ql = Ql.multiply(Ql).mod(p); + Uh = modMult(Uh, Vl); + Vl = modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1))); + Ql = modMult(Ql, Ql); } return new BigInteger[]{ Uh, Vl }; } - + + protected BigInteger modAdd(BigInteger x1, BigInteger x2) + { + BigInteger x3 = x1.add(x2); + if (x3.compareTo(q) >= 0) + { + x3 = x3.subtract(q); + } + return x3; + } + + protected BigInteger modDouble(BigInteger x) + { + BigInteger _2x = x.shiftLeft(1); + if (_2x.compareTo(q) >= 0) + { + _2x = _2x.subtract(q); + } + return _2x; + } + + protected BigInteger modMult(BigInteger x1, BigInteger x2) + { + return modReduce(x1.multiply(x2)); + } + + 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) + { + int qLen = q.bitLength(); + while (x.bitLength() > (qLen + 1)) + { + BigInteger u = x.shiftRight(qLen); + BigInteger v = x.subtract(u.shiftLeft(qLen)); + if (!r.equals(ONE)) + { + u = u.multiply(r); + } + x = u.add(v); + } + while (x.compareTo(q) >= 0) + { + x = x.subtract(q); + } + } + else + { + x = x.mod(q); + } + return x; + } + public boolean equals(Object other) { if (other == this) @@ -669,7 +855,7 @@ public abstract class ECFieldElement // g1z = g1z.xor(g2z.shiftLeft(j)); //// if (g1z.bitLength() > this.m) { //// throw new ArithmeticException( -//// "deg(g1z) >= m, g1z = " + g1z.toString(2)); +//// "deg(g1z) >= m, g1z = " + g1z.toString(16)); //// } // } // return new ECFieldElement.F2m( @@ -801,41 +987,38 @@ 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; +// /** +// * 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; - /** - * The <code>IntArray</code> holding the bits. - */ - private IntArray x; + private int[] ks; /** - * The number of <code>int</code>s required to hold <code>m</code> bits. + * The <code>LongArray</code> holding the bits. */ - private int t; + private LongArray x; /** * Constructor for PPB. @@ -851,6 +1034,7 @@ public abstract class ECFieldElement * 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. + * @deprecated Use ECCurve.fromBigInteger to construct field elements */ public F2m( int m, @@ -859,13 +1043,10 @@ public abstract class ECFieldElement int k3, BigInteger x) { - // t = m / 32 rounded up to the next integer - t = (m + 31) >> 5; - this.x = new IntArray(x, t); - if ((k2 == 0) && (k3 == 0)) { this.representation = TPB; + this.ks = new int[]{ k1 }; } else { @@ -880,17 +1061,11 @@ public abstract class ECFieldElement "k2 must be larger than 0"); } this.representation = PPB; - } - - if (x.signum() < 0) - { - throw new IllegalArgumentException("x value cannot be negative"); + this.ks = new int[]{ k1, k2, k3 }; } this.m = m; - this.k1 = k1; - this.k2 = k2; - this.k3 = k3; + this.x = new LongArray(x); } /** @@ -901,6 +1076,7 @@ public abstract class ECFieldElement * 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. + * @deprecated Use ECCurve.fromBigInteger to construct field elements */ public F2m(int m, int k, BigInteger x) { @@ -908,24 +1084,27 @@ public abstract class ECFieldElement this(m, k, 0, 0, x); } - private F2m(int m, int k1, int k2, int k3, IntArray x) + private F2m(int m, int[] ks, LongArray x) { - t = (m + 31) >> 5; - this.x = x; this.m = m; - this.k1 = k1; - this.k2 = k2; - this.k3 = k3; + this.representation = (ks.length == 1) ? TPB : PPB; + this.ks = ks; + this.x = x; + } - if ((k2 == 0) && (k3 == 0)) - { - this.representation = TPB; - } - else - { - this.representation = PPB; - } + public int bitLength() + { + return x.degree(); + } + + public boolean isZero() + { + return x.isZero(); + } + public boolean testBitZero() + { + return x.testBitZero(); } public BigInteger toBigInteger() @@ -967,19 +1146,15 @@ public abstract class ECFieldElement 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)) + if (aF2m.representation != bF2m.representation) { - throw new IllegalArgumentException("Field elements are not " - + "elements of the same field F2m"); + // Should never occur + throw new IllegalArgumentException("One of the F2m field elements has incorrect representation"); } - if (aF2m.representation != bF2m.representation) + if ((aF2m.m != bF2m.m) || !Arrays.areEqual(aF2m.ks, bF2m.ks)) { - // Should never occur - throw new IllegalArgumentException( - "One of the field " - + "elements are not elements has incorrect representation"); + throw new IllegalArgumentException("Field elements are not elements of the same field F2m"); } } @@ -988,10 +1163,15 @@ public abstract class ECFieldElement // No check performed here for performance reasons. Instead the // elements involved are checked in ECPoint.F2m // checkFieldElements(this, b); - IntArray iarrClone = (IntArray)this.x.clone(); + LongArray iarrClone = (LongArray)this.x.clone(); F2m bF2m = (F2m)b; - iarrClone.addShifted(bF2m.x, 0); - return new F2m(m, k1, k2, k3, iarrClone); + iarrClone.addShiftedByWords(bF2m.x, 0); + return new F2m(m, ks, iarrClone); + } + + public ECFieldElement addOne() + { + return new F2m(m, ks, x.addOne()); } public ECFieldElement subtract(final ECFieldElement b) @@ -1002,17 +1182,14 @@ public abstract class ECFieldElement public ECFieldElement multiply(final ECFieldElement b) { - // Right-to-left comb multiplication in the IntArray + // Right-to-left comb multiplication in the LongArray // 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); - F2m bF2m = (F2m)b; - IntArray mult = x.multiply(bF2m.x, m); - mult.reduce(m, new int[]{k1, k2, k3}); - return new F2m(m, k1, k2, k3, mult); + return new F2m(m, ks, x.modMultiply(((F2m)b).x, m, ks)); } public ECFieldElement divide(final ECFieldElement b) @@ -1030,80 +1207,12 @@ public abstract class ECFieldElement public ECFieldElement square() { - IntArray squared = x.square(m); - squared.reduce(m, new int[]{k1, k2, k3}); - return new F2m(m, k1, k2, k3, squared); + return new F2m(m, ks, x.modSquare(m, ks)); } - 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) - IntArray uz = (IntArray)this.x.clone(); - - // v(z) := f(z) - IntArray vz = new IntArray(t); - vz.setBit(m); - vz.setBit(0); - vz.setBit(this.k1); - if (this.representation == PPB) - { - vz.setBit(this.k2); - vz.setBit(this.k3); - } - - // g1(z) := 1, g2(z) := 0 - IntArray g1z = new IntArray(t); - g1z.setBit(0); - IntArray g2z = new IntArray(t); - - // while u != 0 - while (!uz.isZero()) -// while (uz.getUsedLength() > 0) -// while (uz.bitLength() > 1) - { - // 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 IntArray uzCopy = uz; - uz = vz; - vz = uzCopy; - - final IntArray 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)); - // jInt = n / 32 - int jInt = j >> 5; - // jInt = n % 32 - int jBit = j & 0x1F; - IntArray vzShift = vz.shiftLeft(jBit); - uz.addShifted(vzShift, jInt); - - // g1(z) := g1(z) + z^j * g2(z) -// g1z = g1z.xor(g2z.shiftLeft(j)); - IntArray g2zShift = g2z.shiftLeft(jBit); - g1z.addShifted(g2zShift, jInt); - - } - return new ECFieldElement.F2m( - this.m, this.k1, this.k2, this.k3, g2z); + return new ECFieldElement.F2m(this.m, this.ks, this.x.modInverse(m, ks)); } public ECFieldElement sqrt() @@ -1143,7 +1252,7 @@ public abstract class ECFieldElement */ public int getK1() { - return this.k1; + return this.ks[0]; } /** @@ -1154,7 +1263,7 @@ public abstract class ECFieldElement */ public int getK2() { - return this.k2; + return this.ks.length >= 2 ? this.ks[1] : 0; } /** @@ -1165,7 +1274,7 @@ public abstract class ECFieldElement */ public int getK3() { - return this.k3; + return this.ks.length >= 3 ? this.ks[2] : 0; } public boolean equals(Object anObject) @@ -1182,15 +1291,15 @@ public abstract class ECFieldElement ECFieldElement.F2m b = (ECFieldElement.F2m)anObject; - return ((this.m == b.m) && (this.k1 == b.k1) && (this.k2 == b.k2) - && (this.k3 == b.k3) + return ((this.m == b.m) && (this.representation == b.representation) + && Arrays.areEqual(this.ks, b.ks) && (this.x.equals(b.x))); } public int hashCode() { - return x.hashCode() ^ m ^ k1 ^ k2 ^ k3; + return x.hashCode() ^ m ^ Arrays.hashCode(ks); } } } |