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