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