1 /*
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.security.spec;
27
28 import java.math.BigInteger;
29 import java.util.Arrays;
30
31 /**
32 * This immutable class holds the necessary values needed to represent
33 * an elliptic curve.
34 *
35 * @see ECField
36 * @see ECFieldFp
37 * @see ECFieldF2m
38 *
39 * @author Valerie Peng
40 *
41 * @since 1.5
42 */
43 public class EllipticCurve {
44
45 private final ECField field;
46 private final BigInteger a;
47 private final BigInteger b;
48 private final byte[] seed;
49
50 // Check coefficient c is a valid element in ECField field.
51 private static void checkValidity(ECField field, BigInteger c,
52 String cName) {
53 // can only perform check if field is ECFieldFp or ECFieldF2m.
54 if (field instanceof ECFieldFp) {
55 BigInteger p = ((ECFieldFp)field).getP();
56 if (p.compareTo(c) != 1) {
57 throw new IllegalArgumentException(cName + " is too large");
58 } else if (c.signum() < 0) {
59 throw new IllegalArgumentException(cName + " is negative");
60 }
61 } else if (field instanceof ECFieldF2m) {
62 int m = ((ECFieldF2m)field).getM();
63 if (c.bitLength() > m) {
64 throw new IllegalArgumentException(cName + " is too large");
65 }
66 }
67 }
68
69 /**
70 * Creates an elliptic curve with the specified elliptic field
71 * {@code field} and the coefficients {@code a} and
72 * {@code b}.
73 * @param field the finite field that this elliptic curve is over.
74 * @param a the first coefficient of this elliptic curve.
75 * @param b the second coefficient of this elliptic curve.
76 * @exception NullPointerException if {@code field},
77 * {@code a}, or {@code b} is null.
78 * @exception IllegalArgumentException if {@code a}
79 * or {@code b} is not null and not in {@code field}.
80 */
81 public EllipticCurve(ECField field, BigInteger a,
82 BigInteger b) {
83 this(field, a, b, null);
84 }
85
86 /**
87 * Creates an elliptic curve with the specified elliptic field
88 * {@code field}, the coefficients {@code a} and
89 * {@code b}, and the {@code seed} used for curve generation.
90 * @param field the finite field that this elliptic curve is over.
91 * @param a the first coefficient of this elliptic curve.
92 * @param b the second coefficient of this elliptic curve.
93 * @param seed the bytes used during curve generation for later
94 * validation. Contents of this array are copied to protect against
95 * subsequent modification.
96 * @exception NullPointerException if {@code field},
97 * {@code a}, or {@code b} is null.
98 * @exception IllegalArgumentException if {@code a}
99 * or {@code b} is not null and not in {@code field}.
100 */
101 public EllipticCurve(ECField field, BigInteger a,
102 BigInteger b, byte[] seed) {
103 if (field == null) {
104 throw new NullPointerException("field is null");
105 }
106 if (a == null) {
107 throw new NullPointerException("first coefficient is null");
108 }
109 if (b == null) {
110 throw new NullPointerException("second coefficient is null");
111 }
112 checkValidity(field, a, "first coefficient");
113 checkValidity(field, b, "second coefficient");
114 this.field = field;
115 this.a = a;
116 this.b = b;
117 if (seed != null) {
118 this.seed = seed.clone();
119 } else {
120 this.seed = null;
121 }
122 }
123
124 /**
125 * Returns the finite field {@code field} that this
126 * elliptic curve is over.
127 * @return the field {@code field} that this curve
128 * is over.
129 */
130 public ECField getField() {
131 return field;
132 }
133
134 /**
135 * Returns the first coefficient {@code a} of the
136 * elliptic curve.
137 * @return the first coefficient {@code a}.
138 */
139 public BigInteger getA() {
140 return a;
141 }
142
143 /**
144 * Returns the second coefficient {@code b} of the
145 * elliptic curve.
146 * @return the second coefficient {@code b}.
147 */
148 public BigInteger getB() {
149 return b;
150 }
151
152 /**
153 * Returns the seeding bytes {@code seed} used
154 * during curve generation. May be null if not specified.
155 * @return the seeding bytes {@code seed}. A new
156 * array is returned each time this method is called.
157 */
158 public byte[] getSeed() {
159 if (seed == null) return null;
160 else return seed.clone();
161 }
162
163 /**
164 * Compares this elliptic curve for equality with the
165 * specified object.
166 * @param obj the object to be compared.
167 * @return true if {@code obj} is an instance of
168 * EllipticCurve and the field, A, and B match, false otherwise.
169 */
170 public boolean equals(Object obj) {
171 if (this == obj) return true;
172 if (obj instanceof EllipticCurve) {
173 EllipticCurve curve = (EllipticCurve) obj;
174 if ((field.equals(curve.field)) &&
175 (a.equals(curve.a)) &&
176 (b.equals(curve.b))) {
177 return true;
178 }
179 }
180 return false;
181 }
182
183 /**
184 * Returns a hash code value for this elliptic curve.
185 * @return a hash code value computed from the hash codes of the field, A,
186 * and B, as follows:
187 * <pre>{@code
188 * (field.hashCode() << 6) + (a.hashCode() << 4) + (b.hashCode() << 2)
189 * }</pre>
190 */
191 public int hashCode() {
192 return (field.hashCode() << 6 +
193 (a.hashCode() << 4) +
194 (b.hashCode() << 2));
195 }
196 }
197