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
26package java.security.spec;
27
28import java.math.BigInteger;
29import 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 */
43public 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