001package org.apache.commons.ssl.org.bouncycastle.asn1.ua; 002 003import java.math.BigInteger; 004import java.util.Random; 005 006import org.bouncycastle.math.ec.ECConstants; 007import org.bouncycastle.math.ec.ECCurve; 008import org.bouncycastle.math.ec.ECFieldElement; 009import org.bouncycastle.math.ec.ECPoint; 010 011/** 012 * DSTU4145 encodes points somewhat differently than X9.62 013 * It compresses the point to the size of the field element 014 */ 015public abstract class DSTU4145PointEncoder 016{ 017 private static ECFieldElement trace(ECFieldElement fe) 018 { 019 ECFieldElement t = fe; 020 for (int i = 1; i < fe.getFieldSize(); ++i) 021 { 022 t = t.square().add(fe); 023 } 024 return t; 025 } 026 027 /** 028 * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62 029 * D.1.6) The other solution is <code>z + 1</code>. 030 * 031 * @param beta The value to solve the quadratic equation for. 032 * @return the solution for <code>z<sup>2</sup> + z = beta</code> or 033 * <code>null</code> if no solution exists. 034 */ 035 private static ECFieldElement solveQuadraticEquation(ECCurve curve, ECFieldElement beta) 036 { 037 if (beta.isZero()) 038 { 039 return beta; 040 } 041 042 ECFieldElement zeroElement = curve.fromBigInteger(ECConstants.ZERO); 043 044 ECFieldElement z = null; 045 ECFieldElement gamma = null; 046 047 Random rand = new Random(); 048 int m = beta.getFieldSize(); 049 do 050 { 051 ECFieldElement t = curve.fromBigInteger(new BigInteger(m, rand)); 052 z = zeroElement; 053 ECFieldElement w = beta; 054 for (int i = 1; i <= m - 1; i++) 055 { 056 ECFieldElement w2 = w.square(); 057 z = z.square().add(w2.multiply(t)); 058 w = w2.add(beta); 059 } 060 if (!w.isZero()) 061 { 062 return null; 063 } 064 gamma = z.square().add(z); 065 } 066 while (gamma.isZero()); 067 068 return z; 069 } 070 071 public static byte[] encodePoint(ECPoint Q) 072 { 073 /*if (!Q.isCompressed()) 074 Q=new ECPoint.F2m(Q.getCurve(),Q.getX(),Q.getY(),true); 075 076 byte[] bytes=Q.getEncoded(); 077 078 if (bytes[0]==0x02) 079 bytes[bytes.length-1]&=0xFE; 080 else if (bytes[0]==0x02) 081 bytes[bytes.length-1]|=0x01; 082 083 return Arrays.copyOfRange(bytes, 1, bytes.length);*/ 084 085 Q = Q.normalize(); 086 087 ECFieldElement x = Q.getAffineXCoord(); 088 089 byte[] bytes = x.getEncoded(); 090 091 if (!x.isZero()) 092 { 093 ECFieldElement z = Q.getAffineYCoord().divide(x); 094 if (trace(z).isOne()) 095 { 096 bytes[bytes.length - 1] |= 0x01; 097 } 098 else 099 { 100 bytes[bytes.length - 1] &= 0xFE; 101 } 102 } 103 104 return bytes; 105 } 106 107 public static ECPoint decodePoint(ECCurve curve, byte[] bytes) 108 { 109 /*byte[] bp_enc=new byte[bytes.length+1]; 110 if (0==(bytes[bytes.length-1]&0x1)) 111 bp_enc[0]=0x02; 112 else 113 bp_enc[0]=0x03; 114 System.arraycopy(bytes, 0, bp_enc, 1, bytes.length); 115 if (!trace(curve.fromBigInteger(new BigInteger(1, bytes))).equals(curve.getA().toBigInteger())) 116 bp_enc[bp_enc.length-1]^=0x01; 117 118 return curve.decodePoint(bp_enc);*/ 119 120 ECFieldElement k = curve.fromBigInteger(BigInteger.valueOf(bytes[bytes.length - 1] & 0x1)); 121 122 ECFieldElement xp = curve.fromBigInteger(new BigInteger(1, bytes)); 123 if (!trace(xp).equals(curve.getA())) 124 { 125 xp = xp.addOne(); 126 } 127 128 ECFieldElement yp = null; 129 if (xp.isZero()) 130 { 131 yp = curve.getB().sqrt(); 132 } 133 else 134 { 135 ECFieldElement beta = xp.square().invert().multiply(curve.getB()).add(curve.getA()).add(xp); 136 ECFieldElement z = solveQuadraticEquation(curve, beta); 137 if (z != null) 138 { 139 if (!trace(z).equals(k)) 140 { 141 z = z.addOne(); 142 } 143 yp = xp.multiply(z); 144 } 145 } 146 147 if (yp == null) 148 { 149 throw new IllegalArgumentException("Invalid point compression"); 150 } 151 152 return curve.createPoint(xp.toBigInteger(), yp.toBigInteger()); 153 } 154}