1 package org.bouncycastle.math.ec.custom.sec; 2 3 import org.bouncycastle.math.ec.ECCurve; 4 import org.bouncycastle.math.ec.ECFieldElement; 5 import org.bouncycastle.math.ec.ECPoint; 6 import org.bouncycastle.math.raw.Nat; 7 8 public class SecP521R1Point extends ECPoint.AbstractFp 9 { 10 /** 11 * Create a point which encodes with point compression. 12 * 13 * @param curve 14 * the curve to use 15 * @param x 16 * affine x co-ordinate 17 * @param y 18 * affine y co-ordinate 19 * 20 * @deprecated Use ECCurve.createPoint to construct points 21 */ SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)22 public SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) 23 { 24 this(curve, x, y, false); 25 } 26 27 /** 28 * Create a point that encodes with or without point compresion. 29 * 30 * @param curve 31 * the curve to use 32 * @param x 33 * affine x co-ordinate 34 * @param y 35 * affine y co-ordinate 36 * @param withCompression 37 * if true encode with point compression 38 * 39 * @deprecated per-point compression property will be removed, refer 40 * {@link #getEncoded(boolean)} 41 */ SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)42 public SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) 43 { 44 super(curve, x, y); 45 46 if ((x == null) != (y == null)) 47 { 48 throw new IllegalArgumentException("Exactly one of the field elements is null"); 49 } 50 51 this.withCompression = withCompression; 52 } 53 SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression)54 SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) 55 { 56 super(curve, x, y, zs); 57 58 this.withCompression = withCompression; 59 } 60 detach()61 protected ECPoint detach() 62 { 63 return new SecP521R1Point(null, getAffineXCoord(), getAffineYCoord()); 64 } 65 add(ECPoint b)66 public ECPoint add(ECPoint b) 67 { 68 if (this.isInfinity()) 69 { 70 return b; 71 } 72 if (b.isInfinity()) 73 { 74 return this; 75 } 76 if (this == b) 77 { 78 return twice(); 79 } 80 81 ECCurve curve = this.getCurve(); 82 83 SecP521R1FieldElement X1 = (SecP521R1FieldElement)this.x, Y1 = (SecP521R1FieldElement)this.y; 84 SecP521R1FieldElement X2 = (SecP521R1FieldElement)b.getXCoord(), Y2 = (SecP521R1FieldElement)b.getYCoord(); 85 86 SecP521R1FieldElement Z1 = (SecP521R1FieldElement)this.zs[0]; 87 SecP521R1FieldElement Z2 = (SecP521R1FieldElement)b.getZCoord(0); 88 89 int[] t1 = Nat.create(17); 90 int[] t2 = Nat.create(17); 91 int[] t3 = Nat.create(17); 92 int[] t4 = Nat.create(17); 93 94 boolean Z1IsOne = Z1.isOne(); 95 int[] U2, S2; 96 if (Z1IsOne) 97 { 98 U2 = X2.x; 99 S2 = Y2.x; 100 } 101 else 102 { 103 S2 = t3; 104 SecP521R1Field.square(Z1.x, S2); 105 106 U2 = t2; 107 SecP521R1Field.multiply(S2, X2.x, U2); 108 109 SecP521R1Field.multiply(S2, Z1.x, S2); 110 SecP521R1Field.multiply(S2, Y2.x, S2); 111 } 112 113 boolean Z2IsOne = Z2.isOne(); 114 int[] U1, S1; 115 if (Z2IsOne) 116 { 117 U1 = X1.x; 118 S1 = Y1.x; 119 } 120 else 121 { 122 S1 = t4; 123 SecP521R1Field.square(Z2.x, S1); 124 125 U1 = t1; 126 SecP521R1Field.multiply(S1, X1.x, U1); 127 128 SecP521R1Field.multiply(S1, Z2.x, S1); 129 SecP521R1Field.multiply(S1, Y1.x, S1); 130 } 131 132 int[] H = Nat.create(17); 133 SecP521R1Field.subtract(U1, U2, H); 134 135 int[] R = t2; 136 SecP521R1Field.subtract(S1, S2, R); 137 138 // Check if b == this or b == -this 139 if (Nat.isZero(17, H)) 140 { 141 if (Nat.isZero(17, R)) 142 { 143 // this == b, i.e. this must be doubled 144 return this.twice(); 145 } 146 147 // this == -b, i.e. the result is the point at infinity 148 return curve.getInfinity(); 149 } 150 151 int[] HSquared = t3; 152 SecP521R1Field.square(H, HSquared); 153 154 int[] G = Nat.create(17); 155 SecP521R1Field.multiply(HSquared, H, G); 156 157 int[] V = t3; 158 SecP521R1Field.multiply(HSquared, U1, V); 159 160 SecP521R1Field.multiply(S1, G, t1); 161 162 SecP521R1FieldElement X3 = new SecP521R1FieldElement(t4); 163 SecP521R1Field.square(R, X3.x); 164 SecP521R1Field.add(X3.x, G, X3.x); 165 SecP521R1Field.subtract(X3.x, V, X3.x); 166 SecP521R1Field.subtract(X3.x, V, X3.x); 167 168 SecP521R1FieldElement Y3 = new SecP521R1FieldElement(G); 169 SecP521R1Field.subtract(V, X3.x, Y3.x); 170 SecP521R1Field.multiply(Y3.x, R, t2); 171 SecP521R1Field.subtract(t2, t1, Y3.x); 172 173 SecP521R1FieldElement Z3 = new SecP521R1FieldElement(H); 174 if (!Z1IsOne) 175 { 176 SecP521R1Field.multiply(Z3.x, Z1.x, Z3.x); 177 } 178 if (!Z2IsOne) 179 { 180 SecP521R1Field.multiply(Z3.x, Z2.x, Z3.x); 181 } 182 183 ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; 184 185 return new SecP521R1Point(curve, X3, Y3, zs, this.withCompression); 186 } 187 twice()188 public ECPoint twice() 189 { 190 if (this.isInfinity()) 191 { 192 return this; 193 } 194 195 ECCurve curve = this.getCurve(); 196 197 SecP521R1FieldElement Y1 = (SecP521R1FieldElement)this.y; 198 if (Y1.isZero()) 199 { 200 return curve.getInfinity(); 201 } 202 203 SecP521R1FieldElement X1 = (SecP521R1FieldElement)this.x, Z1 = (SecP521R1FieldElement)this.zs[0]; 204 205 int[] t1 = Nat.create(17); 206 int[] t2 = Nat.create(17); 207 208 int[] Y1Squared = Nat.create(17); 209 SecP521R1Field.square(Y1.x, Y1Squared); 210 211 int[] T = Nat.create(17); 212 SecP521R1Field.square(Y1Squared, T); 213 214 boolean Z1IsOne = Z1.isOne(); 215 216 int[] Z1Squared = Z1.x; 217 if (!Z1IsOne) 218 { 219 Z1Squared = t2; 220 SecP521R1Field.square(Z1.x, Z1Squared); 221 } 222 223 SecP521R1Field.subtract(X1.x, Z1Squared, t1); 224 225 int[] M = t2; 226 SecP521R1Field.add(X1.x, Z1Squared, M); 227 SecP521R1Field.multiply(M, t1, M); 228 Nat.addBothTo(17, M, M, M); 229 SecP521R1Field.reduce23(M); 230 231 int[] S = Y1Squared; 232 SecP521R1Field.multiply(Y1Squared, X1.x, S); 233 Nat.shiftUpBits(17, S, 2, 0); 234 SecP521R1Field.reduce23(S); 235 236 Nat.shiftUpBits(17, T, 3, 0, t1); 237 SecP521R1Field.reduce23(t1); 238 239 SecP521R1FieldElement X3 = new SecP521R1FieldElement(T); 240 SecP521R1Field.square(M, X3.x); 241 SecP521R1Field.subtract(X3.x, S, X3.x); 242 SecP521R1Field.subtract(X3.x, S, X3.x); 243 244 SecP521R1FieldElement Y3 = new SecP521R1FieldElement(S); 245 SecP521R1Field.subtract(S, X3.x, Y3.x); 246 SecP521R1Field.multiply(Y3.x, M, Y3.x); 247 SecP521R1Field.subtract(Y3.x, t1, Y3.x); 248 249 SecP521R1FieldElement Z3 = new SecP521R1FieldElement(M); 250 SecP521R1Field.twice(Y1.x, Z3.x); 251 if (!Z1IsOne) 252 { 253 SecP521R1Field.multiply(Z3.x, Z1.x, Z3.x); 254 } 255 256 return new SecP521R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); 257 } 258 twicePlus(ECPoint b)259 public ECPoint twicePlus(ECPoint b) 260 { 261 if (this == b) 262 { 263 return threeTimes(); 264 } 265 if (this.isInfinity()) 266 { 267 return b; 268 } 269 if (b.isInfinity()) 270 { 271 return twice(); 272 } 273 274 ECFieldElement Y1 = this.y; 275 if (Y1.isZero()) 276 { 277 return b; 278 } 279 280 return twice().add(b); 281 } 282 threeTimes()283 public ECPoint threeTimes() 284 { 285 if (this.isInfinity() || this.y.isZero()) 286 { 287 return this; 288 } 289 290 // NOTE: Be careful about recursions between twicePlus and threeTimes 291 return twice().add(this); 292 } 293 two(ECFieldElement x)294 protected ECFieldElement two(ECFieldElement x) 295 { 296 return x.add(x); 297 } 298 three(ECFieldElement x)299 protected ECFieldElement three(ECFieldElement x) 300 { 301 return two(x).add(x); 302 } 303 four(ECFieldElement x)304 protected ECFieldElement four(ECFieldElement x) 305 { 306 return two(two(x)); 307 } 308 eight(ECFieldElement x)309 protected ECFieldElement eight(ECFieldElement x) 310 { 311 return four(two(x)); 312 } 313 doubleProductFromSquares(ECFieldElement a, ECFieldElement b, ECFieldElement aSquared, ECFieldElement bSquared)314 protected ECFieldElement doubleProductFromSquares(ECFieldElement a, ECFieldElement b, 315 ECFieldElement aSquared, ECFieldElement bSquared) 316 { 317 /* 318 * NOTE: If squaring in the field is faster than multiplication, then this is a quicker 319 * way to calculate 2.A.B, if A^2 and B^2 are already known. 320 */ 321 return a.add(b).square().subtract(aSquared).subtract(bSquared); 322 } 323 negate()324 public ECPoint negate() 325 { 326 if (this.isInfinity()) 327 { 328 return this; 329 } 330 331 return new SecP521R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); 332 } 333 } 334