1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.security.spec; 19 20import java.math.BigInteger; 21import java.util.Arrays; 22 23/** 24 * An Elliptic Curve with its necessary values. 25 */ 26public class EllipticCurve { 27 28 // Underlying finite field 29 private final ECField field; 30 31 // The first coefficient of the equation defining this elliptic curve 32 private final BigInteger a; 33 34 // The second coefficient of the equation defining this elliptic curve 35 private final BigInteger b; 36 37 // Bytes used during this elliptic curve generation, 38 // if it was generated randomly 39 private final byte[] seed; 40 41 // Hash code 42 private volatile int hash; 43 44 /** 45 * Creates a new {@code EllipticCurve} with the specified field, 46 * coefficients and seed. 47 * 48 * @param field 49 * the finite field of this elliptic curve. 50 * @param a 51 * the coefficient {@code a}. 52 * @param b 53 * the coefficient {@code b}. 54 * @param seed 55 * the seed used for the generation of the curve. 56 * @throws IllegalArgumentException 57 * if the specified coefficients are not in the specified field. 58 */ 59 public EllipticCurve(ECField field, BigInteger a, BigInteger b, byte[] seed) { 60 this.field = field; 61 if (this.field == null) { 62 throw new NullPointerException("field == null"); 63 } 64 this.a = a; 65 if (this.a == null) { 66 throw new NullPointerException("a == null"); 67 } 68 this.b = b; 69 if (this.b == null) { 70 throw new NullPointerException("b == null"); 71 } 72 // make defensive copy 73 if (seed == null) { 74 this.seed = null; 75 } else { 76 this.seed = new byte[seed.length]; 77 System.arraycopy(seed, 0, this.seed, 0, this.seed.length); 78 } 79 // check parameters for ECFieldFp and ECFieldF2m. 80 // Check invariant: a and b must be in the field. 81 // Check conditions for custom ECField are not specified. 82 if (this.field instanceof ECFieldFp) { 83 BigInteger p = ((ECFieldFp) this.field).getP(); 84 if (this.a.signum() < 0 || this.a.compareTo(p) >= 0) { 85 throw new IllegalArgumentException("the a is not in the field"); 86 } 87 if (this.b.signum() < 0 || this.b.compareTo(p) >= 0) { 88 throw new IllegalArgumentException("the b is not in the field"); 89 } 90 } else if (this.field instanceof ECFieldF2m) { 91 int fieldSizeInBits = this.field.getFieldSize(); 92 if (!(this.a.bitLength() <= fieldSizeInBits)) { 93 throw new IllegalArgumentException("the a is not in the field"); 94 } 95 if (!(this.b.bitLength() <= fieldSizeInBits)) { 96 throw new IllegalArgumentException("the b is not in the field"); 97 } 98 } 99 } 100 101 /** 102 * Creates a new {@code EllipticCurve} with the specified field and 103 * coefficients. 104 * 105 * @param field 106 * the finite field of this elliptic curve. 107 * @param a 108 * the coefficient {@code a}. 109 * @param b 110 * the coefficient {@code b}. 111 * @throws IllegalArgumentException 112 * if the specified coefficients are not in the specified field. 113 */ 114 public EllipticCurve(ECField field, BigInteger a, BigInteger b) { 115 this(field, a, b, null); 116 } 117 118 /** 119 * Returns the coefficient {@code a} of this elliptic curve. 120 * 121 * @return the coefficient {@code a} of this elliptic curve. 122 */ 123 public BigInteger getA() { 124 return a; 125 } 126 127 /** 128 * Returns the coefficient {@code b} of this elliptic curve. 129 * 130 * @return the coefficient {@code b} of this elliptic curve. 131 */ 132 public BigInteger getB() { 133 return b; 134 } 135 136 /** 137 * Returns the finite field of this elliptic curve. 138 * 139 * @return the finite field of this elliptic curve. 140 */ 141 public ECField getField() { 142 return field; 143 } 144 145 /** 146 * Returns a copy of the seed that was used to generate this elliptic curve. 147 * 148 * @return a copy of the seed that was used to generate this elliptic curve, 149 * or {@code null} if none specified. 150 */ 151 public byte[] getSeed() { 152 if (seed == null) { 153 return null; 154 } else { 155 // return copy 156 byte[] ret = new byte[seed.length]; 157 System.arraycopy(seed, 0, ret, 0, ret.length); 158 return ret; 159 } 160 } 161 162 /** 163 * Returns whether the specified object equals to this elliptic curve. 164 * 165 * @param other 166 * the object to compare. 167 * @return {@code true} if the specified object is equal to this elliptic 168 * curve, otherwise {@code false}. 169 */ 170 public boolean equals(Object other) { 171 if (this == other) { 172 return true; 173 } 174 if (!(other instanceof EllipticCurve)) { 175 return false; 176 } 177 EllipticCurve otherEc = (EllipticCurve) other; 178 return this.field.equals(otherEc.field) && this.a.equals(otherEc.a) 179 && this.b.equals(otherEc.b) 180 && Arrays.equals(this.seed, otherEc.seed); 181 } 182 183 /** 184 * Returns the hashcode of this elliptic curve. 185 * 186 * @return the hashcode of this elliptic curve. 187 */ 188 public int hashCode() { 189 // hash init is delayed 190 if (hash == 0) { 191 int hash0 = 11; 192 hash0 = hash0 * 31 + field.hashCode(); 193 hash0 = hash0 * 31 + a.hashCode(); 194 hash0 = hash0 * 31 + b.hashCode(); 195 if (seed != null) { 196 for (int i = 0; i < seed.length; i++) { 197 hash0 = hash0 * 31 + seed[i]; 198 } 199 } else { 200 hash0 = hash0 * 31; 201 } 202 hash = hash0; 203 } 204 return hash; 205 } 206} 207