/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.security.spec; import java.math.BigInteger; import java.util.Arrays; /** * The parameters specifying a <i>characteristic 2 finite field</i> of an * elliptic curve. */ public class ECFieldF2m implements ECField { // Mid terms array length for trinomial basis private static final int TPB_MID_LEN = 1; // Mid terms array length for pentanomial basis private static final int PPB_MID_LEN = 3; // All terms number for trinomial basis private static final int TPB_LEN = TPB_MID_LEN + 2; // All terms number for pentanomial basis private static final int PPB_LEN = PPB_MID_LEN + 2; // m value private final int m; // Reduction polynomial private final BigInteger rp; // Mid term(s) of reduction polynomial private final int[] ks; /** * Creates a new {@code ECFieldF2m} with {@code 2^m} elements with a normal * basis. * * @param m * the exponent {@code m} for the number of elements. * @throws IllegalArgumentException * if {@code m <= zero}. */ public ECFieldF2m(int m) { this.m = m; if (this.m <= 0) { throw new IllegalArgumentException("m <= 0"); } this.rp = null; this.ks = null; } /** * Creates a new {@code ECFieldF2m} with {@code 2^m} elements with a polynomial * basis and the reduction polynomial based on {@code rp}. * <p> * The reduction polynomial must be either <i>trinomial</i> or * <i>pentanomial</i>. * * @param m * the exponent {@code m} for the number of elements. * @param rp * the base of the reduction polynomial with the n-th bit * corresponding to the n-th coefficient of the reduction * polynomial. * @throws IllegalArgumentException * if {@code m <= zero} or the {@code rp} is invalid. */ public ECFieldF2m(int m, BigInteger rp) { this.m = m; if (this.m <= 0) { throw new IllegalArgumentException("m <= 0"); } this.rp = rp; if (this.rp == null) { throw new NullPointerException("rp == null"); } // the leftmost bit must be (m+1)-th one, // set bits count must be 3 or 5, // bits 0 and m must be set int rp_bc = this.rp.bitCount(); if ((this.rp.bitLength() != (m+1)) || (rp_bc != TPB_LEN && rp_bc != PPB_LEN) || (!this.rp.testBit(0) || !this.rp.testBit(m)) ) { throw new IllegalArgumentException("rp is invalid"); } // setup ks using rp: // allocate for mid terms only ks = new int[rp_bc-2]; // find midterm orders and set ks accordingly BigInteger rpTmp = rp.clearBit(0); for (int i=ks.length-1; i>=0; i-- ) { ks[i] = rpTmp.getLowestSetBit(); rpTmp = rpTmp.clearBit(ks[i]); } } /** * Creates a new {@code ECFieldF2m} with {@code 2^m} elements with * a polynomial basis and the reduction polynomial based on {@code ks}. * <p> * The reduction polynomial must be either <i>trinomial</i> or * <i>pentanomial</i>. * * @param m * the exponent {@code m} for the number of elements. * @param ks * the base of the reduction polynomial with coefficients * given in descending order. * @throws IllegalArgumentException * if {@code m <= zero} or the reduction polynomial is not * valid. */ public ECFieldF2m(int m, int[] ks) { this.m = m; if (this.m <= 0) { throw new IllegalArgumentException("m <= 0"); } // Defensively copies array parameter // to prevent subsequent modification. // NPE as specified if ks is null this.ks = new int[ks.length]; System.arraycopy(ks, 0, this.ks, 0, this.ks.length); // no need to check for null already if (this.ks.length != TPB_MID_LEN && this.ks.length != PPB_MID_LEN) { // must be either trinomial or pentanomial basis throw new IllegalArgumentException("the length of ks is invalid"); } // trinomial basis: // check that m > k >= 1, where k is ks[0] // pentanomial basis: // check that m > k3 > k2 > k1 >= 1 // and kx in descending order, where // k3 is ks[0], k2 is ks[1], k1 is ks[2] boolean checkFailed = false; int prev = this.m; for (int i=0; i<this.ks.length; i++) { if (this.ks[i] < prev) { prev = this.ks[i]; continue; } checkFailed = true; break; } if (checkFailed || prev < 1) { throw new IllegalArgumentException("ks is invalid"); } // Setup rp using ks: // bits 0 and m always set BigInteger rpTmp = BigInteger.ONE.setBit(this.m); // set remaining bits according to ks for (int i=0; i<this.ks.length; i++) { rpTmp = rpTmp.setBit(this.ks[i]); } rp = rpTmp; } /** * Returns whether the specified object equals to this finite field. * * @param obj * the object to compare to this finite field. * @return {@code true} if the specified object is equal to this finite field, * otherwise {@code false}. */ public boolean equals(Object obj) { // object equals to itself if (this == obj) { return true; } if (obj instanceof ECFieldF2m) { ECFieldF2m o = (ECFieldF2m)obj; // check m if (this.m == o.m) { // check rp if (this.rp == null) { if (o.rp == null) { // fields both with normal basis return true; } } else { // at least this field with polynomial basis // check that rp match // return this.rp.equals(o.rp); return Arrays.equals(this.ks, o.ks); } } } return false; } /** * Returns the size of this finite field (in bits). * * @return the size of this finite field (in bits). */ public int getFieldSize() { return m; } /** * Returns the exponent {@code m} for this finite field, with {@code 2^m} as * the number of elements. * * @return the exponent {@code m} for this finite field */ public int getM() { return m; } /** * Returns a copy of the integer array containing the order of the middle * term(s) of the reduction polynomial for a polynomial basis. * * @return a copy of the integer array containing the order of the middle * term(s) of the reduction polynomial for a polynomial basis or * {@code null} for a normal basis. */ public int[] getMidTermsOfReductionPolynomial() { // Defensively copies private array // to prevent subsequent modification // was: return ks == null ? null : (int[])ks.clone(); if (ks == null) { return null; } else { int[] ret = new int[ks.length]; System.arraycopy(ks, 0, ret, 0, ret.length); return ret; } } /** * Returns the base of the reduction polynomial with the n-th bit * corresponding to the n-th coefficient of the reduction polynomial for a * polynomial basis. * * @return the base of the reduction polynomial with the n-th bit * corresponding to the n-th coefficient of the reduction polynomial * for a polynomial basis or {@code null} for a normal basis. */ public BigInteger getReductionPolynomial() { return rp; } /** * Returns the hashcode value for this finite field. * * @return the hashcode value for this finite field. */ public int hashCode() { return rp == null ? m : m + rp.hashCode(); } }