| package org.bouncycastle.asn1.ua; |
| |
| import java.math.BigInteger; |
| import java.util.Random; |
| |
| import org.bouncycastle.math.ec.ECConstants; |
| import org.bouncycastle.math.ec.ECCurve; |
| import org.bouncycastle.math.ec.ECFieldElement; |
| import org.bouncycastle.math.ec.ECPoint; |
| |
| /** |
| * DSTU4145 encodes points somewhat differently than X9.62 |
| * It compresses the point to the size of the field element |
| */ |
| public abstract class DSTU4145PointEncoder |
| { |
| private static ECFieldElement trace(ECFieldElement fe) |
| { |
| ECFieldElement t = fe; |
| for (int i = 1; i < fe.getFieldSize(); ++i) |
| { |
| t = t.square().add(fe); |
| } |
| return t; |
| } |
| |
| /** |
| * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 |
| * D.1.6) The other solution is <code>z + 1</code>. |
| * |
| * @param beta The value to solve the quadratic equation for. |
| * @return the solution for <code>z<sup>2</sup> + z = beta</code> or |
| * <code>null</code> if no solution exists. |
| */ |
| private static ECFieldElement solveQuadraticEquation(ECCurve curve, ECFieldElement beta) |
| { |
| if (beta.isZero()) |
| { |
| return beta; |
| } |
| |
| ECFieldElement zeroElement = curve.fromBigInteger(ECConstants.ZERO); |
| |
| ECFieldElement z = null; |
| ECFieldElement gamma = null; |
| |
| Random rand = new Random(); |
| int m = beta.getFieldSize(); |
| do |
| { |
| ECFieldElement t = curve.fromBigInteger(new BigInteger(m, rand)); |
| z = zeroElement; |
| ECFieldElement w = beta; |
| for (int i = 1; i <= m - 1; i++) |
| { |
| ECFieldElement w2 = w.square(); |
| z = z.square().add(w2.multiply(t)); |
| w = w2.add(beta); |
| } |
| if (!w.isZero()) |
| { |
| return null; |
| } |
| gamma = z.square().add(z); |
| } |
| while (gamma.isZero()); |
| |
| return z; |
| } |
| |
| public static byte[] encodePoint(ECPoint Q) |
| { |
| /*if (!Q.isCompressed()) |
| Q=new ECPoint.F2m(Q.getCurve(),Q.getX(),Q.getY(),true); |
| |
| byte[] bytes=Q.getEncoded(); |
| |
| if (bytes[0]==0x02) |
| bytes[bytes.length-1]&=0xFE; |
| else if (bytes[0]==0x02) |
| bytes[bytes.length-1]|=0x01; |
| |
| return Arrays.copyOfRange(bytes, 1, bytes.length);*/ |
| |
| Q = Q.normalize(); |
| |
| ECFieldElement x = Q.getAffineXCoord(); |
| |
| byte[] bytes = x.getEncoded(); |
| |
| if (!x.isZero()) |
| { |
| ECFieldElement z = Q.getAffineYCoord().divide(x); |
| if (trace(z).isOne()) |
| { |
| bytes[bytes.length - 1] |= 0x01; |
| } |
| else |
| { |
| bytes[bytes.length - 1] &= 0xFE; |
| } |
| } |
| |
| return bytes; |
| } |
| |
| public static ECPoint decodePoint(ECCurve curve, byte[] bytes) |
| { |
| /*byte[] bp_enc=new byte[bytes.length+1]; |
| if (0==(bytes[bytes.length-1]&0x1)) |
| bp_enc[0]=0x02; |
| else |
| bp_enc[0]=0x03; |
| System.arraycopy(bytes, 0, bp_enc, 1, bytes.length); |
| if (!trace(curve.fromBigInteger(new BigInteger(1, bytes))).equals(curve.getA().toBigInteger())) |
| bp_enc[bp_enc.length-1]^=0x01; |
| |
| return curve.decodePoint(bp_enc);*/ |
| |
| ECFieldElement k = curve.fromBigInteger(BigInteger.valueOf(bytes[bytes.length - 1] & 0x1)); |
| |
| ECFieldElement xp = curve.fromBigInteger(new BigInteger(1, bytes)); |
| if (!trace(xp).equals(curve.getA())) |
| { |
| xp = xp.addOne(); |
| } |
| |
| ECFieldElement yp = null; |
| if (xp.isZero()) |
| { |
| yp = curve.getB().sqrt(); |
| } |
| else |
| { |
| ECFieldElement beta = xp.square().invert().multiply(curve.getB()).add(curve.getA()).add(xp); |
| ECFieldElement z = solveQuadraticEquation(curve, beta); |
| if (z != null) |
| { |
| if (!trace(z).equals(k)) |
| { |
| z = z.addOne(); |
| } |
| yp = xp.multiply(z); |
| } |
| } |
| |
| if (yp == null) |
| { |
| throw new IllegalArgumentException("Invalid point compression"); |
| } |
| |
| return curve.validatePoint(xp.toBigInteger(), yp.toBigInteger()); |
| } |
| } |