mirror LGPL code from openJDK11
Change-Id: Id81e065dc9dc2820a9b744c59f0e713478183812
diff --git a/jdk.crypto.ec/share/classes/module-info.java b/jdk.crypto.ec/share/classes/module-info.java
new file mode 100644
index 0000000..9ba6e61
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/module-info.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides the implementation of the SunEC security provider.
+ *
+ * @provides java.security.Provider
+ *
+ * @moduleGraph
+ * @since 9
+ */
+module jdk.crypto.ec {
+ provides java.security.Provider with sun.security.ec.SunEC;
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/ECDHKeyAgreement.java b/jdk.crypto.ec/share/classes/sun/security/ec/ECDHKeyAgreement.java
new file mode 100644
index 0000000..800252b
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/ECDHKeyAgreement.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.math.*;
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.*;
+import java.util.Optional;
+
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+import sun.security.util.ArrayUtil;
+import sun.security.util.ECUtil;
+import sun.security.util.math.*;
+import sun.security.ec.point.*;
+
+/**
+ * KeyAgreement implementation for ECDH.
+ *
+ * @since 1.7
+ */
+public final class ECDHKeyAgreement extends KeyAgreementSpi {
+
+ // private key, if initialized
+ private ECPrivateKey privateKey;
+
+ // public key, non-null between doPhase() & generateSecret() only
+ private ECPublicKey publicKey;
+
+ // length of the secret to be derived
+ private int secretLen;
+
+ /**
+ * Constructs a new ECDHKeyAgreement.
+ */
+ public ECDHKeyAgreement() {
+ }
+
+ // see JCE spec
+ @Override
+ protected void engineInit(Key key, SecureRandom random)
+ throws InvalidKeyException {
+ if (!(key instanceof PrivateKey)) {
+ throw new InvalidKeyException
+ ("Key must be instance of PrivateKey");
+ }
+ privateKey = (ECPrivateKey) ECKeyFactory.toECKey(key);
+ publicKey = null;
+ }
+
+ // see JCE spec
+ @Override
+ protected void engineInit(Key key, AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
+ if (params != null) {
+ throw new InvalidAlgorithmParameterException
+ ("Parameters not supported");
+ }
+ engineInit(key, random);
+ }
+
+ // see JCE spec
+ @Override
+ protected Key engineDoPhase(Key key, boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException {
+ if (privateKey == null) {
+ throw new IllegalStateException("Not initialized");
+ }
+ if (publicKey != null) {
+ throw new IllegalStateException("Phase already executed");
+ }
+ if (!lastPhase) {
+ throw new IllegalStateException
+ ("Only two party agreement supported, lastPhase must be true");
+ }
+ if (!(key instanceof ECPublicKey)) {
+ throw new InvalidKeyException
+ ("Key must be a PublicKey with algorithm EC");
+ }
+
+ this.publicKey = (ECPublicKey) key;
+
+ ECParameterSpec params = publicKey.getParams();
+
+ byte[] publicValue;
+ if (publicKey instanceof ECPublicKeyImpl) {
+ publicValue = ((ECPublicKeyImpl)publicKey).getEncodedPublicValue();
+ } else { // instanceof ECPublicKey
+ publicValue = ECUtil.encodePoint(publicKey.getW(), params.getCurve());
+ }
+ // Check that the public key is on the private key's curve.
+ byte[] encodedPrivateKeyParams = // DER OID
+ ECUtil.encodeECParameterSpec(null, privateKey.getParams());
+ if (!validatePublicKey(encodedPrivateKeyParams, publicValue)) {
+ throw new InvalidKeyException
+ ("Public key must be on the private key's curve");
+ }
+ // Get the keyLenBits from the privateKey's curve.
+ int keyLenBits = privateKey.getParams().getCurve().getField().getFieldSize();
+ secretLen = (keyLenBits + 7) >> 3;
+
+ return null;
+ }
+
+ private static void validateCoordinate(BigInteger c, BigInteger mod) {
+ if (c.compareTo(BigInteger.ZERO) < 0) {
+ throw new ProviderException("invalid coordinate");
+ }
+
+ if (c.compareTo(mod) >= 0) {
+ throw new ProviderException("invalid coordinate");
+ }
+ }
+
+ /*
+ * Check whether a public key is valid. Throw ProviderException
+ * if it is not valid or could not be validated.
+ */
+ private static void validate(ECOperations ops, ECPublicKey key) {
+
+ // ensure that integers are in proper range
+ BigInteger x = key.getW().getAffineX();
+ BigInteger y = key.getW().getAffineY();
+
+ BigInteger p = ops.getField().getSize();
+ validateCoordinate(x, p);
+ validateCoordinate(y, p);
+
+ // ensure the point is on the curve
+ EllipticCurve curve = key.getParams().getCurve();
+ BigInteger rhs = x.modPow(BigInteger.valueOf(3), p).add(curve.getA()
+ .multiply(x)).add(curve.getB()).mod(p);
+ BigInteger lhs = y.modPow(BigInteger.valueOf(2), p).mod(p);
+ if (!rhs.equals(lhs)) {
+ throw new ProviderException("point is not on curve");
+ }
+
+ // check the order of the point
+ ImmutableIntegerModuloP xElem = ops.getField().getElement(x);
+ ImmutableIntegerModuloP yElem = ops.getField().getElement(y);
+ AffinePoint affP = new AffinePoint(xElem, yElem);
+ byte[] order = key.getParams().getOrder().toByteArray();
+ ArrayUtil.reverse(order);
+ Point product = ops.multiply(affP, order);
+ if (!ops.isNeutral(product)) {
+ throw new ProviderException("point has incorrect order");
+ }
+
+ }
+
+ // see JCE spec
+ @Override
+ protected byte[] engineGenerateSecret() throws IllegalStateException {
+ if ((privateKey == null) || (publicKey == null)) {
+ throw new IllegalStateException("Not initialized correctly");
+ }
+
+ Optional<byte[]> resultOpt = deriveKeyImpl(privateKey, publicKey);
+ return resultOpt.orElseGet(
+ () -> deriveKeyNative(privateKey, publicKey)
+ );
+ }
+
+ // see JCE spec
+ @Override
+ protected int engineGenerateSecret(byte[] sharedSecret, int
+ offset) throws IllegalStateException, ShortBufferException {
+ if (secretLen > sharedSecret.length - offset) {
+ throw new ShortBufferException("Need " + secretLen
+ + " bytes, only " + (sharedSecret.length - offset)
+ + " available");
+ }
+ byte[] secret = engineGenerateSecret();
+ System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
+ return secret.length;
+ }
+
+ // see JCE spec
+ @Override
+ protected SecretKey engineGenerateSecret(String algorithm)
+ throws IllegalStateException, NoSuchAlgorithmException,
+ InvalidKeyException {
+ if (algorithm == null) {
+ throw new NoSuchAlgorithmException("Algorithm must not be null");
+ }
+ if (!(algorithm.equals("TlsPremasterSecret"))) {
+ throw new NoSuchAlgorithmException
+ ("Only supported for algorithm TlsPremasterSecret");
+ }
+ return new SecretKeySpec(engineGenerateSecret(), "TlsPremasterSecret");
+ }
+
+ private static
+ Optional<byte[]> deriveKeyImpl(ECPrivateKey priv, ECPublicKey pubKey) {
+
+ ECParameterSpec ecSpec = priv.getParams();
+ EllipticCurve curve = ecSpec.getCurve();
+ Optional<ECOperations> opsOpt = ECOperations.forParameters(ecSpec);
+ if (opsOpt.isEmpty()) {
+ return Optional.empty();
+ }
+ ECOperations ops = opsOpt.get();
+ if (! (priv instanceof ECPrivateKeyImpl)) {
+ return Optional.empty();
+ }
+ ECPrivateKeyImpl privImpl = (ECPrivateKeyImpl) priv;
+ byte[] sArr = privImpl.getArrayS();
+
+ // to match the native implementation, validate the public key here
+ // and throw ProviderException if it is invalid
+ validate(ops, pubKey);
+
+ IntegerFieldModuloP field = ops.getField();
+ // convert s array into field element and multiply by the cofactor
+ MutableIntegerModuloP scalar = field.getElement(sArr).mutable();
+ SmallValue cofactor =
+ field.getSmallValue(priv.getParams().getCofactor());
+ scalar.setProduct(cofactor);
+ int keySize = (curve.getField().getFieldSize() + 7) / 8;
+ byte[] privArr = scalar.asByteArray(keySize);
+
+ ImmutableIntegerModuloP x =
+ field.getElement(pubKey.getW().getAffineX());
+ ImmutableIntegerModuloP y =
+ field.getElement(pubKey.getW().getAffineY());
+ AffinePoint affPub = new AffinePoint(x, y);
+ Point product = ops.multiply(affPub, privArr);
+ if (ops.isNeutral(product)) {
+ throw new ProviderException("Product is zero");
+ }
+ AffinePoint affProduct = product.asAffine();
+
+ byte[] result = affProduct.getX().asByteArray(keySize);
+ ArrayUtil.reverse(result);
+
+ return Optional.of(result);
+ }
+
+ private static
+ byte[] deriveKeyNative(ECPrivateKey privateKey, ECPublicKey publicKey) {
+
+ ECParameterSpec params = privateKey.getParams();
+ byte[] s = privateKey.getS().toByteArray();
+ byte[] encodedParams = // DER OID
+ ECUtil.encodeECParameterSpec(null, params);
+
+ byte[] publicValue;
+ if (publicKey instanceof ECPublicKeyImpl) {
+ ECPublicKeyImpl ecPub = (ECPublicKeyImpl) publicKey;
+ publicValue = ecPub.getEncodedPublicValue();
+ } else { // instanceof ECPublicKey
+ publicValue =
+ ECUtil.encodePoint(publicKey.getW(), params.getCurve());
+ }
+
+ try {
+ return deriveKey(s, publicValue, encodedParams);
+
+ } catch (GeneralSecurityException e) {
+ throw new ProviderException("Could not derive key", e);
+ }
+ }
+
+ /**
+ * Tells whether a public key is on the private key's curve.
+ *
+ * @param encodedParams the private key's curve's DER encoded object identifier.
+ * @param publicKey the public key's W point (in uncompressed form).
+ *
+ * @return true if the public key is on the private key's curve; false otherwise.
+ */
+ private static native boolean validatePublicKey(byte[] encodedParams, byte[] publicKey);
+
+ /**
+ * Generates a secret key using the public and private keys.
+ *
+ * @param s the private key's S value.
+ * @param w the public key's W point (in uncompressed form).
+ * @param encodedParams the curve's DER encoded object identifier.
+ *
+ * @return byte[] the secret key.
+ */
+ private static native byte[] deriveKey(byte[] s, byte[] w,
+ byte[] encodedParams) throws GeneralSecurityException;
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/ECDSAOperations.java b/jdk.crypto.ec/share/classes/sun/security/ec/ECDSAOperations.java
new file mode 100644
index 0000000..3c2f9eb
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/ECDSAOperations.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import sun.security.ec.point.*;
+import sun.security.util.ArrayUtil;
+import sun.security.util.math.*;
+import static sun.security.ec.ECOperations.IntermediateValueException;
+
+import java.security.ProviderException;
+import java.security.spec.*;
+import java.util.Optional;
+
+public class ECDSAOperations {
+
+ public static class Seed {
+ private final byte[] seedValue;
+
+ public Seed(byte[] seedValue) {
+ this.seedValue = seedValue;
+ }
+
+ public byte[] getSeedValue() {
+ return seedValue;
+ }
+ }
+
+ public static class Nonce {
+ private final byte[] nonceValue;
+
+ public Nonce(byte[] nonceValue) {
+ this.nonceValue = nonceValue;
+ }
+
+ public byte[] getNonceValue() {
+ return nonceValue;
+ }
+ }
+
+ private final ECOperations ecOps;
+ private final AffinePoint basePoint;
+
+ public ECDSAOperations(ECOperations ecOps, ECPoint basePoint) {
+ this.ecOps = ecOps;
+ this.basePoint = toAffinePoint(basePoint, ecOps.getField());
+ }
+
+ public ECOperations getEcOperations() {
+ return ecOps;
+ }
+
+ public AffinePoint basePointMultiply(byte[] scalar) {
+ return ecOps.multiply(basePoint, scalar).asAffine();
+ }
+
+ public static AffinePoint toAffinePoint(ECPoint point,
+ IntegerFieldModuloP field) {
+
+ ImmutableIntegerModuloP affineX = field.getElement(point.getAffineX());
+ ImmutableIntegerModuloP affineY = field.getElement(point.getAffineY());
+ return new AffinePoint(affineX, affineY);
+ }
+
+ public static
+ Optional<ECDSAOperations> forParameters(ECParameterSpec ecParams) {
+ Optional<ECOperations> curveOps =
+ ECOperations.forParameters(ecParams);
+ return curveOps.map(
+ ops -> new ECDSAOperations(ops, ecParams.getGenerator())
+ );
+ }
+
+ /**
+ *
+ * Sign a digest using the provided private key and seed.
+ * IMPORTANT: The private key is a scalar represented using a
+ * little-endian byte array. This is backwards from the conventional
+ * representation in ECDSA. The routines that produce and consume this
+ * value uses little-endian, so this deviation from convention removes
+ * the requirement to swap the byte order. The returned signature is in
+ * the conventional byte order.
+ *
+ * @param privateKey the private key scalar as a little-endian byte array
+ * @param digest the digest to be signed
+ * @param seed the seed that will be used to produce the nonce. This object
+ * should contain an array that is at least 64 bits longer than
+ * the number of bits required to represent the group order.
+ * @return the ECDSA signature value
+ * @throws IntermediateValueException if the signature cannot be produced
+ * due to an unacceptable intermediate or final value. If this
+ * exception is thrown, then the caller should discard the nonnce and
+ * try again with an entirely new nonce value.
+ */
+ public byte[] signDigest(byte[] privateKey, byte[] digest, Seed seed)
+ throws IntermediateValueException {
+
+ byte[] nonceArr = ecOps.seedToScalar(seed.getSeedValue());
+
+ Nonce nonce = new Nonce(nonceArr);
+ return signDigest(privateKey, digest, nonce);
+ }
+
+ /**
+ *
+ * Sign a digest using the provided private key and nonce.
+ * IMPORTANT: The private key and nonce are scalars represented by a
+ * little-endian byte array. This is backwards from the conventional
+ * representation in ECDSA. The routines that produce and consume these
+ * values use little-endian, so this deviation from convention removes
+ * the requirement to swap the byte order. The returned signature is in
+ * the conventional byte order.
+ *
+ * @param privateKey the private key scalar as a little-endian byte array
+ * @param digest the digest to be signed
+ * @param nonce the nonce object containing a little-endian scalar value.
+ * @return the ECDSA signature value
+ * @throws IntermediateValueException if the signature cannot be produced
+ * due to an unacceptable intermediate or final value. If this
+ * exception is thrown, then the caller should discard the nonnce and
+ * try again with an entirely new nonce value.
+ */
+ public byte[] signDigest(byte[] privateKey, byte[] digest, Nonce nonce)
+ throws IntermediateValueException {
+
+ IntegerFieldModuloP orderField = ecOps.getOrderField();
+ int orderBits = orderField.getSize().bitLength();
+ if (orderBits % 8 != 0 && orderBits < digest.length * 8) {
+ // This implementation does not support truncating digests to
+ // a length that is not a multiple of 8.
+ throw new ProviderException("Invalid digest length");
+ }
+
+ byte[] k = nonce.getNonceValue();
+ // check nonce length
+ int length = (orderField.getSize().bitLength() + 7) / 8;
+ if (k.length != length) {
+ throw new ProviderException("Incorrect nonce length");
+ }
+
+ MutablePoint R = ecOps.multiply(basePoint, k);
+ IntegerModuloP r = R.asAffine().getX();
+ // put r into the correct field by fully reducing to an array
+ byte[] temp = new byte[length];
+ r.asByteArray(temp);
+ r = orderField.getElement(temp);
+ // store r in result
+ r.asByteArray(temp);
+ byte[] result = new byte[2 * length];
+ ArrayUtil.reverse(temp);
+ System.arraycopy(temp, 0, result, 0, length);
+ // compare r to 0
+ if (ECOperations.allZero(temp)) {
+ throw new IntermediateValueException();
+ }
+
+ IntegerModuloP dU = orderField.getElement(privateKey);
+ int lengthE = Math.min(length, digest.length);
+ byte[] E = new byte[lengthE];
+ System.arraycopy(digest, 0, E, 0, lengthE);
+ ArrayUtil.reverse(E);
+ IntegerModuloP e = orderField.getElement(E);
+ IntegerModuloP kElem = orderField.getElement(k);
+ IntegerModuloP kInv = kElem.multiplicativeInverse();
+ MutableIntegerModuloP s = r.mutable();
+ s.setProduct(dU).setSum(e).setProduct(kInv);
+ // store s in result
+ s.asByteArray(temp);
+ ArrayUtil.reverse(temp);
+ System.arraycopy(temp, 0, result, length, length);
+ // compare s to 0
+ if (ECOperations.allZero(temp)) {
+ throw new IntermediateValueException();
+ }
+
+ return result;
+
+ }
+
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java b/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java
new file mode 100644
index 0000000..a4d2378
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java
@@ -0,0 +1,667 @@
+/*
+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.math.BigInteger;
+
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.*;
+import java.util.Optional;
+
+import sun.security.jca.JCAUtil;
+import sun.security.util.*;
+import static sun.security.ec.ECOperations.IntermediateValueException;
+
+/**
+ * ECDSA signature implementation. This class currently supports the
+ * following algorithm names:
+ *
+ * . "NONEwithECDSA"
+ * . "SHA1withECDSA"
+ * . "SHA224withECDSA"
+ * . "SHA256withECDSA"
+ * . "SHA384withECDSA"
+ * . "SHA512withECDSA"
+ * . "NONEwithECDSAinP1363Format"
+ * . "SHA1withECDSAinP1363Format"
+ * . "SHA224withECDSAinP1363Format"
+ * . "SHA256withECDSAinP1363Format"
+ * . "SHA384withECDSAinP1363Format"
+ * . "SHA512withECDSAinP1363Format"
+ *
+ * @since 1.7
+ */
+abstract class ECDSASignature extends SignatureSpi {
+
+ // message digest implementation we use
+ private final MessageDigest messageDigest;
+
+ // supplied entropy
+ private SecureRandom random;
+
+ // flag indicating whether the digest has been reset
+ private boolean needsReset;
+
+ // private key, if initialized for signing
+ private ECPrivateKey privateKey;
+
+ // public key, if initialized for verifying
+ private ECPublicKey publicKey;
+
+ // signature parameters
+ private ECParameterSpec sigParams = null;
+
+ // The format. true for the IEEE P1363 format. false (default) for ASN.1
+ private final boolean p1363Format;
+
+ /**
+ * Constructs a new ECDSASignature.
+ *
+ * @exception ProviderException if the native ECC library is unavailable.
+ */
+ ECDSASignature() {
+ this(false);
+ }
+
+ /**
+ * Constructs a new ECDSASignature that will use the specified
+ * signature format. {@code p1363Format} should be {@code true} to
+ * use the IEEE P1363 format. If {@code p1363Format} is {@code false},
+ * the DER-encoded ASN.1 format will be used. This constructor is
+ * used by the RawECDSA subclasses.
+ */
+ ECDSASignature(boolean p1363Format) {
+ this.messageDigest = null;
+ this.p1363Format = p1363Format;
+ }
+
+ /**
+ * Constructs a new ECDSASignature. Used by subclasses.
+ */
+ ECDSASignature(String digestName) {
+ this(digestName, false);
+ }
+
+ /**
+ * Constructs a new ECDSASignature that will use the specified
+ * digest and signature format. {@code p1363Format} should be
+ * {@code true} to use the IEEE P1363 format. If {@code p1363Format}
+ * is {@code false}, the DER-encoded ASN.1 format will be used. This
+ * constructor is used by subclasses.
+ */
+ ECDSASignature(String digestName, boolean p1363Format) {
+ try {
+ messageDigest = MessageDigest.getInstance(digestName);
+ } catch (NoSuchAlgorithmException e) {
+ throw new ProviderException(e);
+ }
+ this.needsReset = false;
+ this.p1363Format = p1363Format;
+ }
+
+ // Class for Raw ECDSA signatures.
+ static class RawECDSA extends ECDSASignature {
+
+ // the longest supported digest is 512 bits (SHA-512)
+ private static final int RAW_ECDSA_MAX = 64;
+
+ private final byte[] precomputedDigest;
+ private int offset = 0;
+
+ RawECDSA(boolean p1363Format) {
+ super(p1363Format);
+ precomputedDigest = new byte[RAW_ECDSA_MAX];
+ }
+
+ // Stores the precomputed message digest value.
+ @Override
+ protected void engineUpdate(byte b) throws SignatureException {
+ if (offset >= precomputedDigest.length) {
+ offset = RAW_ECDSA_MAX + 1;
+ return;
+ }
+ precomputedDigest[offset++] = b;
+ }
+
+ // Stores the precomputed message digest value.
+ @Override
+ protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException {
+ if (offset >= precomputedDigest.length) {
+ offset = RAW_ECDSA_MAX + 1;
+ return;
+ }
+ System.arraycopy(b, off, precomputedDigest, offset, len);
+ offset += len;
+ }
+
+ // Stores the precomputed message digest value.
+ @Override
+ protected void engineUpdate(ByteBuffer byteBuffer) {
+ int len = byteBuffer.remaining();
+ if (len <= 0) {
+ return;
+ }
+ if (len >= precomputedDigest.length - offset) {
+ offset = RAW_ECDSA_MAX + 1;
+ return;
+ }
+ byteBuffer.get(precomputedDigest, offset, len);
+ offset += len;
+ }
+
+ @Override
+ protected void resetDigest() {
+ offset = 0;
+ }
+
+ // Returns the precomputed message digest value.
+ @Override
+ protected byte[] getDigestValue() throws SignatureException {
+ if (offset > RAW_ECDSA_MAX) {
+ throw new SignatureException("Message digest is too long");
+
+ }
+ byte[] result = new byte[offset];
+ System.arraycopy(precomputedDigest, 0, result, 0, offset);
+ offset = 0;
+
+ return result;
+ }
+ }
+
+ // Nested class for NONEwithECDSA signatures
+ public static final class Raw extends RawECDSA {
+ public Raw() {
+ super(false);
+ }
+ }
+
+ // Nested class for NONEwithECDSAinP1363Format signatures
+ public static final class RawinP1363Format extends RawECDSA {
+ public RawinP1363Format() {
+ super(true);
+ }
+ }
+
+ // Nested class for SHA1withECDSA signatures
+ public static final class SHA1 extends ECDSASignature {
+ public SHA1() {
+ super("SHA1");
+ }
+ }
+
+ // Nested class for SHA1withECDSAinP1363Format signatures
+ public static final class SHA1inP1363Format extends ECDSASignature {
+ public SHA1inP1363Format() {
+ super("SHA1", true);
+ }
+ }
+
+ // Nested class for SHA224withECDSA signatures
+ public static final class SHA224 extends ECDSASignature {
+ public SHA224() {
+ super("SHA-224");
+ }
+ }
+
+ // Nested class for SHA224withECDSAinP1363Format signatures
+ public static final class SHA224inP1363Format extends ECDSASignature {
+ public SHA224inP1363Format() {
+ super("SHA-224", true);
+ }
+ }
+
+ // Nested class for SHA256withECDSA signatures
+ public static final class SHA256 extends ECDSASignature {
+ public SHA256() {
+ super("SHA-256");
+ }
+ }
+
+ // Nested class for SHA256withECDSAinP1363Format signatures
+ public static final class SHA256inP1363Format extends ECDSASignature {
+ public SHA256inP1363Format() {
+ super("SHA-256", true);
+ }
+ }
+
+ // Nested class for SHA384withECDSA signatures
+ public static final class SHA384 extends ECDSASignature {
+ public SHA384() {
+ super("SHA-384");
+ }
+ }
+
+ // Nested class for SHA384withECDSAinP1363Format signatures
+ public static final class SHA384inP1363Format extends ECDSASignature {
+ public SHA384inP1363Format() {
+ super("SHA-384", true);
+ }
+ }
+
+ // Nested class for SHA512withECDSA signatures
+ public static final class SHA512 extends ECDSASignature {
+ public SHA512() {
+ super("SHA-512");
+ }
+ }
+
+ // Nested class for SHA512withECDSAinP1363Format signatures
+ public static final class SHA512inP1363Format extends ECDSASignature {
+ public SHA512inP1363Format() {
+ super("SHA-512", true);
+ }
+ }
+
+ // initialize for verification. See JCA doc
+ @Override
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException {
+ ECPublicKey key = (ECPublicKey) ECKeyFactory.toECKey(publicKey);
+ if (!isCompatible(this.sigParams, key.getParams())) {
+ throw new InvalidKeyException("Key params does not match signature params");
+ }
+
+ // Should check that the supplied key is appropriate for signature
+ // algorithm (e.g. P-256 for SHA256withECDSA)
+ this.publicKey = key;
+ this.privateKey = null;
+ resetDigest();
+ }
+
+ // initialize for signing. See JCA doc
+ @Override
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException {
+ engineInitSign(privateKey, null);
+ }
+
+ // initialize for signing. See JCA doc
+ @Override
+ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
+ throws InvalidKeyException {
+ ECPrivateKey key = (ECPrivateKey) ECKeyFactory.toECKey(privateKey);
+ if (!isCompatible(this.sigParams, key.getParams())) {
+ throw new InvalidKeyException("Key params does not match signature params");
+ }
+
+ // Should check that the supplied key is appropriate for signature
+ // algorithm (e.g. P-256 for SHA256withECDSA)
+ this.privateKey = key;
+ this.publicKey = null;
+ this.random = random;
+ resetDigest();
+ }
+
+ /**
+ * Resets the message digest if needed.
+ */
+ protected void resetDigest() {
+ if (needsReset) {
+ if (messageDigest != null) {
+ messageDigest.reset();
+ }
+ needsReset = false;
+ }
+ }
+
+ /**
+ * Returns the message digest value.
+ */
+ protected byte[] getDigestValue() throws SignatureException {
+ needsReset = false;
+ return messageDigest.digest();
+ }
+
+ // update the signature with the plaintext data. See JCA doc
+ @Override
+ protected void engineUpdate(byte b) throws SignatureException {
+ messageDigest.update(b);
+ needsReset = true;
+ }
+
+ // update the signature with the plaintext data. See JCA doc
+ @Override
+ protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException {
+ messageDigest.update(b, off, len);
+ needsReset = true;
+ }
+
+ // update the signature with the plaintext data. See JCA doc
+ @Override
+ protected void engineUpdate(ByteBuffer byteBuffer) {
+ int len = byteBuffer.remaining();
+ if (len <= 0) {
+ return;
+ }
+
+ messageDigest.update(byteBuffer);
+ needsReset = true;
+ }
+
+ private static boolean isCompatible(ECParameterSpec sigParams,
+ ECParameterSpec keyParams) {
+ if (sigParams == null) {
+ // no restriction on key param
+ return true;
+ }
+ return ECUtil.equals(sigParams, keyParams);
+ }
+
+
+ private byte[] signDigestImpl(ECDSAOperations ops, int seedBits,
+ byte[] digest, ECPrivateKeyImpl privImpl, SecureRandom random)
+ throws SignatureException {
+
+ byte[] seedBytes = new byte[(seedBits + 7) / 8];
+ byte[] s = privImpl.getArrayS();
+
+ // Attempt to create the signature in a loop that uses new random input
+ // each time. The chance of failure is very small assuming the
+ // implementation derives the nonce using extra bits
+ int numAttempts = 128;
+ for (int i = 0; i < numAttempts; i++) {
+ random.nextBytes(seedBytes);
+ ECDSAOperations.Seed seed = new ECDSAOperations.Seed(seedBytes);
+ try {
+ return ops.signDigest(s, digest, seed);
+ } catch (IntermediateValueException ex) {
+ // try again in the next iteration
+ }
+ }
+
+ throw new SignatureException("Unable to produce signature after "
+ + numAttempts + " attempts");
+ }
+
+
+ private Optional<byte[]> signDigestImpl(ECPrivateKey privateKey,
+ byte[] digest, SecureRandom random) throws SignatureException {
+
+ if (! (privateKey instanceof ECPrivateKeyImpl)) {
+ return Optional.empty();
+ }
+ ECPrivateKeyImpl privImpl = (ECPrivateKeyImpl) privateKey;
+ ECParameterSpec params = privateKey.getParams();
+
+ // seed is the key size + 64 bits
+ int seedBits = params.getOrder().bitLength() + 64;
+ Optional<ECDSAOperations> opsOpt =
+ ECDSAOperations.forParameters(params);
+ if (opsOpt.isEmpty()) {
+ return Optional.empty();
+ } else {
+ byte[] sig = signDigestImpl(opsOpt.get(), seedBits, digest,
+ privImpl, random);
+ return Optional.of(sig);
+ }
+ }
+
+ private byte[] signDigestNative(ECPrivateKey privateKey, byte[] digest,
+ SecureRandom random) throws SignatureException {
+
+ byte[] s = privateKey.getS().toByteArray();
+ ECParameterSpec params = privateKey.getParams();
+
+ // DER OID
+ byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);
+ int orderLength = params.getOrder().bitLength();
+
+ // seed is twice the order length (in bytes) plus 1
+ byte[] seed = new byte[(((orderLength + 7) >> 3) + 1) * 2];
+
+ random.nextBytes(seed);
+
+ // random bits needed for timing countermeasures
+ int timingArgument = random.nextInt();
+ // values must be non-zero to enable countermeasures
+ timingArgument |= 1;
+
+ try {
+ return signDigest(digest, s, encodedParams, seed,
+ timingArgument);
+ } catch (GeneralSecurityException e) {
+ throw new SignatureException("Could not sign data", e);
+ }
+
+ }
+
+ // sign the data and return the signature. See JCA doc
+ @Override
+ protected byte[] engineSign() throws SignatureException {
+
+ if (random == null) {
+ random = JCAUtil.getSecureRandom();
+ }
+
+ byte[] digest = getDigestValue();
+ Optional<byte[]> sigOpt = signDigestImpl(privateKey, digest, random);
+ byte[] sig;
+ if (sigOpt.isPresent()) {
+ sig = sigOpt.get();
+ } else {
+ sig = signDigestNative(privateKey, digest, random);
+ }
+
+ if (p1363Format) {
+ return sig;
+ } else {
+ return ECUtil.encodeSignature(sig);
+ }
+ }
+
+ // verify the data and return the result. See JCA doc
+ @Override
+ protected boolean engineVerify(byte[] signature) throws SignatureException {
+
+ byte[] w;
+ ECParameterSpec params = publicKey.getParams();
+ // DER OID
+ byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);
+
+ if (publicKey instanceof ECPublicKeyImpl) {
+ w = ((ECPublicKeyImpl) publicKey).getEncodedPublicValue();
+ } else { // instanceof ECPublicKey
+ w = ECUtil.encodePoint(publicKey.getW(), params.getCurve());
+ }
+
+ byte[] sig;
+ if (p1363Format) {
+ sig = signature;
+ } else {
+ sig = ECUtil.decodeSignature(signature);
+ }
+
+ try {
+ return verifySignedDigest(sig, getDigestValue(), w, encodedParams);
+ } catch (GeneralSecurityException e) {
+ throw new SignatureException("Could not verify signature", e);
+ }
+ }
+
+ // set parameter, not supported. See JCA doc
+ @Override
+ @Deprecated
+ protected void engineSetParameter(String param, Object value)
+ throws InvalidParameterException {
+ throw new UnsupportedOperationException("setParameter() not supported");
+ }
+
+ @Override
+ protected void engineSetParameter(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException {
+ if (params != null && !(params instanceof ECParameterSpec)) {
+ throw new InvalidAlgorithmParameterException("No parameter accepted");
+ }
+ ECKey key = (this.privateKey == null? this.publicKey : this.privateKey);
+ if ((key != null) && !isCompatible((ECParameterSpec)params, key.getParams())) {
+ throw new InvalidAlgorithmParameterException
+ ("Signature params does not match key params");
+ }
+
+ sigParams = (ECParameterSpec) params;
+ }
+
+ // get parameter, not supported. See JCA doc
+ @Override
+ @Deprecated
+ protected Object engineGetParameter(String param)
+ throws InvalidParameterException {
+ throw new UnsupportedOperationException("getParameter() not supported");
+ }
+
+ @Override
+ protected AlgorithmParameters engineGetParameters() {
+ if (sigParams == null) {
+ return null;
+ }
+ try {
+ AlgorithmParameters ap = AlgorithmParameters.getInstance("EC");
+ ap.init(sigParams);
+ return ap;
+ } catch (Exception e) {
+ // should never happen
+ throw new ProviderException("Error retrieving EC parameters", e);
+ }
+ }
+
+ // Convert the concatenation of R and S into their DER encoding
+ private byte[] encodeSignature(byte[] signature) throws SignatureException {
+
+ try {
+
+ int n = signature.length >> 1;
+ byte[] bytes = new byte[n];
+ System.arraycopy(signature, 0, bytes, 0, n);
+ BigInteger r = new BigInteger(1, bytes);
+ System.arraycopy(signature, n, bytes, 0, n);
+ BigInteger s = new BigInteger(1, bytes);
+
+ DerOutputStream out = new DerOutputStream(signature.length + 10);
+ out.putInteger(r);
+ out.putInteger(s);
+ DerValue result =
+ new DerValue(DerValue.tag_Sequence, out.toByteArray());
+
+ return result.toByteArray();
+
+ } catch (Exception e) {
+ throw new SignatureException("Could not encode signature", e);
+ }
+ }
+
+ // Convert the DER encoding of R and S into a concatenation of R and S
+ private byte[] decodeSignature(byte[] sig) throws SignatureException {
+
+ try {
+ // Enforce strict DER checking for signatures
+ DerInputStream in = new DerInputStream(sig, 0, sig.length, false);
+ DerValue[] values = in.getSequence(2);
+
+ // check number of components in the read sequence
+ // and trailing data
+ if ((values.length != 2) || (in.available() != 0)) {
+ throw new IOException("Invalid encoding for signature");
+ }
+
+ BigInteger r = values[0].getPositiveBigInteger();
+ BigInteger s = values[1].getPositiveBigInteger();
+
+ // trim leading zeroes
+ byte[] rBytes = trimZeroes(r.toByteArray());
+ byte[] sBytes = trimZeroes(s.toByteArray());
+ int k = Math.max(rBytes.length, sBytes.length);
+ // r and s each occupy half the array
+ byte[] result = new byte[k << 1];
+ System.arraycopy(rBytes, 0, result, k - rBytes.length,
+ rBytes.length);
+ System.arraycopy(sBytes, 0, result, result.length - sBytes.length,
+ sBytes.length);
+ if (!MessageDigest.isEqual(sig, encodeSignature(result))) {
+ throw new SignatureException("Invalid signature encoding");
+ }
+ return result;
+
+ } catch (Exception e) {
+ throw new SignatureException("Invalid encoding for signature", e);
+ }
+ }
+
+ // trim leading (most significant) zeroes from the result
+ private static byte[] trimZeroes(byte[] b) {
+ int i = 0;
+ while ((i < b.length - 1) && (b[i] == 0)) {
+ i++;
+ }
+ if (i == 0) {
+ return b;
+ }
+ byte[] t = new byte[b.length - i];
+ System.arraycopy(b, i, t, 0, t.length);
+ return t;
+ }
+
+ /**
+ * Signs the digest using the private key.
+ *
+ * @param digest the digest to be signed.
+ * @param s the private key's S value.
+ * @param encodedParams the curve's DER encoded object identifier.
+ * @param seed the random seed.
+ * @param timing When non-zero, the implmentation will use timing
+ * countermeasures to hide secrets from timing channels. The EC
+ * implementation will disable the countermeasures when this value is
+ * zero, because the underlying EC functions are shared by several
+ * crypto operations, some of which do not use the countermeasures.
+ * The high-order 31 bits must be uniformly random. The entropy from
+ * these bits is used by the countermeasures.
+ *
+ * @return byte[] the signature.
+ */
+ private static native byte[] signDigest(byte[] digest, byte[] s,
+ byte[] encodedParams, byte[] seed, int timing)
+ throws GeneralSecurityException;
+
+ /**
+ * Verifies the signed digest using the public key.
+ *
+ * @param signature the signature to be verified. It is encoded
+ * as a concatenation of the key's R and S values.
+ * @param digest the digest to be used.
+ * @param w the public key's W point (in uncompressed form).
+ * @param encodedParams the curve's DER encoded object identifier.
+ *
+ * @return boolean true if the signature is successfully verified.
+ */
+ private static native boolean verifySignedDigest(byte[] signature,
+ byte[] digest, byte[] w, byte[] encodedParams)
+ throws GeneralSecurityException;
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/ECKeyFactory.java b/jdk.crypto.ec/share/classes/sun/security/ec/ECKeyFactory.java
new file mode 100644
index 0000000..fdcfaa2
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/ECKeyFactory.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.*;
+
+/**
+ * KeyFactory for EC keys. Keys must be instances of PublicKey or PrivateKey
+ * and getAlgorithm() must return "EC". For such keys, it supports conversion
+ * between the following:
+ *
+ * For public keys:
+ * . PublicKey with an X.509 encoding
+ * . ECPublicKey
+ * . ECPublicKeySpec
+ * . X509EncodedKeySpec
+ *
+ * For private keys:
+ * . PrivateKey with a PKCS#8 encoding
+ * . ECPrivateKey
+ * . ECPrivateKeySpec
+ * . PKCS8EncodedKeySpec
+ *
+ * @since 1.6
+ * @author Andreas Sterbenz
+ */
+public final class ECKeyFactory extends KeyFactorySpi {
+
+ // Used by translateKey()
+ private static KeyFactory instance;
+
+ private static KeyFactory getInstance() {
+ if (instance == null) {
+ try {
+ instance = KeyFactory.getInstance("EC", "SunEC");
+ } catch (NoSuchProviderException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ return instance;
+ }
+
+ public ECKeyFactory() {
+ // empty
+ }
+
+ /**
+ * Static method to convert Key into a useable instance of
+ * ECPublicKey or ECPrivateKey. Check the key and convert it
+ * to a Sun key if necessary. If the key is not an EC key
+ * or cannot be used, throw an InvalidKeyException.
+ *
+ * The difference between this method and engineTranslateKey() is that
+ * we do not convert keys of other providers that are already an
+ * instance of ECPublicKey or ECPrivateKey.
+ *
+ * To be used by future Java ECDSA and ECDH implementations.
+ */
+ public static ECKey toECKey(Key key) throws InvalidKeyException {
+ if (key instanceof ECKey) {
+ ECKey ecKey = (ECKey)key;
+ checkKey(ecKey);
+ return ecKey;
+ } else {
+ /*
+ * We don't call the engineTranslateKey method directly
+ * because KeyFactory.translateKey adds code to loop through
+ * all key factories.
+ */
+ return (ECKey)getInstance().translateKey(key);
+ }
+ }
+
+ /**
+ * Check that the given EC key is valid.
+ */
+ private static void checkKey(ECKey key) throws InvalidKeyException {
+ // check for subinterfaces, omit additional checks for our keys
+ if (key instanceof ECPublicKey) {
+ if (key instanceof ECPublicKeyImpl) {
+ return;
+ }
+ } else if (key instanceof ECPrivateKey) {
+ if (key instanceof ECPrivateKeyImpl) {
+ return;
+ }
+ } else {
+ throw new InvalidKeyException("Neither a public nor a private key");
+ }
+ // ECKey does not extend Key, so we need to do a cast
+ String keyAlg = ((Key)key).getAlgorithm();
+ if (keyAlg.equals("EC") == false) {
+ throw new InvalidKeyException("Not an EC key: " + keyAlg);
+ }
+ // XXX further sanity checks about whether this key uses supported
+ // fields, point formats, etc. would go here
+ }
+
+ /**
+ * Translate an EC key into a Sun EC key. If conversion is
+ * not possible, throw an InvalidKeyException.
+ * See also JCA doc.
+ */
+ protected Key engineTranslateKey(Key key) throws InvalidKeyException {
+ if (key == null) {
+ throw new InvalidKeyException("Key must not be null");
+ }
+ String keyAlg = key.getAlgorithm();
+ if (keyAlg.equals("EC") == false) {
+ throw new InvalidKeyException("Not an EC key: " + keyAlg);
+ }
+ if (key instanceof PublicKey) {
+ return implTranslatePublicKey((PublicKey)key);
+ } else if (key instanceof PrivateKey) {
+ return implTranslatePrivateKey((PrivateKey)key);
+ } else {
+ throw new InvalidKeyException("Neither a public nor a private key");
+ }
+ }
+
+ // see JCA doc
+ protected PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException {
+ try {
+ return implGeneratePublic(keySpec);
+ } catch (InvalidKeySpecException e) {
+ throw e;
+ } catch (GeneralSecurityException e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ // see JCA doc
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException {
+ try {
+ return implGeneratePrivate(keySpec);
+ } catch (InvalidKeySpecException e) {
+ throw e;
+ } catch (GeneralSecurityException e) {
+ throw new InvalidKeySpecException(e);
+ }
+ }
+
+ // internal implementation of translateKey() for public keys. See JCA doc
+ private PublicKey implTranslatePublicKey(PublicKey key)
+ throws InvalidKeyException {
+ if (key instanceof ECPublicKey) {
+ if (key instanceof ECPublicKeyImpl) {
+ return key;
+ }
+ ECPublicKey ecKey = (ECPublicKey)key;
+ return new ECPublicKeyImpl(
+ ecKey.getW(),
+ ecKey.getParams()
+ );
+ } else if ("X.509".equals(key.getFormat())) {
+ byte[] encoded = key.getEncoded();
+ return new ECPublicKeyImpl(encoded);
+ } else {
+ throw new InvalidKeyException("Public keys must be instance "
+ + "of ECPublicKey or have X.509 encoding");
+ }
+ }
+
+ // internal implementation of translateKey() for private keys. See JCA doc
+ private PrivateKey implTranslatePrivateKey(PrivateKey key)
+ throws InvalidKeyException {
+ if (key instanceof ECPrivateKey) {
+ if (key instanceof ECPrivateKeyImpl) {
+ return key;
+ }
+ ECPrivateKey ecKey = (ECPrivateKey)key;
+ return new ECPrivateKeyImpl(
+ ecKey.getS(),
+ ecKey.getParams()
+ );
+ } else if ("PKCS#8".equals(key.getFormat())) {
+ return new ECPrivateKeyImpl(key.getEncoded());
+ } else {
+ throw new InvalidKeyException("Private keys must be instance "
+ + "of ECPrivateKey or have PKCS#8 encoding");
+ }
+ }
+
+ // internal implementation of generatePublic. See JCA doc
+ private PublicKey implGeneratePublic(KeySpec keySpec)
+ throws GeneralSecurityException {
+ if (keySpec instanceof X509EncodedKeySpec) {
+ X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;
+ return new ECPublicKeyImpl(x509Spec.getEncoded());
+ } else if (keySpec instanceof ECPublicKeySpec) {
+ ECPublicKeySpec ecSpec = (ECPublicKeySpec)keySpec;
+ return new ECPublicKeyImpl(
+ ecSpec.getW(),
+ ecSpec.getParams()
+ );
+ } else {
+ throw new InvalidKeySpecException("Only ECPublicKeySpec "
+ + "and X509EncodedKeySpec supported for EC public keys");
+ }
+ }
+
+ // internal implementation of generatePrivate. See JCA doc
+ private PrivateKey implGeneratePrivate(KeySpec keySpec)
+ throws GeneralSecurityException {
+ if (keySpec instanceof PKCS8EncodedKeySpec) {
+ PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;
+ return new ECPrivateKeyImpl(pkcsSpec.getEncoded());
+ } else if (keySpec instanceof ECPrivateKeySpec) {
+ ECPrivateKeySpec ecSpec = (ECPrivateKeySpec)keySpec;
+ return new ECPrivateKeyImpl(ecSpec.getS(), ecSpec.getParams());
+ } else {
+ throw new InvalidKeySpecException("Only ECPrivateKeySpec "
+ + "and PKCS8EncodedKeySpec supported for EC private keys");
+ }
+ }
+
+ protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
+ throws InvalidKeySpecException {
+ try {
+ // convert key to one of our keys
+ // this also verifies that the key is a valid EC key and ensures
+ // that the encoding is X.509/PKCS#8 for public/private keys
+ key = engineTranslateKey(key);
+ } catch (InvalidKeyException e) {
+ throw new InvalidKeySpecException(e);
+ }
+ if (key instanceof ECPublicKey) {
+ ECPublicKey ecKey = (ECPublicKey)key;
+ if (keySpec.isAssignableFrom(ECPublicKeySpec.class)) {
+ return keySpec.cast(new ECPublicKeySpec(
+ ecKey.getW(),
+ ecKey.getParams()
+ ));
+ } else if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)) {
+ return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));
+ } else {
+ throw new InvalidKeySpecException
+ ("KeySpec must be ECPublicKeySpec or "
+ + "X509EncodedKeySpec for EC public keys");
+ }
+ } else if (key instanceof ECPrivateKey) {
+ if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) {
+ return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
+ } else if (keySpec.isAssignableFrom(ECPrivateKeySpec.class)) {
+ ECPrivateKey ecKey = (ECPrivateKey)key;
+ return keySpec.cast(new ECPrivateKeySpec(
+ ecKey.getS(),
+ ecKey.getParams()
+ ));
+ } else {
+ throw new InvalidKeySpecException
+ ("KeySpec must be ECPrivateKeySpec or "
+ + "PKCS8EncodedKeySpec for EC private keys");
+ }
+ } else {
+ // should not occur, caught in engineTranslateKey()
+ throw new InvalidKeySpecException("Neither public nor private key");
+ }
+ }
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/ECKeyPairGenerator.java b/jdk.crypto.ec/share/classes/sun/security/ec/ECKeyPairGenerator.java
new file mode 100644
index 0000000..7736fc9
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/ECKeyPairGenerator.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.*;
+import java.util.Optional;
+
+import sun.security.jca.JCAUtil;
+import sun.security.util.ECUtil;
+import sun.security.util.math.*;
+import sun.security.ec.point.*;
+import static sun.security.util.SecurityProviderConstants.DEF_EC_KEY_SIZE;
+import static sun.security.ec.ECOperations.IntermediateValueException;
+
+/**
+ * EC keypair generator.
+ * Standard algorithm, minimum key length is 112 bits, maximum is 571 bits.
+ *
+ * @since 1.7
+ */
+public final class ECKeyPairGenerator extends KeyPairGeneratorSpi {
+
+ private static final int KEY_SIZE_MIN = 112; // min bits (see ecc_impl.h)
+ private static final int KEY_SIZE_MAX = 571; // max bits (see ecc_impl.h)
+
+ // used to seed the keypair generator
+ private SecureRandom random;
+
+ // size of the key to generate, KEY_SIZE_MIN <= keySize <= KEY_SIZE_MAX
+ private int keySize;
+
+ // parameters specified via init, if any
+ private AlgorithmParameterSpec params = null;
+
+ /**
+ * Constructs a new ECKeyPairGenerator.
+ */
+ public ECKeyPairGenerator() {
+ // initialize to default in case the app does not call initialize()
+ initialize(DEF_EC_KEY_SIZE, null);
+ }
+
+ // initialize the generator. See JCA doc
+ @Override
+ public void initialize(int keySize, SecureRandom random) {
+
+ checkKeySize(keySize);
+ this.params = ECUtil.getECParameterSpec(null, keySize);
+ if (params == null) {
+ throw new InvalidParameterException(
+ "No EC parameters available for key size " + keySize + " bits");
+ }
+ this.random = random;
+ }
+
+ // second initialize method. See JCA doc
+ @Override
+ public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+
+ ECParameterSpec ecSpec = null;
+
+ if (params instanceof ECParameterSpec) {
+ ECParameterSpec ecParams = (ECParameterSpec) params;
+ ecSpec = ECUtil.getECParameterSpec(null, ecParams);
+ if (ecSpec == null) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported curve: " + params);
+ }
+ } else if (params instanceof ECGenParameterSpec) {
+ String name = ((ECGenParameterSpec) params).getName();
+ ecSpec = ECUtil.getECParameterSpec(null, name);
+ if (ecSpec == null) {
+ throw new InvalidAlgorithmParameterException(
+ "Unknown curve name: " + name);
+ }
+ } else {
+ throw new InvalidAlgorithmParameterException(
+ "ECParameterSpec or ECGenParameterSpec required for EC");
+ }
+
+ // Not all known curves are supported by the native implementation
+ ensureCurveIsSupported(ecSpec);
+ this.params = ecSpec;
+
+ this.keySize = ecSpec.getCurve().getField().getFieldSize();
+ this.random = random;
+ }
+
+ private static void ensureCurveIsSupported(ECParameterSpec ecSpec)
+ throws InvalidAlgorithmParameterException {
+
+ AlgorithmParameters ecParams = ECUtil.getECParameters(null);
+ byte[] encodedParams;
+ try {
+ ecParams.init(ecSpec);
+ encodedParams = ecParams.getEncoded();
+ } catch (InvalidParameterSpecException ex) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported curve: " + ecSpec.toString());
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ if (!isCurveSupported(encodedParams)) {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported curve: " + ecParams.toString());
+ }
+ }
+
+ // generate the keypair. See JCA doc
+ @Override
+ public KeyPair generateKeyPair() {
+
+ if (random == null) {
+ random = JCAUtil.getSecureRandom();
+ }
+
+ try {
+ Optional<KeyPair> kp = generateKeyPairImpl(random);
+ if (kp.isPresent()) {
+ return kp.get();
+ }
+ return generateKeyPairNative(random);
+ } catch (Exception ex) {
+ throw new ProviderException(ex);
+ }
+ }
+
+ private byte[] generatePrivateScalar(SecureRandom random,
+ ECOperations ecOps, int seedSize) {
+ // Attempt to create the private scalar in a loop that uses new random
+ // input each time. The chance of failure is very small assuming the
+ // implementation derives the nonce using extra bits
+ int numAttempts = 128;
+ byte[] seedArr = new byte[seedSize];
+ for (int i = 0; i < numAttempts; i++) {
+ random.nextBytes(seedArr);
+ try {
+ return ecOps.seedToScalar(seedArr);
+ } catch (IntermediateValueException ex) {
+ // try again in the next iteration
+ }
+ }
+
+ throw new ProviderException("Unable to produce private key after "
+ + numAttempts + " attempts");
+ }
+
+ private Optional<KeyPair> generateKeyPairImpl(SecureRandom random)
+ throws InvalidKeyException {
+
+ ECParameterSpec ecParams = (ECParameterSpec) params;
+
+ Optional<ECOperations> opsOpt = ECOperations.forParameters(ecParams);
+ if (opsOpt.isEmpty()) {
+ return Optional.empty();
+ }
+ ECOperations ops = opsOpt.get();
+ IntegerFieldModuloP field = ops.getField();
+ int numBits = ecParams.getOrder().bitLength();
+ int seedBits = numBits + 64;
+ int seedSize = (seedBits + 7) / 8;
+ byte[] privArr = generatePrivateScalar(random, ops, seedSize);
+
+ ECPoint genPoint = ecParams.getGenerator();
+ ImmutableIntegerModuloP x = field.getElement(genPoint.getAffineX());
+ ImmutableIntegerModuloP y = field.getElement(genPoint.getAffineY());
+ AffinePoint affGen = new AffinePoint(x, y);
+ Point pub = ops.multiply(affGen, privArr);
+ AffinePoint affPub = pub.asAffine();
+
+ PrivateKey privateKey = new ECPrivateKeyImpl(privArr, ecParams);
+
+ ECPoint w = new ECPoint(affPub.getX().asBigInteger(),
+ affPub.getY().asBigInteger());
+ PublicKey publicKey = new ECPublicKeyImpl(w, ecParams);
+
+ return Optional.of(new KeyPair(publicKey, privateKey));
+ }
+
+ private KeyPair generateKeyPairNative(SecureRandom random)
+ throws Exception {
+
+ ECParameterSpec ecParams = (ECParameterSpec) params;
+ byte[] encodedParams = ECUtil.encodeECParameterSpec(null, ecParams);
+
+ // seed is twice the key size (in bytes) plus 1
+ byte[] seed = new byte[(((keySize + 7) >> 3) + 1) * 2];
+ random.nextBytes(seed);
+ Object[] keyBytes = generateECKeyPair(keySize, encodedParams, seed);
+
+ // The 'params' object supplied above is equivalent to the native
+ // one so there is no need to fetch it.
+ // keyBytes[0] is the encoding of the native private key
+ BigInteger s = new BigInteger(1, (byte[]) keyBytes[0]);
+
+ PrivateKey privateKey = new ECPrivateKeyImpl(s, ecParams);
+
+ // keyBytes[1] is the encoding of the native public key
+ byte[] pubKey = (byte[]) keyBytes[1];
+ ECPoint w = ECUtil.decodePoint(pubKey, ecParams.getCurve());
+ PublicKey publicKey = new ECPublicKeyImpl(w, ecParams);
+
+ return new KeyPair(publicKey, privateKey);
+ }
+
+ private void checkKeySize(int keySize) throws InvalidParameterException {
+ if (keySize < KEY_SIZE_MIN) {
+ throw new InvalidParameterException
+ ("Key size must be at least " + KEY_SIZE_MIN + " bits");
+ }
+ if (keySize > KEY_SIZE_MAX) {
+ throw new InvalidParameterException
+ ("Key size must be at most " + KEY_SIZE_MAX + " bits");
+ }
+ this.keySize = keySize;
+ }
+
+ /**
+ * Checks whether the curve in the encoded parameters is supported by the
+ * native implementation. Some curve operations will be performed by the
+ * Java implementation, but not all of them. So native support is still
+ * required for all curves.
+ *
+ * @param encodedParams encoded parameters in the same form accepted
+ * by generateECKeyPair
+ * @return true if and only if generateECKeyPair will succeed for
+ * the supplied parameters
+ */
+ private static native boolean isCurveSupported(byte[] encodedParams);
+
+ /*
+ * Generates the keypair and returns a 2-element array of encoding bytes.
+ * The first one is for the private key, the second for the public key.
+ */
+ private static native Object[] generateECKeyPair(int keySize,
+ byte[] encodedParams, byte[] seed) throws GeneralSecurityException;
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/ECOperations.java b/jdk.crypto.ec/share/classes/sun/security/ec/ECOperations.java
new file mode 100644
index 0000000..2995ef7
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/ECOperations.java
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import sun.security.ec.point.*;
+import sun.security.util.math.*;
+import sun.security.util.math.intpoly.*;
+
+import java.math.BigInteger;
+import java.security.ProviderException;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.EllipticCurve;
+import java.util.Map;
+import java.util.Optional;
+
+/*
+ * Elliptic curve point arithmetic for prime-order curves where a=-3.
+ * Formulas are derived from "Complete addition formulas for prime order
+ * elliptic curves" by Renes, Costello, and Batina.
+ */
+
+public class ECOperations {
+
+ /*
+ * An exception indicating a problem with an intermediate value produced
+ * by some part of the computation. For example, the signing operation
+ * will throw this exception to indicate that the r or s value is 0, and
+ * that the signing operation should be tried again with a different nonce.
+ */
+ static class IntermediateValueException extends Exception {
+ private static final long serialVersionUID = 1;
+ }
+
+ static final Map<BigInteger, IntegerFieldModuloP> fields = Map.of(
+ IntegerPolynomialP256.MODULUS, new IntegerPolynomialP256(),
+ IntegerPolynomialP384.MODULUS, new IntegerPolynomialP384(),
+ IntegerPolynomialP521.MODULUS, new IntegerPolynomialP521()
+ );
+
+ static final Map<BigInteger, IntegerFieldModuloP> orderFields = Map.of(
+ P256OrderField.MODULUS, new P256OrderField(),
+ P384OrderField.MODULUS, new P384OrderField(),
+ P521OrderField.MODULUS, new P521OrderField()
+ );
+
+ public static Optional<ECOperations> forParameters(ECParameterSpec params) {
+
+ EllipticCurve curve = params.getCurve();
+ if (!(curve.getField() instanceof ECFieldFp)) {
+ return Optional.empty();
+ }
+ ECFieldFp primeField = (ECFieldFp) curve.getField();
+
+ BigInteger three = BigInteger.valueOf(3);
+ if (!primeField.getP().subtract(curve.getA()).equals(three)) {
+ return Optional.empty();
+ }
+ IntegerFieldModuloP field = fields.get(primeField.getP());
+ if (field == null) {
+ return Optional.empty();
+ }
+
+ IntegerFieldModuloP orderField = orderFields.get(params.getOrder());
+ if (orderField == null) {
+ return Optional.empty();
+ }
+
+ ImmutableIntegerModuloP b = field.getElement(curve.getB());
+ ECOperations ecOps = new ECOperations(b, orderField);
+ return Optional.of(ecOps);
+ }
+
+ final ImmutableIntegerModuloP b;
+ final SmallValue one;
+ final SmallValue two;
+ final SmallValue three;
+ final SmallValue four;
+ final ProjectivePoint.Immutable neutral;
+ private final IntegerFieldModuloP orderField;
+
+ public ECOperations(IntegerModuloP b, IntegerFieldModuloP orderField) {
+ this.b = b.fixed();
+ this.orderField = orderField;
+
+ this.one = b.getField().getSmallValue(1);
+ this.two = b.getField().getSmallValue(2);
+ this.three = b.getField().getSmallValue(3);
+ this.four = b.getField().getSmallValue(4);
+
+ IntegerFieldModuloP field = b.getField();
+ this.neutral = new ProjectivePoint.Immutable(field.get0(),
+ field.get1(), field.get0());
+ }
+
+ public IntegerFieldModuloP getField() {
+ return b.getField();
+ }
+ public IntegerFieldModuloP getOrderField() {
+ return orderField;
+ }
+
+ protected ProjectivePoint.Immutable getNeutral() {
+ return neutral;
+ }
+
+ public boolean isNeutral(Point p) {
+ ProjectivePoint<?> pp = (ProjectivePoint<?>) p;
+
+ IntegerModuloP z = pp.getZ();
+
+ IntegerFieldModuloP field = z.getField();
+ int byteLength = (field.getSize().bitLength() + 7) / 8;
+ byte[] zBytes = z.asByteArray(byteLength);
+ return allZero(zBytes);
+ }
+
+ byte[] seedToScalar(byte[] seedBytes)
+ throws IntermediateValueException {
+
+ // Produce a nonce from the seed using FIPS 186-4,section B.5.1:
+ // Per-Message Secret Number Generation Using Extra Random Bits
+ // or
+ // Produce a scalar from the seed using FIPS 186-4, section B.4.1:
+ // Key Pair Generation Using Extra Random Bits
+
+ // To keep the implementation simple, sample in the range [0,n)
+ // and throw IntermediateValueException in the (unlikely) event
+ // that the result is 0.
+
+ // Get 64 extra bits and reduce in to the nonce
+ int seedBits = orderField.getSize().bitLength() + 64;
+ if (seedBytes.length * 8 < seedBits) {
+ throw new ProviderException("Incorrect seed length: " +
+ seedBytes.length * 8 + " < " + seedBits);
+ }
+
+ // input conversion only works on byte boundaries
+ // clear high-order bits of last byte so they don't influence nonce
+ int lastByteBits = seedBits % 8;
+ if (lastByteBits != 0) {
+ int lastByteIndex = seedBits / 8;
+ byte mask = (byte) (0xFF >>> (8 - lastByteBits));
+ seedBytes[lastByteIndex] &= mask;
+ }
+
+ int seedLength = (seedBits + 7) / 8;
+ IntegerModuloP scalarElem =
+ orderField.getElement(seedBytes, 0, seedLength, (byte) 0);
+ int scalarLength = (orderField.getSize().bitLength() + 7) / 8;
+ byte[] scalarArr = new byte[scalarLength];
+ scalarElem.asByteArray(scalarArr);
+ if (ECOperations.allZero(scalarArr)) {
+ throw new IntermediateValueException();
+ }
+ return scalarArr;
+ }
+
+ /*
+ * Compare all values in the array to 0 without branching on any value
+ *
+ */
+ public static boolean allZero(byte[] arr) {
+ byte acc = 0;
+ for (int i = 0; i < arr.length; i++) {
+ acc |= arr[i];
+ }
+ return acc == 0;
+ }
+
+ /*
+ * 4-bit branchless array lookup for projective points.
+ */
+ private void lookup4(ProjectivePoint.Immutable[] arr, int index,
+ ProjectivePoint.Mutable result, IntegerModuloP zero) {
+
+ for (int i = 0; i < 16; i++) {
+ int xor = index ^ i;
+ int bit3 = (xor & 0x8) >>> 3;
+ int bit2 = (xor & 0x4) >>> 2;
+ int bit1 = (xor & 0x2) >>> 1;
+ int bit0 = (xor & 0x1);
+ int inverse = bit0 | bit1 | bit2 | bit3;
+ int set = 1 - inverse;
+
+ ProjectivePoint.Immutable pi = arr[i];
+ result.conditionalSet(pi, set);
+ }
+ }
+
+ private void double4(ProjectivePoint.Mutable p, MutableIntegerModuloP t0,
+ MutableIntegerModuloP t1, MutableIntegerModuloP t2,
+ MutableIntegerModuloP t3, MutableIntegerModuloP t4) {
+
+ for (int i = 0; i < 4; i++) {
+ setDouble(p, t0, t1, t2, t3, t4);
+ }
+ }
+
+ /**
+ * Multiply an affine point by a scalar and return the result as a mutable
+ * point.
+ *
+ * @param affineP the point
+ * @param s the scalar as a little-endian array
+ * @return the product
+ */
+ public MutablePoint multiply(AffinePoint affineP, byte[] s) {
+
+ // 4-bit windowed multiply with branchless lookup.
+ // The mixed addition is faster, so it is used to construct the array
+ // at the beginning of the operation.
+
+ IntegerFieldModuloP field = affineP.getX().getField();
+ ImmutableIntegerModuloP zero = field.get0();
+ // temporaries
+ MutableIntegerModuloP t0 = zero.mutable();
+ MutableIntegerModuloP t1 = zero.mutable();
+ MutableIntegerModuloP t2 = zero.mutable();
+ MutableIntegerModuloP t3 = zero.mutable();
+ MutableIntegerModuloP t4 = zero.mutable();
+
+ ProjectivePoint.Mutable result = new ProjectivePoint.Mutable(field);
+ result.getY().setValue(field.get1().mutable());
+
+ ProjectivePoint.Immutable[] pointMultiples =
+ new ProjectivePoint.Immutable[16];
+ // 0P is neutral---same as initial result value
+ pointMultiples[0] = result.fixed();
+
+ ProjectivePoint.Mutable ps = new ProjectivePoint.Mutable(field);
+ ps.setValue(affineP);
+ // 1P = P
+ pointMultiples[1] = ps.fixed();
+
+ // the rest are calculated using mixed point addition
+ for (int i = 2; i < 16; i++) {
+ setSum(ps, affineP, t0, t1, t2, t3, t4);
+ pointMultiples[i] = ps.fixed();
+ }
+
+ ProjectivePoint.Mutable lookupResult = ps.mutable();
+
+ for (int i = s.length - 1; i >= 0; i--) {
+
+ double4(result, t0, t1, t2, t3, t4);
+
+ int high = (0xFF & s[i]) >>> 4;
+ lookup4(pointMultiples, high, lookupResult, zero);
+ setSum(result, lookupResult, t0, t1, t2, t3, t4);
+
+ double4(result, t0, t1, t2, t3, t4);
+
+ int low = 0xF & s[i];
+ lookup4(pointMultiples, low, lookupResult, zero);
+ setSum(result, lookupResult, t0, t1, t2, t3, t4);
+ }
+
+ return result;
+
+ }
+
+ /*
+ * Point double
+ */
+ private void setDouble(ProjectivePoint.Mutable p, MutableIntegerModuloP t0,
+ MutableIntegerModuloP t1, MutableIntegerModuloP t2,
+ MutableIntegerModuloP t3, MutableIntegerModuloP t4) {
+
+ t0.setValue(p.getX()).setSquare();
+ t1.setValue(p.getY()).setSquare();
+ t2.setValue(p.getZ()).setSquare();
+ t3.setValue(p.getX()).setProduct(p.getY());
+ t4.setValue(p.getY()).setProduct(p.getZ());
+
+ t3.setSum(t3);
+ p.getZ().setProduct(p.getX());
+
+ p.getZ().setProduct(two);
+
+ p.getY().setValue(t2).setProduct(b);
+ p.getY().setDifference(p.getZ());
+
+ p.getX().setValue(p.getY()).setProduct(two);
+ p.getY().setSum(p.getX());
+ p.getY().setReduced();
+ p.getX().setValue(t1).setDifference(p.getY());
+
+ p.getY().setSum(t1);
+ p.getY().setProduct(p.getX());
+ p.getX().setProduct(t3);
+
+ t3.setValue(t2).setProduct(two);
+ t2.setSum(t3);
+ p.getZ().setProduct(b);
+
+ t2.setReduced();
+ p.getZ().setDifference(t2);
+ p.getZ().setDifference(t0);
+ t3.setValue(p.getZ()).setProduct(two);
+ p.getZ().setReduced();
+ p.getZ().setSum(t3);
+ t0.setProduct(three);
+
+ t0.setDifference(t2);
+ t0.setProduct(p.getZ());
+ p.getY().setSum(t0);
+
+ t4.setSum(t4);
+ p.getZ().setProduct(t4);
+
+ p.getX().setDifference(p.getZ());
+ p.getZ().setValue(t4).setProduct(t1);
+
+ p.getZ().setProduct(four);
+
+ }
+
+ /*
+ * Mixed point addition. This method constructs new temporaries each time
+ * it is called. For better efficiency, the method that reuses temporaries
+ * should be used if more than one sum will be computed.
+ */
+ public void setSum(MutablePoint p, AffinePoint p2) {
+
+ IntegerModuloP zero = p.getField().get0();
+ MutableIntegerModuloP t0 = zero.mutable();
+ MutableIntegerModuloP t1 = zero.mutable();
+ MutableIntegerModuloP t2 = zero.mutable();
+ MutableIntegerModuloP t3 = zero.mutable();
+ MutableIntegerModuloP t4 = zero.mutable();
+ setSum((ProjectivePoint.Mutable) p, p2, t0, t1, t2, t3, t4);
+
+ }
+
+ /*
+ * Mixed point addition
+ */
+ private void setSum(ProjectivePoint.Mutable p, AffinePoint p2,
+ MutableIntegerModuloP t0, MutableIntegerModuloP t1,
+ MutableIntegerModuloP t2, MutableIntegerModuloP t3,
+ MutableIntegerModuloP t4) {
+
+ t0.setValue(p.getX()).setProduct(p2.getX());
+ t1.setValue(p.getY()).setProduct(p2.getY());
+ t3.setValue(p2.getX()).setSum(p2.getY());
+ t4.setValue(p.getX()).setSum(p.getY());
+ p.getX().setReduced();
+ t3.setProduct(t4);
+ t4.setValue(t0).setSum(t1);
+
+ t3.setDifference(t4);
+ t4.setValue(p2.getY()).setProduct(p.getZ());
+ t4.setSum(p.getY());
+
+ p.getY().setValue(p2.getX()).setProduct(p.getZ());
+ p.getY().setSum(p.getX());
+ t2.setValue(p.getZ());
+ p.getZ().setProduct(b);
+
+ p.getX().setValue(p.getY()).setDifference(p.getZ());
+ p.getX().setReduced();
+ p.getZ().setValue(p.getX()).setProduct(two);
+ p.getX().setSum(p.getZ());
+
+ p.getZ().setValue(t1).setDifference(p.getX());
+ p.getX().setSum(t1);
+ p.getY().setProduct(b);
+
+ t1.setValue(t2).setProduct(two);
+ t2.setSum(t1);
+ t2.setReduced();
+ p.getY().setDifference(t2);
+
+ p.getY().setDifference(t0);
+ p.getY().setReduced();
+ t1.setValue(p.getY()).setProduct(two);
+ p.getY().setSum(t1);
+
+ t1.setValue(t0).setProduct(two);
+ t0.setSum(t1);
+ t0.setDifference(t2);
+
+ t1.setValue(t4).setProduct(p.getY());
+ t2.setValue(t0).setProduct(p.getY());
+ p.getY().setValue(p.getX()).setProduct(p.getZ());
+
+ p.getY().setSum(t2);
+ p.getX().setProduct(t3);
+ p.getX().setDifference(t1);
+
+ p.getZ().setProduct(t4);
+ t1.setValue(t3).setProduct(t0);
+ p.getZ().setSum(t1);
+
+ }
+
+ /*
+ * Projective point addition
+ */
+ private void setSum(ProjectivePoint.Mutable p, ProjectivePoint.Mutable p2,
+ MutableIntegerModuloP t0, MutableIntegerModuloP t1,
+ MutableIntegerModuloP t2, MutableIntegerModuloP t3,
+ MutableIntegerModuloP t4) {
+
+ t0.setValue(p.getX()).setProduct(p2.getX());
+ t1.setValue(p.getY()).setProduct(p2.getY());
+ t2.setValue(p.getZ()).setProduct(p2.getZ());
+
+ t3.setValue(p.getX()).setSum(p.getY());
+ t4.setValue(p2.getX()).setSum(p2.getY());
+ t3.setProduct(t4);
+
+ t4.setValue(t0).setSum(t1);
+ t3.setDifference(t4);
+ t4.setValue(p.getY()).setSum(p.getZ());
+
+ p.getY().setValue(p2.getY()).setSum(p2.getZ());
+ t4.setProduct(p.getY());
+ p.getY().setValue(t1).setSum(t2);
+
+ t4.setDifference(p.getY());
+ p.getX().setSum(p.getZ());
+ p.getY().setValue(p2.getX()).setSum(p2.getZ());
+
+ p.getX().setProduct(p.getY());
+ p.getY().setValue(t0).setSum(t2);
+ p.getY().setAdditiveInverse().setSum(p.getX());
+ p.getY().setReduced();
+
+ p.getZ().setValue(t2).setProduct(b);
+ p.getX().setValue(p.getY()).setDifference(p.getZ());
+ p.getZ().setValue(p.getX()).setProduct(two);
+
+ p.getX().setSum(p.getZ());
+ p.getX().setReduced();
+ p.getZ().setValue(t1).setDifference(p.getX());
+ p.getX().setSum(t1);
+
+ p.getY().setProduct(b);
+ t1.setValue(t2).setSum(t2);
+ t2.setSum(t1);
+ t2.setReduced();
+
+ p.getY().setDifference(t2);
+ p.getY().setDifference(t0);
+ p.getY().setReduced();
+ t1.setValue(p.getY()).setSum(p.getY());
+
+ p.getY().setSum(t1);
+ t1.setValue(t0).setProduct(two);
+ t0.setSum(t1);
+
+ t0.setDifference(t2);
+ t1.setValue(t4).setProduct(p.getY());
+ t2.setValue(t0).setProduct(p.getY());
+
+ p.getY().setValue(p.getX()).setProduct(p.getZ());
+ p.getY().setSum(t2);
+ p.getX().setProduct(t3);
+
+ p.getX().setDifference(t1);
+ p.getZ().setProduct(t4);
+ t1.setValue(t3).setProduct(t0);
+
+ p.getZ().setSum(t1);
+
+ }
+}
+
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/ECPrivateKeyImpl.java b/jdk.crypto.ec/share/classes/sun/security/ec/ECPrivateKeyImpl.java
new file mode 100644
index 0000000..81c992d
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/ECPrivateKeyImpl.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.*;
+
+import sun.security.util.*;
+import sun.security.x509.AlgorithmId;
+import sun.security.pkcs.PKCS8Key;
+
+/**
+ * Key implementation for EC private keys.
+ *
+ * ASN.1 syntax for EC private keys from SEC 1 v1.5 (draft):
+ *
+ * <pre>
+ * EXPLICIT TAGS
+ *
+ * ECPrivateKey ::= SEQUENCE {
+ * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ * privateKey OCTET STRING,
+ * parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
+ * publicKey [1] BIT STRING OPTIONAL
+ * }
+ * </pre>
+ *
+ * We currently ignore the optional parameters and publicKey fields. We
+ * require that the parameters are encoded as part of the AlgorithmIdentifier,
+ * not in the private key structure.
+ *
+ * @since 1.6
+ * @author Andreas Sterbenz
+ */
+public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey {
+
+ private static final long serialVersionUID = 88695385615075129L;
+
+ private BigInteger s; // private value
+ private byte[] arrayS; // private value as a little-endian array
+ private ECParameterSpec params;
+
+ /**
+ * Construct a key from its encoding. Called by the ECKeyFactory.
+ */
+ ECPrivateKeyImpl(byte[] encoded) throws InvalidKeyException {
+ decode(encoded);
+ }
+
+ /**
+ * Construct a key from its components. Used by the
+ * KeyFactory.
+ */
+ ECPrivateKeyImpl(BigInteger s, ECParameterSpec params)
+ throws InvalidKeyException {
+ this.s = s;
+ this.params = params;
+ makeEncoding(s);
+
+ }
+
+ ECPrivateKeyImpl(byte[] s, ECParameterSpec params)
+ throws InvalidKeyException {
+ this.arrayS = s.clone();
+ this.params = params;
+ makeEncoding(s);
+ }
+
+ private void makeEncoding(byte[] s) throws InvalidKeyException {
+ algid = new AlgorithmId
+ (AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));
+ try {
+ DerOutputStream out = new DerOutputStream();
+ out.putInteger(1); // version 1
+ byte[] privBytes = s.clone();
+ ArrayUtil.reverse(privBytes);
+ out.putOctetString(privBytes);
+ DerValue val =
+ new DerValue(DerValue.tag_Sequence, out.toByteArray());
+ key = val.toByteArray();
+ } catch (IOException exc) {
+ // should never occur
+ throw new InvalidKeyException(exc);
+ }
+ }
+
+ private void makeEncoding(BigInteger s) throws InvalidKeyException {
+ algid = new AlgorithmId
+ (AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));
+ try {
+ byte[] sArr = s.toByteArray();
+ // convert to fixed-length array
+ int numOctets = (params.getOrder().bitLength() + 7) / 8;
+ byte[] sOctets = new byte[numOctets];
+ int inPos = Math.max(sArr.length - sOctets.length, 0);
+ int outPos = Math.max(sOctets.length - sArr.length, 0);
+ int length = Math.min(sArr.length, sOctets.length);
+ System.arraycopy(sArr, inPos, sOctets, outPos, length);
+
+ DerOutputStream out = new DerOutputStream();
+ out.putInteger(1); // version 1
+ out.putOctetString(sOctets);
+ DerValue val =
+ new DerValue(DerValue.tag_Sequence, out.toByteArray());
+ key = val.toByteArray();
+ } catch (IOException exc) {
+ // should never occur
+ throw new InvalidKeyException(exc);
+ }
+ }
+
+ // see JCA doc
+ public String getAlgorithm() {
+ return "EC";
+ }
+
+ // see JCA doc
+ public BigInteger getS() {
+ if (s == null) {
+ byte[] arrCopy = arrayS.clone();
+ ArrayUtil.reverse(arrCopy);
+ s = new BigInteger(1, arrCopy);
+ }
+ return s;
+ }
+
+ public byte[] getArrayS() {
+ if (arrayS == null) {
+ byte[] arr = getS().toByteArray();
+ ArrayUtil.reverse(arr);
+ int byteLength = (params.getOrder().bitLength() + 7) / 8;
+ arrayS = new byte[byteLength];
+ int length = Math.min(byteLength, arr.length);
+ System.arraycopy(arr, 0, arrayS, 0, length);
+ }
+ return arrayS.clone();
+ }
+
+ // see JCA doc
+ public ECParameterSpec getParams() {
+ return params;
+ }
+
+ /**
+ * Parse the key. Called by PKCS8Key.
+ */
+ protected void parseKeyBits() throws InvalidKeyException {
+ try {
+ DerInputStream in = new DerInputStream(key);
+ DerValue derValue = in.getDerValue();
+ if (derValue.tag != DerValue.tag_Sequence) {
+ throw new IOException("Not a SEQUENCE");
+ }
+ DerInputStream data = derValue.data;
+ int version = data.getInteger();
+ if (version != 1) {
+ throw new IOException("Version must be 1");
+ }
+ byte[] privData = data.getOctetString();
+ ArrayUtil.reverse(privData);
+ arrayS = privData;
+ while (data.available() != 0) {
+ DerValue value = data.getDerValue();
+ if (value.isContextSpecific((byte) 0)) {
+ // ignore for now
+ } else if (value.isContextSpecific((byte) 1)) {
+ // ignore for now
+ } else {
+ throw new InvalidKeyException("Unexpected value: " + value);
+ }
+ }
+ AlgorithmParameters algParams = this.algid.getParameters();
+ if (algParams == null) {
+ throw new InvalidKeyException("EC domain parameters must be "
+ + "encoded in the algorithm identifier");
+ }
+ params = algParams.getParameterSpec(ECParameterSpec.class);
+ } catch (IOException e) {
+ throw new InvalidKeyException("Invalid EC private key", e);
+ } catch (InvalidParameterSpecException e) {
+ throw new InvalidKeyException("Invalid EC private key", e);
+ }
+ }
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/ECPublicKeyImpl.java b/jdk.crypto.ec/share/classes/sun/security/ec/ECPublicKeyImpl.java
new file mode 100644
index 0000000..bc40302
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/ECPublicKeyImpl.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.io.IOException;
+
+import java.security.*;
+import java.security.interfaces.*;
+import java.security.spec.*;
+
+import sun.security.util.ECParameters;
+import sun.security.util.ECUtil;
+
+import sun.security.x509.*;
+
+/**
+ * Key implementation for EC public keys.
+ *
+ * @since 1.6
+ * @author Andreas Sterbenz
+ */
+public final class ECPublicKeyImpl extends X509Key implements ECPublicKey {
+
+ private static final long serialVersionUID = -2462037275160462289L;
+
+ private ECPoint w;
+ private ECParameterSpec params;
+
+ /**
+ * Construct a key from its components. Used by the
+ * ECKeyFactory.
+ */
+ @SuppressWarnings("deprecation")
+ ECPublicKeyImpl(ECPoint w, ECParameterSpec params)
+ throws InvalidKeyException {
+ this.w = w;
+ this.params = params;
+ // generate the encoding
+ algid = new AlgorithmId
+ (AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));
+ key = ECUtil.encodePoint(w, params.getCurve());
+ }
+
+ /**
+ * Construct a key from its encoding.
+ */
+ ECPublicKeyImpl(byte[] encoded) throws InvalidKeyException {
+ decode(encoded);
+ }
+
+ // see JCA doc
+ public String getAlgorithm() {
+ return "EC";
+ }
+
+ // see JCA doc
+ public ECPoint getW() {
+ return w;
+ }
+
+ // see JCA doc
+ public ECParameterSpec getParams() {
+ return params;
+ }
+
+ // Internal API to get the encoded point. Currently used by SunPKCS11.
+ // This may change/go away depending on what we do with the public API.
+ @SuppressWarnings("deprecation")
+ public byte[] getEncodedPublicValue() {
+ return key.clone();
+ }
+
+ /**
+ * Parse the key. Called by X509Key.
+ */
+ @SuppressWarnings("deprecation")
+ protected void parseKeyBits() throws InvalidKeyException {
+ AlgorithmParameters algParams = this.algid.getParameters();
+ if (algParams == null) {
+ throw new InvalidKeyException("EC domain parameters must be " +
+ "encoded in the algorithm identifier");
+ }
+
+ try {
+ params = algParams.getParameterSpec(ECParameterSpec.class);
+ w = ECUtil.decodePoint(key, params.getCurve());
+ } catch (IOException e) {
+ throw new InvalidKeyException("Invalid EC key", e);
+ } catch (InvalidParameterSpecException e) {
+ throw new InvalidKeyException("Invalid EC key", e);
+ }
+ }
+
+ // return a string representation of this key for debugging
+ public String toString() {
+ return "Sun EC public key, " + params.getCurve().getField().getFieldSize()
+ + " bits\n public x coord: " + w.getAffineX()
+ + "\n public y coord: " + w.getAffineY()
+ + "\n parameters: " + params;
+ }
+
+ protected Object writeReplace() throws java.io.ObjectStreamException {
+ return new KeyRep(KeyRep.Type.PUBLIC,
+ getAlgorithm(),
+ getFormat(),
+ getEncoded());
+ }
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/SunEC.java b/jdk.crypto.ec/share/classes/sun/security/ec/SunEC.java
new file mode 100644
index 0000000..09be69e
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/SunEC.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.util.*;
+import java.security.*;
+import java.util.regex.Pattern;
+import sun.security.util.CurveDB;
+import sun.security.util.NamedCurve;
+
+import static sun.security.util.SecurityConstants.PROVIDER_VER;
+
+/**
+ * Provider class for the Elliptic Curve provider.
+ * Supports EC keypair and parameter generation, ECDSA signing and
+ * ECDH key agreement.
+ *
+ * IMPLEMENTATION NOTE:
+ * The Java classes in this provider access a native ECC implementation
+ * via JNI to a C++ wrapper class which in turn calls C functions.
+ * The Java classes are packaged into the jdk.crypto.sunec module and the
+ * C++ and C functions are packaged into libsunec.so or sunec.dll in the
+ * JRE native libraries directory. If the native library is not present
+ * then this provider is registered with support for fewer ECC algorithms
+ * (KeyPairGenerator, Signature and KeyAgreement are omitted).
+ *
+ * @since 1.7
+ */
+public final class SunEC extends Provider {
+
+ private static final long serialVersionUID = -2279741672933606418L;
+
+ // flag indicating whether the full EC implementation is present
+ // (when native library is absent then fewer EC algorithms are available)
+ private static boolean useFullImplementation = true;
+ static {
+ try {
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run() {
+ System.loadLibrary("sunec"); // check for native library
+ return null;
+ }
+ });
+ } catch (UnsatisfiedLinkError e) {
+ useFullImplementation = false;
+ }
+ }
+
+ private static class ProviderService extends Provider.Service {
+
+ ProviderService(Provider p, String type, String algo, String cn) {
+ super(p, type, algo, cn, null, null);
+ }
+
+ ProviderService(Provider p, String type, String algo, String cn,
+ String[] aliases, HashMap<String, String> attrs) {
+ super(p, type, algo, cn,
+ (aliases == null? null : Arrays.asList(aliases)), attrs);
+ }
+
+ @Override
+ public Object newInstance(Object ctrParamObj)
+ throws NoSuchAlgorithmException {
+ String type = getType();
+ if (ctrParamObj != null) {
+ throw new InvalidParameterException
+ ("constructorParameter not used with " + type + " engines");
+ }
+
+ String algo = getAlgorithm();
+ try {
+ if (type.equals("Signature")) {
+ boolean inP1363 = algo.endsWith("inP1363Format");
+ if (inP1363) {
+ algo = algo.substring(0, algo.length() - 13);
+ }
+ if (algo.equals("SHA1withECDSA")) {
+ return (inP1363? new ECDSASignature.SHA1inP1363Format() :
+ new ECDSASignature.SHA1());
+ } else if (algo.equals("SHA224withECDSA")) {
+ return (inP1363? new ECDSASignature.SHA224inP1363Format() :
+ new ECDSASignature.SHA224());
+ } else if (algo.equals("SHA256withECDSA")) {
+ return (inP1363? new ECDSASignature.SHA256inP1363Format() :
+ new ECDSASignature.SHA256());
+ } else if (algo.equals("SHA384withECDSA")) {
+ return (inP1363? new ECDSASignature.SHA384inP1363Format() :
+ new ECDSASignature.SHA384());
+ } else if (algo.equals("SHA512withECDSA")) {
+ return (inP1363? new ECDSASignature.SHA512inP1363Format() :
+ new ECDSASignature.SHA512());
+ } else if (algo.equals("NONEwithECDSA")) {
+ return (inP1363? new ECDSASignature.RawinP1363Format() :
+ new ECDSASignature.Raw());
+ }
+ } else if (type.equals("KeyFactory")) {
+ if (algo.equals("EC")) {
+ return new ECKeyFactory();
+ } else if (algo.equals("XDH")) {
+ return new XDHKeyFactory();
+ } else if (algo.equals("X25519")) {
+ return new XDHKeyFactory.X25519();
+ } else if (algo.equals("X448")) {
+ return new XDHKeyFactory.X448();
+ }
+ } else if (type.equals("AlgorithmParameters")) {
+ if (algo.equals("EC")) {
+ return new sun.security.util.ECParameters();
+ }
+ } else if (type.equals("KeyPairGenerator")) {
+ if (algo.equals("EC")) {
+ return new ECKeyPairGenerator();
+ } else if (algo.equals("XDH")) {
+ return new XDHKeyPairGenerator();
+ } else if (algo.equals("X25519")) {
+ return new XDHKeyPairGenerator.X25519();
+ } else if (algo.equals("X448")) {
+ return new XDHKeyPairGenerator.X448();
+ }
+ } else if (type.equals("KeyAgreement")) {
+ if (algo.equals("ECDH")) {
+ return new ECDHKeyAgreement();
+ } else if (algo.equals("XDH")) {
+ return new XDHKeyAgreement();
+ } else if (algo.equals("X25519")) {
+ return new XDHKeyAgreement.X25519();
+ } else if (algo.equals("X448")) {
+ return new XDHKeyAgreement.X448();
+ }
+ }
+ } catch (Exception ex) {
+ throw new NoSuchAlgorithmException("Error constructing " +
+ type + " for " + algo + " using SunEC", ex);
+ }
+ throw new ProviderException("No impl for " + algo +
+ " " + type);
+ }
+ }
+
+ public SunEC() {
+ super("SunEC", PROVIDER_VER,
+ "Sun Elliptic Curve provider (EC, ECDSA, ECDH)");
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run() {
+ putEntries(useFullImplementation);
+ return null;
+ }
+ });
+ }
+
+ void putEntries(boolean useFullImplementation) {
+ HashMap<String, String> ATTRS = new HashMap<>(3);
+ ATTRS.put("ImplementedIn", "Software");
+ String ecKeyClasses = "java.security.interfaces.ECPublicKey" +
+ "|java.security.interfaces.ECPrivateKey";
+ ATTRS.put("SupportedKeyClasses", ecKeyClasses);
+ ATTRS.put("KeySize", "256");
+
+ /*
+ * Key Factory engine
+ */
+ putService(new ProviderService(this, "KeyFactory",
+ "EC", "sun.security.ec.ECKeyFactory",
+ new String[] { "EllipticCurve" }, ATTRS));
+
+ /*
+ * Algorithm Parameter engine
+ */
+ // "AlgorithmParameters.EC SupportedCurves" prop used by unit test
+ boolean firstCurve = true;
+ StringBuilder names = new StringBuilder();
+ Pattern nameSplitPattern = Pattern.compile(CurveDB.SPLIT_PATTERN);
+
+ Collection<? extends NamedCurve> supportedCurves =
+ CurveDB.getSupportedCurves();
+ for (NamedCurve namedCurve : supportedCurves) {
+ if (!firstCurve) {
+ names.append("|");
+ } else {
+ firstCurve = false;
+ }
+
+ names.append("[");
+
+ String[] commonNames = nameSplitPattern.split(namedCurve.getName());
+ for (String commonName : commonNames) {
+ names.append(commonName.trim());
+ names.append(",");
+ }
+
+ names.append(namedCurve.getObjectId());
+ names.append("]");
+ }
+
+ HashMap<String, String> apAttrs = new HashMap<>(ATTRS);
+ apAttrs.put("SupportedCurves", names.toString());
+
+ putService(new ProviderService(this, "AlgorithmParameters",
+ "EC", "sun.security.util.ECParameters",
+ new String[] { "EllipticCurve", "1.2.840.10045.2.1", "OID.1.2.840.10045.2.1" },
+ apAttrs));
+
+ putXDHEntries();
+
+ /*
+ * Register the algorithms below only when the full ECC implementation
+ * is available
+ */
+ if (!useFullImplementation) {
+ return;
+ }
+
+ /*
+ * Signature engines
+ */
+ putService(new ProviderService(this, "Signature",
+ "NONEwithECDSA", "sun.security.ec.ECDSASignature$Raw",
+ null, ATTRS));
+ putService(new ProviderService(this, "Signature",
+ "SHA1withECDSA", "sun.security.ec.ECDSASignature$SHA1",
+ new String[] { "1.2.840.10045.4.1", "OID.1.2.840.10045.4.1" },
+ ATTRS));
+ putService(new ProviderService(this, "Signature",
+ "SHA224withECDSA", "sun.security.ec.ECDSASignature$SHA224",
+ new String[] { "1.2.840.10045.4.3.1", "OID.1.2.840.10045.4.3.1"},
+ ATTRS));
+ putService(new ProviderService(this, "Signature",
+ "SHA256withECDSA", "sun.security.ec.ECDSASignature$SHA256",
+ new String[] { "1.2.840.10045.4.3.2", "OID.1.2.840.10045.4.3.2"},
+ ATTRS));
+ putService(new ProviderService(this, "Signature",
+ "SHA384withECDSA", "sun.security.ec.ECDSASignature$SHA384",
+ new String[] { "1.2.840.10045.4.3.3", "OID.1.2.840.10045.4.3.3" },
+ ATTRS));
+ putService(new ProviderService(this, "Signature",
+ "SHA512withECDSA", "sun.security.ec.ECDSASignature$SHA512",
+ new String[] { "1.2.840.10045.4.3.4", "OID.1.2.840.10045.4.3.4" },
+ ATTRS));
+
+ putService(new ProviderService(this, "Signature",
+ "NONEwithECDSAinP1363Format",
+ "sun.security.ec.ECDSASignature$RawinP1363Format"));
+ putService(new ProviderService(this, "Signature",
+ "SHA1withECDSAinP1363Format",
+ "sun.security.ec.ECDSASignature$SHA1inP1363Format"));
+ putService(new ProviderService(this, "Signature",
+ "SHA224withECDSAinP1363Format",
+ "sun.security.ec.ECDSASignature$SHA224inP1363Format"));
+ putService(new ProviderService(this, "Signature",
+ "SHA256withECDSAinP1363Format",
+ "sun.security.ec.ECDSASignature$SHA256inP1363Format"));
+ putService(new ProviderService(this, "Signature",
+ "SHA384withECDSAinP1363Format",
+ "sun.security.ec.ECDSASignature$SHA384inP1363Format"));
+ putService(new ProviderService(this, "Signature",
+ "SHA512withECDSAinP1363Format",
+ "sun.security.ec.ECDSASignature$SHA512inP1363Format"));
+
+ /*
+ * Key Pair Generator engine
+ */
+ putService(new ProviderService(this, "KeyPairGenerator",
+ "EC", "sun.security.ec.ECKeyPairGenerator",
+ new String[] { "EllipticCurve" }, ATTRS));
+
+ /*
+ * Key Agreement engine
+ */
+ putService(new ProviderService(this, "KeyAgreement",
+ "ECDH", "sun.security.ec.ECDHKeyAgreement", null, ATTRS));
+ }
+
+ private void putXDHEntries() {
+
+ HashMap<String, String> ATTRS = new HashMap<>(1);
+ ATTRS.put("ImplementedIn", "Software");
+
+ /* XDH does not require native implementation */
+ putService(new ProviderService(this, "KeyFactory",
+ "XDH", "sun.security.ec.XDHKeyFactory", null, ATTRS));
+ putService(new ProviderService(this, "KeyFactory",
+ "X25519", "sun.security.ec.XDHKeyFactory.X25519",
+ new String[]{"1.3.101.110", "OID.1.3.101.110"}, ATTRS));
+ putService(new ProviderService(this, "KeyFactory",
+ "X448", "sun.security.ec.XDHKeyFactory.X448",
+ new String[]{"1.3.101.111", "OID.1.3.101.111"}, ATTRS));
+
+ putService(new ProviderService(this, "KeyPairGenerator",
+ "XDH", "sun.security.ec.XDHKeyPairGenerator", null, ATTRS));
+ putService(new ProviderService(this, "KeyPairGenerator",
+ "X25519", "sun.security.ec.XDHKeyPairGenerator.X25519",
+ new String[]{"1.3.101.110", "OID.1.3.101.110"}, ATTRS));
+ putService(new ProviderService(this, "KeyPairGenerator",
+ "X448", "sun.security.ec.XDHKeyPairGenerator.X448",
+ new String[]{"1.3.101.111", "OID.1.3.101.111"}, ATTRS));
+
+ putService(new ProviderService(this, "KeyAgreement",
+ "XDH", "sun.security.ec.XDHKeyAgreement", null, ATTRS));
+ putService(new ProviderService(this, "KeyAgreement",
+ "X25519", "sun.security.ec.XDHKeyAgreement.X25519",
+ new String[]{"1.3.101.110", "OID.1.3.101.110"}, ATTRS));
+ putService(new ProviderService(this, "KeyAgreement",
+ "X448", "sun.security.ec.XDHKeyAgreement.X448",
+ new String[]{"1.3.101.111", "OID.1.3.101.111"}, ATTRS));
+
+ }
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java b/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java
new file mode 100644
index 0000000..e2a625a
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.ProviderException;
+import java.security.interfaces.XECPrivateKey;
+import java.security.interfaces.XECPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.NamedParameterSpec;
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
+import java.util.function.Function;
+
+public class XDHKeyAgreement extends KeyAgreementSpi {
+
+ private byte[] privateKey;
+ private byte[] secret;
+ private XECOperations ops;
+ private XECParameters lockedParams = null;
+
+ XDHKeyAgreement() {
+ // do nothing
+ }
+
+ XDHKeyAgreement(AlgorithmParameterSpec paramSpec) {
+ lockedParams = XECParameters.get(ProviderException::new, paramSpec);
+ }
+
+ @Override
+ protected void engineInit(Key key, SecureRandom random)
+ throws InvalidKeyException {
+
+ initImpl(key);
+ }
+
+ @Override
+ protected void engineInit(Key key, final AlgorithmParameterSpec params,
+ SecureRandom random) throws InvalidKeyException,
+ InvalidAlgorithmParameterException {
+
+ initImpl(key);
+
+ // the private key parameters must match params, if present
+ if (params != null) {
+ XECParameters xecParams = XECParameters.get(
+ InvalidAlgorithmParameterException::new, params);
+ if (!xecParams.oidEquals(this.ops.getParameters())) {
+ throw new InvalidKeyException(
+ "Incorrect private key parameters"
+ );
+ }
+ }
+ }
+
+ private
+ <T extends Throwable>
+ void checkLockedParams(Function<String, T> exception,
+ XECParameters params) throws T {
+
+ if (lockedParams != null && lockedParams != params) {
+ throw exception.apply("Parameters must be " +
+ lockedParams.getName());
+ }
+ }
+
+ private void initImpl(Key key) throws InvalidKeyException {
+
+ if (!(key instanceof XECPrivateKey)) {
+ throw new InvalidKeyException
+ ("Unsupported key type");
+ }
+ XECPrivateKey privateKey = (XECPrivateKey) key;
+ XECParameters xecParams = XECParameters.get(
+ InvalidKeyException::new, privateKey.getParams());
+ checkLockedParams(InvalidKeyException::new, xecParams);
+
+ this.ops = new XECOperations(xecParams);
+ this.privateKey = privateKey.getScalar().orElseThrow(
+ () -> new InvalidKeyException("No private key value")
+ );
+ secret = null;
+ }
+
+ @Override
+ protected Key engineDoPhase(Key key, boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException {
+
+ if (this.privateKey == null) {
+ throw new IllegalStateException("Not initialized");
+ }
+ if (this.secret != null) {
+ throw new IllegalStateException("Phase already executed");
+ }
+ if (!lastPhase) {
+ throw new IllegalStateException
+ ("Only two party agreement supported, lastPhase must be true");
+ }
+ if (!(key instanceof XECPublicKey)) {
+ throw new InvalidKeyException
+ ("Unsupported key type");
+ }
+
+ XECPublicKey publicKey = (XECPublicKey) key;
+
+ // Ensure public key parameters are compatible with private key
+ XECParameters xecParams = XECParameters.get(InvalidKeyException::new,
+ publicKey.getParams());
+ if (!ops.getParameters().oidEquals(xecParams)) {
+ throw new InvalidKeyException(
+ "Public key parameters are not compatible with private key.");
+ }
+
+ // The privateKey may be modified to a value that is equivalent for
+ // the purposes of this algorithm.
+ byte[] computedSecret = ops.encodedPointMultiply(
+ this.privateKey,
+ publicKey.getU());
+
+ // test for contributory behavior
+ if (allZero(computedSecret)) {
+ throw new InvalidKeyException("Point has small order");
+ }
+
+ this.secret = computedSecret;
+
+ return null;
+ }
+
+ /*
+ * Constant-time check for an all-zero array
+ */
+ private boolean allZero(byte[] arr) {
+ byte orValue = (byte) 0;
+ for (int i = 0; i < arr.length; i++) {
+ orValue |= arr[i];
+ }
+
+ return orValue == (byte) 0;
+ }
+
+ @Override
+ protected byte[] engineGenerateSecret() throws IllegalStateException {
+ if (secret == null) {
+ throw new IllegalStateException("Not initialized correctly");
+ }
+
+ byte[] result = secret;
+ secret = null;
+ return result;
+ }
+
+ @Override
+ protected int engineGenerateSecret(byte[] sharedSecret, int offset)
+ throws IllegalStateException, ShortBufferException {
+
+ if (secret == null) {
+ throw new IllegalStateException("Not initialized correctly");
+ }
+ int secretLen = this.secret.length;
+ if (secretLen > sharedSecret.length - offset) {
+ throw new ShortBufferException("Need " + secretLen
+ + " bytes, only " + (sharedSecret.length - offset)
+ + " available");
+ }
+
+ System.arraycopy(this.secret, 0, sharedSecret, offset, secretLen);
+ secret = null;
+ return secretLen;
+ }
+
+ @Override
+ protected SecretKey engineGenerateSecret(String algorithm)
+ throws IllegalStateException, NoSuchAlgorithmException,
+ InvalidKeyException {
+
+ if (algorithm == null) {
+ throw new NoSuchAlgorithmException("Algorithm must not be null");
+ }
+
+ if (!(algorithm.equals("TlsPremasterSecret"))) {
+ throw new NoSuchAlgorithmException(
+ "Only supported for algorithm TlsPremasterSecret");
+ }
+ return new SecretKeySpec(engineGenerateSecret(), algorithm);
+ }
+
+ static class X25519 extends XDHKeyAgreement {
+
+ public X25519() {
+ super(NamedParameterSpec.X25519);
+ }
+ }
+
+ static class X448 extends XDHKeyAgreement {
+
+ public X448() {
+ super(NamedParameterSpec.X448);
+ }
+ }
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyFactory.java b/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyFactory.java
new file mode 100644
index 0000000..ac1dbfe
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyFactory.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.security.KeyFactorySpi;
+import java.security.Key;
+import java.security.PublicKey;
+import java.security.PrivateKey;
+import java.security.InvalidKeyException;
+import java.security.ProviderException;
+import java.security.interfaces.XECKey;
+import java.security.interfaces.XECPrivateKey;
+import java.security.interfaces.XECPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.NamedParameterSpec;
+import java.security.spec.KeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.security.spec.XECPublicKeySpec;
+import java.security.spec.XECPrivateKeySpec;
+import java.util.function.Function;
+
+public class XDHKeyFactory extends KeyFactorySpi {
+
+ private XECParameters lockedParams = null;
+
+ XDHKeyFactory() {
+ // do nothing
+ }
+
+ protected XDHKeyFactory(AlgorithmParameterSpec paramSpec) {
+ lockedParams = XECParameters.get(ProviderException::new, paramSpec);
+ }
+
+ @Override
+ protected Key engineTranslateKey(Key key) throws InvalidKeyException {
+
+ if (key == null) {
+ throw new InvalidKeyException("Key must not be null");
+ }
+
+ if (key instanceof XECKey) {
+ XECKey xecKey = (XECKey) key;
+ XECParameters params = XECParameters.get(InvalidKeyException::new,
+ xecKey.getParams());
+ checkLockedParams(InvalidKeyException::new, params);
+
+ if (xecKey instanceof XECPublicKey) {
+ XECPublicKey publicKey = (XECPublicKey) xecKey;
+ return new XDHPublicKeyImpl(params, publicKey.getU());
+ } else if (xecKey instanceof XECPrivateKey) {
+ XECPrivateKey privateKey = (XECPrivateKey) xecKey;
+ byte[] scalar = privateKey.getScalar().orElseThrow(
+ () -> new InvalidKeyException("No private key data"));
+ return new XDHPrivateKeyImpl(params, scalar);
+ } else {
+ throw new InvalidKeyException("Unsupported XECKey subclass");
+ }
+ } else if (key instanceof PublicKey &&
+ key.getFormat().equals("X.509")) {
+ XDHPublicKeyImpl result = new XDHPublicKeyImpl(key.getEncoded());
+ checkLockedParams(InvalidKeyException::new, result.getParams());
+ return result;
+ } else if (key instanceof PrivateKey &&
+ key.getFormat().equals("PKCS#8")) {
+ XDHPrivateKeyImpl result = new XDHPrivateKeyImpl(key.getEncoded());
+ checkLockedParams(InvalidKeyException::new, result.getParams());
+ return result;
+ } else {
+ throw new InvalidKeyException("Unsupported key type or format");
+ }
+ }
+
+ private
+ <T extends Throwable>
+ void checkLockedParams(Function<String, T> exception,
+ AlgorithmParameterSpec spec) throws T {
+
+ XECParameters params = XECParameters.get(exception, spec);
+ checkLockedParams(exception, params);
+ }
+
+ private
+ <T extends Throwable>
+ void checkLockedParams(Function<String, T> exception,
+ XECParameters params) throws T {
+
+ if (lockedParams != null && lockedParams != params) {
+ throw exception.apply("Parameters must be " +
+ lockedParams.getName());
+ }
+ }
+
+ @Override
+ protected PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException {
+
+ try {
+ return generatePublicImpl(keySpec);
+ } catch (InvalidKeyException ex) {
+ throw new InvalidKeySpecException(ex);
+ }
+ }
+
+ @Override
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException {
+
+ try {
+ return generatePrivateImpl(keySpec);
+ } catch (InvalidKeyException ex) {
+ throw new InvalidKeySpecException(ex);
+ }
+ }
+
+
+ private PublicKey generatePublicImpl(KeySpec keySpec)
+ throws InvalidKeyException, InvalidKeySpecException {
+
+ if (keySpec instanceof X509EncodedKeySpec) {
+ X509EncodedKeySpec x509Spec = (X509EncodedKeySpec) keySpec;
+ XDHPublicKeyImpl result =
+ new XDHPublicKeyImpl(x509Spec.getEncoded());
+ checkLockedParams(InvalidKeySpecException::new,
+ result.getParams());
+ return result;
+ } else if (keySpec instanceof XECPublicKeySpec) {
+ XECPublicKeySpec publicKeySpec = (XECPublicKeySpec) keySpec;
+ XECParameters params = XECParameters.get(
+ InvalidKeySpecException::new, publicKeySpec.getParams());
+ checkLockedParams(InvalidKeySpecException::new, params);
+ return new XDHPublicKeyImpl(params, publicKeySpec.getU());
+ } else {
+ throw new InvalidKeySpecException(
+ "Only X509EncodedKeySpec and XECPublicKeySpec are supported");
+ }
+ }
+
+ private PrivateKey generatePrivateImpl(KeySpec keySpec)
+ throws InvalidKeyException, InvalidKeySpecException {
+
+ if (keySpec instanceof PKCS8EncodedKeySpec) {
+ PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec) keySpec;
+ XDHPrivateKeyImpl result =
+ new XDHPrivateKeyImpl(pkcsSpec.getEncoded());
+ checkLockedParams(InvalidKeySpecException::new,
+ result.getParams());
+ return result;
+ } else if (keySpec instanceof XECPrivateKeySpec) {
+ XECPrivateKeySpec privateKeySpec = (XECPrivateKeySpec) keySpec;
+ XECParameters params = XECParameters.get(
+ InvalidKeySpecException::new, privateKeySpec.getParams());
+ checkLockedParams(InvalidKeySpecException::new, params);
+ return new XDHPrivateKeyImpl(params, privateKeySpec.getScalar());
+ } else {
+ throw new InvalidKeySpecException(
+ "Only PKCS8EncodedKeySpec and XECPrivateKeySpec supported");
+ }
+ }
+
+ protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
+ throws InvalidKeySpecException {
+
+ if (key instanceof XECPublicKey) {
+ checkLockedParams(InvalidKeySpecException::new,
+ ((XECPublicKey) key).getParams());
+
+ if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)) {
+ if (!key.getFormat().equals("X.509")) {
+ throw new InvalidKeySpecException("Format is not X.509");
+ }
+ return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));
+ } else if (keySpec.isAssignableFrom(XECPublicKeySpec.class)) {
+ XECPublicKey xecKey = (XECPublicKey) key;
+ return keySpec.cast(
+ new XECPublicKeySpec(xecKey.getParams(), xecKey.getU()));
+ } else {
+ throw new InvalidKeySpecException(
+ "KeySpec must be X509EncodedKeySpec or XECPublicKeySpec");
+ }
+ } else if (key instanceof XECPrivateKey) {
+ checkLockedParams(InvalidKeySpecException::new,
+ ((XECPrivateKey) key).getParams());
+
+ if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) {
+ if (!key.getFormat().equals("PKCS#8")) {
+ throw new InvalidKeySpecException("Format is not PKCS#8");
+ }
+ return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
+ } else if (keySpec.isAssignableFrom(XECPrivateKeySpec.class)) {
+ XECPrivateKey xecKey = (XECPrivateKey) key;
+ byte[] scalar = xecKey.getScalar().orElseThrow(
+ () -> new InvalidKeySpecException("No private key value")
+ );
+ return keySpec.cast(
+ new XECPrivateKeySpec(xecKey.getParams(), scalar));
+ } else {
+ throw new InvalidKeySpecException
+ ("KeySpec must be PKCS8EncodedKeySpec or XECPrivateKeySpec");
+ }
+ } else {
+ throw new InvalidKeySpecException("Unsupported key type");
+ }
+ }
+
+ static class X25519 extends XDHKeyFactory {
+
+ public X25519() {
+ super(NamedParameterSpec.X25519);
+ }
+ }
+
+ static class X448 extends XDHKeyFactory {
+
+ public X448() {
+ super(NamedParameterSpec.X448);
+ }
+ }
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyPairGenerator.java b/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyPairGenerator.java
new file mode 100644
index 0000000..b2d20b5
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyPairGenerator.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.math.BigInteger;
+import java.security.KeyPairGeneratorSpi;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.ProviderException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.NamedParameterSpec;
+
+import sun.security.jca.JCAUtil;
+
+/**
+ * Key pair generator for the XDH key agreement algorithm.
+ */
+public class XDHKeyPairGenerator extends KeyPairGeneratorSpi {
+
+ private static final NamedParameterSpec DEFAULT_PARAM_SPEC
+ = NamedParameterSpec.X25519;
+
+ private SecureRandom random = null;
+ private XECOperations ops = null;
+ private XECParameters lockedParams = null;
+
+ XDHKeyPairGenerator() {
+ tryInitialize(DEFAULT_PARAM_SPEC);
+ }
+
+ private XDHKeyPairGenerator(NamedParameterSpec paramSpec) {
+ tryInitialize(paramSpec);
+ lockedParams = ops.getParameters();
+ }
+
+ private void tryInitialize(NamedParameterSpec paramSpec) {
+ try {
+ initialize(paramSpec, null);
+ } catch (InvalidAlgorithmParameterException ex) {
+ String name = paramSpec.getName();
+ throw new ProviderException(name + " not supported");
+ }
+ }
+
+ @Override
+ public void initialize(int keySize, SecureRandom random) {
+
+ XECParameters params = XECParameters.getBySize(
+ InvalidParameterException::new, keySize);
+
+ initializeImpl(params, random);
+ }
+
+ @Override
+ public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+ throws InvalidAlgorithmParameterException {
+
+ XECParameters xecParams = XECParameters.get(
+ InvalidAlgorithmParameterException::new, params);
+
+ initializeImpl(xecParams, random);
+ }
+
+ private void initializeImpl(XECParameters params, SecureRandom random) {
+
+ if (lockedParams != null && lockedParams != params) {
+ throw new InvalidParameterException("Parameters must be " +
+ lockedParams.getName());
+ }
+
+ this.ops = new XECOperations(params);
+ this.random = random == null ? JCAUtil.getSecureRandom() : random;
+ }
+
+
+ @Override
+ public KeyPair generateKeyPair() {
+
+ byte[] privateKey = ops.generatePrivate(random);
+ // computePublic may modify the private key, so clone it first
+ BigInteger publicKey = ops.computePublic(privateKey.clone());
+
+ try {
+ return new KeyPair(
+ new XDHPublicKeyImpl(ops.getParameters(), publicKey),
+ new XDHPrivateKeyImpl(ops.getParameters(), privateKey)
+ );
+ } catch (InvalidKeyException ex) {
+ throw new ProviderException(ex);
+ }
+ }
+
+ static class X25519 extends XDHKeyPairGenerator {
+
+ public X25519() {
+ super(NamedParameterSpec.X25519);
+ }
+ }
+
+ static class X448 extends XDHKeyPairGenerator {
+
+ public X448() {
+ super(NamedParameterSpec.X448);
+ }
+ }
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/XDHPrivateKeyImpl.java b/jdk.crypto.ec/share/classes/sun/security/ec/XDHPrivateKeyImpl.java
new file mode 100644
index 0000000..2b93cfd
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/XDHPrivateKeyImpl.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.security.interfaces.XECPrivateKey;
+import java.util.Optional;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.NamedParameterSpec;
+
+import sun.security.pkcs.PKCS8Key;
+import sun.security.x509.AlgorithmId;
+
+public final class XDHPrivateKeyImpl extends PKCS8Key implements XECPrivateKey {
+
+ private static final long serialVersionUID = 1L;
+
+ private AlgorithmParameterSpec paramSpec;
+
+ XDHPrivateKeyImpl(XECParameters params, byte[] k)
+ throws InvalidKeyException {
+
+ this.paramSpec = new NamedParameterSpec(params.getName());
+ this.algid = new AlgorithmId(params.getOid());
+ this.key = k.clone();
+
+ checkLength(params);
+ }
+
+ XDHPrivateKeyImpl(byte[] encoded) throws InvalidKeyException {
+
+ decode(encoded);
+ XECParameters params = XECParameters.get(
+ InvalidKeyException::new, algid);
+ paramSpec = new NamedParameterSpec(params.getName());
+
+ checkLength(params);
+ }
+
+ void checkLength(XECParameters params) throws InvalidKeyException {
+
+ if (params.getBytes() != this.key.length) {
+ throw new InvalidKeyException(
+ "key length must be " + params.getBytes());
+ }
+ }
+
+ public byte[] getK() {
+ return key.clone();
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return "XDH";
+ }
+
+ @Override
+ public AlgorithmParameterSpec getParams() {
+ return paramSpec;
+ }
+
+ @Override
+ public Optional<byte[]> getScalar() {
+ return Optional.of(getK());
+ }
+}
+
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/XDHPublicKeyImpl.java b/jdk.crypto.ec/share/classes/sun/security/ec/XDHPublicKeyImpl.java
new file mode 100644
index 0000000..0b9b6d9
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/XDHPublicKeyImpl.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.KeyRep;
+import java.security.PublicKey;
+import java.security.interfaces.XECPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.NamedParameterSpec;
+import java.util.Arrays;
+
+import sun.security.util.BitArray;
+import sun.security.x509.AlgorithmId;
+import sun.security.x509.X509Key;
+
+public final class XDHPublicKeyImpl extends X509Key implements XECPublicKey {
+
+ private static final long serialVersionUID = 1L;
+
+ private final BigInteger u;
+ private final NamedParameterSpec paramSpec;
+
+ XDHPublicKeyImpl(XECParameters params, BigInteger u)
+ throws InvalidKeyException {
+
+ this.paramSpec = new NamedParameterSpec(params.getName());
+ this.algid = new AlgorithmId(params.getOid());
+ this.u = u.mod(params.getP());
+
+ byte[] u_arr = this.u.toByteArray();
+ reverse(u_arr);
+ // u_arr may be too large or too small, depending on the value of u
+ u_arr = Arrays.copyOf(u_arr, params.getBytes());
+
+ setKey(new BitArray(u_arr.length * 8, u_arr));
+
+ checkLength(params);
+ }
+
+ XDHPublicKeyImpl(byte[] encoded) throws InvalidKeyException {
+ decode(encoded);
+
+ XECParameters params =
+ XECParameters.get(InvalidKeyException::new, algid);
+ this.paramSpec = new NamedParameterSpec(params.getName());
+ // construct the BigInteger representation
+ byte[] u_arr = getKey().toByteArray();
+ reverse(u_arr);
+
+ // clear the extra bits
+ int bitsMod8 = params.getBits() % 8;
+ if (bitsMod8 != 0) {
+ int mask = (1 << bitsMod8) - 1;
+ u_arr[0] &= mask;
+ }
+
+ this.u = new BigInteger(1, u_arr);
+
+ checkLength(params);
+ }
+
+ void checkLength(XECParameters params) throws InvalidKeyException {
+
+ if (params.getBytes() * 8 != getKey().length()) {
+ throw new InvalidKeyException(
+ "key length must be " + params.getBytes());
+ }
+ }
+
+ @Override
+ public BigInteger getU() {
+ return u;
+ }
+
+ @Override
+ public AlgorithmParameterSpec getParams() {
+ return paramSpec;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return "XDH";
+ }
+
+ protected Object writeReplace() throws java.io.ObjectStreamException {
+ return new KeyRep(KeyRep.Type.PUBLIC,
+ getAlgorithm(),
+ getFormat(),
+ getEncoded());
+ }
+
+ private static void swap(byte[] arr, int i, int j) {
+ byte tmp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = tmp;
+ }
+
+ private static void reverse(byte [] arr) {
+ int i = 0;
+ int j = arr.length - 1;
+
+ while (i < j) {
+ swap(arr, i, j);
+ i++;
+ j--;
+ }
+ }
+}
+
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/XECOperations.java b/jdk.crypto.ec/share/classes/sun/security/ec/XECOperations.java
new file mode 100644
index 0000000..d26ec63
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/XECOperations.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import sun.security.util.math.IntegerFieldModuloP;
+import sun.security.util.math.ImmutableIntegerModuloP;
+import sun.security.util.math.IntegerModuloP;
+import sun.security.util.math.MutableIntegerModuloP;
+import sun.security.util.math.SmallValue;
+import sun.security.util.math.intpoly.IntegerPolynomial25519;
+import sun.security.util.math.intpoly.IntegerPolynomial448;
+
+import java.math.BigInteger;
+import java.security.ProviderException;
+import java.security.SecureRandom;
+
+public class XECOperations {
+
+ private final XECParameters params;
+ private final IntegerFieldModuloP field;
+ private final ImmutableIntegerModuloP zero;
+ private final ImmutableIntegerModuloP one;
+ private final SmallValue a24;
+ private final ImmutableIntegerModuloP basePoint;
+
+ public XECOperations(XECParameters c) {
+ this.params = c;
+
+ BigInteger p = params.getP();
+ this.field = getIntegerFieldModulo(p);
+ this.zero = field.getElement(BigInteger.ZERO).fixed();
+ this.one = field.get1().fixed();
+ this.a24 = field.getSmallValue(params.getA24());
+ this.basePoint = field.getElement(
+ BigInteger.valueOf(c.getBasePoint()));
+ }
+
+ public XECParameters getParameters() {
+ return params;
+ }
+
+ public byte[] generatePrivate(SecureRandom random) {
+ byte[] result = new byte[this.params.getBytes()];
+ random.nextBytes(result);
+ return result;
+ }
+
+ /**
+ * Compute a public key from an encoded private key. This method will
+ * modify the supplied array in order to prune it.
+ */
+ public BigInteger computePublic(byte[] k) {
+ pruneK(k);
+ return pointMultiply(k, this.basePoint).asBigInteger();
+ }
+
+ /**
+ *
+ * Multiply an encoded scalar with a point as a BigInteger and return an
+ * encoded point. The array k holding the scalar will be pruned by
+ * modifying it in place.
+ *
+ * @param k an encoded scalar
+ * @param u the u-coordinate of a point as a BigInteger
+ * @return the encoded product
+ */
+ public byte[] encodedPointMultiply(byte[] k, BigInteger u) {
+ pruneK(k);
+ ImmutableIntegerModuloP elemU = field.getElement(u);
+ return pointMultiply(k, elemU).asByteArray(params.getBytes());
+ }
+
+ /**
+ *
+ * Multiply an encoded scalar with an encoded point and return an encoded
+ * point. The array k holding the scalar will be pruned by
+ * modifying it in place.
+ *
+ * @param k an encoded scalar
+ * @param u an encoded point
+ * @return the encoded product
+ */
+ public byte[] encodedPointMultiply(byte[] k, byte[] u) {
+ pruneK(k);
+ ImmutableIntegerModuloP elemU = decodeU(u);
+ return pointMultiply(k, elemU).asByteArray(params.getBytes());
+ }
+
+ /**
+ * Return the field element corresponding to an encoded u-coordinate.
+ * This method prunes u by modifying it in place.
+ *
+ * @param u
+ * @param bits
+ * @return
+ */
+ private ImmutableIntegerModuloP decodeU(byte[] u, int bits) {
+
+ maskHighOrder(u, bits);
+
+ return field.getElement(u);
+ }
+
+ /**
+ * Mask off the high order bits of an encoded integer in an array. The
+ * array is modified in place.
+ *
+ * @param arr an array containing an encoded integer
+ * @param bits the number of bits to keep
+ * @return the number, in range [1,8], of bits kept in the highest byte
+ */
+ private static byte maskHighOrder(byte[] arr, int bits) {
+
+ int lastByteIndex = arr.length - 1;
+ byte bitsMod8 = (byte) (bits % 8);
+ byte highBits = bitsMod8 == 0 ? 8 : bitsMod8;
+ byte msbMaskOff = (byte) ((1 << highBits) - 1);
+ arr[lastByteIndex] &= msbMaskOff;
+
+ return highBits;
+ }
+
+ /**
+ * Prune an encoded scalar value by modifying it in place. The extra
+ * high-order bits are masked off, the highest valid bit it set, and the
+ * number is rounded down to a multiple of the cofactor.
+ *
+ * @param k an encoded scalar value
+ * @param bits the number of bits in the scalar
+ * @param logCofactor the base-2 logarithm of the cofactor
+ */
+ private static void pruneK(byte[] k, int bits, int logCofactor) {
+
+ int lastByteIndex = k.length - 1;
+
+ // mask off unused high-order bits
+ byte highBits = maskHighOrder(k, bits);
+
+ // set the highest bit
+ byte msbMaskOn = (byte) (1 << (highBits - 1));
+ k[lastByteIndex] |= msbMaskOn;
+
+ // round down to a multiple of the cofactor
+ byte lsbMaskOff = (byte) (0xFF << logCofactor);
+ k[0] &= lsbMaskOff;
+ }
+
+ private void pruneK(byte[] k) {
+ pruneK(k, params.getBits(), params.getLogCofactor());
+ }
+
+ private ImmutableIntegerModuloP decodeU(byte [] u) {
+ return decodeU(u, params.getBits());
+ }
+
+ // Constant-time conditional swap
+ private static void cswap(int swap, MutableIntegerModuloP x1,
+ MutableIntegerModuloP x2) {
+
+ x1.conditionalSwapWith(x2, swap);
+ }
+
+ private static IntegerFieldModuloP getIntegerFieldModulo(BigInteger p) {
+
+ if (p.equals(IntegerPolynomial25519.MODULUS)) {
+ return new IntegerPolynomial25519();
+ }
+ else if (p.equals(IntegerPolynomial448.MODULUS)) {
+ return new IntegerPolynomial448();
+ }
+
+ throw new ProviderException("Unsupported prime: " + p.toString());
+ }
+
+ private int bitAt(byte[] arr, int index) {
+ int byteIndex = index / 8;
+ int bitIndex = index % 8;
+ return (arr[byteIndex] & (1 << bitIndex)) >> bitIndex;
+ }
+
+ /*
+ * Constant-time Montgomery ladder that computes k*u and returns the
+ * result as a field element.
+ */
+ private IntegerModuloP pointMultiply(byte[] k,
+ ImmutableIntegerModuloP u) {
+
+ ImmutableIntegerModuloP x_1 = u;
+ MutableIntegerModuloP x_2 = this.one.mutable();
+ MutableIntegerModuloP z_2 = this.zero.mutable();
+ MutableIntegerModuloP x_3 = u.mutable();
+ MutableIntegerModuloP z_3 = this.one.mutable();
+ int swap = 0;
+
+ // Variables below are reused to avoid unnecessary allocation
+ // They will be assigned in the loop, so initial value doesn't matter
+ MutableIntegerModuloP m1 = this.zero.mutable();
+ MutableIntegerModuloP DA = this.zero.mutable();
+ MutableIntegerModuloP E = this.zero.mutable();
+ MutableIntegerModuloP a24_times_E = this.zero.mutable();
+
+ // Comments describe the equivalent operations from RFC 7748
+ // In comments, A(m1) means the variable m1 holds the value A
+ for (int t = params.getBits() - 1; t >= 0; t--) {
+ int k_t = bitAt(k, t);
+ swap = swap ^ k_t;
+ cswap(swap, x_2, x_3);
+ cswap(swap, z_2, z_3);
+ swap = k_t;
+
+ // A(m1) = x_2 + z_2
+ m1.setValue(x_2).setSum(z_2);
+ // D = x_3 - z_3
+ // DA = D * A(m1)
+ DA.setValue(x_3).setDifference(z_3).setProduct(m1);
+ // AA(m1) = A(m1)^2
+ m1.setSquare();
+ // B(x_2) = x_2 - z_2
+ x_2.setDifference(z_2);
+ // C = x_3 + z_3
+ // CB(x_3) = C * B(x_2)
+ x_3.setSum(z_3).setProduct(x_2);
+ // BB(x_2) = B^2
+ x_2.setSquare();
+ // E = AA(m1) - BB(x_2)
+ E.setValue(m1).setDifference(x_2);
+ // compute a24 * E using SmallValue
+ a24_times_E.setValue(E);
+ a24_times_E.setProduct(this.a24);
+
+ // assign results to x_3, z_3, x_2, z_2
+ // x_2 = AA(m1) * BB
+ x_2.setProduct(m1);
+ // z_2 = E * (AA(m1) + a24 * E)
+ z_2.setValue(m1).setSum(a24_times_E).setProduct(E);
+ // z_3 = x_1*(DA - CB(x_3))^2
+ z_3.setValue(DA).setDifference(x_3).setSquare().setProduct(x_1);
+ // x_3 = (CB(x_3) + DA)^2
+ x_3.setSum(DA).setSquare();
+ }
+
+ cswap(swap, x_2, x_3);
+ cswap(swap, z_2, z_3);
+
+ // return (x_2 * z_2^(p - 2))
+ return x_2.setProduct(z_2.multiplicativeInverse());
+ }
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/XECParameters.java b/jdk.crypto.ec/share/classes/sun/security/ec/XECParameters.java
new file mode 100644
index 0000000..9d7bddb
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/XECParameters.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.NamedParameterSpec;
+import java.util.Collections;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import sun.security.util.ObjectIdentifier;
+import sun.security.x509.AlgorithmId;
+
+public class XECParameters {
+
+ // Naming/identification parameters
+ private final ObjectIdentifier oid;
+ private final String name;
+
+ // Curve/field parameters
+ private final int bits;
+ private final BigInteger p;
+ private final int logCofactor;
+ private final int a24;
+ private final byte basePoint;
+
+ /**
+ *
+ * Construct an object holding the supplied parameters. No parameters are
+ * checked, so this method always succeeds. This method supports
+ * Montgomery curves of the form y^2 = x^3 + ax^2 + x.
+ *
+ * @param bits The number of relevant bits in a public/private key.
+ * @param p The prime that defines the finite field.
+ * @param a24 The value of (a - 2) / 4, where a is the second-degree curve
+ * coefficient.
+ * @param basePoint The point that generates the desired group
+ * @param logCofactor The base-2 logarithm of the cofactor of the curve
+ * @param oid
+ * @param name
+ */
+ public XECParameters(int bits, BigInteger p, int a24,
+ byte basePoint, int logCofactor,
+ ObjectIdentifier oid, String name) {
+
+ this.bits = bits;
+ this.logCofactor = logCofactor;
+ this.p = p;
+ this.a24 = a24;
+ this.basePoint = basePoint;
+ this.oid = oid;
+ this.name = name;
+
+ }
+
+ public int getBits() {
+ return bits;
+ }
+ public int getBytes() {
+ return (bits + 7) / 8;
+ }
+ public int getLogCofactor() {
+ return logCofactor;
+ }
+ public BigInteger getP() {
+ return p;
+ }
+ public int getA24() {
+ return a24;
+ }
+ public byte getBasePoint() {
+ return basePoint;
+ }
+ public ObjectIdentifier getOid() {
+ return oid;
+ }
+ public String getName() {
+ return name;
+ }
+
+ private static final Map<Integer, XECParameters> SIZE_MAP;
+ private static final Map<ObjectIdentifier, XECParameters> OID_MAP;
+ private static final Map<String, XECParameters> NAME_MAP;
+
+ static {
+ final BigInteger TWO = BigInteger.valueOf(2);
+
+ Map<Integer, XECParameters> bySize = new HashMap<>();
+ Map<ObjectIdentifier, XECParameters> byOid = new HashMap<>();
+ Map<String, XECParameters> byName = new HashMap<>();
+
+ // set up X25519
+ try {
+ BigInteger p = TWO.pow(255).subtract(BigInteger.valueOf(19));
+ addParameters(255, p, 121665, (byte) 0x09, 3,
+ new int[]{1, 3, 101, 110}, NamedParameterSpec.X25519.getName(),
+ bySize, byOid, byName);
+
+ } catch (IOException ex) {
+ // Unable to set X25519 parameters---it will be disabled
+ }
+
+ // set up X448
+ try {
+ BigInteger p = TWO.pow(448).subtract(TWO.pow(224))
+ .subtract(BigInteger.ONE);
+ addParameters(448, p, 39081, (byte) 0x05, 2,
+ new int[]{1, 3, 101, 111}, NamedParameterSpec.X448.getName(),
+ bySize, byOid, byName);
+
+ } catch (IOException ex) {
+ // Unable to set X448 parameters---it will be disabled
+ }
+
+ SIZE_MAP = Collections.unmodifiableMap(bySize);
+ OID_MAP = Collections.unmodifiableMap(byOid);
+ NAME_MAP = Collections.unmodifiableMap(byName);
+ }
+
+ private static void addParameters(int bits, BigInteger p, int a24,
+ byte basePoint, int logCofactor, int[] oidBytes, String name,
+ Map<Integer, XECParameters> bySize,
+ Map<ObjectIdentifier, XECParameters> byOid,
+ Map<String, XECParameters> byName) throws IOException {
+
+ ObjectIdentifier oid = new ObjectIdentifier(oidBytes);
+ XECParameters params =
+ new XECParameters(bits, p, a24, basePoint, logCofactor, oid, name);
+ bySize.put(bits, params);
+ byOid.put(oid, params);
+ byName.put(name.toLowerCase(), params);
+ }
+
+ public static Optional<XECParameters> getByOid(ObjectIdentifier id) {
+ return Optional.ofNullable(OID_MAP.get(id));
+ }
+ public static Optional<XECParameters> getBySize(int size) {
+ return Optional.ofNullable(SIZE_MAP.get(size));
+ }
+ public static Optional<XECParameters> getByName(String name) {
+ return Optional.ofNullable(NAME_MAP.get(name.toLowerCase()));
+ }
+
+ boolean oidEquals(XECParameters other) {
+ return oid.equals(other.getOid());
+ }
+
+ // Utility method that is used by the methods below to handle exception
+ // suppliers
+ private static
+ <A, B> Supplier<B> apply(final Function<A, B> func, final A a) {
+ return new Supplier<B>() {
+ @Override
+ public B get() {
+ return func.apply(a);
+ }
+ };
+ }
+
+ /**
+ * Get parameters by key size, or throw an exception if no parameters are
+ * defined for the specified key size. This method is used in several
+ * contexts that should throw different exceptions when the parameters
+ * are not found. The first argument is a function that produces the
+ * desired exception.
+ *
+ * @param exception a function that produces an exception from a string
+ * @param size the desired key size
+ * @param <T> the type of exception that is thrown
+ * @return the parameters for the specified key size
+ * @throws T when suitable parameters do not exist
+ */
+ public static
+ <T extends Throwable>
+ XECParameters getBySize(Function<String, T> exception,
+ int size) throws T {
+
+ Optional<XECParameters> xecParams = getBySize(size);
+ return xecParams.orElseThrow(
+ apply(exception, "Unsupported size: " + size));
+ }
+
+ /**
+ * Get parameters by algorithm ID, or throw an exception if no
+ * parameters are defined for the specified ID. This method is used in
+ * several contexts that should throw different exceptions when the
+ * parameters are not found. The first argument is a function that produces
+ * the desired exception.
+ *
+ * @param exception a function that produces an exception from a string
+ * @param algId the algorithm ID
+ * @param <T> the type of exception that is thrown
+ * @return the parameters for the specified algorithm ID
+ * @throws T when suitable parameters do not exist
+ */
+ public static
+ <T extends Throwable>
+ XECParameters get(Function<String, T> exception,
+ AlgorithmId algId) throws T {
+
+ Optional<XECParameters> xecParams = getByOid(algId.getOID());
+ return xecParams.orElseThrow(
+ apply(exception, "Unsupported OID: " + algId.getOID()));
+ }
+
+ /**
+ * Get parameters by algorithm parameter spec, or throw an exception if no
+ * parameters are defined for the spec. This method is used in
+ * several contexts that should throw different exceptions when the
+ * parameters are not found. The first argument is a function that produces
+ * the desired exception.
+ *
+ * @param exception a function that produces an exception from a string
+ * @param params the algorithm parameters spec
+ * @param <T> the type of exception that is thrown
+ * @return the parameters for the spec
+ * @throws T when suitable parameters do not exist
+ */
+ public static
+ <T extends Throwable>
+ XECParameters get(Function<String, T> exception,
+ AlgorithmParameterSpec params) throws T {
+
+ if (params instanceof NamedParameterSpec) {
+ NamedParameterSpec namedParams = (NamedParameterSpec) params;
+ Optional<XECParameters> xecParams =
+ getByName(namedParams.getName());
+ return xecParams.orElseThrow(
+ apply(exception, "Unsupported name: " + namedParams.getName()));
+ } else {
+ throw exception.apply("Only NamedParameterSpec is supported.");
+ }
+ }
+}
+
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/point/AffinePoint.java b/jdk.crypto.ec/share/classes/sun/security/ec/point/AffinePoint.java
new file mode 100644
index 0000000..a8b74bd
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/point/AffinePoint.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.security.ec.point;
+
+import sun.security.util.math.ImmutableIntegerModuloP;
+
+import java.util.Objects;
+
+/**
+ * Elliptic curve point represented using affine coordinates (x, y). This class
+ * is not part of the sun.security.ec.point.Point hierarchy because it is not
+ * used to hold intermediate values during point arithmetic, and so it does not
+ * have a mutable form.
+ */
+public class AffinePoint {
+
+ private final ImmutableIntegerModuloP x;
+ private final ImmutableIntegerModuloP y;
+
+ public AffinePoint(ImmutableIntegerModuloP x, ImmutableIntegerModuloP y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public ImmutableIntegerModuloP getX() {
+ return x;
+ }
+
+ public ImmutableIntegerModuloP getY() {
+ return y;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AffinePoint)) {
+ return false;
+ }
+ AffinePoint p = (AffinePoint) obj;
+ boolean xEquals = x.asBigInteger().equals(p.x.asBigInteger());
+ boolean yEquals = y.asBigInteger().equals(p.y.asBigInteger());
+ return xEquals && yEquals;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(x, y);
+ }
+
+ @Override
+ public String toString() {
+ return "(" + x.asBigInteger().toString() + "," +
+ y.asBigInteger().toString() + ")";
+ }
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/point/ImmutablePoint.java b/jdk.crypto.ec/share/classes/sun/security/ec/point/ImmutablePoint.java
new file mode 100644
index 0000000..7f6c6b3
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/point/ImmutablePoint.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec.point;
+
+/**
+ * An interface for immutable points on an elliptic curve over a finite field.
+ */
+public interface ImmutablePoint extends Point {
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/point/MutablePoint.java b/jdk.crypto.ec/share/classes/sun/security/ec/point/MutablePoint.java
new file mode 100644
index 0000000..cb714ac
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/point/MutablePoint.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec.point;
+
+/**
+ * An interface for mutable points on an elliptic curve over a finite field.
+ */
+public interface MutablePoint extends Point {
+
+ MutablePoint setValue(AffinePoint p);
+ MutablePoint setValue(Point p);
+ MutablePoint conditionalSet(Point p, int set);
+
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/point/Point.java b/jdk.crypto.ec/share/classes/sun/security/ec/point/Point.java
new file mode 100644
index 0000000..b28bd9d
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/point/Point.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ec.point;
+
+import sun.security.util.math.IntegerFieldModuloP;
+
+/**
+ * A base interface for points on an elliptic curve over a finite field.
+ * Implementations may use different representations for points, and this
+ * interface creates a common API for manipulating points. This API has no
+ * methods for point arithmetic, which depends on group structure and curve
+ * parameters in addition to point representation.
+ */
+public interface Point {
+
+ IntegerFieldModuloP getField();
+ AffinePoint asAffine();
+
+ ImmutablePoint fixed();
+ MutablePoint mutable();
+
+}
diff --git a/jdk.crypto.ec/share/classes/sun/security/ec/point/ProjectivePoint.java b/jdk.crypto.ec/share/classes/sun/security/ec/point/ProjectivePoint.java
new file mode 100644
index 0000000..587f1c7
--- /dev/null
+++ b/jdk.crypto.ec/share/classes/sun/security/ec/point/ProjectivePoint.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.security.ec.point;
+
+import sun.security.util.math.*;
+
+/**
+ * Elliptic curve point in projective coordinates (X, Y, Z) where
+ * an affine point (x, y) is represented using any (X, Y, Z) s.t.
+ * x = X/Z and y = Y/Z.
+ */
+public abstract class ProjectivePoint
+ <T extends IntegerModuloP> implements Point {
+
+ protected final T x;
+ protected final T y;
+ protected final T z;
+
+ protected ProjectivePoint(T x, T y, T z) {
+
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ @Override
+ public IntegerFieldModuloP getField() {
+ return this.x.getField();
+ }
+
+ @Override
+ public Immutable fixed() {
+ return new Immutable(x.fixed(), y.fixed(), z.fixed());
+ }
+
+ @Override
+ public Mutable mutable() {
+ return new Mutable(x.mutable(), y.mutable(), z.mutable());
+ }
+
+ public T getX() {
+ return x;
+ }
+
+ public T getY() {
+ return y;
+ }
+
+ public T getZ() {
+ return z;
+ }
+
+ public AffinePoint asAffine() {
+ IntegerModuloP zInv = z.multiplicativeInverse();
+ return new AffinePoint(x.multiply(zInv), y.multiply(zInv));
+ }
+
+ public static class Immutable
+ extends ProjectivePoint<ImmutableIntegerModuloP>
+ implements ImmutablePoint {
+
+ public Immutable(ImmutableIntegerModuloP x,
+ ImmutableIntegerModuloP y,
+ ImmutableIntegerModuloP z) {
+ super(x, y, z);
+ }
+ }
+
+ public static class Mutable
+ extends ProjectivePoint<MutableIntegerModuloP>
+ implements MutablePoint {
+
+ public Mutable(MutableIntegerModuloP x,
+ MutableIntegerModuloP y,
+ MutableIntegerModuloP z) {
+ super(x, y, z);
+ }
+
+ public Mutable(IntegerFieldModuloP field) {
+ super(field.get0().mutable(),
+ field.get0().mutable(),
+ field.get0().mutable());
+ }
+
+ @Override
+ public Mutable conditionalSet(Point p, int set) {
+ if (!(p instanceof ProjectivePoint)) {
+ throw new RuntimeException("Incompatible point");
+ }
+ @SuppressWarnings("unchecked")
+ ProjectivePoint<IntegerModuloP> pp =
+ (ProjectivePoint<IntegerModuloP>) p;
+ return conditionalSet(pp, set);
+ }
+
+ private <T extends IntegerModuloP>
+ Mutable conditionalSet(ProjectivePoint<T> pp, int set) {
+
+ x.conditionalSet(pp.x, set);
+ y.conditionalSet(pp.y, set);
+ z.conditionalSet(pp.z, set);
+
+ return this;
+ }
+
+ @Override
+ public Mutable setValue(AffinePoint p) {
+ x.setValue(p.getX());
+ y.setValue(p.getY());
+ z.setValue(p.getX().getField().get1());
+
+ return this;
+ }
+
+ @Override
+ public Mutable setValue(Point p) {
+ if (!(p instanceof ProjectivePoint)) {
+ throw new RuntimeException("Incompatible point");
+ }
+ @SuppressWarnings("unchecked")
+ ProjectivePoint<IntegerModuloP> pp =
+ (ProjectivePoint<IntegerModuloP>) p;
+ return setValue(pp);
+ }
+
+ private <T extends IntegerModuloP>
+ Mutable setValue(ProjectivePoint<T> pp) {
+
+ x.setValue(pp.x);
+ y.setValue(pp.y);
+ z.setValue(pp.z);
+
+ return this;
+ }
+
+ }
+
+}
diff --git a/jdk.crypto.ec/share/legal/ecc.md b/jdk.crypto.ec/share/legal/ecc.md
new file mode 100644
index 0000000..a054b86
--- /dev/null
+++ b/jdk.crypto.ec/share/legal/ecc.md
@@ -0,0 +1,578 @@
+## Mozilla Elliptic Curve Cryptography (ECC)
+
+### Mozilla ECC Notice
+
+This notice is provided with respect to Elliptic Curve Cryptography,
+which is included with JRE, JDK, and OpenJDK.
+
+You are receiving a [copy](http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/tip/src/jdk.crypto.ec/share/native/libsunec/impl)
+of the Elliptic Curve Cryptography library in source
+form with the JDK and OpenJDK source distributions, and as object code in
+the JRE & JDK runtimes.
+<pre>
+In the case of the JRE & JDK runtimes, the terms of the Oracle license do
+NOT apply to the Elliptic Curve Cryptography library; it is licensed under the
+following license, separately from Oracle's JDK & JRE. If you do not wish to
+install the Elliptic Curve Cryptography library, you may delete the
+Elliptic Curve Cryptography library:
+ - On Solaris and Linux systems: delete $(JAVA_HOME)/lib/libsunec.so
+ - On Mac OSX systems: delete $(JAVA_HOME)/lib/libsunec.dylib
+ - On Windows systems: delete $(JAVA_HOME)\bin\sunec.dll
+
+</pre>
+
+### Written Offer for Source Code
+<pre>
+
+For third party technology that you receive from Oracle in binary form
+which is licensed under an open source license that gives you the right
+to receive the source code for that binary, you can obtain a copy of
+the applicable source code from this page:
+ http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/tip/src/jdk.crypto.ec/share/native/libsunec/impl
+
+If the source code for the technology was not provided to you with the
+binary, you can also receive a copy of the source code on physical
+media by submitting a written request to:
+
+ Oracle America, Inc.
+ Attn: Associate General Counsel,
+ Development and Engineering Legal
+ 500 Oracle Parkway, 10th Floor
+ Redwood Shores, CA 94065
+
+Or, you may send an email to Oracle using the form at:
+
+http://www.oracle.com/goto/opensourcecode/request
+
+Your request should include:
+
+ - The name of the component or binary file(s) for which you are requesting the source code
+
+ - The name and version number of the Oracle product containing the binary
+
+ - The date you received the Oracle product
+
+ - Your name
+
+ - Your company name (if applicable)
+
+ - Your return mailing address and email and
+
+ - A telephone number in the event we need to reach you.
+
+We may charge you a fee to cover the cost of physical media and processing.
+Your request must be sent (i) within three (3) years of the date you
+received the Oracle product that included the component or binary
+file(s) that are the subject of your request, or (ii) in the case of
+code licensed under the GPL v3, for as long as Oracle offers spare
+parts or customer support for that product model.
+
+</pre>
+
+### LGPL 2.1
+<pre>
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+</pre>
diff --git a/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp b/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp
new file mode 100644
index 0000000..e784947
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp
@@ -0,0 +1,580 @@
+/*
+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <jni.h>
+#include "jni_util.h"
+#include "impl/ecc_impl.h"
+#include "sun_security_ec_ECDHKeyAgreement.h"
+#include "sun_security_ec_ECKeyPairGenerator.h"
+#include "sun_security_ec_ECDSASignature.h"
+
+#define ILLEGAL_STATE_EXCEPTION "java/lang/IllegalStateException"
+#define INVALID_ALGORITHM_PARAMETER_EXCEPTION \
+ "java/security/InvalidAlgorithmParameterException"
+#define INVALID_PARAMETER_EXCEPTION \
+ "java/security/InvalidParameterException"
+#define KEY_EXCEPTION "java/security/KeyException"
+
+extern "C" {
+
+/*
+ * Declare library specific JNI_Onload entry if static build
+ */
+DEF_STATIC_JNI_OnLoad
+
+/*
+ * Throws an arbitrary Java exception.
+ */
+void ThrowException(JNIEnv *env, const char *exceptionName)
+{
+ jclass exceptionClazz = env->FindClass(exceptionName);
+ if (exceptionClazz != NULL) {
+ env->ThrowNew(exceptionClazz, NULL);
+ }
+}
+
+/*
+ * Deep free of the ECParams struct
+ */
+void FreeECParams(ECParams *ecparams, jboolean freeStruct)
+{
+ // Use B_FALSE to free the SECItem->data element, but not the SECItem itself
+ // Use B_TRUE to free both
+
+ SECITEM_FreeItem(&ecparams->fieldID.u.prime, B_FALSE);
+ SECITEM_FreeItem(&ecparams->curve.a, B_FALSE);
+ SECITEM_FreeItem(&ecparams->curve.b, B_FALSE);
+ SECITEM_FreeItem(&ecparams->curve.seed, B_FALSE);
+ SECITEM_FreeItem(&ecparams->base, B_FALSE);
+ SECITEM_FreeItem(&ecparams->order, B_FALSE);
+ SECITEM_FreeItem(&ecparams->DEREncoding, B_FALSE);
+ SECITEM_FreeItem(&ecparams->curveOID, B_FALSE);
+ if (freeStruct)
+ free(ecparams);
+}
+
+jbyteArray getEncodedBytes(JNIEnv *env, SECItem *hSECItem)
+{
+ SECItem *s = (SECItem *)hSECItem;
+
+ jbyteArray jEncodedBytes = env->NewByteArray(s->len);
+ if (jEncodedBytes == NULL) {
+ return NULL;
+ }
+ // Copy bytes from a native SECItem buffer to Java byte array
+ env->SetByteArrayRegion(jEncodedBytes, 0, s->len, (jbyte *)s->data);
+ if (env->ExceptionCheck()) { // should never happen
+ return NULL;
+ }
+ return jEncodedBytes;
+}
+
+/*
+ * Class: sun_security_ec_ECKeyPairGenerator
+ * Method: isCurveSupported
+ * Signature: ([B)Z
+ */
+JNIEXPORT jboolean
+JNICALL Java_sun_security_ec_ECKeyPairGenerator_isCurveSupported
+ (JNIEnv *env, jclass clazz, jbyteArray encodedParams)
+{
+ SECKEYECParams params_item;
+ ECParams *ecparams = NULL;
+ jboolean result = JNI_FALSE;
+
+ // The curve is supported if we can get parameters for it
+ params_item.len = env->GetArrayLength(encodedParams);
+ params_item.data =
+ (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
+ if (params_item.data == NULL) {
+ goto cleanup;
+ }
+
+ // Fill a new ECParams using the supplied OID
+ if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
+ /* bad curve OID */
+ goto cleanup;
+ }
+
+ // If we make it to here, then the curve is supported
+ result = JNI_TRUE;
+
+cleanup:
+ {
+ if (params_item.data) {
+ env->ReleaseByteArrayElements(encodedParams,
+ (jbyte *) params_item.data, JNI_ABORT);
+ }
+ if (ecparams) {
+ FreeECParams(ecparams, true);
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Class: sun_security_ec_ECKeyPairGenerator
+ * Method: generateECKeyPair
+ * Signature: (I[B[B)[[B
+ */
+JNIEXPORT jobjectArray
+JNICALL Java_sun_security_ec_ECKeyPairGenerator_generateECKeyPair
+ (JNIEnv *env, jclass clazz, jint keySize, jbyteArray encodedParams, jbyteArray seed)
+{
+ ECPrivateKey *privKey = NULL; // contains both public and private values
+ ECParams *ecparams = NULL;
+ SECKEYECParams params_item;
+ jint jSeedLength;
+ jbyte* pSeedBuffer = NULL;
+ jobjectArray result = NULL;
+ jclass baCls = NULL;
+ jbyteArray jba;
+
+ // Initialize the ECParams struct
+ params_item.len = env->GetArrayLength(encodedParams);
+ params_item.data =
+ (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
+ if (params_item.data == NULL) {
+ goto cleanup;
+ }
+
+ // Fill a new ECParams using the supplied OID
+ if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
+ /* bad curve OID */
+ ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
+ goto cleanup;
+ }
+
+ // Copy seed from Java to native buffer
+ jSeedLength = env->GetArrayLength(seed);
+ pSeedBuffer = new jbyte[jSeedLength];
+ env->GetByteArrayRegion(seed, 0, jSeedLength, pSeedBuffer);
+
+ // Generate the new keypair (using the supplied seed)
+ if (EC_NewKey(ecparams, &privKey, (unsigned char *) pSeedBuffer,
+ jSeedLength, 0) != SECSuccess) {
+ ThrowException(env, KEY_EXCEPTION);
+ goto cleanup;
+ }
+
+ jboolean isCopy;
+ baCls = env->FindClass("[B");
+ if (baCls == NULL) {
+ goto cleanup;
+ }
+ result = env->NewObjectArray(2, baCls, NULL);
+ if (result == NULL) {
+ goto cleanup;
+ }
+ jba = getEncodedBytes(env, &(privKey->privateValue));
+ if (jba == NULL) {
+ result = NULL;
+ goto cleanup;
+ }
+ env->SetObjectArrayElement(result, 0, jba); // big integer
+ if (env->ExceptionCheck()) { // should never happen
+ result = NULL;
+ goto cleanup;
+ }
+
+ jba = getEncodedBytes(env, &(privKey->publicValue));
+ if (jba == NULL) {
+ result = NULL;
+ goto cleanup;
+ }
+ env->SetObjectArrayElement(result, 1, jba); // encoded ec point
+ if (env->ExceptionCheck()) { // should never happen
+ result = NULL;
+ goto cleanup;
+ }
+
+cleanup:
+ {
+ if (params_item.data) {
+ env->ReleaseByteArrayElements(encodedParams,
+ (jbyte *) params_item.data, JNI_ABORT);
+ }
+ if (ecparams) {
+ FreeECParams(ecparams, true);
+ }
+ if (privKey) {
+ FreeECParams(&privKey->ecParams, false);
+ SECITEM_FreeItem(&privKey->version, B_FALSE);
+ SECITEM_FreeItem(&privKey->privateValue, B_FALSE);
+ SECITEM_FreeItem(&privKey->publicValue, B_FALSE);
+ free(privKey);
+ }
+
+ if (pSeedBuffer) {
+ delete [] pSeedBuffer;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Class: sun_security_ec_ECDSASignature
+ * Method: signDigest
+ * Signature: ([B[B[B[B)[B
+ */
+JNIEXPORT jbyteArray
+JNICALL Java_sun_security_ec_ECDSASignature_signDigest
+ (JNIEnv *env, jclass clazz, jbyteArray digest, jbyteArray privateKey, jbyteArray encodedParams, jbyteArray seed, jint timing)
+{
+ jbyte* pDigestBuffer = NULL;
+ jint jDigestLength = env->GetArrayLength(digest);
+ jbyteArray jSignedDigest = NULL;
+
+ SECItem signature_item;
+ jbyte* pSignedDigestBuffer = NULL;
+ jbyteArray temp;
+
+ jint jSeedLength = env->GetArrayLength(seed);
+ jbyte* pSeedBuffer = NULL;
+
+ // Copy digest from Java to native buffer
+ pDigestBuffer = new jbyte[jDigestLength];
+ env->GetByteArrayRegion(digest, 0, jDigestLength, pDigestBuffer);
+ SECItem digest_item;
+ digest_item.data = (unsigned char *) pDigestBuffer;
+ digest_item.len = jDigestLength;
+
+ ECPrivateKey privKey;
+ privKey.privateValue.data = NULL;
+
+ // Initialize the ECParams struct
+ ECParams *ecparams = NULL;
+ SECKEYECParams params_item;
+ params_item.len = env->GetArrayLength(encodedParams);
+ params_item.data =
+ (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
+ if (params_item.data == NULL) {
+ goto cleanup;
+ }
+
+ // Fill a new ECParams using the supplied OID
+ if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
+ /* bad curve OID */
+ ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
+ goto cleanup;
+ }
+
+ // Extract private key data
+ privKey.ecParams = *ecparams; // struct assignment
+ privKey.privateValue.len = env->GetArrayLength(privateKey);
+ privKey.privateValue.data =
+ (unsigned char *) env->GetByteArrayElements(privateKey, 0);
+ if (privKey.privateValue.data == NULL) {
+ goto cleanup;
+ }
+
+ // Prepare a buffer for the signature (twice the key length)
+ pSignedDigestBuffer = new jbyte[ecparams->order.len * 2];
+ signature_item.data = (unsigned char *) pSignedDigestBuffer;
+ signature_item.len = ecparams->order.len * 2;
+
+ // Copy seed from Java to native buffer
+ pSeedBuffer = new jbyte[jSeedLength];
+ env->GetByteArrayRegion(seed, 0, jSeedLength, pSeedBuffer);
+
+ // Sign the digest (using the supplied seed)
+ if (ECDSA_SignDigest(&privKey, &signature_item, &digest_item,
+ (unsigned char *) pSeedBuffer, jSeedLength, 0, timing) != SECSuccess) {
+ ThrowException(env, KEY_EXCEPTION);
+ goto cleanup;
+ }
+
+ // Create new byte array
+ temp = env->NewByteArray(signature_item.len);
+ if (temp == NULL) {
+ goto cleanup;
+ }
+
+ // Copy data from native buffer
+ env->SetByteArrayRegion(temp, 0, signature_item.len, pSignedDigestBuffer);
+ jSignedDigest = temp;
+
+cleanup:
+ {
+ if (params_item.data) {
+ env->ReleaseByteArrayElements(encodedParams,
+ (jbyte *) params_item.data, JNI_ABORT);
+ }
+ if (privKey.privateValue.data) {
+ env->ReleaseByteArrayElements(privateKey,
+ (jbyte *) privKey.privateValue.data, JNI_ABORT);
+ }
+ if (pDigestBuffer) {
+ delete [] pDigestBuffer;
+ }
+ if (pSignedDigestBuffer) {
+ delete [] pSignedDigestBuffer;
+ }
+ if (pSeedBuffer) {
+ delete [] pSeedBuffer;
+ }
+ if (ecparams) {
+ FreeECParams(ecparams, true);
+ }
+ }
+
+ return jSignedDigest;
+}
+
+/*
+ * Class: sun_security_ec_ECDSASignature
+ * Method: verifySignedDigest
+ * Signature: ([B[B[B[B)Z
+ */
+JNIEXPORT jboolean
+JNICALL Java_sun_security_ec_ECDSASignature_verifySignedDigest
+ (JNIEnv *env, jclass clazz, jbyteArray signedDigest, jbyteArray digest, jbyteArray publicKey, jbyteArray encodedParams)
+{
+ jboolean isValid = false;
+
+ // Copy signedDigest from Java to native buffer
+ jbyte* pSignedDigestBuffer = NULL;
+ jint jSignedDigestLength = env->GetArrayLength(signedDigest);
+ pSignedDigestBuffer = new jbyte[jSignedDigestLength];
+ env->GetByteArrayRegion(signedDigest, 0, jSignedDigestLength,
+ pSignedDigestBuffer);
+ SECItem signature_item;
+ signature_item.data = (unsigned char *) pSignedDigestBuffer;
+ signature_item.len = jSignedDigestLength;
+
+ // Copy digest from Java to native buffer
+ jbyte* pDigestBuffer = NULL;
+ jint jDigestLength = env->GetArrayLength(digest);
+ pDigestBuffer = new jbyte[jDigestLength];
+ env->GetByteArrayRegion(digest, 0, jDigestLength, pDigestBuffer);
+ SECItem digest_item;
+ digest_item.data = (unsigned char *) pDigestBuffer;
+ digest_item.len = jDigestLength;
+
+ // Extract public key data
+ ECPublicKey pubKey;
+ pubKey.publicValue.data = NULL;
+ ECParams *ecparams = NULL;
+ SECKEYECParams params_item;
+
+ // Initialize the ECParams struct
+ params_item.len = env->GetArrayLength(encodedParams);
+ params_item.data =
+ (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
+ if (params_item.data == NULL) {
+ goto cleanup;
+ }
+
+ // Fill a new ECParams using the supplied OID
+ if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
+ /* bad curve OID */
+ ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
+ goto cleanup;
+ }
+ pubKey.ecParams = *ecparams; // struct assignment
+ pubKey.publicValue.len = env->GetArrayLength(publicKey);
+ pubKey.publicValue.data =
+ (unsigned char *) env->GetByteArrayElements(publicKey, 0);
+
+ if (ECDSA_VerifyDigest(&pubKey, &signature_item, &digest_item, 0)
+ != SECSuccess) {
+ goto cleanup;
+ }
+
+ isValid = true;
+
+cleanup:
+ {
+ if (params_item.data)
+ env->ReleaseByteArrayElements(encodedParams,
+ (jbyte *) params_item.data, JNI_ABORT);
+
+ if (pubKey.publicValue.data)
+ env->ReleaseByteArrayElements(publicKey,
+ (jbyte *) pubKey.publicValue.data, JNI_ABORT);
+
+ if (ecparams)
+ FreeECParams(ecparams, true);
+
+ if (pSignedDigestBuffer)
+ delete [] pSignedDigestBuffer;
+
+ if (pDigestBuffer)
+ delete [] pDigestBuffer;
+ }
+
+ return isValid;
+}
+
+/*
+ * Class: sun_security_ec_ECDHKeyAgreement
+ * Method: validatePublicKey
+ * Signature: ([B[B)Z
+ */
+JNIEXPORT jboolean
+JNICALL Java_sun_security_ec_ECDHKeyAgreement_validatePublicKey
+ (JNIEnv *env, jclass clazz, jbyteArray encodedParams, jbyteArray publicKey)
+{
+ jboolean isValid = false;
+
+ // Extract public key value
+ SECItem publicValue_item;
+ publicValue_item.len = env->GetArrayLength(publicKey);
+ publicValue_item.data =
+ (unsigned char *) env->GetByteArrayElements(publicKey, 0);
+
+ // Initialize the ECParams struct
+ ECParams *ecparams = NULL;
+ SECKEYECParams params_item;
+ params_item.len = env->GetArrayLength(encodedParams);
+ params_item.data =
+ (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
+
+ // Fill a new ECParams using the supplied OID
+ if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
+ /* bad curve OID */
+ goto cleanup;
+ }
+
+ if (EC_ValidatePublicKey(ecparams, &publicValue_item, 0) != SECSuccess) {
+ goto cleanup;
+ }
+
+ isValid = true;
+
+cleanup:
+ {
+ if (publicValue_item.data)
+ env->ReleaseByteArrayElements(publicKey,
+ (jbyte *) publicValue_item.data, JNI_ABORT);
+
+ if (params_item.data)
+ env->ReleaseByteArrayElements(encodedParams,
+ (jbyte *) params_item.data, JNI_ABORT);
+
+ if (ecparams)
+ FreeECParams(ecparams, true);
+ }
+
+ return isValid;
+}
+
+/*
+ * Class: sun_security_ec_ECDHKeyAgreement
+ * Method: deriveKey
+ * Signature: ([B[B[B)[B
+ */
+JNIEXPORT jbyteArray
+JNICALL Java_sun_security_ec_ECDHKeyAgreement_deriveKey
+ (JNIEnv *env, jclass clazz, jbyteArray privateKey, jbyteArray publicKey, jbyteArray encodedParams)
+{
+ jbyteArray jSecret = NULL;
+ ECParams *ecparams = NULL;
+ SECItem privateValue_item;
+ privateValue_item.data = NULL;
+ SECItem publicValue_item;
+ publicValue_item.data = NULL;
+ SECKEYECParams params_item;
+ params_item.data = NULL;
+
+ // Extract private key value
+ privateValue_item.len = env->GetArrayLength(privateKey);
+ privateValue_item.data =
+ (unsigned char *) env->GetByteArrayElements(privateKey, 0);
+ if (privateValue_item.data == NULL) {
+ goto cleanup;
+ }
+
+ // Extract public key value
+ publicValue_item.len = env->GetArrayLength(publicKey);
+ publicValue_item.data =
+ (unsigned char *) env->GetByteArrayElements(publicKey, 0);
+ if (publicValue_item.data == NULL) {
+ goto cleanup;
+ }
+
+ // Initialize the ECParams struct
+ params_item.len = env->GetArrayLength(encodedParams);
+ params_item.data =
+ (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
+ if (params_item.data == NULL) {
+ goto cleanup;
+ }
+
+ // Fill a new ECParams using the supplied OID
+ if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
+ /* bad curve OID */
+ ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
+ goto cleanup;
+ }
+
+ // Prepare a buffer for the secret
+ SECItem secret_item;
+ secret_item.data = NULL;
+ secret_item.len = ecparams->order.len * 2;
+
+ if (ECDH_Derive(&publicValue_item, ecparams, &privateValue_item, B_FALSE,
+ &secret_item, 0) != SECSuccess) {
+ ThrowException(env, ILLEGAL_STATE_EXCEPTION);
+ goto cleanup;
+ }
+
+ // Create new byte array
+ jSecret = env->NewByteArray(secret_item.len);
+ if (jSecret == NULL) {
+ goto cleanup;
+ }
+
+ // Copy bytes from the SECItem buffer to a Java byte array
+ env->SetByteArrayRegion(jSecret, 0, secret_item.len,
+ (jbyte *)secret_item.data);
+
+ // Free the SECItem data buffer
+ SECITEM_FreeItem(&secret_item, B_FALSE);
+
+cleanup:
+ {
+ if (privateValue_item.data)
+ env->ReleaseByteArrayElements(privateKey,
+ (jbyte *) privateValue_item.data, JNI_ABORT);
+
+ if (publicValue_item.data)
+ env->ReleaseByteArrayElements(publicKey,
+ (jbyte *) publicValue_item.data, JNI_ABORT);
+
+ if (params_item.data)
+ env->ReleaseByteArrayElements(encodedParams,
+ (jbyte *) params_item.data, JNI_ABORT);
+
+ if (ecparams)
+ FreeECParams(ecparams, true);
+ }
+
+ return jSecret;
+}
+
+} /* extern "C" */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ec.c b/jdk.crypto.ec/share/native/libsunec/impl/ec.c
new file mode 100644
index 0000000..299135d
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ec.c
@@ -0,0 +1,1091 @@
+/*
+ * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the Elliptic Curve Cryptography library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dr Vipul Gupta <vipul.gupta@sun.com> and
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * Last Modified Date from the Original Code: May 2017
+ *********************************************************************** */
+
+#include "mplogic.h"
+#include "ec.h"
+#include "ecl.h"
+
+#include <sys/types.h>
+#ifndef _KERNEL
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _WIN32
+#include <stdio.h>
+#include <strings.h>
+#endif /* _WIN32 */
+
+#endif
+#include "ecl-exp.h"
+#include "mpi.h"
+#include "ecc_impl.h"
+
+#ifdef _KERNEL
+#define PORT_ZFree(p, l) bzero((p), (l)); kmem_free((p), (l))
+#else
+#ifndef _WIN32
+#define PORT_ZFree(p, l) bzero((p), (l)); free((p))
+#else
+#define PORT_ZFree(p, l) memset((p), 0, (l)); free((p))
+#endif /* _WIN32 */
+#endif
+
+/*
+ * Returns true if pointP is the point at infinity, false otherwise
+ */
+PRBool
+ec_point_at_infinity(SECItem *pointP)
+{
+ unsigned int i;
+
+ for (i = 1; i < pointP->len; i++) {
+ if (pointP->data[i] != 0x00) return PR_FALSE;
+ }
+
+ return PR_TRUE;
+}
+
+/*
+ * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for
+ * the curve whose parameters are encoded in params with base point G.
+ */
+SECStatus
+ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
+ const SECItem *pointP, SECItem *pointQ, int kmflag, int timing)
+{
+ mp_int Px, Py, Qx, Qy;
+ mp_int Gx, Gy, order, irreducible, a, b;
+#if 0 /* currently don't support non-named curves */
+ unsigned int irr_arr[5];
+#endif
+ ECGroup *group = NULL;
+ SECStatus rv = SECFailure;
+ mp_err err = MP_OKAY;
+ unsigned int len;
+
+#if EC_DEBUG
+ int i;
+ char mpstr[256];
+
+ printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len);
+ for (i = 0; i < params->DEREncoding.len; i++)
+ printf("%02x:", params->DEREncoding.data[i]);
+ printf("\n");
+
+ if (k1 != NULL) {
+ mp_tohex(k1, mpstr);
+ printf("ec_points_mul: scalar k1: %s\n", mpstr);
+ mp_todecimal(k1, mpstr);
+ printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr);
+ }
+
+ if (k2 != NULL) {
+ mp_tohex(k2, mpstr);
+ printf("ec_points_mul: scalar k2: %s\n", mpstr);
+ mp_todecimal(k2, mpstr);
+ printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr);
+ }
+
+ if (pointP != NULL) {
+ printf("ec_points_mul: pointP [len=%d]:", pointP->len);
+ for (i = 0; i < pointP->len; i++)
+ printf("%02x:", pointP->data[i]);
+ printf("\n");
+ }
+#endif
+
+ /* NOTE: We only support uncompressed points for now */
+ len = (params->fieldID.size + 7) >> 3;
+ if (pointP != NULL) {
+ if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
+ (pointP->len != (2 * len + 1))) {
+ return SECFailure;
+ };
+ }
+
+ MP_DIGITS(&Px) = 0;
+ MP_DIGITS(&Py) = 0;
+ MP_DIGITS(&Qx) = 0;
+ MP_DIGITS(&Qy) = 0;
+ MP_DIGITS(&Gx) = 0;
+ MP_DIGITS(&Gy) = 0;
+ MP_DIGITS(&order) = 0;
+ MP_DIGITS(&irreducible) = 0;
+ MP_DIGITS(&a) = 0;
+ MP_DIGITS(&b) = 0;
+ CHECK_MPI_OK( mp_init(&Px, kmflag) );
+ CHECK_MPI_OK( mp_init(&Py, kmflag) );
+ CHECK_MPI_OK( mp_init(&Qx, kmflag) );
+ CHECK_MPI_OK( mp_init(&Qy, kmflag) );
+ CHECK_MPI_OK( mp_init(&Gx, kmflag) );
+ CHECK_MPI_OK( mp_init(&Gy, kmflag) );
+ CHECK_MPI_OK( mp_init(&order, kmflag) );
+ CHECK_MPI_OK( mp_init(&irreducible, kmflag) );
+ CHECK_MPI_OK( mp_init(&a, kmflag) );
+ CHECK_MPI_OK( mp_init(&b, kmflag) );
+
+ if ((k2 != NULL) && (pointP != NULL)) {
+ /* Initialize Px and Py */
+ CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) );
+ CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) );
+ }
+
+ /* construct from named params, if possible */
+ if (params->name != ECCurve_noName) {
+ group = ECGroup_fromName(params->name, kmflag);
+ }
+
+#if 0 /* currently don't support non-named curves */
+ if (group == NULL) {
+ /* Set up mp_ints containing the curve coefficients */
+ CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1,
+ (mp_size) len) );
+ CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len,
+ (mp_size) len) );
+ SECITEM_TO_MPINT( params->order, &order );
+ SECITEM_TO_MPINT( params->curve.a, &a );
+ SECITEM_TO_MPINT( params->curve.b, &b );
+ if (params->fieldID.type == ec_field_GFp) {
+ SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
+ group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor);
+ } else {
+ SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
+ irr_arr[0] = params->fieldID.size;
+ irr_arr[1] = params->fieldID.k1;
+ irr_arr[2] = params->fieldID.k2;
+ irr_arr[3] = params->fieldID.k3;
+ irr_arr[4] = 0;
+ group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor);
+ }
+ }
+#endif
+ if (group == NULL)
+ goto cleanup;
+
+ if ((k2 != NULL) && (pointP != NULL)) {
+ CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy, timing) );
+ } else {
+ CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy, timing) );
+ }
+
+ /* Construct the SECItem representation of point Q */
+ pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
+ CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,
+ (mp_size) len) );
+ CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
+ (mp_size) len) );
+
+ rv = SECSuccess;
+
+#if EC_DEBUG
+ printf("ec_points_mul: pointQ [len=%d]:", pointQ->len);
+ for (i = 0; i < pointQ->len; i++)
+ printf("%02x:", pointQ->data[i]);
+ printf("\n");
+#endif
+
+cleanup:
+ ECGroup_free(group);
+ mp_clear(&Px);
+ mp_clear(&Py);
+ mp_clear(&Qx);
+ mp_clear(&Qy);
+ mp_clear(&Gx);
+ mp_clear(&Gy);
+ mp_clear(&order);
+ mp_clear(&irreducible);
+ mp_clear(&a);
+ mp_clear(&b);
+ if (err) {
+ MP_TO_SEC_ERROR(err);
+ rv = SECFailure;
+ }
+
+ return rv;
+}
+
+/* Generates a new EC key pair. The private key is a supplied
+ * value and the public key is the result of performing a scalar
+ * point multiplication of that value with the curve's base point.
+ */
+SECStatus
+ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey,
+ const unsigned char *privKeyBytes, int privKeyLen, int kmflag)
+{
+ SECStatus rv = SECFailure;
+ PRArenaPool *arena;
+ ECPrivateKey *key;
+ mp_int k;
+ mp_err err = MP_OKAY;
+ int len;
+
+#if EC_DEBUG
+ printf("ec_NewKey called\n");
+#endif
+ k.dp = (mp_digit*)NULL;
+
+ if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* Initialize an arena for the EC key. */
+ if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
+ return SECFailure;
+
+ key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey),
+ kmflag);
+ if (!key) {
+ PORT_FreeArena(arena, PR_TRUE);
+ return SECFailure;
+ }
+
+ /* Set the version number (SEC 1 section C.4 says it should be 1) */
+ SECITEM_AllocItem(arena, &key->version, 1, kmflag);
+ key->version.data[0] = 1;
+
+ /* Copy all of the fields from the ECParams argument to the
+ * ECParams structure within the private key.
+ */
+ key->ecParams.arena = arena;
+ key->ecParams.type = ecParams->type;
+ key->ecParams.fieldID.size = ecParams->fieldID.size;
+ key->ecParams.fieldID.type = ecParams->fieldID.type;
+ if (ecParams->fieldID.type == ec_field_GFp) {
+ CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
+ &ecParams->fieldID.u.prime, kmflag));
+ } else {
+ CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,
+ &ecParams->fieldID.u.poly, kmflag));
+ }
+ key->ecParams.fieldID.k1 = ecParams->fieldID.k1;
+ key->ecParams.fieldID.k2 = ecParams->fieldID.k2;
+ key->ecParams.fieldID.k3 = ecParams->fieldID.k3;
+ CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,
+ &ecParams->curve.a, kmflag));
+ CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,
+ &ecParams->curve.b, kmflag));
+ CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,
+ &ecParams->curve.seed, kmflag));
+ CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,
+ &ecParams->base, kmflag));
+ CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,
+ &ecParams->order, kmflag));
+ key->ecParams.cofactor = ecParams->cofactor;
+ CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,
+ &ecParams->DEREncoding, kmflag));
+ key->ecParams.name = ecParams->name;
+ CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID,
+ &ecParams->curveOID, kmflag));
+
+ len = (ecParams->fieldID.size + 7) >> 3;
+ SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1, kmflag);
+ len = ecParams->order.len;
+ SECITEM_AllocItem(arena, &key->privateValue, len, kmflag);
+
+ /* Copy private key */
+ if (privKeyLen >= len) {
+ memcpy(key->privateValue.data, privKeyBytes, len);
+ } else {
+ memset(key->privateValue.data, 0, (len - privKeyLen));
+ memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen);
+ }
+
+ /* Compute corresponding public key */
+ MP_DIGITS(&k) = 0;
+ CHECK_MPI_OK( mp_init(&k, kmflag) );
+ CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data,
+ (mp_size) len) );
+
+ /* key generation does not support timing mitigation */
+ rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue), kmflag, /*timing*/ 0);
+ if (rv != SECSuccess) goto cleanup;
+ *privKey = key;
+
+cleanup:
+ mp_clear(&k);
+ if (rv) {
+ PORT_FreeArena(arena, PR_TRUE);
+ }
+
+#if EC_DEBUG
+ printf("ec_NewKey returning %s\n",
+ (rv == SECSuccess) ? "success" : "failure");
+#endif
+
+ return rv;
+
+}
+
+/* Generates a new EC key pair. The private key is a supplied
+ * random value (in seed) and the public key is the result of
+ * performing a scalar point multiplication of that value with
+ * the curve's base point.
+ */
+SECStatus
+EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey,
+ const unsigned char *seed, int seedlen, int kmflag)
+{
+ SECStatus rv = SECFailure;
+ rv = ec_NewKey(ecParams, privKey, seed, seedlen, kmflag);
+ return rv;
+}
+
+/* Generate a random private key using the algorithm A.4.1 of ANSI X9.62,
+ * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the
+ * random number generator.
+ *
+ * Parameters
+ * - order: a buffer that holds the curve's group order
+ * - len: the length in octets of the order buffer
+ * - random: a buffer of 2 * len random bytes
+ * - randomlen: the length in octets of the random buffer
+ *
+ * Return Value
+ * Returns a buffer of len octets that holds the private key. The caller
+ * is responsible for freeing the buffer with PORT_ZFree.
+ */
+static unsigned char *
+ec_GenerateRandomPrivateKey(const unsigned char *order, int len,
+ const unsigned char *random, int randomlen, int kmflag)
+{
+ SECStatus rv = SECSuccess;
+ mp_err err;
+ unsigned char *privKeyBytes = NULL;
+ mp_int privKeyVal, order_1, one;
+
+ MP_DIGITS(&privKeyVal) = 0;
+ MP_DIGITS(&order_1) = 0;
+ MP_DIGITS(&one) = 0;
+ CHECK_MPI_OK( mp_init(&privKeyVal, kmflag) );
+ CHECK_MPI_OK( mp_init(&order_1, kmflag) );
+ CHECK_MPI_OK( mp_init(&one, kmflag) );
+
+ /*
+ * Reduces the 2*len buffer of random bytes modulo the group order.
+ */
+ if ((privKeyBytes = PORT_Alloc(2*len, kmflag)) == NULL) goto cleanup;
+ if (randomlen != 2 * len) {
+ randomlen = 2 * len;
+ }
+ /* No need to generate - random bytes are now supplied */
+ /* CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );*/
+ memcpy(privKeyBytes, random, randomlen);
+
+ CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) );
+ CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) );
+ CHECK_MPI_OK( mp_set_int(&one, 1) );
+ CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) );
+ CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) );
+ CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) );
+ CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) );
+ memset(privKeyBytes+len, 0, len);
+cleanup:
+ mp_clear(&privKeyVal);
+ mp_clear(&order_1);
+ mp_clear(&one);
+ if (err < MP_OKAY) {
+ MP_TO_SEC_ERROR(err);
+ rv = SECFailure;
+ }
+ if (rv != SECSuccess && privKeyBytes) {
+#ifdef _KERNEL
+ kmem_free(privKeyBytes, 2*len);
+#else
+ free(privKeyBytes);
+#endif
+ privKeyBytes = NULL;
+ }
+ return privKeyBytes;
+}
+
+/* Generates a new EC key pair. The private key is a random value and
+ * the public key is the result of performing a scalar point multiplication
+ * of that value with the curve's base point.
+ */
+SECStatus
+EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey,
+ const unsigned char* random, int randomlen, int kmflag)
+{
+ SECStatus rv = SECFailure;
+ int len;
+ unsigned char *privKeyBytes = NULL;
+
+ if (!ecParams) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ len = ecParams->order.len;
+ privKeyBytes = ec_GenerateRandomPrivateKey(ecParams->order.data, len,
+ random, randomlen, kmflag);
+ if (privKeyBytes == NULL) goto cleanup;
+ /* generate public key */
+ CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len, kmflag) );
+
+cleanup:
+ if (privKeyBytes) {
+ PORT_ZFree(privKeyBytes, len * 2);
+ }
+#if EC_DEBUG
+ printf("EC_NewKey returning %s\n",
+ (rv == SECSuccess) ? "success" : "failure");
+#endif
+
+ return rv;
+}
+
+/* Validates an EC public key as described in Section 5.2.2 of
+ * X9.62. The ECDH primitive when used without the cofactor does
+ * not address small subgroup attacks, which may occur when the
+ * public key is not valid. These attacks can be prevented by
+ * validating the public key before using ECDH.
+ */
+SECStatus
+EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue, int kmflag)
+{
+ mp_int Px, Py;
+ ECGroup *group = NULL;
+ SECStatus rv = SECFailure;
+ mp_err err = MP_OKAY;
+ unsigned int len;
+
+ if (!ecParams || !publicValue) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* NOTE: We only support uncompressed points for now */
+ len = (ecParams->fieldID.size + 7) >> 3;
+ if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
+ return SECFailure;
+ } else if (publicValue->len != (2 * len + 1)) {
+ PORT_SetError(SEC_ERROR_BAD_KEY);
+ return SECFailure;
+ }
+
+ MP_DIGITS(&Px) = 0;
+ MP_DIGITS(&Py) = 0;
+ CHECK_MPI_OK( mp_init(&Px, kmflag) );
+ CHECK_MPI_OK( mp_init(&Py, kmflag) );
+
+ /* Initialize Px and Py */
+ CHECK_MPI_OK( mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size) len) );
+ CHECK_MPI_OK( mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size) len) );
+
+ /* construct from named params */
+ group = ECGroup_fromName(ecParams->name, kmflag);
+ if (group == NULL) {
+ /*
+ * ECGroup_fromName fails if ecParams->name is not a valid
+ * ECCurveName value, or if we run out of memory, or perhaps
+ * for other reasons. Unfortunately if ecParams->name is a
+ * valid ECCurveName value, we don't know what the right error
+ * code should be because ECGroup_fromName doesn't return an
+ * error code to the caller. Set err to MP_UNDEF because
+ * that's what ECGroup_fromName uses internally.
+ */
+ if ((ecParams->name <= ECCurve_noName) ||
+ (ecParams->name >= ECCurve_pastLastCurve)) {
+ err = MP_BADARG;
+ } else {
+ err = MP_UNDEF;
+ }
+ goto cleanup;
+ }
+
+ /* validate public point */
+ if ((err = ECPoint_validate(group, &Px, &Py)) < MP_YES) {
+ if (err == MP_NO) {
+ PORT_SetError(SEC_ERROR_BAD_KEY);
+ rv = SECFailure;
+ err = MP_OKAY; /* don't change the error code */
+ }
+ goto cleanup;
+ }
+
+ rv = SECSuccess;
+
+cleanup:
+ ECGroup_free(group);
+ mp_clear(&Px);
+ mp_clear(&Py);
+ if (err) {
+ MP_TO_SEC_ERROR(err);
+ rv = SECFailure;
+ }
+ return rv;
+}
+
+/*
+** Performs an ECDH key derivation by computing the scalar point
+** multiplication of privateValue and publicValue (with or without the
+** cofactor) and returns the x-coordinate of the resulting elliptic
+** curve point in derived secret. If successful, derivedSecret->data
+** is set to the address of the newly allocated buffer containing the
+** derived secret, and derivedSecret->len is the size of the secret
+** produced. It is the caller's responsibility to free the allocated
+** buffer containing the derived secret.
+*/
+SECStatus
+ECDH_Derive(SECItem *publicValue,
+ ECParams *ecParams,
+ SECItem *privateValue,
+ PRBool withCofactor,
+ SECItem *derivedSecret,
+ int kmflag)
+{
+ SECStatus rv = SECFailure;
+ unsigned int len = 0;
+ SECItem pointQ = {siBuffer, NULL, 0};
+ mp_int k; /* to hold the private value */
+ mp_int cofactor;
+ mp_err err = MP_OKAY;
+#if EC_DEBUG
+ int i;
+#endif
+
+ if (!publicValue || !ecParams || !privateValue ||
+ !derivedSecret) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (EC_ValidatePublicKey(ecParams, publicValue, kmflag) != SECSuccess) {
+ return SECFailure;
+ }
+
+ memset(derivedSecret, 0, sizeof *derivedSecret);
+ len = (ecParams->fieldID.size + 7) >> 3;
+ pointQ.len = 2*len + 1;
+ if ((pointQ.data = PORT_Alloc(2*len + 1, kmflag)) == NULL) goto cleanup;
+
+ MP_DIGITS(&k) = 0;
+ CHECK_MPI_OK( mp_init(&k, kmflag) );
+ CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data,
+ (mp_size) privateValue->len) );
+
+ if (withCofactor && (ecParams->cofactor != 1)) {
+ /* multiply k with the cofactor */
+ MP_DIGITS(&cofactor) = 0;
+ CHECK_MPI_OK( mp_init(&cofactor, kmflag) );
+ mp_set(&cofactor, ecParams->cofactor);
+ CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) );
+ }
+
+ /* Multiply our private key and peer's public point */
+ /* ECDH doesn't support timing mitigation */
+ if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ, kmflag, /*timing*/ 0) != SECSuccess) ||
+ ec_point_at_infinity(&pointQ))
+ goto cleanup;
+
+ /* Allocate memory for the derived secret and copy
+ * the x co-ordinate of pointQ into it.
+ */
+ SECITEM_AllocItem(NULL, derivedSecret, len, kmflag);
+ memcpy(derivedSecret->data, pointQ.data + 1, len);
+
+ rv = SECSuccess;
+
+#if EC_DEBUG
+ printf("derived_secret:\n");
+ for (i = 0; i < derivedSecret->len; i++)
+ printf("%02x:", derivedSecret->data[i]);
+ printf("\n");
+#endif
+
+cleanup:
+ mp_clear(&k);
+
+ if (pointQ.data) {
+ PORT_ZFree(pointQ.data, 2*len + 1);
+ }
+
+ return rv;
+}
+
+/* Computes the ECDSA signature (a concatenation of two values r and s)
+ * on the digest using the given key and the random value kb (used in
+ * computing s).
+ */
+SECStatus
+ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
+ const SECItem *digest, const unsigned char *kb, const int kblen, int kmflag,
+ int timing)
+{
+ SECStatus rv = SECFailure;
+ mp_int x1;
+ mp_int d, k; /* private key, random integer */
+ mp_int r, s; /* tuple (r, s) is the signature */
+ mp_int n;
+ mp_err err = MP_OKAY;
+ ECParams *ecParams = NULL;
+ SECItem kGpoint = { siBuffer, NULL, 0};
+ int flen = 0; /* length in bytes of the field size */
+ unsigned olen; /* length in bytes of the base point order */
+ unsigned int orderBitSize;
+
+#if EC_DEBUG
+ char mpstr[256];
+#endif
+
+ /* Initialize MPI integers. */
+ /* must happen before the first potential call to cleanup */
+ MP_DIGITS(&x1) = 0;
+ MP_DIGITS(&d) = 0;
+ MP_DIGITS(&k) = 0;
+ MP_DIGITS(&r) = 0;
+ MP_DIGITS(&s) = 0;
+ MP_DIGITS(&n) = 0;
+
+ /* Check args */
+ if (!key || !signature || !digest || !kb || (kblen < 0)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto cleanup;
+ }
+
+ ecParams = &(key->ecParams);
+ flen = (ecParams->fieldID.size + 7) >> 3;
+ olen = ecParams->order.len;
+ if (signature->data == NULL) {
+ /* a call to get the signature length only */
+ goto finish;
+ }
+ if (signature->len < 2*olen) {
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ rv = SECBufferTooSmall;
+ goto cleanup;
+ }
+
+
+ CHECK_MPI_OK( mp_init(&x1, kmflag) );
+ CHECK_MPI_OK( mp_init(&d, kmflag) );
+ CHECK_MPI_OK( mp_init(&k, kmflag) );
+ CHECK_MPI_OK( mp_init(&r, kmflag) );
+ CHECK_MPI_OK( mp_init(&s, kmflag) );
+ CHECK_MPI_OK( mp_init(&n, kmflag) );
+
+ SECITEM_TO_MPINT( ecParams->order, &n );
+ SECITEM_TO_MPINT( key->privateValue, &d );
+ CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );
+ /* Make sure k is in the interval [1, n-1] */
+ if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {
+#if EC_DEBUG
+ printf("k is outside [1, n-1]\n");
+ mp_tohex(&k, mpstr);
+ printf("k : %s \n", mpstr);
+ mp_tohex(&n, mpstr);
+ printf("n : %s \n", mpstr);
+#endif
+ PORT_SetError(SEC_ERROR_NEED_RANDOM);
+ goto cleanup;
+ }
+
+ /*
+ ** ANSI X9.62, Section 5.3.2, Step 2
+ **
+ ** Compute kG
+ */
+ kGpoint.len = 2*flen + 1;
+ kGpoint.data = PORT_Alloc(2*flen + 1, kmflag);
+ if ((kGpoint.data == NULL) ||
+ (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint, kmflag, timing)
+ != SECSuccess))
+ goto cleanup;
+
+ /*
+ ** ANSI X9.62, Section 5.3.3, Step 1
+ **
+ ** Extract the x co-ordinate of kG into x1
+ */
+ CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1,
+ (mp_size) flen) );
+
+ /*
+ ** ANSI X9.62, Section 5.3.3, Step 2
+ **
+ ** r = x1 mod n NOTE: n is the order of the curve
+ */
+ CHECK_MPI_OK( mp_mod(&x1, &n, &r) );
+
+ /*
+ ** ANSI X9.62, Section 5.3.3, Step 3
+ **
+ ** verify r != 0
+ */
+ if (mp_cmp_z(&r) == 0) {
+ PORT_SetError(SEC_ERROR_NEED_RANDOM);
+ goto cleanup;
+ }
+
+ /*
+ ** ANSI X9.62, Section 5.3.3, Step 4
+ **
+ ** s = (k**-1 * (HASH(M) + d*r)) mod n
+ */
+ SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */
+
+ /* In the definition of EC signing, digests are truncated
+ * to the order length
+ * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
+ orderBitSize = mpl_significant_bits(&n);
+ if (digest->len*8 > orderBitSize) {
+ mpl_rsh(&s,&s,digest->len*8 - orderBitSize);
+ }
+
+#if EC_DEBUG
+ mp_todecimal(&n, mpstr);
+ printf("n : %s (dec)\n", mpstr);
+ mp_todecimal(&d, mpstr);
+ printf("d : %s (dec)\n", mpstr);
+ mp_tohex(&x1, mpstr);
+ printf("x1: %s\n", mpstr);
+ mp_todecimal(&s, mpstr);
+ printf("digest: %s (decimal)\n", mpstr);
+ mp_todecimal(&r, mpstr);
+ printf("r : %s (dec)\n", mpstr);
+ mp_tohex(&r, mpstr);
+ printf("r : %s\n", mpstr);
+#endif
+
+ CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */
+ CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */
+ CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */
+ CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */
+
+#if EC_DEBUG
+ mp_todecimal(&s, mpstr);
+ printf("s : %s (dec)\n", mpstr);
+ mp_tohex(&s, mpstr);
+ printf("s : %s\n", mpstr);
+#endif
+
+ /*
+ ** ANSI X9.62, Section 5.3.3, Step 5
+ **
+ ** verify s != 0
+ */
+ if (mp_cmp_z(&s) == 0) {
+ PORT_SetError(SEC_ERROR_NEED_RANDOM);
+ goto cleanup;
+ }
+
+ /*
+ **
+ ** Signature is tuple (r, s)
+ */
+ CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) );
+ CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) );
+finish:
+ signature->len = 2*olen;
+
+ rv = SECSuccess;
+ err = MP_OKAY;
+cleanup:
+ mp_clear(&x1);
+ mp_clear(&d);
+ mp_clear(&k);
+ mp_clear(&r);
+ mp_clear(&s);
+ mp_clear(&n);
+
+ if (kGpoint.data) {
+ PORT_ZFree(kGpoint.data, 2*flen + 1);
+ }
+
+ if (err) {
+ MP_TO_SEC_ERROR(err);
+ rv = SECFailure;
+ }
+
+#if EC_DEBUG
+ printf("ECDSA signing with seed %s\n",
+ (rv == SECSuccess) ? "succeeded" : "failed");
+#endif
+
+ return rv;
+}
+
+/*
+** Computes the ECDSA signature on the digest using the given key
+** and a random seed.
+*/
+SECStatus
+ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest,
+ const unsigned char* random, int randomLen, int kmflag, int timing)
+{
+ SECStatus rv = SECFailure;
+ int len;
+ unsigned char *kBytes= NULL;
+
+ if (!key) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* Generate random value k */
+ len = key->ecParams.order.len;
+ kBytes = ec_GenerateRandomPrivateKey(key->ecParams.order.data, len,
+ random, randomLen, kmflag);
+ if (kBytes == NULL) goto cleanup;
+
+ /* Generate ECDSA signature with the specified k value */
+ rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len, kmflag, timing);
+
+cleanup:
+ if (kBytes) {
+ PORT_ZFree(kBytes, len * 2);
+ }
+
+#if EC_DEBUG
+ printf("ECDSA signing %s\n",
+ (rv == SECSuccess) ? "succeeded" : "failed");
+#endif
+
+ return rv;
+}
+
+/*
+** Checks the signature on the given digest using the key provided.
+*/
+SECStatus
+ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
+ const SECItem *digest, int kmflag)
+{
+ SECStatus rv = SECFailure;
+ mp_int r_, s_; /* tuple (r', s') is received signature) */
+ mp_int c, u1, u2, v; /* intermediate values used in verification */
+ mp_int x1;
+ mp_int n;
+ mp_err err = MP_OKAY;
+ ECParams *ecParams = NULL;
+ SECItem pointC = { siBuffer, NULL, 0 };
+ int slen; /* length in bytes of a half signature (r or s) */
+ int flen; /* length in bytes of the field size */
+ unsigned olen; /* length in bytes of the base point order */
+ unsigned int orderBitSize;
+
+#if EC_DEBUG
+ char mpstr[256];
+ printf("ECDSA verification called\n");
+#endif
+
+ /* Initialize MPI integers. */
+ /* must happen before the first potential call to cleanup */
+ MP_DIGITS(&r_) = 0;
+ MP_DIGITS(&s_) = 0;
+ MP_DIGITS(&c) = 0;
+ MP_DIGITS(&u1) = 0;
+ MP_DIGITS(&u2) = 0;
+ MP_DIGITS(&x1) = 0;
+ MP_DIGITS(&v) = 0;
+ MP_DIGITS(&n) = 0;
+
+ /* Check args */
+ if (!key || !signature || !digest) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto cleanup;
+ }
+
+ ecParams = &(key->ecParams);
+ flen = (ecParams->fieldID.size + 7) >> 3;
+ olen = ecParams->order.len;
+ if (signature->len == 0 || signature->len%2 != 0 ||
+ signature->len > 2*olen) {
+ PORT_SetError(SEC_ERROR_INPUT_LEN);
+ goto cleanup;
+ }
+ slen = signature->len/2;
+
+ SECITEM_AllocItem(NULL, &pointC, 2*flen + 1, kmflag);
+ if (pointC.data == NULL)
+ goto cleanup;
+
+ CHECK_MPI_OK( mp_init(&r_, kmflag) );
+ CHECK_MPI_OK( mp_init(&s_, kmflag) );
+ CHECK_MPI_OK( mp_init(&c, kmflag) );
+ CHECK_MPI_OK( mp_init(&u1, kmflag) );
+ CHECK_MPI_OK( mp_init(&u2, kmflag) );
+ CHECK_MPI_OK( mp_init(&x1, kmflag) );
+ CHECK_MPI_OK( mp_init(&v, kmflag) );
+ CHECK_MPI_OK( mp_init(&n, kmflag) );
+
+ /*
+ ** Convert received signature (r', s') into MPI integers.
+ */
+ CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) );
+ CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) );
+
+ /*
+ ** ANSI X9.62, Section 5.4.2, Steps 1 and 2
+ **
+ ** Verify that 0 < r' < n and 0 < s' < n
+ */
+ SECITEM_TO_MPINT(ecParams->order, &n);
+ if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
+ mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) {
+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+ goto cleanup; /* will return rv == SECFailure */
+ }
+
+ /*
+ ** ANSI X9.62, Section 5.4.2, Step 3
+ **
+ ** c = (s')**-1 mod n
+ */
+ CHECK_MPI_OK( mp_invmod(&s_, &n, &c) ); /* c = (s')**-1 mod n */
+
+ /*
+ ** ANSI X9.62, Section 5.4.2, Step 4
+ **
+ ** u1 = ((HASH(M')) * c) mod n
+ */
+ SECITEM_TO_MPINT(*digest, &u1); /* u1 = HASH(M) */
+
+ /* In the definition of EC signing, digests are truncated
+ * to the order length, in bits.
+ * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
+ /* u1 = HASH(M') */
+ orderBitSize = mpl_significant_bits(&n);
+ if (digest->len*8 > orderBitSize) {
+ mpl_rsh(&u1,&u1,digest->len*8- orderBitSize);
+ }
+
+#if EC_DEBUG
+ mp_todecimal(&r_, mpstr);
+ printf("r_: %s (dec)\n", mpstr);
+ mp_todecimal(&s_, mpstr);
+ printf("s_: %s (dec)\n", mpstr);
+ mp_todecimal(&c, mpstr);
+ printf("c : %s (dec)\n", mpstr);
+ mp_todecimal(&u1, mpstr);
+ printf("digest: %s (dec)\n", mpstr);
+#endif
+
+ CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */
+
+ /*
+ ** ANSI X9.62, Section 5.4.2, Step 4
+ **
+ ** u2 = ((r') * c) mod n
+ */
+ CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) );
+
+ /*
+ ** ANSI X9.62, Section 5.4.3, Step 1
+ **
+ ** Compute u1*G + u2*Q
+ ** Here, A = u1.G B = u2.Q and C = A + B
+ ** If the result, C, is the point at infinity, reject the signature
+ */
+ /* verification does not support timing mitigation */
+ if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC, kmflag, /*timing*/ 0)
+ != SECSuccess) {
+ rv = SECFailure;
+ goto cleanup;
+ }
+ if (ec_point_at_infinity(&pointC)) {
+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+ rv = SECFailure;
+ goto cleanup;
+ }
+
+ CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) );
+
+ /*
+ ** ANSI X9.62, Section 5.4.4, Step 2
+ **
+ ** v = x1 mod n
+ */
+ CHECK_MPI_OK( mp_mod(&x1, &n, &v) );
+
+#if EC_DEBUG
+ mp_todecimal(&r_, mpstr);
+ printf("r_: %s (dec)\n", mpstr);
+ mp_todecimal(&v, mpstr);
+ printf("v : %s (dec)\n", mpstr);
+#endif
+
+ /*
+ ** ANSI X9.62, Section 5.4.4, Step 3
+ **
+ ** Verification: v == r'
+ */
+ if (mp_cmp(&v, &r_)) {
+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+ rv = SECFailure; /* Signature failed to verify. */
+ } else {
+ rv = SECSuccess; /* Signature verified. */
+ }
+
+#if EC_DEBUG
+ mp_todecimal(&u1, mpstr);
+ printf("u1: %s (dec)\n", mpstr);
+ mp_todecimal(&u2, mpstr);
+ printf("u2: %s (dec)\n", mpstr);
+ mp_tohex(&x1, mpstr);
+ printf("x1: %s\n", mpstr);
+ mp_todecimal(&v, mpstr);
+ printf("v : %s (dec)\n", mpstr);
+#endif
+
+cleanup:
+ mp_clear(&r_);
+ mp_clear(&s_);
+ mp_clear(&c);
+ mp_clear(&u1);
+ mp_clear(&u2);
+ mp_clear(&x1);
+ mp_clear(&v);
+ mp_clear(&n);
+
+ if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE);
+ if (err) {
+ MP_TO_SEC_ERROR(err);
+ rv = SECFailure;
+ }
+
+#if EC_DEBUG
+ printf("ECDSA verification %s\n",
+ (rv == SECSuccess) ? "succeeded" : "failed");
+#endif
+
+ return rv;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ec.h b/jdk.crypto.ec/share/native/libsunec/impl/ec.h
new file mode 100644
index 0000000..958419a
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ec.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the Elliptic Curve Cryptography library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ *********************************************************************** */
+
+#ifndef __ec_h_
+#define __ec_h_
+
+#define EC_DEBUG 0
+#define EC_POINT_FORM_COMPRESSED_Y0 0x02
+#define EC_POINT_FORM_COMPRESSED_Y1 0x03
+#define EC_POINT_FORM_UNCOMPRESSED 0x04
+#define EC_POINT_FORM_HYBRID_Y0 0x06
+#define EC_POINT_FORM_HYBRID_Y1 0x07
+
+#define ANSI_X962_CURVE_OID_TOTAL_LEN 10
+#define SECG_CURVE_OID_TOTAL_LEN 7
+#define BRAINPOOL_CURVE_OID_TOTAL_LEN 11
+
+#endif /* __ec_h_ */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ec2.h b/jdk.crypto.ec/share/native/libsunec/impl/ec2.h
new file mode 100644
index 0000000..72df04e
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ec2.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for binary polynomial field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * Last Modified Date from the Original Code: May 2017
+ *********************************************************************** */
+
+#ifndef _EC2_H
+#define _EC2_H
+
+#include "ecl-priv.h"
+
+/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
+mp_err ec_GF2m_pt_is_inf_aff(const mp_int *px, const mp_int *py);
+
+/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
+mp_err ec_GF2m_pt_set_inf_aff(mp_int *px, mp_int *py);
+
+/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx,
+ * qy). Uses affine coordinates. */
+mp_err ec_GF2m_pt_add_aff(const mp_int *px, const mp_int *py,
+ const mp_int *qx, const mp_int *qy, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+
+/* Computes R = P - Q. Uses affine coordinates. */
+mp_err ec_GF2m_pt_sub_aff(const mp_int *px, const mp_int *py,
+ const mp_int *qx, const mp_int *qy, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+
+/* Computes R = 2P. Uses affine coordinates. */
+mp_err ec_GF2m_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+
+/* Validates a point on a GF2m curve. */
+mp_err ec_GF2m_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group);
+
+/* by default, this routine is unused and thus doesn't need to be compiled */
+#ifdef ECL_ENABLE_GF2M_PT_MUL_AFF
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the irreducible that
+ * determines the field GF2m. Uses affine coordinates. */
+mp_err ec_GF2m_pt_mul_aff(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+#endif
+
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the irreducible that
+ * determines the field GF2m. Uses Montgomery projective coordinates. */
+mp_err ec_GF2m_pt_mul_mont(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group, int timing);
+
+#ifdef ECL_ENABLE_GF2M_PROJ
+/* Converts a point P(px, py) from affine coordinates to projective
+ * coordinates R(rx, ry, rz). */
+mp_err ec_GF2m_pt_aff2proj(const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, mp_int *rz, const ECGroup *group);
+
+/* Converts a point P(px, py, pz) from projective coordinates to affine
+ * coordinates R(rx, ry). */
+mp_err ec_GF2m_pt_proj2aff(const mp_int *px, const mp_int *py,
+ const mp_int *pz, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+
+/* Checks if point P(px, py, pz) is at infinity. Uses projective
+ * coordinates. */
+mp_err ec_GF2m_pt_is_inf_proj(const mp_int *px, const mp_int *py,
+ const mp_int *pz);
+
+/* Sets P(px, py, pz) to be the point at infinity. Uses projective
+ * coordinates. */
+mp_err ec_GF2m_pt_set_inf_proj(mp_int *px, mp_int *py, mp_int *pz);
+
+/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
+ * (qx, qy, qz). Uses projective coordinates. */
+mp_err ec_GF2m_pt_add_proj(const mp_int *px, const mp_int *py,
+ const mp_int *pz, const mp_int *qx,
+ const mp_int *qy, mp_int *rx, mp_int *ry,
+ mp_int *rz, const ECGroup *group);
+
+/* Computes R = 2P. Uses projective coordinates. */
+mp_err ec_GF2m_pt_dbl_proj(const mp_int *px, const mp_int *py,
+ const mp_int *pz, mp_int *rx, mp_int *ry,
+ mp_int *rz, const ECGroup *group);
+
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the prime that
+ * determines the field GF2m. Uses projective coordinates. */
+mp_err ec_GF2m_pt_mul_proj(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+#endif
+
+#endif /* _EC2_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ec2_163.c b/jdk.crypto.ec/share/native/libsunec/impl/ec2_163.c
new file mode 100644
index 0000000..d35d11d
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ec2_163.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for binary polynomial field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sheueling Chang-Shantz <sheueling.chang@sun.com>,
+ * Stephen Fung <fungstep@hotmail.com>, and
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories.
+ *
+ *********************************************************************** */
+
+#include "ec2.h"
+#include "mp_gf2m.h"
+#include "mp_gf2m-priv.h"
+#include "mpi.h"
+#include "mpi-priv.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+/* Fast reduction for polynomials over a 163-bit curve. Assumes reduction
+ * polynomial with terms {163, 7, 6, 3, 0}. */
+mp_err
+ec_GF2m_163_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit *u, z;
+
+ if (a != r) {
+ MP_CHECKOK(mp_copy(a, r));
+ }
+#ifdef ECL_SIXTY_FOUR_BIT
+ if (MP_USED(r) < 6) {
+ MP_CHECKOK(s_mp_pad(r, 6));
+ }
+ u = MP_DIGITS(r);
+ MP_USED(r) = 6;
+
+ /* u[5] only has 6 significant bits */
+ z = u[5];
+ u[2] ^= (z << 36) ^ (z << 35) ^ (z << 32) ^ (z << 29);
+ z = u[4];
+ u[2] ^= (z >> 28) ^ (z >> 29) ^ (z >> 32) ^ (z >> 35);
+ u[1] ^= (z << 36) ^ (z << 35) ^ (z << 32) ^ (z << 29);
+ z = u[3];
+ u[1] ^= (z >> 28) ^ (z >> 29) ^ (z >> 32) ^ (z >> 35);
+ u[0] ^= (z << 36) ^ (z << 35) ^ (z << 32) ^ (z << 29);
+ z = u[2] >> 35; /* z only has 29 significant bits */
+ u[0] ^= (z << 7) ^ (z << 6) ^ (z << 3) ^ z;
+ /* clear bits above 163 */
+ u[5] = u[4] = u[3] = 0;
+ u[2] ^= z << 35;
+#else
+ if (MP_USED(r) < 11) {
+ MP_CHECKOK(s_mp_pad(r, 11));
+ }
+ u = MP_DIGITS(r);
+ MP_USED(r) = 11;
+
+ /* u[11] only has 6 significant bits */
+ z = u[10];
+ u[5] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3);
+ u[4] ^= (z << 29);
+ z = u[9];
+ u[5] ^= (z >> 28) ^ (z >> 29);
+ u[4] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3);
+ u[3] ^= (z << 29);
+ z = u[8];
+ u[4] ^= (z >> 28) ^ (z >> 29);
+ u[3] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3);
+ u[2] ^= (z << 29);
+ z = u[7];
+ u[3] ^= (z >> 28) ^ (z >> 29);
+ u[2] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3);
+ u[1] ^= (z << 29);
+ z = u[6];
+ u[2] ^= (z >> 28) ^ (z >> 29);
+ u[1] ^= (z << 4) ^ (z << 3) ^ z ^ (z >> 3);
+ u[0] ^= (z << 29);
+ z = u[5] >> 3; /* z only has 29 significant bits */
+ u[1] ^= (z >> 25) ^ (z >> 26);
+ u[0] ^= (z << 7) ^ (z << 6) ^ (z << 3) ^ z;
+ /* clear bits above 163 */
+ u[11] = u[10] = u[9] = u[8] = u[7] = u[6] = 0;
+ u[5] ^= z << 3;
+#endif
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/* Fast squaring for polynomials over a 163-bit curve. Assumes reduction
+ * polynomial with terms {163, 7, 6, 3, 0}. */
+mp_err
+ec_GF2m_163_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit *u, *v;
+
+ v = MP_DIGITS(a);
+
+#ifdef ECL_SIXTY_FOUR_BIT
+ if (MP_USED(a) < 3) {
+ return mp_bsqrmod(a, meth->irr_arr, r);
+ }
+ if (MP_USED(r) < 6) {
+ MP_CHECKOK(s_mp_pad(r, 6));
+ }
+ MP_USED(r) = 6;
+#else
+ if (MP_USED(a) < 6) {
+ return mp_bsqrmod(a, meth->irr_arr, r);
+ }
+ if (MP_USED(r) < 12) {
+ MP_CHECKOK(s_mp_pad(r, 12));
+ }
+ MP_USED(r) = 12;
+#endif
+ u = MP_DIGITS(r);
+
+#ifdef ECL_THIRTY_TWO_BIT
+ u[11] = gf2m_SQR1(v[5]);
+ u[10] = gf2m_SQR0(v[5]);
+ u[9] = gf2m_SQR1(v[4]);
+ u[8] = gf2m_SQR0(v[4]);
+ u[7] = gf2m_SQR1(v[3]);
+ u[6] = gf2m_SQR0(v[3]);
+#endif
+ u[5] = gf2m_SQR1(v[2]);
+ u[4] = gf2m_SQR0(v[2]);
+ u[3] = gf2m_SQR1(v[1]);
+ u[2] = gf2m_SQR0(v[1]);
+ u[1] = gf2m_SQR1(v[0]);
+ u[0] = gf2m_SQR0(v[0]);
+ return ec_GF2m_163_mod(r, r, meth);
+
+ CLEANUP:
+ return res;
+}
+
+/* Fast multiplication for polynomials over a 163-bit curve. Assumes
+ * reduction polynomial with terms {163, 7, 6, 3, 0}. */
+mp_err
+ec_GF2m_163_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit a2 = 0, a1 = 0, a0, b2 = 0, b1 = 0, b0;
+
+#ifdef ECL_THIRTY_TWO_BIT
+ mp_digit a5 = 0, a4 = 0, a3 = 0, b5 = 0, b4 = 0, b3 = 0;
+ mp_digit rm[6];
+#endif
+
+ if (a == b) {
+ return ec_GF2m_163_sqr(a, r, meth);
+ } else {
+ switch (MP_USED(a)) {
+#ifdef ECL_THIRTY_TWO_BIT
+ case 6:
+ a5 = MP_DIGIT(a, 5);
+ case 5:
+ a4 = MP_DIGIT(a, 4);
+ case 4:
+ a3 = MP_DIGIT(a, 3);
+#endif
+ case 3:
+ a2 = MP_DIGIT(a, 2);
+ case 2:
+ a1 = MP_DIGIT(a, 1);
+ default:
+ a0 = MP_DIGIT(a, 0);
+ }
+ switch (MP_USED(b)) {
+#ifdef ECL_THIRTY_TWO_BIT
+ case 6:
+ b5 = MP_DIGIT(b, 5);
+ case 5:
+ b4 = MP_DIGIT(b, 4);
+ case 4:
+ b3 = MP_DIGIT(b, 3);
+#endif
+ case 3:
+ b2 = MP_DIGIT(b, 2);
+ case 2:
+ b1 = MP_DIGIT(b, 1);
+ default:
+ b0 = MP_DIGIT(b, 0);
+ }
+#ifdef ECL_SIXTY_FOUR_BIT
+ MP_CHECKOK(s_mp_pad(r, 6));
+ s_bmul_3x3(MP_DIGITS(r), a2, a1, a0, b2, b1, b0);
+ MP_USED(r) = 6;
+ s_mp_clamp(r);
+#else
+ MP_CHECKOK(s_mp_pad(r, 12));
+ s_bmul_3x3(MP_DIGITS(r) + 6, a5, a4, a3, b5, b4, b3);
+ s_bmul_3x3(MP_DIGITS(r), a2, a1, a0, b2, b1, b0);
+ s_bmul_3x3(rm, a5 ^ a2, a4 ^ a1, a3 ^ a0, b5 ^ b2, b4 ^ b1,
+ b3 ^ b0);
+ rm[5] ^= MP_DIGIT(r, 5) ^ MP_DIGIT(r, 11);
+ rm[4] ^= MP_DIGIT(r, 4) ^ MP_DIGIT(r, 10);
+ rm[3] ^= MP_DIGIT(r, 3) ^ MP_DIGIT(r, 9);
+ rm[2] ^= MP_DIGIT(r, 2) ^ MP_DIGIT(r, 8);
+ rm[1] ^= MP_DIGIT(r, 1) ^ MP_DIGIT(r, 7);
+ rm[0] ^= MP_DIGIT(r, 0) ^ MP_DIGIT(r, 6);
+ MP_DIGIT(r, 8) ^= rm[5];
+ MP_DIGIT(r, 7) ^= rm[4];
+ MP_DIGIT(r, 6) ^= rm[3];
+ MP_DIGIT(r, 5) ^= rm[2];
+ MP_DIGIT(r, 4) ^= rm[1];
+ MP_DIGIT(r, 3) ^= rm[0];
+ MP_USED(r) = 12;
+ s_mp_clamp(r);
+#endif
+ return ec_GF2m_163_mod(r, r, meth);
+ }
+
+ CLEANUP:
+ return res;
+}
+
+/* Wire in fast field arithmetic for 163-bit curves. */
+mp_err
+ec_group_set_gf2m163(ECGroup *group, ECCurveName name)
+{
+ group->meth->field_mod = &ec_GF2m_163_mod;
+ group->meth->field_mul = &ec_GF2m_163_mul;
+ group->meth->field_sqr = &ec_GF2m_163_sqr;
+ return MP_OKAY;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ec2_193.c b/jdk.crypto.ec/share/native/libsunec/impl/ec2_193.c
new file mode 100644
index 0000000..bbff2e5
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ec2_193.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for binary polynomial field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sheueling Chang-Shantz <sheueling.chang@sun.com>,
+ * Stephen Fung <fungstep@hotmail.com>, and
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories.
+ *
+ *********************************************************************** */
+
+#include "ec2.h"
+#include "mp_gf2m.h"
+#include "mp_gf2m-priv.h"
+#include "mpi.h"
+#include "mpi-priv.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+/* Fast reduction for polynomials over a 193-bit curve. Assumes reduction
+ * polynomial with terms {193, 15, 0}. */
+mp_err
+ec_GF2m_193_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit *u, z;
+
+ if (a != r) {
+ MP_CHECKOK(mp_copy(a, r));
+ }
+#ifdef ECL_SIXTY_FOUR_BIT
+ if (MP_USED(r) < 7) {
+ MP_CHECKOK(s_mp_pad(r, 7));
+ }
+ u = MP_DIGITS(r);
+ MP_USED(r) = 7;
+
+ /* u[6] only has 2 significant bits */
+ z = u[6];
+ u[3] ^= (z << 14) ^ (z >> 1);
+ u[2] ^= (z << 63);
+ z = u[5];
+ u[3] ^= (z >> 50);
+ u[2] ^= (z << 14) ^ (z >> 1);
+ u[1] ^= (z << 63);
+ z = u[4];
+ u[2] ^= (z >> 50);
+ u[1] ^= (z << 14) ^ (z >> 1);
+ u[0] ^= (z << 63);
+ z = u[3] >> 1; /* z only has 63 significant bits */
+ u[1] ^= (z >> 49);
+ u[0] ^= (z << 15) ^ z;
+ /* clear bits above 193 */
+ u[6] = u[5] = u[4] = 0;
+ u[3] ^= z << 1;
+#else
+ if (MP_USED(r) < 13) {
+ MP_CHECKOK(s_mp_pad(r, 13));
+ }
+ u = MP_DIGITS(r);
+ MP_USED(r) = 13;
+
+ /* u[12] only has 2 significant bits */
+ z = u[12];
+ u[6] ^= (z << 14) ^ (z >> 1);
+ u[5] ^= (z << 31);
+ z = u[11];
+ u[6] ^= (z >> 18);
+ u[5] ^= (z << 14) ^ (z >> 1);
+ u[4] ^= (z << 31);
+ z = u[10];
+ u[5] ^= (z >> 18);
+ u[4] ^= (z << 14) ^ (z >> 1);
+ u[3] ^= (z << 31);
+ z = u[9];
+ u[4] ^= (z >> 18);
+ u[3] ^= (z << 14) ^ (z >> 1);
+ u[2] ^= (z << 31);
+ z = u[8];
+ u[3] ^= (z >> 18);
+ u[2] ^= (z << 14) ^ (z >> 1);
+ u[1] ^= (z << 31);
+ z = u[7];
+ u[2] ^= (z >> 18);
+ u[1] ^= (z << 14) ^ (z >> 1);
+ u[0] ^= (z << 31);
+ z = u[6] >> 1; /* z only has 31 significant bits */
+ u[1] ^= (z >> 17);
+ u[0] ^= (z << 15) ^ z;
+ /* clear bits above 193 */
+ u[12] = u[11] = u[10] = u[9] = u[8] = u[7] = 0;
+ u[6] ^= z << 1;
+#endif
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/* Fast squaring for polynomials over a 193-bit curve. Assumes reduction
+ * polynomial with terms {193, 15, 0}. */
+mp_err
+ec_GF2m_193_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit *u, *v;
+
+ v = MP_DIGITS(a);
+
+#ifdef ECL_SIXTY_FOUR_BIT
+ if (MP_USED(a) < 4) {
+ return mp_bsqrmod(a, meth->irr_arr, r);
+ }
+ if (MP_USED(r) < 7) {
+ MP_CHECKOK(s_mp_pad(r, 7));
+ }
+ MP_USED(r) = 7;
+#else
+ if (MP_USED(a) < 7) {
+ return mp_bsqrmod(a, meth->irr_arr, r);
+ }
+ if (MP_USED(r) < 13) {
+ MP_CHECKOK(s_mp_pad(r, 13));
+ }
+ MP_USED(r) = 13;
+#endif
+ u = MP_DIGITS(r);
+
+#ifdef ECL_THIRTY_TWO_BIT
+ u[12] = gf2m_SQR0(v[6]);
+ u[11] = gf2m_SQR1(v[5]);
+ u[10] = gf2m_SQR0(v[5]);
+ u[9] = gf2m_SQR1(v[4]);
+ u[8] = gf2m_SQR0(v[4]);
+ u[7] = gf2m_SQR1(v[3]);
+#endif
+ u[6] = gf2m_SQR0(v[3]);
+ u[5] = gf2m_SQR1(v[2]);
+ u[4] = gf2m_SQR0(v[2]);
+ u[3] = gf2m_SQR1(v[1]);
+ u[2] = gf2m_SQR0(v[1]);
+ u[1] = gf2m_SQR1(v[0]);
+ u[0] = gf2m_SQR0(v[0]);
+ return ec_GF2m_193_mod(r, r, meth);
+
+ CLEANUP:
+ return res;
+}
+
+/* Fast multiplication for polynomials over a 193-bit curve. Assumes
+ * reduction polynomial with terms {193, 15, 0}. */
+mp_err
+ec_GF2m_193_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit a3 = 0, a2 = 0, a1 = 0, a0, b3 = 0, b2 = 0, b1 = 0, b0;
+
+#ifdef ECL_THIRTY_TWO_BIT
+ mp_digit a6 = 0, a5 = 0, a4 = 0, b6 = 0, b5 = 0, b4 = 0;
+ mp_digit rm[8];
+#endif
+
+ if (a == b) {
+ return ec_GF2m_193_sqr(a, r, meth);
+ } else {
+ switch (MP_USED(a)) {
+#ifdef ECL_THIRTY_TWO_BIT
+ case 7:
+ a6 = MP_DIGIT(a, 6);
+ case 6:
+ a5 = MP_DIGIT(a, 5);
+ case 5:
+ a4 = MP_DIGIT(a, 4);
+#endif
+ case 4:
+ a3 = MP_DIGIT(a, 3);
+ case 3:
+ a2 = MP_DIGIT(a, 2);
+ case 2:
+ a1 = MP_DIGIT(a, 1);
+ default:
+ a0 = MP_DIGIT(a, 0);
+ }
+ switch (MP_USED(b)) {
+#ifdef ECL_THIRTY_TWO_BIT
+ case 7:
+ b6 = MP_DIGIT(b, 6);
+ case 6:
+ b5 = MP_DIGIT(b, 5);
+ case 5:
+ b4 = MP_DIGIT(b, 4);
+#endif
+ case 4:
+ b3 = MP_DIGIT(b, 3);
+ case 3:
+ b2 = MP_DIGIT(b, 2);
+ case 2:
+ b1 = MP_DIGIT(b, 1);
+ default:
+ b0 = MP_DIGIT(b, 0);
+ }
+#ifdef ECL_SIXTY_FOUR_BIT
+ MP_CHECKOK(s_mp_pad(r, 8));
+ s_bmul_4x4(MP_DIGITS(r), a3, a2, a1, a0, b3, b2, b1, b0);
+ MP_USED(r) = 8;
+ s_mp_clamp(r);
+#else
+ MP_CHECKOK(s_mp_pad(r, 14));
+ s_bmul_3x3(MP_DIGITS(r) + 8, a6, a5, a4, b6, b5, b4);
+ s_bmul_4x4(MP_DIGITS(r), a3, a2, a1, a0, b3, b2, b1, b0);
+ s_bmul_4x4(rm, a3, a6 ^ a2, a5 ^ a1, a4 ^ a0, b3, b6 ^ b2, b5 ^ b1,
+ b4 ^ b0);
+ rm[7] ^= MP_DIGIT(r, 7);
+ rm[6] ^= MP_DIGIT(r, 6);
+ rm[5] ^= MP_DIGIT(r, 5) ^ MP_DIGIT(r, 13);
+ rm[4] ^= MP_DIGIT(r, 4) ^ MP_DIGIT(r, 12);
+ rm[3] ^= MP_DIGIT(r, 3) ^ MP_DIGIT(r, 11);
+ rm[2] ^= MP_DIGIT(r, 2) ^ MP_DIGIT(r, 10);
+ rm[1] ^= MP_DIGIT(r, 1) ^ MP_DIGIT(r, 9);
+ rm[0] ^= MP_DIGIT(r, 0) ^ MP_DIGIT(r, 8);
+ MP_DIGIT(r, 11) ^= rm[7];
+ MP_DIGIT(r, 10) ^= rm[6];
+ MP_DIGIT(r, 9) ^= rm[5];
+ MP_DIGIT(r, 8) ^= rm[4];
+ MP_DIGIT(r, 7) ^= rm[3];
+ MP_DIGIT(r, 6) ^= rm[2];
+ MP_DIGIT(r, 5) ^= rm[1];
+ MP_DIGIT(r, 4) ^= rm[0];
+ MP_USED(r) = 14;
+ s_mp_clamp(r);
+#endif
+ return ec_GF2m_193_mod(r, r, meth);
+ }
+
+ CLEANUP:
+ return res;
+}
+
+/* Wire in fast field arithmetic for 193-bit curves. */
+mp_err
+ec_group_set_gf2m193(ECGroup *group, ECCurveName name)
+{
+ group->meth->field_mod = &ec_GF2m_193_mod;
+ group->meth->field_mul = &ec_GF2m_193_mul;
+ group->meth->field_sqr = &ec_GF2m_193_sqr;
+ return MP_OKAY;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ec2_233.c b/jdk.crypto.ec/share/native/libsunec/impl/ec2_233.c
new file mode 100644
index 0000000..6ba2706
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ec2_233.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for binary polynomial field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sheueling Chang-Shantz <sheueling.chang@sun.com>,
+ * Stephen Fung <fungstep@hotmail.com>, and
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories.
+ *
+ *********************************************************************** */
+
+#include "ec2.h"
+#include "mp_gf2m.h"
+#include "mp_gf2m-priv.h"
+#include "mpi.h"
+#include "mpi-priv.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+/* Fast reduction for polynomials over a 233-bit curve. Assumes reduction
+ * polynomial with terms {233, 74, 0}. */
+mp_err
+ec_GF2m_233_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit *u, z;
+
+ if (a != r) {
+ MP_CHECKOK(mp_copy(a, r));
+ }
+#ifdef ECL_SIXTY_FOUR_BIT
+ if (MP_USED(r) < 8) {
+ MP_CHECKOK(s_mp_pad(r, 8));
+ }
+ u = MP_DIGITS(r);
+ MP_USED(r) = 8;
+
+ /* u[7] only has 18 significant bits */
+ z = u[7];
+ u[4] ^= (z << 33) ^ (z >> 41);
+ u[3] ^= (z << 23);
+ z = u[6];
+ u[4] ^= (z >> 31);
+ u[3] ^= (z << 33) ^ (z >> 41);
+ u[2] ^= (z << 23);
+ z = u[5];
+ u[3] ^= (z >> 31);
+ u[2] ^= (z << 33) ^ (z >> 41);
+ u[1] ^= (z << 23);
+ z = u[4];
+ u[2] ^= (z >> 31);
+ u[1] ^= (z << 33) ^ (z >> 41);
+ u[0] ^= (z << 23);
+ z = u[3] >> 41; /* z only has 23 significant bits */
+ u[1] ^= (z << 10);
+ u[0] ^= z;
+ /* clear bits above 233 */
+ u[7] = u[6] = u[5] = u[4] = 0;
+ u[3] ^= z << 41;
+#else
+ if (MP_USED(r) < 15) {
+ MP_CHECKOK(s_mp_pad(r, 15));
+ }
+ u = MP_DIGITS(r);
+ MP_USED(r) = 15;
+
+ /* u[14] only has 18 significant bits */
+ z = u[14];
+ u[9] ^= (z << 1);
+ u[7] ^= (z >> 9);
+ u[6] ^= (z << 23);
+ z = u[13];
+ u[9] ^= (z >> 31);
+ u[8] ^= (z << 1);
+ u[6] ^= (z >> 9);
+ u[5] ^= (z << 23);
+ z = u[12];
+ u[8] ^= (z >> 31);
+ u[7] ^= (z << 1);
+ u[5] ^= (z >> 9);
+ u[4] ^= (z << 23);
+ z = u[11];
+ u[7] ^= (z >> 31);
+ u[6] ^= (z << 1);
+ u[4] ^= (z >> 9);
+ u[3] ^= (z << 23);
+ z = u[10];
+ u[6] ^= (z >> 31);
+ u[5] ^= (z << 1);
+ u[3] ^= (z >> 9);
+ u[2] ^= (z << 23);
+ z = u[9];
+ u[5] ^= (z >> 31);
+ u[4] ^= (z << 1);
+ u[2] ^= (z >> 9);
+ u[1] ^= (z << 23);
+ z = u[8];
+ u[4] ^= (z >> 31);
+ u[3] ^= (z << 1);
+ u[1] ^= (z >> 9);
+ u[0] ^= (z << 23);
+ z = u[7] >> 9; /* z only has 23 significant bits */
+ u[3] ^= (z >> 22);
+ u[2] ^= (z << 10);
+ u[0] ^= z;
+ /* clear bits above 233 */
+ u[14] = u[13] = u[12] = u[11] = u[10] = u[9] = u[8] = 0;
+ u[7] ^= z << 9;
+#endif
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/* Fast squaring for polynomials over a 233-bit curve. Assumes reduction
+ * polynomial with terms {233, 74, 0}. */
+mp_err
+ec_GF2m_233_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit *u, *v;
+
+ v = MP_DIGITS(a);
+
+#ifdef ECL_SIXTY_FOUR_BIT
+ if (MP_USED(a) < 4) {
+ return mp_bsqrmod(a, meth->irr_arr, r);
+ }
+ if (MP_USED(r) < 8) {
+ MP_CHECKOK(s_mp_pad(r, 8));
+ }
+ MP_USED(r) = 8;
+#else
+ if (MP_USED(a) < 8) {
+ return mp_bsqrmod(a, meth->irr_arr, r);
+ }
+ if (MP_USED(r) < 15) {
+ MP_CHECKOK(s_mp_pad(r, 15));
+ }
+ MP_USED(r) = 15;
+#endif
+ u = MP_DIGITS(r);
+
+#ifdef ECL_THIRTY_TWO_BIT
+ u[14] = gf2m_SQR0(v[7]);
+ u[13] = gf2m_SQR1(v[6]);
+ u[12] = gf2m_SQR0(v[6]);
+ u[11] = gf2m_SQR1(v[5]);
+ u[10] = gf2m_SQR0(v[5]);
+ u[9] = gf2m_SQR1(v[4]);
+ u[8] = gf2m_SQR0(v[4]);
+#endif
+ u[7] = gf2m_SQR1(v[3]);
+ u[6] = gf2m_SQR0(v[3]);
+ u[5] = gf2m_SQR1(v[2]);
+ u[4] = gf2m_SQR0(v[2]);
+ u[3] = gf2m_SQR1(v[1]);
+ u[2] = gf2m_SQR0(v[1]);
+ u[1] = gf2m_SQR1(v[0]);
+ u[0] = gf2m_SQR0(v[0]);
+ return ec_GF2m_233_mod(r, r, meth);
+
+ CLEANUP:
+ return res;
+}
+
+/* Fast multiplication for polynomials over a 233-bit curve. Assumes
+ * reduction polynomial with terms {233, 74, 0}. */
+mp_err
+ec_GF2m_233_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit a3 = 0, a2 = 0, a1 = 0, a0, b3 = 0, b2 = 0, b1 = 0, b0;
+
+#ifdef ECL_THIRTY_TWO_BIT
+ mp_digit a7 = 0, a6 = 0, a5 = 0, a4 = 0, b7 = 0, b6 = 0, b5 = 0, b4 =
+ 0;
+ mp_digit rm[8];
+#endif
+
+ if (a == b) {
+ return ec_GF2m_233_sqr(a, r, meth);
+ } else {
+ switch (MP_USED(a)) {
+#ifdef ECL_THIRTY_TWO_BIT
+ case 8:
+ a7 = MP_DIGIT(a, 7);
+ case 7:
+ a6 = MP_DIGIT(a, 6);
+ case 6:
+ a5 = MP_DIGIT(a, 5);
+ case 5:
+ a4 = MP_DIGIT(a, 4);
+#endif
+ case 4:
+ a3 = MP_DIGIT(a, 3);
+ case 3:
+ a2 = MP_DIGIT(a, 2);
+ case 2:
+ a1 = MP_DIGIT(a, 1);
+ default:
+ a0 = MP_DIGIT(a, 0);
+ }
+ switch (MP_USED(b)) {
+#ifdef ECL_THIRTY_TWO_BIT
+ case 8:
+ b7 = MP_DIGIT(b, 7);
+ case 7:
+ b6 = MP_DIGIT(b, 6);
+ case 6:
+ b5 = MP_DIGIT(b, 5);
+ case 5:
+ b4 = MP_DIGIT(b, 4);
+#endif
+ case 4:
+ b3 = MP_DIGIT(b, 3);
+ case 3:
+ b2 = MP_DIGIT(b, 2);
+ case 2:
+ b1 = MP_DIGIT(b, 1);
+ default:
+ b0 = MP_DIGIT(b, 0);
+ }
+#ifdef ECL_SIXTY_FOUR_BIT
+ MP_CHECKOK(s_mp_pad(r, 8));
+ s_bmul_4x4(MP_DIGITS(r), a3, a2, a1, a0, b3, b2, b1, b0);
+ MP_USED(r) = 8;
+ s_mp_clamp(r);
+#else
+ MP_CHECKOK(s_mp_pad(r, 16));
+ s_bmul_4x4(MP_DIGITS(r) + 8, a7, a6, a5, a4, b7, b6, b5, b4);
+ s_bmul_4x4(MP_DIGITS(r), a3, a2, a1, a0, b3, b2, b1, b0);
+ s_bmul_4x4(rm, a7 ^ a3, a6 ^ a2, a5 ^ a1, a4 ^ a0, b7 ^ b3,
+ b6 ^ b2, b5 ^ b1, b4 ^ b0);
+ rm[7] ^= MP_DIGIT(r, 7) ^ MP_DIGIT(r, 15);
+ rm[6] ^= MP_DIGIT(r, 6) ^ MP_DIGIT(r, 14);
+ rm[5] ^= MP_DIGIT(r, 5) ^ MP_DIGIT(r, 13);
+ rm[4] ^= MP_DIGIT(r, 4) ^ MP_DIGIT(r, 12);
+ rm[3] ^= MP_DIGIT(r, 3) ^ MP_DIGIT(r, 11);
+ rm[2] ^= MP_DIGIT(r, 2) ^ MP_DIGIT(r, 10);
+ rm[1] ^= MP_DIGIT(r, 1) ^ MP_DIGIT(r, 9);
+ rm[0] ^= MP_DIGIT(r, 0) ^ MP_DIGIT(r, 8);
+ MP_DIGIT(r, 11) ^= rm[7];
+ MP_DIGIT(r, 10) ^= rm[6];
+ MP_DIGIT(r, 9) ^= rm[5];
+ MP_DIGIT(r, 8) ^= rm[4];
+ MP_DIGIT(r, 7) ^= rm[3];
+ MP_DIGIT(r, 6) ^= rm[2];
+ MP_DIGIT(r, 5) ^= rm[1];
+ MP_DIGIT(r, 4) ^= rm[0];
+ MP_USED(r) = 16;
+ s_mp_clamp(r);
+#endif
+ return ec_GF2m_233_mod(r, r, meth);
+ }
+
+ CLEANUP:
+ return res;
+}
+
+/* Wire in fast field arithmetic for 233-bit curves. */
+mp_err
+ec_group_set_gf2m233(ECGroup *group, ECCurveName name)
+{
+ group->meth->field_mod = &ec_GF2m_233_mod;
+ group->meth->field_mul = &ec_GF2m_233_mul;
+ group->meth->field_sqr = &ec_GF2m_233_sqr;
+ return MP_OKAY;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c b/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c
new file mode 100644
index 0000000..8d0f546
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for binary polynomial field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * Last Modified Date from the Original Code: May 2017
+ *********************************************************************** */
+
+#include "ec2.h"
+#include "mplogic.h"
+#include "mp_gf2m.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
+mp_err
+ec_GF2m_pt_is_inf_aff(const mp_int *px, const mp_int *py)
+{
+
+ if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) {
+ return MP_YES;
+ } else {
+ return MP_NO;
+ }
+
+}
+
+/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
+mp_err
+ec_GF2m_pt_set_inf_aff(mp_int *px, mp_int *py)
+{
+ mp_zero(px);
+ mp_zero(py);
+ return MP_OKAY;
+}
+
+/* Computes R = P + Q based on IEEE P1363 A.10.2. Elliptic curve points P,
+ * Q, and R can all be identical. Uses affine coordinates. */
+mp_err
+ec_GF2m_pt_add_aff(const mp_int *px, const mp_int *py, const mp_int *qx,
+ const mp_int *qy, mp_int *rx, mp_int *ry,
+ const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ mp_int lambda, tempx, tempy;
+
+ MP_DIGITS(&lambda) = 0;
+ MP_DIGITS(&tempx) = 0;
+ MP_DIGITS(&tempy) = 0;
+ MP_CHECKOK(mp_init(&lambda, FLAG(px)));
+ MP_CHECKOK(mp_init(&tempx, FLAG(px)));
+ MP_CHECKOK(mp_init(&tempy, FLAG(px)));
+ /* if P = inf, then R = Q */
+ if (ec_GF2m_pt_is_inf_aff(px, py) == 0) {
+ MP_CHECKOK(mp_copy(qx, rx));
+ MP_CHECKOK(mp_copy(qy, ry));
+ res = MP_OKAY;
+ goto CLEANUP;
+ }
+ /* if Q = inf, then R = P */
+ if (ec_GF2m_pt_is_inf_aff(qx, qy) == 0) {
+ MP_CHECKOK(mp_copy(px, rx));
+ MP_CHECKOK(mp_copy(py, ry));
+ res = MP_OKAY;
+ goto CLEANUP;
+ }
+ /* if px != qx, then lambda = (py+qy) / (px+qx), tempx = a + lambda^2
+ * + lambda + px + qx */
+ if (mp_cmp(px, qx) != 0) {
+ MP_CHECKOK(group->meth->field_add(py, qy, &tempy, group->meth));
+ MP_CHECKOK(group->meth->field_add(px, qx, &tempx, group->meth));
+ MP_CHECKOK(group->meth->
+ field_div(&tempy, &tempx, &lambda, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(&lambda, &tempx, group->meth));
+ MP_CHECKOK(group->meth->
+ field_add(&tempx, &lambda, &tempx, group->meth));
+ MP_CHECKOK(group->meth->
+ field_add(&tempx, &group->curvea, &tempx, group->meth));
+ MP_CHECKOK(group->meth->
+ field_add(&tempx, px, &tempx, group->meth));
+ MP_CHECKOK(group->meth->
+ field_add(&tempx, qx, &tempx, group->meth));
+ } else {
+ /* if py != qy or qx = 0, then R = inf */
+ if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qx) == 0)) {
+ mp_zero(rx);
+ mp_zero(ry);
+ res = MP_OKAY;
+ goto CLEANUP;
+ }
+ /* lambda = qx + qy / qx */
+ MP_CHECKOK(group->meth->field_div(qy, qx, &lambda, group->meth));
+ MP_CHECKOK(group->meth->
+ field_add(&lambda, qx, &lambda, group->meth));
+ /* tempx = a + lambda^2 + lambda */
+ MP_CHECKOK(group->meth->field_sqr(&lambda, &tempx, group->meth));
+ MP_CHECKOK(group->meth->
+ field_add(&tempx, &lambda, &tempx, group->meth));
+ MP_CHECKOK(group->meth->
+ field_add(&tempx, &group->curvea, &tempx, group->meth));
+ }
+ /* ry = (qx + tempx) * lambda + tempx + qy */
+ MP_CHECKOK(group->meth->field_add(qx, &tempx, &tempy, group->meth));
+ MP_CHECKOK(group->meth->
+ field_mul(&tempy, &lambda, &tempy, group->meth));
+ MP_CHECKOK(group->meth->
+ field_add(&tempy, &tempx, &tempy, group->meth));
+ MP_CHECKOK(group->meth->field_add(&tempy, qy, ry, group->meth));
+ /* rx = tempx */
+ MP_CHECKOK(mp_copy(&tempx, rx));
+
+ CLEANUP:
+ mp_clear(&lambda);
+ mp_clear(&tempx);
+ mp_clear(&tempy);
+ return res;
+}
+
+/* Computes R = P - Q. Elliptic curve points P, Q, and R can all be
+ * identical. Uses affine coordinates. */
+mp_err
+ec_GF2m_pt_sub_aff(const mp_int *px, const mp_int *py, const mp_int *qx,
+ const mp_int *qy, mp_int *rx, mp_int *ry,
+ const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ mp_int nqy;
+
+ MP_DIGITS(&nqy) = 0;
+ MP_CHECKOK(mp_init(&nqy, FLAG(px)));
+ /* nqy = qx+qy */
+ MP_CHECKOK(group->meth->field_add(qx, qy, &nqy, group->meth));
+ MP_CHECKOK(group->point_add(px, py, qx, &nqy, rx, ry, group));
+ CLEANUP:
+ mp_clear(&nqy);
+ return res;
+}
+
+/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
+ * affine coordinates. */
+mp_err
+ec_GF2m_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, const ECGroup *group)
+{
+ return group->point_add(px, py, px, py, rx, ry, group);
+}
+
+/* by default, this routine is unused and thus doesn't need to be compiled */
+#ifdef ECL_ENABLE_GF2M_PT_MUL_AFF
+/* Computes R = nP based on IEEE P1363 A.10.3. Elliptic curve points P and
+ * R can be identical. Uses affine coordinates. */
+mp_err
+ec_GF2m_pt_mul_aff(const mp_int *n, const mp_int *px, const mp_int *py,
+ mp_int *rx, mp_int *ry, const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ mp_int k, k3, qx, qy, sx, sy;
+ int b1, b3, i, l;
+
+ MP_DIGITS(&k) = 0;
+ MP_DIGITS(&k3) = 0;
+ MP_DIGITS(&qx) = 0;
+ MP_DIGITS(&qy) = 0;
+ MP_DIGITS(&sx) = 0;
+ MP_DIGITS(&sy) = 0;
+ MP_CHECKOK(mp_init(&k));
+ MP_CHECKOK(mp_init(&k3));
+ MP_CHECKOK(mp_init(&qx));
+ MP_CHECKOK(mp_init(&qy));
+ MP_CHECKOK(mp_init(&sx));
+ MP_CHECKOK(mp_init(&sy));
+
+ /* if n = 0 then r = inf */
+ if (mp_cmp_z(n) == 0) {
+ mp_zero(rx);
+ mp_zero(ry);
+ res = MP_OKAY;
+ goto CLEANUP;
+ }
+ /* Q = P, k = n */
+ MP_CHECKOK(mp_copy(px, &qx));
+ MP_CHECKOK(mp_copy(py, &qy));
+ MP_CHECKOK(mp_copy(n, &k));
+ /* if n < 0 then Q = -Q, k = -k */
+ if (mp_cmp_z(n) < 0) {
+ MP_CHECKOK(group->meth->field_add(&qx, &qy, &qy, group->meth));
+ MP_CHECKOK(mp_neg(&k, &k));
+ }
+#ifdef ECL_DEBUG /* basic double and add method */
+ l = mpl_significant_bits(&k) - 1;
+ MP_CHECKOK(mp_copy(&qx, &sx));
+ MP_CHECKOK(mp_copy(&qy, &sy));
+ for (i = l - 1; i >= 0; i--) {
+ /* S = 2S */
+ MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group));
+ /* if k_i = 1, then S = S + Q */
+ if (mpl_get_bit(&k, i) != 0) {
+ MP_CHECKOK(group->
+ point_add(&sx, &sy, &qx, &qy, &sx, &sy, group));
+ }
+ }
+#else /* double and add/subtract method from
+ * standard */
+ /* k3 = 3 * k */
+ MP_CHECKOK(mp_set_int(&k3, 3));
+ MP_CHECKOK(mp_mul(&k, &k3, &k3));
+ /* S = Q */
+ MP_CHECKOK(mp_copy(&qx, &sx));
+ MP_CHECKOK(mp_copy(&qy, &sy));
+ /* l = index of high order bit in binary representation of 3*k */
+ l = mpl_significant_bits(&k3) - 1;
+ /* for i = l-1 downto 1 */
+ for (i = l - 1; i >= 1; i--) {
+ /* S = 2S */
+ MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group));
+ b3 = MP_GET_BIT(&k3, i);
+ b1 = MP_GET_BIT(&k, i);
+ /* if k3_i = 1 and k_i = 0, then S = S + Q */
+ if ((b3 == 1) && (b1 == 0)) {
+ MP_CHECKOK(group->
+ point_add(&sx, &sy, &qx, &qy, &sx, &sy, group));
+ /* if k3_i = 0 and k_i = 1, then S = S - Q */
+ } else if ((b3 == 0) && (b1 == 1)) {
+ MP_CHECKOK(group->
+ point_sub(&sx, &sy, &qx, &qy, &sx, &sy, group));
+ }
+ }
+#endif
+ /* output S */
+ MP_CHECKOK(mp_copy(&sx, rx));
+ MP_CHECKOK(mp_copy(&sy, ry));
+
+ CLEANUP:
+ mp_clear(&k);
+ mp_clear(&k3);
+ mp_clear(&qx);
+ mp_clear(&qy);
+ mp_clear(&sx);
+ mp_clear(&sy);
+ return res;
+}
+#endif
+
+/* Validates a point on a GF2m curve. */
+mp_err
+ec_GF2m_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group)
+{
+ mp_err res = MP_NO;
+ mp_int accl, accr, tmp, pxt, pyt;
+
+ MP_DIGITS(&accl) = 0;
+ MP_DIGITS(&accr) = 0;
+ MP_DIGITS(&tmp) = 0;
+ MP_DIGITS(&pxt) = 0;
+ MP_DIGITS(&pyt) = 0;
+ MP_CHECKOK(mp_init(&accl, FLAG(px)));
+ MP_CHECKOK(mp_init(&accr, FLAG(px)));
+ MP_CHECKOK(mp_init(&tmp, FLAG(px)));
+ MP_CHECKOK(mp_init(&pxt, FLAG(px)));
+ MP_CHECKOK(mp_init(&pyt, FLAG(px)));
+
+ /* 1: Verify that publicValue is not the point at infinity */
+ if (ec_GF2m_pt_is_inf_aff(px, py) == MP_YES) {
+ res = MP_NO;
+ goto CLEANUP;
+ }
+ /* 2: Verify that the coordinates of publicValue are elements
+ * of the field.
+ */
+ if ((MP_SIGN(px) == MP_NEG) || (mp_cmp(px, &group->meth->irr) >= 0) ||
+ (MP_SIGN(py) == MP_NEG) || (mp_cmp(py, &group->meth->irr) >= 0)) {
+ res = MP_NO;
+ goto CLEANUP;
+ }
+ /* 3: Verify that publicValue is on the curve. */
+ if (group->meth->field_enc) {
+ group->meth->field_enc(px, &pxt, group->meth);
+ group->meth->field_enc(py, &pyt, group->meth);
+ } else {
+ mp_copy(px, &pxt);
+ mp_copy(py, &pyt);
+ }
+ /* left-hand side: y^2 + x*y */
+ MP_CHECKOK( group->meth->field_sqr(&pyt, &accl, group->meth) );
+ MP_CHECKOK( group->meth->field_mul(&pxt, &pyt, &tmp, group->meth) );
+ MP_CHECKOK( group->meth->field_add(&accl, &tmp, &accl, group->meth) );
+ /* right-hand side: x^3 + a*x^2 + b */
+ MP_CHECKOK( group->meth->field_sqr(&pxt, &tmp, group->meth) );
+ MP_CHECKOK( group->meth->field_mul(&pxt, &tmp, &accr, group->meth) );
+ MP_CHECKOK( group->meth->field_mul(&group->curvea, &tmp, &tmp, group->meth) );
+ MP_CHECKOK( group->meth->field_add(&tmp, &accr, &accr, group->meth) );
+ MP_CHECKOK( group->meth->field_add(&accr, &group->curveb, &accr, group->meth) );
+ /* check LHS - RHS == 0 */
+ MP_CHECKOK( group->meth->field_add(&accl, &accr, &accr, group->meth) );
+ if (mp_cmp_z(&accr) != 0) {
+ res = MP_NO;
+ goto CLEANUP;
+ }
+ /* 4: Verify that the order of the curve times the publicValue
+ * is the point at infinity.
+ */
+ /* timing mitigation is not supported */
+ MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, /*timing*/ 0) );
+ if (ec_GF2m_pt_is_inf_aff(&pxt, &pyt) != MP_YES) {
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ res = MP_YES;
+
+CLEANUP:
+ mp_clear(&accl);
+ mp_clear(&accr);
+ mp_clear(&tmp);
+ mp_clear(&pxt);
+ mp_clear(&pyt);
+ return res;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c b/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c
new file mode 100644
index 0000000..bb60553
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ec2_mont.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for binary polynomial field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sheueling Chang-Shantz <sheueling.chang@sun.com>,
+ * Stephen Fung <fungstep@hotmail.com>, and
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories.
+ *
+ * Last Modified Date from the Original Code: May 2017
+ *********************************************************************** */
+
+#include "ec2.h"
+#include "mplogic.h"
+#include "mp_gf2m.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+/* Compute the x-coordinate x/z for the point 2*(x/z) in Montgomery
+ * projective coordinates. Uses algorithm Mdouble in appendix of Lopez, J.
+ * and Dahab, R. "Fast multiplication on elliptic curves over GF(2^m)
+ * without precomputation". modified to not require precomputation of
+ * c=b^{2^{m-1}}. */
+static mp_err
+gf2m_Mdouble(mp_int *x, mp_int *z, const ECGroup *group, int kmflag)
+{
+ mp_err res = MP_OKAY;
+ mp_int t1;
+
+ MP_DIGITS(&t1) = 0;
+ MP_CHECKOK(mp_init(&t1, kmflag));
+
+ MP_CHECKOK(group->meth->field_sqr(x, x, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(z, &t1, group->meth));
+ MP_CHECKOK(group->meth->field_mul(x, &t1, z, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(x, x, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(&t1, &t1, group->meth));
+ MP_CHECKOK(group->meth->
+ field_mul(&group->curveb, &t1, &t1, group->meth));
+ MP_CHECKOK(group->meth->field_add(x, &t1, x, group->meth));
+
+ CLEANUP:
+ mp_clear(&t1);
+ return res;
+}
+
+/* Compute the x-coordinate x1/z1 for the point (x1/z1)+(x2/x2) in
+ * Montgomery projective coordinates. Uses algorithm Madd in appendix of
+ * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over
+ * GF(2^m) without precomputation". */
+static mp_err
+gf2m_Madd(const mp_int *x, mp_int *x1, mp_int *z1, mp_int *x2, mp_int *z2,
+ const ECGroup *group, int kmflag)
+{
+ mp_err res = MP_OKAY;
+ mp_int t1, t2;
+
+ MP_DIGITS(&t1) = 0;
+ MP_DIGITS(&t2) = 0;
+ MP_CHECKOK(mp_init(&t1, kmflag));
+ MP_CHECKOK(mp_init(&t2, kmflag));
+
+ MP_CHECKOK(mp_copy(x, &t1));
+ MP_CHECKOK(group->meth->field_mul(x1, z2, x1, group->meth));
+ MP_CHECKOK(group->meth->field_mul(z1, x2, z1, group->meth));
+ MP_CHECKOK(group->meth->field_mul(x1, z1, &t2, group->meth));
+ MP_CHECKOK(group->meth->field_add(z1, x1, z1, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(z1, z1, group->meth));
+ MP_CHECKOK(group->meth->field_mul(z1, &t1, x1, group->meth));
+ MP_CHECKOK(group->meth->field_add(x1, &t2, x1, group->meth));
+
+ CLEANUP:
+ mp_clear(&t1);
+ mp_clear(&t2);
+ return res;
+}
+
+/* Compute the x, y affine coordinates from the point (x1, z1) (x2, z2)
+ * using Montgomery point multiplication algorithm Mxy() in appendix of
+ * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over
+ * GF(2^m) without precomputation". Returns: 0 on error 1 if return value
+ * should be the point at infinity 2 otherwise */
+static int
+gf2m_Mxy(const mp_int *x, const mp_int *y, mp_int *x1, mp_int *z1,
+ mp_int *x2, mp_int *z2, const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ int ret = 0;
+ mp_int t3, t4, t5;
+
+ MP_DIGITS(&t3) = 0;
+ MP_DIGITS(&t4) = 0;
+ MP_DIGITS(&t5) = 0;
+ MP_CHECKOK(mp_init(&t3, FLAG(x2)));
+ MP_CHECKOK(mp_init(&t4, FLAG(x2)));
+ MP_CHECKOK(mp_init(&t5, FLAG(x2)));
+
+ if (mp_cmp_z(z1) == 0) {
+ mp_zero(x2);
+ mp_zero(z2);
+ ret = 1;
+ goto CLEANUP;
+ }
+
+ if (mp_cmp_z(z2) == 0) {
+ MP_CHECKOK(mp_copy(x, x2));
+ MP_CHECKOK(group->meth->field_add(x, y, z2, group->meth));
+ ret = 2;
+ goto CLEANUP;
+ }
+
+ MP_CHECKOK(mp_set_int(&t5, 1));
+ if (group->meth->field_enc) {
+ MP_CHECKOK(group->meth->field_enc(&t5, &t5, group->meth));
+ }
+
+ MP_CHECKOK(group->meth->field_mul(z1, z2, &t3, group->meth));
+
+ MP_CHECKOK(group->meth->field_mul(z1, x, z1, group->meth));
+ MP_CHECKOK(group->meth->field_add(z1, x1, z1, group->meth));
+ MP_CHECKOK(group->meth->field_mul(z2, x, z2, group->meth));
+ MP_CHECKOK(group->meth->field_mul(z2, x1, x1, group->meth));
+ MP_CHECKOK(group->meth->field_add(z2, x2, z2, group->meth));
+
+ MP_CHECKOK(group->meth->field_mul(z2, z1, z2, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(x, &t4, group->meth));
+ MP_CHECKOK(group->meth->field_add(&t4, y, &t4, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&t4, &t3, &t4, group->meth));
+ MP_CHECKOK(group->meth->field_add(&t4, z2, &t4, group->meth));
+
+ MP_CHECKOK(group->meth->field_mul(&t3, x, &t3, group->meth));
+ MP_CHECKOK(group->meth->field_div(&t5, &t3, &t3, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&t3, &t4, &t4, group->meth));
+ MP_CHECKOK(group->meth->field_mul(x1, &t3, x2, group->meth));
+ MP_CHECKOK(group->meth->field_add(x2, x, z2, group->meth));
+
+ MP_CHECKOK(group->meth->field_mul(z2, &t4, z2, group->meth));
+ MP_CHECKOK(group->meth->field_add(z2, y, z2, group->meth));
+
+ ret = 2;
+
+ CLEANUP:
+ mp_clear(&t3);
+ mp_clear(&t4);
+ mp_clear(&t5);
+ if (res == MP_OKAY) {
+ return ret;
+ } else {
+ return 0;
+ }
+}
+
+/* Computes R = nP based on algorithm 2P of Lopex, J. and Dahab, R. "Fast
+ * multiplication on elliptic curves over GF(2^m) without
+ * precomputation". Elliptic curve points P and R can be identical. Uses
+ * Montgomery projective coordinates. The timing parameter is ignored
+ * because this algorithm resists timing attacks by default. */
+mp_err
+ec_GF2m_pt_mul_mont(const mp_int *n, const mp_int *px, const mp_int *py,
+ mp_int *rx, mp_int *ry, const ECGroup *group,
+ int timing)
+{
+ mp_err res = MP_OKAY;
+ mp_int x1, x2, z1, z2;
+ int i, j;
+ mp_digit top_bit, mask;
+
+ MP_DIGITS(&x1) = 0;
+ MP_DIGITS(&x2) = 0;
+ MP_DIGITS(&z1) = 0;
+ MP_DIGITS(&z2) = 0;
+ MP_CHECKOK(mp_init(&x1, FLAG(n)));
+ MP_CHECKOK(mp_init(&x2, FLAG(n)));
+ MP_CHECKOK(mp_init(&z1, FLAG(n)));
+ MP_CHECKOK(mp_init(&z2, FLAG(n)));
+
+ /* if result should be point at infinity */
+ if ((mp_cmp_z(n) == 0) || (ec_GF2m_pt_is_inf_aff(px, py) == MP_YES)) {
+ MP_CHECKOK(ec_GF2m_pt_set_inf_aff(rx, ry));
+ goto CLEANUP;
+ }
+
+ MP_CHECKOK(mp_copy(px, &x1)); /* x1 = px */
+ MP_CHECKOK(mp_set_int(&z1, 1)); /* z1 = 1 */
+ MP_CHECKOK(group->meth->field_sqr(&x1, &z2, group->meth)); /* z2 =
+ * x1^2 =
+ * px^2 */
+ MP_CHECKOK(group->meth->field_sqr(&z2, &x2, group->meth));
+ MP_CHECKOK(group->meth->field_add(&x2, &group->curveb, &x2, group->meth)); /* x2
+ * =
+ * px^4
+ * +
+ * b
+ */
+
+ /* find top-most bit and go one past it */
+ i = MP_USED(n) - 1;
+ j = MP_DIGIT_BIT - 1;
+ top_bit = 1;
+ top_bit <<= MP_DIGIT_BIT - 1;
+ mask = top_bit;
+ while (!(MP_DIGITS(n)[i] & mask)) {
+ mask >>= 1;
+ j--;
+ }
+ mask >>= 1;
+ j--;
+
+ /* if top most bit was at word break, go to next word */
+ if (!mask) {
+ i--;
+ j = MP_DIGIT_BIT - 1;
+ mask = top_bit;
+ }
+
+ for (; i >= 0; i--) {
+ for (; j >= 0; j--) {
+ if (MP_DIGITS(n)[i] & mask) {
+ MP_CHECKOK(gf2m_Madd(px, &x1, &z1, &x2, &z2, group, FLAG(n)));
+ MP_CHECKOK(gf2m_Mdouble(&x2, &z2, group, FLAG(n)));
+ } else {
+ MP_CHECKOK(gf2m_Madd(px, &x2, &z2, &x1, &z1, group, FLAG(n)));
+ MP_CHECKOK(gf2m_Mdouble(&x1, &z1, group, FLAG(n)));
+ }
+ mask >>= 1;
+ }
+ j = MP_DIGIT_BIT - 1;
+ mask = top_bit;
+ }
+
+ /* convert out of "projective" coordinates */
+ i = gf2m_Mxy(px, py, &x1, &z1, &x2, &z2, group);
+ if (i == 0) {
+ res = MP_BADARG;
+ goto CLEANUP;
+ } else if (i == 1) {
+ MP_CHECKOK(ec_GF2m_pt_set_inf_aff(rx, ry));
+ } else {
+ MP_CHECKOK(mp_copy(&x2, rx));
+ MP_CHECKOK(mp_copy(&z2, ry));
+ }
+
+ CLEANUP:
+ mp_clear(&x1);
+ mp_clear(&x2);
+ mp_clear(&z1);
+ mp_clear(&z2);
+ return res;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ec_naf.c b/jdk.crypto.ec/share/native/libsunec/impl/ec_naf.c
new file mode 100644
index 0000000..bb26a02
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ec_naf.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Stephen Fung <fungstep@hotmail.com>, Sun Microsystems Laboratories
+ *
+ *********************************************************************** */
+
+#include "ecl-priv.h"
+
+/* Returns 2^e as an integer. This is meant to be used for small powers of
+ * two. */
+int
+ec_twoTo(int e)
+{
+ int a = 1;
+ int i;
+
+ for (i = 0; i < e; i++) {
+ a *= 2;
+ }
+ return a;
+}
+
+/* Computes the windowed non-adjacent-form (NAF) of a scalar. Out should
+ * be an array of signed char's to output to, bitsize should be the number
+ * of bits of out, in is the original scalar, and w is the window size.
+ * NAF is discussed in the paper: D. Hankerson, J. Hernandez and A.
+ * Menezes, "Software implementation of elliptic curve cryptography over
+ * binary fields", Proc. CHES 2000. */
+mp_err
+ec_compute_wNAF(signed char *out, int bitsize, const mp_int *in, int w)
+{
+ mp_int k;
+ mp_err res = MP_OKAY;
+ int i, twowm1, mask;
+
+ twowm1 = ec_twoTo(w - 1);
+ mask = 2 * twowm1 - 1;
+
+ MP_DIGITS(&k) = 0;
+ MP_CHECKOK(mp_init_copy(&k, in));
+
+ i = 0;
+ /* Compute wNAF form */
+ while (mp_cmp_z(&k) > 0) {
+ if (mp_isodd(&k)) {
+ out[i] = MP_DIGIT(&k, 0) & mask;
+ if (out[i] >= twowm1)
+ out[i] -= 2 * twowm1;
+
+ /* Subtract off out[i]. Note mp_sub_d only works with
+ * unsigned digits */
+ if (out[i] >= 0) {
+ mp_sub_d(&k, out[i], &k);
+ } else {
+ mp_add_d(&k, -(out[i]), &k);
+ }
+ } else {
+ out[i] = 0;
+ }
+ mp_div_2(&k, &k);
+ i++;
+ }
+ /* Zero out the remaining elements of the out array. */
+ for (; i < bitsize + 1; i++) {
+ out[i] = 0;
+ }
+ CLEANUP:
+ mp_clear(&k);
+ return res;
+
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h b/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h
new file mode 100644
index 0000000..9d6b701
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecc_impl.h
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dr Vipul Gupta <vipul.gupta@sun.com> and
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * Last Modified Date from the Original Code: May 2017
+ *********************************************************************** */
+
+#ifndef _ECC_IMPL_H
+#define _ECC_IMPL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include "ecl-exp.h"
+
+/*
+ * Multi-platform definitions
+ */
+#ifdef __linux__
+#define B_FALSE FALSE
+#define B_TRUE TRUE
+typedef unsigned char uint8_t;
+typedef unsigned long ulong_t;
+typedef enum { B_FALSE, B_TRUE } boolean_t;
+#endif /* __linux__ */
+
+#ifdef _ALLBSD_SOURCE
+#include <stdint.h>
+#define B_FALSE FALSE
+#define B_TRUE TRUE
+typedef unsigned long ulong_t;
+typedef enum boolean { B_FALSE, B_TRUE } boolean_t;
+#endif /* _ALLBSD_SOURCE */
+
+#ifdef AIX
+#define B_FALSE FALSE
+#define B_TRUE TRUE
+typedef unsigned char uint8_t;
+typedef unsigned long ulong_t;
+#endif /* AIX */
+
+#ifdef _WIN32
+typedef unsigned char uint8_t;
+typedef unsigned long ulong_t;
+typedef enum boolean { B_FALSE, B_TRUE } boolean_t;
+#define strdup _strdup /* Replace POSIX name with ISO C++ name */
+#endif /* _WIN32 */
+
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif /* _KERNEL */
+
+#define EC_MAX_DIGEST_LEN 1024 /* max digest that can be signed */
+#define EC_MAX_POINT_LEN 145 /* max len of DER encoded Q */
+#define EC_MAX_VALUE_LEN 72 /* max len of ANSI X9.62 private value d */
+#define EC_MAX_SIG_LEN 144 /* max signature len for supported curves */
+#define EC_MIN_KEY_LEN 112 /* min key length in bits */
+#define EC_MAX_KEY_LEN 571 /* max key length in bits */
+#define EC_MAX_OID_LEN 10 /* max length of OID buffer */
+
+/*
+ * Various structures and definitions from NSS are here.
+ */
+
+#ifdef _KERNEL
+#define PORT_ArenaAlloc(a, n, f) kmem_alloc((n), (f))
+#define PORT_ArenaZAlloc(a, n, f) kmem_zalloc((n), (f))
+#define PORT_ArenaGrow(a, b, c, d) NULL
+#define PORT_ZAlloc(n, f) kmem_zalloc((n), (f))
+#define PORT_Alloc(n, f) kmem_alloc((n), (f))
+#else
+#define PORT_ArenaAlloc(a, n, f) malloc((n))
+#define PORT_ArenaZAlloc(a, n, f) calloc(1, (n))
+#define PORT_ArenaGrow(a, b, c, d) NULL
+#define PORT_ZAlloc(n, f) calloc(1, (n))
+#define PORT_Alloc(n, f) malloc((n))
+#endif
+
+#define PORT_NewArena(b) (char *)12345
+#define PORT_ArenaMark(a) NULL
+#define PORT_ArenaUnmark(a, b)
+#define PORT_ArenaRelease(a, m)
+#define PORT_FreeArena(a, b)
+#define PORT_Strlen(s) strlen((s))
+#define PORT_SetError(e)
+
+#define PRBool boolean_t
+#define PR_TRUE B_TRUE
+#define PR_FALSE B_FALSE
+
+#ifdef _KERNEL
+#define PORT_Assert ASSERT
+#define PORT_Memcpy(t, f, l) bcopy((f), (t), (l))
+#else
+#define PORT_Assert assert
+#define PORT_Memcpy(t, f, l) memcpy((t), (f), (l))
+#endif
+
+#define CHECK_OK(func) if (func == NULL) goto cleanup
+#define CHECK_SEC_OK(func) if (SECSuccess != (rv = func)) goto cleanup
+
+typedef enum {
+ siBuffer = 0,
+ siClearDataBuffer = 1,
+ siCipherDataBuffer = 2,
+ siDERCertBuffer = 3,
+ siEncodedCertBuffer = 4,
+ siDERNameBuffer = 5,
+ siEncodedNameBuffer = 6,
+ siAsciiNameString = 7,
+ siAsciiString = 8,
+ siDEROID = 9,
+ siUnsignedInteger = 10,
+ siUTCTime = 11,
+ siGeneralizedTime = 12
+} SECItemType;
+
+typedef struct SECItemStr SECItem;
+
+struct SECItemStr {
+ SECItemType type;
+ unsigned char *data;
+ unsigned int len;
+};
+
+typedef SECItem SECKEYECParams;
+
+typedef enum { ec_params_explicit,
+ ec_params_named
+} ECParamsType;
+
+typedef enum { ec_field_GFp = 1,
+ ec_field_GF2m
+} ECFieldType;
+
+struct ECFieldIDStr {
+ int size; /* field size in bits */
+ ECFieldType type;
+ union {
+ SECItem prime; /* prime p for (GFp) */
+ SECItem poly; /* irreducible binary polynomial for (GF2m) */
+ } u;
+ int k1; /* first coefficient of pentanomial or
+ * the only coefficient of trinomial
+ */
+ int k2; /* two remaining coefficients of pentanomial */
+ int k3;
+};
+typedef struct ECFieldIDStr ECFieldID;
+
+struct ECCurveStr {
+ SECItem a; /* contains octet stream encoding of
+ * field element (X9.62 section 4.3.3)
+ */
+ SECItem b;
+ SECItem seed;
+};
+typedef struct ECCurveStr ECCurve;
+
+typedef void PRArenaPool;
+
+struct ECParamsStr {
+ PRArenaPool * arena;
+ ECParamsType type;
+ ECFieldID fieldID;
+ ECCurve curve;
+ SECItem base;
+ SECItem order;
+ int cofactor;
+ SECItem DEREncoding;
+ ECCurveName name;
+ SECItem curveOID;
+};
+typedef struct ECParamsStr ECParams;
+
+struct ECPublicKeyStr {
+ ECParams ecParams;
+ SECItem publicValue; /* elliptic curve point encoded as
+ * octet stream.
+ */
+};
+typedef struct ECPublicKeyStr ECPublicKey;
+
+struct ECPrivateKeyStr {
+ ECParams ecParams;
+ SECItem publicValue; /* encoded ec point */
+ SECItem privateValue; /* private big integer */
+ SECItem version; /* As per SEC 1, Appendix C, Section C.4 */
+};
+typedef struct ECPrivateKeyStr ECPrivateKey;
+
+typedef enum _SECStatus {
+ SECBufferTooSmall = -3,
+ SECWouldBlock = -2,
+ SECFailure = -1,
+ SECSuccess = 0
+} SECStatus;
+
+#ifdef _KERNEL
+#define RNG_GenerateGlobalRandomBytes(p,l) ecc_knzero_random_generator((p), (l))
+#else
+/*
+ This function is no longer required because the random bytes are now
+ supplied by the caller. Force a failure.
+*/
+#define RNG_GenerateGlobalRandomBytes(p,l) SECFailure
+#endif
+#define CHECK_MPI_OK(func) if (MP_OKAY > (err = func)) goto cleanup
+#define MP_TO_SEC_ERROR(err)
+
+#define SECITEM_TO_MPINT(it, mp) \
+ CHECK_MPI_OK(mp_read_unsigned_octets((mp), (it).data, (it).len))
+
+extern int ecc_knzero_random_generator(uint8_t *, size_t);
+extern ulong_t soft_nzero_random_generator(uint8_t *, ulong_t);
+
+extern SECStatus EC_DecodeParams(const SECItem *, ECParams **, int);
+extern SECItem * SECITEM_AllocItem(PRArenaPool *, SECItem *, unsigned int, int);
+extern SECStatus SECITEM_CopyItem(PRArenaPool *, SECItem *, const SECItem *,
+ int);
+extern void SECITEM_FreeItem(SECItem *, boolean_t);
+/* This function has been modified to accept an array of random bytes */
+extern SECStatus EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey,
+ const unsigned char* random, int randomlen, int);
+extern SECStatus EC_ValidatePublicKey(ECParams *, SECItem *, int);
+/* This function has been modified to accept an array of random bytes */
+extern SECStatus ECDSA_SignDigest(ECPrivateKey *, SECItem *, const SECItem *,
+ const unsigned char* random, int randomlen, int, int timing);
+extern SECStatus ECDSA_VerifyDigest(ECPublicKey *, const SECItem *,
+ const SECItem *, int);
+extern SECStatus ECDH_Derive(SECItem *, ECParams *, SECItem *, boolean_t,
+ SECItem *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ECC_IMPL_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecdecode.c b/jdk.crypto.ec/share/native/libsunec/impl/ecdecode.c
new file mode 100644
index 0000000..acc10d9
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecdecode.c
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the Elliptic Curve Cryptography library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dr Vipul Gupta <vipul.gupta@sun.com> and
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * Last Modified Date from the Original Code: Nov 2016
+ *********************************************************************** */
+
+#include <sys/types.h>
+
+#ifndef _WIN32
+#if !defined(__linux__) && !defined(_ALLBSD_SOURCE)
+#include <sys/systm.h>
+#endif /* __linux__ || _ALLBSD_SOURCE */
+#include <sys/param.h>
+#endif /* _WIN32 */
+
+#ifdef _KERNEL
+#include <sys/kmem.h>
+#else
+#include <string.h>
+#endif
+#include "ec.h"
+#include "ecl-curve.h"
+#include "ecc_impl.h"
+
+#define MAX_ECKEY_LEN 72
+#define SEC_ASN1_OBJECT_ID 0x06
+
+/*
+ * Initializes a SECItem from a hexadecimal string
+ *
+ * Warning: This function ignores leading 00's, so any leading 00's
+ * in the hexadecimal string must be optional.
+ */
+static SECItem *
+hexString2SECItem(PRArenaPool *arena, SECItem *item, const char *str,
+ int kmflag)
+{
+ int i = 0;
+ int byteval = 0;
+ int tmp = (int)strlen(str);
+
+ if ((tmp % 2) != 0) return NULL;
+
+ /* skip leading 00's unless the hex string is "00" */
+ while ((tmp > 2) && (str[0] == '0') && (str[1] == '0')) {
+ str += 2;
+ tmp -= 2;
+ }
+
+ item->data = (unsigned char *) PORT_ArenaAlloc(arena, tmp/2, kmflag);
+ if (item->data == NULL) return NULL;
+ item->len = tmp/2;
+
+ while (str[i]) {
+ if ((str[i] >= '0') && (str[i] <= '9'))
+ tmp = str[i] - '0';
+ else if ((str[i] >= 'a') && (str[i] <= 'f'))
+ tmp = str[i] - 'a' + 10;
+ else if ((str[i] >= 'A') && (str[i] <= 'F'))
+ tmp = str[i] - 'A' + 10;
+ else
+ return NULL;
+
+ byteval = byteval * 16 + tmp;
+ if ((i % 2) != 0) {
+ item->data[i/2] = byteval;
+ byteval = 0;
+ }
+ i++;
+ }
+
+ return item;
+}
+
+static SECStatus
+gf_populate_params(ECCurveName name, ECFieldType field_type, ECParams *params,
+ int kmflag)
+{
+ SECStatus rv = SECFailure;
+ const ECCurveParams *curveParams;
+ /* 2 ['0'+'4'] + MAX_ECKEY_LEN * 2 [x,y] * 2 [hex string] + 1 ['\0'] */
+ char genenc[3 + 2 * 2 * MAX_ECKEY_LEN];
+
+ if (((int)name < ECCurve_noName) || (name > ECCurve_pastLastCurve))
+ goto cleanup;
+ params->name = name;
+ curveParams = ecCurve_map[params->name];
+ CHECK_OK(curveParams);
+ if ((strlen(curveParams->genx) + strlen(curveParams->geny)) > 2 * 2 * MAX_ECKEY_LEN) {
+ goto cleanup;
+ }
+ params->fieldID.size = curveParams->size;
+ params->fieldID.type = field_type;
+ if (field_type == ec_field_GFp) {
+ CHECK_OK(hexString2SECItem(NULL, ¶ms->fieldID.u.prime,
+ curveParams->irr, kmflag));
+ } else {
+ CHECK_OK(hexString2SECItem(NULL, ¶ms->fieldID.u.poly,
+ curveParams->irr, kmflag));
+ }
+ CHECK_OK(hexString2SECItem(NULL, ¶ms->curve.a,
+ curveParams->curvea, kmflag));
+ CHECK_OK(hexString2SECItem(NULL, ¶ms->curve.b,
+ curveParams->curveb, kmflag));
+ genenc[0] = '0';
+ genenc[1] = '4';
+ genenc[2] = '\0';
+ strcat(genenc, curveParams->genx);
+ strcat(genenc, curveParams->geny);
+ CHECK_OK(hexString2SECItem(NULL, ¶ms->base, genenc, kmflag));
+ CHECK_OK(hexString2SECItem(NULL, ¶ms->order,
+ curveParams->order, kmflag));
+ params->cofactor = curveParams->cofactor;
+
+ rv = SECSuccess;
+
+cleanup:
+ return rv;
+}
+
+ECCurveName SECOID_FindOIDTag(const SECItem *);
+
+SECStatus
+EC_FillParams(PRArenaPool *arena, const SECItem *encodedParams,
+ ECParams *params, int kmflag)
+{
+ SECStatus rv = SECFailure;
+ ECCurveName tag;
+ SECItem oid = { siBuffer, NULL, 0};
+
+#if EC_DEBUG
+ int i;
+
+ printf("Encoded params in EC_DecodeParams: ");
+ for (i = 0; i < encodedParams->len; i++) {
+ printf("%02x:", encodedParams->data[i]);
+ }
+ printf("\n");
+#endif
+
+ if ((encodedParams->len != ANSI_X962_CURVE_OID_TOTAL_LEN) &&
+ (encodedParams->len != SECG_CURVE_OID_TOTAL_LEN) &&
+ (encodedParams->len != BRAINPOOL_CURVE_OID_TOTAL_LEN)) {
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+ return SECFailure;
+ };
+
+ oid.len = encodedParams->len - 2;
+ oid.data = encodedParams->data + 2;
+ if ((encodedParams->data[0] != SEC_ASN1_OBJECT_ID) ||
+ ((tag = SECOID_FindOIDTag(&oid)) == ECCurve_noName)) {
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+ return SECFailure;
+ }
+
+ params->arena = arena;
+ params->cofactor = 0;
+ params->type = ec_params_named;
+ params->name = ECCurve_noName;
+
+ /* For named curves, fill out curveOID */
+ params->curveOID.len = oid.len;
+ params->curveOID.data = (unsigned char *) PORT_ArenaAlloc(NULL, oid.len,
+ kmflag);
+ if (params->curveOID.data == NULL) goto cleanup;
+ memcpy(params->curveOID.data, oid.data, oid.len);
+
+#if EC_DEBUG
+#ifndef SECOID_FindOIDTagDescription
+ printf("Curve: %s\n", ecCurve_map[tag]->text);
+#else
+ printf("Curve: %s\n", SECOID_FindOIDTagDescription(tag));
+#endif
+#endif
+
+ switch (tag) {
+
+ /* Binary curves */
+
+ case ECCurve_X9_62_CHAR2_PNB163V1:
+ /* Populate params for c2pnb163v1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB163V1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_PNB163V2:
+ /* Populate params for c2pnb163v2 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB163V2, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_PNB163V3:
+ /* Populate params for c2pnb163v3 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB163V3, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_PNB176V1:
+ /* Populate params for c2pnb176v1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB176V1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_TNB191V1:
+ /* Populate params for c2tnb191v1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB191V1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_TNB191V2:
+ /* Populate params for c2tnb191v2 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB191V2, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_TNB191V3:
+ /* Populate params for c2tnb191v3 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB191V3, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_PNB208W1:
+ /* Populate params for c2pnb208w1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB208W1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_TNB239V1:
+ /* Populate params for c2tnb239v1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB239V1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_TNB239V2:
+ /* Populate params for c2tnb239v2 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB239V2, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_TNB239V3:
+ /* Populate params for c2tnb239v3 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB239V3, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_PNB272W1:
+ /* Populate params for c2pnb272w1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB272W1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_PNB304W1:
+ /* Populate params for c2pnb304w1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB304W1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_TNB359V1:
+ /* Populate params for c2tnb359v1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB359V1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_PNB368W1:
+ /* Populate params for c2pnb368w1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_PNB368W1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_CHAR2_TNB431R1:
+ /* Populate params for c2tnb431r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_CHAR2_TNB431R1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_113R1:
+ /* Populate params for sect113r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_113R1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_113R2:
+ /* Populate params for sect113r2 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_113R2, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_131R1:
+ /* Populate params for sect131r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_131R1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_131R2:
+ /* Populate params for sect131r2 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_131R2, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_163K1:
+ /* Populate params for sect163k1
+ * (the NIST K-163 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_163K1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_163R1:
+ /* Populate params for sect163r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_163R1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_163R2:
+ /* Populate params for sect163r2
+ * (the NIST B-163 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_163R2, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_193R1:
+ /* Populate params for sect193r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_193R1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_193R2:
+ /* Populate params for sect193r2 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_193R2, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_233K1:
+ /* Populate params for sect233k1
+ * (the NIST K-233 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_233K1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_233R1:
+ /* Populate params for sect233r1
+ * (the NIST B-233 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_233R1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_239K1:
+ /* Populate params for sect239k1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_239K1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_283K1:
+ /* Populate params for sect283k1
+ * (the NIST K-283 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_283K1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_283R1:
+ /* Populate params for sect283r1
+ * (the NIST B-283 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_283R1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_409K1:
+ /* Populate params for sect409k1
+ * (the NIST K-409 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_409K1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_409R1:
+ /* Populate params for sect409r1
+ * (the NIST B-409 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_409R1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_571K1:
+ /* Populate params for sect571k1
+ * (the NIST K-571 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_571K1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_CHAR2_571R1:
+ /* Populate params for sect571r1
+ * (the NIST B-571 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_CHAR2_571R1, ec_field_GF2m,
+ params, kmflag) );
+ break;
+
+ /* Prime curves */
+
+ case ECCurve_X9_62_PRIME_192V1:
+ /* Populate params for prime192v1 aka secp192r1
+ * (the NIST P-192 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_192V1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_PRIME_192V2:
+ /* Populate params for prime192v2 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_192V2, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_PRIME_192V3:
+ /* Populate params for prime192v3 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_192V3, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_PRIME_239V1:
+ /* Populate params for prime239v1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_239V1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_PRIME_239V2:
+ /* Populate params for prime239v2 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_239V2, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_PRIME_239V3:
+ /* Populate params for prime239v3 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_239V3, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_X9_62_PRIME_256V1:
+ /* Populate params for prime256v1 aka secp256r1
+ * (the NIST P-256 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_X9_62_PRIME_256V1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_112R1:
+ /* Populate params for secp112r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_112R1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_112R2:
+ /* Populate params for secp112r2 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_112R2, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_128R1:
+ /* Populate params for secp128r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_128R1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_128R2:
+ /* Populate params for secp128r2 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_128R2, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_160K1:
+ /* Populate params for secp160k1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_160K1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_160R1:
+ /* Populate params for secp160r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_160R1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_160R2:
+ /* Populate params for secp160r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_160R2, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_192K1:
+ /* Populate params for secp192k1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_192K1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_224K1:
+ /* Populate params for secp224k1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_224K1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_224R1:
+ /* Populate params for secp224r1
+ * (the NIST P-224 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_224R1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_256K1:
+ /* Populate params for secp256k1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_256K1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_384R1:
+ /* Populate params for secp384r1
+ * (the NIST P-384 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_384R1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_SECG_PRIME_521R1:
+ /* Populate params for secp521r1
+ * (the NIST P-521 curve)
+ */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_SECG_PRIME_521R1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_BrainpoolP256r1:
+ /* Populate params for brainpoolP256r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_BrainpoolP256r1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_BrainpoolP320r1:
+ /* Populate params for brainpoolP320r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_BrainpoolP320r1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_BrainpoolP384r1:
+ /* Populate params for brainpoolP384r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_BrainpoolP384r1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ case ECCurve_BrainpoolP512r1:
+ /* Populate params for brainpoolP512r1 */
+ CHECK_SEC_OK( gf_populate_params(ECCurve_BrainpoolP512r1, ec_field_GFp,
+ params, kmflag) );
+ break;
+
+ default:
+ break;
+ };
+
+cleanup:
+ if (!params->cofactor) {
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+#if EC_DEBUG
+ printf("Unrecognized curve, returning NULL params\n");
+#endif
+ }
+
+ return rv;
+}
+
+SECStatus
+EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams, int kmflag)
+{
+ PRArenaPool *arena;
+ ECParams *params;
+ SECStatus rv = SECFailure;
+
+ /* Initialize an arena for the ECParams structure */
+ if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
+ return SECFailure;
+
+ params = (ECParams *)PORT_ArenaZAlloc(NULL, sizeof(ECParams), kmflag);
+ if (!params) {
+ PORT_FreeArena(NULL, B_TRUE);
+ return SECFailure;
+ }
+
+ /* Copy the encoded params */
+ SECITEM_AllocItem(arena, &(params->DEREncoding), encodedParams->len,
+ kmflag);
+ memcpy(params->DEREncoding.data, encodedParams->data, encodedParams->len);
+
+ /* Fill out the rest of the ECParams structure based on
+ * the encoded params
+ */
+ rv = EC_FillParams(NULL, encodedParams, params, kmflag);
+ if (rv == SECFailure) {
+ PORT_FreeArena(NULL, B_TRUE);
+ return SECFailure;
+ } else {
+ *ecparams = params;;
+ return SECSuccess;
+ }
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecl-curve.h b/jdk.crypto.ec/share/native/libsunec/impl/ecl-curve.h
new file mode 100644
index 0000000..aaa75e5
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecl-curve.h
@@ -0,0 +1,733 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ *********************************************************************** */
+
+#ifndef _ECL_CURVE_H
+#define _ECL_CURVE_H
+
+#include "ecl-exp.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+/* NIST prime curves */
+static const ECCurveParams ecCurve_NIST_P192 = {
+ "NIST-P192", ECField_GFp, 192,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",
+ "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1",
+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
+ "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
+ "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", 1
+};
+
+static const ECCurveParams ecCurve_NIST_P224 = {
+ "NIST-P224", ECField_GFp, 224,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE",
+ "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",
+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",
+ "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", 1
+};
+
+static const ECCurveParams ecCurve_NIST_P256 = {
+ "NIST-P256", ECField_GFp, 256,
+ "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
+ "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
+ "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
+ "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
+ "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 1
+};
+
+static const ECCurveParams ecCurve_NIST_P384 = {
+ "NIST-P384", ECField_GFp, 384,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
+ "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
+ "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
+ 1
+};
+
+static const ECCurveParams ecCurve_NIST_P521 = {
+ "NIST-P521", ECField_GFp, 521,
+ "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+ "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
+ "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
+ "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
+ "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
+ 1
+};
+
+/* NIST binary curves */
+static const ECCurveParams ecCurve_NIST_K163 = {
+ "NIST-K163", ECField_GF2m, 163,
+ "0800000000000000000000000000000000000000C9",
+ "000000000000000000000000000000000000000001",
+ "000000000000000000000000000000000000000001",
+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8",
+ "0289070FB05D38FF58321F2E800536D538CCDAA3D9",
+ "04000000000000000000020108A2E0CC0D99F8A5EF", 2
+};
+
+static const ECCurveParams ecCurve_NIST_B163 = {
+ "NIST-B163", ECField_GF2m, 163,
+ "0800000000000000000000000000000000000000C9",
+ "000000000000000000000000000000000000000001",
+ "020A601907B8C953CA1481EB10512F78744A3205FD",
+ "03F0EBA16286A2D57EA0991168D4994637E8343E36",
+ "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1",
+ "040000000000000000000292FE77E70C12A4234C33", 2
+};
+
+static const ECCurveParams ecCurve_NIST_K233 = {
+ "NIST-K233", ECField_GF2m, 233,
+ "020000000000000000000000000000000000000004000000000000000001",
+ "000000000000000000000000000000000000000000000000000000000000",
+ "000000000000000000000000000000000000000000000000000000000001",
+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126",
+ "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3",
+ "008000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF", 4
+};
+
+static const ECCurveParams ecCurve_NIST_B233 = {
+ "NIST-B233", ECField_GF2m, 233,
+ "020000000000000000000000000000000000000004000000000000000001",
+ "000000000000000000000000000000000000000000000000000000000001",
+ "0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD",
+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B",
+ "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052",
+ "01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7", 2
+};
+
+static const ECCurveParams ecCurve_NIST_K283 = {
+ "NIST-K283", ECField_GF2m, 283,
+ "0800000000000000000000000000000000000000000000000000000000000000000010A1",
+ "000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000000000000000000000000000000000000000000000000000000000000000000001",
+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836",
+ "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259",
+ "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61", 4
+};
+
+static const ECCurveParams ecCurve_NIST_B283 = {
+ "NIST-B283", ECField_GF2m, 283,
+ "0800000000000000000000000000000000000000000000000000000000000000000010A1",
+ "000000000000000000000000000000000000000000000000000000000000000000000001",
+ "027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5",
+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053",
+ "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4",
+ "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307", 2
+};
+
+static const ECCurveParams ecCurve_NIST_K409 = {
+ "NIST-K409", ECField_GF2m, 409,
+ "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001",
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746",
+ "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B",
+ "007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF", 4
+};
+
+static const ECCurveParams ecCurve_NIST_B409 = {
+ "NIST-B409", ECField_GF2m, 409,
+ "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001",
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
+ "0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F",
+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7",
+ "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706",
+ "010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173", 2
+};
+
+static const ECCurveParams ecCurve_NIST_K571 = {
+ "NIST-K571", ECField_GF2m, 571,
+ "080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425",
+ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972",
+ "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3",
+ "020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001", 4
+};
+
+static const ECCurveParams ecCurve_NIST_B571 = {
+ "NIST-B571", ECField_GF2m, 571,
+ "080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425",
+ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
+ "02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A",
+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19",
+ "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B",
+ "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47", 2
+};
+
+/* ANSI X9.62 prime curves */
+static const ECCurveParams ecCurve_X9_62_PRIME_192V2 = {
+ "X9.62 P-192V2", ECField_GFp, 192,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",
+ "CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953",
+ "EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A",
+ "6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15",
+ "FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31", 1
+};
+
+static const ECCurveParams ecCurve_X9_62_PRIME_192V3 = {
+ "X9.62 P-192V3", ECField_GFp, 192,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",
+ "22123DC2395A05CAA7423DAECCC94760A7D462256BD56916",
+ "7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896",
+ "38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0",
+ "FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13", 1
+};
+
+static const ECCurveParams ecCurve_X9_62_PRIME_239V1 = {
+ "X9.62 P-239V1", ECField_GFp, 239,
+ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF",
+ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC",
+ "6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A",
+ "0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF",
+ "7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE",
+ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B", 1
+};
+
+static const ECCurveParams ecCurve_X9_62_PRIME_239V2 = {
+ "X9.62 P-239V2", ECField_GFp, 239,
+ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF",
+ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC",
+ "617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C",
+ "38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7",
+ "5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA",
+ "7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063", 1
+};
+
+static const ECCurveParams ecCurve_X9_62_PRIME_239V3 = {
+ "X9.62 P-239V3", ECField_GFp, 239,
+ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF",
+ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC",
+ "255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E",
+ "6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A",
+ "1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3",
+ "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551", 1
+};
+
+/* ANSI X9.62 binary curves */
+static const ECCurveParams ecCurve_X9_62_CHAR2_PNB163V1 = {
+ "X9.62 C2-PNB163V1", ECField_GF2m, 163,
+ "080000000000000000000000000000000000000107",
+ "072546B5435234A422E0789675F432C89435DE5242",
+ "00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9",
+ "07AF69989546103D79329FCC3D74880F33BBE803CB",
+ "01EC23211B5966ADEA1D3F87F7EA5848AEF0B7CA9F",
+ "0400000000000000000001E60FC8821CC74DAEAFC1", 2
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_PNB163V2 = {
+ "X9.62 C2-PNB163V2", ECField_GF2m, 163,
+ "080000000000000000000000000000000000000107",
+ "0108B39E77C4B108BED981ED0E890E117C511CF072",
+ "0667ACEB38AF4E488C407433FFAE4F1C811638DF20",
+ "0024266E4EB5106D0A964D92C4860E2671DB9B6CC5",
+ "079F684DDF6684C5CD258B3890021B2386DFD19FC5",
+ "03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 2
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_PNB163V3 = {
+ "X9.62 C2-PNB163V3", ECField_GF2m, 163,
+ "080000000000000000000000000000000000000107",
+ "07A526C63D3E25A256A007699F5447E32AE456B50E",
+ "03F7061798EB99E238FD6F1BF95B48FEEB4854252B",
+ "02F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB",
+ "05B935590C155E17EA48EB3FF3718B893DF59A05D0",
+ "03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 2
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_PNB176V1 = {
+ "X9.62 C2-PNB176V1", ECField_GF2m, 176,
+ "0100000000000000000000000000000000080000000007",
+ "E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B",
+ "5DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2",
+ "8D16C2866798B600F9F08BB4A8E860F3298CE04A5798",
+ "6FA4539C2DADDDD6BAB5167D61B436E1D92BB16A562C",
+ "00010092537397ECA4F6145799D62B0A19CE06FE26AD", 0xFF6E
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_TNB191V1 = {
+ "X9.62 C2-TNB191V1", ECField_GF2m, 191,
+ "800000000000000000000000000000000000000000000201",
+ "2866537B676752636A68F56554E12640276B649EF7526267",
+ "2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC",
+ "36B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D",
+ "765BE73433B3F95E332932E70EA245CA2418EA0EF98018FB",
+ "40000000000000000000000004A20E90C39067C893BBB9A5", 2
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_TNB191V2 = {
+ "X9.62 C2-TNB191V2", ECField_GF2m, 191,
+ "800000000000000000000000000000000000000000000201",
+ "401028774D7777C7B7666D1366EA432071274F89FF01E718",
+ "0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01",
+ "3809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10",
+ "17434386626D14F3DBF01760D9213A3E1CF37AEC437D668A",
+ "20000000000000000000000050508CB89F652824E06B8173", 4
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_TNB191V3 = {
+ "X9.62 C2-TNB191V3", ECField_GF2m, 191,
+ "800000000000000000000000000000000000000000000201",
+ "6C01074756099122221056911C77D77E77A777E7E7E77FCB",
+ "71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8",
+ "375D4CE24FDE434489DE8746E71786015009E66E38A926DD",
+ "545A39176196575D985999366E6AD34CE0A77CD7127B06BE",
+ "155555555555555555555555610C0B196812BFB6288A3EA3", 6
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_PNB208W1 = {
+ "X9.62 C2-PNB208W1", ECField_GF2m, 208,
+ "010000000000000000000000000000000800000000000000000007",
+ "0000000000000000000000000000000000000000000000000000",
+ "C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E",
+ "89FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A",
+ "0F55B51A06E78E9AC38A035FF520D8B01781BEB1A6BB08617DE3",
+ "000101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 0xFE48
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_TNB239V1 = {
+ "X9.62 C2-TNB239V1", ECField_GF2m, 239,
+ "800000000000000000000000000000000000000000000000001000000001",
+ "32010857077C5431123A46B808906756F543423E8D27877578125778AC76",
+ "790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16",
+ "57927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D",
+ "61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305",
+ "2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 4
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_TNB239V2 = {
+ "X9.62 C2-TNB239V2", ECField_GF2m, 239,
+ "800000000000000000000000000000000000000000000000001000000001",
+ "4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F",
+ "5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B",
+ "28F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205",
+ "5667334C45AFF3B5A03BAD9DD75E2C71A99362567D5453F7FA6E227EC833",
+ "1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 6
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_TNB239V3 = {
+ "X9.62 C2-TNB239V3", ECField_GF2m, 239,
+ "800000000000000000000000000000000000000000000000001000000001",
+ "01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F",
+ "6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40",
+ "70F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92",
+ "2E5A0EAF6E5E1305B9004DCE5C0ED7FE59A35608F33837C816D80B79F461",
+ "0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 0xA
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_PNB272W1 = {
+ "X9.62 C2-PNB272W1", ECField_GF2m, 272,
+ "010000000000000000000000000000000000000000000000000000010000000000000B",
+ "91A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20",
+ "7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7",
+ "6108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D",
+ "10C7695716851EEF6BA7F6872E6142FBD241B830FF5EFCACECCAB05E02005DDE9D23",
+ "000100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521",
+ 0xFF06
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_PNB304W1 = {
+ "X9.62 C2-PNB304W1", ECField_GF2m, 304,
+ "010000000000000000000000000000000000000000000000000000000000000000000000000807",
+ "FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681",
+ "BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE",
+ "197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614",
+ "E19FBEB76E0DA171517ECF401B50289BF014103288527A9B416A105E80260B549FDC1B92C03B",
+ "000101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 0xFE2E
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_TNB359V1 = {
+ "X9.62 C2-TNB359V1", ECField_GF2m, 359,
+ "800000000000000000000000000000000000000000000000000000000000000000000000100000000000000001",
+ "5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557",
+ "2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988",
+ "3C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097",
+ "53D7E08529547048121E9C95F3791DD804963948F34FAE7BF44EA82365DC7868FE57E4AE2DE211305A407104BD",
+ "01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 0x4C
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_PNB368W1 = {
+ "X9.62 C2-PNB368W1", ECField_GF2m, 368,
+ "0100000000000000000000000000000000000000000000000000000000000000000000002000000000000000000007",
+ "E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D",
+ "FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A",
+ "1085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F",
+ "7B3EB1BDDCBA62D5D8B2059B525797FC73822C59059C623A45FF3843CEE8F87CD1855ADAA81E2A0750B80FDA2310",
+ "00010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 0xFF70
+};
+
+static const ECCurveParams ecCurve_X9_62_CHAR2_TNB431R1 = {
+ "X9.62 C2-TNB431R1", ECField_GF2m, 431,
+ "800000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000001",
+ "1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F",
+ "10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618",
+ "120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7",
+ "20D0AF8903A96F8D5FA2C255745D3C451B302C9346D9B7E485E7BCE41F6B591F3E8F6ADDCBB0BC4C2F947A7DE1A89B625D6A598B3760",
+ "0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 0x2760
+};
+
+/* SEC2 prime curves */
+static const ECCurveParams ecCurve_SECG_PRIME_112R1 = {
+ "SECP-112R1", ECField_GFp, 112,
+ "DB7C2ABF62E35E668076BEAD208B",
+ "DB7C2ABF62E35E668076BEAD2088",
+ "659EF8BA043916EEDE8911702B22",
+ "09487239995A5EE76B55F9C2F098",
+ "A89CE5AF8724C0A23E0E0FF77500",
+ "DB7C2ABF62E35E7628DFAC6561C5", 1
+};
+
+static const ECCurveParams ecCurve_SECG_PRIME_112R2 = {
+ "SECP-112R2", ECField_GFp, 112,
+ "DB7C2ABF62E35E668076BEAD208B",
+ "6127C24C05F38A0AAAF65C0EF02C",
+ "51DEF1815DB5ED74FCC34C85D709",
+ "4BA30AB5E892B4E1649DD0928643",
+ "adcd46f5882e3747def36e956e97",
+ "36DF0AAFD8B8D7597CA10520D04B", 4
+};
+
+static const ECCurveParams ecCurve_SECG_PRIME_128R1 = {
+ "SECP-128R1", ECField_GFp, 128,
+ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
+ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC",
+ "E87579C11079F43DD824993C2CEE5ED3",
+ "161FF7528B899B2D0C28607CA52C5B86",
+ "CF5AC8395BAFEB13C02DA292DDED7A83",
+ "FFFFFFFE0000000075A30D1B9038A115", 1
+};
+
+static const ECCurveParams ecCurve_SECG_PRIME_128R2 = {
+ "SECP-128R2", ECField_GFp, 128,
+ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
+ "D6031998D1B3BBFEBF59CC9BBFF9AEE1",
+ "5EEEFCA380D02919DC2C6558BB6D8A5D",
+ "7B6AA5D85E572983E6FB32A7CDEBC140",
+ "27B6916A894D3AEE7106FE805FC34B44",
+ "3FFFFFFF7FFFFFFFBE0024720613B5A3", 4
+};
+
+static const ECCurveParams ecCurve_SECG_PRIME_160K1 = {
+ "SECP-160K1", ECField_GFp, 160,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73",
+ "0000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000007",
+ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB",
+ "938CF935318FDCED6BC28286531733C3F03C4FEE",
+ "0100000000000000000001B8FA16DFAB9ACA16B6B3", 1
+};
+
+static const ECCurveParams ecCurve_SECG_PRIME_160R1 = {
+ "SECP-160R1", ECField_GFp, 160,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC",
+ "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
+ "4A96B5688EF573284664698968C38BB913CBFC82",
+ "23A628553168947D59DCC912042351377AC5FB32",
+ "0100000000000000000001F4C8F927AED3CA752257", 1
+};
+
+static const ECCurveParams ecCurve_SECG_PRIME_160R2 = {
+ "SECP-160R2", ECField_GFp, 160,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70",
+ "B4E134D3FB59EB8BAB57274904664D5AF50388BA",
+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D",
+ "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E",
+ "0100000000000000000000351EE786A818F3A1A16B", 1
+};
+
+static const ECCurveParams ecCurve_SECG_PRIME_192K1 = {
+ "SECP-192K1", ECField_GFp, 192,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37",
+ "000000000000000000000000000000000000000000000000",
+ "000000000000000000000000000000000000000000000003",
+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D",
+ "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D",
+ "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", 1
+};
+
+static const ECCurveParams ecCurve_SECG_PRIME_224K1 = {
+ "SECP-224K1", ECField_GFp, 224,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D",
+ "00000000000000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000000000000000000000000005",
+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C",
+ "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5",
+ "010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", 1
+};
+
+static const ECCurveParams ecCurve_SECG_PRIME_256K1 = {
+ "SECP-256K1", ECField_GFp, 256,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000007",
+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",
+ "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 1
+};
+
+/* SEC2 binary curves */
+static const ECCurveParams ecCurve_SECG_CHAR2_113R1 = {
+ "SECT-113R1", ECField_GF2m, 113,
+ "020000000000000000000000000201",
+ "003088250CA6E7C7FE649CE85820F7",
+ "00E8BEE4D3E2260744188BE0E9C723",
+ "009D73616F35F4AB1407D73562C10F",
+ "00A52830277958EE84D1315ED31886",
+ "0100000000000000D9CCEC8A39E56F", 2
+};
+
+static const ECCurveParams ecCurve_SECG_CHAR2_113R2 = {
+ "SECT-113R2", ECField_GF2m, 113,
+ "020000000000000000000000000201",
+ "00689918DBEC7E5A0DD6DFC0AA55C7",
+ "0095E9A9EC9B297BD4BF36E059184F",
+ "01A57A6A7B26CA5EF52FCDB8164797",
+ "00B3ADC94ED1FE674C06E695BABA1D",
+ "010000000000000108789B2496AF93", 2
+};
+
+static const ECCurveParams ecCurve_SECG_CHAR2_131R1 = {
+ "SECT-131R1", ECField_GF2m, 131,
+ "080000000000000000000000000000010D",
+ "07A11B09A76B562144418FF3FF8C2570B8",
+ "0217C05610884B63B9C6C7291678F9D341",
+ "0081BAF91FDF9833C40F9C181343638399",
+ "078C6E7EA38C001F73C8134B1B4EF9E150",
+ "0400000000000000023123953A9464B54D", 2
+};
+
+static const ECCurveParams ecCurve_SECG_CHAR2_131R2 = {
+ "SECT-131R2", ECField_GF2m, 131,
+ "080000000000000000000000000000010D",
+ "03E5A88919D7CAFCBF415F07C2176573B2",
+ "04B8266A46C55657AC734CE38F018F2192",
+ "0356DCD8F2F95031AD652D23951BB366A8",
+ "0648F06D867940A5366D9E265DE9EB240F",
+ "0400000000000000016954A233049BA98F", 2
+};
+
+static const ECCurveParams ecCurve_SECG_CHAR2_163R1 = {
+ "SECT-163R1", ECField_GF2m, 163,
+ "0800000000000000000000000000000000000000C9",
+ "07B6882CAAEFA84F9554FF8428BD88E246D2782AE2",
+ "0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9",
+ "0369979697AB43897789566789567F787A7876A654",
+ "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883",
+ "03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B", 2
+};
+
+static const ECCurveParams ecCurve_SECG_CHAR2_193R1 = {
+ "SECT-193R1", ECField_GF2m, 193,
+ "02000000000000000000000000000000000000000000008001",
+ "0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01",
+ "00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814",
+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1",
+ "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05",
+ "01000000000000000000000000C7F34A778F443ACC920EBA49", 2
+};
+
+static const ECCurveParams ecCurve_SECG_CHAR2_193R2 = {
+ "SECT-193R2", ECField_GF2m, 193,
+ "02000000000000000000000000000000000000000000008001",
+ "0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B",
+ "00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE",
+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F",
+ "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C",
+ "010000000000000000000000015AAB561B005413CCD4EE99D5", 2
+};
+
+static const ECCurveParams ecCurve_SECG_CHAR2_239K1 = {
+ "SECT-239K1", ECField_GF2m, 239,
+ "800000000000000000004000000000000000000000000000000000000001",
+ "000000000000000000000000000000000000000000000000000000000000",
+ "000000000000000000000000000000000000000000000000000000000001",
+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC",
+ "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA",
+ "2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5", 4
+};
+
+/* WTLS curves */
+static const ECCurveParams ecCurve_WTLS_1 = {
+ "WTLS-1", ECField_GF2m, 113,
+ "020000000000000000000000000201",
+ "000000000000000000000000000001",
+ "000000000000000000000000000001",
+ "01667979A40BA497E5D5C270780617",
+ "00F44B4AF1ECC2630E08785CEBCC15",
+ "00FFFFFFFFFFFFFFFDBF91AF6DEA73", 2
+};
+
+static const ECCurveParams ecCurve_WTLS_8 = {
+ "WTLS-8", ECField_GFp, 112,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFDE7",
+ "0000000000000000000000000000",
+ "0000000000000000000000000003",
+ "0000000000000000000000000001",
+ "0000000000000000000000000002",
+ "0100000000000001ECEA551AD837E9", 1
+};
+
+static const ECCurveParams ecCurve_WTLS_9 = {
+ "WTLS-9", ECField_GFp, 160,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC808F",
+ "0000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000003",
+ "0000000000000000000000000000000000000001",
+ "0000000000000000000000000000000000000002",
+ "0100000000000000000001CDC98AE0E2DE574ABF33", 1
+};
+
+static const ECCurveParams ecCurve_BrainpoolP256r1 = {
+ "brainpoolP256r1", ECField_GFp, 256,
+ "A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377",
+ "7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9",
+ "26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6",
+ "8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262",
+ "547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997",
+ "A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 1
+};
+
+static const ECCurveParams ecCurve_BrainpoolP320r1 = {
+ "brainpoolP320r1", ECField_GFp, 320,
+ "D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27",
+ "3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4",
+ "520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6",
+ "43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E20611",
+ "14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1",
+ "D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 1
+};
+
+static const ECCurveParams ecCurve_BrainpoolP384r1 = {
+ "brainpoolP384r1", ECField_GFp, 384,
+ "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53",
+ "7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826",
+ "04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11",
+ "1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E",
+ "8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315",
+ "8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 1
+};
+
+static const ECCurveParams ecCurve_BrainpoolP512r1 = {
+ "brainpoolP512r1", ECField_GFp, 512,
+ "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3",
+ "7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA",
+ "3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723",
+ "81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822",
+ "7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892",
+ "AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 1
+};
+
+/* mapping between ECCurveName enum and pointers to ECCurveParams */
+static const ECCurveParams *ecCurve_map[] = {
+ NULL, /* ECCurve_noName */
+ &ecCurve_NIST_P192, /* ECCurve_NIST_P192 */
+ &ecCurve_NIST_P224, /* ECCurve_NIST_P224 */
+ &ecCurve_NIST_P256, /* ECCurve_NIST_P256 */
+ &ecCurve_NIST_P384, /* ECCurve_NIST_P384 */
+ &ecCurve_NIST_P521, /* ECCurve_NIST_P521 */
+ &ecCurve_NIST_K163, /* ECCurve_NIST_K163 */
+ &ecCurve_NIST_B163, /* ECCurve_NIST_B163 */
+ &ecCurve_NIST_K233, /* ECCurve_NIST_K233 */
+ &ecCurve_NIST_B233, /* ECCurve_NIST_B233 */
+ &ecCurve_NIST_K283, /* ECCurve_NIST_K283 */
+ &ecCurve_NIST_B283, /* ECCurve_NIST_B283 */
+ &ecCurve_NIST_K409, /* ECCurve_NIST_K409 */
+ &ecCurve_NIST_B409, /* ECCurve_NIST_B409 */
+ &ecCurve_NIST_K571, /* ECCurve_NIST_K571 */
+ &ecCurve_NIST_B571, /* ECCurve_NIST_B571 */
+ &ecCurve_X9_62_PRIME_192V2, /* ECCurve_X9_62_PRIME_192V2 */
+ &ecCurve_X9_62_PRIME_192V3, /* ECCurve_X9_62_PRIME_192V3 */
+ &ecCurve_X9_62_PRIME_239V1, /* ECCurve_X9_62_PRIME_239V1 */
+ &ecCurve_X9_62_PRIME_239V2, /* ECCurve_X9_62_PRIME_239V2 */
+ &ecCurve_X9_62_PRIME_239V3, /* ECCurve_X9_62_PRIME_239V3 */
+ &ecCurve_X9_62_CHAR2_PNB163V1, /* ECCurve_X9_62_CHAR2_PNB163V1 */
+ &ecCurve_X9_62_CHAR2_PNB163V2, /* ECCurve_X9_62_CHAR2_PNB163V2 */
+ &ecCurve_X9_62_CHAR2_PNB163V3, /* ECCurve_X9_62_CHAR2_PNB163V3 */
+ &ecCurve_X9_62_CHAR2_PNB176V1, /* ECCurve_X9_62_CHAR2_PNB176V1 */
+ &ecCurve_X9_62_CHAR2_TNB191V1, /* ECCurve_X9_62_CHAR2_TNB191V1 */
+ &ecCurve_X9_62_CHAR2_TNB191V2, /* ECCurve_X9_62_CHAR2_TNB191V2 */
+ &ecCurve_X9_62_CHAR2_TNB191V3, /* ECCurve_X9_62_CHAR2_TNB191V3 */
+ &ecCurve_X9_62_CHAR2_PNB208W1, /* ECCurve_X9_62_CHAR2_PNB208W1 */
+ &ecCurve_X9_62_CHAR2_TNB239V1, /* ECCurve_X9_62_CHAR2_TNB239V1 */
+ &ecCurve_X9_62_CHAR2_TNB239V2, /* ECCurve_X9_62_CHAR2_TNB239V2 */
+ &ecCurve_X9_62_CHAR2_TNB239V3, /* ECCurve_X9_62_CHAR2_TNB239V3 */
+ &ecCurve_X9_62_CHAR2_PNB272W1, /* ECCurve_X9_62_CHAR2_PNB272W1 */
+ &ecCurve_X9_62_CHAR2_PNB304W1, /* ECCurve_X9_62_CHAR2_PNB304W1 */
+ &ecCurve_X9_62_CHAR2_TNB359V1, /* ECCurve_X9_62_CHAR2_TNB359V1 */
+ &ecCurve_X9_62_CHAR2_PNB368W1, /* ECCurve_X9_62_CHAR2_PNB368W1 */
+ &ecCurve_X9_62_CHAR2_TNB431R1, /* ECCurve_X9_62_CHAR2_TNB431R1 */
+ &ecCurve_SECG_PRIME_112R1, /* ECCurve_SECG_PRIME_112R1 */
+ &ecCurve_SECG_PRIME_112R2, /* ECCurve_SECG_PRIME_112R2 */
+ &ecCurve_SECG_PRIME_128R1, /* ECCurve_SECG_PRIME_128R1 */
+ &ecCurve_SECG_PRIME_128R2, /* ECCurve_SECG_PRIME_128R2 */
+ &ecCurve_SECG_PRIME_160K1, /* ECCurve_SECG_PRIME_160K1 */
+ &ecCurve_SECG_PRIME_160R1, /* ECCurve_SECG_PRIME_160R1 */
+ &ecCurve_SECG_PRIME_160R2, /* ECCurve_SECG_PRIME_160R2 */
+ &ecCurve_SECG_PRIME_192K1, /* ECCurve_SECG_PRIME_192K1 */
+ &ecCurve_SECG_PRIME_224K1, /* ECCurve_SECG_PRIME_224K1 */
+ &ecCurve_SECG_PRIME_256K1, /* ECCurve_SECG_PRIME_256K1 */
+ &ecCurve_SECG_CHAR2_113R1, /* ECCurve_SECG_CHAR2_113R1 */
+ &ecCurve_SECG_CHAR2_113R2, /* ECCurve_SECG_CHAR2_113R2 */
+ &ecCurve_SECG_CHAR2_131R1, /* ECCurve_SECG_CHAR2_131R1 */
+ &ecCurve_SECG_CHAR2_131R2, /* ECCurve_SECG_CHAR2_131R2 */
+ &ecCurve_SECG_CHAR2_163R1, /* ECCurve_SECG_CHAR2_163R1 */
+ &ecCurve_SECG_CHAR2_193R1, /* ECCurve_SECG_CHAR2_193R1 */
+ &ecCurve_SECG_CHAR2_193R2, /* ECCurve_SECG_CHAR2_193R2 */
+ &ecCurve_SECG_CHAR2_239K1, /* ECCurve_SECG_CHAR2_239K1 */
+ &ecCurve_WTLS_1, /* ECCurve_WTLS_1 */
+ &ecCurve_WTLS_8, /* ECCurve_WTLS_8 */
+ &ecCurve_WTLS_9, /* ECCurve_WTLS_9 */
+ &ecCurve_BrainpoolP256r1, /* ECCurve_BrainpoolP256r1 */
+ &ecCurve_BrainpoolP320r1, /* ECCurve_BrainpoolP320r1 */
+ &ecCurve_BrainpoolP384r1, /* ECCurve_brainpoolP384r1 */
+ &ecCurve_BrainpoolP512r1, /* ECCurve_brainpoolP512r1 */
+ NULL /* ECCurve_pastLastCurve */
+};
+
+#endif /* _ECL_CURVE_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecl-exp.h b/jdk.crypto.ec/share/native/libsunec/impl/ecl-exp.h
new file mode 100644
index 0000000..8b442c6
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecl-exp.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ *********************************************************************** */
+
+#ifndef _ECL_EXP_H
+#define _ECL_EXP_H
+
+/* Curve field type */
+typedef enum {
+ ECField_GFp,
+ ECField_GF2m
+} ECField;
+
+/* Hexadecimal encoding of curve parameters */
+struct ECCurveParamsStr {
+ char *text;
+ ECField field;
+ unsigned int size;
+ char *irr;
+ char *curvea;
+ char *curveb;
+ char *genx;
+ char *geny;
+ char *order;
+ int cofactor;
+};
+typedef struct ECCurveParamsStr ECCurveParams;
+
+/* Named curve parameters */
+typedef enum {
+
+ ECCurve_noName = 0,
+
+ /* NIST prime curves */
+ ECCurve_NIST_P192,
+ ECCurve_NIST_P224,
+ ECCurve_NIST_P256,
+ ECCurve_NIST_P384,
+ ECCurve_NIST_P521,
+
+ /* NIST binary curves */
+ ECCurve_NIST_K163,
+ ECCurve_NIST_B163,
+ ECCurve_NIST_K233,
+ ECCurve_NIST_B233,
+ ECCurve_NIST_K283,
+ ECCurve_NIST_B283,
+ ECCurve_NIST_K409,
+ ECCurve_NIST_B409,
+ ECCurve_NIST_K571,
+ ECCurve_NIST_B571,
+
+ /* ANSI X9.62 prime curves */
+ /* ECCurve_X9_62_PRIME_192V1 == ECCurve_NIST_P192 */
+ ECCurve_X9_62_PRIME_192V2,
+ ECCurve_X9_62_PRIME_192V3,
+ ECCurve_X9_62_PRIME_239V1,
+ ECCurve_X9_62_PRIME_239V2,
+ ECCurve_X9_62_PRIME_239V3,
+ /* ECCurve_X9_62_PRIME_256V1 == ECCurve_NIST_P256 */
+
+ /* ANSI X9.62 binary curves */
+ ECCurve_X9_62_CHAR2_PNB163V1,
+ ECCurve_X9_62_CHAR2_PNB163V2,
+ ECCurve_X9_62_CHAR2_PNB163V3,
+ ECCurve_X9_62_CHAR2_PNB176V1,
+ ECCurve_X9_62_CHAR2_TNB191V1,
+ ECCurve_X9_62_CHAR2_TNB191V2,
+ ECCurve_X9_62_CHAR2_TNB191V3,
+ ECCurve_X9_62_CHAR2_PNB208W1,
+ ECCurve_X9_62_CHAR2_TNB239V1,
+ ECCurve_X9_62_CHAR2_TNB239V2,
+ ECCurve_X9_62_CHAR2_TNB239V3,
+ ECCurve_X9_62_CHAR2_PNB272W1,
+ ECCurve_X9_62_CHAR2_PNB304W1,
+ ECCurve_X9_62_CHAR2_TNB359V1,
+ ECCurve_X9_62_CHAR2_PNB368W1,
+ ECCurve_X9_62_CHAR2_TNB431R1,
+
+ /* SEC2 prime curves */
+ ECCurve_SECG_PRIME_112R1,
+ ECCurve_SECG_PRIME_112R2,
+ ECCurve_SECG_PRIME_128R1,
+ ECCurve_SECG_PRIME_128R2,
+ ECCurve_SECG_PRIME_160K1,
+ ECCurve_SECG_PRIME_160R1,
+ ECCurve_SECG_PRIME_160R2,
+ ECCurve_SECG_PRIME_192K1,
+ /* ECCurve_SECG_PRIME_192R1 == ECCurve_NIST_P192 */
+ ECCurve_SECG_PRIME_224K1,
+ /* ECCurve_SECG_PRIME_224R1 == ECCurve_NIST_P224 */
+ ECCurve_SECG_PRIME_256K1,
+ /* ECCurve_SECG_PRIME_256R1 == ECCurve_NIST_P256 */
+ /* ECCurve_SECG_PRIME_384R1 == ECCurve_NIST_P384 */
+ /* ECCurve_SECG_PRIME_521R1 == ECCurve_NIST_P521 */
+
+ /* SEC2 binary curves */
+ ECCurve_SECG_CHAR2_113R1,
+ ECCurve_SECG_CHAR2_113R2,
+ ECCurve_SECG_CHAR2_131R1,
+ ECCurve_SECG_CHAR2_131R2,
+ /* ECCurve_SECG_CHAR2_163K1 == ECCurve_NIST_K163 */
+ ECCurve_SECG_CHAR2_163R1,
+ /* ECCurve_SECG_CHAR2_163R2 == ECCurve_NIST_B163 */
+ ECCurve_SECG_CHAR2_193R1,
+ ECCurve_SECG_CHAR2_193R2,
+ /* ECCurve_SECG_CHAR2_233K1 == ECCurve_NIST_K233 */
+ /* ECCurve_SECG_CHAR2_233R1 == ECCurve_NIST_B233 */
+ ECCurve_SECG_CHAR2_239K1,
+ /* ECCurve_SECG_CHAR2_283K1 == ECCurve_NIST_K283 */
+ /* ECCurve_SECG_CHAR2_283R1 == ECCurve_NIST_B283 */
+ /* ECCurve_SECG_CHAR2_409K1 == ECCurve_NIST_K409 */
+ /* ECCurve_SECG_CHAR2_409R1 == ECCurve_NIST_B409 */
+ /* ECCurve_SECG_CHAR2_571K1 == ECCurve_NIST_K571 */
+ /* ECCurve_SECG_CHAR2_571R1 == ECCurve_NIST_B571 */
+
+ /* WTLS curves */
+ ECCurve_WTLS_1,
+ /* there is no WTLS 2 curve */
+ /* ECCurve_WTLS_3 == ECCurve_NIST_K163 */
+ /* ECCurve_WTLS_4 == ECCurve_SECG_CHAR2_113R1 */
+ /* ECCurve_WTLS_5 == ECCurve_X9_62_CHAR2_PNB163V1 */
+ /* ECCurve_WTLS_6 == ECCurve_SECG_PRIME_112R1 */
+ /* ECCurve_WTLS_7 == ECCurve_SECG_PRIME_160R1 */
+ ECCurve_WTLS_8,
+ ECCurve_WTLS_9,
+ /* ECCurve_WTLS_10 == ECCurve_NIST_K233 */
+ /* ECCurve_WTLS_11 == ECCurve_NIST_B233 */
+ /* ECCurve_WTLS_12 == ECCurve_NIST_P224 */
+
+ /* ECC Brainpool prime curves in RFC 5639*/
+ ECCurve_BrainpoolP256r1,
+ ECCurve_BrainpoolP320r1,
+ ECCurve_BrainpoolP384r1,
+ ECCurve_BrainpoolP512r1,
+
+ ECCurve_pastLastCurve
+} ECCurveName;
+
+/* Aliased named curves */
+
+#define ECCurve_X9_62_PRIME_192V1 ECCurve_NIST_P192
+#define ECCurve_X9_62_PRIME_256V1 ECCurve_NIST_P256
+#define ECCurve_SECG_PRIME_192R1 ECCurve_NIST_P192
+#define ECCurve_SECG_PRIME_224R1 ECCurve_NIST_P224
+#define ECCurve_SECG_PRIME_256R1 ECCurve_NIST_P256
+#define ECCurve_SECG_PRIME_384R1 ECCurve_NIST_P384
+#define ECCurve_SECG_PRIME_521R1 ECCurve_NIST_P521
+#define ECCurve_SECG_CHAR2_163K1 ECCurve_NIST_K163
+#define ECCurve_SECG_CHAR2_163R2 ECCurve_NIST_B163
+#define ECCurve_SECG_CHAR2_233K1 ECCurve_NIST_K233
+#define ECCurve_SECG_CHAR2_233R1 ECCurve_NIST_B233
+#define ECCurve_SECG_CHAR2_283K1 ECCurve_NIST_K283
+#define ECCurve_SECG_CHAR2_283R1 ECCurve_NIST_B283
+#define ECCurve_SECG_CHAR2_409K1 ECCurve_NIST_K409
+#define ECCurve_SECG_CHAR2_409R1 ECCurve_NIST_B409
+#define ECCurve_SECG_CHAR2_571K1 ECCurve_NIST_K571
+#define ECCurve_SECG_CHAR2_571R1 ECCurve_NIST_B571
+#define ECCurve_WTLS_3 ECCurve_NIST_K163
+#define ECCurve_WTLS_4 ECCurve_SECG_CHAR2_113R1
+#define ECCurve_WTLS_5 ECCurve_X9_62_CHAR2_PNB163V1
+#define ECCurve_WTLS_6 ECCurve_SECG_PRIME_112R1
+#define ECCurve_WTLS_7 ECCurve_SECG_PRIME_160R1
+#define ECCurve_WTLS_10 ECCurve_NIST_K233
+#define ECCurve_WTLS_11 ECCurve_NIST_B233
+#define ECCurve_WTLS_12 ECCurve_NIST_P224
+
+#endif /* _ECL_EXP_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h b/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h
new file mode 100644
index 0000000..bdfe615
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecl-priv.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Stephen Fung <fungstep@hotmail.com> and
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * Last Modified Date from the Original Code: May 2017
+ *********************************************************************** */
+
+#ifndef _ECL_PRIV_H
+#define _ECL_PRIV_H
+
+#include "ecl.h"
+#include "mpi.h"
+#include "mplogic.h"
+
+/* MAX_FIELD_SIZE_DIGITS is the maximum size of field element supported */
+/* the following needs to go away... */
+#if defined(MP_USE_LONG_LONG_DIGIT) || defined(MP_USE_LONG_DIGIT)
+#define ECL_SIXTY_FOUR_BIT
+#else
+#define ECL_THIRTY_TWO_BIT
+#endif
+
+#define ECL_CURVE_DIGITS(curve_size_in_bits) \
+ (((curve_size_in_bits)+(sizeof(mp_digit)*8-1))/(sizeof(mp_digit)*8))
+#define ECL_BITS (sizeof(mp_digit)*8)
+#define ECL_MAX_FIELD_SIZE_DIGITS (80/sizeof(mp_digit))
+
+/* Gets the i'th bit in the binary representation of a. If i >= length(a),
+ * then return 0. (The above behaviour differs from mpl_get_bit, which
+ * causes an error if i >= length(a).) */
+#define MP_GET_BIT(a, i) \
+ ((i) >= mpl_significant_bits((a))) ? 0 : mpl_get_bit((a), (i))
+
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+#define MP_ADD_CARRY(a1, a2, s, cin, cout) \
+ { mp_word w; \
+ w = ((mp_word)(cin)) + (a1) + (a2); \
+ s = ACCUM(w); \
+ cout = CARRYOUT(w); }
+
+/* Handle case when carry-in value is zero */
+#define MP_ADD_CARRY_ZERO(a1, a2, s, cout) \
+ MP_ADD_CARRY(a1, a2, s, 0, cout);
+
+#define MP_SUB_BORROW(a1, a2, s, bin, bout) \
+ { mp_word w; \
+ w = ((mp_word)(a1)) - (a2) - (bin); \
+ s = ACCUM(w); \
+ bout = (w >> MP_DIGIT_BIT) & 1; }
+
+#else
+/* NOTE,
+ * cin and cout could be the same variable.
+ * bin and bout could be the same variable.
+ * a1 or a2 and s could be the same variable.
+ * don't trash those outputs until their respective inputs have
+ * been read. */
+#define MP_ADD_CARRY(a1, a2, s, cin, cout) \
+ { mp_digit tmp,sum; \
+ tmp = (a1); \
+ sum = tmp + (a2); \
+ tmp = (sum < tmp); /* detect overflow */ \
+ s = sum += (cin); \
+ cout = tmp + (sum < (cin)); }
+
+/* Handle case when carry-in value is zero */
+#define MP_ADD_CARRY_ZERO(a1, a2, s, cout) \
+ { mp_digit tmp,sum; \
+ tmp = (a1); \
+ sum = tmp + (a2); \
+ tmp = (sum < tmp); /* detect overflow */ \
+ s = sum; \
+ cout = tmp; }
+
+#define MP_SUB_BORROW(a1, a2, s, bin, bout) \
+ { mp_digit tmp; \
+ tmp = (a1); \
+ s = tmp - (a2); \
+ tmp = (s > tmp); /* detect borrow */ \
+ if ((bin) && !s--) tmp++; \
+ bout = tmp; }
+#endif
+
+
+struct GFMethodStr;
+typedef struct GFMethodStr GFMethod;
+struct GFMethodStr {
+ /* Indicates whether the structure was constructed from dynamic memory
+ * or statically created. */
+ int constructed;
+ /* Irreducible that defines the field. For prime fields, this is the
+ * prime p. For binary polynomial fields, this is the bitstring
+ * representation of the irreducible polynomial. */
+ mp_int irr;
+ /* For prime fields, the value irr_arr[0] is the number of bits in the
+ * field. For binary polynomial fields, the irreducible polynomial
+ * f(t) is represented as an array of unsigned int[], where f(t) is
+ * of the form: f(t) = t^p[0] + t^p[1] + ... + t^p[4] where m = p[0]
+ * > p[1] > ... > p[4] = 0. */
+ unsigned int irr_arr[5];
+ /* Field arithmetic methods. All methods (except field_enc and
+ * field_dec) are assumed to take field-encoded parameters and return
+ * field-encoded values. All methods (except field_enc and field_dec)
+ * are required to be implemented. */
+ mp_err (*field_add) (const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+ mp_err (*field_neg) (const mp_int *a, mp_int *r, const GFMethod *meth);
+ mp_err (*field_sub) (const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+ mp_err (*field_mod) (const mp_int *a, mp_int *r, const GFMethod *meth);
+ mp_err (*field_mul) (const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+ mp_err (*field_sqr) (const mp_int *a, mp_int *r, const GFMethod *meth);
+ mp_err (*field_div) (const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+ mp_err (*field_enc) (const mp_int *a, mp_int *r, const GFMethod *meth);
+ mp_err (*field_dec) (const mp_int *a, mp_int *r, const GFMethod *meth);
+ /* Extra storage for implementation-specific data. Any memory
+ * allocated to these extra fields will be cleared by extra_free. */
+ void *extra1;
+ void *extra2;
+ void (*extra_free) (GFMethod *meth);
+};
+
+/* Construct generic GFMethods. */
+GFMethod *GFMethod_consGFp(const mp_int *irr);
+GFMethod *GFMethod_consGFp_mont(const mp_int *irr);
+GFMethod *GFMethod_consGF2m(const mp_int *irr,
+ const unsigned int irr_arr[5]);
+/* Free the memory allocated (if any) to a GFMethod object. */
+void GFMethod_free(GFMethod *meth);
+
+struct ECGroupStr {
+ /* Indicates whether the structure was constructed from dynamic memory
+ * or statically created. */
+ int constructed;
+ /* Field definition and arithmetic. */
+ GFMethod *meth;
+ /* Textual representation of curve name, if any. */
+ char *text;
+#ifdef _KERNEL
+ int text_len;
+#endif
+ /* Curve parameters, field-encoded. */
+ mp_int curvea, curveb;
+ /* x and y coordinates of the base point, field-encoded. */
+ mp_int genx, geny;
+ /* Order and cofactor of the base point. */
+ mp_int order;
+ int cofactor;
+ /* Point arithmetic methods. All methods are assumed to take
+ * field-encoded parameters and return field-encoded values. All
+ * methods (except base_point_mul and points_mul) are required to be
+ * implemented. */
+ mp_err (*point_add) (const mp_int *px, const mp_int *py,
+ const mp_int *qx, const mp_int *qy, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+ mp_err (*point_sub) (const mp_int *px, const mp_int *py,
+ const mp_int *qx, const mp_int *qy, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+ mp_err (*point_dbl) (const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+ mp_err (*point_mul) (const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group, int timing);
+ mp_err (*base_point_mul) (const mp_int *n, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+ mp_err (*points_mul) (const mp_int *k1, const mp_int *k2,
+ const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, const ECGroup *group,
+ int timing);
+ mp_err (*validate_point) (const mp_int *px, const mp_int *py, const ECGroup *group);
+ /* Extra storage for implementation-specific data. Any memory
+ * allocated to these extra fields will be cleared by extra_free. */
+ void *extra1;
+ void *extra2;
+ void (*extra_free) (ECGroup *group);
+};
+
+/* Wrapper functions for generic prime field arithmetic. */
+mp_err ec_GFp_add(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GFp_neg(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GFp_sub(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+
+/* fixed length in-line adds. Count is in words */
+mp_err ec_GFp_add_3(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GFp_add_4(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GFp_add_5(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GFp_add_6(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GFp_sub_3(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GFp_sub_4(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GFp_sub_5(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GFp_sub_6(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+
+mp_err ec_GFp_mod(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GFp_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GFp_sqr(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GFp_div(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+/* Wrapper functions for generic binary polynomial field arithmetic. */
+mp_err ec_GF2m_add(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GF2m_neg(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GF2m_mod(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GF2m_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GF2m_sqr(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GF2m_div(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+
+/* Montgomery prime field arithmetic. */
+mp_err ec_GFp_mul_mont(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GFp_sqr_mont(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GFp_div_mont(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth);
+mp_err ec_GFp_enc_mont(const mp_int *a, mp_int *r, const GFMethod *meth);
+mp_err ec_GFp_dec_mont(const mp_int *a, mp_int *r, const GFMethod *meth);
+void ec_GFp_extra_free_mont(GFMethod *meth);
+
+/* point multiplication */
+mp_err ec_pts_mul_basic(const mp_int *k1, const mp_int *k2,
+ const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, const ECGroup *group,
+ int timing);
+mp_err ec_pts_mul_simul_w2(const mp_int *k1, const mp_int *k2,
+ const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, const ECGroup *group,
+ int timing);
+
+/* Computes the windowed non-adjacent-form (NAF) of a scalar. Out should
+ * be an array of signed char's to output to, bitsize should be the number
+ * of bits of out, in is the original scalar, and w is the window size.
+ * NAF is discussed in the paper: D. Hankerson, J. Hernandez and A.
+ * Menezes, "Software implementation of elliptic curve cryptography over
+ * binary fields", Proc. CHES 2000. */
+mp_err ec_compute_wNAF(signed char *out, int bitsize, const mp_int *in,
+ int w);
+
+/* Optimized field arithmetic */
+mp_err ec_group_set_gfp192(ECGroup *group, ECCurveName);
+mp_err ec_group_set_gfp224(ECGroup *group, ECCurveName);
+mp_err ec_group_set_gfp256(ECGroup *group, ECCurveName);
+mp_err ec_group_set_gfp384(ECGroup *group, ECCurveName);
+mp_err ec_group_set_gfp521(ECGroup *group, ECCurveName);
+mp_err ec_group_set_gf2m163(ECGroup *group, ECCurveName name);
+mp_err ec_group_set_gf2m193(ECGroup *group, ECCurveName name);
+mp_err ec_group_set_gf2m233(ECGroup *group, ECCurveName name);
+
+/* Optimized floating-point arithmetic */
+#ifdef ECL_USE_FP
+mp_err ec_group_set_secp160r1_fp(ECGroup *group);
+mp_err ec_group_set_nistp192_fp(ECGroup *group);
+mp_err ec_group_set_nistp224_fp(ECGroup *group);
+#endif
+
+#endif /* _ECL_PRIV_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecl.c b/jdk.crypto.ec/share/native/libsunec/impl/ecl.c
new file mode 100644
index 0000000..49f407a
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecl.c
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ *********************************************************************** */
+
+#include "mpi.h"
+#include "mplogic.h"
+#include "ecl.h"
+#include "ecl-priv.h"
+#include "ec2.h"
+#include "ecp.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+/* Allocate memory for a new ECGroup object. */
+ECGroup *
+ECGroup_new(int kmflag)
+{
+ mp_err res = MP_OKAY;
+ ECGroup *group;
+#ifdef _KERNEL
+ group = (ECGroup *) kmem_alloc(sizeof(ECGroup), kmflag);
+#else
+ group = (ECGroup *) malloc(sizeof(ECGroup));
+#endif
+ if (group == NULL)
+ return NULL;
+ group->constructed = MP_YES;
+ group->meth = NULL;
+ group->text = NULL;
+ MP_DIGITS(&group->curvea) = 0;
+ MP_DIGITS(&group->curveb) = 0;
+ MP_DIGITS(&group->genx) = 0;
+ MP_DIGITS(&group->geny) = 0;
+ MP_DIGITS(&group->order) = 0;
+ group->base_point_mul = NULL;
+ group->points_mul = NULL;
+ group->validate_point = NULL;
+ group->extra1 = NULL;
+ group->extra2 = NULL;
+ group->extra_free = NULL;
+ MP_CHECKOK(mp_init(&group->curvea, kmflag));
+ MP_CHECKOK(mp_init(&group->curveb, kmflag));
+ MP_CHECKOK(mp_init(&group->genx, kmflag));
+ MP_CHECKOK(mp_init(&group->geny, kmflag));
+ MP_CHECKOK(mp_init(&group->order, kmflag));
+
+ CLEANUP:
+ if (res != MP_OKAY) {
+ ECGroup_free(group);
+ return NULL;
+ }
+ return group;
+}
+
+/* Construct a generic ECGroup for elliptic curves over prime fields. */
+ECGroup *
+ECGroup_consGFp(const mp_int *irr, const mp_int *curvea,
+ const mp_int *curveb, const mp_int *genx,
+ const mp_int *geny, const mp_int *order, int cofactor)
+{
+ mp_err res = MP_OKAY;
+ ECGroup *group = NULL;
+
+ group = ECGroup_new(FLAG(irr));
+ if (group == NULL)
+ return NULL;
+
+ group->meth = GFMethod_consGFp(irr);
+ if (group->meth == NULL) {
+ res = MP_MEM;
+ goto CLEANUP;
+ }
+ MP_CHECKOK(mp_copy(curvea, &group->curvea));
+ MP_CHECKOK(mp_copy(curveb, &group->curveb));
+ MP_CHECKOK(mp_copy(genx, &group->genx));
+ MP_CHECKOK(mp_copy(geny, &group->geny));
+ MP_CHECKOK(mp_copy(order, &group->order));
+ group->cofactor = cofactor;
+ group->point_add = &ec_GFp_pt_add_aff;
+ group->point_sub = &ec_GFp_pt_sub_aff;
+ group->point_dbl = &ec_GFp_pt_dbl_aff;
+ group->point_mul = &ec_GFp_pt_mul_jm_wNAF;
+ group->base_point_mul = NULL;
+ group->points_mul = &ec_GFp_pts_mul_jac;
+ group->validate_point = &ec_GFp_validate_point;
+
+ CLEANUP:
+ if (res != MP_OKAY) {
+ ECGroup_free(group);
+ return NULL;
+ }
+ return group;
+}
+
+/* Construct a generic ECGroup for elliptic curves over prime fields with
+ * field arithmetic implemented in Montgomery coordinates. */
+ECGroup *
+ECGroup_consGFp_mont(const mp_int *irr, const mp_int *curvea,
+ const mp_int *curveb, const mp_int *genx,
+ const mp_int *geny, const mp_int *order, int cofactor)
+{
+ mp_err res = MP_OKAY;
+ ECGroup *group = NULL;
+
+ group = ECGroup_new(FLAG(irr));
+ if (group == NULL)
+ return NULL;
+
+ group->meth = GFMethod_consGFp_mont(irr);
+ if (group->meth == NULL) {
+ res = MP_MEM;
+ goto CLEANUP;
+ }
+ MP_CHECKOK(group->meth->
+ field_enc(curvea, &group->curvea, group->meth));
+ MP_CHECKOK(group->meth->
+ field_enc(curveb, &group->curveb, group->meth));
+ MP_CHECKOK(group->meth->field_enc(genx, &group->genx, group->meth));
+ MP_CHECKOK(group->meth->field_enc(geny, &group->geny, group->meth));
+ MP_CHECKOK(mp_copy(order, &group->order));
+ group->cofactor = cofactor;
+ group->point_add = &ec_GFp_pt_add_aff;
+ group->point_sub = &ec_GFp_pt_sub_aff;
+ group->point_dbl = &ec_GFp_pt_dbl_aff;
+ group->point_mul = &ec_GFp_pt_mul_jm_wNAF;
+ group->base_point_mul = NULL;
+ group->points_mul = &ec_GFp_pts_mul_jac;
+ group->validate_point = &ec_GFp_validate_point;
+
+ CLEANUP:
+ if (res != MP_OKAY) {
+ ECGroup_free(group);
+ return NULL;
+ }
+ return group;
+}
+
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
+/* Construct a generic ECGroup for elliptic curves over binary polynomial
+ * fields. */
+ECGroup *
+ECGroup_consGF2m(const mp_int *irr, const unsigned int irr_arr[5],
+ const mp_int *curvea, const mp_int *curveb,
+ const mp_int *genx, const mp_int *geny,
+ const mp_int *order, int cofactor)
+{
+ mp_err res = MP_OKAY;
+ ECGroup *group = NULL;
+
+ group = ECGroup_new(FLAG(irr));
+ if (group == NULL)
+ return NULL;
+
+ group->meth = GFMethod_consGF2m(irr, irr_arr);
+ if (group->meth == NULL) {
+ res = MP_MEM;
+ goto CLEANUP;
+ }
+ MP_CHECKOK(mp_copy(curvea, &group->curvea));
+ MP_CHECKOK(mp_copy(curveb, &group->curveb));
+ MP_CHECKOK(mp_copy(genx, &group->genx));
+ MP_CHECKOK(mp_copy(geny, &group->geny));
+ MP_CHECKOK(mp_copy(order, &group->order));
+ group->cofactor = cofactor;
+ group->point_add = &ec_GF2m_pt_add_aff;
+ group->point_sub = &ec_GF2m_pt_sub_aff;
+ group->point_dbl = &ec_GF2m_pt_dbl_aff;
+ group->point_mul = &ec_GF2m_pt_mul_mont;
+ group->base_point_mul = NULL;
+ group->points_mul = &ec_pts_mul_basic;
+ group->validate_point = &ec_GF2m_validate_point;
+
+ CLEANUP:
+ if (res != MP_OKAY) {
+ ECGroup_free(group);
+ return NULL;
+ }
+ return group;
+}
+#endif
+
+/* Construct ECGroup from hex parameters and name, if any. Called by
+ * ECGroup_fromHex and ECGroup_fromName. */
+ECGroup *
+ecgroup_fromNameAndHex(const ECCurveName name,
+ const ECCurveParams * params, int kmflag)
+{
+ mp_int irr, curvea, curveb, genx, geny, order;
+ int bits;
+ ECGroup *group = NULL;
+ mp_err res = MP_OKAY;
+
+ /* initialize values */
+ MP_DIGITS(&irr) = 0;
+ MP_DIGITS(&curvea) = 0;
+ MP_DIGITS(&curveb) = 0;
+ MP_DIGITS(&genx) = 0;
+ MP_DIGITS(&geny) = 0;
+ MP_DIGITS(&order) = 0;
+ MP_CHECKOK(mp_init(&irr, kmflag));
+ MP_CHECKOK(mp_init(&curvea, kmflag));
+ MP_CHECKOK(mp_init(&curveb, kmflag));
+ MP_CHECKOK(mp_init(&genx, kmflag));
+ MP_CHECKOK(mp_init(&geny, kmflag));
+ MP_CHECKOK(mp_init(&order, kmflag));
+ MP_CHECKOK(mp_read_radix(&irr, params->irr, 16));
+ MP_CHECKOK(mp_read_radix(&curvea, params->curvea, 16));
+ MP_CHECKOK(mp_read_radix(&curveb, params->curveb, 16));
+ MP_CHECKOK(mp_read_radix(&genx, params->genx, 16));
+ MP_CHECKOK(mp_read_radix(&geny, params->geny, 16));
+ MP_CHECKOK(mp_read_radix(&order, params->order, 16));
+
+ /* determine number of bits */
+ bits = mpl_significant_bits(&irr) - 1;
+ if (bits < MP_OKAY) {
+ res = bits;
+ goto CLEANUP;
+ }
+
+ /* determine which optimizations (if any) to use */
+ if (params->field == ECField_GFp) {
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
+ switch (name) {
+#ifdef ECL_USE_FP
+ case ECCurve_SECG_PRIME_160R1:
+ group =
+ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+ &order, params->cofactor);
+ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+ MP_CHECKOK(ec_group_set_secp160r1_fp(group));
+ break;
+#endif
+ case ECCurve_SECG_PRIME_192R1:
+#ifdef ECL_USE_FP
+ group =
+ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+ &order, params->cofactor);
+ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+ MP_CHECKOK(ec_group_set_nistp192_fp(group));
+#else
+ group =
+ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+ &order, params->cofactor);
+ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+ MP_CHECKOK(ec_group_set_gfp192(group, name));
+#endif
+ break;
+ case ECCurve_SECG_PRIME_224R1:
+#ifdef ECL_USE_FP
+ group =
+ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+ &order, params->cofactor);
+ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+ MP_CHECKOK(ec_group_set_nistp224_fp(group));
+#else
+ group =
+ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+ &order, params->cofactor);
+ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+ MP_CHECKOK(ec_group_set_gfp224(group, name));
+#endif
+ break;
+ case ECCurve_SECG_PRIME_256R1:
+ group =
+ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+ &order, params->cofactor);
+ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+ MP_CHECKOK(ec_group_set_gfp256(group, name));
+ break;
+ case ECCurve_SECG_PRIME_521R1:
+ group =
+ ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
+ &order, params->cofactor);
+ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+ MP_CHECKOK(ec_group_set_gfp521(group, name));
+ break;
+ default:
+ /* use generic arithmetic */
+#endif
+ group =
+ ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny,
+ &order, params->cofactor);
+ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+#ifdef NSS_ECC_MORE_THAN_SUITE_B
+ }
+ } else if (params->field == ECField_GF2m) {
+ group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, &geny, &order, params->cofactor);
+ if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
+ if ((name == ECCurve_NIST_K163) ||
+ (name == ECCurve_NIST_B163) ||
+ (name == ECCurve_SECG_CHAR2_163R1)) {
+ MP_CHECKOK(ec_group_set_gf2m163(group, name));
+ } else if ((name == ECCurve_SECG_CHAR2_193R1) ||
+ (name == ECCurve_SECG_CHAR2_193R2)) {
+ MP_CHECKOK(ec_group_set_gf2m193(group, name));
+ } else if ((name == ECCurve_NIST_K233) ||
+ (name == ECCurve_NIST_B233)) {
+ MP_CHECKOK(ec_group_set_gf2m233(group, name));
+ }
+#endif
+ } else {
+ res = MP_UNDEF;
+ goto CLEANUP;
+ }
+
+ /* set name, if any */
+ if ((group != NULL) && (params->text != NULL)) {
+#ifdef _KERNEL
+ int n = strlen(params->text) + 1;
+
+ group->text = kmem_alloc(n, kmflag);
+ if (group->text == NULL) {
+ res = MP_MEM;
+ goto CLEANUP;
+ }
+ bcopy(params->text, group->text, n);
+ group->text_len = n;
+#else
+ group->text = strdup(params->text);
+ if (group->text == NULL) {
+ res = MP_MEM;
+ }
+#endif
+ }
+
+ CLEANUP:
+ mp_clear(&irr);
+ mp_clear(&curvea);
+ mp_clear(&curveb);
+ mp_clear(&genx);
+ mp_clear(&geny);
+ mp_clear(&order);
+ if (res != MP_OKAY) {
+ ECGroup_free(group);
+ return NULL;
+ }
+ return group;
+}
+
+/* Construct ECGroup from hexadecimal representations of parameters. */
+ECGroup *
+ECGroup_fromHex(const ECCurveParams * params, int kmflag)
+{
+ return ecgroup_fromNameAndHex(ECCurve_noName, params, kmflag);
+}
+
+/* Construct ECGroup from named parameters. */
+ECGroup *
+ECGroup_fromName(const ECCurveName name, int kmflag)
+{
+ ECGroup *group = NULL;
+ ECCurveParams *params = NULL;
+ mp_err res = MP_OKAY;
+
+ params = EC_GetNamedCurveParams(name, kmflag);
+ if (params == NULL) {
+ res = MP_UNDEF;
+ goto CLEANUP;
+ }
+
+ /* construct actual group */
+ group = ecgroup_fromNameAndHex(name, params, kmflag);
+ if (group == NULL) {
+ res = MP_UNDEF;
+ goto CLEANUP;
+ }
+
+ CLEANUP:
+ EC_FreeCurveParams(params);
+ if (res != MP_OKAY) {
+ ECGroup_free(group);
+ return NULL;
+ }
+ return group;
+}
+
+/* Validates an EC public key as described in Section 5.2.2 of X9.62. */
+mp_err ECPoint_validate(const ECGroup *group, const mp_int *px, const
+ mp_int *py)
+{
+ /* 1: Verify that publicValue is not the point at infinity */
+ /* 2: Verify that the coordinates of publicValue are elements
+ * of the field.
+ */
+ /* 3: Verify that publicValue is on the curve. */
+ /* 4: Verify that the order of the curve times the publicValue
+ * is the point at infinity.
+ */
+ return group->validate_point(px, py, group);
+}
+
+/* Free the memory allocated (if any) to an ECGroup object. */
+void
+ECGroup_free(ECGroup *group)
+{
+ if (group == NULL)
+ return;
+ GFMethod_free(group->meth);
+ if (group->constructed == MP_NO)
+ return;
+ mp_clear(&group->curvea);
+ mp_clear(&group->curveb);
+ mp_clear(&group->genx);
+ mp_clear(&group->geny);
+ mp_clear(&group->order);
+ if (group->text != NULL)
+#ifdef _KERNEL
+ kmem_free(group->text, group->text_len);
+#else
+ free(group->text);
+#endif
+ if (group->extra_free != NULL)
+ group->extra_free(group);
+#ifdef _KERNEL
+ kmem_free(group, sizeof (ECGroup));
+#else
+ free(group);
+#endif
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecl.h b/jdk.crypto.ec/share/native/libsunec/impl/ecl.h
new file mode 100644
index 0000000..deff0aa
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecl.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * Last Modified Date from the Original Code: May 2017
+ *********************************************************************** */
+
+#ifndef _ECL_H
+#define _ECL_H
+
+/* Although this is not an exported header file, code which uses elliptic
+ * curve point operations will need to include it. */
+
+#include "ecl-exp.h"
+#include "mpi.h"
+
+struct ECGroupStr;
+typedef struct ECGroupStr ECGroup;
+
+/* Construct ECGroup from hexadecimal representations of parameters. */
+ECGroup *ECGroup_fromHex(const ECCurveParams * params, int kmflag);
+
+/* Construct ECGroup from named parameters. */
+ECGroup *ECGroup_fromName(const ECCurveName name, int kmflag);
+
+/* Free an allocated ECGroup. */
+void ECGroup_free(ECGroup *group);
+
+/* Construct ECCurveParams from an ECCurveName */
+ECCurveParams *EC_GetNamedCurveParams(const ECCurveName name, int kmflag);
+
+/* Duplicates an ECCurveParams */
+ECCurveParams *ECCurveParams_dup(const ECCurveParams * params, int kmflag);
+
+/* Free an allocated ECCurveParams */
+void EC_FreeCurveParams(ECCurveParams * params);
+
+/* Elliptic curve scalar-point multiplication. Computes Q(x, y) = k * P(x,
+ * y). If x, y = NULL, then P is assumed to be the generator (base point)
+ * of the group of points on the elliptic curve. Input and output values
+ * are assumed to be NOT field-encoded. */
+mp_err ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
+ const mp_int *py, mp_int *qx, mp_int *qy,
+ int timing);
+
+/* Elliptic curve scalar-point multiplication. Computes Q(x, y) = k1 * G +
+ * k2 * P(x, y), where G is the generator (base point) of the group of
+ * points on the elliptic curve. Input and output values are assumed to
+ * be NOT field-encoded. */
+mp_err ECPoints_mul(const ECGroup *group, const mp_int *k1,
+ const mp_int *k2, const mp_int *px, const mp_int *py,
+ mp_int *qx, mp_int *qy, int timing);
+
+/* Validates an EC public key as described in Section 5.2.2 of X9.62.
+ * Returns MP_YES if the public key is valid, MP_NO if the public key
+ * is invalid, or an error code if the validation could not be
+ * performed. */
+mp_err ECPoint_validate(const ECGroup *group, const mp_int *px, const
+ mp_int *py);
+
+#endif /* _ECL_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecl_curve.c b/jdk.crypto.ec/share/native/libsunec/impl/ecl_curve.c
new file mode 100644
index 0000000..fe88324
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecl_curve.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ *********************************************************************** */
+
+#include "ecl.h"
+#include "ecl-curve.h"
+#include "ecl-priv.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#define CHECK(func) if ((func) == NULL) { res = 0; goto CLEANUP; }
+
+/* Duplicates an ECCurveParams */
+ECCurveParams *
+ECCurveParams_dup(const ECCurveParams * params, int kmflag)
+{
+ int res = 1;
+ ECCurveParams *ret = NULL;
+
+#ifdef _KERNEL
+ ret = (ECCurveParams *) kmem_zalloc(sizeof(ECCurveParams), kmflag);
+#else
+ CHECK(ret = (ECCurveParams *) calloc(1, sizeof(ECCurveParams)));
+#endif
+ if (params->text != NULL) {
+#ifdef _KERNEL
+ ret->text = kmem_alloc(strlen(params->text) + 1, kmflag);
+ bcopy(params->text, ret->text, strlen(params->text) + 1);
+#else
+ CHECK(ret->text = strdup(params->text));
+#endif
+ }
+ ret->field = params->field;
+ ret->size = params->size;
+ if (params->irr != NULL) {
+#ifdef _KERNEL
+ ret->irr = kmem_alloc(strlen(params->irr) + 1, kmflag);
+ bcopy(params->irr, ret->irr, strlen(params->irr) + 1);
+#else
+ CHECK(ret->irr = strdup(params->irr));
+#endif
+ }
+ if (params->curvea != NULL) {
+#ifdef _KERNEL
+ ret->curvea = kmem_alloc(strlen(params->curvea) + 1, kmflag);
+ bcopy(params->curvea, ret->curvea, strlen(params->curvea) + 1);
+#else
+ CHECK(ret->curvea = strdup(params->curvea));
+#endif
+ }
+ if (params->curveb != NULL) {
+#ifdef _KERNEL
+ ret->curveb = kmem_alloc(strlen(params->curveb) + 1, kmflag);
+ bcopy(params->curveb, ret->curveb, strlen(params->curveb) + 1);
+#else
+ CHECK(ret->curveb = strdup(params->curveb));
+#endif
+ }
+ if (params->genx != NULL) {
+#ifdef _KERNEL
+ ret->genx = kmem_alloc(strlen(params->genx) + 1, kmflag);
+ bcopy(params->genx, ret->genx, strlen(params->genx) + 1);
+#else
+ CHECK(ret->genx = strdup(params->genx));
+#endif
+ }
+ if (params->geny != NULL) {
+#ifdef _KERNEL
+ ret->geny = kmem_alloc(strlen(params->geny) + 1, kmflag);
+ bcopy(params->geny, ret->geny, strlen(params->geny) + 1);
+#else
+ CHECK(ret->geny = strdup(params->geny));
+#endif
+ }
+ if (params->order != NULL) {
+#ifdef _KERNEL
+ ret->order = kmem_alloc(strlen(params->order) + 1, kmflag);
+ bcopy(params->order, ret->order, strlen(params->order) + 1);
+#else
+ CHECK(ret->order = strdup(params->order));
+#endif
+ }
+ ret->cofactor = params->cofactor;
+
+ CLEANUP:
+ if (res != 1) {
+ EC_FreeCurveParams(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+#undef CHECK
+
+/* Construct ECCurveParams from an ECCurveName */
+ECCurveParams *
+EC_GetNamedCurveParams(const ECCurveName name, int kmflag)
+{
+ if ((name <= ECCurve_noName) || (ECCurve_pastLastCurve <= name) ||
+ (ecCurve_map[name] == NULL)) {
+ return NULL;
+ } else {
+ return ECCurveParams_dup(ecCurve_map[name], kmflag);
+ }
+}
+
+/* Free the memory allocated (if any) to an ECCurveParams object. */
+void
+EC_FreeCurveParams(ECCurveParams * params)
+{
+ if (params == NULL)
+ return;
+ if (params->text != NULL)
+#ifdef _KERNEL
+ kmem_free(params->text, strlen(params->text) + 1);
+#else
+ free(params->text);
+#endif
+ if (params->irr != NULL)
+#ifdef _KERNEL
+ kmem_free(params->irr, strlen(params->irr) + 1);
+#else
+ free(params->irr);
+#endif
+ if (params->curvea != NULL)
+#ifdef _KERNEL
+ kmem_free(params->curvea, strlen(params->curvea) + 1);
+#else
+ free(params->curvea);
+#endif
+ if (params->curveb != NULL)
+#ifdef _KERNEL
+ kmem_free(params->curveb, strlen(params->curveb) + 1);
+#else
+ free(params->curveb);
+#endif
+ if (params->genx != NULL)
+#ifdef _KERNEL
+ kmem_free(params->genx, strlen(params->genx) + 1);
+#else
+ free(params->genx);
+#endif
+ if (params->geny != NULL)
+#ifdef _KERNEL
+ kmem_free(params->geny, strlen(params->geny) + 1);
+#else
+ free(params->geny);
+#endif
+ if (params->order != NULL)
+#ifdef _KERNEL
+ kmem_free(params->order, strlen(params->order) + 1);
+#else
+ free(params->order);
+#endif
+#ifdef _KERNEL
+ kmem_free(params, sizeof(ECCurveParams));
+#else
+ free(params);
+#endif
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecl_gf.c b/jdk.crypto.ec/share/native/libsunec/impl/ecl_gf.c
new file mode 100644
index 0000000..3723925
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecl_gf.c
@@ -0,0 +1,1043 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Stephen Fung <fungstep@hotmail.com> and
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ *********************************************************************** */
+
+#include "mpi.h"
+#include "mp_gf2m.h"
+#include "ecl-priv.h"
+#include "mpi-priv.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+/* Allocate memory for a new GFMethod object. */
+GFMethod *
+GFMethod_new(int kmflag)
+{
+ mp_err res = MP_OKAY;
+ GFMethod *meth;
+#ifdef _KERNEL
+ meth = (GFMethod *) kmem_alloc(sizeof(GFMethod), kmflag);
+#else
+ meth = (GFMethod *) malloc(sizeof(GFMethod));
+ if (meth == NULL)
+ return NULL;
+#endif
+ meth->constructed = MP_YES;
+ MP_DIGITS(&meth->irr) = 0;
+ meth->extra_free = NULL;
+ MP_CHECKOK(mp_init(&meth->irr, kmflag));
+
+ CLEANUP:
+ if (res != MP_OKAY) {
+ GFMethod_free(meth);
+ return NULL;
+ }
+ return meth;
+}
+
+/* Construct a generic GFMethod for arithmetic over prime fields with
+ * irreducible irr. */
+GFMethod *
+GFMethod_consGFp(const mp_int *irr)
+{
+ mp_err res = MP_OKAY;
+ GFMethod *meth = NULL;
+
+ meth = GFMethod_new(FLAG(irr));
+ if (meth == NULL)
+ return NULL;
+
+ MP_CHECKOK(mp_copy(irr, &meth->irr));
+ meth->irr_arr[0] = mpl_significant_bits(irr);
+ meth->irr_arr[1] = meth->irr_arr[2] = meth->irr_arr[3] =
+ meth->irr_arr[4] = 0;
+ switch(MP_USED(&meth->irr)) {
+ /* maybe we need 1 and 2 words here as well?*/
+ case 3:
+ meth->field_add = &ec_GFp_add_3;
+ meth->field_sub = &ec_GFp_sub_3;
+ break;
+ case 4:
+ meth->field_add = &ec_GFp_add_4;
+ meth->field_sub = &ec_GFp_sub_4;
+ break;
+ case 5:
+ meth->field_add = &ec_GFp_add_5;
+ meth->field_sub = &ec_GFp_sub_5;
+ break;
+ case 6:
+ meth->field_add = &ec_GFp_add_6;
+ meth->field_sub = &ec_GFp_sub_6;
+ break;
+ default:
+ meth->field_add = &ec_GFp_add;
+ meth->field_sub = &ec_GFp_sub;
+ }
+ meth->field_neg = &ec_GFp_neg;
+ meth->field_mod = &ec_GFp_mod;
+ meth->field_mul = &ec_GFp_mul;
+ meth->field_sqr = &ec_GFp_sqr;
+ meth->field_div = &ec_GFp_div;
+ meth->field_enc = NULL;
+ meth->field_dec = NULL;
+ meth->extra1 = NULL;
+ meth->extra2 = NULL;
+ meth->extra_free = NULL;
+
+ CLEANUP:
+ if (res != MP_OKAY) {
+ GFMethod_free(meth);
+ return NULL;
+ }
+ return meth;
+}
+
+/* Construct a generic GFMethod for arithmetic over binary polynomial
+ * fields with irreducible irr that has array representation irr_arr (see
+ * ecl-priv.h for description of the representation). If irr_arr is NULL,
+ * then it is constructed from the bitstring representation. */
+GFMethod *
+GFMethod_consGF2m(const mp_int *irr, const unsigned int irr_arr[5])
+{
+ mp_err res = MP_OKAY;
+ int ret;
+ GFMethod *meth = NULL;
+
+ meth = GFMethod_new(FLAG(irr));
+ if (meth == NULL)
+ return NULL;
+
+ MP_CHECKOK(mp_copy(irr, &meth->irr));
+ if (irr_arr != NULL) {
+ /* Irreducible polynomials are either trinomials or pentanomials. */
+ meth->irr_arr[0] = irr_arr[0];
+ meth->irr_arr[1] = irr_arr[1];
+ meth->irr_arr[2] = irr_arr[2];
+ if (irr_arr[2] > 0) {
+ meth->irr_arr[3] = irr_arr[3];
+ meth->irr_arr[4] = irr_arr[4];
+ } else {
+ meth->irr_arr[3] = meth->irr_arr[4] = 0;
+ }
+ } else {
+ ret = mp_bpoly2arr(irr, meth->irr_arr, 5);
+ /* Irreducible polynomials are either trinomials or pentanomials. */
+ if ((ret != 5) && (ret != 3)) {
+ res = MP_UNDEF;
+ goto CLEANUP;
+ }
+ }
+ meth->field_add = &ec_GF2m_add;
+ meth->field_neg = &ec_GF2m_neg;
+ meth->field_sub = &ec_GF2m_add;
+ meth->field_mod = &ec_GF2m_mod;
+ meth->field_mul = &ec_GF2m_mul;
+ meth->field_sqr = &ec_GF2m_sqr;
+ meth->field_div = &ec_GF2m_div;
+ meth->field_enc = NULL;
+ meth->field_dec = NULL;
+ meth->extra1 = NULL;
+ meth->extra2 = NULL;
+ meth->extra_free = NULL;
+
+ CLEANUP:
+ if (res != MP_OKAY) {
+ GFMethod_free(meth);
+ return NULL;
+ }
+ return meth;
+}
+
+/* Free the memory allocated (if any) to a GFMethod object. */
+void
+GFMethod_free(GFMethod *meth)
+{
+ if (meth == NULL)
+ return;
+ if (meth->constructed == MP_NO)
+ return;
+ mp_clear(&meth->irr);
+ if (meth->extra_free != NULL)
+ meth->extra_free(meth);
+#ifdef _KERNEL
+ kmem_free(meth, sizeof(GFMethod));
+#else
+ free(meth);
+#endif
+}
+
+/* Wrapper functions for generic prime field arithmetic. */
+
+/* Add two field elements. Assumes that 0 <= a, b < meth->irr */
+mp_err
+ec_GFp_add(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ /* PRE: 0 <= a, b < p = meth->irr POST: 0 <= r < p, r = a + b (mod p) */
+ mp_err res;
+
+ if ((res = mp_add(a, b, r)) != MP_OKAY) {
+ return res;
+ }
+ if (mp_cmp(r, &meth->irr) >= 0) {
+ return mp_sub(r, &meth->irr, r);
+ }
+ return res;
+}
+
+/* Negates a field element. Assumes that 0 <= a < meth->irr */
+mp_err
+ec_GFp_neg(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ /* PRE: 0 <= a < p = meth->irr POST: 0 <= r < p, r = -a (mod p) */
+
+ if (mp_cmp_z(a) == 0) {
+ mp_zero(r);
+ return MP_OKAY;
+ }
+ return mp_sub(&meth->irr, a, r);
+}
+
+/* Subtracts two field elements. Assumes that 0 <= a, b < meth->irr */
+mp_err
+ec_GFp_sub(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ /* PRE: 0 <= a, b < p = meth->irr POST: 0 <= r < p, r = a - b (mod p) */
+ res = mp_sub(a, b, r);
+ if (res == MP_RANGE) {
+ MP_CHECKOK(mp_sub(b, a, r));
+ if (mp_cmp_z(r) < 0) {
+ MP_CHECKOK(mp_add(r, &meth->irr, r));
+ }
+ MP_CHECKOK(ec_GFp_neg(r, r, meth));
+ }
+ if (mp_cmp_z(r) < 0) {
+ MP_CHECKOK(mp_add(r, &meth->irr, r));
+ }
+ CLEANUP:
+ return res;
+}
+/*
+ * Inline adds for small curve lengths.
+ */
+/* 3 words */
+mp_err
+ec_GFp_add_3(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit a0 = 0, a1 = 0, a2 = 0;
+ mp_digit r0 = 0, r1 = 0, r2 = 0;
+ mp_digit carry;
+
+ switch(MP_USED(a)) {
+ case 3:
+ a2 = MP_DIGIT(a,2);
+ case 2:
+ a1 = MP_DIGIT(a,1);
+ case 1:
+ a0 = MP_DIGIT(a,0);
+ }
+ switch(MP_USED(b)) {
+ case 3:
+ r2 = MP_DIGIT(b,2);
+ case 2:
+ r1 = MP_DIGIT(b,1);
+ case 1:
+ r0 = MP_DIGIT(b,0);
+ }
+
+#ifndef MPI_AMD64_ADD
+ MP_ADD_CARRY_ZERO(a0, r0, r0, carry);
+ MP_ADD_CARRY(a1, r1, r1, carry, carry);
+ MP_ADD_CARRY(a2, r2, r2, carry, carry);
+#else
+ __asm__ (
+ "xorq %3,%3 \n\t"
+ "addq %4,%0 \n\t"
+ "adcq %5,%1 \n\t"
+ "adcq %6,%2 \n\t"
+ "adcq $0,%3 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(carry)
+ : "r" (a0), "r" (a1), "r" (a2),
+ "0" (r0), "1" (r1), "2" (r2)
+ : "%cc" );
+#endif
+
+ MP_CHECKOK(s_mp_pad(r, 3));
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 3;
+
+ /* Do quick 'subract' if we've gone over
+ * (add the 2's complement of the curve field) */
+ a2 = MP_DIGIT(&meth->irr,2);
+ if (carry || r2 > a2 ||
+ ((r2 == a2) && mp_cmp(r,&meth->irr) != MP_LT)) {
+ a1 = MP_DIGIT(&meth->irr,1);
+ a0 = MP_DIGIT(&meth->irr,0);
+#ifndef MPI_AMD64_ADD
+ MP_SUB_BORROW(r0, a0, r0, 0, carry);
+ MP_SUB_BORROW(r1, a1, r1, carry, carry);
+ MP_SUB_BORROW(r2, a2, r2, carry, carry);
+#else
+ __asm__ (
+ "subq %3,%0 \n\t"
+ "sbbq %4,%1 \n\t"
+ "sbbq %5,%2 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2)
+ : "r" (a0), "r" (a1), "r" (a2),
+ "0" (r0), "1" (r1), "2" (r2)
+ : "%cc" );
+#endif
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ }
+
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/* 4 words */
+mp_err
+ec_GFp_add_4(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0;
+ mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0;
+ mp_digit carry;
+
+ switch(MP_USED(a)) {
+ case 4:
+ a3 = MP_DIGIT(a,3);
+ case 3:
+ a2 = MP_DIGIT(a,2);
+ case 2:
+ a1 = MP_DIGIT(a,1);
+ case 1:
+ a0 = MP_DIGIT(a,0);
+ }
+ switch(MP_USED(b)) {
+ case 4:
+ r3 = MP_DIGIT(b,3);
+ case 3:
+ r2 = MP_DIGIT(b,2);
+ case 2:
+ r1 = MP_DIGIT(b,1);
+ case 1:
+ r0 = MP_DIGIT(b,0);
+ }
+
+#ifndef MPI_AMD64_ADD
+ MP_ADD_CARRY_ZERO(a0, r0, r0, carry);
+ MP_ADD_CARRY(a1, r1, r1, carry, carry);
+ MP_ADD_CARRY(a2, r2, r2, carry, carry);
+ MP_ADD_CARRY(a3, r3, r3, carry, carry);
+#else
+ __asm__ (
+ "xorq %4,%4 \n\t"
+ "addq %5,%0 \n\t"
+ "adcq %6,%1 \n\t"
+ "adcq %7,%2 \n\t"
+ "adcq %8,%3 \n\t"
+ "adcq $0,%4 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(carry)
+ : "r" (a0), "r" (a1), "r" (a2), "r" (a3),
+ "0" (r0), "1" (r1), "2" (r2), "3" (r3)
+ : "%cc" );
+#endif
+
+ MP_CHECKOK(s_mp_pad(r, 4));
+ MP_DIGIT(r, 3) = r3;
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 4;
+
+ /* Do quick 'subract' if we've gone over
+ * (add the 2's complement of the curve field) */
+ a3 = MP_DIGIT(&meth->irr,3);
+ if (carry || r3 > a3 ||
+ ((r3 == a3) && mp_cmp(r,&meth->irr) != MP_LT)) {
+ a2 = MP_DIGIT(&meth->irr,2);
+ a1 = MP_DIGIT(&meth->irr,1);
+ a0 = MP_DIGIT(&meth->irr,0);
+#ifndef MPI_AMD64_ADD
+ MP_SUB_BORROW(r0, a0, r0, 0, carry);
+ MP_SUB_BORROW(r1, a1, r1, carry, carry);
+ MP_SUB_BORROW(r2, a2, r2, carry, carry);
+ MP_SUB_BORROW(r3, a3, r3, carry, carry);
+#else
+ __asm__ (
+ "subq %4,%0 \n\t"
+ "sbbq %5,%1 \n\t"
+ "sbbq %6,%2 \n\t"
+ "sbbq %7,%3 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3)
+ : "r" (a0), "r" (a1), "r" (a2), "r" (a3),
+ "0" (r0), "1" (r1), "2" (r2), "3" (r3)
+ : "%cc" );
+#endif
+ MP_DIGIT(r, 3) = r3;
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ }
+
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/* 5 words */
+mp_err
+ec_GFp_add_5(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0;
+ mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0;
+ mp_digit carry;
+
+ switch(MP_USED(a)) {
+ case 5:
+ a4 = MP_DIGIT(a,4);
+ case 4:
+ a3 = MP_DIGIT(a,3);
+ case 3:
+ a2 = MP_DIGIT(a,2);
+ case 2:
+ a1 = MP_DIGIT(a,1);
+ case 1:
+ a0 = MP_DIGIT(a,0);
+ }
+ switch(MP_USED(b)) {
+ case 5:
+ r4 = MP_DIGIT(b,4);
+ case 4:
+ r3 = MP_DIGIT(b,3);
+ case 3:
+ r2 = MP_DIGIT(b,2);
+ case 2:
+ r1 = MP_DIGIT(b,1);
+ case 1:
+ r0 = MP_DIGIT(b,0);
+ }
+
+ MP_ADD_CARRY_ZERO(a0, r0, r0, carry);
+ MP_ADD_CARRY(a1, r1, r1, carry, carry);
+ MP_ADD_CARRY(a2, r2, r2, carry, carry);
+ MP_ADD_CARRY(a3, r3, r3, carry, carry);
+ MP_ADD_CARRY(a4, r4, r4, carry, carry);
+
+ MP_CHECKOK(s_mp_pad(r, 5));
+ MP_DIGIT(r, 4) = r4;
+ MP_DIGIT(r, 3) = r3;
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 5;
+
+ /* Do quick 'subract' if we've gone over
+ * (add the 2's complement of the curve field) */
+ a4 = MP_DIGIT(&meth->irr,4);
+ if (carry || r4 > a4 ||
+ ((r4 == a4) && mp_cmp(r,&meth->irr) != MP_LT)) {
+ a3 = MP_DIGIT(&meth->irr,3);
+ a2 = MP_DIGIT(&meth->irr,2);
+ a1 = MP_DIGIT(&meth->irr,1);
+ a0 = MP_DIGIT(&meth->irr,0);
+ MP_SUB_BORROW(r0, a0, r0, 0, carry);
+ MP_SUB_BORROW(r1, a1, r1, carry, carry);
+ MP_SUB_BORROW(r2, a2, r2, carry, carry);
+ MP_SUB_BORROW(r3, a3, r3, carry, carry);
+ MP_SUB_BORROW(r4, a4, r4, carry, carry);
+ MP_DIGIT(r, 4) = r4;
+ MP_DIGIT(r, 3) = r3;
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ }
+
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/* 6 words */
+mp_err
+ec_GFp_add_6(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0;
+ mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0;
+ mp_digit carry;
+
+ switch(MP_USED(a)) {
+ case 6:
+ a5 = MP_DIGIT(a,5);
+ case 5:
+ a4 = MP_DIGIT(a,4);
+ case 4:
+ a3 = MP_DIGIT(a,3);
+ case 3:
+ a2 = MP_DIGIT(a,2);
+ case 2:
+ a1 = MP_DIGIT(a,1);
+ case 1:
+ a0 = MP_DIGIT(a,0);
+ }
+ switch(MP_USED(b)) {
+ case 6:
+ r5 = MP_DIGIT(b,5);
+ case 5:
+ r4 = MP_DIGIT(b,4);
+ case 4:
+ r3 = MP_DIGIT(b,3);
+ case 3:
+ r2 = MP_DIGIT(b,2);
+ case 2:
+ r1 = MP_DIGIT(b,1);
+ case 1:
+ r0 = MP_DIGIT(b,0);
+ }
+
+ MP_ADD_CARRY_ZERO(a0, r0, r0, carry);
+ MP_ADD_CARRY(a1, r1, r1, carry, carry);
+ MP_ADD_CARRY(a2, r2, r2, carry, carry);
+ MP_ADD_CARRY(a3, r3, r3, carry, carry);
+ MP_ADD_CARRY(a4, r4, r4, carry, carry);
+ MP_ADD_CARRY(a5, r5, r5, carry, carry);
+
+ MP_CHECKOK(s_mp_pad(r, 6));
+ MP_DIGIT(r, 5) = r5;
+ MP_DIGIT(r, 4) = r4;
+ MP_DIGIT(r, 3) = r3;
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 6;
+
+ /* Do quick 'subract' if we've gone over
+ * (add the 2's complement of the curve field) */
+ a5 = MP_DIGIT(&meth->irr,5);
+ if (carry || r5 > a5 ||
+ ((r5 == a5) && mp_cmp(r,&meth->irr) != MP_LT)) {
+ a4 = MP_DIGIT(&meth->irr,4);
+ a3 = MP_DIGIT(&meth->irr,3);
+ a2 = MP_DIGIT(&meth->irr,2);
+ a1 = MP_DIGIT(&meth->irr,1);
+ a0 = MP_DIGIT(&meth->irr,0);
+ MP_SUB_BORROW(r0, a0, r0, 0, carry);
+ MP_SUB_BORROW(r1, a1, r1, carry, carry);
+ MP_SUB_BORROW(r2, a2, r2, carry, carry);
+ MP_SUB_BORROW(r3, a3, r3, carry, carry);
+ MP_SUB_BORROW(r4, a4, r4, carry, carry);
+ MP_SUB_BORROW(r5, a5, r5, carry, carry);
+ MP_DIGIT(r, 5) = r5;
+ MP_DIGIT(r, 4) = r4;
+ MP_DIGIT(r, 3) = r3;
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ }
+
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/*
+ * The following subraction functions do in-line subractions based
+ * on our curve size.
+ *
+ * ... 3 words
+ */
+mp_err
+ec_GFp_sub_3(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit b0 = 0, b1 = 0, b2 = 0;
+ mp_digit r0 = 0, r1 = 0, r2 = 0;
+ mp_digit borrow;
+
+ switch(MP_USED(a)) {
+ case 3:
+ r2 = MP_DIGIT(a,2);
+ case 2:
+ r1 = MP_DIGIT(a,1);
+ case 1:
+ r0 = MP_DIGIT(a,0);
+ }
+ switch(MP_USED(b)) {
+ case 3:
+ b2 = MP_DIGIT(b,2);
+ case 2:
+ b1 = MP_DIGIT(b,1);
+ case 1:
+ b0 = MP_DIGIT(b,0);
+ }
+
+#ifndef MPI_AMD64_ADD
+ MP_SUB_BORROW(r0, b0, r0, 0, borrow);
+ MP_SUB_BORROW(r1, b1, r1, borrow, borrow);
+ MP_SUB_BORROW(r2, b2, r2, borrow, borrow);
+#else
+ __asm__ (
+ "xorq %3,%3 \n\t"
+ "subq %4,%0 \n\t"
+ "sbbq %5,%1 \n\t"
+ "sbbq %6,%2 \n\t"
+ "adcq $0,%3 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2), "=r" (borrow)
+ : "r" (b0), "r" (b1), "r" (b2),
+ "0" (r0), "1" (r1), "2" (r2)
+ : "%cc" );
+#endif
+
+ /* Do quick 'add' if we've gone under 0
+ * (subtract the 2's complement of the curve field) */
+ if (borrow) {
+ b2 = MP_DIGIT(&meth->irr,2);
+ b1 = MP_DIGIT(&meth->irr,1);
+ b0 = MP_DIGIT(&meth->irr,0);
+#ifndef MPI_AMD64_ADD
+ MP_ADD_CARRY_ZERO(b0, r0, r0, borrow);
+ MP_ADD_CARRY(b1, r1, r1, borrow, borrow);
+ MP_ADD_CARRY(b2, r2, r2, borrow, borrow);
+#else
+ __asm__ (
+ "addq %3,%0 \n\t"
+ "adcq %4,%1 \n\t"
+ "adcq %5,%2 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2)
+ : "r" (b0), "r" (b1), "r" (b2),
+ "0" (r0), "1" (r1), "2" (r2)
+ : "%cc" );
+#endif
+ }
+
+#ifdef MPI_AMD64_ADD
+ /* compiler fakeout? */
+ if ((r2 == b0) && (r1 == b0) && (r0 == b0)) {
+ MP_CHECKOK(s_mp_pad(r, 4));
+ }
+#endif
+ MP_CHECKOK(s_mp_pad(r, 3));
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 3;
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/* 4 words */
+mp_err
+ec_GFp_sub_4(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0;
+ mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0;
+ mp_digit borrow;
+
+ switch(MP_USED(a)) {
+ case 4:
+ r3 = MP_DIGIT(a,3);
+ case 3:
+ r2 = MP_DIGIT(a,2);
+ case 2:
+ r1 = MP_DIGIT(a,1);
+ case 1:
+ r0 = MP_DIGIT(a,0);
+ }
+ switch(MP_USED(b)) {
+ case 4:
+ b3 = MP_DIGIT(b,3);
+ case 3:
+ b2 = MP_DIGIT(b,2);
+ case 2:
+ b1 = MP_DIGIT(b,1);
+ case 1:
+ b0 = MP_DIGIT(b,0);
+ }
+
+#ifndef MPI_AMD64_ADD
+ MP_SUB_BORROW(r0, b0, r0, 0, borrow);
+ MP_SUB_BORROW(r1, b1, r1, borrow, borrow);
+ MP_SUB_BORROW(r2, b2, r2, borrow, borrow);
+ MP_SUB_BORROW(r3, b3, r3, borrow, borrow);
+#else
+ __asm__ (
+ "xorq %4,%4 \n\t"
+ "subq %5,%0 \n\t"
+ "sbbq %6,%1 \n\t"
+ "sbbq %7,%2 \n\t"
+ "sbbq %8,%3 \n\t"
+ "adcq $0,%4 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r" (borrow)
+ : "r" (b0), "r" (b1), "r" (b2), "r" (b3),
+ "0" (r0), "1" (r1), "2" (r2), "3" (r3)
+ : "%cc" );
+#endif
+
+ /* Do quick 'add' if we've gone under 0
+ * (subtract the 2's complement of the curve field) */
+ if (borrow) {
+ b3 = MP_DIGIT(&meth->irr,3);
+ b2 = MP_DIGIT(&meth->irr,2);
+ b1 = MP_DIGIT(&meth->irr,1);
+ b0 = MP_DIGIT(&meth->irr,0);
+#ifndef MPI_AMD64_ADD
+ MP_ADD_CARRY_ZERO(b0, r0, r0, borrow);
+ MP_ADD_CARRY(b1, r1, r1, borrow, borrow);
+ MP_ADD_CARRY(b2, r2, r2, borrow, borrow);
+ MP_ADD_CARRY(b3, r3, r3, borrow, borrow);
+#else
+ __asm__ (
+ "addq %4,%0 \n\t"
+ "adcq %5,%1 \n\t"
+ "adcq %6,%2 \n\t"
+ "adcq %7,%3 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3)
+ : "r" (b0), "r" (b1), "r" (b2), "r" (b3),
+ "0" (r0), "1" (r1), "2" (r2), "3" (r3)
+ : "%cc" );
+#endif
+ }
+#ifdef MPI_AMD64_ADD
+ /* compiler fakeout? */
+ if ((r3 == b0) && (r1 == b0) && (r0 == b0)) {
+ MP_CHECKOK(s_mp_pad(r, 4));
+ }
+#endif
+ MP_CHECKOK(s_mp_pad(r, 4));
+ MP_DIGIT(r, 3) = r3;
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 4;
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/* 5 words */
+mp_err
+ec_GFp_sub_5(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0;
+ mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0;
+ mp_digit borrow;
+
+ switch(MP_USED(a)) {
+ case 5:
+ r4 = MP_DIGIT(a,4);
+ case 4:
+ r3 = MP_DIGIT(a,3);
+ case 3:
+ r2 = MP_DIGIT(a,2);
+ case 2:
+ r1 = MP_DIGIT(a,1);
+ case 1:
+ r0 = MP_DIGIT(a,0);
+ }
+ switch(MP_USED(b)) {
+ case 5:
+ b4 = MP_DIGIT(b,4);
+ case 4:
+ b3 = MP_DIGIT(b,3);
+ case 3:
+ b2 = MP_DIGIT(b,2);
+ case 2:
+ b1 = MP_DIGIT(b,1);
+ case 1:
+ b0 = MP_DIGIT(b,0);
+ }
+
+ MP_SUB_BORROW(r0, b0, r0, 0, borrow);
+ MP_SUB_BORROW(r1, b1, r1, borrow, borrow);
+ MP_SUB_BORROW(r2, b2, r2, borrow, borrow);
+ MP_SUB_BORROW(r3, b3, r3, borrow, borrow);
+ MP_SUB_BORROW(r4, b4, r4, borrow, borrow);
+
+ /* Do quick 'add' if we've gone under 0
+ * (subtract the 2's complement of the curve field) */
+ if (borrow) {
+ b4 = MP_DIGIT(&meth->irr,4);
+ b3 = MP_DIGIT(&meth->irr,3);
+ b2 = MP_DIGIT(&meth->irr,2);
+ b1 = MP_DIGIT(&meth->irr,1);
+ b0 = MP_DIGIT(&meth->irr,0);
+ MP_ADD_CARRY_ZERO(b0, r0, r0, borrow);
+ MP_ADD_CARRY(b1, r1, r1, borrow, borrow);
+ MP_ADD_CARRY(b2, r2, r2, borrow, borrow);
+ MP_ADD_CARRY(b3, r3, r3, borrow, borrow);
+ MP_ADD_CARRY(b4, r4, r4, borrow, borrow);
+ }
+ MP_CHECKOK(s_mp_pad(r, 5));
+ MP_DIGIT(r, 4) = r4;
+ MP_DIGIT(r, 3) = r3;
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 5;
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+/* 6 words */
+mp_err
+ec_GFp_sub_6(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0;
+ mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0;
+ mp_digit borrow;
+
+ switch(MP_USED(a)) {
+ case 6:
+ r5 = MP_DIGIT(a,5);
+ case 5:
+ r4 = MP_DIGIT(a,4);
+ case 4:
+ r3 = MP_DIGIT(a,3);
+ case 3:
+ r2 = MP_DIGIT(a,2);
+ case 2:
+ r1 = MP_DIGIT(a,1);
+ case 1:
+ r0 = MP_DIGIT(a,0);
+ }
+ switch(MP_USED(b)) {
+ case 6:
+ b5 = MP_DIGIT(b,5);
+ case 5:
+ b4 = MP_DIGIT(b,4);
+ case 4:
+ b3 = MP_DIGIT(b,3);
+ case 3:
+ b2 = MP_DIGIT(b,2);
+ case 2:
+ b1 = MP_DIGIT(b,1);
+ case 1:
+ b0 = MP_DIGIT(b,0);
+ }
+
+ MP_SUB_BORROW(r0, b0, r0, 0, borrow);
+ MP_SUB_BORROW(r1, b1, r1, borrow, borrow);
+ MP_SUB_BORROW(r2, b2, r2, borrow, borrow);
+ MP_SUB_BORROW(r3, b3, r3, borrow, borrow);
+ MP_SUB_BORROW(r4, b4, r4, borrow, borrow);
+ MP_SUB_BORROW(r5, b5, r5, borrow, borrow);
+
+ /* Do quick 'add' if we've gone under 0
+ * (subtract the 2's complement of the curve field) */
+ if (borrow) {
+ b5 = MP_DIGIT(&meth->irr,5);
+ b4 = MP_DIGIT(&meth->irr,4);
+ b3 = MP_DIGIT(&meth->irr,3);
+ b2 = MP_DIGIT(&meth->irr,2);
+ b1 = MP_DIGIT(&meth->irr,1);
+ b0 = MP_DIGIT(&meth->irr,0);
+ MP_ADD_CARRY_ZERO(b0, r0, r0, borrow);
+ MP_ADD_CARRY(b1, r1, r1, borrow, borrow);
+ MP_ADD_CARRY(b2, r2, r2, borrow, borrow);
+ MP_ADD_CARRY(b3, r3, r3, borrow, borrow);
+ MP_ADD_CARRY(b4, r4, r4, borrow, borrow);
+ MP_ADD_CARRY(b5, r5, r5, borrow, borrow);
+ }
+
+ MP_CHECKOK(s_mp_pad(r, 6));
+ MP_DIGIT(r, 5) = r5;
+ MP_DIGIT(r, 4) = r4;
+ MP_DIGIT(r, 3) = r3;
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 6;
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+
+/* Reduces an integer to a field element. */
+mp_err
+ec_GFp_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ return mp_mod(a, &meth->irr, r);
+}
+
+/* Multiplies two field elements. */
+mp_err
+ec_GFp_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ return mp_mulmod(a, b, &meth->irr, r);
+}
+
+/* Squares a field element. */
+mp_err
+ec_GFp_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ return mp_sqrmod(a, &meth->irr, r);
+}
+
+/* Divides two field elements. If a is NULL, then returns the inverse of
+ * b. */
+mp_err
+ec_GFp_div(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_int t;
+
+ /* If a is NULL, then return the inverse of b, otherwise return a/b. */
+ if (a == NULL) {
+ return mp_invmod(b, &meth->irr, r);
+ } else {
+ /* MPI doesn't support divmod, so we implement it using invmod and
+ * mulmod. */
+ MP_CHECKOK(mp_init(&t, FLAG(b)));
+ MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
+ MP_CHECKOK(mp_mulmod(a, &t, &meth->irr, r));
+ CLEANUP:
+ mp_clear(&t);
+ return res;
+ }
+}
+
+/* Wrapper functions for generic binary polynomial field arithmetic. */
+
+/* Adds two field elements. */
+mp_err
+ec_GF2m_add(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ return mp_badd(a, b, r);
+}
+
+/* Negates a field element. Note that for binary polynomial fields, the
+ * negation of a field element is the field element itself. */
+mp_err
+ec_GF2m_neg(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ if (a == r) {
+ return MP_OKAY;
+ } else {
+ return mp_copy(a, r);
+ }
+}
+
+/* Reduces a binary polynomial to a field element. */
+mp_err
+ec_GF2m_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ return mp_bmod(a, meth->irr_arr, r);
+}
+
+/* Multiplies two field elements. */
+mp_err
+ec_GF2m_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ return mp_bmulmod(a, b, meth->irr_arr, r);
+}
+
+/* Squares a field element. */
+mp_err
+ec_GF2m_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ return mp_bsqrmod(a, meth->irr_arr, r);
+}
+
+/* Divides two field elements. If a is NULL, then returns the inverse of
+ * b. */
+mp_err
+ec_GF2m_div(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_int t;
+
+ /* If a is NULL, then return the inverse of b, otherwise return a/b. */
+ if (a == NULL) {
+ /* The GF(2^m) portion of MPI doesn't support invmod, so we
+ * compute 1/b. */
+ MP_CHECKOK(mp_init(&t, FLAG(b)));
+ MP_CHECKOK(mp_set_int(&t, 1));
+ MP_CHECKOK(mp_bdivmod(&t, b, &meth->irr, meth->irr_arr, r));
+ CLEANUP:
+ mp_clear(&t);
+ return res;
+ } else {
+ return mp_bdivmod(a, b, &meth->irr, meth->irr_arr, r);
+ }
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c b/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c
new file mode 100644
index 0000000..316dd0c
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * Last Modified Date from the Original Code: May 2017
+ *********************************************************************** */
+
+#include "mpi.h"
+#include "mplogic.h"
+#include "ecl.h"
+#include "ecl-priv.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k * P(x,
+ * y). If x, y = NULL, then P is assumed to be the generator (base point)
+ * of the group of points on the elliptic curve. Input and output values
+ * are assumed to be NOT field-encoded. */
+mp_err
+ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ int timing)
+{
+ mp_err res = MP_OKAY;
+ mp_int kt;
+
+ ARGCHK((k != NULL) && (group != NULL), MP_BADARG);
+ MP_DIGITS(&kt) = 0;
+
+ /* want scalar to be less than or equal to group order */
+ if (mp_cmp(k, &group->order) > 0) {
+ MP_CHECKOK(mp_init(&kt, FLAG(k)));
+ MP_CHECKOK(mp_mod(k, &group->order, &kt));
+ } else {
+ MP_SIGN(&kt) = MP_ZPOS;
+ MP_USED(&kt) = MP_USED(k);
+ MP_ALLOC(&kt) = MP_ALLOC(k);
+ MP_DIGITS(&kt) = MP_DIGITS(k);
+ }
+
+ if ((px == NULL) || (py == NULL)) {
+ if (group->base_point_mul) {
+ MP_CHECKOK(group->base_point_mul(&kt, rx, ry, group));
+ } else {
+ kt.flag = (mp_sign)0;
+ MP_CHECKOK(group->
+ point_mul(&kt, &group->genx, &group->geny, rx, ry,
+ group, timing));
+ }
+ } else {
+ kt.flag = (mp_sign)0;
+ if (group->meth->field_enc) {
+ MP_CHECKOK(group->meth->field_enc(px, rx, group->meth));
+ MP_CHECKOK(group->meth->field_enc(py, ry, group->meth));
+ MP_CHECKOK(group->point_mul(&kt, rx, ry, rx, ry, group, timing));
+ } else {
+ MP_CHECKOK(group->point_mul(&kt, px, py, rx, ry, group, timing));
+ }
+ }
+ if (group->meth->field_dec) {
+ MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
+ MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
+ }
+
+ CLEANUP:
+ if (MP_DIGITS(&kt) != MP_DIGITS(k)) {
+ mp_clear(&kt);
+ }
+ return res;
+}
+
+/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G +
+ * k2 * P(x, y), where G is the generator (base point) of the group of
+ * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
+ * Input and output values are assumed to be NOT field-encoded. */
+mp_err
+ec_pts_mul_basic(const mp_int *k1, const mp_int *k2, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group, int timing)
+{
+ mp_err res = MP_OKAY;
+ mp_int sx, sy;
+
+ ARGCHK(group != NULL, MP_BADARG);
+ ARGCHK(!((k1 == NULL)
+ && ((k2 == NULL) || (px == NULL)
+ || (py == NULL))), MP_BADARG);
+
+ /* if some arguments are not defined used ECPoint_mul */
+ if (k1 == NULL) {
+ return ECPoint_mul(group, k2, px, py, rx, ry, timing);
+ } else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
+ return ECPoint_mul(group, k1, NULL, NULL, rx, ry, timing);
+ }
+
+ MP_DIGITS(&sx) = 0;
+ MP_DIGITS(&sy) = 0;
+ MP_CHECKOK(mp_init(&sx, FLAG(k1)));
+ MP_CHECKOK(mp_init(&sy, FLAG(k1)));
+
+ MP_CHECKOK(ECPoint_mul(group, k1, NULL, NULL, &sx, &sy, timing));
+ MP_CHECKOK(ECPoint_mul(group, k2, px, py, rx, ry, timing));
+
+ if (group->meth->field_enc) {
+ MP_CHECKOK(group->meth->field_enc(&sx, &sx, group->meth));
+ MP_CHECKOK(group->meth->field_enc(&sy, &sy, group->meth));
+ MP_CHECKOK(group->meth->field_enc(rx, rx, group->meth));
+ MP_CHECKOK(group->meth->field_enc(ry, ry, group->meth));
+ }
+
+ MP_CHECKOK(group->point_add(&sx, &sy, rx, ry, rx, ry, group));
+
+ if (group->meth->field_dec) {
+ MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
+ MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
+ }
+
+ CLEANUP:
+ mp_clear(&sx);
+ mp_clear(&sy);
+ return res;
+}
+
+/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G +
+ * k2 * P(x, y), where G is the generator (base point) of the group of
+ * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
+ * Input and output values are assumed to be NOT field-encoded. Uses
+ * algorithm 15 (simultaneous multiple point multiplication) from Brown,
+ * Hankerson, Lopez, Menezes. Software Implementation of the NIST
+ * Elliptic Curves over Prime Fields. */
+mp_err
+ec_pts_mul_simul_w2(const mp_int *k1, const mp_int *k2, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group, int timing)
+{
+ mp_err res = MP_OKAY;
+ mp_int precomp[4][4][2];
+ const mp_int *a, *b;
+ int i, j;
+ int ai, bi, d;
+
+ ARGCHK(group != NULL, MP_BADARG);
+ ARGCHK(!((k1 == NULL)
+ && ((k2 == NULL) || (px == NULL)
+ || (py == NULL))), MP_BADARG);
+
+ /* if some arguments are not defined used ECPoint_mul */
+ if (k1 == NULL) {
+ return ECPoint_mul(group, k2, px, py, rx, ry, timing);
+ } else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
+ return ECPoint_mul(group, k1, NULL, NULL, rx, ry, timing);
+ }
+
+ /* initialize precomputation table */
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ MP_DIGITS(&precomp[i][j][0]) = 0;
+ MP_DIGITS(&precomp[i][j][1]) = 0;
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ MP_CHECKOK( mp_init_size(&precomp[i][j][0],
+ ECL_MAX_FIELD_SIZE_DIGITS, FLAG(k1)) );
+ MP_CHECKOK( mp_init_size(&precomp[i][j][1],
+ ECL_MAX_FIELD_SIZE_DIGITS, FLAG(k1)) );
+ }
+ }
+
+ /* fill precomputation table */
+ /* assign {k1, k2} = {a, b} such that len(a) >= len(b) */
+ if (mpl_significant_bits(k1) < mpl_significant_bits(k2)) {
+ a = k2;
+ b = k1;
+ if (group->meth->field_enc) {
+ MP_CHECKOK(group->meth->
+ field_enc(px, &precomp[1][0][0], group->meth));
+ MP_CHECKOK(group->meth->
+ field_enc(py, &precomp[1][0][1], group->meth));
+ } else {
+ MP_CHECKOK(mp_copy(px, &precomp[1][0][0]));
+ MP_CHECKOK(mp_copy(py, &precomp[1][0][1]));
+ }
+ MP_CHECKOK(mp_copy(&group->genx, &precomp[0][1][0]));
+ MP_CHECKOK(mp_copy(&group->geny, &precomp[0][1][1]));
+ } else {
+ a = k1;
+ b = k2;
+ MP_CHECKOK(mp_copy(&group->genx, &precomp[1][0][0]));
+ MP_CHECKOK(mp_copy(&group->geny, &precomp[1][0][1]));
+ if (group->meth->field_enc) {
+ MP_CHECKOK(group->meth->
+ field_enc(px, &precomp[0][1][0], group->meth));
+ MP_CHECKOK(group->meth->
+ field_enc(py, &precomp[0][1][1], group->meth));
+ } else {
+ MP_CHECKOK(mp_copy(px, &precomp[0][1][0]));
+ MP_CHECKOK(mp_copy(py, &precomp[0][1][1]));
+ }
+ }
+ /* precompute [*][0][*] */
+ mp_zero(&precomp[0][0][0]);
+ mp_zero(&precomp[0][0][1]);
+ MP_CHECKOK(group->
+ point_dbl(&precomp[1][0][0], &precomp[1][0][1],
+ &precomp[2][0][0], &precomp[2][0][1], group));
+ MP_CHECKOK(group->
+ point_add(&precomp[1][0][0], &precomp[1][0][1],
+ &precomp[2][0][0], &precomp[2][0][1],
+ &precomp[3][0][0], &precomp[3][0][1], group));
+ /* precompute [*][1][*] */
+ for (i = 1; i < 4; i++) {
+ MP_CHECKOK(group->
+ point_add(&precomp[0][1][0], &precomp[0][1][1],
+ &precomp[i][0][0], &precomp[i][0][1],
+ &precomp[i][1][0], &precomp[i][1][1], group));
+ }
+ /* precompute [*][2][*] */
+ MP_CHECKOK(group->
+ point_dbl(&precomp[0][1][0], &precomp[0][1][1],
+ &precomp[0][2][0], &precomp[0][2][1], group));
+ for (i = 1; i < 4; i++) {
+ MP_CHECKOK(group->
+ point_add(&precomp[0][2][0], &precomp[0][2][1],
+ &precomp[i][0][0], &precomp[i][0][1],
+ &precomp[i][2][0], &precomp[i][2][1], group));
+ }
+ /* precompute [*][3][*] */
+ MP_CHECKOK(group->
+ point_add(&precomp[0][1][0], &precomp[0][1][1],
+ &precomp[0][2][0], &precomp[0][2][1],
+ &precomp[0][3][0], &precomp[0][3][1], group));
+ for (i = 1; i < 4; i++) {
+ MP_CHECKOK(group->
+ point_add(&precomp[0][3][0], &precomp[0][3][1],
+ &precomp[i][0][0], &precomp[i][0][1],
+ &precomp[i][3][0], &precomp[i][3][1], group));
+ }
+
+ d = (mpl_significant_bits(a) + 1) / 2;
+
+ /* R = inf */
+ mp_zero(rx);
+ mp_zero(ry);
+
+ for (i = d - 1; i >= 0; i--) {
+ ai = MP_GET_BIT(a, 2 * i + 1);
+ ai <<= 1;
+ ai |= MP_GET_BIT(a, 2 * i);
+ bi = MP_GET_BIT(b, 2 * i + 1);
+ bi <<= 1;
+ bi |= MP_GET_BIT(b, 2 * i);
+ /* R = 2^2 * R */
+ MP_CHECKOK(group->point_dbl(rx, ry, rx, ry, group));
+ MP_CHECKOK(group->point_dbl(rx, ry, rx, ry, group));
+ /* R = R + (ai * A + bi * B) */
+ MP_CHECKOK(group->
+ point_add(rx, ry, &precomp[ai][bi][0],
+ &precomp[ai][bi][1], rx, ry, group));
+ }
+
+ if (group->meth->field_dec) {
+ MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
+ MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
+ }
+
+ CLEANUP:
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ mp_clear(&precomp[i][j][0]);
+ mp_clear(&precomp[i][j][1]);
+ }
+ }
+ return res;
+}
+
+/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G +
+ * k2 * P(x, y), where G is the generator (base point) of the group of
+ * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
+ * Input and output values are assumed to be NOT field-encoded. */
+mp_err
+ECPoints_mul(const ECGroup *group, const mp_int *k1, const mp_int *k2,
+ const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry,
+ int timing)
+{
+ mp_err res = MP_OKAY;
+ mp_int k1t, k2t;
+ const mp_int *k1p, *k2p;
+
+ MP_DIGITS(&k1t) = 0;
+ MP_DIGITS(&k2t) = 0;
+
+ ARGCHK(group != NULL, MP_BADARG);
+
+ /* want scalar to be less than or equal to group order */
+ if (k1 != NULL) {
+ if (mp_cmp(k1, &group->order) >= 0) {
+ MP_CHECKOK(mp_init(&k1t, FLAG(k1)));
+ MP_CHECKOK(mp_mod(k1, &group->order, &k1t));
+ k1p = &k1t;
+ } else {
+ k1p = k1;
+ }
+ } else {
+ k1p = k1;
+ }
+ if (k2 != NULL) {
+ if (mp_cmp(k2, &group->order) >= 0) {
+ MP_CHECKOK(mp_init(&k2t, FLAG(k2)));
+ MP_CHECKOK(mp_mod(k2, &group->order, &k2t));
+ k2p = &k2t;
+ } else {
+ k2p = k2;
+ }
+ } else {
+ k2p = k2;
+ }
+
+ /* if points_mul is defined, then use it */
+ if (group->points_mul) {
+ res = group->points_mul(k1p, k2p, px, py, rx, ry, group, timing);
+ } else {
+ res = ec_pts_mul_simul_w2(k1p, k2p, px, py, rx, ry, group, timing);
+ }
+
+ CLEANUP:
+ mp_clear(&k1t);
+ mp_clear(&k2t);
+ return res;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecp.h b/jdk.crypto.ec/share/native/libsunec/impl/ecp.h
new file mode 100644
index 0000000..b367b90
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecp.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ * Last Modified Date from the Original Code: May 2017
+ *********************************************************************** */
+
+#ifndef _ECP_H
+#define _ECP_H
+
+#include "ecl-priv.h"
+
+/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
+mp_err ec_GFp_pt_is_inf_aff(const mp_int *px, const mp_int *py);
+
+/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
+mp_err ec_GFp_pt_set_inf_aff(mp_int *px, mp_int *py);
+
+/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx,
+ * qy). Uses affine coordinates. */
+mp_err ec_GFp_pt_add_aff(const mp_int *px, const mp_int *py,
+ const mp_int *qx, const mp_int *qy, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+
+/* Computes R = P - Q. Uses affine coordinates. */
+mp_err ec_GFp_pt_sub_aff(const mp_int *px, const mp_int *py,
+ const mp_int *qx, const mp_int *qy, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+
+/* Computes R = 2P. Uses affine coordinates. */
+mp_err ec_GFp_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, const ECGroup *group);
+
+/* Validates a point on a GFp curve. */
+mp_err ec_GFp_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group);
+
+#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the prime that
+ * determines the field GFp. Uses affine coordinates. */
+mp_err ec_GFp_pt_mul_aff(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+#endif
+
+/* Converts a point P(px, py) from affine coordinates to Jacobian
+ * projective coordinates R(rx, ry, rz). */
+mp_err ec_GFp_pt_aff2jac(const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, mp_int *rz, const ECGroup *group);
+
+/* Converts a point P(px, py, pz) from Jacobian projective coordinates to
+ * affine coordinates R(rx, ry). */
+mp_err ec_GFp_pt_jac2aff(const mp_int *px, const mp_int *py,
+ const mp_int *pz, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+
+/* Checks if point P(px, py, pz) is at infinity. Uses Jacobian
+ * coordinates. */
+mp_err ec_GFp_pt_is_inf_jac(const mp_int *px, const mp_int *py,
+ const mp_int *pz);
+
+/* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian
+ * coordinates. */
+mp_err ec_GFp_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz);
+
+/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
+ * (qx, qy, qz). Uses Jacobian coordinates. */
+mp_err ec_GFp_pt_add_jac_aff(const mp_int *px, const mp_int *py,
+ const mp_int *pz, const mp_int *qx,
+ const mp_int *qy, mp_int *rx, mp_int *ry,
+ mp_int *rz, const ECGroup *group);
+
+/* Computes R = 2P. Uses Jacobian coordinates. */
+mp_err ec_GFp_pt_dbl_jac(const mp_int *px, const mp_int *py,
+ const mp_int *pz, mp_int *rx, mp_int *ry,
+ mp_int *rz, const ECGroup *group);
+
+#ifdef ECL_ENABLE_GFP_PT_MUL_JAC
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the prime that
+ * determines the field GFp. Uses Jacobian coordinates. */
+mp_err ec_GFp_pt_mul_jac(const mp_int *n, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group);
+#endif
+
+/* Computes R(x, y) = k1 * G + k2 * P(x, y), where G is the generator
+ * (base point) of the group of points on the elliptic curve. Allows k1 =
+ * NULL or { k2, P } = NULL. Implemented using mixed Jacobian-affine
+ * coordinates. Input and output values are assumed to be NOT
+ * field-encoded and are in affine form. */
+mp_err
+ ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group, int timing);
+
+/* Computes R = nP where R is (rx, ry) and P is the base point. Elliptic
+ * curve points P and R can be identical. Uses mixed Modified-Jacobian
+ * co-ordinates for doubling and Chudnovsky Jacobian coordinates for
+ * additions. Assumes input is already field-encoded using field_enc, and
+ * returns output that is still field-encoded. Uses 5-bit window NAF
+ * method (algorithm 11) for scalar-point multiplication from Brown,
+ * Hankerson, Lopez, Menezes. Software Implementation of the NIST Elliptic
+ * Curves Over Prime Fields. The implementation includes a countermeasure
+ * that attempts to hide the size of n from timing channels. This counter-
+ * measure is enabled using the timing argument. The high-rder bits of timing
+ * must be uniformly random in order for this countermeasure to work. */
+mp_err
+ ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py,
+ mp_int *rx, mp_int *ry, const ECGroup *group,
+ int timing);
+
+#endif /* _ECP_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecp_192.c b/jdk.crypto.ec/share/native/libsunec/impl/ecp_192.c
new file mode 100644
index 0000000..69b0d85
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecp_192.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ *********************************************************************** */
+
+#include "ecp.h"
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+#define ECP192_DIGITS ECL_CURVE_DIGITS(192)
+
+/* Fast modular reduction for p192 = 2^192 - 2^64 - 1. a can be r. Uses
+ * algorithm 7 from Brown, Hankerson, Lopez, Menezes. Software
+ * Implementation of the NIST Elliptic Curves over Prime Fields. */
+mp_err
+ec_GFp_nistp192_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_size a_used = MP_USED(a);
+ mp_digit r3;
+#ifndef MPI_AMD64_ADD
+ mp_digit carry;
+#endif
+#ifdef ECL_THIRTY_TWO_BIT
+ mp_digit a5a = 0, a5b = 0, a4a = 0, a4b = 0, a3a = 0, a3b = 0;
+ mp_digit r0a, r0b, r1a, r1b, r2a, r2b;
+#else
+ mp_digit a5 = 0, a4 = 0, a3 = 0;
+ mp_digit r0, r1, r2;
+#endif
+
+ /* reduction not needed if a is not larger than field size */
+ if (a_used < ECP192_DIGITS) {
+ if (a == r) {
+ return MP_OKAY;
+ }
+ return mp_copy(a, r);
+ }
+
+ /* for polynomials larger than twice the field size, use regular
+ * reduction */
+ if (a_used > ECP192_DIGITS*2) {
+ MP_CHECKOK(mp_mod(a, &meth->irr, r));
+ } else {
+ /* copy out upper words of a */
+
+#ifdef ECL_THIRTY_TWO_BIT
+
+ /* in all the math below,
+ * nXb is most signifiant, nXa is least significant */
+ switch (a_used) {
+ case 12:
+ a5b = MP_DIGIT(a, 11);
+ case 11:
+ a5a = MP_DIGIT(a, 10);
+ case 10:
+ a4b = MP_DIGIT(a, 9);
+ case 9:
+ a4a = MP_DIGIT(a, 8);
+ case 8:
+ a3b = MP_DIGIT(a, 7);
+ case 7:
+ a3a = MP_DIGIT(a, 6);
+ }
+
+
+ r2b= MP_DIGIT(a, 5);
+ r2a= MP_DIGIT(a, 4);
+ r1b = MP_DIGIT(a, 3);
+ r1a = MP_DIGIT(a, 2);
+ r0b = MP_DIGIT(a, 1);
+ r0a = MP_DIGIT(a, 0);
+
+ /* implement r = (a2,a1,a0)+(a5,a5,a5)+(a4,a4,0)+(0,a3,a3) */
+ MP_ADD_CARRY(r0a, a3a, r0a, 0, carry);
+ MP_ADD_CARRY(r0b, a3b, r0b, carry, carry);
+ MP_ADD_CARRY(r1a, a3a, r1a, carry, carry);
+ MP_ADD_CARRY(r1b, a3b, r1b, carry, carry);
+ MP_ADD_CARRY(r2a, a4a, r2a, carry, carry);
+ MP_ADD_CARRY(r2b, a4b, r2b, carry, carry);
+ r3 = carry; carry = 0;
+ MP_ADD_CARRY(r0a, a5a, r0a, 0, carry);
+ MP_ADD_CARRY(r0b, a5b, r0b, carry, carry);
+ MP_ADD_CARRY(r1a, a5a, r1a, carry, carry);
+ MP_ADD_CARRY(r1b, a5b, r1b, carry, carry);
+ MP_ADD_CARRY(r2a, a5a, r2a, carry, carry);
+ MP_ADD_CARRY(r2b, a5b, r2b, carry, carry);
+ r3 += carry;
+ MP_ADD_CARRY(r1a, a4a, r1a, 0, carry);
+ MP_ADD_CARRY(r1b, a4b, r1b, carry, carry);
+ MP_ADD_CARRY(r2a, 0, r2a, carry, carry);
+ MP_ADD_CARRY(r2b, 0, r2b, carry, carry);
+ r3 += carry;
+
+ /* reduce out the carry */
+ while (r3) {
+ MP_ADD_CARRY(r0a, r3, r0a, 0, carry);
+ MP_ADD_CARRY(r0b, 0, r0b, carry, carry);
+ MP_ADD_CARRY(r1a, r3, r1a, carry, carry);
+ MP_ADD_CARRY(r1b, 0, r1b, carry, carry);
+ MP_ADD_CARRY(r2a, 0, r2a, carry, carry);
+ MP_ADD_CARRY(r2b, 0, r2b, carry, carry);
+ r3 = carry;
+ }
+
+ /* check for final reduction */
+ /*
+ * our field is 0xffffffffffffffff, 0xfffffffffffffffe,
+ * 0xffffffffffffffff. That means we can only be over and need
+ * one more reduction
+ * if r2 == 0xffffffffffffffffff (same as r2+1 == 0)
+ * and
+ * r1 == 0xffffffffffffffffff or
+ * r1 == 0xfffffffffffffffffe and r0 = 0xfffffffffffffffff
+ * In all cases, we subtract the field (or add the 2's
+ * complement value (1,1,0)). (r0, r1, r2)
+ */
+ if (((r2b == 0xffffffff) && (r2a == 0xffffffff)
+ && (r1b == 0xffffffff) ) &&
+ ((r1a == 0xffffffff) ||
+ (r1a == 0xfffffffe) && (r0a == 0xffffffff) &&
+ (r0b == 0xffffffff)) ) {
+ /* do a quick subtract */
+ MP_ADD_CARRY(r0a, 1, r0a, 0, carry);
+ r0b += carry;
+ r1a = r1b = r2a = r2b = 0;
+ }
+
+ /* set the lower words of r */
+ if (a != r) {
+ MP_CHECKOK(s_mp_pad(r, 6));
+ }
+ MP_DIGIT(r, 5) = r2b;
+ MP_DIGIT(r, 4) = r2a;
+ MP_DIGIT(r, 3) = r1b;
+ MP_DIGIT(r, 2) = r1a;
+ MP_DIGIT(r, 1) = r0b;
+ MP_DIGIT(r, 0) = r0a;
+ MP_USED(r) = 6;
+#else
+ switch (a_used) {
+ case 6:
+ a5 = MP_DIGIT(a, 5);
+ case 5:
+ a4 = MP_DIGIT(a, 4);
+ case 4:
+ a3 = MP_DIGIT(a, 3);
+ }
+
+ r2 = MP_DIGIT(a, 2);
+ r1 = MP_DIGIT(a, 1);
+ r0 = MP_DIGIT(a, 0);
+
+ /* implement r = (a2,a1,a0)+(a5,a5,a5)+(a4,a4,0)+(0,a3,a3) */
+#ifndef MPI_AMD64_ADD
+ MP_ADD_CARRY_ZERO(r0, a3, r0, carry);
+ MP_ADD_CARRY(r1, a3, r1, carry, carry);
+ MP_ADD_CARRY(r2, a4, r2, carry, carry);
+ r3 = carry;
+ MP_ADD_CARRY_ZERO(r0, a5, r0, carry);
+ MP_ADD_CARRY(r1, a5, r1, carry, carry);
+ MP_ADD_CARRY(r2, a5, r2, carry, carry);
+ r3 += carry;
+ MP_ADD_CARRY_ZERO(r1, a4, r1, carry);
+ MP_ADD_CARRY(r2, 0, r2, carry, carry);
+ r3 += carry;
+
+#else
+ r2 = MP_DIGIT(a, 2);
+ r1 = MP_DIGIT(a, 1);
+ r0 = MP_DIGIT(a, 0);
+
+ /* set the lower words of r */
+ __asm__ (
+ "xorq %3,%3 \n\t"
+ "addq %4,%0 \n\t"
+ "adcq %4,%1 \n\t"
+ "adcq %5,%2 \n\t"
+ "adcq $0,%3 \n\t"
+ "addq %6,%0 \n\t"
+ "adcq %6,%1 \n\t"
+ "adcq %6,%2 \n\t"
+ "adcq $0,%3 \n\t"
+ "addq %5,%1 \n\t"
+ "adcq $0,%2 \n\t"
+ "adcq $0,%3 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(a3),
+ "=r"(a4), "=r"(a5)
+ : "0" (r0), "1" (r1), "2" (r2), "3" (r3),
+ "4" (a3), "5" (a4), "6"(a5)
+ : "%cc" );
+#endif
+
+ /* reduce out the carry */
+ while (r3) {
+#ifndef MPI_AMD64_ADD
+ MP_ADD_CARRY_ZERO(r0, r3, r0, carry);
+ MP_ADD_CARRY(r1, r3, r1, carry, carry);
+ MP_ADD_CARRY(r2, 0, r2, carry, carry);
+ r3 = carry;
+#else
+ a3=r3;
+ __asm__ (
+ "xorq %3,%3 \n\t"
+ "addq %4,%0 \n\t"
+ "adcq %4,%1 \n\t"
+ "adcq $0,%2 \n\t"
+ "adcq $0,%3 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(a3)
+ : "0" (r0), "1" (r1), "2" (r2), "3" (r3), "4"(a3)
+ : "%cc" );
+#endif
+ }
+
+ /* check for final reduction */
+ /*
+ * our field is 0xffffffffffffffff, 0xfffffffffffffffe,
+ * 0xffffffffffffffff. That means we can only be over and need
+ * one more reduction
+ * if r2 == 0xffffffffffffffffff (same as r2+1 == 0)
+ * and
+ * r1 == 0xffffffffffffffffff or
+ * r1 == 0xfffffffffffffffffe and r0 = 0xfffffffffffffffff
+ * In all cases, we subtract the field (or add the 2's
+ * complement value (1,1,0)). (r0, r1, r2)
+ */
+ if (r3 || ((r2 == MP_DIGIT_MAX) &&
+ ((r1 == MP_DIGIT_MAX) ||
+ ((r1 == (MP_DIGIT_MAX-1)) && (r0 == MP_DIGIT_MAX))))) {
+ /* do a quick subtract */
+ r0++;
+ r1 = r2 = 0;
+ }
+ /* set the lower words of r */
+ if (a != r) {
+ MP_CHECKOK(s_mp_pad(r, 3));
+ }
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ MP_USED(r) = 3;
+#endif
+ }
+
+ CLEANUP:
+ return res;
+}
+
+#ifndef ECL_THIRTY_TWO_BIT
+/* Compute the sum of 192 bit curves. Do the work in-line since the
+ * number of words are so small, we don't want to overhead of mp function
+ * calls. Uses optimized modular reduction for p192.
+ */
+mp_err
+ec_GFp_nistp192_add(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit a0 = 0, a1 = 0, a2 = 0;
+ mp_digit r0 = 0, r1 = 0, r2 = 0;
+ mp_digit carry;
+
+ switch(MP_USED(a)) {
+ case 3:
+ a2 = MP_DIGIT(a,2);
+ case 2:
+ a1 = MP_DIGIT(a,1);
+ case 1:
+ a0 = MP_DIGIT(a,0);
+ }
+ switch(MP_USED(b)) {
+ case 3:
+ r2 = MP_DIGIT(b,2);
+ case 2:
+ r1 = MP_DIGIT(b,1);
+ case 1:
+ r0 = MP_DIGIT(b,0);
+ }
+
+#ifndef MPI_AMD64_ADD
+ MP_ADD_CARRY_ZERO(a0, r0, r0, carry);
+ MP_ADD_CARRY(a1, r1, r1, carry, carry);
+ MP_ADD_CARRY(a2, r2, r2, carry, carry);
+#else
+ __asm__ (
+ "xorq %3,%3 \n\t"
+ "addq %4,%0 \n\t"
+ "adcq %5,%1 \n\t"
+ "adcq %6,%2 \n\t"
+ "adcq $0,%3 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(carry)
+ : "r" (a0), "r" (a1), "r" (a2), "0" (r0),
+ "1" (r1), "2" (r2)
+ : "%cc" );
+#endif
+
+ /* Do quick 'subract' if we've gone over
+ * (add the 2's complement of the curve field) */
+ if (carry || ((r2 == MP_DIGIT_MAX) &&
+ ((r1 == MP_DIGIT_MAX) ||
+ ((r1 == (MP_DIGIT_MAX-1)) && (r0 == MP_DIGIT_MAX))))) {
+#ifndef MPI_AMD64_ADD
+ MP_ADD_CARRY_ZERO(r0, 1, r0, carry);
+ MP_ADD_CARRY(r1, 1, r1, carry, carry);
+ MP_ADD_CARRY(r2, 0, r2, carry, carry);
+#else
+ __asm__ (
+ "addq $1,%0 \n\t"
+ "adcq $1,%1 \n\t"
+ "adcq $0,%2 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2)
+ : "0" (r0), "1" (r1), "2" (r2)
+ : "%cc" );
+#endif
+ }
+
+
+ MP_CHECKOK(s_mp_pad(r, 3));
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 3;
+ s_mp_clamp(r);
+
+
+ CLEANUP:
+ return res;
+}
+
+/* Compute the diff of 192 bit curves. Do the work in-line since the
+ * number of words are so small, we don't want to overhead of mp function
+ * calls. Uses optimized modular reduction for p192.
+ */
+mp_err
+ec_GFp_nistp192_sub(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_digit b0 = 0, b1 = 0, b2 = 0;
+ mp_digit r0 = 0, r1 = 0, r2 = 0;
+ mp_digit borrow;
+
+ switch(MP_USED(a)) {
+ case 3:
+ r2 = MP_DIGIT(a,2);
+ case 2:
+ r1 = MP_DIGIT(a,1);
+ case 1:
+ r0 = MP_DIGIT(a,0);
+ }
+
+ switch(MP_USED(b)) {
+ case 3:
+ b2 = MP_DIGIT(b,2);
+ case 2:
+ b1 = MP_DIGIT(b,1);
+ case 1:
+ b0 = MP_DIGIT(b,0);
+ }
+
+#ifndef MPI_AMD64_ADD
+ MP_SUB_BORROW(r0, b0, r0, 0, borrow);
+ MP_SUB_BORROW(r1, b1, r1, borrow, borrow);
+ MP_SUB_BORROW(r2, b2, r2, borrow, borrow);
+#else
+ __asm__ (
+ "xorq %3,%3 \n\t"
+ "subq %4,%0 \n\t"
+ "sbbq %5,%1 \n\t"
+ "sbbq %6,%2 \n\t"
+ "adcq $0,%3 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(borrow)
+ : "r" (b0), "r" (b1), "r" (b2), "0" (r0),
+ "1" (r1), "2" (r2)
+ : "%cc" );
+#endif
+
+ /* Do quick 'add' if we've gone under 0
+ * (subtract the 2's complement of the curve field) */
+ if (borrow) {
+#ifndef MPI_AMD64_ADD
+ MP_SUB_BORROW(r0, 1, r0, 0, borrow);
+ MP_SUB_BORROW(r1, 1, r1, borrow, borrow);
+ MP_SUB_BORROW(r2, 0, r2, borrow, borrow);
+#else
+ __asm__ (
+ "subq $1,%0 \n\t"
+ "sbbq $1,%1 \n\t"
+ "sbbq $0,%2 \n\t"
+ : "=r"(r0), "=r"(r1), "=r"(r2)
+ : "0" (r0), "1" (r1), "2" (r2)
+ : "%cc" );
+#endif
+ }
+
+ MP_CHECKOK(s_mp_pad(r, 3));
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 3;
+ s_mp_clamp(r);
+
+ CLEANUP:
+ return res;
+}
+
+#endif
+
+/* Compute the square of polynomial a, reduce modulo p192. Store the
+ * result in r. r could be a. Uses optimized modular reduction for p192.
+ */
+mp_err
+ec_GFp_nistp192_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ MP_CHECKOK(mp_sqr(a, r));
+ MP_CHECKOK(ec_GFp_nistp192_mod(r, r, meth));
+ CLEANUP:
+ return res;
+}
+
+/* Compute the product of two polynomials a and b, reduce modulo p192.
+ * Store the result in r. r could be a or b; a could be b. Uses
+ * optimized modular reduction for p192. */
+mp_err
+ec_GFp_nistp192_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ MP_CHECKOK(mp_mul(a, b, r));
+ MP_CHECKOK(ec_GFp_nistp192_mod(r, r, meth));
+ CLEANUP:
+ return res;
+}
+
+/* Divides two field elements. If a is NULL, then returns the inverse of
+ * b. */
+mp_err
+ec_GFp_nistp192_div(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_int t;
+
+ /* If a is NULL, then return the inverse of b, otherwise return a/b. */
+ if (a == NULL) {
+ return mp_invmod(b, &meth->irr, r);
+ } else {
+ /* MPI doesn't support divmod, so we implement it using invmod and
+ * mulmod. */
+ MP_CHECKOK(mp_init(&t, FLAG(b)));
+ MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
+ MP_CHECKOK(mp_mul(a, &t, r));
+ MP_CHECKOK(ec_GFp_nistp192_mod(r, r, meth));
+ CLEANUP:
+ mp_clear(&t);
+ return res;
+ }
+}
+
+/* Wire in fast field arithmetic and precomputation of base point for
+ * named curves. */
+mp_err
+ec_group_set_gfp192(ECGroup *group, ECCurveName name)
+{
+ if (name == ECCurve_NIST_P192) {
+ group->meth->field_mod = &ec_GFp_nistp192_mod;
+ group->meth->field_mul = &ec_GFp_nistp192_mul;
+ group->meth->field_sqr = &ec_GFp_nistp192_sqr;
+ group->meth->field_div = &ec_GFp_nistp192_div;
+#ifndef ECL_THIRTY_TWO_BIT
+ group->meth->field_add = &ec_GFp_nistp192_add;
+ group->meth->field_sub = &ec_GFp_nistp192_sub;
+#endif
+ }
+ return MP_OKAY;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecp_224.c b/jdk.crypto.ec/share/native/libsunec/impl/ecp_224.c
new file mode 100644
index 0000000..b2901e0
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecp_224.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ *********************************************************************** */
+
+#include "ecp.h"
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+#define ECP224_DIGITS ECL_CURVE_DIGITS(224)
+
+/* Fast modular reduction for p224 = 2^224 - 2^96 + 1. a can be r. Uses
+ * algorithm 7 from Brown, Hankerson, Lopez, Menezes. Software
+ * Implementation of the NIST Elliptic Curves over Prime Fields. */
+mp_err
+ec_GFp_nistp224_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_size a_used = MP_USED(a);
+
+ int r3b;
+ mp_digit carry;
+#ifdef ECL_THIRTY_TWO_BIT
+ mp_digit a6a = 0, a6b = 0,
+ a5a = 0, a5b = 0, a4a = 0, a4b = 0, a3a = 0, a3b = 0;
+ mp_digit r0a, r0b, r1a, r1b, r2a, r2b, r3a;
+#else
+ mp_digit a6 = 0, a5 = 0, a4 = 0, a3b = 0, a5a = 0;
+ mp_digit a6b = 0, a6a_a5b = 0, a5b = 0, a5a_a4b = 0, a4a_a3b = 0;
+ mp_digit r0, r1, r2, r3;
+#endif
+
+ /* reduction not needed if a is not larger than field size */
+ if (a_used < ECP224_DIGITS) {
+ if (a == r) return MP_OKAY;
+ return mp_copy(a, r);
+ }
+ /* for polynomials larger than twice the field size, use regular
+ * reduction */
+ if (a_used > ECL_CURVE_DIGITS(224*2)) {
+ MP_CHECKOK(mp_mod(a, &meth->irr, r));
+ } else {
+#ifdef ECL_THIRTY_TWO_BIT
+ /* copy out upper words of a */
+ switch (a_used) {
+ case 14:
+ a6b = MP_DIGIT(a, 13);
+ case 13:
+ a6a = MP_DIGIT(a, 12);
+ case 12:
+ a5b = MP_DIGIT(a, 11);
+ case 11:
+ a5a = MP_DIGIT(a, 10);
+ case 10:
+ a4b = MP_DIGIT(a, 9);
+ case 9:
+ a4a = MP_DIGIT(a, 8);
+ case 8:
+ a3b = MP_DIGIT(a, 7);
+ }
+ r3a = MP_DIGIT(a, 6);
+ r2b= MP_DIGIT(a, 5);
+ r2a= MP_DIGIT(a, 4);
+ r1b = MP_DIGIT(a, 3);
+ r1a = MP_DIGIT(a, 2);
+ r0b = MP_DIGIT(a, 1);
+ r0a = MP_DIGIT(a, 0);
+
+
+ /* implement r = (a3a,a2,a1,a0)
+ +(a5a, a4,a3b, 0)
+ +( 0, a6,a5b, 0)
+ -( 0 0, 0|a6b, a6a|a5b )
+ -( a6b, a6a|a5b, a5a|a4b, a4a|a3b ) */
+ MP_ADD_CARRY (r1b, a3b, r1b, 0, carry);
+ MP_ADD_CARRY (r2a, a4a, r2a, carry, carry);
+ MP_ADD_CARRY (r2b, a4b, r2b, carry, carry);
+ MP_ADD_CARRY (r3a, a5a, r3a, carry, carry);
+ r3b = carry;
+ MP_ADD_CARRY (r1b, a5b, r1b, 0, carry);
+ MP_ADD_CARRY (r2a, a6a, r2a, carry, carry);
+ MP_ADD_CARRY (r2b, a6b, r2b, carry, carry);
+ MP_ADD_CARRY (r3a, 0, r3a, carry, carry);
+ r3b += carry;
+ MP_SUB_BORROW(r0a, a3b, r0a, 0, carry);
+ MP_SUB_BORROW(r0b, a4a, r0b, carry, carry);
+ MP_SUB_BORROW(r1a, a4b, r1a, carry, carry);
+ MP_SUB_BORROW(r1b, a5a, r1b, carry, carry);
+ MP_SUB_BORROW(r2a, a5b, r2a, carry, carry);
+ MP_SUB_BORROW(r2b, a6a, r2b, carry, carry);
+ MP_SUB_BORROW(r3a, a6b, r3a, carry, carry);
+ r3b -= carry;
+ MP_SUB_BORROW(r0a, a5b, r0a, 0, carry);
+ MP_SUB_BORROW(r0b, a6a, r0b, carry, carry);
+ MP_SUB_BORROW(r1a, a6b, r1a, carry, carry);
+ if (carry) {
+ MP_SUB_BORROW(r1b, 0, r1b, carry, carry);
+ MP_SUB_BORROW(r2a, 0, r2a, carry, carry);
+ MP_SUB_BORROW(r2b, 0, r2b, carry, carry);
+ MP_SUB_BORROW(r3a, 0, r3a, carry, carry);
+ r3b -= carry;
+ }
+
+ while (r3b > 0) {
+ int tmp;
+ MP_ADD_CARRY(r1b, r3b, r1b, 0, carry);
+ if (carry) {
+ MP_ADD_CARRY(r2a, 0, r2a, carry, carry);
+ MP_ADD_CARRY(r2b, 0, r2b, carry, carry);
+ MP_ADD_CARRY(r3a, 0, r3a, carry, carry);
+ }
+ tmp = carry;
+ MP_SUB_BORROW(r0a, r3b, r0a, 0, carry);
+ if (carry) {
+ MP_SUB_BORROW(r0b, 0, r0b, carry, carry);
+ MP_SUB_BORROW(r1a, 0, r1a, carry, carry);
+ MP_SUB_BORROW(r1b, 0, r1b, carry, carry);
+ MP_SUB_BORROW(r2a, 0, r2a, carry, carry);
+ MP_SUB_BORROW(r2b, 0, r2b, carry, carry);
+ MP_SUB_BORROW(r3a, 0, r3a, carry, carry);
+ tmp -= carry;
+ }
+ r3b = tmp;
+ }
+
+ while (r3b < 0) {
+ mp_digit maxInt = MP_DIGIT_MAX;
+ MP_ADD_CARRY (r0a, 1, r0a, 0, carry);
+ MP_ADD_CARRY (r0b, 0, r0b, carry, carry);
+ MP_ADD_CARRY (r1a, 0, r1a, carry, carry);
+ MP_ADD_CARRY (r1b, maxInt, r1b, carry, carry);
+ MP_ADD_CARRY (r2a, maxInt, r2a, carry, carry);
+ MP_ADD_CARRY (r2b, maxInt, r2b, carry, carry);
+ MP_ADD_CARRY (r3a, maxInt, r3a, carry, carry);
+ r3b += carry;
+ }
+ /* check for final reduction */
+ /* now the only way we are over is if the top 4 words are all ones */
+ if ((r3a == MP_DIGIT_MAX) && (r2b == MP_DIGIT_MAX)
+ && (r2a == MP_DIGIT_MAX) && (r1b == MP_DIGIT_MAX) &&
+ ((r1a != 0) || (r0b != 0) || (r0a != 0)) ) {
+ /* one last subraction */
+ MP_SUB_BORROW(r0a, 1, r0a, 0, carry);
+ MP_SUB_BORROW(r0b, 0, r0b, carry, carry);
+ MP_SUB_BORROW(r1a, 0, r1a, carry, carry);
+ r1b = r2a = r2b = r3a = 0;
+ }
+
+
+ if (a != r) {
+ MP_CHECKOK(s_mp_pad(r, 7));
+ }
+ /* set the lower words of r */
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 7;
+ MP_DIGIT(r, 6) = r3a;
+ MP_DIGIT(r, 5) = r2b;
+ MP_DIGIT(r, 4) = r2a;
+ MP_DIGIT(r, 3) = r1b;
+ MP_DIGIT(r, 2) = r1a;
+ MP_DIGIT(r, 1) = r0b;
+ MP_DIGIT(r, 0) = r0a;
+#else
+ /* copy out upper words of a */
+ switch (a_used) {
+ case 7:
+ a6 = MP_DIGIT(a, 6);
+ a6b = a6 >> 32;
+ a6a_a5b = a6 << 32;
+ case 6:
+ a5 = MP_DIGIT(a, 5);
+ a5b = a5 >> 32;
+ a6a_a5b |= a5b;
+ a5b = a5b << 32;
+ a5a_a4b = a5 << 32;
+ a5a = a5 & 0xffffffff;
+ case 5:
+ a4 = MP_DIGIT(a, 4);
+ a5a_a4b |= a4 >> 32;
+ a4a_a3b = a4 << 32;
+ case 4:
+ a3b = MP_DIGIT(a, 3) >> 32;
+ a4a_a3b |= a3b;
+ a3b = a3b << 32;
+ }
+
+ r3 = MP_DIGIT(a, 3) & 0xffffffff;
+ r2 = MP_DIGIT(a, 2);
+ r1 = MP_DIGIT(a, 1);
+ r0 = MP_DIGIT(a, 0);
+
+ /* implement r = (a3a,a2,a1,a0)
+ +(a5a, a4,a3b, 0)
+ +( 0, a6,a5b, 0)
+ -( 0 0, 0|a6b, a6a|a5b )
+ -( a6b, a6a|a5b, a5a|a4b, a4a|a3b ) */
+ MP_ADD_CARRY_ZERO (r1, a3b, r1, carry);
+ MP_ADD_CARRY (r2, a4 , r2, carry, carry);
+ MP_ADD_CARRY (r3, a5a, r3, carry, carry);
+ MP_ADD_CARRY_ZERO (r1, a5b, r1, carry);
+ MP_ADD_CARRY (r2, a6 , r2, carry, carry);
+ MP_ADD_CARRY (r3, 0, r3, carry, carry);
+
+ MP_SUB_BORROW(r0, a4a_a3b, r0, 0, carry);
+ MP_SUB_BORROW(r1, a5a_a4b, r1, carry, carry);
+ MP_SUB_BORROW(r2, a6a_a5b, r2, carry, carry);
+ MP_SUB_BORROW(r3, a6b , r3, carry, carry);
+ MP_SUB_BORROW(r0, a6a_a5b, r0, 0, carry);
+ MP_SUB_BORROW(r1, a6b , r1, carry, carry);
+ if (carry) {
+ MP_SUB_BORROW(r2, 0, r2, carry, carry);
+ MP_SUB_BORROW(r3, 0, r3, carry, carry);
+ }
+
+
+ /* if the value is negative, r3 has a 2's complement
+ * high value */
+ r3b = (int)(r3 >>32);
+ while (r3b > 0) {
+ r3 &= 0xffffffff;
+ MP_ADD_CARRY_ZERO(r1,((mp_digit)r3b) << 32, r1, carry);
+ if (carry) {
+ MP_ADD_CARRY(r2, 0, r2, carry, carry);
+ MP_ADD_CARRY(r3, 0, r3, carry, carry);
+ }
+ MP_SUB_BORROW(r0, r3b, r0, 0, carry);
+ if (carry) {
+ MP_SUB_BORROW(r1, 0, r1, carry, carry);
+ MP_SUB_BORROW(r2, 0, r2, carry, carry);
+ MP_SUB_BORROW(r3, 0, r3, carry, carry);
+ }
+ r3b = (int)(r3 >>32);
+ }
+
+ while (r3b < 0) {
+ MP_ADD_CARRY_ZERO (r0, 1, r0, carry);
+ MP_ADD_CARRY (r1, MP_DIGIT_MAX <<32, r1, carry, carry);
+ MP_ADD_CARRY (r2, MP_DIGIT_MAX, r2, carry, carry);
+ MP_ADD_CARRY (r3, MP_DIGIT_MAX >> 32, r3, carry, carry);
+ r3b = (int)(r3 >>32);
+ }
+ /* check for final reduction */
+ /* now the only way we are over is if the top 4 words are all ones */
+ if ((r3 == (MP_DIGIT_MAX >> 32)) && (r2 == MP_DIGIT_MAX)
+ && ((r1 & MP_DIGIT_MAX << 32)== MP_DIGIT_MAX << 32) &&
+ ((r1 != MP_DIGIT_MAX << 32 ) || (r0 != 0)) ) {
+ /* one last subraction */
+ MP_SUB_BORROW(r0, 1, r0, 0, carry);
+ MP_SUB_BORROW(r1, 0, r1, carry, carry);
+ r2 = r3 = 0;
+ }
+
+
+ if (a != r) {
+ MP_CHECKOK(s_mp_pad(r, 4));
+ }
+ /* set the lower words of r */
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 4;
+ MP_DIGIT(r, 3) = r3;
+ MP_DIGIT(r, 2) = r2;
+ MP_DIGIT(r, 1) = r1;
+ MP_DIGIT(r, 0) = r0;
+#endif
+ }
+
+ CLEANUP:
+ return res;
+}
+
+/* Compute the square of polynomial a, reduce modulo p224. Store the
+ * result in r. r could be a. Uses optimized modular reduction for p224.
+ */
+mp_err
+ec_GFp_nistp224_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ MP_CHECKOK(mp_sqr(a, r));
+ MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth));
+ CLEANUP:
+ return res;
+}
+
+/* Compute the product of two polynomials a and b, reduce modulo p224.
+ * Store the result in r. r could be a or b; a could be b. Uses
+ * optimized modular reduction for p224. */
+mp_err
+ec_GFp_nistp224_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ MP_CHECKOK(mp_mul(a, b, r));
+ MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth));
+ CLEANUP:
+ return res;
+}
+
+/* Divides two field elements. If a is NULL, then returns the inverse of
+ * b. */
+mp_err
+ec_GFp_nistp224_div(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_int t;
+
+ /* If a is NULL, then return the inverse of b, otherwise return a/b. */
+ if (a == NULL) {
+ return mp_invmod(b, &meth->irr, r);
+ } else {
+ /* MPI doesn't support divmod, so we implement it using invmod and
+ * mulmod. */
+ MP_CHECKOK(mp_init(&t, FLAG(b)));
+ MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
+ MP_CHECKOK(mp_mul(a, &t, r));
+ MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth));
+ CLEANUP:
+ mp_clear(&t);
+ return res;
+ }
+}
+
+/* Wire in fast field arithmetic and precomputation of base point for
+ * named curves. */
+mp_err
+ec_group_set_gfp224(ECGroup *group, ECCurveName name)
+{
+ if (name == ECCurve_NIST_P224) {
+ group->meth->field_mod = &ec_GFp_nistp224_mod;
+ group->meth->field_mul = &ec_GFp_nistp224_mul;
+ group->meth->field_sqr = &ec_GFp_nistp224_sqr;
+ group->meth->field_div = &ec_GFp_nistp224_div;
+ }
+ return MP_OKAY;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecp_256.c b/jdk.crypto.ec/share/native/libsunec/impl/ecp_256.c
new file mode 100644
index 0000000..a5a5fa3
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecp_256.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>
+ *
+ *********************************************************************** */
+
+#include "ecp.h"
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+/* Fast modular reduction for p256 = 2^256 - 2^224 + 2^192+ 2^96 - 1. a can be r.
+ * Uses algorithm 2.29 from Hankerson, Menezes, Vanstone. Guide to
+ * Elliptic Curve Cryptography. */
+mp_err
+ec_GFp_nistp256_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_size a_used = MP_USED(a);
+ int a_bits = mpl_significant_bits(a);
+ mp_digit carry;
+
+#ifdef ECL_THIRTY_TWO_BIT
+ mp_digit a8=0, a9=0, a10=0, a11=0, a12=0, a13=0, a14=0, a15=0;
+ mp_digit r0, r1, r2, r3, r4, r5, r6, r7;
+ int r8; /* must be a signed value ! */
+#else
+ mp_digit a4=0, a5=0, a6=0, a7=0;
+ mp_digit a4h, a4l, a5h, a5l, a6h, a6l, a7h, a7l;
+ mp_digit r0, r1, r2, r3;
+ int r4; /* must be a signed value ! */
+#endif
+ /* for polynomials larger than twice the field size
+ * use regular reduction */
+ if (a_bits < 256) {
+ if (a == r) return MP_OKAY;
+ return mp_copy(a,r);
+ }
+ if (a_bits > 512) {
+ MP_CHECKOK(mp_mod(a, &meth->irr, r));
+ } else {
+
+#ifdef ECL_THIRTY_TWO_BIT
+ switch (a_used) {
+ case 16:
+ a15 = MP_DIGIT(a,15);
+ case 15:
+ a14 = MP_DIGIT(a,14);
+ case 14:
+ a13 = MP_DIGIT(a,13);
+ case 13:
+ a12 = MP_DIGIT(a,12);
+ case 12:
+ a11 = MP_DIGIT(a,11);
+ case 11:
+ a10 = MP_DIGIT(a,10);
+ case 10:
+ a9 = MP_DIGIT(a,9);
+ case 9:
+ a8 = MP_DIGIT(a,8);
+ }
+
+ r0 = MP_DIGIT(a,0);
+ r1 = MP_DIGIT(a,1);
+ r2 = MP_DIGIT(a,2);
+ r3 = MP_DIGIT(a,3);
+ r4 = MP_DIGIT(a,4);
+ r5 = MP_DIGIT(a,5);
+ r6 = MP_DIGIT(a,6);
+ r7 = MP_DIGIT(a,7);
+
+ /* sum 1 */
+ MP_ADD_CARRY(r3, a11, r3, 0, carry);
+ MP_ADD_CARRY(r4, a12, r4, carry, carry);
+ MP_ADD_CARRY(r5, a13, r5, carry, carry);
+ MP_ADD_CARRY(r6, a14, r6, carry, carry);
+ MP_ADD_CARRY(r7, a15, r7, carry, carry);
+ r8 = carry;
+ MP_ADD_CARRY(r3, a11, r3, 0, carry);
+ MP_ADD_CARRY(r4, a12, r4, carry, carry);
+ MP_ADD_CARRY(r5, a13, r5, carry, carry);
+ MP_ADD_CARRY(r6, a14, r6, carry, carry);
+ MP_ADD_CARRY(r7, a15, r7, carry, carry);
+ r8 += carry;
+ /* sum 2 */
+ MP_ADD_CARRY(r3, a12, r3, 0, carry);
+ MP_ADD_CARRY(r4, a13, r4, carry, carry);
+ MP_ADD_CARRY(r5, a14, r5, carry, carry);
+ MP_ADD_CARRY(r6, a15, r6, carry, carry);
+ MP_ADD_CARRY(r7, 0, r7, carry, carry);
+ r8 += carry;
+ /* combine last bottom of sum 3 with second sum 2 */
+ MP_ADD_CARRY(r0, a8, r0, 0, carry);
+ MP_ADD_CARRY(r1, a9, r1, carry, carry);
+ MP_ADD_CARRY(r2, a10, r2, carry, carry);
+ MP_ADD_CARRY(r3, a12, r3, carry, carry);
+ MP_ADD_CARRY(r4, a13, r4, carry, carry);
+ MP_ADD_CARRY(r5, a14, r5, carry, carry);
+ MP_ADD_CARRY(r6, a15, r6, carry, carry);
+ MP_ADD_CARRY(r7, a15, r7, carry, carry); /* from sum 3 */
+ r8 += carry;
+ /* sum 3 (rest of it)*/
+ MP_ADD_CARRY(r6, a14, r6, 0, carry);
+ MP_ADD_CARRY(r7, 0, r7, carry, carry);
+ r8 += carry;
+ /* sum 4 (rest of it)*/
+ MP_ADD_CARRY(r0, a9, r0, 0, carry);
+ MP_ADD_CARRY(r1, a10, r1, carry, carry);
+ MP_ADD_CARRY(r2, a11, r2, carry, carry);
+ MP_ADD_CARRY(r3, a13, r3, carry, carry);
+ MP_ADD_CARRY(r4, a14, r4, carry, carry);
+ MP_ADD_CARRY(r5, a15, r5, carry, carry);
+ MP_ADD_CARRY(r6, a13, r6, carry, carry);
+ MP_ADD_CARRY(r7, a8, r7, carry, carry);
+ r8 += carry;
+ /* diff 5 */
+ MP_SUB_BORROW(r0, a11, r0, 0, carry);
+ MP_SUB_BORROW(r1, a12, r1, carry, carry);
+ MP_SUB_BORROW(r2, a13, r2, carry, carry);
+ MP_SUB_BORROW(r3, 0, r3, carry, carry);
+ MP_SUB_BORROW(r4, 0, r4, carry, carry);
+ MP_SUB_BORROW(r5, 0, r5, carry, carry);
+ MP_SUB_BORROW(r6, a8, r6, carry, carry);
+ MP_SUB_BORROW(r7, a10, r7, carry, carry);
+ r8 -= carry;
+ /* diff 6 */
+ MP_SUB_BORROW(r0, a12, r0, 0, carry);
+ MP_SUB_BORROW(r1, a13, r1, carry, carry);
+ MP_SUB_BORROW(r2, a14, r2, carry, carry);
+ MP_SUB_BORROW(r3, a15, r3, carry, carry);
+ MP_SUB_BORROW(r4, 0, r4, carry, carry);
+ MP_SUB_BORROW(r5, 0, r5, carry, carry);
+ MP_SUB_BORROW(r6, a9, r6, carry, carry);
+ MP_SUB_BORROW(r7, a11, r7, carry, carry);
+ r8 -= carry;
+ /* diff 7 */
+ MP_SUB_BORROW(r0, a13, r0, 0, carry);
+ MP_SUB_BORROW(r1, a14, r1, carry, carry);
+ MP_SUB_BORROW(r2, a15, r2, carry, carry);
+ MP_SUB_BORROW(r3, a8, r3, carry, carry);
+ MP_SUB_BORROW(r4, a9, r4, carry, carry);
+ MP_SUB_BORROW(r5, a10, r5, carry, carry);
+ MP_SUB_BORROW(r6, 0, r6, carry, carry);
+ MP_SUB_BORROW(r7, a12, r7, carry, carry);
+ r8 -= carry;
+ /* diff 8 */
+ MP_SUB_BORROW(r0, a14, r0, 0, carry);
+ MP_SUB_BORROW(r1, a15, r1, carry, carry);
+ MP_SUB_BORROW(r2, 0, r2, carry, carry);
+ MP_SUB_BORROW(r3, a9, r3, carry, carry);
+ MP_SUB_BORROW(r4, a10, r4, carry, carry);
+ MP_SUB_BORROW(r5, a11, r5, carry, carry);
+ MP_SUB_BORROW(r6, 0, r6, carry, carry);
+ MP_SUB_BORROW(r7, a13, r7, carry, carry);
+ r8 -= carry;
+
+ /* reduce the overflows */
+ while (r8 > 0) {
+ mp_digit r8_d = r8;
+ MP_ADD_CARRY(r0, r8_d, r0, 0, carry);
+ MP_ADD_CARRY(r1, 0, r1, carry, carry);
+ MP_ADD_CARRY(r2, 0, r2, carry, carry);
+ MP_ADD_CARRY(r3, -r8_d, r3, carry, carry);
+ MP_ADD_CARRY(r4, MP_DIGIT_MAX, r4, carry, carry);
+ MP_ADD_CARRY(r5, MP_DIGIT_MAX, r5, carry, carry);
+ MP_ADD_CARRY(r6, -(r8_d+1), r6, carry, carry);
+ MP_ADD_CARRY(r7, (r8_d-1), r7, carry, carry);
+ r8 = carry;
+ }
+
+ /* reduce the underflows */
+ while (r8 < 0) {
+ mp_digit r8_d = -r8;
+ MP_SUB_BORROW(r0, r8_d, r0, 0, carry);
+ MP_SUB_BORROW(r1, 0, r1, carry, carry);
+ MP_SUB_BORROW(r2, 0, r2, carry, carry);
+ MP_SUB_BORROW(r3, -r8_d, r3, carry, carry);
+ MP_SUB_BORROW(r4, MP_DIGIT_MAX, r4, carry, carry);
+ MP_SUB_BORROW(r5, MP_DIGIT_MAX, r5, carry, carry);
+ MP_SUB_BORROW(r6, -(r8_d+1), r6, carry, carry);
+ MP_SUB_BORROW(r7, (r8_d-1), r7, carry, carry);
+ r8 = -carry;
+ }
+ if (a != r) {
+ MP_CHECKOK(s_mp_pad(r,8));
+ }
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 8;
+
+ MP_DIGIT(r,7) = r7;
+ MP_DIGIT(r,6) = r6;
+ MP_DIGIT(r,5) = r5;
+ MP_DIGIT(r,4) = r4;
+ MP_DIGIT(r,3) = r3;
+ MP_DIGIT(r,2) = r2;
+ MP_DIGIT(r,1) = r1;
+ MP_DIGIT(r,0) = r0;
+
+ /* final reduction if necessary */
+ if ((r7 == MP_DIGIT_MAX) &&
+ ((r6 > 1) || ((r6 == 1) &&
+ (r5 || r4 || r3 ||
+ ((r2 == MP_DIGIT_MAX) && (r1 == MP_DIGIT_MAX)
+ && (r0 == MP_DIGIT_MAX)))))) {
+ MP_CHECKOK(mp_sub(r, &meth->irr, r));
+ }
+#ifdef notdef
+
+
+ /* smooth the negatives */
+ while (MP_SIGN(r) != MP_ZPOS) {
+ MP_CHECKOK(mp_add(r, &meth->irr, r));
+ }
+ while (MP_USED(r) > 8) {
+ MP_CHECKOK(mp_sub(r, &meth->irr, r));
+ }
+
+ /* final reduction if necessary */
+ if (MP_DIGIT(r,7) >= MP_DIGIT(&meth->irr,7)) {
+ if (mp_cmp(r,&meth->irr) != MP_LT) {
+ MP_CHECKOK(mp_sub(r, &meth->irr, r));
+ }
+ }
+#endif
+ s_mp_clamp(r);
+#else
+ switch (a_used) {
+ case 8:
+ a7 = MP_DIGIT(a,7);
+ case 7:
+ a6 = MP_DIGIT(a,6);
+ case 6:
+ a5 = MP_DIGIT(a,5);
+ case 5:
+ a4 = MP_DIGIT(a,4);
+ }
+ a7l = a7 << 32;
+ a7h = a7 >> 32;
+ a6l = a6 << 32;
+ a6h = a6 >> 32;
+ a5l = a5 << 32;
+ a5h = a5 >> 32;
+ a4l = a4 << 32;
+ a4h = a4 >> 32;
+ r3 = MP_DIGIT(a,3);
+ r2 = MP_DIGIT(a,2);
+ r1 = MP_DIGIT(a,1);
+ r0 = MP_DIGIT(a,0);
+
+ /* sum 1 */
+ MP_ADD_CARRY_ZERO(r1, a5h << 32, r1, carry);
+ MP_ADD_CARRY(r2, a6, r2, carry, carry);
+ MP_ADD_CARRY(r3, a7, r3, carry, carry);
+ r4 = carry;
+ MP_ADD_CARRY_ZERO(r1, a5h << 32, r1, carry);
+ MP_ADD_CARRY(r2, a6, r2, carry, carry);
+ MP_ADD_CARRY(r3, a7, r3, carry, carry);
+ r4 += carry;
+ /* sum 2 */
+ MP_ADD_CARRY_ZERO(r1, a6l, r1, carry);
+ MP_ADD_CARRY(r2, a6h | a7l, r2, carry, carry);
+ MP_ADD_CARRY(r3, a7h, r3, carry, carry);
+ r4 += carry;
+ MP_ADD_CARRY_ZERO(r1, a6l, r1, carry);
+ MP_ADD_CARRY(r2, a6h | a7l, r2, carry, carry);
+ MP_ADD_CARRY(r3, a7h, r3, carry, carry);
+ r4 += carry;
+
+ /* sum 3 */
+ MP_ADD_CARRY_ZERO(r0, a4, r0, carry);
+ MP_ADD_CARRY(r1, a5l >> 32, r1, carry, carry);
+ MP_ADD_CARRY(r2, 0, r2, carry, carry);
+ MP_ADD_CARRY(r3, a7, r3, carry, carry);
+ r4 += carry;
+ /* sum 4 */
+ MP_ADD_CARRY_ZERO(r0, a4h | a5l, r0, carry);
+ MP_ADD_CARRY(r1, a5h|(a6h<<32), r1, carry, carry);
+ MP_ADD_CARRY(r2, a7, r2, carry, carry);
+ MP_ADD_CARRY(r3, a6h | a4l, r3, carry, carry);
+ r4 += carry;
+ /* diff 5 */
+ MP_SUB_BORROW(r0, a5h | a6l, r0, 0, carry);
+ MP_SUB_BORROW(r1, a6h, r1, carry, carry);
+ MP_SUB_BORROW(r2, 0, r2, carry, carry);
+ MP_SUB_BORROW(r3, (a4l>>32)|a5l,r3, carry, carry);
+ r4 -= carry;
+ /* diff 6 */
+ MP_SUB_BORROW(r0, a6, r0, 0, carry);
+ MP_SUB_BORROW(r1, a7, r1, carry, carry);
+ MP_SUB_BORROW(r2, 0, r2, carry, carry);
+ MP_SUB_BORROW(r3, a4h|(a5h<<32),r3, carry, carry);
+ r4 -= carry;
+ /* diff 7 */
+ MP_SUB_BORROW(r0, a6h|a7l, r0, 0, carry);
+ MP_SUB_BORROW(r1, a7h|a4l, r1, carry, carry);
+ MP_SUB_BORROW(r2, a4h|a5l, r2, carry, carry);
+ MP_SUB_BORROW(r3, a6l, r3, carry, carry);
+ r4 -= carry;
+ /* diff 8 */
+ MP_SUB_BORROW(r0, a7, r0, 0, carry);
+ MP_SUB_BORROW(r1, a4h<<32, r1, carry, carry);
+ MP_SUB_BORROW(r2, a5, r2, carry, carry);
+ MP_SUB_BORROW(r3, a6h<<32, r3, carry, carry);
+ r4 -= carry;
+
+ /* reduce the overflows */
+ while (r4 > 0) {
+ mp_digit r4_long = r4;
+ mp_digit r4l = (r4_long << 32);
+ MP_ADD_CARRY_ZERO(r0, r4_long, r0, carry);
+ MP_ADD_CARRY(r1, -r4l, r1, carry, carry);
+ MP_ADD_CARRY(r2, MP_DIGIT_MAX, r2, carry, carry);
+ MP_ADD_CARRY(r3, r4l-r4_long-1,r3, carry, carry);
+ r4 = carry;
+ }
+
+ /* reduce the underflows */
+ while (r4 < 0) {
+ mp_digit r4_long = -r4;
+ mp_digit r4l = (r4_long << 32);
+ MP_SUB_BORROW(r0, r4_long, r0, 0, carry);
+ MP_SUB_BORROW(r1, -r4l, r1, carry, carry);
+ MP_SUB_BORROW(r2, MP_DIGIT_MAX, r2, carry, carry);
+ MP_SUB_BORROW(r3, r4l-r4_long-1,r3, carry, carry);
+ r4 = -carry;
+ }
+
+ if (a != r) {
+ MP_CHECKOK(s_mp_pad(r,4));
+ }
+ MP_SIGN(r) = MP_ZPOS;
+ MP_USED(r) = 4;
+
+ MP_DIGIT(r,3) = r3;
+ MP_DIGIT(r,2) = r2;
+ MP_DIGIT(r,1) = r1;
+ MP_DIGIT(r,0) = r0;
+
+ /* final reduction if necessary */
+ if ((r3 > 0xFFFFFFFF00000001ULL) ||
+ ((r3 == 0xFFFFFFFF00000001ULL) &&
+ (r2 || (r1 >> 32)||
+ (r1 == 0xFFFFFFFFULL && r0 == MP_DIGIT_MAX)))) {
+ /* very rare, just use mp_sub */
+ MP_CHECKOK(mp_sub(r, &meth->irr, r));
+ }
+
+ s_mp_clamp(r);
+#endif
+ }
+
+ CLEANUP:
+ return res;
+}
+
+/* Compute the square of polynomial a, reduce modulo p256. Store the
+ * result in r. r could be a. Uses optimized modular reduction for p256.
+ */
+mp_err
+ec_GFp_nistp256_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ MP_CHECKOK(mp_sqr(a, r));
+ MP_CHECKOK(ec_GFp_nistp256_mod(r, r, meth));
+ CLEANUP:
+ return res;
+}
+
+/* Compute the product of two polynomials a and b, reduce modulo p256.
+ * Store the result in r. r could be a or b; a could be b. Uses
+ * optimized modular reduction for p256. */
+mp_err
+ec_GFp_nistp256_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ MP_CHECKOK(mp_mul(a, b, r));
+ MP_CHECKOK(ec_GFp_nistp256_mod(r, r, meth));
+ CLEANUP:
+ return res;
+}
+
+/* Wire in fast field arithmetic and precomputation of base point for
+ * named curves. */
+mp_err
+ec_group_set_gfp256(ECGroup *group, ECCurveName name)
+{
+ if (name == ECCurve_NIST_P256) {
+ group->meth->field_mod = &ec_GFp_nistp256_mod;
+ group->meth->field_mul = &ec_GFp_nistp256_mul;
+ group->meth->field_sqr = &ec_GFp_nistp256_sqr;
+ }
+ return MP_OKAY;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecp_384.c b/jdk.crypto.ec/share/native/libsunec/impl/ecp_384.c
new file mode 100644
index 0000000..e40a8f1
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecp_384.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>
+ *
+ *********************************************************************** */
+
+#include "ecp.h"
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+/* Fast modular reduction for p384 = 2^384 - 2^128 - 2^96 + 2^32 - 1. a can be r.
+ * Uses algorithm 2.30 from Hankerson, Menezes, Vanstone. Guide to
+ * Elliptic Curve Cryptography. */
+mp_err
+ec_GFp_nistp384_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ int a_bits = mpl_significant_bits(a);
+ int i;
+
+ /* m1, m2 are statically-allocated mp_int of exactly the size we need */
+ mp_int m[10];
+
+#ifdef ECL_THIRTY_TWO_BIT
+ mp_digit s[10][12];
+ for (i = 0; i < 10; i++) {
+ MP_SIGN(&m[i]) = MP_ZPOS;
+ MP_ALLOC(&m[i]) = 12;
+ MP_USED(&m[i]) = 12;
+ MP_DIGITS(&m[i]) = s[i];
+ }
+#else
+ mp_digit s[10][6];
+ for (i = 0; i < 10; i++) {
+ MP_SIGN(&m[i]) = MP_ZPOS;
+ MP_ALLOC(&m[i]) = 6;
+ MP_USED(&m[i]) = 6;
+ MP_DIGITS(&m[i]) = s[i];
+ }
+#endif
+
+#ifdef ECL_THIRTY_TWO_BIT
+ /* for polynomials larger than twice the field size or polynomials
+ * not using all words, use regular reduction */
+ if ((a_bits > 768) || (a_bits <= 736)) {
+ MP_CHECKOK(mp_mod(a, &meth->irr, r));
+ } else {
+ for (i = 0; i < 12; i++) {
+ s[0][i] = MP_DIGIT(a, i);
+ }
+ s[1][0] = 0;
+ s[1][1] = 0;
+ s[1][2] = 0;
+ s[1][3] = 0;
+ s[1][4] = MP_DIGIT(a, 21);
+ s[1][5] = MP_DIGIT(a, 22);
+ s[1][6] = MP_DIGIT(a, 23);
+ s[1][7] = 0;
+ s[1][8] = 0;
+ s[1][9] = 0;
+ s[1][10] = 0;
+ s[1][11] = 0;
+ for (i = 0; i < 12; i++) {
+ s[2][i] = MP_DIGIT(a, i+12);
+ }
+ s[3][0] = MP_DIGIT(a, 21);
+ s[3][1] = MP_DIGIT(a, 22);
+ s[3][2] = MP_DIGIT(a, 23);
+ for (i = 3; i < 12; i++) {
+ s[3][i] = MP_DIGIT(a, i+9);
+ }
+ s[4][0] = 0;
+ s[4][1] = MP_DIGIT(a, 23);
+ s[4][2] = 0;
+ s[4][3] = MP_DIGIT(a, 20);
+ for (i = 4; i < 12; i++) {
+ s[4][i] = MP_DIGIT(a, i+8);
+ }
+ s[5][0] = 0;
+ s[5][1] = 0;
+ s[5][2] = 0;
+ s[5][3] = 0;
+ s[5][4] = MP_DIGIT(a, 20);
+ s[5][5] = MP_DIGIT(a, 21);
+ s[5][6] = MP_DIGIT(a, 22);
+ s[5][7] = MP_DIGIT(a, 23);
+ s[5][8] = 0;
+ s[5][9] = 0;
+ s[5][10] = 0;
+ s[5][11] = 0;
+ s[6][0] = MP_DIGIT(a, 20);
+ s[6][1] = 0;
+ s[6][2] = 0;
+ s[6][3] = MP_DIGIT(a, 21);
+ s[6][4] = MP_DIGIT(a, 22);
+ s[6][5] = MP_DIGIT(a, 23);
+ s[6][6] = 0;
+ s[6][7] = 0;
+ s[6][8] = 0;
+ s[6][9] = 0;
+ s[6][10] = 0;
+ s[6][11] = 0;
+ s[7][0] = MP_DIGIT(a, 23);
+ for (i = 1; i < 12; i++) {
+ s[7][i] = MP_DIGIT(a, i+11);
+ }
+ s[8][0] = 0;
+ s[8][1] = MP_DIGIT(a, 20);
+ s[8][2] = MP_DIGIT(a, 21);
+ s[8][3] = MP_DIGIT(a, 22);
+ s[8][4] = MP_DIGIT(a, 23);
+ s[8][5] = 0;
+ s[8][6] = 0;
+ s[8][7] = 0;
+ s[8][8] = 0;
+ s[8][9] = 0;
+ s[8][10] = 0;
+ s[8][11] = 0;
+ s[9][0] = 0;
+ s[9][1] = 0;
+ s[9][2] = 0;
+ s[9][3] = MP_DIGIT(a, 23);
+ s[9][4] = MP_DIGIT(a, 23);
+ s[9][5] = 0;
+ s[9][6] = 0;
+ s[9][7] = 0;
+ s[9][8] = 0;
+ s[9][9] = 0;
+ s[9][10] = 0;
+ s[9][11] = 0;
+
+ MP_CHECKOK(mp_add(&m[0], &m[1], r));
+ MP_CHECKOK(mp_add(r, &m[1], r));
+ MP_CHECKOK(mp_add(r, &m[2], r));
+ MP_CHECKOK(mp_add(r, &m[3], r));
+ MP_CHECKOK(mp_add(r, &m[4], r));
+ MP_CHECKOK(mp_add(r, &m[5], r));
+ MP_CHECKOK(mp_add(r, &m[6], r));
+ MP_CHECKOK(mp_sub(r, &m[7], r));
+ MP_CHECKOK(mp_sub(r, &m[8], r));
+ MP_CHECKOK(mp_submod(r, &m[9], &meth->irr, r));
+ s_mp_clamp(r);
+ }
+#else
+ /* for polynomials larger than twice the field size or polynomials
+ * not using all words, use regular reduction */
+ if ((a_bits > 768) || (a_bits <= 736)) {
+ MP_CHECKOK(mp_mod(a, &meth->irr, r));
+ } else {
+ for (i = 0; i < 6; i++) {
+ s[0][i] = MP_DIGIT(a, i);
+ }
+ s[1][0] = 0;
+ s[1][1] = 0;
+ s[1][2] = (MP_DIGIT(a, 10) >> 32) | (MP_DIGIT(a, 11) << 32);
+ s[1][3] = MP_DIGIT(a, 11) >> 32;
+ s[1][4] = 0;
+ s[1][5] = 0;
+ for (i = 0; i < 6; i++) {
+ s[2][i] = MP_DIGIT(a, i+6);
+ }
+ s[3][0] = (MP_DIGIT(a, 10) >> 32) | (MP_DIGIT(a, 11) << 32);
+ s[3][1] = (MP_DIGIT(a, 11) >> 32) | (MP_DIGIT(a, 6) << 32);
+ for (i = 2; i < 6; i++) {
+ s[3][i] = (MP_DIGIT(a, i+4) >> 32) | (MP_DIGIT(a, i+5) << 32);
+ }
+ s[4][0] = (MP_DIGIT(a, 11) >> 32) << 32;
+ s[4][1] = MP_DIGIT(a, 10) << 32;
+ for (i = 2; i < 6; i++) {
+ s[4][i] = MP_DIGIT(a, i+4);
+ }
+ s[5][0] = 0;
+ s[5][1] = 0;
+ s[5][2] = MP_DIGIT(a, 10);
+ s[5][3] = MP_DIGIT(a, 11);
+ s[5][4] = 0;
+ s[5][5] = 0;
+ s[6][0] = (MP_DIGIT(a, 10) << 32) >> 32;
+ s[6][1] = (MP_DIGIT(a, 10) >> 32) << 32;
+ s[6][2] = MP_DIGIT(a, 11);
+ s[6][3] = 0;
+ s[6][4] = 0;
+ s[6][5] = 0;
+ s[7][0] = (MP_DIGIT(a, 11) >> 32) | (MP_DIGIT(a, 6) << 32);
+ for (i = 1; i < 6; i++) {
+ s[7][i] = (MP_DIGIT(a, i+5) >> 32) | (MP_DIGIT(a, i+6) << 32);
+ }
+ s[8][0] = MP_DIGIT(a, 10) << 32;
+ s[8][1] = (MP_DIGIT(a, 10) >> 32) | (MP_DIGIT(a, 11) << 32);
+ s[8][2] = MP_DIGIT(a, 11) >> 32;
+ s[8][3] = 0;
+ s[8][4] = 0;
+ s[8][5] = 0;
+ s[9][0] = 0;
+ s[9][1] = (MP_DIGIT(a, 11) >> 32) << 32;
+ s[9][2] = MP_DIGIT(a, 11) >> 32;
+ s[9][3] = 0;
+ s[9][4] = 0;
+ s[9][5] = 0;
+
+ MP_CHECKOK(mp_add(&m[0], &m[1], r));
+ MP_CHECKOK(mp_add(r, &m[1], r));
+ MP_CHECKOK(mp_add(r, &m[2], r));
+ MP_CHECKOK(mp_add(r, &m[3], r));
+ MP_CHECKOK(mp_add(r, &m[4], r));
+ MP_CHECKOK(mp_add(r, &m[5], r));
+ MP_CHECKOK(mp_add(r, &m[6], r));
+ MP_CHECKOK(mp_sub(r, &m[7], r));
+ MP_CHECKOK(mp_sub(r, &m[8], r));
+ MP_CHECKOK(mp_submod(r, &m[9], &meth->irr, r));
+ s_mp_clamp(r);
+ }
+#endif
+
+ CLEANUP:
+ return res;
+}
+
+/* Compute the square of polynomial a, reduce modulo p384. Store the
+ * result in r. r could be a. Uses optimized modular reduction for p384.
+ */
+mp_err
+ec_GFp_nistp384_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ MP_CHECKOK(mp_sqr(a, r));
+ MP_CHECKOK(ec_GFp_nistp384_mod(r, r, meth));
+ CLEANUP:
+ return res;
+}
+
+/* Compute the product of two polynomials a and b, reduce modulo p384.
+ * Store the result in r. r could be a or b; a could be b. Uses
+ * optimized modular reduction for p384. */
+mp_err
+ec_GFp_nistp384_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ MP_CHECKOK(mp_mul(a, b, r));
+ MP_CHECKOK(ec_GFp_nistp384_mod(r, r, meth));
+ CLEANUP:
+ return res;
+}
+
+/* Wire in fast field arithmetic and precomputation of base point for
+ * named curves. */
+mp_err
+ec_group_set_gfp384(ECGroup *group, ECCurveName name)
+{
+ if (name == ECCurve_NIST_P384) {
+ group->meth->field_mod = &ec_GFp_nistp384_mod;
+ group->meth->field_mul = &ec_GFp_nistp384_mul;
+ group->meth->field_sqr = &ec_GFp_nistp384_sqr;
+ }
+ return MP_OKAY;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecp_521.c b/jdk.crypto.ec/share/native/libsunec/impl/ecp_521.c
new file mode 100644
index 0000000..11172dd
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecp_521.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>
+ *
+ *********************************************************************** */
+
+#include "ecp.h"
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+#define ECP521_DIGITS ECL_CURVE_DIGITS(521)
+
+/* Fast modular reduction for p521 = 2^521 - 1. a can be r. Uses
+ * algorithm 2.31 from Hankerson, Menezes, Vanstone. Guide to
+ * Elliptic Curve Cryptography. */
+mp_err
+ec_GFp_nistp521_mod(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ int a_bits = mpl_significant_bits(a);
+ unsigned int i;
+
+ /* m1, m2 are statically-allocated mp_int of exactly the size we need */
+ mp_int m1;
+
+ mp_digit s1[ECP521_DIGITS] = { 0 };
+
+ MP_SIGN(&m1) = MP_ZPOS;
+ MP_ALLOC(&m1) = ECP521_DIGITS;
+ MP_USED(&m1) = ECP521_DIGITS;
+ MP_DIGITS(&m1) = s1;
+
+ if (a_bits < 521) {
+ if (a==r) return MP_OKAY;
+ return mp_copy(a, r);
+ }
+ /* for polynomials larger than twice the field size or polynomials
+ * not using all words, use regular reduction */
+ if (a_bits > (521*2)) {
+ MP_CHECKOK(mp_mod(a, &meth->irr, r));
+ } else {
+#define FIRST_DIGIT (ECP521_DIGITS-1)
+ for (i = FIRST_DIGIT; i < MP_USED(a)-1; i++) {
+ s1[i-FIRST_DIGIT] = (MP_DIGIT(a, i) >> 9)
+ | (MP_DIGIT(a, 1+i) << (MP_DIGIT_BIT-9));
+ }
+ s1[i-FIRST_DIGIT] = MP_DIGIT(a, i) >> 9;
+
+ if ( a != r ) {
+ MP_CHECKOK(s_mp_pad(r,ECP521_DIGITS));
+ for (i = 0; i < ECP521_DIGITS; i++) {
+ MP_DIGIT(r,i) = MP_DIGIT(a, i);
+ }
+ }
+ MP_USED(r) = ECP521_DIGITS;
+ MP_DIGIT(r,FIRST_DIGIT) &= 0x1FF;
+
+ MP_CHECKOK(s_mp_add(r, &m1));
+ if (MP_DIGIT(r, FIRST_DIGIT) & 0x200) {
+ MP_CHECKOK(s_mp_add_d(r,1));
+ MP_DIGIT(r,FIRST_DIGIT) &= 0x1FF;
+ }
+ s_mp_clamp(r);
+ }
+
+ CLEANUP:
+ return res;
+}
+
+/* Compute the square of polynomial a, reduce modulo p521. Store the
+ * result in r. r could be a. Uses optimized modular reduction for p521.
+ */
+mp_err
+ec_GFp_nistp521_sqr(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ MP_CHECKOK(mp_sqr(a, r));
+ MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
+ CLEANUP:
+ return res;
+}
+
+/* Compute the product of two polynomials a and b, reduce modulo p521.
+ * Store the result in r. r could be a or b; a could be b. Uses
+ * optimized modular reduction for p521. */
+mp_err
+ec_GFp_nistp521_mul(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ MP_CHECKOK(mp_mul(a, b, r));
+ MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
+ CLEANUP:
+ return res;
+}
+
+/* Divides two field elements. If a is NULL, then returns the inverse of
+ * b. */
+mp_err
+ec_GFp_nistp521_div(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+ mp_int t;
+
+ /* If a is NULL, then return the inverse of b, otherwise return a/b. */
+ if (a == NULL) {
+ return mp_invmod(b, &meth->irr, r);
+ } else {
+ /* MPI doesn't support divmod, so we implement it using invmod and
+ * mulmod. */
+ MP_CHECKOK(mp_init(&t, FLAG(b)));
+ MP_CHECKOK(mp_invmod(b, &meth->irr, &t));
+ MP_CHECKOK(mp_mul(a, &t, r));
+ MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth));
+ CLEANUP:
+ mp_clear(&t);
+ return res;
+ }
+}
+
+/* Wire in fast field arithmetic and precomputation of base point for
+ * named curves. */
+mp_err
+ec_group_set_gfp521(ECGroup *group, ECCurveName name)
+{
+ if (name == ECCurve_NIST_P521) {
+ group->meth->field_mod = &ec_GFp_nistp521_mod;
+ group->meth->field_mul = &ec_GFp_nistp521_mul;
+ group->meth->field_sqr = &ec_GFp_nistp521_sqr;
+ group->meth->field_div = &ec_GFp_nistp521_div;
+ }
+ return MP_OKAY;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c b/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c
new file mode 100644
index 0000000..c9d9232
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sheueling Chang-Shantz <sheueling.chang@sun.com>,
+ * Stephen Fung <fungstep@hotmail.com>, and
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories.
+ * Bodo Moeller <moeller@cdc.informatik.tu-darmstadt.de>,
+ * Nils Larsch <nla@trustcenter.de>, and
+ * Lenka Fibikova <fibikova@exp-math.uni-essen.de>, the OpenSSL Project
+ *
+ * Last Modified Date from the Original Code: May 2017
+ *********************************************************************** */
+
+#include "ecp.h"
+#include "mplogic.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */
+mp_err
+ec_GFp_pt_is_inf_aff(const mp_int *px, const mp_int *py)
+{
+
+ if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) {
+ return MP_YES;
+ } else {
+ return MP_NO;
+ }
+
+}
+
+/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */
+mp_err
+ec_GFp_pt_set_inf_aff(mp_int *px, mp_int *py)
+{
+ mp_zero(px);
+ mp_zero(py);
+ return MP_OKAY;
+}
+
+/* Computes R = P + Q based on IEEE P1363 A.10.1. Elliptic curve points P,
+ * Q, and R can all be identical. Uses affine coordinates. Assumes input
+ * is already field-encoded using field_enc, and returns output that is
+ * still field-encoded. */
+mp_err
+ec_GFp_pt_add_aff(const mp_int *px, const mp_int *py, const mp_int *qx,
+ const mp_int *qy, mp_int *rx, mp_int *ry,
+ const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ mp_int lambda, temp, tempx, tempy;
+
+ MP_DIGITS(&lambda) = 0;
+ MP_DIGITS(&temp) = 0;
+ MP_DIGITS(&tempx) = 0;
+ MP_DIGITS(&tempy) = 0;
+ MP_CHECKOK(mp_init(&lambda, FLAG(px)));
+ MP_CHECKOK(mp_init(&temp, FLAG(px)));
+ MP_CHECKOK(mp_init(&tempx, FLAG(px)));
+ MP_CHECKOK(mp_init(&tempy, FLAG(px)));
+ /* if P = inf, then R = Q */
+ if (ec_GFp_pt_is_inf_aff(px, py) == 0) {
+ MP_CHECKOK(mp_copy(qx, rx));
+ MP_CHECKOK(mp_copy(qy, ry));
+ res = MP_OKAY;
+ goto CLEANUP;
+ }
+ /* if Q = inf, then R = P */
+ if (ec_GFp_pt_is_inf_aff(qx, qy) == 0) {
+ MP_CHECKOK(mp_copy(px, rx));
+ MP_CHECKOK(mp_copy(py, ry));
+ res = MP_OKAY;
+ goto CLEANUP;
+ }
+ /* if px != qx, then lambda = (py-qy) / (px-qx) */
+ if (mp_cmp(px, qx) != 0) {
+ MP_CHECKOK(group->meth->field_sub(py, qy, &tempy, group->meth));
+ MP_CHECKOK(group->meth->field_sub(px, qx, &tempx, group->meth));
+ MP_CHECKOK(group->meth->
+ field_div(&tempy, &tempx, &lambda, group->meth));
+ } else {
+ /* if py != qy or qy = 0, then R = inf */
+ if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qy) == 0)) {
+ mp_zero(rx);
+ mp_zero(ry);
+ res = MP_OKAY;
+ goto CLEANUP;
+ }
+ /* lambda = (3qx^2+a) / (2qy) */
+ MP_CHECKOK(group->meth->field_sqr(qx, &tempx, group->meth));
+ MP_CHECKOK(mp_set_int(&temp, 3));
+ if (group->meth->field_enc) {
+ MP_CHECKOK(group->meth->field_enc(&temp, &temp, group->meth));
+ }
+ MP_CHECKOK(group->meth->
+ field_mul(&tempx, &temp, &tempx, group->meth));
+ MP_CHECKOK(group->meth->
+ field_add(&tempx, &group->curvea, &tempx, group->meth));
+ MP_CHECKOK(mp_set_int(&temp, 2));
+ if (group->meth->field_enc) {
+ MP_CHECKOK(group->meth->field_enc(&temp, &temp, group->meth));
+ }
+ MP_CHECKOK(group->meth->field_mul(qy, &temp, &tempy, group->meth));
+ MP_CHECKOK(group->meth->
+ field_div(&tempx, &tempy, &lambda, group->meth));
+ }
+ /* rx = lambda^2 - px - qx */
+ MP_CHECKOK(group->meth->field_sqr(&lambda, &tempx, group->meth));
+ MP_CHECKOK(group->meth->field_sub(&tempx, px, &tempx, group->meth));
+ MP_CHECKOK(group->meth->field_sub(&tempx, qx, &tempx, group->meth));
+ /* ry = (x1-x2) * lambda - y1 */
+ MP_CHECKOK(group->meth->field_sub(qx, &tempx, &tempy, group->meth));
+ MP_CHECKOK(group->meth->
+ field_mul(&tempy, &lambda, &tempy, group->meth));
+ MP_CHECKOK(group->meth->field_sub(&tempy, qy, &tempy, group->meth));
+ MP_CHECKOK(mp_copy(&tempx, rx));
+ MP_CHECKOK(mp_copy(&tempy, ry));
+
+ CLEANUP:
+ mp_clear(&lambda);
+ mp_clear(&temp);
+ mp_clear(&tempx);
+ mp_clear(&tempy);
+ return res;
+}
+
+/* Computes R = P - Q. Elliptic curve points P, Q, and R can all be
+ * identical. Uses affine coordinates. Assumes input is already
+ * field-encoded using field_enc, and returns output that is still
+ * field-encoded. */
+mp_err
+ec_GFp_pt_sub_aff(const mp_int *px, const mp_int *py, const mp_int *qx,
+ const mp_int *qy, mp_int *rx, mp_int *ry,
+ const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ mp_int nqy;
+
+ MP_DIGITS(&nqy) = 0;
+ MP_CHECKOK(mp_init(&nqy, FLAG(px)));
+ /* nqy = -qy */
+ MP_CHECKOK(group->meth->field_neg(qy, &nqy, group->meth));
+ res = group->point_add(px, py, qx, &nqy, rx, ry, group);
+ CLEANUP:
+ mp_clear(&nqy);
+ return res;
+}
+
+/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
+ * affine coordinates. Assumes input is already field-encoded using
+ * field_enc, and returns output that is still field-encoded. */
+mp_err
+ec_GFp_pt_dbl_aff(const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, const ECGroup *group)
+{
+ return ec_GFp_pt_add_aff(px, py, px, py, rx, ry, group);
+}
+
+/* by default, this routine is unused and thus doesn't need to be compiled */
+#ifdef ECL_ENABLE_GFP_PT_MUL_AFF
+/* Computes R = nP based on IEEE P1363 A.10.3. Elliptic curve points P and
+ * R can be identical. Uses affine coordinates. Assumes input is already
+ * field-encoded using field_enc, and returns output that is still
+ * field-encoded. */
+mp_err
+ec_GFp_pt_mul_aff(const mp_int *n, const mp_int *px, const mp_int *py,
+ mp_int *rx, mp_int *ry, const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ mp_int k, k3, qx, qy, sx, sy;
+ int b1, b3, i, l;
+
+ MP_DIGITS(&k) = 0;
+ MP_DIGITS(&k3) = 0;
+ MP_DIGITS(&qx) = 0;
+ MP_DIGITS(&qy) = 0;
+ MP_DIGITS(&sx) = 0;
+ MP_DIGITS(&sy) = 0;
+ MP_CHECKOK(mp_init(&k));
+ MP_CHECKOK(mp_init(&k3));
+ MP_CHECKOK(mp_init(&qx));
+ MP_CHECKOK(mp_init(&qy));
+ MP_CHECKOK(mp_init(&sx));
+ MP_CHECKOK(mp_init(&sy));
+
+ /* if n = 0 then r = inf */
+ if (mp_cmp_z(n) == 0) {
+ mp_zero(rx);
+ mp_zero(ry);
+ res = MP_OKAY;
+ goto CLEANUP;
+ }
+ /* Q = P, k = n */
+ MP_CHECKOK(mp_copy(px, &qx));
+ MP_CHECKOK(mp_copy(py, &qy));
+ MP_CHECKOK(mp_copy(n, &k));
+ /* if n < 0 then Q = -Q, k = -k */
+ if (mp_cmp_z(n) < 0) {
+ MP_CHECKOK(group->meth->field_neg(&qy, &qy, group->meth));
+ MP_CHECKOK(mp_neg(&k, &k));
+ }
+#ifdef ECL_DEBUG /* basic double and add method */
+ l = mpl_significant_bits(&k) - 1;
+ MP_CHECKOK(mp_copy(&qx, &sx));
+ MP_CHECKOK(mp_copy(&qy, &sy));
+ for (i = l - 1; i >= 0; i--) {
+ /* S = 2S */
+ MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group));
+ /* if k_i = 1, then S = S + Q */
+ if (mpl_get_bit(&k, i) != 0) {
+ MP_CHECKOK(group->
+ point_add(&sx, &sy, &qx, &qy, &sx, &sy, group));
+ }
+ }
+#else /* double and add/subtract method from
+ * standard */
+ /* k3 = 3 * k */
+ MP_CHECKOK(mp_set_int(&k3, 3));
+ MP_CHECKOK(mp_mul(&k, &k3, &k3));
+ /* S = Q */
+ MP_CHECKOK(mp_copy(&qx, &sx));
+ MP_CHECKOK(mp_copy(&qy, &sy));
+ /* l = index of high order bit in binary representation of 3*k */
+ l = mpl_significant_bits(&k3) - 1;
+ /* for i = l-1 downto 1 */
+ for (i = l - 1; i >= 1; i--) {
+ /* S = 2S */
+ MP_CHECKOK(group->point_dbl(&sx, &sy, &sx, &sy, group));
+ b3 = MP_GET_BIT(&k3, i);
+ b1 = MP_GET_BIT(&k, i);
+ /* if k3_i = 1 and k_i = 0, then S = S + Q */
+ if ((b3 == 1) && (b1 == 0)) {
+ MP_CHECKOK(group->
+ point_add(&sx, &sy, &qx, &qy, &sx, &sy, group));
+ /* if k3_i = 0 and k_i = 1, then S = S - Q */
+ } else if ((b3 == 0) && (b1 == 1)) {
+ MP_CHECKOK(group->
+ point_sub(&sx, &sy, &qx, &qy, &sx, &sy, group));
+ }
+ }
+#endif
+ /* output S */
+ MP_CHECKOK(mp_copy(&sx, rx));
+ MP_CHECKOK(mp_copy(&sy, ry));
+
+ CLEANUP:
+ mp_clear(&k);
+ mp_clear(&k3);
+ mp_clear(&qx);
+ mp_clear(&qy);
+ mp_clear(&sx);
+ mp_clear(&sy);
+ return res;
+}
+#endif
+
+/* Validates a point on a GFp curve. */
+mp_err
+ec_GFp_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group)
+{
+ mp_err res = MP_NO;
+ mp_int accl, accr, tmp, pxt, pyt;
+
+ MP_DIGITS(&accl) = 0;
+ MP_DIGITS(&accr) = 0;
+ MP_DIGITS(&tmp) = 0;
+ MP_DIGITS(&pxt) = 0;
+ MP_DIGITS(&pyt) = 0;
+ MP_CHECKOK(mp_init(&accl, FLAG(px)));
+ MP_CHECKOK(mp_init(&accr, FLAG(px)));
+ MP_CHECKOK(mp_init(&tmp, FLAG(px)));
+ MP_CHECKOK(mp_init(&pxt, FLAG(px)));
+ MP_CHECKOK(mp_init(&pyt, FLAG(px)));
+
+ /* 1: Verify that publicValue is not the point at infinity */
+ if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) {
+ res = MP_NO;
+ goto CLEANUP;
+ }
+ /* 2: Verify that the coordinates of publicValue are elements
+ * of the field.
+ */
+ if ((MP_SIGN(px) == MP_NEG) || (mp_cmp(px, &group->meth->irr) >= 0) ||
+ (MP_SIGN(py) == MP_NEG) || (mp_cmp(py, &group->meth->irr) >= 0)) {
+ res = MP_NO;
+ goto CLEANUP;
+ }
+ /* 3: Verify that publicValue is on the curve. */
+ if (group->meth->field_enc) {
+ group->meth->field_enc(px, &pxt, group->meth);
+ group->meth->field_enc(py, &pyt, group->meth);
+ } else {
+ mp_copy(px, &pxt);
+ mp_copy(py, &pyt);
+ }
+ /* left-hand side: y^2 */
+ MP_CHECKOK( group->meth->field_sqr(&pyt, &accl, group->meth) );
+ /* right-hand side: x^3 + a*x + b */
+ MP_CHECKOK( group->meth->field_sqr(&pxt, &tmp, group->meth) );
+ MP_CHECKOK( group->meth->field_mul(&pxt, &tmp, &accr, group->meth) );
+ MP_CHECKOK( group->meth->field_mul(&group->curvea, &pxt, &tmp, group->meth) );
+ MP_CHECKOK( group->meth->field_add(&tmp, &accr, &accr, group->meth) );
+ MP_CHECKOK( group->meth->field_add(&accr, &group->curveb, &accr, group->meth) );
+ /* check LHS - RHS == 0 */
+ MP_CHECKOK( group->meth->field_sub(&accl, &accr, &accr, group->meth) );
+ if (mp_cmp_z(&accr) != 0) {
+ res = MP_NO;
+ goto CLEANUP;
+ }
+ /* 4: Verify that the order of the curve times the publicValue
+ * is the point at infinity.
+ */
+ /* timing mitigation is not supported */
+ MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, /*timing*/ 0) );
+ if (ec_GFp_pt_is_inf_aff(&pxt, &pyt) != MP_YES) {
+ res = MP_NO;
+ goto CLEANUP;
+ }
+
+ res = MP_YES;
+
+CLEANUP:
+ mp_clear(&accl);
+ mp_clear(&accr);
+ mp_clear(&tmp);
+ mp_clear(&pxt);
+ mp_clear(&pyt);
+ return res;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c b/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c
new file mode 100644
index 0000000..9e1bdf2
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sheueling Chang-Shantz <sheueling.chang@sun.com>,
+ * Stephen Fung <fungstep@hotmail.com>, and
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories.
+ * Bodo Moeller <moeller@cdc.informatik.tu-darmstadt.de>,
+ * Nils Larsch <nla@trustcenter.de>, and
+ * Lenka Fibikova <fibikova@exp-math.uni-essen.de>, the OpenSSL Project
+ *
+ * Last Modified Date from the Original Code: May 2017
+ *********************************************************************** */
+
+#include "ecp.h"
+#include "mplogic.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+#ifdef ECL_DEBUG
+#include <assert.h>
+#endif
+
+/* Converts a point P(px, py) from affine coordinates to Jacobian
+ * projective coordinates R(rx, ry, rz). Assumes input is already
+ * field-encoded using field_enc, and returns output that is still
+ * field-encoded. */
+mp_err
+ec_GFp_pt_aff2jac(const mp_int *px, const mp_int *py, mp_int *rx,
+ mp_int *ry, mp_int *rz, const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+
+ if (ec_GFp_pt_is_inf_aff(px, py) == MP_YES) {
+ MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
+ } else {
+ MP_CHECKOK(mp_copy(px, rx));
+ MP_CHECKOK(mp_copy(py, ry));
+ MP_CHECKOK(mp_set_int(rz, 1));
+ if (group->meth->field_enc) {
+ MP_CHECKOK(group->meth->field_enc(rz, rz, group->meth));
+ }
+ }
+ CLEANUP:
+ return res;
+}
+
+/* Converts a point P(px, py, pz) from Jacobian projective coordinates to
+ * affine coordinates R(rx, ry). P and R can share x and y coordinates.
+ * Assumes input is already field-encoded using field_enc, and returns
+ * output that is still field-encoded. */
+mp_err
+ec_GFp_pt_jac2aff(const mp_int *px, const mp_int *py, const mp_int *pz,
+ mp_int *rx, mp_int *ry, const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ mp_int z1, z2, z3;
+
+ MP_DIGITS(&z1) = 0;
+ MP_DIGITS(&z2) = 0;
+ MP_DIGITS(&z3) = 0;
+ MP_CHECKOK(mp_init(&z1, FLAG(px)));
+ MP_CHECKOK(mp_init(&z2, FLAG(px)));
+ MP_CHECKOK(mp_init(&z3, FLAG(px)));
+
+ /* if point at infinity, then set point at infinity and exit */
+ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
+ MP_CHECKOK(ec_GFp_pt_set_inf_aff(rx, ry));
+ goto CLEANUP;
+ }
+
+ /* transform (px, py, pz) into (px / pz^2, py / pz^3) */
+ if (mp_cmp_d(pz, 1) == 0) {
+ MP_CHECKOK(mp_copy(px, rx));
+ MP_CHECKOK(mp_copy(py, ry));
+ } else {
+ MP_CHECKOK(group->meth->field_div(NULL, pz, &z1, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(&z1, &z2, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&z1, &z2, &z3, group->meth));
+ MP_CHECKOK(group->meth->field_mul(px, &z2, rx, group->meth));
+ MP_CHECKOK(group->meth->field_mul(py, &z3, ry, group->meth));
+ }
+
+ CLEANUP:
+ mp_clear(&z1);
+ mp_clear(&z2);
+ mp_clear(&z3);
+ return res;
+}
+
+/* Checks if point P(px, py, pz) is at infinity. Uses Jacobian
+ * coordinates. */
+mp_err
+ec_GFp_pt_is_inf_jac(const mp_int *px, const mp_int *py, const mp_int *pz)
+{
+ return mp_cmp_z(pz);
+}
+
+/* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian
+ * coordinates. */
+mp_err
+ec_GFp_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz)
+{
+ mp_zero(pz);
+ return MP_OKAY;
+}
+
+/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
+ * (qx, qy, 1). Elliptic curve points P, Q, and R can all be identical.
+ * Uses mixed Jacobian-affine coordinates. Assumes input is already
+ * field-encoded using field_enc, and returns output that is still
+ * field-encoded. Uses equation (2) from Brown, Hankerson, Lopez, and
+ * Menezes. Software Implementation of the NIST Elliptic Curves Over Prime
+ * Fields. */
+mp_err
+ec_GFp_pt_add_jac_aff(const mp_int *px, const mp_int *py, const mp_int *pz,
+ const mp_int *qx, const mp_int *qy, mp_int *rx,
+ mp_int *ry, mp_int *rz, const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ mp_int A, B, C, D, C2, C3;
+
+ MP_DIGITS(&A) = 0;
+ MP_DIGITS(&B) = 0;
+ MP_DIGITS(&C) = 0;
+ MP_DIGITS(&D) = 0;
+ MP_DIGITS(&C2) = 0;
+ MP_DIGITS(&C3) = 0;
+ MP_CHECKOK(mp_init(&A, FLAG(px)));
+ MP_CHECKOK(mp_init(&B, FLAG(px)));
+ MP_CHECKOK(mp_init(&C, FLAG(px)));
+ MP_CHECKOK(mp_init(&D, FLAG(px)));
+ MP_CHECKOK(mp_init(&C2, FLAG(px)));
+ MP_CHECKOK(mp_init(&C3, FLAG(px)));
+
+ /* If either P or Q is the point at infinity, then return the other
+ * point */
+ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
+ MP_CHECKOK(ec_GFp_pt_aff2jac(qx, qy, rx, ry, rz, group));
+ goto CLEANUP;
+ }
+ if (ec_GFp_pt_is_inf_aff(qx, qy) == MP_YES) {
+ MP_CHECKOK(mp_copy(px, rx));
+ MP_CHECKOK(mp_copy(py, ry));
+ MP_CHECKOK(mp_copy(pz, rz));
+ goto CLEANUP;
+ }
+
+ /* A = qx * pz^2, B = qy * pz^3 */
+ MP_CHECKOK(group->meth->field_sqr(pz, &A, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&A, pz, &B, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&A, qx, &A, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&B, qy, &B, group->meth));
+
+ /*
+ * Additional checks for point equality and point at infinity
+ */
+ if (mp_cmp(px, &A) == 0 && mp_cmp(py, &B) == 0) {
+ /* POINT_DOUBLE(P) */
+ MP_CHECKOK(ec_GFp_pt_dbl_jac(px, py, pz, rx, ry, rz, group));
+ goto CLEANUP;
+ }
+
+ /* C = A - px, D = B - py */
+ MP_CHECKOK(group->meth->field_sub(&A, px, &C, group->meth));
+ MP_CHECKOK(group->meth->field_sub(&B, py, &D, group->meth));
+
+ /* C2 = C^2, C3 = C^3 */
+ MP_CHECKOK(group->meth->field_sqr(&C, &C2, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&C, &C2, &C3, group->meth));
+
+ /* rz = pz * C */
+ MP_CHECKOK(group->meth->field_mul(pz, &C, rz, group->meth));
+
+ /* C = px * C^2 */
+ MP_CHECKOK(group->meth->field_mul(px, &C2, &C, group->meth));
+ /* A = D^2 */
+ MP_CHECKOK(group->meth->field_sqr(&D, &A, group->meth));
+
+ /* rx = D^2 - (C^3 + 2 * (px * C^2)) */
+ MP_CHECKOK(group->meth->field_add(&C, &C, rx, group->meth));
+ MP_CHECKOK(group->meth->field_add(&C3, rx, rx, group->meth));
+ MP_CHECKOK(group->meth->field_sub(&A, rx, rx, group->meth));
+
+ /* C3 = py * C^3 */
+ MP_CHECKOK(group->meth->field_mul(py, &C3, &C3, group->meth));
+
+ /* ry = D * (px * C^2 - rx) - py * C^3 */
+ MP_CHECKOK(group->meth->field_sub(&C, rx, ry, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&D, ry, ry, group->meth));
+ MP_CHECKOK(group->meth->field_sub(ry, &C3, ry, group->meth));
+
+ CLEANUP:
+ mp_clear(&A);
+ mp_clear(&B);
+ mp_clear(&C);
+ mp_clear(&D);
+ mp_clear(&C2);
+ mp_clear(&C3);
+ return res;
+}
+
+/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
+ * Jacobian coordinates.
+ *
+ * Assumes input is already field-encoded using field_enc, and returns
+ * output that is still field-encoded.
+ *
+ * This routine implements Point Doubling in the Jacobian Projective
+ * space as described in the paper "Efficient elliptic curve exponentiation
+ * using mixed coordinates", by H. Cohen, A Miyaji, T. Ono.
+ */
+mp_err
+ec_GFp_pt_dbl_jac(const mp_int *px, const mp_int *py, const mp_int *pz,
+ mp_int *rx, mp_int *ry, mp_int *rz, const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ mp_int t0, t1, M, S;
+
+ MP_DIGITS(&t0) = 0;
+ MP_DIGITS(&t1) = 0;
+ MP_DIGITS(&M) = 0;
+ MP_DIGITS(&S) = 0;
+ MP_CHECKOK(mp_init(&t0, FLAG(px)));
+ MP_CHECKOK(mp_init(&t1, FLAG(px)));
+ MP_CHECKOK(mp_init(&M, FLAG(px)));
+ MP_CHECKOK(mp_init(&S, FLAG(px)));
+
+ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
+ MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
+ goto CLEANUP;
+ }
+
+ if (mp_cmp_d(pz, 1) == 0) {
+ /* M = 3 * px^2 + a */
+ MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth));
+ MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth));
+ MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth));
+ MP_CHECKOK(group->meth->
+ field_add(&t0, &group->curvea, &M, group->meth));
+ } else if (mp_cmp_int(&group->curvea, -3, FLAG(px)) == 0) {
+ /* M = 3 * (px + pz^2) * (px - pz^2) */
+ MP_CHECKOK(group->meth->field_sqr(pz, &M, group->meth));
+ MP_CHECKOK(group->meth->field_add(px, &M, &t0, group->meth));
+ MP_CHECKOK(group->meth->field_sub(px, &M, &t1, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&t0, &t1, &M, group->meth));
+ MP_CHECKOK(group->meth->field_add(&M, &M, &t0, group->meth));
+ MP_CHECKOK(group->meth->field_add(&t0, &M, &M, group->meth));
+ } else {
+ /* M = 3 * (px^2) + a * (pz^4) */
+ MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth));
+ MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth));
+ MP_CHECKOK(group->meth->field_add(&t0, &M, &t0, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(pz, &M, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(&M, &M, group->meth));
+ MP_CHECKOK(group->meth->
+ field_mul(&M, &group->curvea, &M, group->meth));
+ MP_CHECKOK(group->meth->field_add(&M, &t0, &M, group->meth));
+ }
+
+ /* rz = 2 * py * pz */
+ /* t0 = 4 * py^2 */
+ if (mp_cmp_d(pz, 1) == 0) {
+ MP_CHECKOK(group->meth->field_add(py, py, rz, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(rz, &t0, group->meth));
+ } else {
+ MP_CHECKOK(group->meth->field_add(py, py, &t0, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&t0, pz, rz, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(&t0, &t0, group->meth));
+ }
+
+ /* S = 4 * px * py^2 = px * (2 * py)^2 */
+ MP_CHECKOK(group->meth->field_mul(px, &t0, &S, group->meth));
+
+ /* rx = M^2 - 2 * S */
+ MP_CHECKOK(group->meth->field_add(&S, &S, &t1, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(&M, rx, group->meth));
+ MP_CHECKOK(group->meth->field_sub(rx, &t1, rx, group->meth));
+
+ /* ry = M * (S - rx) - 8 * py^4 */
+ MP_CHECKOK(group->meth->field_sqr(&t0, &t1, group->meth));
+ if (mp_isodd(&t1)) {
+ MP_CHECKOK(mp_add(&t1, &group->meth->irr, &t1));
+ }
+ MP_CHECKOK(mp_div_2(&t1, &t1));
+ MP_CHECKOK(group->meth->field_sub(&S, rx, &S, group->meth));
+ MP_CHECKOK(group->meth->field_mul(&M, &S, &M, group->meth));
+ MP_CHECKOK(group->meth->field_sub(&M, &t1, ry, group->meth));
+
+ CLEANUP:
+ mp_clear(&t0);
+ mp_clear(&t1);
+ mp_clear(&M);
+ mp_clear(&S);
+ return res;
+}
+
+/* by default, this routine is unused and thus doesn't need to be compiled */
+#ifdef ECL_ENABLE_GFP_PT_MUL_JAC
+/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters
+ * a, b and p are the elliptic curve coefficients and the prime that
+ * determines the field GFp. Elliptic curve points P and R can be
+ * identical. Uses mixed Jacobian-affine coordinates. Assumes input is
+ * already field-encoded using field_enc, and returns output that is still
+ * field-encoded. Uses 4-bit window method. */
+mp_err
+ec_GFp_pt_mul_jac(const mp_int *n, const mp_int *px, const mp_int *py,
+ mp_int *rx, mp_int *ry, const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ mp_int precomp[16][2], rz;
+ int i, ni, d;
+
+ MP_DIGITS(&rz) = 0;
+ for (i = 0; i < 16; i++) {
+ MP_DIGITS(&precomp[i][0]) = 0;
+ MP_DIGITS(&precomp[i][1]) = 0;
+ }
+
+ ARGCHK(group != NULL, MP_BADARG);
+ ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG);
+
+ /* initialize precomputation table */
+ for (i = 0; i < 16; i++) {
+ MP_CHECKOK(mp_init(&precomp[i][0]));
+ MP_CHECKOK(mp_init(&precomp[i][1]));
+ }
+
+ /* fill precomputation table */
+ mp_zero(&precomp[0][0]);
+ mp_zero(&precomp[0][1]);
+ MP_CHECKOK(mp_copy(px, &precomp[1][0]));
+ MP_CHECKOK(mp_copy(py, &precomp[1][1]));
+ for (i = 2; i < 16; i++) {
+ MP_CHECKOK(group->
+ point_add(&precomp[1][0], &precomp[1][1],
+ &precomp[i - 1][0], &precomp[i - 1][1],
+ &precomp[i][0], &precomp[i][1], group));
+ }
+
+ d = (mpl_significant_bits(n) + 3) / 4;
+
+ /* R = inf */
+ MP_CHECKOK(mp_init(&rz));
+ MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz));
+
+ for (i = d - 1; i >= 0; i--) {
+ /* compute window ni */
+ ni = MP_GET_BIT(n, 4 * i + 3);
+ ni <<= 1;
+ ni |= MP_GET_BIT(n, 4 * i + 2);
+ ni <<= 1;
+ ni |= MP_GET_BIT(n, 4 * i + 1);
+ ni <<= 1;
+ ni |= MP_GET_BIT(n, 4 * i);
+ /* R = 2^4 * R */
+ MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+ MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+ MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+ MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+ /* R = R + (ni * P) */
+ MP_CHECKOK(ec_GFp_pt_add_jac_aff
+ (rx, ry, &rz, &precomp[ni][0], &precomp[ni][1], rx, ry,
+ &rz, group));
+ }
+
+ /* convert result S to affine coordinates */
+ MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));
+
+ CLEANUP:
+ mp_clear(&rz);
+ for (i = 0; i < 16; i++) {
+ mp_clear(&precomp[i][0]);
+ mp_clear(&precomp[i][1]);
+ }
+ return res;
+}
+#endif
+
+/* Elliptic curve scalar-point multiplication. Computes R(x, y) = k1 * G +
+ * k2 * P(x, y), where G is the generator (base point) of the group of
+ * points on the elliptic curve. Allows k1 = NULL or { k2, P } = NULL.
+ * Uses mixed Jacobian-affine coordinates. Input and output values are
+ * assumed to be NOT field-encoded. Uses algorithm 15 (simultaneous
+ * multiple point multiplication) from Brown, Hankerson, Lopez, Menezes.
+ * Software Implementation of the NIST Elliptic Curves over Prime Fields. */
+mp_err
+ec_GFp_pts_mul_jac(const mp_int *k1, const mp_int *k2, const mp_int *px,
+ const mp_int *py, mp_int *rx, mp_int *ry,
+ const ECGroup *group, int timing)
+{
+ mp_err res = MP_OKAY;
+ mp_int precomp[4][4][2];
+ mp_int rz;
+ const mp_int *a, *b;
+ int i, j;
+ int ai, bi, d;
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ MP_DIGITS(&precomp[i][j][0]) = 0;
+ MP_DIGITS(&precomp[i][j][1]) = 0;
+ }
+ }
+ MP_DIGITS(&rz) = 0;
+
+ ARGCHK(group != NULL, MP_BADARG);
+ ARGCHK(!((k1 == NULL)
+ && ((k2 == NULL) || (px == NULL)
+ || (py == NULL))), MP_BADARG);
+
+ /* if some arguments are not defined used ECPoint_mul */
+ if (k1 == NULL) {
+ return ECPoint_mul(group, k2, px, py, rx, ry, timing);
+ } else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
+ return ECPoint_mul(group, k1, NULL, NULL, rx, ry, timing);
+ }
+
+ /* initialize precomputation table */
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ MP_CHECKOK(mp_init(&precomp[i][j][0], FLAG(k1)));
+ MP_CHECKOK(mp_init(&precomp[i][j][1], FLAG(k1)));
+ }
+ }
+
+ /* fill precomputation table */
+ /* assign {k1, k2} = {a, b} such that len(a) >= len(b) */
+ if (mpl_significant_bits(k1) < mpl_significant_bits(k2)) {
+ a = k2;
+ b = k1;
+ if (group->meth->field_enc) {
+ MP_CHECKOK(group->meth->
+ field_enc(px, &precomp[1][0][0], group->meth));
+ MP_CHECKOK(group->meth->
+ field_enc(py, &precomp[1][0][1], group->meth));
+ } else {
+ MP_CHECKOK(mp_copy(px, &precomp[1][0][0]));
+ MP_CHECKOK(mp_copy(py, &precomp[1][0][1]));
+ }
+ MP_CHECKOK(mp_copy(&group->genx, &precomp[0][1][0]));
+ MP_CHECKOK(mp_copy(&group->geny, &precomp[0][1][1]));
+ } else {
+ a = k1;
+ b = k2;
+ MP_CHECKOK(mp_copy(&group->genx, &precomp[1][0][0]));
+ MP_CHECKOK(mp_copy(&group->geny, &precomp[1][0][1]));
+ if (group->meth->field_enc) {
+ MP_CHECKOK(group->meth->
+ field_enc(px, &precomp[0][1][0], group->meth));
+ MP_CHECKOK(group->meth->
+ field_enc(py, &precomp[0][1][1], group->meth));
+ } else {
+ MP_CHECKOK(mp_copy(px, &precomp[0][1][0]));
+ MP_CHECKOK(mp_copy(py, &precomp[0][1][1]));
+ }
+ }
+ /* precompute [*][0][*] */
+ mp_zero(&precomp[0][0][0]);
+ mp_zero(&precomp[0][0][1]);
+ MP_CHECKOK(group->
+ point_dbl(&precomp[1][0][0], &precomp[1][0][1],
+ &precomp[2][0][0], &precomp[2][0][1], group));
+ MP_CHECKOK(group->
+ point_add(&precomp[1][0][0], &precomp[1][0][1],
+ &precomp[2][0][0], &precomp[2][0][1],
+ &precomp[3][0][0], &precomp[3][0][1], group));
+ /* precompute [*][1][*] */
+ for (i = 1; i < 4; i++) {
+ MP_CHECKOK(group->
+ point_add(&precomp[0][1][0], &precomp[0][1][1],
+ &precomp[i][0][0], &precomp[i][0][1],
+ &precomp[i][1][0], &precomp[i][1][1], group));
+ }
+ /* precompute [*][2][*] */
+ MP_CHECKOK(group->
+ point_dbl(&precomp[0][1][0], &precomp[0][1][1],
+ &precomp[0][2][0], &precomp[0][2][1], group));
+ for (i = 1; i < 4; i++) {
+ MP_CHECKOK(group->
+ point_add(&precomp[0][2][0], &precomp[0][2][1],
+ &precomp[i][0][0], &precomp[i][0][1],
+ &precomp[i][2][0], &precomp[i][2][1], group));
+ }
+ /* precompute [*][3][*] */
+ MP_CHECKOK(group->
+ point_add(&precomp[0][1][0], &precomp[0][1][1],
+ &precomp[0][2][0], &precomp[0][2][1],
+ &precomp[0][3][0], &precomp[0][3][1], group));
+ for (i = 1; i < 4; i++) {
+ MP_CHECKOK(group->
+ point_add(&precomp[0][3][0], &precomp[0][3][1],
+ &precomp[i][0][0], &precomp[i][0][1],
+ &precomp[i][3][0], &precomp[i][3][1], group));
+ }
+
+ d = (mpl_significant_bits(a) + 1) / 2;
+
+ /* R = inf */
+ MP_CHECKOK(mp_init(&rz, FLAG(k1)));
+ MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz));
+
+ for (i = d - 1; i >= 0; i--) {
+ ai = MP_GET_BIT(a, 2 * i + 1);
+ ai <<= 1;
+ ai |= MP_GET_BIT(a, 2 * i);
+ bi = MP_GET_BIT(b, 2 * i + 1);
+ bi <<= 1;
+ bi |= MP_GET_BIT(b, 2 * i);
+ /* R = 2^2 * R */
+ MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+ MP_CHECKOK(ec_GFp_pt_dbl_jac(rx, ry, &rz, rx, ry, &rz, group));
+ /* R = R + (ai * A + bi * B) */
+ MP_CHECKOK(ec_GFp_pt_add_jac_aff
+ (rx, ry, &rz, &precomp[ai][bi][0], &precomp[ai][bi][1],
+ rx, ry, &rz, group));
+ }
+
+ MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));
+
+ if (group->meth->field_dec) {
+ MP_CHECKOK(group->meth->field_dec(rx, rx, group->meth));
+ MP_CHECKOK(group->meth->field_dec(ry, ry, group->meth));
+ }
+
+ CLEANUP:
+ mp_clear(&rz);
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ mp_clear(&precomp[i][j][0]);
+ mp_clear(&precomp[i][j][1]);
+ }
+ }
+ return res;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c b/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c
new file mode 100644
index 0000000..c5cdef9
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library for prime field curves.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Stephen Fung <fungstep@hotmail.com>, Sun Microsystems Laboratories
+ *
+ * Last Modified Date from the Original Code: May 2017
+ *********************************************************************** */
+
+#include "ecp.h"
+#include "ecl-priv.h"
+#include "mplogic.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#endif
+
+#define MAX_SCRATCH 6
+
+/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses
+ * Modified Jacobian coordinates.
+ *
+ * Assumes input is already field-encoded using field_enc, and returns
+ * output that is still field-encoded.
+ *
+ */
+mp_err
+ec_GFp_pt_dbl_jm(const mp_int *px, const mp_int *py, const mp_int *pz,
+ const mp_int *paz4, mp_int *rx, mp_int *ry, mp_int *rz,
+ mp_int *raz4, mp_int scratch[], const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ mp_int *t0, *t1, *M, *S;
+
+ t0 = &scratch[0];
+ t1 = &scratch[1];
+ M = &scratch[2];
+ S = &scratch[3];
+
+#if MAX_SCRATCH < 4
+#error "Scratch array defined too small "
+#endif
+
+ /* Check for point at infinity */
+ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
+ /* Set r = pt at infinity by setting rz = 0 */
+
+ MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
+ goto CLEANUP;
+ }
+
+ /* M = 3 (px^2) + a*(pz^4) */
+ MP_CHECKOK(group->meth->field_sqr(px, t0, group->meth));
+ MP_CHECKOK(group->meth->field_add(t0, t0, M, group->meth));
+ MP_CHECKOK(group->meth->field_add(t0, M, t0, group->meth));
+ MP_CHECKOK(group->meth->field_add(t0, paz4, M, group->meth));
+
+ /* rz = 2 * py * pz */
+ MP_CHECKOK(group->meth->field_mul(py, pz, S, group->meth));
+ MP_CHECKOK(group->meth->field_add(S, S, rz, group->meth));
+
+ /* t0 = 2y^2 , t1 = 8y^4 */
+ MP_CHECKOK(group->meth->field_sqr(py, t0, group->meth));
+ MP_CHECKOK(group->meth->field_add(t0, t0, t0, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(t0, t1, group->meth));
+ MP_CHECKOK(group->meth->field_add(t1, t1, t1, group->meth));
+
+ /* S = 4 * px * py^2 = 2 * px * t0 */
+ MP_CHECKOK(group->meth->field_mul(px, t0, S, group->meth));
+ MP_CHECKOK(group->meth->field_add(S, S, S, group->meth));
+
+
+ /* rx = M^2 - 2S */
+ MP_CHECKOK(group->meth->field_sqr(M, rx, group->meth));
+ MP_CHECKOK(group->meth->field_sub(rx, S, rx, group->meth));
+ MP_CHECKOK(group->meth->field_sub(rx, S, rx, group->meth));
+
+ /* ry = M * (S - rx) - t1 */
+ MP_CHECKOK(group->meth->field_sub(S, rx, S, group->meth));
+ MP_CHECKOK(group->meth->field_mul(S, M, ry, group->meth));
+ MP_CHECKOK(group->meth->field_sub(ry, t1, ry, group->meth));
+
+ /* ra*z^4 = 2*t1*(apz4) */
+ MP_CHECKOK(group->meth->field_mul(paz4, t1, raz4, group->meth));
+ MP_CHECKOK(group->meth->field_add(raz4, raz4, raz4, group->meth));
+
+
+ CLEANUP:
+ return res;
+}
+
+/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
+ * (qx, qy, 1). Elliptic curve points P, Q, and R can all be identical.
+ * Uses mixed Modified_Jacobian-affine coordinates. Assumes input is
+ * already field-encoded using field_enc, and returns output that is still
+ * field-encoded. */
+mp_err
+ec_GFp_pt_add_jm_aff(const mp_int *px, const mp_int *py, const mp_int *pz,
+ const mp_int *paz4, const mp_int *qx,
+ const mp_int *qy, mp_int *rx, mp_int *ry, mp_int *rz,
+ mp_int *raz4, mp_int scratch[], const ECGroup *group)
+{
+ mp_err res = MP_OKAY;
+ mp_int *A, *B, *C, *D, *C2, *C3;
+
+ A = &scratch[0];
+ B = &scratch[1];
+ C = &scratch[2];
+ D = &scratch[3];
+ C2 = &scratch[4];
+ C3 = &scratch[5];
+
+#if MAX_SCRATCH < 6
+#error "Scratch array defined too small "
+#endif
+
+ /* If either P or Q is the point at infinity, then return the other
+ * point */
+ if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
+ MP_CHECKOK(ec_GFp_pt_aff2jac(qx, qy, rx, ry, rz, group));
+ MP_CHECKOK(group->meth->field_sqr(rz, raz4, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(raz4, raz4, group->meth));
+ MP_CHECKOK(group->meth->
+ field_mul(raz4, &group->curvea, raz4, group->meth));
+ goto CLEANUP;
+ }
+ if (ec_GFp_pt_is_inf_aff(qx, qy) == MP_YES) {
+ MP_CHECKOK(mp_copy(px, rx));
+ MP_CHECKOK(mp_copy(py, ry));
+ MP_CHECKOK(mp_copy(pz, rz));
+ MP_CHECKOK(mp_copy(paz4, raz4));
+ goto CLEANUP;
+ }
+
+ /* A = qx * pz^2, B = qy * pz^3 */
+ MP_CHECKOK(group->meth->field_sqr(pz, A, group->meth));
+ MP_CHECKOK(group->meth->field_mul(A, pz, B, group->meth));
+ MP_CHECKOK(group->meth->field_mul(A, qx, A, group->meth));
+ MP_CHECKOK(group->meth->field_mul(B, qy, B, group->meth));
+
+ /*
+ * Additional checks for point equality and point at infinity
+ */
+ if (mp_cmp(px, A) == 0 && mp_cmp(py, B) == 0) {
+ /* POINT_DOUBLE(P) */
+ MP_CHECKOK(ec_GFp_pt_dbl_jm(px, py, pz, paz4, rx, ry, rz, raz4,
+ scratch, group));
+ goto CLEANUP;
+ }
+
+ /* C = A - px, D = B - py */
+ MP_CHECKOK(group->meth->field_sub(A, px, C, group->meth));
+ MP_CHECKOK(group->meth->field_sub(B, py, D, group->meth));
+
+ /* C2 = C^2, C3 = C^3 */
+ MP_CHECKOK(group->meth->field_sqr(C, C2, group->meth));
+ MP_CHECKOK(group->meth->field_mul(C, C2, C3, group->meth));
+
+ /* rz = pz * C */
+ MP_CHECKOK(group->meth->field_mul(pz, C, rz, group->meth));
+
+ /* C = px * C^2 */
+ MP_CHECKOK(group->meth->field_mul(px, C2, C, group->meth));
+ /* A = D^2 */
+ MP_CHECKOK(group->meth->field_sqr(D, A, group->meth));
+
+ /* rx = D^2 - (C^3 + 2 * (px * C^2)) */
+ MP_CHECKOK(group->meth->field_add(C, C, rx, group->meth));
+ MP_CHECKOK(group->meth->field_add(C3, rx, rx, group->meth));
+ MP_CHECKOK(group->meth->field_sub(A, rx, rx, group->meth));
+
+ /* C3 = py * C^3 */
+ MP_CHECKOK(group->meth->field_mul(py, C3, C3, group->meth));
+
+ /* ry = D * (px * C^2 - rx) - py * C^3 */
+ MP_CHECKOK(group->meth->field_sub(C, rx, ry, group->meth));
+ MP_CHECKOK(group->meth->field_mul(D, ry, ry, group->meth));
+ MP_CHECKOK(group->meth->field_sub(ry, C3, ry, group->meth));
+
+ /* raz4 = a * rz^4 */
+ MP_CHECKOK(group->meth->field_sqr(rz, raz4, group->meth));
+ MP_CHECKOK(group->meth->field_sqr(raz4, raz4, group->meth));
+ MP_CHECKOK(group->meth->
+ field_mul(raz4, &group->curvea, raz4, group->meth));
+CLEANUP:
+ return res;
+}
+
+/* Computes R = nP where R is (rx, ry) and P is the base point. Elliptic
+ * curve points P and R can be identical. Uses mixed Modified-Jacobian
+ * co-ordinates for doubling and Chudnovsky Jacobian coordinates for
+ * additions. Assumes input is already field-encoded using field_enc, and
+ * returns output that is still field-encoded. Uses 5-bit window NAF
+ * method (algorithm 11) for scalar-point multiplication from Brown,
+ * Hankerson, Lopez, Menezes. Software Implementation of the NIST Elliptic
+ * Curves Over Prime Fields. */
+mp_err
+ec_GFp_pt_mul_jm_wNAF(const mp_int *n, const mp_int *px, const mp_int *py,
+ mp_int *rx, mp_int *ry, const ECGroup *group,
+ int timing)
+{
+ mp_err res = MP_OKAY;
+ mp_int precomp[16][2], rz, tpx, tpy, tpz;
+ mp_int raz4, tpaz4;
+ mp_int scratch[MAX_SCRATCH];
+ signed char *naf = NULL;
+ int i, orderBitSize;
+ int numDoubles, numAdds, extraDoubles, extraAdds;
+
+ MP_DIGITS(&rz) = 0;
+ MP_DIGITS(&raz4) = 0;
+ MP_DIGITS(&tpx) = 0;
+ MP_DIGITS(&tpy) = 0;
+ MP_DIGITS(&tpz) = 0;
+ MP_DIGITS(&tpaz4) = 0;
+ for (i = 0; i < 16; i++) {
+ MP_DIGITS(&precomp[i][0]) = 0;
+ MP_DIGITS(&precomp[i][1]) = 0;
+ }
+ for (i = 0; i < MAX_SCRATCH; i++) {
+ MP_DIGITS(&scratch[i]) = 0;
+ }
+
+ ARGCHK(group != NULL, MP_BADARG);
+ ARGCHK((n != NULL) && (px != NULL) && (py != NULL), MP_BADARG);
+
+ /* initialize precomputation table */
+ MP_CHECKOK(mp_init(&tpx, FLAG(n)));
+ MP_CHECKOK(mp_init(&tpy, FLAG(n)));
+ MP_CHECKOK(mp_init(&tpz, FLAG(n)));
+ MP_CHECKOK(mp_init(&tpaz4, FLAG(n)));
+ MP_CHECKOK(mp_init(&rz, FLAG(n)));
+ MP_CHECKOK(mp_init(&raz4, FLAG(n)));
+
+ for (i = 0; i < 16; i++) {
+ MP_CHECKOK(mp_init(&precomp[i][0], FLAG(n)));
+ MP_CHECKOK(mp_init(&precomp[i][1], FLAG(n)));
+ }
+ for (i = 0; i < MAX_SCRATCH; i++) {
+ MP_CHECKOK(mp_init(&scratch[i], FLAG(n)));
+ }
+
+ /* Set out[8] = P */
+ MP_CHECKOK(mp_copy(px, &precomp[8][0]));
+ MP_CHECKOK(mp_copy(py, &precomp[8][1]));
+
+ /* Set (tpx, tpy) = 2P */
+ MP_CHECKOK(group->
+ point_dbl(&precomp[8][0], &precomp[8][1], &tpx, &tpy,
+ group));
+
+ /* Set 3P, 5P, ..., 15P */
+ for (i = 8; i < 15; i++) {
+ MP_CHECKOK(group->
+ point_add(&precomp[i][0], &precomp[i][1], &tpx, &tpy,
+ &precomp[i + 1][0], &precomp[i + 1][1],
+ group));
+ }
+
+ /* Set -15P, -13P, ..., -P */
+ for (i = 0; i < 8; i++) {
+ MP_CHECKOK(mp_copy(&precomp[15 - i][0], &precomp[i][0]));
+ MP_CHECKOK(group->meth->
+ field_neg(&precomp[15 - i][1], &precomp[i][1],
+ group->meth));
+ }
+
+ /* R = inf */
+ MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz));
+
+ orderBitSize = mpl_significant_bits(&group->order);
+
+ /* Allocate memory for NAF */
+#ifdef _KERNEL
+ naf = (signed char *) kmem_alloc((orderBitSize + 1), FLAG(n));
+#else
+ naf = (signed char *) malloc(sizeof(signed char) * (orderBitSize + 1));
+ if (naf == NULL) {
+ res = MP_MEM;
+ goto CLEANUP;
+ }
+#endif
+
+ /* Compute 5NAF */
+ ec_compute_wNAF(naf, orderBitSize, n, 5);
+
+ numAdds = 0;
+ numDoubles = orderBitSize;
+ /* wNAF method */
+ for (i = orderBitSize; i >= 0; i--) {
+
+ if (ec_GFp_pt_is_inf_jac(rx, ry, &rz) == MP_YES) {
+ numDoubles--;
+ }
+
+ /* R = 2R */
+ ec_GFp_pt_dbl_jm(rx, ry, &rz, &raz4, rx, ry, &rz,
+ &raz4, scratch, group);
+
+ if (naf[i] != 0) {
+ ec_GFp_pt_add_jm_aff(rx, ry, &rz, &raz4,
+ &precomp[(naf[i] + 15) / 2][0],
+ &precomp[(naf[i] + 15) / 2][1], rx, ry,
+ &rz, &raz4, scratch, group);
+ numAdds++;
+ }
+ }
+
+ /* extra operations to make timing less dependent on secrets */
+ if (timing) {
+ /* low-order bit of timing argument contains no entropy */
+ timing >>= 1;
+
+ MP_CHECKOK(ec_GFp_pt_set_inf_jac(&tpx, &tpy, &tpz));
+ mp_zero(&tpaz4);
+
+ /* Set the temp value to a non-infinite point */
+ ec_GFp_pt_add_jm_aff(&tpx, &tpy, &tpz, &tpaz4,
+ &precomp[8][0],
+ &precomp[8][1], &tpx, &tpy,
+ &tpz, &tpaz4, scratch, group);
+
+ /* two bits of extra adds */
+ extraAdds = timing & 0x3;
+ timing >>= 2;
+ /* Window size is 5, so the maximum number of additions is ceil(orderBitSize/5) */
+ /* This is the same as (orderBitSize + 4) / 5 */
+ for(i = numAdds; i <= (orderBitSize + 4) / 5 + extraAdds; i++) {
+ ec_GFp_pt_add_jm_aff(&tpx, &tpy, &tpz, &tpaz4,
+ &precomp[9 + (i % 3)][0],
+ &precomp[9 + (i % 3)][1], &tpx, &tpy,
+ &tpz, &tpaz4, scratch, group);
+ }
+
+ /* two bits of extra doubles */
+ extraDoubles = timing & 0x3;
+ timing >>= 2;
+ for(i = numDoubles; i <= orderBitSize + extraDoubles; i++) {
+ ec_GFp_pt_dbl_jm(&tpx, &tpy, &tpz, &tpaz4, &tpx, &tpy, &tpz,
+ &tpaz4, scratch, group);
+ }
+
+ }
+
+ /* convert result S to affine coordinates */
+ MP_CHECKOK(ec_GFp_pt_jac2aff(rx, ry, &rz, rx, ry, group));
+
+ CLEANUP:
+ for (i = 0; i < MAX_SCRATCH; i++) {
+ mp_clear(&scratch[i]);
+ }
+ for (i = 0; i < 16; i++) {
+ mp_clear(&precomp[i][0]);
+ mp_clear(&precomp[i][1]);
+ }
+ mp_clear(&tpx);
+ mp_clear(&tpy);
+ mp_clear(&tpz);
+ mp_clear(&tpaz4);
+ mp_clear(&rz);
+ mp_clear(&raz4);
+#ifdef _KERNEL
+ kmem_free(naf, (orderBitSize + 1));
+#else
+ free(naf);
+#endif
+ return res;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/ecp_mont.c b/jdk.crypto.ec/share/native/libsunec/impl/ecp_mont.c
new file mode 100644
index 0000000..6b5d6a6
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/ecp_mont.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the elliptic curve math library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
+ *
+ *********************************************************************** */
+
+/* Uses Montgomery reduction for field arithmetic. See mpi/mpmontg.c for
+ * code implementation. */
+
+#include "mpi.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+#include "ecl-priv.h"
+#include "ecp.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#include <stdio.h>
+#endif
+
+/* Construct a generic GFMethod for arithmetic over prime fields with
+ * irreducible irr. */
+GFMethod *
+GFMethod_consGFp_mont(const mp_int *irr)
+{
+ mp_err res = MP_OKAY;
+ int i;
+ GFMethod *meth = NULL;
+ mp_mont_modulus *mmm;
+
+ meth = GFMethod_consGFp(irr);
+ if (meth == NULL)
+ return NULL;
+
+#ifdef _KERNEL
+ mmm = (mp_mont_modulus *) kmem_alloc(sizeof(mp_mont_modulus),
+ FLAG(irr));
+#else
+ mmm = (mp_mont_modulus *) malloc(sizeof(mp_mont_modulus));
+#endif
+ if (mmm == NULL) {
+ res = MP_MEM;
+ goto CLEANUP;
+ }
+
+ meth->field_mul = &ec_GFp_mul_mont;
+ meth->field_sqr = &ec_GFp_sqr_mont;
+ meth->field_div = &ec_GFp_div_mont;
+ meth->field_enc = &ec_GFp_enc_mont;
+ meth->field_dec = &ec_GFp_dec_mont;
+ meth->extra1 = mmm;
+ meth->extra2 = NULL;
+ meth->extra_free = &ec_GFp_extra_free_mont;
+
+ mmm->N = meth->irr;
+ i = mpl_significant_bits(&meth->irr);
+ i += MP_DIGIT_BIT - 1;
+ mmm->b = i - i % MP_DIGIT_BIT;
+ mmm->n0prime = 0 - s_mp_invmod_radix(MP_DIGIT(&meth->irr, 0));
+
+ CLEANUP:
+ if (res != MP_OKAY) {
+ GFMethod_free(meth);
+ return NULL;
+ }
+ return meth;
+}
+
+/* Wrapper functions for generic prime field arithmetic. */
+
+/* Field multiplication using Montgomery reduction. */
+mp_err
+ec_GFp_mul_mont(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+#ifdef MP_MONT_USE_MP_MUL
+ /* if MP_MONT_USE_MP_MUL is defined, then the function s_mp_mul_mont
+ * is not implemented and we have to use mp_mul and s_mp_redc directly
+ */
+ MP_CHECKOK(mp_mul(a, b, r));
+ MP_CHECKOK(s_mp_redc(r, (mp_mont_modulus *) meth->extra1));
+#else
+ mp_int s;
+
+ MP_DIGITS(&s) = 0;
+ /* s_mp_mul_mont doesn't allow source and destination to be the same */
+ if ((a == r) || (b == r)) {
+ MP_CHECKOK(mp_init(&s, FLAG(a)));
+ MP_CHECKOK(s_mp_mul_mont
+ (a, b, &s, (mp_mont_modulus *) meth->extra1));
+ MP_CHECKOK(mp_copy(&s, r));
+ mp_clear(&s);
+ } else {
+ return s_mp_mul_mont(a, b, r, (mp_mont_modulus *) meth->extra1);
+ }
+#endif
+ CLEANUP:
+ return res;
+}
+
+/* Field squaring using Montgomery reduction. */
+mp_err
+ec_GFp_sqr_mont(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ return ec_GFp_mul_mont(a, a, r, meth);
+}
+
+/* Field division using Montgomery reduction. */
+mp_err
+ec_GFp_div_mont(const mp_int *a, const mp_int *b, mp_int *r,
+ const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ /* if A=aZ represents a encoded in montgomery coordinates with Z and #
+ * and \ respectively represent multiplication and division in
+ * montgomery coordinates, then A\B = (a/b)Z = (A/B)Z and Binv =
+ * (1/b)Z = (1/B)(Z^2) where B # Binv = Z */
+ MP_CHECKOK(ec_GFp_div(a, b, r, meth));
+ MP_CHECKOK(ec_GFp_enc_mont(r, r, meth));
+ if (a == NULL) {
+ MP_CHECKOK(ec_GFp_enc_mont(r, r, meth));
+ }
+ CLEANUP:
+ return res;
+}
+
+/* Encode a field element in Montgomery form. See s_mp_to_mont in
+ * mpi/mpmontg.c */
+mp_err
+ec_GFp_enc_mont(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_mont_modulus *mmm;
+ mp_err res = MP_OKAY;
+
+ mmm = (mp_mont_modulus *) meth->extra1;
+ MP_CHECKOK(mpl_lsh(a, r, mmm->b));
+ MP_CHECKOK(mp_mod(r, &mmm->N, r));
+ CLEANUP:
+ return res;
+}
+
+/* Decode a field element from Montgomery form. */
+mp_err
+ec_GFp_dec_mont(const mp_int *a, mp_int *r, const GFMethod *meth)
+{
+ mp_err res = MP_OKAY;
+
+ if (a != r) {
+ MP_CHECKOK(mp_copy(a, r));
+ }
+ MP_CHECKOK(s_mp_redc(r, (mp_mont_modulus *) meth->extra1));
+ CLEANUP:
+ return res;
+}
+
+/* Free the memory allocated to the extra fields of Montgomery GFMethod
+ * object. */
+void
+ec_GFp_extra_free_mont(GFMethod *meth)
+{
+ if (meth->extra1 != NULL) {
+#ifdef _KERNEL
+ kmem_free(meth->extra1, sizeof(mp_mont_modulus));
+#else
+ free(meth->extra1);
+#endif
+ meth->extra1 = NULL;
+ }
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/logtab.h b/jdk.crypto.ec/share/native/libsunec/impl/logtab.h
new file mode 100644
index 0000000..9f709cc
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/logtab.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ *********************************************************************** */
+
+#ifndef _LOGTAB_H
+#define _LOGTAB_H
+
+const float s_logv_2[] = {
+ 0.000000000f, 0.000000000f, 1.000000000f, 0.630929754f, /* 0 1 2 3 */
+ 0.500000000f, 0.430676558f, 0.386852807f, 0.356207187f, /* 4 5 6 7 */
+ 0.333333333f, 0.315464877f, 0.301029996f, 0.289064826f, /* 8 9 10 11 */
+ 0.278942946f, 0.270238154f, 0.262649535f, 0.255958025f, /* 12 13 14 15 */
+ 0.250000000f, 0.244650542f, 0.239812467f, 0.235408913f, /* 16 17 18 19 */
+ 0.231378213f, 0.227670249f, 0.224243824f, 0.221064729f, /* 20 21 22 23 */
+ 0.218104292f, 0.215338279f, 0.212746054f, 0.210309918f, /* 24 25 26 27 */
+ 0.208014598f, 0.205846832f, 0.203795047f, 0.201849087f, /* 28 29 30 31 */
+ 0.200000000f, 0.198239863f, 0.196561632f, 0.194959022f, /* 32 33 34 35 */
+ 0.193426404f, 0.191958720f, 0.190551412f, 0.189200360f, /* 36 37 38 39 */
+ 0.187901825f, 0.186652411f, 0.185449023f, 0.184288833f, /* 40 41 42 43 */
+ 0.183169251f, 0.182087900f, 0.181042597f, 0.180031327f, /* 44 45 46 47 */
+ 0.179052232f, 0.178103594f, 0.177183820f, 0.176291434f, /* 48 49 50 51 */
+ 0.175425064f, 0.174583430f, 0.173765343f, 0.172969690f, /* 52 53 54 55 */
+ 0.172195434f, 0.171441601f, 0.170707280f, 0.169991616f, /* 56 57 58 59 */
+ 0.169293808f, 0.168613099f, 0.167948779f, 0.167300179f, /* 60 61 62 63 */
+ 0.166666667f
+};
+
+#endif /* _LOGTAB_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/mp_gf2m-priv.h b/jdk.crypto.ec/share/native/libsunec/impl/mp_gf2m-priv.h
new file mode 100644
index 0000000..caa56e4
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/mp_gf2m-priv.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the Multi-precision Binary Polynomial Arithmetic Library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sheueling Chang Shantz <sheueling.chang@sun.com> and
+ * Douglas Stebila <douglas@stebila.ca> of Sun Laboratories.
+ *
+ *********************************************************************** */
+
+#ifndef _MP_GF2M_PRIV_H_
+#define _MP_GF2M_PRIV_H_
+
+#include "mpi-priv.h"
+
+extern const mp_digit mp_gf2m_sqr_tb[16];
+
+#if defined(MP_USE_UINT_DIGIT)
+#define MP_DIGIT_BITS 32
+#else
+#define MP_DIGIT_BITS 64
+#endif
+
+/* Platform-specific macros for fast binary polynomial squaring. */
+#if MP_DIGIT_BITS == 32
+#define gf2m_SQR1(w) \
+ mp_gf2m_sqr_tb[(w) >> 28 & 0xF] << 24 | mp_gf2m_sqr_tb[(w) >> 24 & 0xF] << 16 | \
+ mp_gf2m_sqr_tb[(w) >> 20 & 0xF] << 8 | mp_gf2m_sqr_tb[(w) >> 16 & 0xF]
+#define gf2m_SQR0(w) \
+ mp_gf2m_sqr_tb[(w) >> 12 & 0xF] << 24 | mp_gf2m_sqr_tb[(w) >> 8 & 0xF] << 16 | \
+ mp_gf2m_sqr_tb[(w) >> 4 & 0xF] << 8 | mp_gf2m_sqr_tb[(w) & 0xF]
+#else
+#define gf2m_SQR1(w) \
+ mp_gf2m_sqr_tb[(w) >> 60 & 0xF] << 56 | mp_gf2m_sqr_tb[(w) >> 56 & 0xF] << 48 | \
+ mp_gf2m_sqr_tb[(w) >> 52 & 0xF] << 40 | mp_gf2m_sqr_tb[(w) >> 48 & 0xF] << 32 | \
+ mp_gf2m_sqr_tb[(w) >> 44 & 0xF] << 24 | mp_gf2m_sqr_tb[(w) >> 40 & 0xF] << 16 | \
+ mp_gf2m_sqr_tb[(w) >> 36 & 0xF] << 8 | mp_gf2m_sqr_tb[(w) >> 32 & 0xF]
+#define gf2m_SQR0(w) \
+ mp_gf2m_sqr_tb[(w) >> 28 & 0xF] << 56 | mp_gf2m_sqr_tb[(w) >> 24 & 0xF] << 48 | \
+ mp_gf2m_sqr_tb[(w) >> 20 & 0xF] << 40 | mp_gf2m_sqr_tb[(w) >> 16 & 0xF] << 32 | \
+ mp_gf2m_sqr_tb[(w) >> 12 & 0xF] << 24 | mp_gf2m_sqr_tb[(w) >> 8 & 0xF] << 16 | \
+ mp_gf2m_sqr_tb[(w) >> 4 & 0xF] << 8 | mp_gf2m_sqr_tb[(w) & 0xF]
+#endif
+
+/* Multiply two binary polynomials mp_digits a, b.
+ * Result is a polynomial with degree < 2 * MP_DIGIT_BITS - 1.
+ * Output in two mp_digits rh, rl.
+ */
+void s_bmul_1x1(mp_digit *rh, mp_digit *rl, const mp_digit a, const mp_digit b);
+
+/* Compute xor-multiply of two binary polynomials (a1, a0) x (b1, b0)
+ * result is a binary polynomial in 4 mp_digits r[4].
+ * The caller MUST ensure that r has the right amount of space allocated.
+ */
+void s_bmul_2x2(mp_digit *r, const mp_digit a1, const mp_digit a0, const mp_digit b1,
+ const mp_digit b0);
+
+/* Compute xor-multiply of two binary polynomials (a2, a1, a0) x (b2, b1, b0)
+ * result is a binary polynomial in 6 mp_digits r[6].
+ * The caller MUST ensure that r has the right amount of space allocated.
+ */
+void s_bmul_3x3(mp_digit *r, const mp_digit a2, const mp_digit a1, const mp_digit a0,
+ const mp_digit b2, const mp_digit b1, const mp_digit b0);
+
+/* Compute xor-multiply of two binary polynomials (a3, a2, a1, a0) x (b3, b2, b1, b0)
+ * result is a binary polynomial in 8 mp_digits r[8].
+ * The caller MUST ensure that r has the right amount of space allocated.
+ */
+void s_bmul_4x4(mp_digit *r, const mp_digit a3, const mp_digit a2, const mp_digit a1,
+ const mp_digit a0, const mp_digit b3, const mp_digit b2, const mp_digit b1,
+ const mp_digit b0);
+
+#endif /* _MP_GF2M_PRIV_H_ */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/mp_gf2m.c b/jdk.crypto.ec/share/native/libsunec/impl/mp_gf2m.c
new file mode 100644
index 0000000..31911c0
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/mp_gf2m.c
@@ -0,0 +1,603 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the Multi-precision Binary Polynomial Arithmetic Library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sheueling Chang Shantz <sheueling.chang@sun.com> and
+ * Douglas Stebila <douglas@stebila.ca> of Sun Laboratories.
+ *
+ *********************************************************************** */
+
+#include "mp_gf2m.h"
+#include "mp_gf2m-priv.h"
+#include "mplogic.h"
+#include "mpi-priv.h"
+
+const mp_digit mp_gf2m_sqr_tb[16] =
+{
+ 0, 1, 4, 5, 16, 17, 20, 21,
+ 64, 65, 68, 69, 80, 81, 84, 85
+};
+
+/* Multiply two binary polynomials mp_digits a, b.
+ * Result is a polynomial with degree < 2 * MP_DIGIT_BITS - 1.
+ * Output in two mp_digits rh, rl.
+ */
+#if MP_DIGIT_BITS == 32
+void
+s_bmul_1x1(mp_digit *rh, mp_digit *rl, const mp_digit a, const mp_digit b)
+{
+ register mp_digit h, l, s;
+ mp_digit tab[8], top2b = a >> 30;
+ register mp_digit a1, a2, a4;
+
+ a1 = a & (0x3FFFFFFF); a2 = a1 << 1; a4 = a2 << 1;
+
+ tab[0] = 0; tab[1] = a1; tab[2] = a2; tab[3] = a1^a2;
+ tab[4] = a4; tab[5] = a1^a4; tab[6] = a2^a4; tab[7] = a1^a2^a4;
+
+ s = tab[b & 0x7]; l = s;
+ s = tab[b >> 3 & 0x7]; l ^= s << 3; h = s >> 29;
+ s = tab[b >> 6 & 0x7]; l ^= s << 6; h ^= s >> 26;
+ s = tab[b >> 9 & 0x7]; l ^= s << 9; h ^= s >> 23;
+ s = tab[b >> 12 & 0x7]; l ^= s << 12; h ^= s >> 20;
+ s = tab[b >> 15 & 0x7]; l ^= s << 15; h ^= s >> 17;
+ s = tab[b >> 18 & 0x7]; l ^= s << 18; h ^= s >> 14;
+ s = tab[b >> 21 & 0x7]; l ^= s << 21; h ^= s >> 11;
+ s = tab[b >> 24 & 0x7]; l ^= s << 24; h ^= s >> 8;
+ s = tab[b >> 27 & 0x7]; l ^= s << 27; h ^= s >> 5;
+ s = tab[b >> 30 ]; l ^= s << 30; h ^= s >> 2;
+
+ /* compensate for the top two bits of a */
+
+ if (top2b & 01) { l ^= b << 30; h ^= b >> 2; }
+ if (top2b & 02) { l ^= b << 31; h ^= b >> 1; }
+
+ *rh = h; *rl = l;
+}
+#else
+void
+s_bmul_1x1(mp_digit *rh, mp_digit *rl, const mp_digit a, const mp_digit b)
+{
+ register mp_digit h, l, s;
+ mp_digit tab[16], top3b = a >> 61;
+ register mp_digit a1, a2, a4, a8;
+
+ a1 = a & (0x1FFFFFFFFFFFFFFFULL); a2 = a1 << 1;
+ a4 = a2 << 1; a8 = a4 << 1;
+ tab[ 0] = 0; tab[ 1] = a1; tab[ 2] = a2; tab[ 3] = a1^a2;
+ tab[ 4] = a4; tab[ 5] = a1^a4; tab[ 6] = a2^a4; tab[ 7] = a1^a2^a4;
+ tab[ 8] = a8; tab[ 9] = a1^a8; tab[10] = a2^a8; tab[11] = a1^a2^a8;
+ tab[12] = a4^a8; tab[13] = a1^a4^a8; tab[14] = a2^a4^a8; tab[15] = a1^a2^a4^a8;
+
+ s = tab[b & 0xF]; l = s;
+ s = tab[b >> 4 & 0xF]; l ^= s << 4; h = s >> 60;
+ s = tab[b >> 8 & 0xF]; l ^= s << 8; h ^= s >> 56;
+ s = tab[b >> 12 & 0xF]; l ^= s << 12; h ^= s >> 52;
+ s = tab[b >> 16 & 0xF]; l ^= s << 16; h ^= s >> 48;
+ s = tab[b >> 20 & 0xF]; l ^= s << 20; h ^= s >> 44;
+ s = tab[b >> 24 & 0xF]; l ^= s << 24; h ^= s >> 40;
+ s = tab[b >> 28 & 0xF]; l ^= s << 28; h ^= s >> 36;
+ s = tab[b >> 32 & 0xF]; l ^= s << 32; h ^= s >> 32;
+ s = tab[b >> 36 & 0xF]; l ^= s << 36; h ^= s >> 28;
+ s = tab[b >> 40 & 0xF]; l ^= s << 40; h ^= s >> 24;
+ s = tab[b >> 44 & 0xF]; l ^= s << 44; h ^= s >> 20;
+ s = tab[b >> 48 & 0xF]; l ^= s << 48; h ^= s >> 16;
+ s = tab[b >> 52 & 0xF]; l ^= s << 52; h ^= s >> 12;
+ s = tab[b >> 56 & 0xF]; l ^= s << 56; h ^= s >> 8;
+ s = tab[b >> 60 ]; l ^= s << 60; h ^= s >> 4;
+
+ /* compensate for the top three bits of a */
+
+ if (top3b & 01) { l ^= b << 61; h ^= b >> 3; }
+ if (top3b & 02) { l ^= b << 62; h ^= b >> 2; }
+ if (top3b & 04) { l ^= b << 63; h ^= b >> 1; }
+
+ *rh = h; *rl = l;
+}
+#endif
+
+/* Compute xor-multiply of two binary polynomials (a1, a0) x (b1, b0)
+ * result is a binary polynomial in 4 mp_digits r[4].
+ * The caller MUST ensure that r has the right amount of space allocated.
+ */
+void
+s_bmul_2x2(mp_digit *r, const mp_digit a1, const mp_digit a0, const mp_digit b1,
+ const mp_digit b0)
+{
+ mp_digit m1, m0;
+ /* r[3] = h1, r[2] = h0; r[1] = l1; r[0] = l0 */
+ s_bmul_1x1(r+3, r+2, a1, b1);
+ s_bmul_1x1(r+1, r, a0, b0);
+ s_bmul_1x1(&m1, &m0, a0 ^ a1, b0 ^ b1);
+ /* Correction on m1 ^= l1 ^ h1; m0 ^= l0 ^ h0; */
+ r[2] ^= m1 ^ r[1] ^ r[3]; /* h0 ^= m1 ^ l1 ^ h1; */
+ r[1] = r[3] ^ r[2] ^ r[0] ^ m1 ^ m0; /* l1 ^= l0 ^ h0 ^ m0; */
+}
+
+/* Compute xor-multiply of two binary polynomials (a2, a1, a0) x (b2, b1, b0)
+ * result is a binary polynomial in 6 mp_digits r[6].
+ * The caller MUST ensure that r has the right amount of space allocated.
+ */
+void
+s_bmul_3x3(mp_digit *r, const mp_digit a2, const mp_digit a1, const mp_digit a0,
+ const mp_digit b2, const mp_digit b1, const mp_digit b0)
+{
+ mp_digit zm[4];
+
+ s_bmul_1x1(r+5, r+4, a2, b2); /* fill top 2 words */
+ s_bmul_2x2(zm, a1, a2^a0, b1, b2^b0); /* fill middle 4 words */
+ s_bmul_2x2(r, a1, a0, b1, b0); /* fill bottom 4 words */
+
+ zm[3] ^= r[3];
+ zm[2] ^= r[2];
+ zm[1] ^= r[1] ^ r[5];
+ zm[0] ^= r[0] ^ r[4];
+
+ r[5] ^= zm[3];
+ r[4] ^= zm[2];
+ r[3] ^= zm[1];
+ r[2] ^= zm[0];
+}
+
+/* Compute xor-multiply of two binary polynomials (a3, a2, a1, a0) x (b3, b2, b1, b0)
+ * result is a binary polynomial in 8 mp_digits r[8].
+ * The caller MUST ensure that r has the right amount of space allocated.
+ */
+void s_bmul_4x4(mp_digit *r, const mp_digit a3, const mp_digit a2, const mp_digit a1,
+ const mp_digit a0, const mp_digit b3, const mp_digit b2, const mp_digit b1,
+ const mp_digit b0)
+{
+ mp_digit zm[4];
+
+ s_bmul_2x2(r+4, a3, a2, b3, b2); /* fill top 4 words */
+ s_bmul_2x2(zm, a3^a1, a2^a0, b3^b1, b2^b0); /* fill middle 4 words */
+ s_bmul_2x2(r, a1, a0, b1, b0); /* fill bottom 4 words */
+
+ zm[3] ^= r[3] ^ r[7];
+ zm[2] ^= r[2] ^ r[6];
+ zm[1] ^= r[1] ^ r[5];
+ zm[0] ^= r[0] ^ r[4];
+
+ r[5] ^= zm[3];
+ r[4] ^= zm[2];
+ r[3] ^= zm[1];
+ r[2] ^= zm[0];
+}
+
+/* Compute addition of two binary polynomials a and b,
+ * store result in c; c could be a or b, a and b could be equal;
+ * c is the bitwise XOR of a and b.
+ */
+mp_err
+mp_badd(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_digit *pa, *pb, *pc;
+ mp_size ix;
+ mp_size used_pa, used_pb;
+ mp_err res = MP_OKAY;
+
+ /* Add all digits up to the precision of b. If b had more
+ * precision than a initially, swap a, b first
+ */
+ if (MP_USED(a) >= MP_USED(b)) {
+ pa = MP_DIGITS(a);
+ pb = MP_DIGITS(b);
+ used_pa = MP_USED(a);
+ used_pb = MP_USED(b);
+ } else {
+ pa = MP_DIGITS(b);
+ pb = MP_DIGITS(a);
+ used_pa = MP_USED(b);
+ used_pb = MP_USED(a);
+ }
+
+ /* Make sure c has enough precision for the output value */
+ MP_CHECKOK( s_mp_pad(c, used_pa) );
+
+ /* Do word-by-word xor */
+ pc = MP_DIGITS(c);
+ for (ix = 0; ix < used_pb; ix++) {
+ (*pc++) = (*pa++) ^ (*pb++);
+ }
+
+ /* Finish the rest of digits until we're actually done */
+ for (; ix < used_pa; ++ix) {
+ *pc++ = *pa++;
+ }
+
+ MP_USED(c) = used_pa;
+ MP_SIGN(c) = ZPOS;
+ s_mp_clamp(c);
+
+CLEANUP:
+ return res;
+}
+
+#define s_mp_div2(a) MP_CHECKOK( mpl_rsh((a), (a), 1) );
+
+/* Compute binary polynomial multiply d = a * b */
+static void
+s_bmul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *d)
+{
+ mp_digit a_i, a0b0, a1b1, carry = 0;
+ while (a_len--) {
+ a_i = *a++;
+ s_bmul_1x1(&a1b1, &a0b0, a_i, b);
+ *d++ = a0b0 ^ carry;
+ carry = a1b1;
+ }
+ *d = carry;
+}
+
+/* Compute binary polynomial xor multiply accumulate d ^= a * b */
+static void
+s_bmul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *d)
+{
+ mp_digit a_i, a0b0, a1b1, carry = 0;
+ while (a_len--) {
+ a_i = *a++;
+ s_bmul_1x1(&a1b1, &a0b0, a_i, b);
+ *d++ ^= a0b0 ^ carry;
+ carry = a1b1;
+ }
+ *d ^= carry;
+}
+
+/* Compute binary polynomial xor multiply c = a * b.
+ * All parameters may be identical.
+ */
+mp_err
+mp_bmul(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_digit *pb, b_i;
+ mp_int tmp;
+ mp_size ib, a_used, b_used;
+ mp_err res = MP_OKAY;
+
+ MP_DIGITS(&tmp) = 0;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if (a == c) {
+ MP_CHECKOK( mp_init_copy(&tmp, a) );
+ if (a == b)
+ b = &tmp;
+ a = &tmp;
+ } else if (b == c) {
+ MP_CHECKOK( mp_init_copy(&tmp, b) );
+ b = &tmp;
+ }
+
+ if (MP_USED(a) < MP_USED(b)) {
+ const mp_int *xch = b; /* switch a and b if b longer */
+ b = a;
+ a = xch;
+ }
+
+ MP_USED(c) = 1; MP_DIGIT(c, 0) = 0;
+ MP_CHECKOK( s_mp_pad(c, USED(a) + USED(b)) );
+
+ pb = MP_DIGITS(b);
+ s_bmul_d(MP_DIGITS(a), MP_USED(a), *pb++, MP_DIGITS(c));
+
+ /* Outer loop: Digits of b */
+ a_used = MP_USED(a);
+ b_used = MP_USED(b);
+ MP_USED(c) = a_used + b_used;
+ for (ib = 1; ib < b_used; ib++) {
+ b_i = *pb++;
+
+ /* Inner product: Digits of a */
+ if (b_i)
+ s_bmul_d_add(MP_DIGITS(a), a_used, b_i, MP_DIGITS(c) + ib);
+ else
+ MP_DIGIT(c, ib + a_used) = b_i;
+ }
+
+ s_mp_clamp(c);
+
+ SIGN(c) = ZPOS;
+
+CLEANUP:
+ mp_clear(&tmp);
+ return res;
+}
+
+
+/* Compute modular reduction of a and store result in r.
+ * r could be a.
+ * For modular arithmetic, the irreducible polynomial f(t) is represented
+ * as an array of int[], where f(t) is of the form:
+ * f(t) = t^p[0] + t^p[1] + ... + t^p[k]
+ * where m = p[0] > p[1] > ... > p[k] = 0.
+ */
+mp_err
+mp_bmod(const mp_int *a, const unsigned int p[], mp_int *r)
+{
+ int j, k;
+ int n, dN, d0, d1;
+ mp_digit zz, *z, tmp;
+ mp_size used;
+ mp_err res = MP_OKAY;
+
+ /* The algorithm does the reduction in place in r,
+ * if a != r, copy a into r first so reduction can be done in r
+ */
+ if (a != r) {
+ MP_CHECKOK( mp_copy(a, r) );
+ }
+ z = MP_DIGITS(r);
+
+ /* start reduction */
+ dN = p[0] / MP_DIGIT_BITS;
+ used = MP_USED(r);
+
+ for (j = used - 1; j > dN;) {
+
+ zz = z[j];
+ if (zz == 0) {
+ j--; continue;
+ }
+ z[j] = 0;
+
+ for (k = 1; p[k] > 0; k++) {
+ /* reducing component t^p[k] */
+ n = p[0] - p[k];
+ d0 = n % MP_DIGIT_BITS;
+ d1 = MP_DIGIT_BITS - d0;
+ n /= MP_DIGIT_BITS;
+ z[j-n] ^= (zz>>d0);
+ if (d0)
+ z[j-n-1] ^= (zz<<d1);
+ }
+
+ /* reducing component t^0 */
+ n = dN;
+ d0 = p[0] % MP_DIGIT_BITS;
+ d1 = MP_DIGIT_BITS - d0;
+ z[j-n] ^= (zz >> d0);
+ if (d0)
+ z[j-n-1] ^= (zz << d1);
+
+ }
+
+ /* final round of reduction */
+ while (j == dN) {
+
+ d0 = p[0] % MP_DIGIT_BITS;
+ zz = z[dN] >> d0;
+ if (zz == 0) break;
+ d1 = MP_DIGIT_BITS - d0;
+
+ /* clear up the top d1 bits */
+ if (d0) z[dN] = (z[dN] << d1) >> d1;
+ *z ^= zz; /* reduction t^0 component */
+
+ for (k = 1; p[k] > 0; k++) {
+ /* reducing component t^p[k]*/
+ n = p[k] / MP_DIGIT_BITS;
+ d0 = p[k] % MP_DIGIT_BITS;
+ d1 = MP_DIGIT_BITS - d0;
+ z[n] ^= (zz << d0);
+ tmp = zz >> d1;
+ if (d0 && tmp)
+ z[n+1] ^= tmp;
+ }
+ }
+
+ s_mp_clamp(r);
+CLEANUP:
+ return res;
+}
+
+/* Compute the product of two polynomials a and b, reduce modulo p,
+ * Store the result in r. r could be a or b; a could be b.
+ */
+mp_err
+mp_bmulmod(const mp_int *a, const mp_int *b, const unsigned int p[], mp_int *r)
+{
+ mp_err res;
+
+ if (a == b) return mp_bsqrmod(a, p, r);
+ if ((res = mp_bmul(a, b, r) ) != MP_OKAY)
+ return res;
+ return mp_bmod(r, p, r);
+}
+
+/* Compute binary polynomial squaring c = a*a mod p .
+ * Parameter r and a can be identical.
+ */
+
+mp_err
+mp_bsqrmod(const mp_int *a, const unsigned int p[], mp_int *r)
+{
+ mp_digit *pa, *pr, a_i;
+ mp_int tmp;
+ mp_size ia, a_used;
+ mp_err res;
+
+ ARGCHK(a != NULL && r != NULL, MP_BADARG);
+ MP_DIGITS(&tmp) = 0;
+
+ if (a == r) {
+ MP_CHECKOK( mp_init_copy(&tmp, a) );
+ a = &tmp;
+ }
+
+ MP_USED(r) = 1; MP_DIGIT(r, 0) = 0;
+ MP_CHECKOK( s_mp_pad(r, 2*USED(a)) );
+
+ pa = MP_DIGITS(a);
+ pr = MP_DIGITS(r);
+ a_used = MP_USED(a);
+ MP_USED(r) = 2 * a_used;
+
+ for (ia = 0; ia < a_used; ia++) {
+ a_i = *pa++;
+ *pr++ = gf2m_SQR0(a_i);
+ *pr++ = gf2m_SQR1(a_i);
+ }
+
+ MP_CHECKOK( mp_bmod(r, p, r) );
+ s_mp_clamp(r);
+ SIGN(r) = ZPOS;
+
+CLEANUP:
+ mp_clear(&tmp);
+ return res;
+}
+
+/* Compute binary polynomial y/x mod p, y divided by x, reduce modulo p.
+ * Store the result in r. r could be x or y, and x could equal y.
+ * Uses algorithm Modular_Division_GF(2^m) from
+ * Chang-Shantz, S. "From Euclid's GCD to Montgomery Multiplication to
+ * the Great Divide".
+ */
+int
+mp_bdivmod(const mp_int *y, const mp_int *x, const mp_int *pp,
+ const unsigned int p[], mp_int *r)
+{
+ mp_int aa, bb, uu;
+ mp_int *a, *b, *u, *v;
+ mp_err res = MP_OKAY;
+
+ MP_DIGITS(&aa) = 0;
+ MP_DIGITS(&bb) = 0;
+ MP_DIGITS(&uu) = 0;
+
+ MP_CHECKOK( mp_init_copy(&aa, x) );
+ MP_CHECKOK( mp_init_copy(&uu, y) );
+ MP_CHECKOK( mp_init_copy(&bb, pp) );
+ MP_CHECKOK( s_mp_pad(r, USED(pp)) );
+ MP_USED(r) = 1; MP_DIGIT(r, 0) = 0;
+
+ a = &aa; b= &bb; u=&uu; v=r;
+ /* reduce x and y mod p */
+ MP_CHECKOK( mp_bmod(a, p, a) );
+ MP_CHECKOK( mp_bmod(u, p, u) );
+
+ while (!mp_isodd(a)) {
+ s_mp_div2(a);
+ if (mp_isodd(u)) {
+ MP_CHECKOK( mp_badd(u, pp, u) );
+ }
+ s_mp_div2(u);
+ }
+
+ do {
+ if (mp_cmp_mag(b, a) > 0) {
+ MP_CHECKOK( mp_badd(b, a, b) );
+ MP_CHECKOK( mp_badd(v, u, v) );
+ do {
+ s_mp_div2(b);
+ if (mp_isodd(v)) {
+ MP_CHECKOK( mp_badd(v, pp, v) );
+ }
+ s_mp_div2(v);
+ } while (!mp_isodd(b));
+ }
+ else if ((MP_DIGIT(a,0) == 1) && (MP_USED(a) == 1))
+ break;
+ else {
+ MP_CHECKOK( mp_badd(a, b, a) );
+ MP_CHECKOK( mp_badd(u, v, u) );
+ do {
+ s_mp_div2(a);
+ if (mp_isodd(u)) {
+ MP_CHECKOK( mp_badd(u, pp, u) );
+ }
+ s_mp_div2(u);
+ } while (!mp_isodd(a));
+ }
+ } while (1);
+
+ MP_CHECKOK( mp_copy(u, r) );
+
+CLEANUP:
+ /* XXX this appears to be a memory leak in the NSS code */
+ mp_clear(&aa);
+ mp_clear(&bb);
+ mp_clear(&uu);
+ return res;
+
+}
+
+/* Convert the bit-string representation of a polynomial a into an array
+ * of integers corresponding to the bits with non-zero coefficient.
+ * Up to max elements of the array will be filled. Return value is total
+ * number of coefficients that would be extracted if array was large enough.
+ */
+int
+mp_bpoly2arr(const mp_int *a, unsigned int p[], int max)
+{
+ int i, j, k;
+ mp_digit top_bit, mask;
+
+ top_bit = 1;
+ top_bit <<= MP_DIGIT_BIT - 1;
+
+ for (k = 0; k < max; k++) p[k] = 0;
+ k = 0;
+
+ for (i = MP_USED(a) - 1; i >= 0; i--) {
+ mask = top_bit;
+ for (j = MP_DIGIT_BIT - 1; j >= 0; j--) {
+ if (MP_DIGITS(a)[i] & mask) {
+ if (k < max) p[k] = MP_DIGIT_BIT * i + j;
+ k++;
+ }
+ mask >>= 1;
+ }
+ }
+
+ return k;
+}
+
+/* Convert the coefficient array representation of a polynomial to a
+ * bit-string. The array must be terminated by 0.
+ */
+mp_err
+mp_barr2poly(const unsigned int p[], mp_int *a)
+{
+
+ mp_err res = MP_OKAY;
+ int i;
+
+ mp_zero(a);
+ for (i = 0; p[i] > 0; i++) {
+ MP_CHECKOK( mpl_set_bit(a, p[i], 1) );
+ }
+ MP_CHECKOK( mpl_set_bit(a, 0, 1) );
+
+CLEANUP:
+ return res;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/mp_gf2m.h b/jdk.crypto.ec/share/native/libsunec/impl/mp_gf2m.h
new file mode 100644
index 0000000..c95d30f
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/mp_gf2m.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the Multi-precision Binary Polynomial Arithmetic Library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sheueling Chang Shantz <sheueling.chang@sun.com> and
+ * Douglas Stebila <douglas@stebila.ca> of Sun Laboratories.
+ *
+ *********************************************************************** */
+
+#ifndef _MP_GF2M_H_
+#define _MP_GF2M_H_
+
+#include "mpi.h"
+
+mp_err mp_badd(const mp_int *a, const mp_int *b, mp_int *c);
+mp_err mp_bmul(const mp_int *a, const mp_int *b, mp_int *c);
+
+/* For modular arithmetic, the irreducible polynomial f(t) is represented
+ * as an array of int[], where f(t) is of the form:
+ * f(t) = t^p[0] + t^p[1] + ... + t^p[k]
+ * where m = p[0] > p[1] > ... > p[k] = 0.
+ */
+mp_err mp_bmod(const mp_int *a, const unsigned int p[], mp_int *r);
+mp_err mp_bmulmod(const mp_int *a, const mp_int *b, const unsigned int p[],
+ mp_int *r);
+mp_err mp_bsqrmod(const mp_int *a, const unsigned int p[], mp_int *r);
+mp_err mp_bdivmod(const mp_int *y, const mp_int *x, const mp_int *pp,
+ const unsigned int p[], mp_int *r);
+
+int mp_bpoly2arr(const mp_int *a, unsigned int p[], int max);
+mp_err mp_barr2poly(const unsigned int p[], mp_int *a);
+
+#endif /* _MP_GF2M_H_ */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/mpi-config.h b/jdk.crypto.ec/share/native/libsunec/impl/mpi-config.h
new file mode 100644
index 0000000..a349f96
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/mpi-config.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1997
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Netscape Communications Corporation
+ *
+ *********************************************************************** */
+
+#ifndef _MPI_CONFIG_H
+#define _MPI_CONFIG_H
+
+/* $Id: mpi-config.h,v 1.5 2004/04/25 15:03:10 gerv%gerv.net Exp $ */
+
+/*
+ For boolean options,
+ 0 = no
+ 1 = yes
+
+ Other options are documented individually.
+
+ */
+
+#ifndef MP_IOFUNC
+#define MP_IOFUNC 0 /* include mp_print() ? */
+#endif
+
+#ifndef MP_MODARITH
+#define MP_MODARITH 1 /* include modular arithmetic ? */
+#endif
+
+#ifndef MP_NUMTH
+#define MP_NUMTH 1 /* include number theoretic functions? */
+#endif
+
+#ifndef MP_LOGTAB
+#define MP_LOGTAB 1 /* use table of logs instead of log()? */
+#endif
+
+#ifndef MP_MEMSET
+#define MP_MEMSET 1 /* use memset() to zero buffers? */
+#endif
+
+#ifndef MP_MEMCPY
+#define MP_MEMCPY 1 /* use memcpy() to copy buffers? */
+#endif
+
+#ifndef MP_CRYPTO
+#define MP_CRYPTO 1 /* erase memory on free? */
+#endif
+
+#ifndef MP_ARGCHK
+/*
+ 0 = no parameter checks
+ 1 = runtime checks, continue execution and return an error to caller
+ 2 = assertions; dump core on parameter errors
+ */
+#ifdef DEBUG
+#define MP_ARGCHK 2 /* how to check input arguments */
+#else
+#define MP_ARGCHK 1 /* how to check input arguments */
+#endif
+#endif
+
+#ifndef MP_DEBUG
+#define MP_DEBUG 0 /* print diagnostic output? */
+#endif
+
+#ifndef MP_DEFPREC
+#define MP_DEFPREC 64 /* default precision, in digits */
+#endif
+
+#ifndef MP_MACRO
+#define MP_MACRO 0 /* use macros for frequent calls? */
+#endif
+
+#ifndef MP_SQUARE
+#define MP_SQUARE 1 /* use separate squaring code? */
+#endif
+
+#endif /* _MPI_CONFIG_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/mpi-priv.h b/jdk.crypto.ec/share/native/libsunec/impl/mpi-priv.h
new file mode 100644
index 0000000..76bac90
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/mpi-priv.h
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Netscape Communications Corporation
+ *
+ *********************************************************************** */
+
+/* Arbitrary precision integer arithmetic library
+ *
+ * NOTE WELL: the content of this header file is NOT part of the "public"
+ * API for the MPI library, and may change at any time.
+ * Application programs that use libmpi should NOT include this header file.
+ */
+
+#ifndef _MPI_PRIV_H
+#define _MPI_PRIV_H
+
+/* $Id: mpi-priv.h,v 1.20 2005/11/22 07:16:43 relyea%netscape.com Exp $ */
+
+#include "mpi.h"
+#ifndef _KERNEL
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#endif /* _KERNEL */
+
+#if MP_DEBUG
+#include <stdio.h>
+
+#define DIAG(T,V) {fprintf(stderr,T);mp_print(V,stderr);fputc('\n',stderr);}
+#else
+#define DIAG(T,V)
+#endif
+
+/* If we aren't using a wired-in logarithm table, we need to include
+ the math library to get the log() function
+ */
+
+/* {{{ s_logv_2[] - log table for 2 in various bases */
+
+#if MP_LOGTAB
+/*
+ A table of the logs of 2 for various bases (the 0 and 1 entries of
+ this table are meaningless and should not be referenced).
+
+ This table is used to compute output lengths for the mp_toradix()
+ function. Since a number n in radix r takes up about log_r(n)
+ digits, we estimate the output size by taking the least integer
+ greater than log_r(n), where:
+
+ log_r(n) = log_2(n) * log_r(2)
+
+ This table, therefore, is a table of log_r(2) for 2 <= r <= 36,
+ which are the output bases supported.
+ */
+
+extern const float s_logv_2[];
+#define LOG_V_2(R) s_logv_2[(R)]
+
+#else
+
+/*
+ If MP_LOGTAB is not defined, use the math library to compute the
+ logarithms on the fly. Otherwise, use the table.
+ Pick which works best for your system.
+ */
+
+#include <math.h>
+#define LOG_V_2(R) (log(2.0)/log(R))
+
+#endif /* if MP_LOGTAB */
+
+/* }}} */
+
+/* {{{ Digit arithmetic macros */
+
+/*
+ When adding and multiplying digits, the results can be larger than
+ can be contained in an mp_digit. Thus, an mp_word is used. These
+ macros mask off the upper and lower digits of the mp_word (the
+ mp_word may be more than 2 mp_digits wide, but we only concern
+ ourselves with the low-order 2 mp_digits)
+ */
+
+#define CARRYOUT(W) (mp_digit)((W)>>DIGIT_BIT)
+#define ACCUM(W) (mp_digit)(W)
+
+#define MP_MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MP_MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MP_HOWMANY(a,b) (((a) + (b) - 1)/(b))
+#define MP_ROUNDUP(a,b) (MP_HOWMANY(a,b) * (b))
+
+/* }}} */
+
+/* {{{ Comparison constants */
+
+#define MP_LT -1
+#define MP_EQ 0
+#define MP_GT 1
+
+/* }}} */
+
+/* {{{ private function declarations */
+
+/*
+ If MP_MACRO is false, these will be defined as actual functions;
+ otherwise, suitable macro definitions will be used. This works
+ around the fact that ANSI C89 doesn't support an 'inline' keyword
+ (although I hear C9x will ... about bloody time). At present, the
+ macro definitions are identical to the function bodies, but they'll
+ expand in place, instead of generating a function call.
+
+ I chose these particular functions to be made into macros because
+ some profiling showed they are called a lot on a typical workload,
+ and yet they are primarily housekeeping.
+ */
+#if MP_MACRO == 0
+ void s_mp_setz(mp_digit *dp, mp_size count); /* zero digits */
+ void s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count); /* copy */
+ void *s_mp_alloc(size_t nb, size_t ni, int flag); /* general allocator */
+ void s_mp_free(void *ptr, mp_size); /* general free function */
+extern unsigned long mp_allocs;
+extern unsigned long mp_frees;
+extern unsigned long mp_copies;
+#else
+
+ /* Even if these are defined as macros, we need to respect the settings
+ of the MP_MEMSET and MP_MEMCPY configuration options...
+ */
+ #if MP_MEMSET == 0
+ #define s_mp_setz(dp, count) \
+ {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=0;}
+ #else
+ #define s_mp_setz(dp, count) memset(dp, 0, (count) * sizeof(mp_digit))
+ #endif /* MP_MEMSET */
+
+ #if MP_MEMCPY == 0
+ #define s_mp_copy(sp, dp, count) \
+ {int ix;for(ix=0;ix<(count);ix++)(dp)[ix]=(sp)[ix];}
+ #else
+ #define s_mp_copy(sp, dp, count) memcpy(dp, sp, (count) * sizeof(mp_digit))
+ #endif /* MP_MEMCPY */
+
+ #define s_mp_alloc(nb, ni) calloc(nb, ni)
+ #define s_mp_free(ptr) {if(ptr) free(ptr);}
+#endif /* MP_MACRO */
+
+mp_err s_mp_grow(mp_int *mp, mp_size min); /* increase allocated size */
+mp_err s_mp_pad(mp_int *mp, mp_size min); /* left pad with zeroes */
+
+#if MP_MACRO == 0
+ void s_mp_clamp(mp_int *mp); /* clip leading zeroes */
+#else
+ #define s_mp_clamp(mp)\
+ { mp_size used = MP_USED(mp); \
+ while (used > 1 && DIGIT(mp, used - 1) == 0) --used; \
+ MP_USED(mp) = used; \
+ }
+#endif /* MP_MACRO */
+
+void s_mp_exch(mp_int *a, mp_int *b); /* swap a and b in place */
+
+mp_err s_mp_lshd(mp_int *mp, mp_size p); /* left-shift by p digits */
+void s_mp_rshd(mp_int *mp, mp_size p); /* right-shift by p digits */
+mp_err s_mp_mul_2d(mp_int *mp, mp_digit d); /* multiply by 2^d in place */
+void s_mp_div_2d(mp_int *mp, mp_digit d); /* divide by 2^d in place */
+void s_mp_mod_2d(mp_int *mp, mp_digit d); /* modulo 2^d in place */
+void s_mp_div_2(mp_int *mp); /* divide by 2 in place */
+mp_err s_mp_mul_2(mp_int *mp); /* multiply by 2 in place */
+mp_err s_mp_norm(mp_int *a, mp_int *b, mp_digit *pd);
+ /* normalize for division */
+mp_err s_mp_add_d(mp_int *mp, mp_digit d); /* unsigned digit addition */
+mp_err s_mp_sub_d(mp_int *mp, mp_digit d); /* unsigned digit subtract */
+mp_err s_mp_mul_d(mp_int *mp, mp_digit d); /* unsigned digit multiply */
+mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r);
+ /* unsigned digit divide */
+mp_err s_mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu);
+ /* Barrett reduction */
+mp_err s_mp_add(mp_int *a, const mp_int *b); /* magnitude addition */
+mp_err s_mp_add_3arg(const mp_int *a, const mp_int *b, mp_int *c);
+mp_err s_mp_sub(mp_int *a, const mp_int *b); /* magnitude subtract */
+mp_err s_mp_sub_3arg(const mp_int *a, const mp_int *b, mp_int *c);
+mp_err s_mp_add_offset(mp_int *a, mp_int *b, mp_size offset);
+ /* a += b * RADIX^offset */
+mp_err s_mp_mul(mp_int *a, const mp_int *b); /* magnitude multiply */
+#if MP_SQUARE
+mp_err s_mp_sqr(mp_int *a); /* magnitude square */
+#else
+#define s_mp_sqr(a) s_mp_mul(a, a)
+#endif
+mp_err s_mp_div(mp_int *rem, mp_int *div, mp_int *quot); /* magnitude div */
+mp_err s_mp_exptmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c);
+mp_err s_mp_2expt(mp_int *a, mp_digit k); /* a = 2^k */
+int s_mp_cmp(const mp_int *a, const mp_int *b); /* magnitude comparison */
+int s_mp_cmp_d(const mp_int *a, mp_digit d); /* magnitude digit compare */
+int s_mp_ispow2(const mp_int *v); /* is v a power of 2? */
+int s_mp_ispow2d(mp_digit d); /* is d a power of 2? */
+
+int s_mp_tovalue(char ch, int r); /* convert ch to value */
+char s_mp_todigit(mp_digit val, int r, int low); /* convert val to digit */
+int s_mp_outlen(int bits, int r); /* output length in bytes */
+mp_digit s_mp_invmod_radix(mp_digit P); /* returns (P ** -1) mod RADIX */
+mp_err s_mp_invmod_odd_m( const mp_int *a, const mp_int *m, mp_int *c);
+mp_err s_mp_invmod_2d( const mp_int *a, mp_size k, mp_int *c);
+mp_err s_mp_invmod_even_m(const mp_int *a, const mp_int *m, mp_int *c);
+
+#ifdef NSS_USE_COMBA
+
+#define IS_POWER_OF_2(a) ((a) && !((a) & ((a)-1)))
+
+void s_mp_mul_comba_4(const mp_int *A, const mp_int *B, mp_int *C);
+void s_mp_mul_comba_8(const mp_int *A, const mp_int *B, mp_int *C);
+void s_mp_mul_comba_16(const mp_int *A, const mp_int *B, mp_int *C);
+void s_mp_mul_comba_32(const mp_int *A, const mp_int *B, mp_int *C);
+
+void s_mp_sqr_comba_4(const mp_int *A, mp_int *B);
+void s_mp_sqr_comba_8(const mp_int *A, mp_int *B);
+void s_mp_sqr_comba_16(const mp_int *A, mp_int *B);
+void s_mp_sqr_comba_32(const mp_int *A, mp_int *B);
+
+#endif /* end NSS_USE_COMBA */
+
+/* ------ mpv functions, operate on arrays of digits, not on mp_int's ------ */
+#if defined (__OS2__) && defined (__IBMC__)
+#define MPI_ASM_DECL __cdecl
+#else
+#define MPI_ASM_DECL
+#endif
+
+#ifdef MPI_AMD64
+
+mp_digit MPI_ASM_DECL s_mpv_mul_set_vec64(mp_digit*, mp_digit *, mp_size, mp_digit);
+mp_digit MPI_ASM_DECL s_mpv_mul_add_vec64(mp_digit*, const mp_digit*, mp_size, mp_digit);
+
+/* c = a * b */
+#define s_mpv_mul_d(a, a_len, b, c) \
+ ((unsigned long*)c)[a_len] = s_mpv_mul_set_vec64(c, a, a_len, b)
+
+/* c += a * b */
+#define s_mpv_mul_d_add(a, a_len, b, c) \
+ ((unsigned long*)c)[a_len] = s_mpv_mul_add_vec64(c, a, a_len, b)
+
+#else
+
+void MPI_ASM_DECL s_mpv_mul_d(const mp_digit *a, mp_size a_len,
+ mp_digit b, mp_digit *c);
+void MPI_ASM_DECL s_mpv_mul_d_add(const mp_digit *a, mp_size a_len,
+ mp_digit b, mp_digit *c);
+
+#endif
+
+void MPI_ASM_DECL s_mpv_mul_d_add_prop(const mp_digit *a,
+ mp_size a_len, mp_digit b,
+ mp_digit *c);
+void MPI_ASM_DECL s_mpv_sqr_add_prop(const mp_digit *a,
+ mp_size a_len,
+ mp_digit *sqrs);
+
+mp_err MPI_ASM_DECL s_mpv_div_2dx1d(mp_digit Nhi, mp_digit Nlo,
+ mp_digit divisor, mp_digit *quot, mp_digit *rem);
+
+/* c += a * b * (MP_RADIX ** offset); */
+#define s_mp_mul_d_add_offset(a, b, c, off) \
+(s_mpv_mul_d_add_prop(MP_DIGITS(a), MP_USED(a), b, MP_DIGITS(c) + off), MP_OKAY)
+
+typedef struct {
+ mp_int N; /* modulus N */
+ mp_digit n0prime; /* n0' = - (n0 ** -1) mod MP_RADIX */
+ mp_size b; /* R == 2 ** b, also b = # significant bits in N */
+} mp_mont_modulus;
+
+mp_err s_mp_mul_mont(const mp_int *a, const mp_int *b, mp_int *c,
+ mp_mont_modulus *mmm);
+mp_err s_mp_redc(mp_int *T, mp_mont_modulus *mmm);
+
+/*
+ * s_mpi_getProcessorLineSize() returns the size in bytes of the cache line
+ * if a cache exists, or zero if there is no cache. If more than one
+ * cache line exists, it should return the smallest line size (which is
+ * usually the L1 cache).
+ *
+ * mp_modexp uses this information to make sure that private key information
+ * isn't being leaked through the cache.
+ *
+ * see mpcpucache.c for the implementation.
+ */
+unsigned long s_mpi_getProcessorLineSize();
+
+/* }}} */
+#endif /* _MPI_PRIV_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/mpi.c b/jdk.crypto.ec/share/native/libsunec/impl/mpi.c
new file mode 100644
index 0000000..e085c0c
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/mpi.c
@@ -0,0 +1,4871 @@
+/*
+ * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Netscape Communications Corporation
+ * Douglas Stebila <douglas@stebila.ca> of Sun Laboratories.
+ *
+ * Last Modified Date from the Original Code: Nov 2019
+ *********************************************************************** */
+
+/* Arbitrary precision integer arithmetic library */
+
+#include "mpi-priv.h"
+#if defined(OSF1)
+#include <c_asm.h>
+#endif
+
+#if MP_LOGTAB
+/*
+ A table of the logs of 2 for various bases (the 0 and 1 entries of
+ this table are meaningless and should not be referenced).
+
+ This table is used to compute output lengths for the mp_toradix()
+ function. Since a number n in radix r takes up about log_r(n)
+ digits, we estimate the output size by taking the least integer
+ greater than log_r(n), where:
+
+ log_r(n) = log_2(n) * log_r(2)
+
+ This table, therefore, is a table of log_r(2) for 2 <= r <= 36,
+ which are the output bases supported.
+ */
+#include "logtab.h"
+#endif
+
+/* {{{ Constant strings */
+
+/* Constant strings returned by mp_strerror() */
+static const char *mp_err_string[] = {
+ "unknown result code", /* say what? */
+ "boolean true", /* MP_OKAY, MP_YES */
+ "boolean false", /* MP_NO */
+ "out of memory", /* MP_MEM */
+ "argument out of range", /* MP_RANGE */
+ "invalid input parameter", /* MP_BADARG */
+ "result is undefined" /* MP_UNDEF */
+};
+
+/* Value to digit maps for radix conversion */
+
+/* s_dmap_1 - standard digits and letters */
+static const char *s_dmap_1 =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+
+/* }}} */
+
+unsigned long mp_allocs;
+unsigned long mp_frees;
+unsigned long mp_copies;
+
+/* {{{ Default precision manipulation */
+
+/* Default precision for newly created mp_int's */
+static mp_size s_mp_defprec = MP_DEFPREC;
+
+mp_size mp_get_prec(void)
+{
+ return s_mp_defprec;
+
+} /* end mp_get_prec() */
+
+void mp_set_prec(mp_size prec)
+{
+ if(prec == 0)
+ s_mp_defprec = MP_DEFPREC;
+ else
+ s_mp_defprec = prec;
+
+} /* end mp_set_prec() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ mp_init(mp, kmflag) */
+
+/*
+ mp_init(mp, kmflag)
+
+ Initialize a new zero-valued mp_int. Returns MP_OKAY if successful,
+ MP_MEM if memory could not be allocated for the structure.
+ */
+
+mp_err mp_init(mp_int *mp, int kmflag)
+{
+ return mp_init_size(mp, s_mp_defprec, kmflag);
+
+} /* end mp_init() */
+
+/* }}} */
+
+/* {{{ mp_init_size(mp, prec, kmflag) */
+
+/*
+ mp_init_size(mp, prec, kmflag)
+
+ Initialize a new zero-valued mp_int with at least the given
+ precision; returns MP_OKAY if successful, or MP_MEM if memory could
+ not be allocated for the structure.
+ */
+
+mp_err mp_init_size(mp_int *mp, mp_size prec, int kmflag)
+{
+ ARGCHK(mp != NULL && prec > 0, MP_BADARG);
+
+ prec = MP_ROUNDUP(prec, s_mp_defprec);
+ if((DIGITS(mp) = s_mp_alloc(prec, sizeof(mp_digit), kmflag)) == NULL)
+ return MP_MEM;
+
+ SIGN(mp) = ZPOS;
+ USED(mp) = 1;
+ ALLOC(mp) = prec;
+
+ return MP_OKAY;
+
+} /* end mp_init_size() */
+
+/* }}} */
+
+/* {{{ mp_init_copy(mp, from) */
+
+/*
+ mp_init_copy(mp, from)
+
+ Initialize mp as an exact copy of from. Returns MP_OKAY if
+ successful, MP_MEM if memory could not be allocated for the new
+ structure.
+ */
+
+mp_err mp_init_copy(mp_int *mp, const mp_int *from)
+{
+ ARGCHK(mp != NULL && from != NULL, MP_BADARG);
+
+ if(mp == from)
+ return MP_OKAY;
+
+ if((DIGITS(mp) = s_mp_alloc(ALLOC(from), sizeof(mp_digit), FLAG(from))) == NULL)
+ return MP_MEM;
+
+ s_mp_copy(DIGITS(from), DIGITS(mp), USED(from));
+ USED(mp) = USED(from);
+ ALLOC(mp) = ALLOC(from);
+ SIGN(mp) = SIGN(from);
+
+#ifndef _WIN32
+ FLAG(mp) = FLAG(from);
+#endif /* _WIN32 */
+
+ return MP_OKAY;
+
+} /* end mp_init_copy() */
+
+/* }}} */
+
+/* {{{ mp_copy(from, to) */
+
+/*
+ mp_copy(from, to)
+
+ Copies the mp_int 'from' to the mp_int 'to'. It is presumed that
+ 'to' has already been initialized (if not, use mp_init_copy()
+ instead). If 'from' and 'to' are identical, nothing happens.
+ */
+
+mp_err mp_copy(const mp_int *from, mp_int *to)
+{
+ ARGCHK(from != NULL && to != NULL, MP_BADARG);
+
+ if(from == to)
+ return MP_OKAY;
+
+ ++mp_copies;
+ { /* copy */
+ mp_digit *tmp;
+
+ /*
+ If the allocated buffer in 'to' already has enough space to hold
+ all the used digits of 'from', we'll re-use it to avoid hitting
+ the memory allocater more than necessary; otherwise, we'd have
+ to grow anyway, so we just allocate a hunk and make the copy as
+ usual
+ */
+ if(ALLOC(to) >= USED(from)) {
+ s_mp_setz(DIGITS(to) + USED(from), ALLOC(to) - USED(from));
+ s_mp_copy(DIGITS(from), DIGITS(to), USED(from));
+
+ } else {
+ if((tmp = s_mp_alloc(ALLOC(from), sizeof(mp_digit), FLAG(from))) == NULL)
+ return MP_MEM;
+
+ s_mp_copy(DIGITS(from), tmp, USED(from));
+
+ if(DIGITS(to) != NULL) {
+#if MP_CRYPTO
+ s_mp_setz(DIGITS(to), ALLOC(to));
+#endif
+ s_mp_free(DIGITS(to), ALLOC(to));
+ }
+
+ DIGITS(to) = tmp;
+ ALLOC(to) = ALLOC(from);
+ }
+
+ /* Copy the precision and sign from the original */
+ USED(to) = USED(from);
+ SIGN(to) = SIGN(from);
+ } /* end copy */
+
+ return MP_OKAY;
+
+} /* end mp_copy() */
+
+/* }}} */
+
+/* {{{ mp_exch(mp1, mp2) */
+
+/*
+ mp_exch(mp1, mp2)
+
+ Exchange mp1 and mp2 without allocating any intermediate memory
+ (well, unless you count the stack space needed for this call and the
+ locals it creates...). This cannot fail.
+ */
+
+void mp_exch(mp_int *mp1, mp_int *mp2)
+{
+#if MP_ARGCHK == 2
+ assert(mp1 != NULL && mp2 != NULL);
+#else
+ if(mp1 == NULL || mp2 == NULL)
+ return;
+#endif
+
+ s_mp_exch(mp1, mp2);
+
+} /* end mp_exch() */
+
+/* }}} */
+
+/* {{{ mp_clear(mp) */
+
+/*
+ mp_clear(mp)
+
+ Release the storage used by an mp_int, and void its fields so that
+ if someone calls mp_clear() again for the same int later, we won't
+ get tollchocked.
+ */
+
+void mp_clear(mp_int *mp)
+{
+ if(mp == NULL)
+ return;
+
+ if(DIGITS(mp) != NULL) {
+#if MP_CRYPTO
+ s_mp_setz(DIGITS(mp), ALLOC(mp));
+#endif
+ s_mp_free(DIGITS(mp), ALLOC(mp));
+ DIGITS(mp) = NULL;
+ }
+
+ USED(mp) = 0;
+ ALLOC(mp) = 0;
+
+} /* end mp_clear() */
+
+/* }}} */
+
+/* {{{ mp_zero(mp) */
+
+/*
+ mp_zero(mp)
+
+ Set mp to zero. Does not change the allocated size of the structure,
+ and therefore cannot fail (except on a bad argument, which we ignore)
+ */
+void mp_zero(mp_int *mp)
+{
+ if(mp == NULL)
+ return;
+
+ s_mp_setz(DIGITS(mp), ALLOC(mp));
+ USED(mp) = 1;
+ SIGN(mp) = ZPOS;
+
+} /* end mp_zero() */
+
+/* }}} */
+
+/* {{{ mp_set(mp, d) */
+
+void mp_set(mp_int *mp, mp_digit d)
+{
+ if(mp == NULL)
+ return;
+
+ mp_zero(mp);
+ DIGIT(mp, 0) = d;
+
+} /* end mp_set() */
+
+/* }}} */
+
+/* {{{ mp_set_int(mp, z) */
+
+mp_err mp_set_int(mp_int *mp, long z)
+{
+ int ix;
+ unsigned long v = labs(z);
+ mp_err res;
+
+ ARGCHK(mp != NULL, MP_BADARG);
+
+ mp_zero(mp);
+ if(z == 0)
+ return MP_OKAY; /* shortcut for zero */
+
+ if (sizeof v <= sizeof(mp_digit)) {
+ DIGIT(mp,0) = v;
+ } else {
+ for (ix = sizeof(long) - 1; ix >= 0; ix--) {
+ if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY)
+ return res;
+
+ res = s_mp_add_d(mp, (mp_digit)((v >> (ix * CHAR_BIT)) & UCHAR_MAX));
+ if (res != MP_OKAY)
+ return res;
+ }
+ }
+ if(z < 0)
+ SIGN(mp) = NEG;
+
+ return MP_OKAY;
+
+} /* end mp_set_int() */
+
+/* }}} */
+
+/* {{{ mp_set_ulong(mp, z) */
+
+mp_err mp_set_ulong(mp_int *mp, unsigned long z)
+{
+ int ix;
+ mp_err res;
+
+ ARGCHK(mp != NULL, MP_BADARG);
+
+ mp_zero(mp);
+ if(z == 0)
+ return MP_OKAY; /* shortcut for zero */
+
+ if (sizeof z <= sizeof(mp_digit)) {
+ DIGIT(mp,0) = z;
+ } else {
+ for (ix = sizeof(long) - 1; ix >= 0; ix--) {
+ if ((res = s_mp_mul_d(mp, (UCHAR_MAX + 1))) != MP_OKAY)
+ return res;
+
+ res = s_mp_add_d(mp, (mp_digit)((z >> (ix * CHAR_BIT)) & UCHAR_MAX));
+ if (res != MP_OKAY)
+ return res;
+ }
+ }
+ return MP_OKAY;
+} /* end mp_set_ulong() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Digit arithmetic */
+
+/* {{{ mp_add_d(a, d, b) */
+
+/*
+ mp_add_d(a, d, b)
+
+ Compute the sum b = a + d, for a single digit d. Respects the sign of
+ its primary addend (single digits are unsigned anyway).
+ */
+
+mp_err mp_add_d(const mp_int *a, mp_digit d, mp_int *b)
+{
+ mp_int tmp;
+ mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
+ return res;
+
+ if(SIGN(&tmp) == ZPOS) {
+ if((res = s_mp_add_d(&tmp, d)) != MP_OKAY)
+ goto CLEANUP;
+ } else if(s_mp_cmp_d(&tmp, d) >= 0) {
+ if((res = s_mp_sub_d(&tmp, d)) != MP_OKAY)
+ goto CLEANUP;
+ } else {
+ mp_neg(&tmp, &tmp);
+
+ DIGIT(&tmp, 0) = d - DIGIT(&tmp, 0);
+ }
+
+ if(s_mp_cmp_d(&tmp, 0) == 0)
+ SIGN(&tmp) = ZPOS;
+
+ s_mp_exch(&tmp, b);
+
+CLEANUP:
+ mp_clear(&tmp);
+ return res;
+
+} /* end mp_add_d() */
+
+/* }}} */
+
+/* {{{ mp_sub_d(a, d, b) */
+
+/*
+ mp_sub_d(a, d, b)
+
+ Compute the difference b = a - d, for a single digit d. Respects the
+ sign of its subtrahend (single digits are unsigned anyway).
+ */
+
+mp_err mp_sub_d(const mp_int *a, mp_digit d, mp_int *b)
+{
+ mp_int tmp;
+ mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
+ return res;
+
+ if(SIGN(&tmp) == NEG) {
+ if((res = s_mp_add_d(&tmp, d)) != MP_OKAY)
+ goto CLEANUP;
+ } else if(s_mp_cmp_d(&tmp, d) >= 0) {
+ if((res = s_mp_sub_d(&tmp, d)) != MP_OKAY)
+ goto CLEANUP;
+ } else {
+ mp_neg(&tmp, &tmp);
+
+ DIGIT(&tmp, 0) = d - DIGIT(&tmp, 0);
+ SIGN(&tmp) = NEG;
+ }
+
+ if(s_mp_cmp_d(&tmp, 0) == 0)
+ SIGN(&tmp) = ZPOS;
+
+ s_mp_exch(&tmp, b);
+
+CLEANUP:
+ mp_clear(&tmp);
+ return res;
+
+} /* end mp_sub_d() */
+
+/* }}} */
+
+/* {{{ mp_mul_d(a, d, b) */
+
+/*
+ mp_mul_d(a, d, b)
+
+ Compute the product b = a * d, for a single digit d. Respects the sign
+ of its multiplicand (single digits are unsigned anyway)
+ */
+
+mp_err mp_mul_d(const mp_int *a, mp_digit d, mp_int *b)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if(d == 0) {
+ mp_zero(b);
+ return MP_OKAY;
+ }
+
+ if((res = mp_copy(a, b)) != MP_OKAY)
+ return res;
+
+ res = s_mp_mul_d(b, d);
+
+ return res;
+
+} /* end mp_mul_d() */
+
+/* }}} */
+
+/* {{{ mp_mul_2(a, c) */
+
+mp_err mp_mul_2(const mp_int *a, mp_int *c)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+ if((res = mp_copy(a, c)) != MP_OKAY)
+ return res;
+
+ return s_mp_mul_2(c);
+
+} /* end mp_mul_2() */
+
+/* }}} */
+
+/* {{{ mp_div_d(a, d, q, r) */
+
+/*
+ mp_div_d(a, d, q, r)
+
+ Compute the quotient q = a / d and remainder r = a mod d, for a
+ single digit d. Respects the sign of its divisor (single digits are
+ unsigned anyway).
+ */
+
+mp_err mp_div_d(const mp_int *a, mp_digit d, mp_int *q, mp_digit *r)
+{
+ mp_err res;
+ mp_int qp;
+ mp_digit rem;
+ int pow;
+
+ ARGCHK(a != NULL, MP_BADARG);
+
+ if(d == 0)
+ return MP_RANGE;
+
+ /* Shortcut for powers of two ... */
+ if((pow = s_mp_ispow2d(d)) >= 0) {
+ mp_digit mask;
+
+ mask = ((mp_digit)1 << pow) - 1;
+ rem = DIGIT(a, 0) & mask;
+
+ if(q) {
+ mp_copy(a, q);
+ s_mp_div_2d(q, pow);
+ }
+
+ if(r)
+ *r = rem;
+
+ return MP_OKAY;
+ }
+
+ if((res = mp_init_copy(&qp, a)) != MP_OKAY)
+ return res;
+
+ res = s_mp_div_d(&qp, d, &rem);
+
+ if(s_mp_cmp_d(&qp, 0) == 0)
+ SIGN(q) = ZPOS;
+
+ if(r)
+ *r = rem;
+
+ if(q)
+ s_mp_exch(&qp, q);
+
+ mp_clear(&qp);
+ return res;
+
+} /* end mp_div_d() */
+
+/* }}} */
+
+/* {{{ mp_div_2(a, c) */
+
+/*
+ mp_div_2(a, c)
+
+ Compute c = a / 2, disregarding the remainder.
+ */
+
+mp_err mp_div_2(const mp_int *a, mp_int *c)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+ if((res = mp_copy(a, c)) != MP_OKAY)
+ return res;
+
+ s_mp_div_2(c);
+
+ return MP_OKAY;
+
+} /* end mp_div_2() */
+
+/* }}} */
+
+/* {{{ mp_expt_d(a, d, b) */
+
+mp_err mp_expt_d(const mp_int *a, mp_digit d, mp_int *c)
+{
+ mp_int s, x;
+ mp_err res;
+
+ ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+ if((res = mp_init(&s, FLAG(a))) != MP_OKAY)
+ return res;
+ if((res = mp_init_copy(&x, a)) != MP_OKAY)
+ goto X;
+
+ DIGIT(&s, 0) = 1;
+
+ while(d != 0) {
+ if(d & 1) {
+ if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ d /= 2;
+
+ if((res = s_mp_sqr(&x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ s.flag = (mp_sign)0;
+ s_mp_exch(&s, c);
+
+CLEANUP:
+ mp_clear(&x);
+X:
+ mp_clear(&s);
+
+ return res;
+
+} /* end mp_expt_d() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Full arithmetic */
+
+/* {{{ mp_abs(a, b) */
+
+/*
+ mp_abs(a, b)
+
+ Compute b = |a|. 'a' and 'b' may be identical.
+ */
+
+mp_err mp_abs(const mp_int *a, mp_int *b)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if((res = mp_copy(a, b)) != MP_OKAY)
+ return res;
+
+ SIGN(b) = ZPOS;
+
+ return MP_OKAY;
+
+} /* end mp_abs() */
+
+/* }}} */
+
+/* {{{ mp_neg(a, b) */
+
+/*
+ mp_neg(a, b)
+
+ Compute b = -a. 'a' and 'b' may be identical.
+ */
+
+mp_err mp_neg(const mp_int *a, mp_int *b)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if((res = mp_copy(a, b)) != MP_OKAY)
+ return res;
+
+ if(s_mp_cmp_d(b, 0) == MP_EQ)
+ SIGN(b) = ZPOS;
+ else
+ SIGN(b) = (SIGN(b) == NEG) ? ZPOS : NEG;
+
+ return MP_OKAY;
+
+} /* end mp_neg() */
+
+/* }}} */
+
+/* {{{ mp_add(a, b, c) */
+
+/*
+ mp_add(a, b, c)
+
+ Compute c = a + b. All parameters may be identical.
+ */
+
+mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if(SIGN(a) == SIGN(b)) { /* same sign: add values, keep sign */
+ MP_CHECKOK( s_mp_add_3arg(a, b, c) );
+ } else if(s_mp_cmp(a, b) >= 0) { /* different sign: |a| >= |b| */
+ MP_CHECKOK( s_mp_sub_3arg(a, b, c) );
+ } else { /* different sign: |a| < |b| */
+ MP_CHECKOK( s_mp_sub_3arg(b, a, c) );
+ }
+
+ if (s_mp_cmp_d(c, 0) == MP_EQ)
+ SIGN(c) = ZPOS;
+
+CLEANUP:
+ return res;
+
+} /* end mp_add() */
+
+/* }}} */
+
+/* {{{ mp_sub(a, b, c) */
+
+/*
+ mp_sub(a, b, c)
+
+ Compute c = a - b. All parameters may be identical.
+ */
+
+mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_err res;
+ int magDiff;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if (a == b) {
+ mp_zero(c);
+ return MP_OKAY;
+ }
+
+ if (MP_SIGN(a) != MP_SIGN(b)) {
+ MP_CHECKOK( s_mp_add_3arg(a, b, c) );
+ } else if (!(magDiff = s_mp_cmp(a, b))) {
+ mp_zero(c);
+ res = MP_OKAY;
+ } else if (magDiff > 0) {
+ MP_CHECKOK( s_mp_sub_3arg(a, b, c) );
+ } else {
+ MP_CHECKOK( s_mp_sub_3arg(b, a, c) );
+ MP_SIGN(c) = !MP_SIGN(a);
+ }
+
+ if (s_mp_cmp_d(c, 0) == MP_EQ)
+ MP_SIGN(c) = MP_ZPOS;
+
+CLEANUP:
+ return res;
+
+} /* end mp_sub() */
+
+/* }}} */
+
+/* {{{ mp_mul(a, b, c) */
+
+/*
+ mp_mul(a, b, c)
+
+ Compute c = a * b. All parameters may be identical.
+ */
+mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int * c)
+{
+ mp_digit *pb;
+ mp_int tmp;
+ mp_err res;
+ mp_size ib;
+ mp_size useda, usedb;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if (a == c) {
+ if ((res = mp_init_copy(&tmp, a)) != MP_OKAY)
+ return res;
+ if (a == b)
+ b = &tmp;
+ a = &tmp;
+ } else if (b == c) {
+ if ((res = mp_init_copy(&tmp, b)) != MP_OKAY)
+ return res;
+ b = &tmp;
+ } else {
+ MP_DIGITS(&tmp) = 0;
+ }
+
+ if (MP_USED(a) < MP_USED(b)) {
+ const mp_int *xch = b; /* switch a and b, to do fewer outer loops */
+ b = a;
+ a = xch;
+ }
+
+ MP_USED(c) = 1; MP_DIGIT(c, 0) = 0;
+ if((res = s_mp_pad(c, USED(a) + USED(b))) != MP_OKAY)
+ goto CLEANUP;
+
+#ifdef NSS_USE_COMBA
+ if ((MP_USED(a) == MP_USED(b)) && IS_POWER_OF_2(MP_USED(b))) {
+ if (MP_USED(a) == 4) {
+ s_mp_mul_comba_4(a, b, c);
+ goto CLEANUP;
+ }
+ if (MP_USED(a) == 8) {
+ s_mp_mul_comba_8(a, b, c);
+ goto CLEANUP;
+ }
+ if (MP_USED(a) == 16) {
+ s_mp_mul_comba_16(a, b, c);
+ goto CLEANUP;
+ }
+ if (MP_USED(a) == 32) {
+ s_mp_mul_comba_32(a, b, c);
+ goto CLEANUP;
+ }
+ }
+#endif
+
+ pb = MP_DIGITS(b);
+ s_mpv_mul_d(MP_DIGITS(a), MP_USED(a), *pb++, MP_DIGITS(c));
+
+ /* Outer loop: Digits of b */
+ useda = MP_USED(a);
+ usedb = MP_USED(b);
+ for (ib = 1; ib < usedb; ib++) {
+ mp_digit b_i = *pb++;
+
+ /* Inner product: Digits of a */
+ if (b_i)
+ s_mpv_mul_d_add(MP_DIGITS(a), useda, b_i, MP_DIGITS(c) + ib);
+ else
+ MP_DIGIT(c, ib + useda) = b_i;
+ }
+
+ s_mp_clamp(c);
+
+ if(SIGN(a) == SIGN(b) || s_mp_cmp_d(c, 0) == MP_EQ)
+ SIGN(c) = ZPOS;
+ else
+ SIGN(c) = NEG;
+
+CLEANUP:
+ mp_clear(&tmp);
+ return res;
+} /* end mp_mul() */
+
+/* }}} */
+
+/* {{{ mp_sqr(a, sqr) */
+
+#if MP_SQUARE
+/*
+ Computes the square of a. This can be done more
+ efficiently than a general multiplication, because many of the
+ computation steps are redundant when squaring. The inner product
+ step is a bit more complicated, but we save a fair number of
+ iterations of the multiplication loop.
+ */
+
+/* sqr = a^2; Caller provides both a and tmp; */
+mp_err mp_sqr(const mp_int *a, mp_int *sqr)
+{
+ mp_digit *pa;
+ mp_digit d;
+ mp_err res;
+ mp_size ix;
+ mp_int tmp;
+ int count;
+
+ ARGCHK(a != NULL && sqr != NULL, MP_BADARG);
+
+ if (a == sqr) {
+ if((res = mp_init_copy(&tmp, a)) != MP_OKAY)
+ return res;
+ a = &tmp;
+ } else {
+ DIGITS(&tmp) = 0;
+ res = MP_OKAY;
+ }
+
+ ix = 2 * MP_USED(a);
+ if (ix > MP_ALLOC(sqr)) {
+ MP_USED(sqr) = 1;
+ MP_CHECKOK( s_mp_grow(sqr, ix) );
+ }
+ MP_USED(sqr) = ix;
+ MP_DIGIT(sqr, 0) = 0;
+
+#ifdef NSS_USE_COMBA
+ if (IS_POWER_OF_2(MP_USED(a))) {
+ if (MP_USED(a) == 4) {
+ s_mp_sqr_comba_4(a, sqr);
+ goto CLEANUP;
+ }
+ if (MP_USED(a) == 8) {
+ s_mp_sqr_comba_8(a, sqr);
+ goto CLEANUP;
+ }
+ if (MP_USED(a) == 16) {
+ s_mp_sqr_comba_16(a, sqr);
+ goto CLEANUP;
+ }
+ if (MP_USED(a) == 32) {
+ s_mp_sqr_comba_32(a, sqr);
+ goto CLEANUP;
+ }
+ }
+#endif
+
+ pa = MP_DIGITS(a);
+ count = MP_USED(a) - 1;
+ if (count > 0) {
+ d = *pa++;
+ s_mpv_mul_d(pa, count, d, MP_DIGITS(sqr) + 1);
+ for (ix = 3; --count > 0; ix += 2) {
+ d = *pa++;
+ s_mpv_mul_d_add(pa, count, d, MP_DIGITS(sqr) + ix);
+ } /* for(ix ...) */
+ MP_DIGIT(sqr, MP_USED(sqr)-1) = 0; /* above loop stopped short of this. */
+
+ /* now sqr *= 2 */
+ s_mp_mul_2(sqr);
+ } else {
+ MP_DIGIT(sqr, 1) = 0;
+ }
+
+ /* now add the squares of the digits of a to sqr. */
+ s_mpv_sqr_add_prop(MP_DIGITS(a), MP_USED(a), MP_DIGITS(sqr));
+
+ SIGN(sqr) = ZPOS;
+ s_mp_clamp(sqr);
+
+CLEANUP:
+ mp_clear(&tmp);
+ return res;
+
+} /* end mp_sqr() */
+#endif
+
+/* }}} */
+
+/* {{{ mp_div(a, b, q, r) */
+
+/*
+ mp_div(a, b, q, r)
+
+ Compute q = a / b and r = a mod b. Input parameters may be re-used
+ as output parameters. If q or r is NULL, that portion of the
+ computation will be discarded (although it will still be computed)
+ */
+mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *q, mp_int *r)
+{
+ mp_err res;
+ mp_int *pQ, *pR;
+ mp_int qtmp, rtmp, btmp;
+ int cmp;
+ mp_sign signA;
+ mp_sign signB;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ signA = MP_SIGN(a);
+ signB = MP_SIGN(b);
+
+ if(mp_cmp_z(b) == MP_EQ)
+ return MP_RANGE;
+
+ DIGITS(&qtmp) = 0;
+ DIGITS(&rtmp) = 0;
+ DIGITS(&btmp) = 0;
+
+ /* Set up some temporaries... */
+ if (!r || r == a || r == b) {
+ MP_CHECKOK( mp_init_copy(&rtmp, a) );
+ pR = &rtmp;
+ } else {
+ MP_CHECKOK( mp_copy(a, r) );
+ pR = r;
+ }
+
+ if (!q || q == a || q == b) {
+ MP_CHECKOK( mp_init_size(&qtmp, MP_USED(a), FLAG(a)) );
+ pQ = &qtmp;
+ } else {
+ MP_CHECKOK( s_mp_pad(q, MP_USED(a)) );
+ pQ = q;
+ mp_zero(pQ);
+ }
+
+ /*
+ If |a| <= |b|, we can compute the solution without division;
+ otherwise, we actually do the work required.
+ */
+ if ((cmp = s_mp_cmp(a, b)) <= 0) {
+ if (cmp) {
+ /* r was set to a above. */
+ mp_zero(pQ);
+ } else {
+ mp_set(pQ, 1);
+ mp_zero(pR);
+ }
+ } else {
+ MP_CHECKOK( mp_init_copy(&btmp, b) );
+ MP_CHECKOK( s_mp_div(pR, &btmp, pQ) );
+ }
+
+ /* Compute the signs for the output */
+ MP_SIGN(pR) = signA; /* Sr = Sa */
+ /* Sq = ZPOS if Sa == Sb */ /* Sq = NEG if Sa != Sb */
+ MP_SIGN(pQ) = (signA == signB) ? ZPOS : NEG;
+
+ if(s_mp_cmp_d(pQ, 0) == MP_EQ)
+ SIGN(pQ) = ZPOS;
+ if(s_mp_cmp_d(pR, 0) == MP_EQ)
+ SIGN(pR) = ZPOS;
+
+ /* Copy output, if it is needed */
+ if(q && q != pQ)
+ s_mp_exch(pQ, q);
+
+ if(r && r != pR)
+ s_mp_exch(pR, r);
+
+CLEANUP:
+ mp_clear(&btmp);
+ mp_clear(&rtmp);
+ mp_clear(&qtmp);
+
+ return res;
+
+} /* end mp_div() */
+
+/* }}} */
+
+/* {{{ mp_div_2d(a, d, q, r) */
+
+mp_err mp_div_2d(const mp_int *a, mp_digit d, mp_int *q, mp_int *r)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL, MP_BADARG);
+
+ if(q) {
+ if((res = mp_copy(a, q)) != MP_OKAY)
+ return res;
+ }
+ if(r) {
+ if((res = mp_copy(a, r)) != MP_OKAY)
+ return res;
+ }
+ if(q) {
+ s_mp_div_2d(q, d);
+ }
+ if(r) {
+ s_mp_mod_2d(r, d);
+ }
+
+ return MP_OKAY;
+
+} /* end mp_div_2d() */
+
+/* }}} */
+
+/* {{{ mp_expt(a, b, c) */
+
+/*
+ mp_expt(a, b, c)
+
+ Compute c = a ** b, that is, raise a to the b power. Uses a
+ standard iterative square-and-multiply technique.
+ */
+
+mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c)
+{
+ mp_int s, x;
+ mp_err res;
+ mp_digit d;
+ unsigned int dig, bit;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if(mp_cmp_z(b) < 0)
+ return MP_RANGE;
+
+ if((res = mp_init(&s, FLAG(a))) != MP_OKAY)
+ return res;
+
+ mp_set(&s, 1);
+
+ if((res = mp_init_copy(&x, a)) != MP_OKAY)
+ goto X;
+
+ /* Loop over low-order digits in ascending order */
+ for(dig = 0; dig < (USED(b) - 1); dig++) {
+ d = DIGIT(b, dig);
+
+ /* Loop over bits of each non-maximal digit */
+ for(bit = 0; bit < DIGIT_BIT; bit++) {
+ if(d & 1) {
+ if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ d >>= 1;
+
+ if((res = s_mp_sqr(&x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+ }
+
+ /* Consider now the last digit... */
+ d = DIGIT(b, dig);
+
+ while(d) {
+ if(d & 1) {
+ if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ d >>= 1;
+
+ if((res = s_mp_sqr(&x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ if(mp_iseven(b))
+ SIGN(&s) = SIGN(a);
+
+ res = mp_copy(&s, c);
+
+CLEANUP:
+ mp_clear(&x);
+X:
+ mp_clear(&s);
+
+ return res;
+
+} /* end mp_expt() */
+
+/* }}} */
+
+/* {{{ mp_2expt(a, k) */
+
+/* Compute a = 2^k */
+
+mp_err mp_2expt(mp_int *a, mp_digit k)
+{
+ ARGCHK(a != NULL, MP_BADARG);
+
+ return s_mp_2expt(a, k);
+
+} /* end mp_2expt() */
+
+/* }}} */
+
+/* {{{ mp_mod(a, m, c) */
+
+/*
+ mp_mod(a, m, c)
+
+ Compute c = a (mod m). Result will always be 0 <= c < m.
+ */
+
+mp_err mp_mod(const mp_int *a, const mp_int *m, mp_int *c)
+{
+ mp_err res;
+ int mag;
+
+ ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
+
+ if(SIGN(m) == NEG)
+ return MP_RANGE;
+
+ /*
+ If |a| > m, we need to divide to get the remainder and take the
+ absolute value.
+
+ If |a| < m, we don't need to do any division, just copy and adjust
+ the sign (if a is negative).
+
+ If |a| == m, we can simply set the result to zero.
+
+ This order is intended to minimize the average path length of the
+ comparison chain on common workloads -- the most frequent cases are
+ that |a| != m, so we do those first.
+ */
+ if((mag = s_mp_cmp(a, m)) > 0) {
+ if((res = mp_div(a, m, NULL, c)) != MP_OKAY)
+ return res;
+
+ if(SIGN(c) == NEG) {
+ if((res = mp_add(c, m, c)) != MP_OKAY)
+ return res;
+ }
+
+ } else if(mag < 0) {
+ if((res = mp_copy(a, c)) != MP_OKAY)
+ return res;
+
+ if(mp_cmp_z(a) < 0) {
+ if((res = mp_add(c, m, c)) != MP_OKAY)
+ return res;
+
+ }
+
+ } else {
+ mp_zero(c);
+
+ }
+
+ return MP_OKAY;
+
+} /* end mp_mod() */
+
+/* }}} */
+
+/* {{{ mp_mod_d(a, d, c) */
+
+/*
+ mp_mod_d(a, d, c)
+
+ Compute c = a (mod d). Result will always be 0 <= c < d
+ */
+mp_err mp_mod_d(const mp_int *a, mp_digit d, mp_digit *c)
+{
+ mp_err res;
+ mp_digit rem;
+
+ ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+ if(s_mp_cmp_d(a, d) > 0) {
+ if((res = mp_div_d(a, d, NULL, &rem)) != MP_OKAY)
+ return res;
+
+ } else {
+ if(SIGN(a) == NEG)
+ rem = d - DIGIT(a, 0);
+ else
+ rem = DIGIT(a, 0);
+ }
+
+ if(c)
+ *c = rem;
+
+ return MP_OKAY;
+
+} /* end mp_mod_d() */
+
+/* }}} */
+
+/* {{{ mp_sqrt(a, b) */
+
+/*
+ mp_sqrt(a, b)
+
+ Compute the integer square root of a, and store the result in b.
+ Uses an integer-arithmetic version of Newton's iterative linear
+ approximation technique to determine this value; the result has the
+ following two properties:
+
+ b^2 <= a
+ (b+1)^2 >= a
+
+ It is a range error to pass a negative value.
+ */
+mp_err mp_sqrt(const mp_int *a, mp_int *b)
+{
+ mp_int x, t;
+ mp_err res;
+ mp_size used;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ /* Cannot take square root of a negative value */
+ if(SIGN(a) == NEG)
+ return MP_RANGE;
+
+ /* Special cases for zero and one, trivial */
+ if(mp_cmp_d(a, 1) <= 0)
+ return mp_copy(a, b);
+
+ /* Initialize the temporaries we'll use below */
+ if((res = mp_init_size(&t, USED(a), FLAG(a))) != MP_OKAY)
+ return res;
+
+ /* Compute an initial guess for the iteration as a itself */
+ if((res = mp_init_copy(&x, a)) != MP_OKAY)
+ goto X;
+
+ used = MP_USED(&x);
+ if (used > 1) {
+ s_mp_rshd(&x, used / 2);
+ }
+
+ for(;;) {
+ /* t = (x * x) - a */
+ mp_copy(&x, &t); /* can't fail, t is big enough for original x */
+ if((res = mp_sqr(&t, &t)) != MP_OKAY ||
+ (res = mp_sub(&t, a, &t)) != MP_OKAY)
+ goto CLEANUP;
+
+ /* t = t / 2x */
+ s_mp_mul_2(&x);
+ if((res = mp_div(&t, &x, &t, NULL)) != MP_OKAY)
+ goto CLEANUP;
+ s_mp_div_2(&x);
+
+ /* Terminate the loop, if the quotient is zero */
+ if(mp_cmp_z(&t) == MP_EQ)
+ break;
+
+ /* x = x - t */
+ if((res = mp_sub(&x, &t, &x)) != MP_OKAY)
+ goto CLEANUP;
+
+ }
+
+ /* Copy result to output parameter */
+ mp_sub_d(&x, 1, &x);
+ s_mp_exch(&x, b);
+
+ CLEANUP:
+ mp_clear(&x);
+ X:
+ mp_clear(&t);
+
+ return res;
+
+} /* end mp_sqrt() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Modular arithmetic */
+
+#if MP_MODARITH
+/* {{{ mp_addmod(a, b, m, c) */
+
+/*
+ mp_addmod(a, b, m, c)
+
+ Compute c = (a + b) mod m
+ */
+
+mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
+
+ if((res = mp_add(a, b, c)) != MP_OKAY)
+ return res;
+ if((res = mp_mod(c, m, c)) != MP_OKAY)
+ return res;
+
+ return MP_OKAY;
+
+}
+
+/* }}} */
+
+/* {{{ mp_submod(a, b, m, c) */
+
+/*
+ mp_submod(a, b, m, c)
+
+ Compute c = (a - b) mod m
+ */
+
+mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
+
+ if((res = mp_sub(a, b, c)) != MP_OKAY)
+ return res;
+ if((res = mp_mod(c, m, c)) != MP_OKAY)
+ return res;
+
+ return MP_OKAY;
+
+}
+
+/* }}} */
+
+/* {{{ mp_mulmod(a, b, m, c) */
+
+/*
+ mp_mulmod(a, b, m, c)
+
+ Compute c = (a * b) mod m
+ */
+
+mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL && b != NULL && m != NULL && c != NULL, MP_BADARG);
+
+ if((res = mp_mul(a, b, c)) != MP_OKAY)
+ return res;
+ if((res = mp_mod(c, m, c)) != MP_OKAY)
+ return res;
+
+ return MP_OKAY;
+
+}
+
+/* }}} */
+
+/* {{{ mp_sqrmod(a, m, c) */
+
+#if MP_SQUARE
+mp_err mp_sqrmod(const mp_int *a, const mp_int *m, mp_int *c)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL && m != NULL && c != NULL, MP_BADARG);
+
+ if((res = mp_sqr(a, c)) != MP_OKAY)
+ return res;
+ if((res = mp_mod(c, m, c)) != MP_OKAY)
+ return res;
+
+ return MP_OKAY;
+
+} /* end mp_sqrmod() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_exptmod(a, b, m, c) */
+
+/*
+ s_mp_exptmod(a, b, m, c)
+
+ Compute c = (a ** b) mod m. Uses a standard square-and-multiply
+ method with modular reductions at each step. (This is basically the
+ same code as mp_expt(), except for the addition of the reductions)
+
+ The modular reductions are done using Barrett's algorithm (see
+ s_mp_reduce() below for details)
+ */
+
+mp_err s_mp_exptmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c)
+{
+ mp_int s, x, mu;
+ mp_err res;
+ mp_digit d;
+ unsigned int dig, bit;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if(mp_cmp_z(b) < 0 || mp_cmp_z(m) <= 0)
+ return MP_RANGE;
+
+ if((res = mp_init(&s, FLAG(a))) != MP_OKAY)
+ return res;
+ if((res = mp_init_copy(&x, a)) != MP_OKAY ||
+ (res = mp_mod(&x, m, &x)) != MP_OKAY)
+ goto X;
+ if((res = mp_init(&mu, FLAG(a))) != MP_OKAY)
+ goto MU;
+
+ mp_set(&s, 1);
+
+ /* mu = b^2k / m */
+ s_mp_add_d(&mu, 1);
+ s_mp_lshd(&mu, 2 * USED(m));
+ if((res = mp_div(&mu, m, &mu, NULL)) != MP_OKAY)
+ goto CLEANUP;
+
+ /* Loop over digits of b in ascending order, except highest order */
+ for(dig = 0; dig < (USED(b) - 1); dig++) {
+ d = DIGIT(b, dig);
+
+ /* Loop over the bits of the lower-order digits */
+ for(bit = 0; bit < DIGIT_BIT; bit++) {
+ if(d & 1) {
+ if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+ goto CLEANUP;
+ if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ d >>= 1;
+
+ if((res = s_mp_sqr(&x)) != MP_OKAY)
+ goto CLEANUP;
+ if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
+ goto CLEANUP;
+ }
+ }
+
+ /* Now do the last digit... */
+ d = DIGIT(b, dig);
+
+ while(d) {
+ if(d & 1) {
+ if((res = s_mp_mul(&s, &x)) != MP_OKAY)
+ goto CLEANUP;
+ if((res = s_mp_reduce(&s, m, &mu)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ d >>= 1;
+
+ if((res = s_mp_sqr(&x)) != MP_OKAY)
+ goto CLEANUP;
+ if((res = s_mp_reduce(&x, m, &mu)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ s_mp_exch(&s, c);
+
+ CLEANUP:
+ mp_clear(&mu);
+ MU:
+ mp_clear(&x);
+ X:
+ mp_clear(&s);
+
+ return res;
+
+} /* end s_mp_exptmod() */
+
+/* }}} */
+
+/* {{{ mp_exptmod_d(a, d, m, c) */
+
+mp_err mp_exptmod_d(const mp_int *a, mp_digit d, const mp_int *m, mp_int *c)
+{
+ mp_int s, x;
+ mp_err res;
+
+ ARGCHK(a != NULL && c != NULL, MP_BADARG);
+
+ if((res = mp_init(&s, FLAG(a))) != MP_OKAY)
+ return res;
+ if((res = mp_init_copy(&x, a)) != MP_OKAY)
+ goto X;
+
+ mp_set(&s, 1);
+
+ while(d != 0) {
+ if(d & 1) {
+ if((res = s_mp_mul(&s, &x)) != MP_OKAY ||
+ (res = mp_mod(&s, m, &s)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ d /= 2;
+
+ if((res = s_mp_sqr(&x)) != MP_OKAY ||
+ (res = mp_mod(&x, m, &x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ s.flag = (mp_sign)0;
+ s_mp_exch(&s, c);
+
+CLEANUP:
+ mp_clear(&x);
+X:
+ mp_clear(&s);
+
+ return res;
+
+} /* end mp_exptmod_d() */
+
+/* }}} */
+#endif /* if MP_MODARITH */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Comparison functions */
+
+/* {{{ mp_cmp_z(a) */
+
+/*
+ mp_cmp_z(a)
+
+ Compare a <=> 0. Returns <0 if a<0, 0 if a=0, >0 if a>0.
+ */
+
+int mp_cmp_z(const mp_int *a)
+{
+ if(SIGN(a) == NEG)
+ return MP_LT;
+ else if(USED(a) == 1 && DIGIT(a, 0) == 0)
+ return MP_EQ;
+ else
+ return MP_GT;
+
+} /* end mp_cmp_z() */
+
+/* }}} */
+
+/* {{{ mp_cmp_d(a, d) */
+
+/*
+ mp_cmp_d(a, d)
+
+ Compare a <=> d. Returns <0 if a<d, 0 if a=d, >0 if a>d
+ */
+
+int mp_cmp_d(const mp_int *a, mp_digit d)
+{
+ ARGCHK(a != NULL, MP_EQ);
+
+ if(SIGN(a) == NEG)
+ return MP_LT;
+
+ return s_mp_cmp_d(a, d);
+
+} /* end mp_cmp_d() */
+
+/* }}} */
+
+/* {{{ mp_cmp(a, b) */
+
+int mp_cmp(const mp_int *a, const mp_int *b)
+{
+ ARGCHK(a != NULL && b != NULL, MP_EQ);
+
+ if(SIGN(a) == SIGN(b)) {
+ int mag;
+
+ if((mag = s_mp_cmp(a, b)) == MP_EQ)
+ return MP_EQ;
+
+ if(SIGN(a) == ZPOS)
+ return mag;
+ else
+ return -mag;
+
+ } else if(SIGN(a) == ZPOS) {
+ return MP_GT;
+ } else {
+ return MP_LT;
+ }
+
+} /* end mp_cmp() */
+
+/* }}} */
+
+/* {{{ mp_cmp_mag(a, b) */
+
+/*
+ mp_cmp_mag(a, b)
+
+ Compares |a| <=> |b|, and returns an appropriate comparison result
+ */
+
+int mp_cmp_mag(mp_int *a, mp_int *b)
+{
+ ARGCHK(a != NULL && b != NULL, MP_EQ);
+
+ return s_mp_cmp(a, b);
+
+} /* end mp_cmp_mag() */
+
+/* }}} */
+
+/* {{{ mp_cmp_int(a, z, kmflag) */
+
+/*
+ This just converts z to an mp_int, and uses the existing comparison
+ routines. This is sort of inefficient, but it's not clear to me how
+ frequently this wil get used anyway. For small positive constants,
+ you can always use mp_cmp_d(), and for zero, there is mp_cmp_z().
+ */
+int mp_cmp_int(const mp_int *a, long z, int kmflag)
+{
+ mp_int tmp;
+ int out;
+
+ ARGCHK(a != NULL, MP_EQ);
+
+ mp_init(&tmp, kmflag); mp_set_int(&tmp, z);
+ out = mp_cmp(a, &tmp);
+ mp_clear(&tmp);
+
+ return out;
+
+} /* end mp_cmp_int() */
+
+/* }}} */
+
+/* {{{ mp_isodd(a) */
+
+/*
+ mp_isodd(a)
+
+ Returns a true (non-zero) value if a is odd, false (zero) otherwise.
+ */
+int mp_isodd(const mp_int *a)
+{
+ ARGCHK(a != NULL, 0);
+
+ return (int)(DIGIT(a, 0) & 1);
+
+} /* end mp_isodd() */
+
+/* }}} */
+
+/* {{{ mp_iseven(a) */
+
+int mp_iseven(const mp_int *a)
+{
+ return !mp_isodd(a);
+
+} /* end mp_iseven() */
+
+/* }}} */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ Number theoretic functions */
+
+#if MP_NUMTH
+/* {{{ mp_gcd(a, b, c) */
+
+/*
+ Like the old mp_gcd() function, except computes the GCD using the
+ binary algorithm due to Josef Stein in 1961 (via Knuth).
+ */
+mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c)
+{
+ mp_err res;
+ mp_int u, v, t;
+ mp_size k = 0;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if(mp_cmp_z(a) == MP_EQ && mp_cmp_z(b) == MP_EQ)
+ return MP_RANGE;
+ if(mp_cmp_z(a) == MP_EQ) {
+ return mp_copy(b, c);
+ } else if(mp_cmp_z(b) == MP_EQ) {
+ return mp_copy(a, c);
+ }
+
+ if((res = mp_init(&t, FLAG(a))) != MP_OKAY)
+ return res;
+ if((res = mp_init_copy(&u, a)) != MP_OKAY)
+ goto U;
+ if((res = mp_init_copy(&v, b)) != MP_OKAY)
+ goto V;
+
+ SIGN(&u) = ZPOS;
+ SIGN(&v) = ZPOS;
+
+ /* Divide out common factors of 2 until at least 1 of a, b is even */
+ while(mp_iseven(&u) && mp_iseven(&v)) {
+ s_mp_div_2(&u);
+ s_mp_div_2(&v);
+ ++k;
+ }
+
+ /* Initialize t */
+ if(mp_isodd(&u)) {
+ if((res = mp_copy(&v, &t)) != MP_OKAY)
+ goto CLEANUP;
+
+ /* t = -v */
+ if(SIGN(&v) == ZPOS)
+ SIGN(&t) = NEG;
+ else
+ SIGN(&t) = ZPOS;
+
+ } else {
+ if((res = mp_copy(&u, &t)) != MP_OKAY)
+ goto CLEANUP;
+
+ }
+
+ for(;;) {
+ while(mp_iseven(&t)) {
+ s_mp_div_2(&t);
+ }
+
+ if(mp_cmp_z(&t) == MP_GT) {
+ if((res = mp_copy(&t, &u)) != MP_OKAY)
+ goto CLEANUP;
+
+ } else {
+ if((res = mp_copy(&t, &v)) != MP_OKAY)
+ goto CLEANUP;
+
+ /* v = -t */
+ if(SIGN(&t) == ZPOS)
+ SIGN(&v) = NEG;
+ else
+ SIGN(&v) = ZPOS;
+ }
+
+ if((res = mp_sub(&u, &v, &t)) != MP_OKAY)
+ goto CLEANUP;
+
+ if(s_mp_cmp_d(&t, 0) == MP_EQ)
+ break;
+ }
+
+ s_mp_2expt(&v, k); /* v = 2^k */
+ res = mp_mul(&u, &v, c); /* c = u * v */
+
+ CLEANUP:
+ mp_clear(&v);
+ V:
+ mp_clear(&u);
+ U:
+ mp_clear(&t);
+
+ return res;
+
+} /* end mp_gcd() */
+
+/* }}} */
+
+/* {{{ mp_lcm(a, b, c) */
+
+/* We compute the least common multiple using the rule:
+
+ ab = [a, b](a, b)
+
+ ... by computing the product, and dividing out the gcd.
+ */
+
+mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c)
+{
+ mp_int gcd, prod;
+ mp_err res;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ /* Set up temporaries */
+ if((res = mp_init(&gcd, FLAG(a))) != MP_OKAY)
+ return res;
+ if((res = mp_init(&prod, FLAG(a))) != MP_OKAY)
+ goto GCD;
+
+ if((res = mp_mul(a, b, &prod)) != MP_OKAY)
+ goto CLEANUP;
+ if((res = mp_gcd(a, b, &gcd)) != MP_OKAY)
+ goto CLEANUP;
+
+ res = mp_div(&prod, &gcd, c, NULL);
+
+ CLEANUP:
+ mp_clear(&prod);
+ GCD:
+ mp_clear(&gcd);
+
+ return res;
+
+} /* end mp_lcm() */
+
+/* }}} */
+
+/* {{{ mp_xgcd(a, b, g, x, y) */
+
+/*
+ mp_xgcd(a, b, g, x, y)
+
+ Compute g = (a, b) and values x and y satisfying Bezout's identity
+ (that is, ax + by = g). This uses the binary extended GCD algorithm
+ based on the Stein algorithm used for mp_gcd()
+ See algorithm 14.61 in Handbook of Applied Cryptogrpahy.
+ */
+
+mp_err mp_xgcd(const mp_int *a, const mp_int *b, mp_int *g, mp_int *x, mp_int *y)
+{
+ mp_int gx, xc, yc, u, v, A, B, C, D;
+ mp_int *clean[9];
+ mp_err res;
+ int last = -1;
+
+ if(mp_cmp_z(b) == 0)
+ return MP_RANGE;
+
+ /* Initialize all these variables we need */
+ MP_CHECKOK( mp_init(&u, FLAG(a)) );
+ clean[++last] = &u;
+ MP_CHECKOK( mp_init(&v, FLAG(a)) );
+ clean[++last] = &v;
+ MP_CHECKOK( mp_init(&gx, FLAG(a)) );
+ clean[++last] = &gx;
+ MP_CHECKOK( mp_init(&A, FLAG(a)) );
+ clean[++last] = &A;
+ MP_CHECKOK( mp_init(&B, FLAG(a)) );
+ clean[++last] = &B;
+ MP_CHECKOK( mp_init(&C, FLAG(a)) );
+ clean[++last] = &C;
+ MP_CHECKOK( mp_init(&D, FLAG(a)) );
+ clean[++last] = &D;
+ MP_CHECKOK( mp_init_copy(&xc, a) );
+ clean[++last] = &xc;
+ mp_abs(&xc, &xc);
+ MP_CHECKOK( mp_init_copy(&yc, b) );
+ clean[++last] = &yc;
+ mp_abs(&yc, &yc);
+
+ mp_set(&gx, 1);
+
+ /* Divide by two until at least one of them is odd */
+ while(mp_iseven(&xc) && mp_iseven(&yc)) {
+ mp_size nx = mp_trailing_zeros(&xc);
+ mp_size ny = mp_trailing_zeros(&yc);
+ mp_size n = MP_MIN(nx, ny);
+ s_mp_div_2d(&xc,n);
+ s_mp_div_2d(&yc,n);
+ MP_CHECKOK( s_mp_mul_2d(&gx,n) );
+ }
+
+ mp_copy(&xc, &u);
+ mp_copy(&yc, &v);
+ mp_set(&A, 1); mp_set(&D, 1);
+
+ /* Loop through binary GCD algorithm */
+ do {
+ while(mp_iseven(&u)) {
+ s_mp_div_2(&u);
+
+ if(mp_iseven(&A) && mp_iseven(&B)) {
+ s_mp_div_2(&A); s_mp_div_2(&B);
+ } else {
+ MP_CHECKOK( mp_add(&A, &yc, &A) );
+ s_mp_div_2(&A);
+ MP_CHECKOK( mp_sub(&B, &xc, &B) );
+ s_mp_div_2(&B);
+ }
+ }
+
+ while(mp_iseven(&v)) {
+ s_mp_div_2(&v);
+
+ if(mp_iseven(&C) && mp_iseven(&D)) {
+ s_mp_div_2(&C); s_mp_div_2(&D);
+ } else {
+ MP_CHECKOK( mp_add(&C, &yc, &C) );
+ s_mp_div_2(&C);
+ MP_CHECKOK( mp_sub(&D, &xc, &D) );
+ s_mp_div_2(&D);
+ }
+ }
+
+ if(mp_cmp(&u, &v) >= 0) {
+ MP_CHECKOK( mp_sub(&u, &v, &u) );
+ MP_CHECKOK( mp_sub(&A, &C, &A) );
+ MP_CHECKOK( mp_sub(&B, &D, &B) );
+ } else {
+ MP_CHECKOK( mp_sub(&v, &u, &v) );
+ MP_CHECKOK( mp_sub(&C, &A, &C) );
+ MP_CHECKOK( mp_sub(&D, &B, &D) );
+ }
+ } while (mp_cmp_z(&u) != 0);
+
+ /* copy results to output */
+ if(x)
+ MP_CHECKOK( mp_copy(&C, x) );
+
+ if(y)
+ MP_CHECKOK( mp_copy(&D, y) );
+
+ if(g)
+ MP_CHECKOK( mp_mul(&gx, &v, g) );
+
+ CLEANUP:
+ while(last >= 0)
+ mp_clear(clean[last--]);
+
+ return res;
+
+} /* end mp_xgcd() */
+
+/* }}} */
+
+mp_size mp_trailing_zeros(const mp_int *mp)
+{
+ mp_digit d;
+ mp_size n = 0;
+ unsigned int ix;
+
+ if (!mp || !MP_DIGITS(mp) || !mp_cmp_z(mp))
+ return n;
+
+ for (ix = 0; !(d = MP_DIGIT(mp,ix)) && (ix < MP_USED(mp)); ++ix)
+ n += MP_DIGIT_BIT;
+ if (!d)
+ return 0; /* shouldn't happen, but ... */
+#if !defined(MP_USE_UINT_DIGIT)
+ if (!(d & 0xffffffffU)) {
+ d >>= 32;
+ n += 32;
+ }
+#endif
+ if (!(d & 0xffffU)) {
+ d >>= 16;
+ n += 16;
+ }
+ if (!(d & 0xffU)) {
+ d >>= 8;
+ n += 8;
+ }
+ if (!(d & 0xfU)) {
+ d >>= 4;
+ n += 4;
+ }
+ if (!(d & 0x3U)) {
+ d >>= 2;
+ n += 2;
+ }
+ if (!(d & 0x1U)) {
+ d >>= 1;
+ n += 1;
+ }
+#if MP_ARGCHK == 2
+ assert(0 != (d & 1));
+#endif
+ return n;
+}
+
+/* Given a and prime p, computes c and k such that a*c == 2**k (mod p).
+** Returns k (positive) or error (negative).
+** This technique from the paper "Fast Modular Reciprocals" (unpublished)
+** by Richard Schroeppel (a.k.a. Captain Nemo).
+*/
+mp_err s_mp_almost_inverse(const mp_int *a, const mp_int *p, mp_int *c)
+{
+ mp_err res;
+ mp_err k = 0;
+ mp_int d, f, g;
+
+ ARGCHK(a && p && c, MP_BADARG);
+
+ MP_DIGITS(&d) = 0;
+ MP_DIGITS(&f) = 0;
+ MP_DIGITS(&g) = 0;
+ MP_CHECKOK( mp_init(&d, FLAG(a)) );
+ MP_CHECKOK( mp_init_copy(&f, a) ); /* f = a */
+ MP_CHECKOK( mp_init_copy(&g, p) ); /* g = p */
+
+ mp_set(c, 1);
+ mp_zero(&d);
+
+ if (mp_cmp_z(&f) == 0) {
+ res = MP_UNDEF;
+ } else
+ for (;;) {
+ int diff_sign;
+ while (mp_iseven(&f)) {
+ mp_size n = mp_trailing_zeros(&f);
+ if (!n) {
+ res = MP_UNDEF;
+ goto CLEANUP;
+ }
+ s_mp_div_2d(&f, n);
+ MP_CHECKOK( s_mp_mul_2d(&d, n) );
+ k += n;
+ }
+ if (mp_cmp_d(&f, 1) == MP_EQ) { /* f == 1 */
+ res = k;
+ break;
+ }
+ diff_sign = mp_cmp(&f, &g);
+ if (diff_sign < 0) { /* f < g */
+ s_mp_exch(&f, &g);
+ s_mp_exch(c, &d);
+ } else if (diff_sign == 0) { /* f == g */
+ res = MP_UNDEF; /* a and p are not relatively prime */
+ break;
+ }
+ if ((MP_DIGIT(&f,0) % 4) == (MP_DIGIT(&g,0) % 4)) {
+ MP_CHECKOK( mp_sub(&f, &g, &f) ); /* f = f - g */
+ MP_CHECKOK( mp_sub(c, &d, c) ); /* c = c - d */
+ } else {
+ MP_CHECKOK( mp_add(&f, &g, &f) ); /* f = f + g */
+ MP_CHECKOK( mp_add(c, &d, c) ); /* c = c + d */
+ }
+ }
+ if (res >= 0) {
+ if (s_mp_cmp(c, p) >= 0) {
+ MP_CHECKOK( mp_div(c, p, NULL, c));
+ }
+ if (MP_SIGN(c) != MP_ZPOS) {
+ MP_CHECKOK( mp_add(c, p, c) );
+ }
+ res = k;
+ }
+
+CLEANUP:
+ mp_clear(&d);
+ mp_clear(&f);
+ mp_clear(&g);
+ return res;
+}
+
+/* Compute T = (P ** -1) mod MP_RADIX. Also works for 16-bit mp_digits.
+** This technique from the paper "Fast Modular Reciprocals" (unpublished)
+** by Richard Schroeppel (a.k.a. Captain Nemo).
+*/
+mp_digit s_mp_invmod_radix(mp_digit P)
+{
+ mp_digit T = P;
+ T *= 2 - (P * T);
+ T *= 2 - (P * T);
+ T *= 2 - (P * T);
+ T *= 2 - (P * T);
+#if !defined(MP_USE_UINT_DIGIT)
+ T *= 2 - (P * T);
+ T *= 2 - (P * T);
+#endif
+ return T;
+}
+
+/* Given c, k, and prime p, where a*c == 2**k (mod p),
+** Compute x = (a ** -1) mod p. This is similar to Montgomery reduction.
+** This technique from the paper "Fast Modular Reciprocals" (unpublished)
+** by Richard Schroeppel (a.k.a. Captain Nemo).
+*/
+mp_err s_mp_fixup_reciprocal(const mp_int *c, const mp_int *p, int k, mp_int *x)
+{
+ int k_orig = k;
+ mp_digit r;
+ mp_size ix;
+ mp_err res;
+
+ if (mp_cmp_z(c) < 0) { /* c < 0 */
+ MP_CHECKOK( mp_add(c, p, x) ); /* x = c + p */
+ } else {
+ MP_CHECKOK( mp_copy(c, x) ); /* x = c */
+ }
+
+ /* make sure x is large enough */
+ ix = MP_HOWMANY(k, MP_DIGIT_BIT) + MP_USED(p) + 1;
+ ix = MP_MAX(ix, MP_USED(x));
+ MP_CHECKOK( s_mp_pad(x, ix) );
+
+ r = 0 - s_mp_invmod_radix(MP_DIGIT(p,0));
+
+ for (ix = 0; k > 0; ix++) {
+ int j = MP_MIN(k, MP_DIGIT_BIT);
+ mp_digit v = r * MP_DIGIT(x, ix);
+ if (j < MP_DIGIT_BIT) {
+ v &= ((mp_digit)1 << j) - 1; /* v = v mod (2 ** j) */
+ }
+ s_mp_mul_d_add_offset(p, v, x, ix); /* x += p * v * (RADIX ** ix) */
+ k -= j;
+ }
+ s_mp_clamp(x);
+ s_mp_div_2d(x, k_orig);
+ res = MP_OKAY;
+
+CLEANUP:
+ return res;
+}
+
+/* compute mod inverse using Schroeppel's method, only if m is odd */
+mp_err s_mp_invmod_odd_m(const mp_int *a, const mp_int *m, mp_int *c)
+{
+ int k;
+ mp_err res;
+ mp_int x;
+
+ ARGCHK(a && m && c, MP_BADARG);
+
+ if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
+ return MP_RANGE;
+ if (mp_iseven(m))
+ return MP_UNDEF;
+
+ MP_DIGITS(&x) = 0;
+
+ if (a == c) {
+ if ((res = mp_init_copy(&x, a)) != MP_OKAY)
+ return res;
+ if (a == m)
+ m = &x;
+ a = &x;
+ } else if (m == c) {
+ if ((res = mp_init_copy(&x, m)) != MP_OKAY)
+ return res;
+ m = &x;
+ } else {
+ MP_DIGITS(&x) = 0;
+ }
+
+ MP_CHECKOK( s_mp_almost_inverse(a, m, c) );
+ k = res;
+ MP_CHECKOK( s_mp_fixup_reciprocal(c, m, k, c) );
+CLEANUP:
+ mp_clear(&x);
+ return res;
+}
+
+/* Known good algorithm for computing modular inverse. But slow. */
+mp_err mp_invmod_xgcd(const mp_int *a, const mp_int *m, mp_int *c)
+{
+ mp_int g, x;
+ mp_err res;
+
+ ARGCHK(a && m && c, MP_BADARG);
+
+ if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
+ return MP_RANGE;
+
+ MP_DIGITS(&g) = 0;
+ MP_DIGITS(&x) = 0;
+ MP_CHECKOK( mp_init(&x, FLAG(a)) );
+ MP_CHECKOK( mp_init(&g, FLAG(a)) );
+
+ MP_CHECKOK( mp_xgcd(a, m, &g, &x, NULL) );
+
+ if (mp_cmp_d(&g, 1) != MP_EQ) {
+ res = MP_UNDEF;
+ goto CLEANUP;
+ }
+
+ res = mp_mod(&x, m, c);
+ SIGN(c) = SIGN(a);
+
+CLEANUP:
+ mp_clear(&x);
+ mp_clear(&g);
+
+ return res;
+}
+
+/* modular inverse where modulus is 2**k. */
+/* c = a**-1 mod 2**k */
+mp_err s_mp_invmod_2d(const mp_int *a, mp_size k, mp_int *c)
+{
+ mp_err res;
+ mp_size ix = k + 4;
+ mp_int t0, t1, val, tmp, two2k;
+
+ static const mp_digit d2 = 2;
+ static const mp_int two = { 0, MP_ZPOS, 1, 1, (mp_digit *)&d2 };
+
+ if (mp_iseven(a))
+ return MP_UNDEF;
+ if (k <= MP_DIGIT_BIT) {
+ mp_digit i = s_mp_invmod_radix(MP_DIGIT(a,0));
+ if (k < MP_DIGIT_BIT)
+ i &= ((mp_digit)1 << k) - (mp_digit)1;
+ mp_set(c, i);
+ return MP_OKAY;
+ }
+ MP_DIGITS(&t0) = 0;
+ MP_DIGITS(&t1) = 0;
+ MP_DIGITS(&val) = 0;
+ MP_DIGITS(&tmp) = 0;
+ MP_DIGITS(&two2k) = 0;
+ MP_CHECKOK( mp_init_copy(&val, a) );
+ s_mp_mod_2d(&val, k);
+ MP_CHECKOK( mp_init_copy(&t0, &val) );
+ MP_CHECKOK( mp_init_copy(&t1, &t0) );
+ MP_CHECKOK( mp_init(&tmp, FLAG(a)) );
+ MP_CHECKOK( mp_init(&two2k, FLAG(a)) );
+ MP_CHECKOK( s_mp_2expt(&two2k, k) );
+ do {
+ MP_CHECKOK( mp_mul(&val, &t1, &tmp) );
+ MP_CHECKOK( mp_sub(&two, &tmp, &tmp) );
+ MP_CHECKOK( mp_mul(&t1, &tmp, &t1) );
+ s_mp_mod_2d(&t1, k);
+ while (MP_SIGN(&t1) != MP_ZPOS) {
+ MP_CHECKOK( mp_add(&t1, &two2k, &t1) );
+ }
+ if (mp_cmp(&t1, &t0) == MP_EQ)
+ break;
+ MP_CHECKOK( mp_copy(&t1, &t0) );
+ } while (--ix > 0);
+ if (!ix) {
+ res = MP_UNDEF;
+ } else {
+ mp_exch(c, &t1);
+ }
+
+CLEANUP:
+ mp_clear(&t0);
+ mp_clear(&t1);
+ mp_clear(&val);
+ mp_clear(&tmp);
+ mp_clear(&two2k);
+ return res;
+}
+
+mp_err s_mp_invmod_even_m(const mp_int *a, const mp_int *m, mp_int *c)
+{
+ mp_err res;
+ mp_size k;
+ mp_int oddFactor, evenFactor; /* factors of the modulus */
+ mp_int oddPart, evenPart; /* parts to combine via CRT. */
+ mp_int C2, tmp1, tmp2;
+
+ /*static const mp_digit d1 = 1; */
+ /*static const mp_int one = { MP_ZPOS, 1, 1, (mp_digit *)&d1 }; */
+
+ if ((res = s_mp_ispow2(m)) >= 0) {
+ k = res;
+ return s_mp_invmod_2d(a, k, c);
+ }
+ MP_DIGITS(&oddFactor) = 0;
+ MP_DIGITS(&evenFactor) = 0;
+ MP_DIGITS(&oddPart) = 0;
+ MP_DIGITS(&evenPart) = 0;
+ MP_DIGITS(&C2) = 0;
+ MP_DIGITS(&tmp1) = 0;
+ MP_DIGITS(&tmp2) = 0;
+
+ MP_CHECKOK( mp_init_copy(&oddFactor, m) ); /* oddFactor = m */
+ MP_CHECKOK( mp_init(&evenFactor, FLAG(m)) );
+ MP_CHECKOK( mp_init(&oddPart, FLAG(m)) );
+ MP_CHECKOK( mp_init(&evenPart, FLAG(m)) );
+ MP_CHECKOK( mp_init(&C2, FLAG(m)) );
+ MP_CHECKOK( mp_init(&tmp1, FLAG(m)) );
+ MP_CHECKOK( mp_init(&tmp2, FLAG(m)) );
+
+ k = mp_trailing_zeros(m);
+ s_mp_div_2d(&oddFactor, k);
+ MP_CHECKOK( s_mp_2expt(&evenFactor, k) );
+
+ /* compute a**-1 mod oddFactor. */
+ MP_CHECKOK( s_mp_invmod_odd_m(a, &oddFactor, &oddPart) );
+ /* compute a**-1 mod evenFactor, where evenFactor == 2**k. */
+ MP_CHECKOK( s_mp_invmod_2d( a, k, &evenPart) );
+
+ /* Use Chinese Remainer theorem to compute a**-1 mod m. */
+ /* let m1 = oddFactor, v1 = oddPart,
+ * let m2 = evenFactor, v2 = evenPart.
+ */
+
+ /* Compute C2 = m1**-1 mod m2. */
+ MP_CHECKOK( s_mp_invmod_2d(&oddFactor, k, &C2) );
+
+ /* compute u = (v2 - v1)*C2 mod m2 */
+ MP_CHECKOK( mp_sub(&evenPart, &oddPart, &tmp1) );
+ MP_CHECKOK( mp_mul(&tmp1, &C2, &tmp2) );
+ s_mp_mod_2d(&tmp2, k);
+ while (MP_SIGN(&tmp2) != MP_ZPOS) {
+ MP_CHECKOK( mp_add(&tmp2, &evenFactor, &tmp2) );
+ }
+
+ /* compute answer = v1 + u*m1 */
+ MP_CHECKOK( mp_mul(&tmp2, &oddFactor, c) );
+ MP_CHECKOK( mp_add(&oddPart, c, c) );
+ /* not sure this is necessary, but it's low cost if not. */
+ MP_CHECKOK( mp_mod(c, m, c) );
+
+CLEANUP:
+ mp_clear(&oddFactor);
+ mp_clear(&evenFactor);
+ mp_clear(&oddPart);
+ mp_clear(&evenPart);
+ mp_clear(&C2);
+ mp_clear(&tmp1);
+ mp_clear(&tmp2);
+ return res;
+}
+
+
+/* {{{ mp_invmod(a, m, c) */
+
+/*
+ mp_invmod(a, m, c)
+
+ Compute c = a^-1 (mod m), if there is an inverse for a (mod m).
+ This is equivalent to the question of whether (a, m) = 1. If not,
+ MP_UNDEF is returned, and there is no inverse.
+ */
+
+mp_err mp_invmod(const mp_int *a, const mp_int *m, mp_int *c)
+{
+
+ ARGCHK(a && m && c, MP_BADARG);
+
+ if(mp_cmp_z(a) == 0 || mp_cmp_z(m) == 0)
+ return MP_RANGE;
+
+ if (mp_isodd(m)) {
+ return s_mp_invmod_odd_m(a, m, c);
+ }
+ if (mp_iseven(a))
+ return MP_UNDEF; /* not invertable */
+
+ return s_mp_invmod_even_m(a, m, c);
+
+} /* end mp_invmod() */
+
+/* }}} */
+#endif /* if MP_NUMTH */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ mp_print(mp, ofp) */
+
+#if MP_IOFUNC
+/*
+ mp_print(mp, ofp)
+
+ Print a textual representation of the given mp_int on the output
+ stream 'ofp'. Output is generated using the internal radix.
+ */
+
+void mp_print(mp_int *mp, FILE *ofp)
+{
+ int ix;
+
+ if(mp == NULL || ofp == NULL)
+ return;
+
+ fputc((SIGN(mp) == NEG) ? '-' : '+', ofp);
+
+ for(ix = USED(mp) - 1; ix >= 0; ix--) {
+ fprintf(ofp, DIGIT_FMT, DIGIT(mp, ix));
+ }
+
+} /* end mp_print() */
+
+#endif /* if MP_IOFUNC */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/* {{{ More I/O Functions */
+
+/* {{{ mp_read_raw(mp, str, len) */
+
+/*
+ mp_read_raw(mp, str, len)
+
+ Read in a raw value (base 256) into the given mp_int
+ */
+
+mp_err mp_read_raw(mp_int *mp, char *str, int len)
+{
+ int ix;
+ mp_err res;
+ unsigned char *ustr = (unsigned char *)str;
+
+ ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
+
+ mp_zero(mp);
+
+ /* Get sign from first byte */
+ if(ustr[0])
+ SIGN(mp) = NEG;
+ else
+ SIGN(mp) = ZPOS;
+
+ /* Read the rest of the digits */
+ for(ix = 1; ix < len; ix++) {
+ if((res = mp_mul_d(mp, 256, mp)) != MP_OKAY)
+ return res;
+ if((res = mp_add_d(mp, ustr[ix], mp)) != MP_OKAY)
+ return res;
+ }
+
+ return MP_OKAY;
+
+} /* end mp_read_raw() */
+
+/* }}} */
+
+/* {{{ mp_raw_size(mp) */
+
+int mp_raw_size(mp_int *mp)
+{
+ ARGCHK(mp != NULL, 0);
+
+ return (USED(mp) * sizeof(mp_digit)) + 1;
+
+} /* end mp_raw_size() */
+
+/* }}} */
+
+/* {{{ mp_toraw(mp, str) */
+
+mp_err mp_toraw(mp_int *mp, char *str)
+{
+ int ix, jx, pos = 1;
+
+ ARGCHK(mp != NULL && str != NULL, MP_BADARG);
+
+ str[0] = (char)SIGN(mp);
+
+ /* Iterate over each digit... */
+ for(ix = USED(mp) - 1; ix >= 0; ix--) {
+ mp_digit d = DIGIT(mp, ix);
+
+ /* Unpack digit bytes, high order first */
+ for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
+ str[pos++] = (char)(d >> (jx * CHAR_BIT));
+ }
+ }
+
+ return MP_OKAY;
+
+} /* end mp_toraw() */
+
+/* }}} */
+
+/* {{{ mp_read_radix(mp, str, radix) */
+
+/*
+ mp_read_radix(mp, str, radix)
+
+ Read an integer from the given string, and set mp to the resulting
+ value. The input is presumed to be in base 10. Leading non-digit
+ characters are ignored, and the function reads until a non-digit
+ character or the end of the string.
+ */
+
+mp_err mp_read_radix(mp_int *mp, const char *str, int radix)
+{
+ int ix = 0, val = 0;
+ mp_err res;
+ mp_sign sig = ZPOS;
+
+ ARGCHK(mp != NULL && str != NULL && radix >= 2 && radix <= MAX_RADIX,
+ MP_BADARG);
+
+ mp_zero(mp);
+
+ /* Skip leading non-digit characters until a digit or '-' or '+' */
+ while(str[ix] &&
+ (s_mp_tovalue(str[ix], radix) < 0) &&
+ str[ix] != '-' &&
+ str[ix] != '+') {
+ ++ix;
+ }
+
+ if(str[ix] == '-') {
+ sig = NEG;
+ ++ix;
+ } else if(str[ix] == '+') {
+ sig = ZPOS; /* this is the default anyway... */
+ ++ix;
+ }
+
+ while((val = s_mp_tovalue(str[ix], radix)) >= 0) {
+ if((res = s_mp_mul_d(mp, radix)) != MP_OKAY)
+ return res;
+ if((res = s_mp_add_d(mp, val)) != MP_OKAY)
+ return res;
+ ++ix;
+ }
+
+ if(s_mp_cmp_d(mp, 0) == MP_EQ)
+ SIGN(mp) = ZPOS;
+ else
+ SIGN(mp) = sig;
+
+ return MP_OKAY;
+
+} /* end mp_read_radix() */
+
+mp_err mp_read_variable_radix(mp_int *a, const char * str, int default_radix)
+{
+ int radix = default_radix;
+ int cx;
+ mp_sign sig = ZPOS;
+ mp_err res;
+
+ /* Skip leading non-digit characters until a digit or '-' or '+' */
+ while ((cx = *str) != 0 &&
+ (s_mp_tovalue(cx, radix) < 0) &&
+ cx != '-' &&
+ cx != '+') {
+ ++str;
+ }
+
+ if (cx == '-') {
+ sig = NEG;
+ ++str;
+ } else if (cx == '+') {
+ sig = ZPOS; /* this is the default anyway... */
+ ++str;
+ }
+
+ if (str[0] == '0') {
+ if ((str[1] | 0x20) == 'x') {
+ radix = 16;
+ str += 2;
+ } else {
+ radix = 8;
+ str++;
+ }
+ }
+ res = mp_read_radix(a, str, radix);
+ if (res == MP_OKAY) {
+ MP_SIGN(a) = (s_mp_cmp_d(a, 0) == MP_EQ) ? ZPOS : sig;
+ }
+ return res;
+}
+
+/* }}} */
+
+/* {{{ mp_radix_size(mp, radix) */
+
+int mp_radix_size(mp_int *mp, int radix)
+{
+ int bits;
+
+ if(!mp || radix < 2 || radix > MAX_RADIX)
+ return 0;
+
+ bits = USED(mp) * DIGIT_BIT - 1;
+
+ return s_mp_outlen(bits, radix);
+
+} /* end mp_radix_size() */
+
+/* }}} */
+
+/* {{{ mp_toradix(mp, str, radix) */
+
+mp_err mp_toradix(mp_int *mp, char *str, int radix)
+{
+ int ix, pos = 0;
+
+ ARGCHK(mp != NULL && str != NULL, MP_BADARG);
+ ARGCHK(radix > 1 && radix <= MAX_RADIX, MP_RANGE);
+
+ if(mp_cmp_z(mp) == MP_EQ) {
+ str[0] = '0';
+ str[1] = '\0';
+ } else {
+ mp_err res;
+ mp_int tmp;
+ mp_sign sgn;
+ mp_digit rem, rdx = (mp_digit)radix;
+ char ch;
+
+ if((res = mp_init_copy(&tmp, mp)) != MP_OKAY)
+ return res;
+
+ /* Save sign for later, and take absolute value */
+ sgn = SIGN(&tmp); SIGN(&tmp) = ZPOS;
+
+ /* Generate output digits in reverse order */
+ while(mp_cmp_z(&tmp) != 0) {
+ if((res = mp_div_d(&tmp, rdx, &tmp, &rem)) != MP_OKAY) {
+ mp_clear(&tmp);
+ return res;
+ }
+
+ /* Generate digits, use capital letters */
+ ch = s_mp_todigit(rem, radix, 0);
+
+ str[pos++] = ch;
+ }
+
+ /* Add - sign if original value was negative */
+ if(sgn == NEG)
+ str[pos++] = '-';
+
+ /* Add trailing NUL to end the string */
+ str[pos--] = '\0';
+
+ /* Reverse the digits and sign indicator */
+ ix = 0;
+ while(ix < pos) {
+ char tmp = str[ix];
+
+ str[ix] = str[pos];
+ str[pos] = tmp;
+ ++ix;
+ --pos;
+ }
+
+ mp_clear(&tmp);
+ }
+
+ return MP_OKAY;
+
+} /* end mp_toradix() */
+
+/* }}} */
+
+/* {{{ mp_tovalue(ch, r) */
+
+int mp_tovalue(char ch, int r)
+{
+ return s_mp_tovalue(ch, r);
+
+} /* end mp_tovalue() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ mp_strerror(ec) */
+
+/*
+ mp_strerror(ec)
+
+ Return a string describing the meaning of error code 'ec'. The
+ string returned is allocated in static memory, so the caller should
+ not attempt to modify or free the memory associated with this
+ string.
+ */
+const char *mp_strerror(mp_err ec)
+{
+ int aec = (ec < 0) ? -ec : ec;
+
+ /* Code values are negative, so the senses of these comparisons
+ are accurate */
+ if(ec < MP_LAST_CODE || ec > MP_OKAY) {
+ return mp_err_string[0]; /* unknown error code */
+ } else {
+ return mp_err_string[aec + 1];
+ }
+
+} /* end mp_strerror() */
+
+/* }}} */
+
+/*========================================================================*/
+/*------------------------------------------------------------------------*/
+/* Static function definitions (internal use only) */
+
+/* {{{ Memory management */
+
+/* {{{ s_mp_grow(mp, min) */
+
+/* Make sure there are at least 'min' digits allocated to mp */
+mp_err s_mp_grow(mp_int *mp, mp_size min)
+{
+ if(min > ALLOC(mp)) {
+ mp_digit *tmp;
+
+ /* Set min to next nearest default precision block size */
+ min = MP_ROUNDUP(min, s_mp_defprec);
+
+ if((tmp = s_mp_alloc(min, sizeof(mp_digit), FLAG(mp))) == NULL)
+ return MP_MEM;
+
+ s_mp_copy(DIGITS(mp), tmp, USED(mp));
+
+#if MP_CRYPTO
+ s_mp_setz(DIGITS(mp), ALLOC(mp));
+#endif
+ s_mp_free(DIGITS(mp), ALLOC(mp));
+ DIGITS(mp) = tmp;
+ ALLOC(mp) = min;
+ }
+
+ return MP_OKAY;
+
+} /* end s_mp_grow() */
+
+/* }}} */
+
+/* {{{ s_mp_pad(mp, min) */
+
+/* Make sure the used size of mp is at least 'min', growing if needed */
+mp_err s_mp_pad(mp_int *mp, mp_size min)
+{
+ if(min > USED(mp)) {
+ mp_err res;
+
+ /* Make sure there is room to increase precision */
+ if (min > ALLOC(mp)) {
+ if ((res = s_mp_grow(mp, min)) != MP_OKAY)
+ return res;
+ } else {
+ s_mp_setz(DIGITS(mp) + USED(mp), min - USED(mp));
+ }
+
+ /* Increase precision; should already be 0-filled */
+ USED(mp) = min;
+ }
+
+ return MP_OKAY;
+
+} /* end s_mp_pad() */
+
+/* }}} */
+
+/* {{{ s_mp_setz(dp, count) */
+
+#if MP_MACRO == 0
+/* Set 'count' digits pointed to by dp to be zeroes */
+void s_mp_setz(mp_digit *dp, mp_size count)
+{
+#if MP_MEMSET == 0
+ int ix;
+
+ for(ix = 0; ix < count; ix++)
+ dp[ix] = 0;
+#else
+ memset(dp, 0, count * sizeof(mp_digit));
+#endif
+
+} /* end s_mp_setz() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_copy(sp, dp, count) */
+
+#if MP_MACRO == 0
+/* Copy 'count' digits from sp to dp */
+void s_mp_copy(const mp_digit *sp, mp_digit *dp, mp_size count)
+{
+#if MP_MEMCPY == 0
+ int ix;
+
+ for(ix = 0; ix < count; ix++)
+ dp[ix] = sp[ix];
+#else
+ memcpy(dp, sp, count * sizeof(mp_digit));
+#endif
+
+} /* end s_mp_copy() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_alloc(nb, ni, kmflag) */
+
+#if MP_MACRO == 0
+/* Allocate ni records of nb bytes each, and return a pointer to that */
+void *s_mp_alloc(size_t nb, size_t ni, int kmflag)
+{
+ ++mp_allocs;
+#ifdef _KERNEL
+ mp_int *mp;
+ mp = kmem_zalloc(nb * ni, kmflag);
+ if (mp != NULL)
+ FLAG(mp) = kmflag;
+ return (mp);
+#else
+ return calloc(nb, ni);
+#endif
+
+} /* end s_mp_alloc() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_free(ptr) */
+
+#if MP_MACRO == 0
+/* Free the memory pointed to by ptr */
+void s_mp_free(void *ptr, mp_size alloc)
+{
+ if(ptr) {
+ ++mp_frees;
+#ifdef _KERNEL
+ kmem_free(ptr, alloc * sizeof (mp_digit));
+#else
+ free(ptr);
+#endif
+ }
+} /* end s_mp_free() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_clamp(mp) */
+
+#if MP_MACRO == 0
+/* Remove leading zeroes from the given value */
+void s_mp_clamp(mp_int *mp)
+{
+ mp_size used = MP_USED(mp);
+ while (used > 1 && DIGIT(mp, used - 1) == 0)
+ --used;
+ MP_USED(mp) = used;
+} /* end s_mp_clamp() */
+#endif
+
+/* }}} */
+
+/* {{{ s_mp_exch(a, b) */
+
+/* Exchange the data for a and b; (b, a) = (a, b) */
+void s_mp_exch(mp_int *a, mp_int *b)
+{
+ mp_int tmp;
+
+ tmp = *a;
+ *a = *b;
+ *b = tmp;
+
+} /* end s_mp_exch() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Arithmetic helpers */
+
+/* {{{ s_mp_lshd(mp, p) */
+
+/*
+ Shift mp leftward by p digits, growing if needed, and zero-filling
+ the in-shifted digits at the right end. This is a convenient
+ alternative to multiplication by powers of the radix
+ The value of USED(mp) must already have been set to the value for
+ the shifted result.
+ */
+
+mp_err s_mp_lshd(mp_int *mp, mp_size p)
+{
+ mp_err res;
+ mp_size pos;
+ int ix;
+
+ if(p == 0)
+ return MP_OKAY;
+
+ if (MP_USED(mp) == 1 && MP_DIGIT(mp, 0) == 0)
+ return MP_OKAY;
+
+ if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY)
+ return res;
+
+ pos = USED(mp) - 1;
+
+ /* Shift all the significant figures over as needed */
+ for(ix = pos - p; ix >= 0; ix--)
+ DIGIT(mp, ix + p) = DIGIT(mp, ix);
+
+ /* Fill the bottom digits with zeroes */
+ for(ix = 0; ix < p; ix++)
+ DIGIT(mp, ix) = 0;
+
+ return MP_OKAY;
+
+} /* end s_mp_lshd() */
+
+/* }}} */
+
+/* {{{ s_mp_mul_2d(mp, d) */
+
+/*
+ Multiply the integer by 2^d, where d is a number of bits. This
+ amounts to a bitwise shift of the value.
+ */
+mp_err s_mp_mul_2d(mp_int *mp, mp_digit d)
+{
+ mp_err res;
+ mp_digit dshift, bshift;
+ mp_digit mask;
+
+ ARGCHK(mp != NULL, MP_BADARG);
+
+ dshift = d / MP_DIGIT_BIT;
+ bshift = d % MP_DIGIT_BIT;
+ /* bits to be shifted out of the top word */
+ mask = ((mp_digit)~0 << (MP_DIGIT_BIT - bshift));
+ mask &= MP_DIGIT(mp, MP_USED(mp) - 1);
+
+ if (MP_OKAY != (res = s_mp_pad(mp, MP_USED(mp) + dshift + (mask != 0) )))
+ return res;
+
+ if (dshift && MP_OKAY != (res = s_mp_lshd(mp, dshift)))
+ return res;
+
+ if (bshift) {
+ mp_digit *pa = MP_DIGITS(mp);
+ mp_digit *alim = pa + MP_USED(mp);
+ mp_digit prev = 0;
+
+ for (pa += dshift; pa < alim; ) {
+ mp_digit x = *pa;
+ *pa++ = (x << bshift) | prev;
+ prev = x >> (DIGIT_BIT - bshift);
+ }
+ }
+
+ s_mp_clamp(mp);
+ return MP_OKAY;
+} /* end s_mp_mul_2d() */
+
+/* {{{ s_mp_rshd(mp, p) */
+
+/*
+ Shift mp rightward by p digits. Maintains the invariant that
+ digits above the precision are all zero. Digits shifted off the
+ end are lost. Cannot fail.
+ */
+
+void s_mp_rshd(mp_int *mp, mp_size p)
+{
+ mp_size ix;
+ mp_digit *src, *dst;
+
+ if(p == 0)
+ return;
+
+ /* Shortcut when all digits are to be shifted off */
+ if(p >= USED(mp)) {
+ s_mp_setz(DIGITS(mp), ALLOC(mp));
+ USED(mp) = 1;
+ SIGN(mp) = ZPOS;
+ return;
+ }
+
+ /* Shift all the significant figures over as needed */
+ dst = MP_DIGITS(mp);
+ src = dst + p;
+ for (ix = USED(mp) - p; ix > 0; ix--)
+ *dst++ = *src++;
+
+ MP_USED(mp) -= p;
+ /* Fill the top digits with zeroes */
+ while (p-- > 0)
+ *dst++ = 0;
+
+#if 0
+ /* Strip off any leading zeroes */
+ s_mp_clamp(mp);
+#endif
+
+} /* end s_mp_rshd() */
+
+/* }}} */
+
+/* {{{ s_mp_div_2(mp) */
+
+/* Divide by two -- take advantage of radix properties to do it fast */
+void s_mp_div_2(mp_int *mp)
+{
+ s_mp_div_2d(mp, 1);
+
+} /* end s_mp_div_2() */
+
+/* }}} */
+
+/* {{{ s_mp_mul_2(mp) */
+
+mp_err s_mp_mul_2(mp_int *mp)
+{
+ mp_digit *pd;
+ unsigned int ix, used;
+ mp_digit kin = 0;
+
+ /* Shift digits leftward by 1 bit */
+ used = MP_USED(mp);
+ pd = MP_DIGITS(mp);
+ for (ix = 0; ix < used; ix++) {
+ mp_digit d = *pd;
+ *pd++ = (d << 1) | kin;
+ kin = (d >> (DIGIT_BIT - 1));
+ }
+
+ /* Deal with rollover from last digit */
+ if (kin) {
+ if (ix >= ALLOC(mp)) {
+ mp_err res;
+ if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY)
+ return res;
+ }
+
+ DIGIT(mp, ix) = kin;
+ USED(mp) += 1;
+ }
+
+ return MP_OKAY;
+
+} /* end s_mp_mul_2() */
+
+/* }}} */
+
+/* {{{ s_mp_mod_2d(mp, d) */
+
+/*
+ Remainder the integer by 2^d, where d is a number of bits. This
+ amounts to a bitwise AND of the value, and does not require the full
+ division code
+ */
+void s_mp_mod_2d(mp_int *mp, mp_digit d)
+{
+ mp_size ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT);
+ mp_size ix;
+ mp_digit dmask;
+
+ if(ndig >= USED(mp))
+ return;
+
+ /* Flush all the bits above 2^d in its digit */
+ dmask = ((mp_digit)1 << nbit) - 1;
+ DIGIT(mp, ndig) &= dmask;
+
+ /* Flush all digits above the one with 2^d in it */
+ for(ix = ndig + 1; ix < USED(mp); ix++)
+ DIGIT(mp, ix) = 0;
+
+ s_mp_clamp(mp);
+
+} /* end s_mp_mod_2d() */
+
+/* }}} */
+
+/* {{{ s_mp_div_2d(mp, d) */
+
+/*
+ Divide the integer by 2^d, where d is a number of bits. This
+ amounts to a bitwise shift of the value, and does not require the
+ full division code (used in Barrett reduction, see below)
+ */
+void s_mp_div_2d(mp_int *mp, mp_digit d)
+{
+ int ix;
+ mp_digit save, next, mask;
+
+ s_mp_rshd(mp, d / DIGIT_BIT);
+ d %= DIGIT_BIT;
+ if (d) {
+ mask = ((mp_digit)1 << d) - 1;
+ save = 0;
+ for(ix = USED(mp) - 1; ix >= 0; ix--) {
+ next = DIGIT(mp, ix) & mask;
+ DIGIT(mp, ix) = (DIGIT(mp, ix) >> d) | (save << (DIGIT_BIT - d));
+ save = next;
+ }
+ }
+ s_mp_clamp(mp);
+
+} /* end s_mp_div_2d() */
+
+/* }}} */
+
+/* {{{ s_mp_norm(a, b, *d) */
+
+/*
+ s_mp_norm(a, b, *d)
+
+ Normalize a and b for division, where b is the divisor. In order
+ that we might make good guesses for quotient digits, we want the
+ leading digit of b to be at least half the radix, which we
+ accomplish by multiplying a and b by a power of 2. The exponent
+ (shift count) is placed in *pd, so that the remainder can be shifted
+ back at the end of the division process.
+ */
+
+mp_err s_mp_norm(mp_int *a, mp_int *b, mp_digit *pd)
+{
+ mp_digit d;
+ mp_digit mask;
+ mp_digit b_msd;
+ mp_err res = MP_OKAY;
+
+ d = 0;
+ mask = DIGIT_MAX & ~(DIGIT_MAX >> 1); /* mask is msb of digit */
+ b_msd = DIGIT(b, USED(b) - 1);
+ while (!(b_msd & mask)) {
+ b_msd <<= 1;
+ ++d;
+ }
+
+ if (d) {
+ MP_CHECKOK( s_mp_mul_2d(a, d) );
+ MP_CHECKOK( s_mp_mul_2d(b, d) );
+ }
+
+ *pd = d;
+CLEANUP:
+ return res;
+
+} /* end s_mp_norm() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive digit arithmetic */
+
+/* {{{ s_mp_add_d(mp, d) */
+
+/* Add d to |mp| in place */
+mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ mp_word w, k = 0;
+ mp_size ix = 1;
+
+ w = (mp_word)DIGIT(mp, 0) + d;
+ DIGIT(mp, 0) = ACCUM(w);
+ k = CARRYOUT(w);
+
+ while(ix < USED(mp) && k) {
+ w = (mp_word)DIGIT(mp, ix) + k;
+ DIGIT(mp, ix) = ACCUM(w);
+ k = CARRYOUT(w);
+ ++ix;
+ }
+
+ if(k != 0) {
+ mp_err res;
+
+ if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY)
+ return res;
+
+ DIGIT(mp, ix) = (mp_digit)k;
+ }
+
+ return MP_OKAY;
+#else
+ mp_digit * pmp = MP_DIGITS(mp);
+ mp_digit sum, mp_i, carry = 0;
+ mp_err res = MP_OKAY;
+ int used = (int)MP_USED(mp);
+
+ mp_i = *pmp;
+ *pmp++ = sum = d + mp_i;
+ carry = (sum < d);
+ while (carry && --used > 0) {
+ mp_i = *pmp;
+ *pmp++ = sum = carry + mp_i;
+ carry = !sum;
+ }
+ if (carry && !used) {
+ /* mp is growing */
+ used = MP_USED(mp);
+ MP_CHECKOK( s_mp_pad(mp, used + 1) );
+ MP_DIGIT(mp, used) = carry;
+ }
+CLEANUP:
+ return res;
+#endif
+} /* end s_mp_add_d() */
+
+/* }}} */
+
+/* {{{ s_mp_sub_d(mp, d) */
+
+/* Subtract d from |mp| in place, assumes |mp| > d */
+mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+ mp_word w, b = 0;
+ mp_size ix = 1;
+
+ /* Compute initial subtraction */
+ w = (RADIX + (mp_word)DIGIT(mp, 0)) - d;
+ b = CARRYOUT(w) ? 0 : 1;
+ DIGIT(mp, 0) = ACCUM(w);
+
+ /* Propagate borrows leftward */
+ while(b && ix < USED(mp)) {
+ w = (RADIX + (mp_word)DIGIT(mp, ix)) - b;
+ b = CARRYOUT(w) ? 0 : 1;
+ DIGIT(mp, ix) = ACCUM(w);
+ ++ix;
+ }
+
+ /* Remove leading zeroes */
+ s_mp_clamp(mp);
+
+ /* If we have a borrow out, it's a violation of the input invariant */
+ if(b)
+ return MP_RANGE;
+ else
+ return MP_OKAY;
+#else
+ mp_digit *pmp = MP_DIGITS(mp);
+ mp_digit mp_i, diff, borrow;
+ mp_size used = MP_USED(mp);
+
+ mp_i = *pmp;
+ *pmp++ = diff = mp_i - d;
+ borrow = (diff > mp_i);
+ while (borrow && --used) {
+ mp_i = *pmp;
+ *pmp++ = diff = mp_i - borrow;
+ borrow = (diff > mp_i);
+ }
+ s_mp_clamp(mp);
+ return (borrow && !used) ? MP_RANGE : MP_OKAY;
+#endif
+} /* end s_mp_sub_d() */
+
+/* }}} */
+
+/* {{{ s_mp_mul_d(a, d) */
+
+/* Compute a = a * d, single digit multiplication */
+mp_err s_mp_mul_d(mp_int *a, mp_digit d)
+{
+ mp_err res;
+ mp_size used;
+ int pow;
+
+ if (!d) {
+ mp_zero(a);
+ return MP_OKAY;
+ }
+ if (d == 1)
+ return MP_OKAY;
+ if (0 <= (pow = s_mp_ispow2d(d))) {
+ return s_mp_mul_2d(a, (mp_digit)pow);
+ }
+
+ used = MP_USED(a);
+ MP_CHECKOK( s_mp_pad(a, used + 1) );
+
+ s_mpv_mul_d(MP_DIGITS(a), used, d, MP_DIGITS(a));
+
+ s_mp_clamp(a);
+
+CLEANUP:
+ return res;
+
+} /* end s_mp_mul_d() */
+
+/* }}} */
+
+/* {{{ s_mp_div_d(mp, d, r) */
+
+/*
+ s_mp_div_d(mp, d, r)
+
+ Compute the quotient mp = mp / d and remainder r = mp mod d, for a
+ single digit d. If r is null, the remainder will be discarded.
+ */
+
+mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r)
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
+ mp_word w = 0, q;
+#else
+ mp_digit w = 0, q;
+#endif
+ int ix;
+ mp_err res;
+ mp_int quot;
+ mp_int rem;
+
+ if(d == 0)
+ return MP_RANGE;
+ if (d == 1) {
+ if (r)
+ *r = 0;
+ return MP_OKAY;
+ }
+ /* could check for power of 2 here, but mp_div_d does that. */
+ if (MP_USED(mp) == 1) {
+ mp_digit n = MP_DIGIT(mp,0);
+ mp_digit rem;
+
+ q = n / d;
+ rem = n % d;
+ MP_DIGIT(mp,0) = q;
+ if (r)
+ *r = rem;
+ return MP_OKAY;
+ }
+
+ MP_DIGITS(&rem) = 0;
+ MP_DIGITS(") = 0;
+ /* Make room for the quotient */
+ MP_CHECKOK( mp_init_size(", USED(mp), FLAG(mp)) );
+
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
+ for(ix = USED(mp) - 1; ix >= 0; ix--) {
+ w = (w << DIGIT_BIT) | DIGIT(mp, ix);
+
+ if(w >= d) {
+ q = w / d;
+ w = w % d;
+ } else {
+ q = 0;
+ }
+
+ s_mp_lshd(", 1);
+ DIGIT(", 0) = (mp_digit)q;
+ }
+#else
+ {
+ mp_digit p;
+#if !defined(MP_ASSEMBLY_DIV_2DX1D)
+ mp_digit norm;
+#endif
+
+ MP_CHECKOK( mp_init_copy(&rem, mp) );
+
+#if !defined(MP_ASSEMBLY_DIV_2DX1D)
+ MP_DIGIT(", 0) = d;
+ MP_CHECKOK( s_mp_norm(&rem, ", &norm) );
+ if (norm)
+ d <<= norm;
+ MP_DIGIT(", 0) = 0;
+#endif
+
+ p = 0;
+ for (ix = USED(&rem) - 1; ix >= 0; ix--) {
+ w = DIGIT(&rem, ix);
+
+ if (p) {
+ MP_CHECKOK( s_mpv_div_2dx1d(p, w, d, &q, &w) );
+ } else if (w >= d) {
+ q = w / d;
+ w = w % d;
+ } else {
+ q = 0;
+ }
+
+ MP_CHECKOK( s_mp_lshd(", 1) );
+ DIGIT(", 0) = q;
+ p = w;
+ }
+#if !defined(MP_ASSEMBLY_DIV_2DX1D)
+ if (norm)
+ w >>= norm;
+#endif
+ }
+#endif
+
+ /* Deliver the remainder, if desired */
+ if(r)
+ *r = (mp_digit)w;
+
+ s_mp_clamp(");
+ mp_exch(", mp);
+CLEANUP:
+ mp_clear(");
+ mp_clear(&rem);
+
+ return res;
+} /* end s_mp_div_d() */
+
+/* }}} */
+
+
+/* }}} */
+
+/* {{{ Primitive full arithmetic */
+
+/* {{{ s_mp_add(a, b) */
+
+/* Compute a = |a| + |b| */
+mp_err s_mp_add(mp_int *a, const mp_int *b) /* magnitude addition */
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ mp_word w = 0;
+#else
+ mp_digit d, sum, carry = 0;
+#endif
+ mp_digit *pa, *pb;
+ mp_size ix;
+ mp_size used;
+ mp_err res;
+
+ /* Make sure a has enough precision for the output value */
+ if((USED(b) > USED(a)) && (res = s_mp_pad(a, USED(b))) != MP_OKAY)
+ return res;
+
+ /*
+ Add up all digits up to the precision of b. If b had initially
+ the same precision as a, or greater, we took care of it by the
+ padding step above, so there is no problem. If b had initially
+ less precision, we'll have to make sure the carry out is duly
+ propagated upward among the higher-order digits of the sum.
+ */
+ pa = MP_DIGITS(a);
+ pb = MP_DIGITS(b);
+ used = MP_USED(b);
+ for(ix = 0; ix < used; ix++) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ w = w + *pa + *pb++;
+ *pa++ = ACCUM(w);
+ w = CARRYOUT(w);
+#else
+ d = *pa;
+ sum = d + *pb++;
+ d = (sum < d); /* detect overflow */
+ *pa++ = sum += carry;
+ carry = d + (sum < carry); /* detect overflow */
+#endif
+ }
+
+ /* If we run out of 'b' digits before we're actually done, make
+ sure the carries get propagated upward...
+ */
+ used = MP_USED(a);
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ while (w && ix < used) {
+ w = w + *pa;
+ *pa++ = ACCUM(w);
+ w = CARRYOUT(w);
+ ++ix;
+ }
+#else
+ while (carry && ix < used) {
+ sum = carry + *pa;
+ *pa++ = sum;
+ carry = !sum;
+ ++ix;
+ }
+#endif
+
+ /* If there's an overall carry out, increase precision and include
+ it. We could have done this initially, but why touch the memory
+ allocator unless we're sure we have to?
+ */
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ if (w) {
+ if((res = s_mp_pad(a, used + 1)) != MP_OKAY)
+ return res;
+
+ DIGIT(a, ix) = (mp_digit)w;
+ }
+#else
+ if (carry) {
+ if((res = s_mp_pad(a, used + 1)) != MP_OKAY)
+ return res;
+
+ DIGIT(a, used) = carry;
+ }
+#endif
+
+ return MP_OKAY;
+} /* end s_mp_add() */
+
+/* }}} */
+
+/* Compute c = |a| + |b| */ /* magnitude addition */
+mp_err s_mp_add_3arg(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_digit *pa, *pb, *pc;
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ mp_word w = 0;
+#else
+ mp_digit sum, carry = 0, d;
+#endif
+ mp_size ix;
+ mp_size used;
+ mp_err res;
+
+ MP_SIGN(c) = MP_SIGN(a);
+ if (MP_USED(a) < MP_USED(b)) {
+ const mp_int *xch = a;
+ a = b;
+ b = xch;
+ }
+
+ /* Make sure a has enough precision for the output value */
+ if (MP_OKAY != (res = s_mp_pad(c, MP_USED(a))))
+ return res;
+
+ /*
+ Add up all digits up to the precision of b. If b had initially
+ the same precision as a, or greater, we took care of it by the
+ exchange step above, so there is no problem. If b had initially
+ less precision, we'll have to make sure the carry out is duly
+ propagated upward among the higher-order digits of the sum.
+ */
+ pa = MP_DIGITS(a);
+ pb = MP_DIGITS(b);
+ pc = MP_DIGITS(c);
+ used = MP_USED(b);
+ for (ix = 0; ix < used; ix++) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ w = w + *pa++ + *pb++;
+ *pc++ = ACCUM(w);
+ w = CARRYOUT(w);
+#else
+ d = *pa++;
+ sum = d + *pb++;
+ d = (sum < d); /* detect overflow */
+ *pc++ = sum += carry;
+ carry = d + (sum < carry); /* detect overflow */
+#endif
+ }
+
+ /* If we run out of 'b' digits before we're actually done, make
+ sure the carries get propagated upward...
+ */
+ for (used = MP_USED(a); ix < used; ++ix) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ w = w + *pa++;
+ *pc++ = ACCUM(w);
+ w = CARRYOUT(w);
+#else
+ *pc++ = sum = carry + *pa++;
+ carry = (sum < carry);
+#endif
+ }
+
+ /* If there's an overall carry out, increase precision and include
+ it. We could have done this initially, but why touch the memory
+ allocator unless we're sure we have to?
+ */
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ if (w) {
+ if((res = s_mp_pad(c, used + 1)) != MP_OKAY)
+ return res;
+
+ DIGIT(c, used) = (mp_digit)w;
+ ++used;
+ }
+#else
+ if (carry) {
+ if((res = s_mp_pad(c, used + 1)) != MP_OKAY)
+ return res;
+
+ DIGIT(c, used) = carry;
+ ++used;
+ }
+#endif
+ MP_USED(c) = used;
+ return MP_OKAY;
+}
+/* {{{ s_mp_add_offset(a, b, offset) */
+
+/* Compute a = |a| + ( |b| * (RADIX ** offset) ) */
+mp_err s_mp_add_offset(mp_int *a, mp_int *b, mp_size offset)
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ mp_word w, k = 0;
+#else
+ mp_digit d, sum, carry = 0;
+#endif
+ mp_size ib;
+ mp_size ia;
+ mp_size lim;
+ mp_err res;
+
+ /* Make sure a has enough precision for the output value */
+ lim = MP_USED(b) + offset;
+ if((lim > USED(a)) && (res = s_mp_pad(a, lim)) != MP_OKAY)
+ return res;
+
+ /*
+ Add up all digits up to the precision of b. If b had initially
+ the same precision as a, or greater, we took care of it by the
+ padding step above, so there is no problem. If b had initially
+ less precision, we'll have to make sure the carry out is duly
+ propagated upward among the higher-order digits of the sum.
+ */
+ lim = USED(b);
+ for(ib = 0, ia = offset; ib < lim; ib++, ia++) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ w = (mp_word)DIGIT(a, ia) + DIGIT(b, ib) + k;
+ DIGIT(a, ia) = ACCUM(w);
+ k = CARRYOUT(w);
+#else
+ d = MP_DIGIT(a, ia);
+ sum = d + MP_DIGIT(b, ib);
+ d = (sum < d);
+ MP_DIGIT(a,ia) = sum += carry;
+ carry = d + (sum < carry);
+#endif
+ }
+
+ /* If we run out of 'b' digits before we're actually done, make
+ sure the carries get propagated upward...
+ */
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ for (lim = MP_USED(a); k && (ia < lim); ++ia) {
+ w = (mp_word)DIGIT(a, ia) + k;
+ DIGIT(a, ia) = ACCUM(w);
+ k = CARRYOUT(w);
+ }
+#else
+ for (lim = MP_USED(a); carry && (ia < lim); ++ia) {
+ d = MP_DIGIT(a, ia);
+ MP_DIGIT(a,ia) = sum = d + carry;
+ carry = (sum < d);
+ }
+#endif
+
+ /* If there's an overall carry out, increase precision and include
+ it. We could have done this initially, but why touch the memory
+ allocator unless we're sure we have to?
+ */
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD)
+ if(k) {
+ if((res = s_mp_pad(a, USED(a) + 1)) != MP_OKAY)
+ return res;
+
+ DIGIT(a, ia) = (mp_digit)k;
+ }
+#else
+ if (carry) {
+ if((res = s_mp_pad(a, lim + 1)) != MP_OKAY)
+ return res;
+
+ DIGIT(a, lim) = carry;
+ }
+#endif
+ s_mp_clamp(a);
+
+ return MP_OKAY;
+
+} /* end s_mp_add_offset() */
+
+/* }}} */
+
+/* {{{ s_mp_sub(a, b) */
+
+/* Compute a = |a| - |b|, assumes |a| >= |b| */
+mp_err s_mp_sub(mp_int *a, const mp_int *b) /* magnitude subtract */
+{
+ mp_digit *pa, *pb, *limit;
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+ mp_sword w = 0;
+#else
+ mp_digit d, diff, borrow = 0;
+#endif
+
+ /*
+ Subtract and propagate borrow. Up to the precision of b, this
+ accounts for the digits of b; after that, we just make sure the
+ carries get to the right place. This saves having to pad b out to
+ the precision of a just to make the loops work right...
+ */
+ pa = MP_DIGITS(a);
+ pb = MP_DIGITS(b);
+ limit = pb + MP_USED(b);
+ while (pb < limit) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+ w = w + *pa - *pb++;
+ *pa++ = ACCUM(w);
+ w >>= MP_DIGIT_BIT;
+#else
+ d = *pa;
+ diff = d - *pb++;
+ d = (diff > d); /* detect borrow */
+ if (borrow && --diff == MP_DIGIT_MAX)
+ ++d;
+ *pa++ = diff;
+ borrow = d;
+#endif
+ }
+ limit = MP_DIGITS(a) + MP_USED(a);
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+ while (w && pa < limit) {
+ w = w + *pa;
+ *pa++ = ACCUM(w);
+ w >>= MP_DIGIT_BIT;
+ }
+#else
+ while (borrow && pa < limit) {
+ d = *pa;
+ *pa++ = diff = d - borrow;
+ borrow = (diff > d);
+ }
+#endif
+
+ /* Clobber any leading zeroes we created */
+ s_mp_clamp(a);
+
+ /*
+ If there was a borrow out, then |b| > |a| in violation
+ of our input invariant. We've already done the work,
+ but we'll at least complain about it...
+ */
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+ return w ? MP_RANGE : MP_OKAY;
+#else
+ return borrow ? MP_RANGE : MP_OKAY;
+#endif
+} /* end s_mp_sub() */
+
+/* }}} */
+
+/* Compute c = |a| - |b|, assumes |a| >= |b| */ /* magnitude subtract */
+mp_err s_mp_sub_3arg(const mp_int *a, const mp_int *b, mp_int *c)
+{
+ mp_digit *pa, *pb, *pc;
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+ mp_sword w = 0;
+#else
+ mp_digit d, diff, borrow = 0;
+#endif
+ int ix, limit;
+ mp_err res;
+
+ MP_SIGN(c) = MP_SIGN(a);
+
+ /* Make sure a has enough precision for the output value */
+ if (MP_OKAY != (res = s_mp_pad(c, MP_USED(a))))
+ return res;
+
+ /*
+ Subtract and propagate borrow. Up to the precision of b, this
+ accounts for the digits of b; after that, we just make sure the
+ carries get to the right place. This saves having to pad b out to
+ the precision of a just to make the loops work right...
+ */
+ pa = MP_DIGITS(a);
+ pb = MP_DIGITS(b);
+ pc = MP_DIGITS(c);
+ limit = MP_USED(b);
+ for (ix = 0; ix < limit; ++ix) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+ w = w + *pa++ - *pb++;
+ *pc++ = ACCUM(w);
+ w >>= MP_DIGIT_BIT;
+#else
+ d = *pa++;
+ diff = d - *pb++;
+ d = (diff > d);
+ if (borrow && --diff == MP_DIGIT_MAX)
+ ++d;
+ *pc++ = diff;
+ borrow = d;
+#endif
+ }
+ for (limit = MP_USED(a); ix < limit; ++ix) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+ w = w + *pa++;
+ *pc++ = ACCUM(w);
+ w >>= MP_DIGIT_BIT;
+#else
+ d = *pa++;
+ *pc++ = diff = d - borrow;
+ borrow = (diff > d);
+#endif
+ }
+
+ /* Clobber any leading zeroes we created */
+ MP_USED(c) = ix;
+ s_mp_clamp(c);
+
+ /*
+ If there was a borrow out, then |b| > |a| in violation
+ of our input invariant. We've already done the work,
+ but we'll at least complain about it...
+ */
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_SUB_WORD)
+ return w ? MP_RANGE : MP_OKAY;
+#else
+ return borrow ? MP_RANGE : MP_OKAY;
+#endif
+}
+/* {{{ s_mp_mul(a, b) */
+
+/* Compute a = |a| * |b| */
+mp_err s_mp_mul(mp_int *a, const mp_int *b)
+{
+ return mp_mul(a, b, a);
+} /* end s_mp_mul() */
+
+/* }}} */
+
+#if defined(MP_USE_UINT_DIGIT) && defined(MP_USE_LONG_LONG_MULTIPLY)
+/* This trick works on Sparc V8 CPUs with the Workshop compilers. */
+#define MP_MUL_DxD(a, b, Phi, Plo) \
+ { unsigned long long product = (unsigned long long)a * b; \
+ Plo = (mp_digit)product; \
+ Phi = (mp_digit)(product >> MP_DIGIT_BIT); }
+#elif defined(OSF1)
+#define MP_MUL_DxD(a, b, Phi, Plo) \
+ { Plo = asm ("mulq %a0, %a1, %v0", a, b);\
+ Phi = asm ("umulh %a0, %a1, %v0", a, b); }
+#else
+#define MP_MUL_DxD(a, b, Phi, Plo) \
+ { mp_digit a0b1, a1b0; \
+ Plo = (a & MP_HALF_DIGIT_MAX) * (b & MP_HALF_DIGIT_MAX); \
+ Phi = (a >> MP_HALF_DIGIT_BIT) * (b >> MP_HALF_DIGIT_BIT); \
+ a0b1 = (a & MP_HALF_DIGIT_MAX) * (b >> MP_HALF_DIGIT_BIT); \
+ a1b0 = (a >> MP_HALF_DIGIT_BIT) * (b & MP_HALF_DIGIT_MAX); \
+ a1b0 += a0b1; \
+ Phi += a1b0 >> MP_HALF_DIGIT_BIT; \
+ if (a1b0 < a0b1) \
+ Phi += MP_HALF_RADIX; \
+ a1b0 <<= MP_HALF_DIGIT_BIT; \
+ Plo += a1b0; \
+ if (Plo < a1b0) \
+ ++Phi; \
+ }
+#endif
+
+#if !defined(MP_ASSEMBLY_MULTIPLY)
+/* c = a * b */
+void s_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
+ mp_digit d = 0;
+
+ /* Inner product: Digits of a */
+ while (a_len--) {
+ mp_word w = ((mp_word)b * *a++) + d;
+ *c++ = ACCUM(w);
+ d = CARRYOUT(w);
+ }
+ *c = d;
+#else
+ mp_digit carry = 0;
+ while (a_len--) {
+ mp_digit a_i = *a++;
+ mp_digit a0b0, a1b1;
+
+ MP_MUL_DxD(a_i, b, a1b1, a0b0);
+
+ a0b0 += carry;
+ if (a0b0 < carry)
+ ++a1b1;
+ *c++ = a0b0;
+ carry = a1b1;
+ }
+ *c = carry;
+#endif
+}
+
+/* c += a * b */
+void s_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b,
+ mp_digit *c)
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
+ mp_digit d = 0;
+
+ /* Inner product: Digits of a */
+ while (a_len--) {
+ mp_word w = ((mp_word)b * *a++) + *c + d;
+ *c++ = ACCUM(w);
+ d = CARRYOUT(w);
+ }
+ *c = d;
+#else
+ mp_digit carry = 0;
+ while (a_len--) {
+ mp_digit a_i = *a++;
+ mp_digit a0b0, a1b1;
+
+ MP_MUL_DxD(a_i, b, a1b1, a0b0);
+
+ a0b0 += carry;
+ if (a0b0 < carry)
+ ++a1b1;
+ a0b0 += a_i = *c;
+ if (a0b0 < a_i)
+ ++a1b1;
+ *c++ = a0b0;
+ carry = a1b1;
+ }
+ *c = carry;
+#endif
+}
+
+/* Presently, this is only used by the Montgomery arithmetic code. */
+/* c += a * b */
+void s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c)
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
+ mp_digit d = 0;
+
+ /* Inner product: Digits of a */
+ while (a_len--) {
+ mp_word w = ((mp_word)b * *a++) + *c + d;
+ *c++ = ACCUM(w);
+ d = CARRYOUT(w);
+ }
+
+ while (d) {
+ mp_word w = (mp_word)*c + d;
+ *c++ = ACCUM(w);
+ d = CARRYOUT(w);
+ }
+#else
+ mp_digit carry = 0;
+ while (a_len--) {
+ mp_digit a_i = *a++;
+ mp_digit a0b0, a1b1;
+
+ MP_MUL_DxD(a_i, b, a1b1, a0b0);
+
+ a0b0 += carry;
+ if (a0b0 < carry)
+ ++a1b1;
+
+ a0b0 += a_i = *c;
+ if (a0b0 < a_i)
+ ++a1b1;
+
+ *c++ = a0b0;
+ carry = a1b1;
+ }
+ while (carry) {
+ mp_digit c_i = *c;
+ carry += c_i;
+ *c++ = carry;
+ carry = carry < c_i;
+ }
+#endif
+}
+#endif
+
+#if defined(MP_USE_UINT_DIGIT) && defined(MP_USE_LONG_LONG_MULTIPLY)
+/* This trick works on Sparc V8 CPUs with the Workshop compilers. */
+#define MP_SQR_D(a, Phi, Plo) \
+ { unsigned long long square = (unsigned long long)a * a; \
+ Plo = (mp_digit)square; \
+ Phi = (mp_digit)(square >> MP_DIGIT_BIT); }
+#elif defined(OSF1)
+#define MP_SQR_D(a, Phi, Plo) \
+ { Plo = asm ("mulq %a0, %a0, %v0", a);\
+ Phi = asm ("umulh %a0, %a0, %v0", a); }
+#else
+#define MP_SQR_D(a, Phi, Plo) \
+ { mp_digit Pmid; \
+ Plo = (a & MP_HALF_DIGIT_MAX) * (a & MP_HALF_DIGIT_MAX); \
+ Phi = (a >> MP_HALF_DIGIT_BIT) * (a >> MP_HALF_DIGIT_BIT); \
+ Pmid = (a & MP_HALF_DIGIT_MAX) * (a >> MP_HALF_DIGIT_BIT); \
+ Phi += Pmid >> (MP_HALF_DIGIT_BIT - 1); \
+ Pmid <<= (MP_HALF_DIGIT_BIT + 1); \
+ Plo += Pmid; \
+ if (Plo < Pmid) \
+ ++Phi; \
+ }
+#endif
+
+#if !defined(MP_ASSEMBLY_SQUARE)
+/* Add the squares of the digits of a to the digits of b. */
+void s_mpv_sqr_add_prop(const mp_digit *pa, mp_size a_len, mp_digit *ps)
+{
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_MUL_WORD)
+ mp_word w;
+ mp_digit d;
+ mp_size ix;
+
+ w = 0;
+#define ADD_SQUARE(n) \
+ d = pa[n]; \
+ w += (d * (mp_word)d) + ps[2*n]; \
+ ps[2*n] = ACCUM(w); \
+ w = (w >> DIGIT_BIT) + ps[2*n+1]; \
+ ps[2*n+1] = ACCUM(w); \
+ w = (w >> DIGIT_BIT)
+
+ for (ix = a_len; ix >= 4; ix -= 4) {
+ ADD_SQUARE(0);
+ ADD_SQUARE(1);
+ ADD_SQUARE(2);
+ ADD_SQUARE(3);
+ pa += 4;
+ ps += 8;
+ }
+ if (ix) {
+ ps += 2*ix;
+ pa += ix;
+ switch (ix) {
+ case 3: ADD_SQUARE(-3); /* FALLTHRU */
+ case 2: ADD_SQUARE(-2); /* FALLTHRU */
+ case 1: ADD_SQUARE(-1); /* FALLTHRU */
+ case 0: break;
+ }
+ }
+ while (w) {
+ w += *ps;
+ *ps++ = ACCUM(w);
+ w = (w >> DIGIT_BIT);
+ }
+#else
+ mp_digit carry = 0;
+ while (a_len--) {
+ mp_digit a_i = *pa++;
+ mp_digit a0a0, a1a1;
+
+ MP_SQR_D(a_i, a1a1, a0a0);
+
+ /* here a1a1 and a0a0 constitute a_i ** 2 */
+ a0a0 += carry;
+ if (a0a0 < carry)
+ ++a1a1;
+
+ /* now add to ps */
+ a0a0 += a_i = *ps;
+ if (a0a0 < a_i)
+ ++a1a1;
+ *ps++ = a0a0;
+ a1a1 += a_i = *ps;
+ carry = (a1a1 < a_i);
+ *ps++ = a1a1;
+ }
+ while (carry) {
+ mp_digit s_i = *ps;
+ carry += s_i;
+ *ps++ = carry;
+ carry = carry < s_i;
+ }
+#endif
+}
+#endif
+
+#if (defined(MP_NO_MP_WORD) || defined(MP_NO_DIV_WORD)) \
+&& !defined(MP_ASSEMBLY_DIV_2DX1D)
+/*
+** Divide 64-bit (Nhi,Nlo) by 32-bit divisor, which must be normalized
+** so its high bit is 1. This code is from NSPR.
+*/
+mp_err s_mpv_div_2dx1d(mp_digit Nhi, mp_digit Nlo, mp_digit divisor,
+ mp_digit *qp, mp_digit *rp)
+{
+ mp_digit d1, d0, q1, q0;
+ mp_digit r1, r0, m;
+
+ d1 = divisor >> MP_HALF_DIGIT_BIT;
+ d0 = divisor & MP_HALF_DIGIT_MAX;
+ r1 = Nhi % d1;
+ q1 = Nhi / d1;
+ m = q1 * d0;
+ r1 = (r1 << MP_HALF_DIGIT_BIT) | (Nlo >> MP_HALF_DIGIT_BIT);
+ if (r1 < m) {
+ q1--, r1 += divisor;
+ if (r1 >= divisor && r1 < m) {
+ q1--, r1 += divisor;
+ }
+ }
+ r1 -= m;
+ r0 = r1 % d1;
+ q0 = r1 / d1;
+ m = q0 * d0;
+ r0 = (r0 << MP_HALF_DIGIT_BIT) | (Nlo & MP_HALF_DIGIT_MAX);
+ if (r0 < m) {
+ q0--, r0 += divisor;
+ if (r0 >= divisor && r0 < m) {
+ q0--, r0 += divisor;
+ }
+ }
+ if (qp)
+ *qp = (q1 << MP_HALF_DIGIT_BIT) | q0;
+ if (rp)
+ *rp = r0 - m;
+ return MP_OKAY;
+}
+#endif
+
+#if MP_SQUARE
+/* {{{ s_mp_sqr(a) */
+
+mp_err s_mp_sqr(mp_int *a)
+{
+ mp_err res;
+ mp_int tmp;
+ tmp.flag = (mp_sign)0;
+
+ if((res = mp_init_size(&tmp, 2 * USED(a), FLAG(a))) != MP_OKAY)
+ return res;
+ res = mp_sqr(a, &tmp);
+ if (res == MP_OKAY) {
+ s_mp_exch(&tmp, a);
+ }
+ mp_clear(&tmp);
+ return res;
+}
+
+/* }}} */
+#endif
+
+/* {{{ s_mp_div(a, b) */
+
+/*
+ s_mp_div(a, b)
+
+ Compute a = a / b and b = a mod b. Assumes b > a.
+ */
+
+mp_err s_mp_div(mp_int *rem, /* i: dividend, o: remainder */
+ mp_int *div, /* i: divisor */
+ mp_int *quot) /* i: 0; o: quotient */
+{
+ mp_int part, t;
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
+ mp_word q_msd;
+#else
+ mp_digit q_msd;
+#endif
+ mp_err res;
+ mp_digit d;
+ mp_digit div_msd;
+ int ix;
+
+ t.dp = (mp_digit *)NULL;
+
+ if(mp_cmp_z(div) == 0)
+ return MP_RANGE;
+
+ /* Shortcut if divisor is power of two */
+ if((ix = s_mp_ispow2(div)) >= 0) {
+ MP_CHECKOK( mp_copy(rem, quot) );
+ s_mp_div_2d(quot, (mp_digit)ix);
+ s_mp_mod_2d(rem, (mp_digit)ix);
+
+ return MP_OKAY;
+ }
+
+ DIGITS(&t) = 0;
+ MP_SIGN(rem) = ZPOS;
+ MP_SIGN(div) = ZPOS;
+
+ /* A working temporary for division */
+ MP_CHECKOK( mp_init_size(&t, MP_ALLOC(rem), FLAG(rem)));
+
+ /* Normalize to optimize guessing */
+ MP_CHECKOK( s_mp_norm(rem, div, &d) );
+
+ part = *rem;
+
+ /* Perform the division itself...woo! */
+ MP_USED(quot) = MP_ALLOC(quot);
+
+ /* Find a partial substring of rem which is at least div */
+ /* If we didn't find one, we're finished dividing */
+ while (MP_USED(rem) > MP_USED(div) || s_mp_cmp(rem, div) >= 0) {
+ int i;
+ int unusedRem;
+
+ unusedRem = MP_USED(rem) - MP_USED(div);
+ MP_DIGITS(&part) = MP_DIGITS(rem) + unusedRem;
+ MP_ALLOC(&part) = MP_ALLOC(rem) - unusedRem;
+ MP_USED(&part) = MP_USED(div);
+ if (s_mp_cmp(&part, div) < 0) {
+ -- unusedRem;
+#if MP_ARGCHK == 2
+ assert(unusedRem >= 0);
+#endif
+ -- MP_DIGITS(&part);
+ ++ MP_USED(&part);
+ ++ MP_ALLOC(&part);
+ }
+
+ /* Compute a guess for the next quotient digit */
+ q_msd = MP_DIGIT(&part, MP_USED(&part) - 1);
+ div_msd = MP_DIGIT(div, MP_USED(div) - 1);
+ if (q_msd >= div_msd) {
+ q_msd = 1;
+ } else if (MP_USED(&part) > 1) {
+#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_DIV_WORD)
+ q_msd = (q_msd << MP_DIGIT_BIT) | MP_DIGIT(&part, MP_USED(&part) - 2);
+ q_msd /= div_msd;
+ if (q_msd == RADIX)
+ --q_msd;
+#else
+ mp_digit r;
+ MP_CHECKOK( s_mpv_div_2dx1d(q_msd, MP_DIGIT(&part, MP_USED(&part) - 2),
+ div_msd, &q_msd, &r) );
+#endif
+ } else {
+ q_msd = 0;
+ }
+#if MP_ARGCHK == 2
+ assert(q_msd > 0); /* This case should never occur any more. */
+#endif
+ if (q_msd <= 0)
+ break;
+
+ /* See what that multiplies out to */
+ mp_copy(div, &t);
+ MP_CHECKOK( s_mp_mul_d(&t, (mp_digit)q_msd) );
+
+ /*
+ If it's too big, back it off. We should not have to do this
+ more than once, or, in rare cases, twice. Knuth describes a
+ method by which this could be reduced to a maximum of once, but
+ I didn't implement that here.
+ * When using s_mpv_div_2dx1d, we may have to do this 3 times.
+ */
+ for (i = 4; s_mp_cmp(&t, &part) > 0 && i > 0; --i) {
+ --q_msd;
+ s_mp_sub(&t, div); /* t -= div */
+ }
+ if (i < 0) {
+ res = MP_RANGE;
+ goto CLEANUP;
+ }
+
+ /* At this point, q_msd should be the right next digit */
+ MP_CHECKOK( s_mp_sub(&part, &t) ); /* part -= t */
+ s_mp_clamp(rem);
+
+ /*
+ Include the digit in the quotient. We allocated enough memory
+ for any quotient we could ever possibly get, so we should not
+ have to check for failures here
+ */
+ MP_DIGIT(quot, unusedRem) = (mp_digit)q_msd;
+ }
+
+ /* Denormalize remainder */
+ if (d) {
+ s_mp_div_2d(rem, d);
+ }
+
+ s_mp_clamp(quot);
+
+CLEANUP:
+ mp_clear(&t);
+
+ return res;
+
+} /* end s_mp_div() */
+
+
+/* }}} */
+
+/* {{{ s_mp_2expt(a, k) */
+
+mp_err s_mp_2expt(mp_int *a, mp_digit k)
+{
+ mp_err res;
+ mp_size dig, bit;
+
+ dig = k / DIGIT_BIT;
+ bit = k % DIGIT_BIT;
+
+ mp_zero(a);
+ if((res = s_mp_pad(a, dig + 1)) != MP_OKAY)
+ return res;
+
+ DIGIT(a, dig) |= ((mp_digit)1 << bit);
+
+ return MP_OKAY;
+
+} /* end s_mp_2expt() */
+
+/* }}} */
+
+/* {{{ s_mp_reduce(x, m, mu) */
+
+/*
+ Compute Barrett reduction, x (mod m), given a precomputed value for
+ mu = b^2k / m, where b = RADIX and k = #digits(m). This should be
+ faster than straight division, when many reductions by the same
+ value of m are required (such as in modular exponentiation). This
+ can nearly halve the time required to do modular exponentiation,
+ as compared to using the full integer divide to reduce.
+
+ This algorithm was derived from the _Handbook of Applied
+ Cryptography_ by Menezes, Oorschot and VanStone, Ch. 14,
+ pp. 603-604.
+ */
+
+mp_err s_mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu)
+{
+ mp_int q;
+ mp_err res;
+
+ if((res = mp_init_copy(&q, x)) != MP_OKAY)
+ return res;
+
+ s_mp_rshd(&q, USED(m) - 1); /* q1 = x / b^(k-1) */
+ s_mp_mul(&q, mu); /* q2 = q1 * mu */
+ s_mp_rshd(&q, USED(m) + 1); /* q3 = q2 / b^(k+1) */
+
+ /* x = x mod b^(k+1), quick (no division) */
+ s_mp_mod_2d(x, DIGIT_BIT * (USED(m) + 1));
+
+ /* q = q * m mod b^(k+1), quick (no division) */
+ s_mp_mul(&q, m);
+ s_mp_mod_2d(&q, DIGIT_BIT * (USED(m) + 1));
+
+ /* x = x - q */
+ if((res = mp_sub(x, &q, x)) != MP_OKAY)
+ goto CLEANUP;
+
+ /* If x < 0, add b^(k+1) to it */
+ if(mp_cmp_z(x) < 0) {
+ mp_set(&q, 1);
+ if((res = s_mp_lshd(&q, USED(m) + 1)) != MP_OKAY)
+ goto CLEANUP;
+ if((res = mp_add(x, &q, x)) != MP_OKAY)
+ goto CLEANUP;
+ }
+
+ /* Back off if it's too big */
+ while(mp_cmp(x, m) >= 0) {
+ if((res = s_mp_sub(x, m)) != MP_OKAY)
+ break;
+ }
+
+ CLEANUP:
+ mp_clear(&q);
+
+ return res;
+
+} /* end s_mp_reduce() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive comparisons */
+
+/* {{{ s_mp_cmp(a, b) */
+
+/* Compare |a| <=> |b|, return 0 if equal, <0 if a<b, >0 if a>b */
+int s_mp_cmp(const mp_int *a, const mp_int *b)
+{
+ mp_size used_a = MP_USED(a);
+ {
+ mp_size used_b = MP_USED(b);
+
+ if (used_a > used_b)
+ goto IS_GT;
+ if (used_a < used_b)
+ goto IS_LT;
+ }
+ {
+ mp_digit *pa, *pb;
+ mp_digit da = 0, db = 0;
+
+#define CMP_AB(n) if ((da = pa[n]) != (db = pb[n])) goto done
+
+ pa = MP_DIGITS(a) + used_a;
+ pb = MP_DIGITS(b) + used_a;
+ while (used_a >= 4) {
+ pa -= 4;
+ pb -= 4;
+ used_a -= 4;
+ CMP_AB(3);
+ CMP_AB(2);
+ CMP_AB(1);
+ CMP_AB(0);
+ }
+ while (used_a-- > 0 && ((da = *--pa) == (db = *--pb)))
+ /* do nothing */;
+done:
+ if (da > db)
+ goto IS_GT;
+ if (da < db)
+ goto IS_LT;
+ }
+ return MP_EQ;
+IS_LT:
+ return MP_LT;
+IS_GT:
+ return MP_GT;
+} /* end s_mp_cmp() */
+
+/* }}} */
+
+/* {{{ s_mp_cmp_d(a, d) */
+
+/* Compare |a| <=> d, return 0 if equal, <0 if a<d, >0 if a>d */
+int s_mp_cmp_d(const mp_int *a, mp_digit d)
+{
+ if(USED(a) > 1)
+ return MP_GT;
+
+ if(DIGIT(a, 0) < d)
+ return MP_LT;
+ else if(DIGIT(a, 0) > d)
+ return MP_GT;
+ else
+ return MP_EQ;
+
+} /* end s_mp_cmp_d() */
+
+/* }}} */
+
+/* {{{ s_mp_ispow2(v) */
+
+/*
+ Returns -1 if the value is not a power of two; otherwise, it returns
+ k such that v = 2^k, i.e. lg(v).
+ */
+int s_mp_ispow2(const mp_int *v)
+{
+ mp_digit d;
+ int extra = 0, ix;
+
+ ix = MP_USED(v) - 1;
+ d = MP_DIGIT(v, ix); /* most significant digit of v */
+
+ extra = s_mp_ispow2d(d);
+ if (extra < 0 || ix == 0)
+ return extra;
+
+ while (--ix >= 0) {
+ if (DIGIT(v, ix) != 0)
+ return -1; /* not a power of two */
+ extra += MP_DIGIT_BIT;
+ }
+
+ return extra;
+
+} /* end s_mp_ispow2() */
+
+/* }}} */
+
+/* {{{ s_mp_ispow2d(d) */
+
+int s_mp_ispow2d(mp_digit d)
+{
+ if ((d != 0) && ((d & (d-1)) == 0)) { /* d is a power of 2 */
+ int pow = 0;
+#if defined (MP_USE_UINT_DIGIT)
+ if (d & 0xffff0000U)
+ pow += 16;
+ if (d & 0xff00ff00U)
+ pow += 8;
+ if (d & 0xf0f0f0f0U)
+ pow += 4;
+ if (d & 0xccccccccU)
+ pow += 2;
+ if (d & 0xaaaaaaaaU)
+ pow += 1;
+#elif defined(MP_USE_LONG_LONG_DIGIT)
+ if (d & 0xffffffff00000000ULL)
+ pow += 32;
+ if (d & 0xffff0000ffff0000ULL)
+ pow += 16;
+ if (d & 0xff00ff00ff00ff00ULL)
+ pow += 8;
+ if (d & 0xf0f0f0f0f0f0f0f0ULL)
+ pow += 4;
+ if (d & 0xccccccccccccccccULL)
+ pow += 2;
+ if (d & 0xaaaaaaaaaaaaaaaaULL)
+ pow += 1;
+#elif defined(MP_USE_LONG_DIGIT)
+ if (d & 0xffffffff00000000UL)
+ pow += 32;
+ if (d & 0xffff0000ffff0000UL)
+ pow += 16;
+ if (d & 0xff00ff00ff00ff00UL)
+ pow += 8;
+ if (d & 0xf0f0f0f0f0f0f0f0UL)
+ pow += 4;
+ if (d & 0xccccccccccccccccUL)
+ pow += 2;
+ if (d & 0xaaaaaaaaaaaaaaaaUL)
+ pow += 1;
+#else
+#error "unknown type for mp_digit"
+#endif
+ return pow;
+ }
+ return -1;
+
+} /* end s_mp_ispow2d() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ Primitive I/O helpers */
+
+/* {{{ s_mp_tovalue(ch, r) */
+
+/*
+ Convert the given character to its digit value, in the given radix.
+ If the given character is not understood in the given radix, -1 is
+ returned. Otherwise the digit's numeric value is returned.
+
+ The results will be odd if you use a radix < 2 or > 62, you are
+ expected to know what you're up to.
+ */
+int s_mp_tovalue(char ch, int r)
+{
+ int val, xch;
+
+ if(r > 36)
+ xch = ch;
+ else
+ xch = toupper(ch);
+
+ if(isdigit(xch))
+ val = xch - '0';
+ else if(isupper(xch))
+ val = xch - 'A' + 10;
+ else if(islower(xch))
+ val = xch - 'a' + 36;
+ else if(xch == '+')
+ val = 62;
+ else if(xch == '/')
+ val = 63;
+ else
+ return -1;
+
+ if(val < 0 || val >= r)
+ return -1;
+
+ return val;
+
+} /* end s_mp_tovalue() */
+
+/* }}} */
+
+/* {{{ s_mp_todigit(val, r, low) */
+
+/*
+ Convert val to a radix-r digit, if possible. If val is out of range
+ for r, returns zero. Otherwise, returns an ASCII character denoting
+ the value in the given radix.
+
+ The results may be odd if you use a radix < 2 or > 64, you are
+ expected to know what you're doing.
+ */
+
+char s_mp_todigit(mp_digit val, int r, int low)
+{
+ char ch;
+
+ if(val >= (unsigned int)r)
+ return 0;
+
+ ch = s_dmap_1[val];
+
+ if(r <= 36 && low)
+ ch = tolower(ch);
+
+ return ch;
+
+} /* end s_mp_todigit() */
+
+/* }}} */
+
+/* {{{ s_mp_outlen(bits, radix) */
+
+/*
+ Return an estimate for how long a string is needed to hold a radix
+ r representation of a number with 'bits' significant bits, plus an
+ extra for a zero terminator (assuming C style strings here)
+ */
+int s_mp_outlen(int bits, int r)
+{
+ return (int)((double)bits * LOG_V_2(r) + 1.5) + 1;
+
+} /* end s_mp_outlen() */
+
+/* }}} */
+
+/* }}} */
+
+/* {{{ mp_read_unsigned_octets(mp, str, len) */
+/* mp_read_unsigned_octets(mp, str, len)
+ Read in a raw value (base 256) into the given mp_int
+ No sign bit, number is positive. Leading zeros ignored.
+ */
+
+mp_err
+mp_read_unsigned_octets(mp_int *mp, const unsigned char *str, mp_size len)
+{
+ int count;
+ mp_err res;
+ mp_digit d;
+
+ ARGCHK(mp != NULL && str != NULL && len > 0, MP_BADARG);
+
+ mp_zero(mp);
+
+ count = len % sizeof(mp_digit);
+ if (count) {
+ for (d = 0; count-- > 0; --len) {
+ d = (d << 8) | *str++;
+ }
+ MP_DIGIT(mp, 0) = d;
+ }
+
+ /* Read the rest of the digits */
+ for(; len > 0; len -= sizeof(mp_digit)) {
+ for (d = 0, count = sizeof(mp_digit); count > 0; --count) {
+ d = (d << 8) | *str++;
+ }
+ if (MP_EQ == mp_cmp_z(mp)) {
+ if (!d)
+ continue;
+ } else {
+ if((res = s_mp_lshd(mp, 1)) != MP_OKAY)
+ return res;
+ }
+ MP_DIGIT(mp, 0) = d;
+ }
+ return MP_OKAY;
+} /* end mp_read_unsigned_octets() */
+/* }}} */
+
+/* {{{ mp_unsigned_octet_size(mp) */
+int
+mp_unsigned_octet_size(const mp_int *mp)
+{
+ int bytes;
+ int ix;
+ mp_digit d = 0;
+
+ ARGCHK(mp != NULL, MP_BADARG);
+ ARGCHK(MP_ZPOS == SIGN(mp), MP_BADARG);
+
+ bytes = (USED(mp) * sizeof(mp_digit));
+
+ /* subtract leading zeros. */
+ /* Iterate over each digit... */
+ for(ix = USED(mp) - 1; ix >= 0; ix--) {
+ d = DIGIT(mp, ix);
+ if (d)
+ break;
+ bytes -= sizeof(d);
+ }
+ if (!bytes)
+ return 1;
+
+ /* Have MSD, check digit bytes, high order first */
+ for(ix = sizeof(mp_digit) - 1; ix >= 0; ix--) {
+ unsigned char x = (unsigned char)(d >> (ix * CHAR_BIT));
+ if (x)
+ break;
+ --bytes;
+ }
+ return bytes;
+} /* end mp_unsigned_octet_size() */
+/* }}} */
+
+/* {{{ mp_to_unsigned_octets(mp, str) */
+/* output a buffer of big endian octets no longer than specified. */
+mp_err
+mp_to_unsigned_octets(const mp_int *mp, unsigned char *str, mp_size maxlen)
+{
+ int ix, pos = 0;
+ unsigned int bytes;
+
+ ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
+
+ bytes = mp_unsigned_octet_size(mp);
+ ARGCHK(bytes <= maxlen, MP_BADARG);
+
+ /* Iterate over each digit... */
+ for(ix = USED(mp) - 1; ix >= 0; ix--) {
+ mp_digit d = DIGIT(mp, ix);
+ int jx;
+
+ /* Unpack digit bytes, high order first */
+ for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
+ unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
+ if (!pos && !x) /* suppress leading zeros */
+ continue;
+ str[pos++] = x;
+ }
+ }
+ if (!pos)
+ str[pos++] = 0;
+ return pos;
+} /* end mp_to_unsigned_octets() */
+/* }}} */
+
+/* {{{ mp_to_signed_octets(mp, str) */
+/* output a buffer of big endian octets no longer than specified. */
+mp_err
+mp_to_signed_octets(const mp_int *mp, unsigned char *str, mp_size maxlen)
+{
+ int ix, pos = 0;
+ unsigned int bytes;
+
+ ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
+
+ bytes = mp_unsigned_octet_size(mp);
+ ARGCHK(bytes <= maxlen, MP_BADARG);
+
+ /* Iterate over each digit... */
+ for(ix = USED(mp) - 1; ix >= 0; ix--) {
+ mp_digit d = DIGIT(mp, ix);
+ int jx;
+
+ /* Unpack digit bytes, high order first */
+ for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
+ unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
+ if (!pos) {
+ if (!x) /* suppress leading zeros */
+ continue;
+ if (x & 0x80) { /* add one leading zero to make output positive. */
+ ARGCHK(bytes + 1 <= maxlen, MP_BADARG);
+ if (bytes + 1 > maxlen)
+ return MP_BADARG;
+ str[pos++] = 0;
+ }
+ }
+ str[pos++] = x;
+ }
+ }
+ if (!pos)
+ str[pos++] = 0;
+ return pos;
+} /* end mp_to_signed_octets() */
+/* }}} */
+
+/* {{{ mp_to_fixlen_octets(mp, str) */
+/* output a buffer of big endian octets exactly as long as requested. */
+mp_err
+mp_to_fixlen_octets(const mp_int *mp, unsigned char *str, mp_size length)
+{
+ int ix, pos = 0;
+ unsigned int bytes;
+
+ ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG);
+
+ bytes = mp_unsigned_octet_size(mp);
+ ARGCHK(bytes <= length, MP_BADARG);
+
+ /* place any needed leading zeros */
+ for (;length > bytes; --length) {
+ *str++ = 0;
+ }
+
+ /* Iterate over each digit... */
+ for(ix = USED(mp) - 1; ix >= 0; ix--) {
+ mp_digit d = DIGIT(mp, ix);
+ int jx;
+
+ /* Unpack digit bytes, high order first */
+ for(jx = sizeof(mp_digit) - 1; jx >= 0; jx--) {
+ unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT));
+ if (!pos && !x) /* suppress leading zeros */
+ continue;
+ str[pos++] = x;
+ }
+ }
+ if (!pos)
+ str[pos++] = 0;
+ return MP_OKAY;
+} /* end mp_to_fixlen_octets() */
+/* }}} */
+
+
+/*------------------------------------------------------------------------*/
+/* HERE THERE BE DRAGONS */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/mpi.h b/jdk.crypto.ec/share/native/libsunec/impl/mpi.h
new file mode 100644
index 0000000..4a8eb2c
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/mpi.h
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Netscape Communications Corporation
+ *
+ *********************************************************************** */
+
+/* Arbitrary precision integer arithmetic library */
+
+#ifndef _MPI_H
+#define _MPI_H
+
+/* $Id: mpi.h,v 1.22 2004/04/27 23:04:36 gerv%gerv.net Exp $ */
+
+#include "mpi-config.h"
+
+#ifndef _WIN32
+#include <sys/param.h>
+#endif /* _WIN32 */
+
+#ifdef _KERNEL
+#include <sys/debug.h>
+#include <sys/systm.h>
+#define assert ASSERT
+#define labs(a) (a >= 0 ? a : -a)
+#define UCHAR_MAX 255
+#define memset(s, c, n) bzero(s, n)
+#define memcpy(a,b,c) bcopy((caddr_t)b, (caddr_t)a, c)
+/*
+ * Generic #define's to cover missing things in the kernel
+ */
+#ifndef isdigit
+#define isdigit(x) ((x) >= '0' && (x) <= '9')
+#endif
+#ifndef isupper
+#define isupper(x) (((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z'))
+#endif
+#ifndef islower
+#define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z'))
+#endif
+#ifndef isalpha
+#define isalpha(x) (isupper(x) || islower(x))
+#endif
+#ifndef toupper
+#define toupper(x) (islower(x) ? (x) - 'a' + 'A' : (x))
+#endif
+#ifndef tolower
+#define tolower(x) (isupper(x) ? (x) + 'a' - 'A' : (x))
+#endif
+#ifndef isspace
+#define isspace(x) (((x) == ' ') || ((x) == '\r') || ((x) == '\n') || \
+ ((x) == '\t') || ((x) == '\b'))
+#endif
+#endif /* _KERNEL */
+
+#if MP_DEBUG
+#undef MP_IOFUNC
+#define MP_IOFUNC 1
+#endif
+
+#if MP_IOFUNC
+#include <stdio.h>
+#include <ctype.h>
+#endif
+
+#ifndef _KERNEL
+#include <limits.h>
+#endif
+
+#if defined(BSDI)
+#undef ULLONG_MAX
+#endif
+
+#if defined( macintosh )
+#include <Types.h>
+#elif defined( _WIN32_WCE)
+/* #include <sys/types.h> What do we need here ?? */
+#else
+#include <sys/types.h>
+#endif
+
+#define MP_NEG 1
+#define MP_ZPOS 0
+
+#define MP_OKAY 0 /* no error, all is well */
+#define MP_YES 0 /* yes (boolean result) */
+#define MP_NO -1 /* no (boolean result) */
+#define MP_MEM -2 /* out of memory */
+#define MP_RANGE -3 /* argument out of range */
+#define MP_BADARG -4 /* invalid parameter */
+#define MP_UNDEF -5 /* answer is undefined */
+#define MP_LAST_CODE MP_UNDEF
+
+typedef unsigned int mp_sign;
+typedef unsigned int mp_size;
+typedef int mp_err;
+typedef int mp_flag;
+
+#define MP_32BIT_MAX 4294967295U
+
+#if !defined(ULONG_MAX)
+#error "ULONG_MAX not defined"
+#elif !defined(UINT_MAX)
+#error "UINT_MAX not defined"
+#elif !defined(USHRT_MAX)
+#error "USHRT_MAX not defined"
+#endif
+
+#if defined(ULONG_LONG_MAX) /* GCC, HPUX */
+#define MP_ULONG_LONG_MAX ULONG_LONG_MAX
+#elif defined(ULLONG_MAX) /* Solaris */
+#define MP_ULONG_LONG_MAX ULLONG_MAX
+/* MP_ULONG_LONG_MAX was defined to be ULLONG_MAX */
+#elif defined(ULONGLONG_MAX) /* IRIX, AIX */
+#define MP_ULONG_LONG_MAX ULONGLONG_MAX
+#endif
+
+/* We only use unsigned long for mp_digit iff long is more than 32 bits. */
+#if !defined(MP_USE_UINT_DIGIT) && ULONG_MAX > MP_32BIT_MAX
+typedef unsigned long mp_digit;
+#define MP_DIGIT_MAX ULONG_MAX
+#define MP_DIGIT_FMT "%016lX" /* printf() format for 1 digit */
+#define MP_HALF_DIGIT_MAX UINT_MAX
+#undef MP_NO_MP_WORD
+#define MP_NO_MP_WORD 1
+#undef MP_USE_LONG_DIGIT
+#define MP_USE_LONG_DIGIT 1
+#undef MP_USE_LONG_LONG_DIGIT
+
+#elif !defined(MP_USE_UINT_DIGIT) && defined(MP_ULONG_LONG_MAX)
+typedef unsigned long long mp_digit;
+#define MP_DIGIT_MAX MP_ULONG_LONG_MAX
+#define MP_DIGIT_FMT "%016llX" /* printf() format for 1 digit */
+#define MP_HALF_DIGIT_MAX UINT_MAX
+#undef MP_NO_MP_WORD
+#define MP_NO_MP_WORD 1
+#undef MP_USE_LONG_LONG_DIGIT
+#define MP_USE_LONG_LONG_DIGIT 1
+#undef MP_USE_LONG_DIGIT
+
+#else
+typedef unsigned int mp_digit;
+#define MP_DIGIT_MAX UINT_MAX
+#define MP_DIGIT_FMT "%08X" /* printf() format for 1 digit */
+#define MP_HALF_DIGIT_MAX USHRT_MAX
+#undef MP_USE_UINT_DIGIT
+#define MP_USE_UINT_DIGIT 1
+#undef MP_USE_LONG_LONG_DIGIT
+#undef MP_USE_LONG_DIGIT
+#endif
+
+#if !defined(MP_NO_MP_WORD)
+#if defined(MP_USE_UINT_DIGIT) && \
+ (defined(MP_ULONG_LONG_MAX) || (ULONG_MAX > UINT_MAX))
+
+#if (ULONG_MAX > UINT_MAX)
+typedef unsigned long mp_word;
+typedef long mp_sword;
+#define MP_WORD_MAX ULONG_MAX
+
+#else
+typedef unsigned long long mp_word;
+typedef long long mp_sword;
+#define MP_WORD_MAX MP_ULONG_LONG_MAX
+#endif
+
+#else
+#define MP_NO_MP_WORD 1
+#endif
+#endif /* !defined(MP_NO_MP_WORD) */
+
+#if !defined(MP_WORD_MAX) && defined(MP_DEFINE_SMALL_WORD)
+typedef unsigned int mp_word;
+typedef int mp_sword;
+#define MP_WORD_MAX UINT_MAX
+#endif
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#define MP_DIGIT_BIT (CHAR_BIT*sizeof(mp_digit))
+#define MP_WORD_BIT (CHAR_BIT*sizeof(mp_word))
+#define MP_RADIX (1+(mp_word)MP_DIGIT_MAX)
+
+#define MP_HALF_DIGIT_BIT (MP_DIGIT_BIT/2)
+#define MP_HALF_RADIX (1+(mp_digit)MP_HALF_DIGIT_MAX)
+/* MP_HALF_RADIX really ought to be called MP_SQRT_RADIX, but it's named
+** MP_HALF_RADIX because it's the radix for MP_HALF_DIGITs, and it's
+** consistent with the other _HALF_ names.
+*/
+
+
+/* Macros for accessing the mp_int internals */
+#define MP_FLAG(MP) ((MP)->flag)
+#define MP_SIGN(MP) ((MP)->sign)
+#define MP_USED(MP) ((MP)->used)
+#define MP_ALLOC(MP) ((MP)->alloc)
+#define MP_DIGITS(MP) ((MP)->dp)
+#define MP_DIGIT(MP,N) (MP)->dp[(N)]
+
+/* This defines the maximum I/O base (minimum is 2) */
+#define MP_MAX_RADIX 64
+
+typedef struct {
+ mp_sign flag; /* KM_SLEEP/KM_NOSLEEP */
+ mp_sign sign; /* sign of this quantity */
+ mp_size alloc; /* how many digits allocated */
+ mp_size used; /* how many digits used */
+ mp_digit *dp; /* the digits themselves */
+} mp_int;
+
+/* Default precision */
+mp_size mp_get_prec(void);
+void mp_set_prec(mp_size prec);
+
+/* Memory management */
+mp_err mp_init(mp_int *mp, int kmflag);
+mp_err mp_init_size(mp_int *mp, mp_size prec, int kmflag);
+mp_err mp_init_copy(mp_int *mp, const mp_int *from);
+mp_err mp_copy(const mp_int *from, mp_int *to);
+void mp_exch(mp_int *mp1, mp_int *mp2);
+void mp_clear(mp_int *mp);
+void mp_zero(mp_int *mp);
+void mp_set(mp_int *mp, mp_digit d);
+mp_err mp_set_int(mp_int *mp, long z);
+#define mp_set_long(mp,z) mp_set_int(mp,z)
+mp_err mp_set_ulong(mp_int *mp, unsigned long z);
+
+/* Single digit arithmetic */
+mp_err mp_add_d(const mp_int *a, mp_digit d, mp_int *b);
+mp_err mp_sub_d(const mp_int *a, mp_digit d, mp_int *b);
+mp_err mp_mul_d(const mp_int *a, mp_digit d, mp_int *b);
+mp_err mp_mul_2(const mp_int *a, mp_int *c);
+mp_err mp_div_d(const mp_int *a, mp_digit d, mp_int *q, mp_digit *r);
+mp_err mp_div_2(const mp_int *a, mp_int *c);
+mp_err mp_expt_d(const mp_int *a, mp_digit d, mp_int *c);
+
+/* Sign manipulations */
+mp_err mp_abs(const mp_int *a, mp_int *b);
+mp_err mp_neg(const mp_int *a, mp_int *b);
+
+/* Full arithmetic */
+mp_err mp_add(const mp_int *a, const mp_int *b, mp_int *c);
+mp_err mp_sub(const mp_int *a, const mp_int *b, mp_int *c);
+mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int *c);
+#if MP_SQUARE
+mp_err mp_sqr(const mp_int *a, mp_int *b);
+#else
+#define mp_sqr(a, b) mp_mul(a, a, b)
+#endif
+mp_err mp_div(const mp_int *a, const mp_int *b, mp_int *q, mp_int *r);
+mp_err mp_div_2d(const mp_int *a, mp_digit d, mp_int *q, mp_int *r);
+mp_err mp_expt(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_2expt(mp_int *a, mp_digit k);
+mp_err mp_sqrt(const mp_int *a, mp_int *b);
+
+/* Modular arithmetic */
+#if MP_MODARITH
+mp_err mp_mod(const mp_int *a, const mp_int *m, mp_int *c);
+mp_err mp_mod_d(const mp_int *a, mp_digit d, mp_digit *c);
+mp_err mp_addmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c);
+mp_err mp_submod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c);
+mp_err mp_mulmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c);
+#if MP_SQUARE
+mp_err mp_sqrmod(const mp_int *a, const mp_int *m, mp_int *c);
+#else
+#define mp_sqrmod(a, m, c) mp_mulmod(a, a, m, c)
+#endif
+mp_err mp_exptmod(const mp_int *a, const mp_int *b, const mp_int *m, mp_int *c);
+mp_err mp_exptmod_d(const mp_int *a, mp_digit d, const mp_int *m, mp_int *c);
+#endif /* MP_MODARITH */
+
+/* Comparisons */
+int mp_cmp_z(const mp_int *a);
+int mp_cmp_d(const mp_int *a, mp_digit d);
+int mp_cmp(const mp_int *a, const mp_int *b);
+int mp_cmp_mag(mp_int *a, mp_int *b);
+int mp_cmp_int(const mp_int *a, long z, int kmflag);
+int mp_isodd(const mp_int *a);
+int mp_iseven(const mp_int *a);
+
+/* Number theoretic */
+#if MP_NUMTH
+mp_err mp_gcd(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_lcm(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_xgcd(const mp_int *a, const mp_int *b, mp_int *g, mp_int *x, mp_int *y);
+mp_err mp_invmod(const mp_int *a, const mp_int *m, mp_int *c);
+mp_err mp_invmod_xgcd(const mp_int *a, const mp_int *m, mp_int *c);
+#endif /* end MP_NUMTH */
+
+/* Input and output */
+#if MP_IOFUNC
+void mp_print(mp_int *mp, FILE *ofp);
+#endif /* end MP_IOFUNC */
+
+/* Base conversion */
+mp_err mp_read_raw(mp_int *mp, char *str, int len);
+int mp_raw_size(mp_int *mp);
+mp_err mp_toraw(mp_int *mp, char *str);
+mp_err mp_read_radix(mp_int *mp, const char *str, int radix);
+mp_err mp_read_variable_radix(mp_int *a, const char * str, int default_radix);
+int mp_radix_size(mp_int *mp, int radix);
+mp_err mp_toradix(mp_int *mp, char *str, int radix);
+int mp_tovalue(char ch, int r);
+
+#define mp_tobinary(M, S) mp_toradix((M), (S), 2)
+#define mp_tooctal(M, S) mp_toradix((M), (S), 8)
+#define mp_todecimal(M, S) mp_toradix((M), (S), 10)
+#define mp_tohex(M, S) mp_toradix((M), (S), 16)
+
+/* Error strings */
+const char *mp_strerror(mp_err ec);
+
+/* Octet string conversion functions */
+mp_err mp_read_unsigned_octets(mp_int *mp, const unsigned char *str, mp_size len);
+int mp_unsigned_octet_size(const mp_int *mp);
+mp_err mp_to_unsigned_octets(const mp_int *mp, unsigned char *str, mp_size maxlen);
+mp_err mp_to_signed_octets(const mp_int *mp, unsigned char *str, mp_size maxlen);
+mp_err mp_to_fixlen_octets(const mp_int *mp, unsigned char *str, mp_size len);
+
+/* Miscellaneous */
+mp_size mp_trailing_zeros(const mp_int *mp);
+
+#define MP_CHECKOK(x) if (MP_OKAY > (res = (x))) goto CLEANUP
+#define MP_CHECKERR(x) if (MP_OKAY > (res = (x))) goto CLEANUP
+
+#if defined(MP_API_COMPATIBLE)
+#define NEG MP_NEG
+#define ZPOS MP_ZPOS
+#define DIGIT_MAX MP_DIGIT_MAX
+#define DIGIT_BIT MP_DIGIT_BIT
+#define DIGIT_FMT MP_DIGIT_FMT
+#define RADIX MP_RADIX
+#define MAX_RADIX MP_MAX_RADIX
+#define FLAG(MP) MP_FLAG(MP)
+#define SIGN(MP) MP_SIGN(MP)
+#define USED(MP) MP_USED(MP)
+#define ALLOC(MP) MP_ALLOC(MP)
+#define DIGITS(MP) MP_DIGITS(MP)
+#define DIGIT(MP,N) MP_DIGIT(MP,N)
+
+#if MP_ARGCHK == 1
+#define ARGCHK(X,Y) {if(!(X)){return (Y);}}
+#elif MP_ARGCHK == 2
+#ifdef _KERNEL
+#define ARGCHK(X,Y) ASSERT(X)
+#else
+#include <assert.h>
+#define ARGCHK(X,Y) assert(X)
+#endif
+#else
+#define ARGCHK(X,Y) /* */
+#endif
+#endif /* defined MP_API_COMPATIBLE */
+
+#endif /* _MPI_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/mplogic.c b/jdk.crypto.ec/share/native/libsunec/impl/mplogic.c
new file mode 100644
index 0000000..ba44086
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/mplogic.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ *********************************************************************** */
+
+/* Bitwise logical operations on MPI values */
+
+#include "mpi-priv.h"
+#include "mplogic.h"
+
+/* {{{ Lookup table for population count */
+
+static unsigned char bitc[] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+/* }}} */
+
+/*
+ mpl_rsh(a, b, d) - b = a >> d
+ mpl_lsh(a, b, d) - b = a << d
+ */
+
+/* {{{ mpl_rsh(a, b, d) */
+
+mp_err mpl_rsh(const mp_int *a, mp_int *b, mp_digit d)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if((res = mp_copy(a, b)) != MP_OKAY)
+ return res;
+
+ s_mp_div_2d(b, d);
+
+ return MP_OKAY;
+
+} /* end mpl_rsh() */
+
+/* }}} */
+
+/* {{{ mpl_lsh(a, b, d) */
+
+mp_err mpl_lsh(const mp_int *a, mp_int *b, mp_digit d)
+{
+ mp_err res;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if((res = mp_copy(a, b)) != MP_OKAY)
+ return res;
+
+ return s_mp_mul_2d(b, d);
+
+} /* end mpl_lsh() */
+
+/* }}} */
+
+/*------------------------------------------------------------------------*/
+/*
+ mpl_set_bit
+
+ Returns MP_OKAY or some error code.
+ Grows a if needed to set a bit to 1.
+ */
+mp_err mpl_set_bit(mp_int *a, mp_size bitNum, mp_size value)
+{
+ mp_size ix;
+ mp_err rv;
+ mp_digit mask;
+
+ ARGCHK(a != NULL, MP_BADARG);
+
+ ix = bitNum / MP_DIGIT_BIT;
+ if (ix + 1 > MP_USED(a)) {
+ rv = s_mp_pad(a, ix + 1);
+ if (rv != MP_OKAY)
+ return rv;
+ }
+
+ bitNum = bitNum % MP_DIGIT_BIT;
+ mask = (mp_digit)1 << bitNum;
+ if (value)
+ MP_DIGIT(a,ix) |= mask;
+ else
+ MP_DIGIT(a,ix) &= ~mask;
+ s_mp_clamp(a);
+ return MP_OKAY;
+}
+
+/*
+ mpl_get_bit
+
+ returns 0 or 1 or some (negative) error code.
+ */
+mp_err mpl_get_bit(const mp_int *a, mp_size bitNum)
+{
+ mp_size bit, ix;
+ mp_err rv;
+
+ ARGCHK(a != NULL, MP_BADARG);
+
+ ix = bitNum / MP_DIGIT_BIT;
+ ARGCHK(ix <= MP_USED(a) - 1, MP_RANGE);
+
+ bit = bitNum % MP_DIGIT_BIT;
+ rv = (mp_err)(MP_DIGIT(a, ix) >> bit) & 1;
+ return rv;
+}
+
+/*
+ mpl_get_bits
+ - Extracts numBits bits from a, where the least significant extracted bit
+ is bit lsbNum. Returns a negative value if error occurs.
+ - Because sign bit is used to indicate error, maximum number of bits to
+ be returned is the lesser of (a) the number of bits in an mp_digit, or
+ (b) one less than the number of bits in an mp_err.
+ - lsbNum + numbits can be greater than the number of significant bits in
+ integer a, as long as bit lsbNum is in the high order digit of a.
+ */
+mp_err mpl_get_bits(const mp_int *a, mp_size lsbNum, mp_size numBits)
+{
+ mp_size rshift = (lsbNum % MP_DIGIT_BIT);
+ mp_size lsWndx = (lsbNum / MP_DIGIT_BIT);
+ mp_digit * digit = MP_DIGITS(a) + lsWndx;
+ mp_digit mask = ((1 << numBits) - 1);
+
+ ARGCHK(numBits < CHAR_BIT * sizeof mask, MP_BADARG);
+ ARGCHK(MP_HOWMANY(lsbNum, MP_DIGIT_BIT) <= MP_USED(a), MP_RANGE);
+
+ if ((numBits + lsbNum % MP_DIGIT_BIT <= MP_DIGIT_BIT) ||
+ (lsWndx + 1 >= MP_USED(a))) {
+ mask &= (digit[0] >> rshift);
+ } else {
+ mask &= ((digit[0] >> rshift) | (digit[1] << (MP_DIGIT_BIT - rshift)));
+ }
+ return (mp_err)mask;
+}
+
+/*
+ mpl_significant_bits
+ returns number of significnant bits in abs(a).
+ returns 1 if value is zero.
+ */
+mp_err mpl_significant_bits(const mp_int *a)
+{
+ mp_err bits = 0;
+ int ix;
+
+ ARGCHK(a != NULL, MP_BADARG);
+
+ ix = MP_USED(a);
+ for (ix = MP_USED(a); ix > 0; ) {
+ mp_digit d;
+ d = MP_DIGIT(a, --ix);
+ if (d) {
+ while (d) {
+ ++bits;
+ d >>= 1;
+ }
+ break;
+ }
+ }
+ bits += ix * MP_DIGIT_BIT;
+ if (!bits)
+ bits = 1;
+ return bits;
+}
+
+/*------------------------------------------------------------------------*/
+/* HERE THERE BE DRAGONS */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/mplogic.h b/jdk.crypto.ec/share/native/libsunec/impl/mplogic.h
new file mode 100644
index 0000000..fda4f32
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/mplogic.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ *********************************************************************** */
+
+/* Bitwise logical operations on MPI values */
+
+#ifndef _MPLOGIC_H
+#define _MPLOGIC_H
+
+/* $Id: mplogic.h,v 1.7 2004/04/27 23:04:36 gerv%gerv.net Exp $ */
+
+#include "mpi.h"
+
+/*
+ The logical operations treat an mp_int as if it were a bit vector,
+ without regard to its sign (an mp_int is represented in a signed
+ magnitude format). Values are treated as if they had an infinite
+ string of zeros left of the most-significant bit.
+ */
+
+/* Parity results */
+
+#define MP_EVEN MP_YES
+#define MP_ODD MP_NO
+
+/* Bitwise functions */
+
+mp_err mpl_not(mp_int *a, mp_int *b); /* one's complement */
+mp_err mpl_and(mp_int *a, mp_int *b, mp_int *c); /* bitwise AND */
+mp_err mpl_or(mp_int *a, mp_int *b, mp_int *c); /* bitwise OR */
+mp_err mpl_xor(mp_int *a, mp_int *b, mp_int *c); /* bitwise XOR */
+
+/* Shift functions */
+
+mp_err mpl_rsh(const mp_int *a, mp_int *b, mp_digit d); /* right shift */
+mp_err mpl_lsh(const mp_int *a, mp_int *b, mp_digit d); /* left shift */
+
+/* Bit count and parity */
+
+mp_err mpl_num_set(mp_int *a, int *num); /* count set bits */
+mp_err mpl_num_clear(mp_int *a, int *num); /* count clear bits */
+mp_err mpl_parity(mp_int *a); /* determine parity */
+
+/* Get & Set the value of a bit */
+
+mp_err mpl_set_bit(mp_int *a, mp_size bitNum, mp_size value);
+mp_err mpl_get_bit(const mp_int *a, mp_size bitNum);
+mp_err mpl_get_bits(const mp_int *a, mp_size lsbNum, mp_size numBits);
+mp_err mpl_significant_bits(const mp_int *a);
+
+#endif /* _MPLOGIC_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/mpmontg.c b/jdk.crypto.ec/share/native/libsunec/impl/mpmontg.c
new file mode 100644
index 0000000..4c848a3
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/mpmontg.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sheueling Chang Shantz <sheueling.chang@sun.com>,
+ * Stephen Fung <stephen.fung@sun.com>, and
+ * Douglas Stebila <douglas@stebila.ca> of Sun Laboratories.
+ *
+ *********************************************************************** */
+
+/* This file implements moduluar exponentiation using Montgomery's
+ * method for modular reduction. This file implements the method
+ * described as "Improvement 1" in the paper "A Cryptogrpahic Library for
+ * the Motorola DSP56000" by Stephen R. Dusse' and Burton S. Kaliski Jr.
+ * published in "Advances in Cryptology: Proceedings of EUROCRYPT '90"
+ * "Lecture Notes in Computer Science" volume 473, 1991, pg 230-244,
+ * published by Springer Verlag.
+ */
+
+#define MP_USING_CACHE_SAFE_MOD_EXP 1
+#ifndef _KERNEL
+#include <string.h>
+#include <stddef.h> /* ptrdiff_t */
+#endif
+#include "mpi-priv.h"
+#include "mplogic.h"
+#include "mpprime.h"
+#ifdef MP_USING_MONT_MULF
+#include "montmulf.h"
+#endif
+
+/* if MP_CHAR_STORE_SLOW is defined, we */
+/* need to know endianness of this platform. */
+#ifdef MP_CHAR_STORE_SLOW
+#if !defined(MP_IS_BIG_ENDIAN) && !defined(MP_IS_LITTLE_ENDIAN)
+#error "You must define MP_IS_BIG_ENDIAN or MP_IS_LITTLE_ENDIAN\n" \
+ " if you define MP_CHAR_STORE_SLOW."
+#endif
+#endif
+
+#ifndef STATIC
+#define STATIC
+#endif
+
+#define MAX_ODD_INTS 32 /* 2 ** (WINDOW_BITS - 1) */
+
+#ifndef _KERNEL
+#if defined(_WIN32_WCE)
+#define ABORT res = MP_UNDEF; goto CLEANUP
+#else
+#define ABORT abort()
+#endif
+#else
+#define ABORT res = MP_UNDEF; goto CLEANUP
+#endif /* _KERNEL */
+
+/* computes T = REDC(T), 2^b == R */
+mp_err s_mp_redc(mp_int *T, mp_mont_modulus *mmm)
+{
+ mp_err res;
+ mp_size i;
+
+ i = MP_USED(T) + MP_USED(&mmm->N) + 2;
+ MP_CHECKOK( s_mp_pad(T, i) );
+ for (i = 0; i < MP_USED(&mmm->N); ++i ) {
+ mp_digit m_i = MP_DIGIT(T, i) * mmm->n0prime;
+ /* T += N * m_i * (MP_RADIX ** i); */
+ MP_CHECKOK( s_mp_mul_d_add_offset(&mmm->N, m_i, T, i) );
+ }
+ s_mp_clamp(T);
+
+ /* T /= R */
+ s_mp_div_2d(T, mmm->b);
+
+ if ((res = s_mp_cmp(T, &mmm->N)) >= 0) {
+ /* T = T - N */
+ MP_CHECKOK( s_mp_sub(T, &mmm->N) );
+#ifdef DEBUG
+ if ((res = mp_cmp(T, &mmm->N)) >= 0) {
+ res = MP_UNDEF;
+ goto CLEANUP;
+ }
+#endif
+ }
+ res = MP_OKAY;
+CLEANUP:
+ return res;
+}
+
+#if !defined(MP_ASSEMBLY_MUL_MONT) && !defined(MP_MONT_USE_MP_MUL)
+mp_err s_mp_mul_mont(const mp_int *a, const mp_int *b, mp_int *c,
+ mp_mont_modulus *mmm)
+{
+ mp_digit *pb;
+ mp_digit m_i;
+ mp_err res;
+ mp_size ib;
+ mp_size useda, usedb;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if (MP_USED(a) < MP_USED(b)) {
+ const mp_int *xch = b; /* switch a and b, to do fewer outer loops */
+ b = a;
+ a = xch;
+ }
+
+ MP_USED(c) = 1; MP_DIGIT(c, 0) = 0;
+ ib = MP_USED(a) + MP_MAX(MP_USED(b), MP_USED(&mmm->N)) + 2;
+ if((res = s_mp_pad(c, ib)) != MP_OKAY)
+ goto CLEANUP;
+
+ useda = MP_USED(a);
+ pb = MP_DIGITS(b);
+ s_mpv_mul_d(MP_DIGITS(a), useda, *pb++, MP_DIGITS(c));
+ s_mp_setz(MP_DIGITS(c) + useda + 1, ib - (useda + 1));
+ m_i = MP_DIGIT(c, 0) * mmm->n0prime;
+ s_mp_mul_d_add_offset(&mmm->N, m_i, c, 0);
+
+ /* Outer loop: Digits of b */
+ usedb = MP_USED(b);
+ for (ib = 1; ib < usedb; ib++) {
+ mp_digit b_i = *pb++;
+
+ /* Inner product: Digits of a */
+ if (b_i)
+ s_mpv_mul_d_add_prop(MP_DIGITS(a), useda, b_i, MP_DIGITS(c) + ib);
+ m_i = MP_DIGIT(c, ib) * mmm->n0prime;
+ s_mp_mul_d_add_offset(&mmm->N, m_i, c, ib);
+ }
+ if (usedb < MP_USED(&mmm->N)) {
+ for (usedb = MP_USED(&mmm->N); ib < usedb; ++ib ) {
+ m_i = MP_DIGIT(c, ib) * mmm->n0prime;
+ s_mp_mul_d_add_offset(&mmm->N, m_i, c, ib);
+ }
+ }
+ s_mp_clamp(c);
+ s_mp_div_2d(c, mmm->b);
+ if (s_mp_cmp(c, &mmm->N) >= 0) {
+ MP_CHECKOK( s_mp_sub(c, &mmm->N) );
+ }
+ res = MP_OKAY;
+
+CLEANUP:
+ return res;
+}
+#endif
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/mpprime.h b/jdk.crypto.ec/share/native/libsunec/impl/mpprime.h
new file mode 100644
index 0000000..d4cea94
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/mpprime.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the MPI Arbitrary Precision Integer Arithmetic library.
+ *
+ * The Initial Developer of the Original Code is
+ * Michael J. Fromberger.
+ * Portions created by the Initial Developer are Copyright (C) 1997
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ *********************************************************************** */
+
+/* Utilities for finding and working with prime and pseudo-prime integers */
+
+#ifndef _MP_PRIME_H
+#define _MP_PRIME_H
+
+#include "mpi.h"
+
+extern const int prime_tab_size; /* number of primes available */
+extern const mp_digit prime_tab[];
+
+/* Tests for divisibility */
+mp_err mpp_divis(mp_int *a, mp_int *b);
+mp_err mpp_divis_d(mp_int *a, mp_digit d);
+
+/* Random selection */
+mp_err mpp_random(mp_int *a);
+mp_err mpp_random_size(mp_int *a, mp_size prec);
+
+/* Pseudo-primality testing */
+mp_err mpp_divis_vector(mp_int *a, const mp_digit *vec, int size, int *which);
+mp_err mpp_divis_primes(mp_int *a, mp_digit *np);
+mp_err mpp_fermat(mp_int *a, mp_digit w);
+mp_err mpp_fermat_list(mp_int *a, const mp_digit *primes, mp_size nPrimes);
+mp_err mpp_pprime(mp_int *a, int nt);
+mp_err mpp_sieve(mp_int *trial, const mp_digit *primes, mp_size nPrimes,
+ unsigned char *sieve, mp_size nSieve);
+mp_err mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong,
+ unsigned long * nTries);
+
+#endif /* _MP_PRIME_H */
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/oid.c b/jdk.crypto.ec/share/native/libsunec/impl/oid.c
new file mode 100644
index 0000000..3d899dc
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/oid.c
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * Last Modified Date from the Original Code: March 2012
+ *********************************************************************** */
+
+#include <sys/types.h>
+
+#ifndef _WIN32
+#if !defined(__linux__) && !defined(_ALLBSD_SOURCE)
+#include <sys/systm.h>
+#endif /* __linux__ || _ALLBSD_SOURCE */
+#include <sys/param.h>
+#endif /* _WIN32 */
+
+#ifdef _KERNEL
+#include <sys/kmem.h>
+#else
+#include <string.h>
+#endif
+#include "ec.h"
+#include "ecl-curve.h"
+#include "ecc_impl.h"
+#include "secoidt.h"
+
+#define CERTICOM_OID 0x2b, 0x81, 0x04
+#define SECG_OID CERTICOM_OID, 0x00
+
+#define ANSI_X962_OID 0x2a, 0x86, 0x48, 0xce, 0x3d
+#define ANSI_X962_CURVE_OID ANSI_X962_OID, 0x03
+#define ANSI_X962_GF2m_OID ANSI_X962_CURVE_OID, 0x00
+#define ANSI_X962_GFp_OID ANSI_X962_CURVE_OID, 0x01
+
+#define TELETRUST_ALGO_OID 0x2b, 0x24, 0x03
+#define ECC_BRAINPOOL TELETRUST_ALGO_OID, 0x03, 0x02, 0x08
+#define ECC_BRAINPOOL_EC_V1 ECC_BRAINPOOL, 0x01, 0x01
+
+#define CONST_OID static const unsigned char
+
+/* ANSI X9.62 prime curve OIDs */
+/* NOTE: prime192v1 is the same as secp192r1, prime256v1 is the
+ * same as secp256r1
+ */
+CONST_OID ansiX962prime192v1[] = { ANSI_X962_GFp_OID, 0x01 };
+CONST_OID ansiX962prime192v2[] = { ANSI_X962_GFp_OID, 0x02 };
+CONST_OID ansiX962prime192v3[] = { ANSI_X962_GFp_OID, 0x03 };
+CONST_OID ansiX962prime239v1[] = { ANSI_X962_GFp_OID, 0x04 };
+CONST_OID ansiX962prime239v2[] = { ANSI_X962_GFp_OID, 0x05 };
+CONST_OID ansiX962prime239v3[] = { ANSI_X962_GFp_OID, 0x06 };
+CONST_OID ansiX962prime256v1[] = { ANSI_X962_GFp_OID, 0x07 };
+
+/* SECG prime curve OIDs */
+CONST_OID secgECsecp112r1[] = { SECG_OID, 0x06 };
+CONST_OID secgECsecp112r2[] = { SECG_OID, 0x07 };
+CONST_OID secgECsecp128r1[] = { SECG_OID, 0x1c };
+CONST_OID secgECsecp128r2[] = { SECG_OID, 0x1d };
+CONST_OID secgECsecp160k1[] = { SECG_OID, 0x09 };
+CONST_OID secgECsecp160r1[] = { SECG_OID, 0x08 };
+CONST_OID secgECsecp160r2[] = { SECG_OID, 0x1e };
+CONST_OID secgECsecp192k1[] = { SECG_OID, 0x1f };
+CONST_OID secgECsecp224k1[] = { SECG_OID, 0x20 };
+CONST_OID secgECsecp224r1[] = { SECG_OID, 0x21 };
+CONST_OID secgECsecp256k1[] = { SECG_OID, 0x0a };
+CONST_OID secgECsecp384r1[] = { SECG_OID, 0x22 };
+CONST_OID secgECsecp521r1[] = { SECG_OID, 0x23 };
+
+/* SECG characterisitic two curve OIDs */
+CONST_OID secgECsect113r1[] = {SECG_OID, 0x04 };
+CONST_OID secgECsect113r2[] = {SECG_OID, 0x05 };
+CONST_OID secgECsect131r1[] = {SECG_OID, 0x16 };
+CONST_OID secgECsect131r2[] = {SECG_OID, 0x17 };
+CONST_OID secgECsect163k1[] = {SECG_OID, 0x01 };
+CONST_OID secgECsect163r1[] = {SECG_OID, 0x02 };
+CONST_OID secgECsect163r2[] = {SECG_OID, 0x0f };
+CONST_OID secgECsect193r1[] = {SECG_OID, 0x18 };
+CONST_OID secgECsect193r2[] = {SECG_OID, 0x19 };
+CONST_OID secgECsect233k1[] = {SECG_OID, 0x1a };
+CONST_OID secgECsect233r1[] = {SECG_OID, 0x1b };
+CONST_OID secgECsect239k1[] = {SECG_OID, 0x03 };
+CONST_OID secgECsect283k1[] = {SECG_OID, 0x10 };
+CONST_OID secgECsect283r1[] = {SECG_OID, 0x11 };
+CONST_OID secgECsect409k1[] = {SECG_OID, 0x24 };
+CONST_OID secgECsect409r1[] = {SECG_OID, 0x25 };
+CONST_OID secgECsect571k1[] = {SECG_OID, 0x26 };
+CONST_OID secgECsect571r1[] = {SECG_OID, 0x27 };
+
+/* ANSI X9.62 characteristic two curve OIDs */
+CONST_OID ansiX962c2pnb163v1[] = { ANSI_X962_GF2m_OID, 0x01 };
+CONST_OID ansiX962c2pnb163v2[] = { ANSI_X962_GF2m_OID, 0x02 };
+CONST_OID ansiX962c2pnb163v3[] = { ANSI_X962_GF2m_OID, 0x03 };
+CONST_OID ansiX962c2pnb176v1[] = { ANSI_X962_GF2m_OID, 0x04 };
+CONST_OID ansiX962c2tnb191v1[] = { ANSI_X962_GF2m_OID, 0x05 };
+CONST_OID ansiX962c2tnb191v2[] = { ANSI_X962_GF2m_OID, 0x06 };
+CONST_OID ansiX962c2tnb191v3[] = { ANSI_X962_GF2m_OID, 0x07 };
+CONST_OID ansiX962c2onb191v4[] = { ANSI_X962_GF2m_OID, 0x08 };
+CONST_OID ansiX962c2onb191v5[] = { ANSI_X962_GF2m_OID, 0x09 };
+CONST_OID ansiX962c2pnb208w1[] = { ANSI_X962_GF2m_OID, 0x0a };
+CONST_OID ansiX962c2tnb239v1[] = { ANSI_X962_GF2m_OID, 0x0b };
+CONST_OID ansiX962c2tnb239v2[] = { ANSI_X962_GF2m_OID, 0x0c };
+CONST_OID ansiX962c2tnb239v3[] = { ANSI_X962_GF2m_OID, 0x0d };
+CONST_OID ansiX962c2onb239v4[] = { ANSI_X962_GF2m_OID, 0x0e };
+CONST_OID ansiX962c2onb239v5[] = { ANSI_X962_GF2m_OID, 0x0f };
+CONST_OID ansiX962c2pnb272w1[] = { ANSI_X962_GF2m_OID, 0x10 };
+CONST_OID ansiX962c2pnb304w1[] = { ANSI_X962_GF2m_OID, 0x11 };
+CONST_OID ansiX962c2tnb359v1[] = { ANSI_X962_GF2m_OID, 0x12 };
+CONST_OID ansiX962c2pnb368w1[] = { ANSI_X962_GF2m_OID, 0x13 };
+CONST_OID ansiX962c2tnb431r1[] = { ANSI_X962_GF2m_OID, 0x14 };
+
+/* TeleTrusT ECC Brainpool prime curve OIDs */
+CONST_OID brainpoolP160r1[] = { ECC_BRAINPOOL_EC_V1, 0x01 };
+CONST_OID brainpoolP160t1[] = { ECC_BRAINPOOL_EC_V1, 0x02 };
+CONST_OID brainpoolP192r1[] = { ECC_BRAINPOOL_EC_V1, 0x03 };
+CONST_OID brainpoolP192t1[] = { ECC_BRAINPOOL_EC_V1, 0x04 };
+CONST_OID brainpoolP224r1[] = { ECC_BRAINPOOL_EC_V1, 0x05 };
+CONST_OID brainpoolP224t1[] = { ECC_BRAINPOOL_EC_V1, 0x06 };
+CONST_OID brainpoolP256r1[] = { ECC_BRAINPOOL_EC_V1, 0x07 };
+CONST_OID brainpoolP256t1[] = { ECC_BRAINPOOL_EC_V1, 0x08 };
+CONST_OID brainpoolP320r1[] = { ECC_BRAINPOOL_EC_V1, 0x09 };
+CONST_OID brainpoolP320t1[] = { ECC_BRAINPOOL_EC_V1, 0x0a };
+CONST_OID brainpoolP384r1[] = { ECC_BRAINPOOL_EC_V1, 0x0b };
+CONST_OID brainpoolP384t1[] = { ECC_BRAINPOOL_EC_V1, 0x0c };
+CONST_OID brainpoolP512r1[] = { ECC_BRAINPOOL_EC_V1, 0x0d };
+CONST_OID brainpoolP512t1[] = { ECC_BRAINPOOL_EC_V1, 0x0e };
+
+#define OI(x) { siDEROID, (unsigned char *)x, sizeof x }
+#ifndef SECOID_NO_STRINGS
+#define OD(oid,tag,desc,mech,ext) { OI(oid), tag, desc, mech, ext }
+#else
+#define OD(oid,tag,desc,mech,ext) { OI(oid), tag, 0, mech, ext }
+#endif
+
+#define CKM_INVALID_MECHANISM 0xffffffffUL
+
+/* XXX this is incorrect */
+#define INVALID_CERT_EXTENSION 1
+
+#define CKM_ECDSA 0x00001041
+#define CKM_ECDSA_SHA1 0x00001042
+#define CKM_ECDH1_DERIVE 0x00001050
+
+static SECOidData ANSI_prime_oids[] = {
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+
+ OD( ansiX962prime192v1, ECCurve_NIST_P192,
+ "ANSI X9.62 elliptic curve prime192v1 (aka secp192r1, NIST P-192)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime192v2, ECCurve_X9_62_PRIME_192V2,
+ "ANSI X9.62 elliptic curve prime192v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime192v3, ECCurve_X9_62_PRIME_192V3,
+ "ANSI X9.62 elliptic curve prime192v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime239v1, ECCurve_X9_62_PRIME_239V1,
+ "ANSI X9.62 elliptic curve prime239v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime239v2, ECCurve_X9_62_PRIME_239V2,
+ "ANSI X9.62 elliptic curve prime239v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime239v3, ECCurve_X9_62_PRIME_239V3,
+ "ANSI X9.62 elliptic curve prime239v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime256v1, ECCurve_NIST_P256,
+ "ANSI X9.62 elliptic curve prime256v1 (aka secp256r1, NIST P-256)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION )
+};
+
+static SECOidData SECG_oids[] = {
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+
+ OD( secgECsect163k1, ECCurve_NIST_K163,
+ "SECG elliptic curve sect163k1 (aka NIST K-163)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect163r1, ECCurve_SECG_CHAR2_163R1,
+ "SECG elliptic curve sect163r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect239k1, ECCurve_SECG_CHAR2_239K1,
+ "SECG elliptic curve sect239k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect113r1, ECCurve_SECG_CHAR2_113R1,
+ "SECG elliptic curve sect113r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect113r2, ECCurve_SECG_CHAR2_113R2,
+ "SECG elliptic curve sect113r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp112r1, ECCurve_SECG_PRIME_112R1,
+ "SECG elliptic curve secp112r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp112r2, ECCurve_SECG_PRIME_112R2,
+ "SECG elliptic curve secp112r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp160r1, ECCurve_SECG_PRIME_160R1,
+ "SECG elliptic curve secp160r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp160k1, ECCurve_SECG_PRIME_160K1,
+ "SECG elliptic curve secp160k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp256k1, ECCurve_SECG_PRIME_256K1,
+ "SECG elliptic curve secp256k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ OD( secgECsect163r2, ECCurve_NIST_B163,
+ "SECG elliptic curve sect163r2 (aka NIST B-163)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect283k1, ECCurve_NIST_K283,
+ "SECG elliptic curve sect283k1 (aka NIST K-283)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect283r1, ECCurve_NIST_B283,
+ "SECG elliptic curve sect283r1 (aka NIST B-283)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ OD( secgECsect131r1, ECCurve_SECG_CHAR2_131R1,
+ "SECG elliptic curve sect131r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect131r2, ECCurve_SECG_CHAR2_131R2,
+ "SECG elliptic curve sect131r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect193r1, ECCurve_SECG_CHAR2_193R1,
+ "SECG elliptic curve sect193r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect193r2, ECCurve_SECG_CHAR2_193R2,
+ "SECG elliptic curve sect193r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect233k1, ECCurve_NIST_K233,
+ "SECG elliptic curve sect233k1 (aka NIST K-233)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect233r1, ECCurve_NIST_B233,
+ "SECG elliptic curve sect233r1 (aka NIST B-233)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp128r1, ECCurve_SECG_PRIME_128R1,
+ "SECG elliptic curve secp128r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp128r2, ECCurve_SECG_PRIME_128R2,
+ "SECG elliptic curve secp128r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp160r2, ECCurve_SECG_PRIME_160R2,
+ "SECG elliptic curve secp160r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp192k1, ECCurve_SECG_PRIME_192K1,
+ "SECG elliptic curve secp192k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp224k1, ECCurve_SECG_PRIME_224K1,
+ "SECG elliptic curve secp224k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp224r1, ECCurve_NIST_P224,
+ "SECG elliptic curve secp224r1 (aka NIST P-224)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp384r1, ECCurve_NIST_P384,
+ "SECG elliptic curve secp384r1 (aka NIST P-384)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp521r1, ECCurve_NIST_P521,
+ "SECG elliptic curve secp521r1 (aka NIST P-521)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect409k1, ECCurve_NIST_K409,
+ "SECG elliptic curve sect409k1 (aka NIST K-409)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect409r1, ECCurve_NIST_B409,
+ "SECG elliptic curve sect409r1 (aka NIST B-409)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect571k1, ECCurve_NIST_K571,
+ "SECG elliptic curve sect571k1 (aka NIST K-571)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect571r1, ECCurve_NIST_B571,
+ "SECG elliptic curve sect571r1 (aka NIST B-571)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION )
+};
+
+static SECOidData ANSI_oids[] = {
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+
+ /* ANSI X9.62 named elliptic curves (characteristic two field) */
+ OD( ansiX962c2pnb163v1, ECCurve_X9_62_CHAR2_PNB163V1,
+ "ANSI X9.62 elliptic curve c2pnb163v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb163v2, ECCurve_X9_62_CHAR2_PNB163V2,
+ "ANSI X9.62 elliptic curve c2pnb163v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb163v3, ECCurve_X9_62_CHAR2_PNB163V3,
+ "ANSI X9.62 elliptic curve c2pnb163v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb176v1, ECCurve_X9_62_CHAR2_PNB176V1,
+ "ANSI X9.62 elliptic curve c2pnb176v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb191v1, ECCurve_X9_62_CHAR2_TNB191V1,
+ "ANSI X9.62 elliptic curve c2tnb191v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb191v2, ECCurve_X9_62_CHAR2_TNB191V2,
+ "ANSI X9.62 elliptic curve c2tnb191v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb191v3, ECCurve_X9_62_CHAR2_TNB191V3,
+ "ANSI X9.62 elliptic curve c2tnb191v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ OD( ansiX962c2pnb208w1, ECCurve_X9_62_CHAR2_PNB208W1,
+ "ANSI X9.62 elliptic curve c2pnb208w1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb239v1, ECCurve_X9_62_CHAR2_TNB239V1,
+ "ANSI X9.62 elliptic curve c2tnb239v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb239v2, ECCurve_X9_62_CHAR2_TNB239V2,
+ "ANSI X9.62 elliptic curve c2tnb239v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb239v3, ECCurve_X9_62_CHAR2_TNB239V3,
+ "ANSI X9.62 elliptic curve c2tnb239v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ OD( ansiX962c2pnb272w1, ECCurve_X9_62_CHAR2_PNB272W1,
+ "ANSI X9.62 elliptic curve c2pnb272w1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb304w1, ECCurve_X9_62_CHAR2_PNB304W1,
+ "ANSI X9.62 elliptic curve c2pnb304w1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb359v1, ECCurve_X9_62_CHAR2_TNB359V1,
+ "ANSI X9.62 elliptic curve c2tnb359v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb368w1, ECCurve_X9_62_CHAR2_PNB368W1,
+ "ANSI X9.62 elliptic curve c2pnb368w1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb431r1, ECCurve_X9_62_CHAR2_TNB431R1,
+ "ANSI X9.62 elliptic curve c2tnb431r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION )
+};
+
+static SECOidData BRAINPOOL_oids[] = {
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+
+ /* RFC 5639 Brainpool named elliptic curves */
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ OD( brainpoolP256r1, ECCurve_BrainpoolP256r1,
+ "brainpoolP256r1 domain parameter set",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ OD( brainpoolP320r1, ECCurve_BrainpoolP320r1,
+ "brainpoolP320r1 domain parameter set",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ OD( brainpoolP384r1, ECCurve_BrainpoolP384r1,
+ "brainpoolP384r1 domain parameter set",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ OD( brainpoolP512r1, ECCurve_BrainpoolP512r1,
+ "brainpoolP512r1 domain parameter set",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ { { siDEROID, NULL, 0 }, ECCurve_noName,
+ "Unknown OID", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION }
+};
+
+int
+oideql(unsigned char *reqoid, unsigned char *foundoid, size_t reqlen, size_t foundlen)
+{
+ if (!reqoid || !foundoid) {
+ return 0;
+ }
+
+ if (reqlen != foundlen) {
+ return 0;
+ }
+
+ return memcmp(reqoid, foundoid, reqlen) == 0;
+}
+
+SECOidData *
+SECOID_FindOID(const SECItem *oid)
+{
+ SECOidData *po;
+ SECOidData *ret = NULL;
+ int reqlen = oid->len;
+
+ if (reqlen == 8) {
+ if (oid->data[6] == 0x00) {
+ /* XXX bounds check */
+ po = &ANSI_oids[oid->data[7]];
+ if (oideql(oid->data, po->oid.data, reqlen, po->oid.len)) {
+ ret = po;
+ }
+ }
+ if (oid->data[6] == 0x01) {
+ /* XXX bounds check */
+ po = &ANSI_prime_oids[oid->data[7]];
+ if (oideql(oid->data, po->oid.data, reqlen, po->oid.len)) {
+ ret = po;
+ }
+ }
+ } else if (reqlen == 5) {
+ /* XXX bounds check */
+ po = &SECG_oids[oid->data[4]];
+ if (oideql(oid->data, po->oid.data, reqlen, po->oid.len)) {
+ ret = po;
+ }
+ } else if (reqlen == 9) {
+ /* XXX bounds check */
+ po = &BRAINPOOL_oids[oid->data[8]];
+ if (oideql(oid->data, po->oid.data, reqlen, po->oid.len)) {
+ ret = po;
+ }
+ }
+ return(ret);
+}
+
+ECCurveName
+SECOID_FindOIDTag(const SECItem *oid)
+{
+ SECOidData *oiddata;
+
+ oiddata = SECOID_FindOID (oid);
+ if (oiddata == NULL)
+ return ECCurve_noName;
+
+ return oiddata->offset;
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/secitem.c b/jdk.crypto.ec/share/native/libsunec/impl/secitem.c
new file mode 100644
index 0000000..fab4415
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/secitem.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Last Modified Date from the Original Code: March 2012
+ *********************************************************************** */
+
+/*
+ * Support routines for SECItem data structure.
+ *
+ * $Id: secitem.c,v 1.14 2006/05/22 22:24:34 wtchang%redhat.com Exp $
+ */
+
+#include <sys/types.h>
+
+#ifndef _WIN32
+#if !defined(__linux__) && !defined(_ALLBSD_SOURCE)
+#include <sys/systm.h>
+#endif /* __linux__ || _ALLBSD_SOURCE */
+#include <sys/param.h>
+#endif /* _WIN32 */
+
+#ifdef _KERNEL
+#include <sys/kmem.h>
+#else
+#include <string.h>
+
+#ifndef _WIN32
+#include <strings.h>
+#endif /* _WIN32 */
+
+#include <assert.h>
+#endif
+#include "ec.h"
+#include "ecl-curve.h"
+#include "ecc_impl.h"
+
+void SECITEM_FreeItem(SECItem *, PRBool);
+
+SECItem *
+SECITEM_AllocItem(PRArenaPool *arena, SECItem *item, unsigned int len,
+ int kmflag)
+{
+ SECItem *result = NULL;
+ void *mark = NULL;
+
+ if (arena != NULL) {
+ mark = PORT_ArenaMark(arena);
+ }
+
+ if (item == NULL) {
+ if (arena != NULL) {
+ result = PORT_ArenaZAlloc(arena, sizeof(SECItem), kmflag);
+ } else {
+ result = PORT_ZAlloc(sizeof(SECItem), kmflag);
+ }
+ if (result == NULL) {
+ goto loser;
+ }
+ } else {
+ PORT_Assert(item->data == NULL);
+ result = item;
+ }
+
+ result->len = len;
+ if (len) {
+ if (arena != NULL) {
+ result->data = PORT_ArenaAlloc(arena, len, kmflag);
+ } else {
+ result->data = PORT_Alloc(len, kmflag);
+ }
+ if (result->data == NULL) {
+ goto loser;
+ }
+ } else {
+ result->data = NULL;
+ }
+
+ if (mark) {
+ PORT_ArenaUnmark(arena, mark);
+ }
+ return(result);
+
+loser:
+ if ( arena != NULL ) {
+ if (mark) {
+ PORT_ArenaRelease(arena, mark);
+ }
+ if (item != NULL) {
+ item->data = NULL;
+ item->len = 0;
+ }
+ } else {
+ if (result != NULL) {
+ SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE);
+ }
+ /*
+ * If item is not NULL, the above has set item->data and
+ * item->len to 0.
+ */
+ }
+ return(NULL);
+}
+
+SECStatus
+SECITEM_CopyItem(PRArenaPool *arena, SECItem *to, const SECItem *from,
+ int kmflag)
+{
+ to->type = from->type;
+ if (from->data && from->len) {
+ if ( arena ) {
+ to->data = (unsigned char*) PORT_ArenaAlloc(arena, from->len,
+ kmflag);
+ } else {
+ to->data = (unsigned char*) PORT_Alloc(from->len, kmflag);
+ }
+
+ if (!to->data) {
+ return SECFailure;
+ }
+ PORT_Memcpy(to->data, from->data, from->len);
+ to->len = from->len;
+ } else {
+ to->data = 0;
+ to->len = 0;
+ }
+ return SECSuccess;
+}
+
+void
+SECITEM_FreeItem(SECItem *zap, PRBool freeit)
+{
+ if (zap) {
+#ifdef _KERNEL
+ kmem_free(zap->data, zap->len);
+#else
+ free(zap->data);
+#endif
+ zap->data = 0;
+ zap->len = 0;
+ if (freeit) {
+#ifdef _KERNEL
+ kmem_free(zap, sizeof (SECItem));
+#else
+ free(zap);
+#endif
+ }
+ }
+}
diff --git a/jdk.crypto.ec/share/native/libsunec/impl/secoidt.h b/jdk.crypto.ec/share/native/libsunec/impl/secoidt.h
new file mode 100644
index 0000000..58dde3b
--- /dev/null
+++ b/jdk.crypto.ec/share/native/libsunec/impl/secoidt.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* *********************************************************************
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ *********************************************************************** */
+
+#ifndef _SECOIDT_H_
+#define _SECOIDT_H_
+
+/*
+ * secoidt.h - public data structures for ASN.1 OID functions
+ *
+ * $Id: secoidt.h,v 1.23 2007/05/05 22:45:16 nelson%bolyard.com Exp $
+ */
+
+typedef struct SECOidDataStr SECOidData;
+typedef struct SECAlgorithmIDStr SECAlgorithmID;
+
+/*
+** An X.500 algorithm identifier
+*/
+struct SECAlgorithmIDStr {
+ SECItem algorithm;
+ SECItem parameters;
+};
+
+#define SEC_OID_SECG_EC_SECP192R1 SEC_OID_ANSIX962_EC_PRIME192V1
+#define SEC_OID_SECG_EC_SECP256R1 SEC_OID_ANSIX962_EC_PRIME256V1
+#define SEC_OID_PKCS12_KEY_USAGE SEC_OID_X509_KEY_USAGE
+
+/* fake OID for DSS sign/verify */
+#define SEC_OID_SHA SEC_OID_MISS_DSS
+
+typedef enum {
+ INVALID_CERT_EXTENSION = 0,
+ UNSUPPORTED_CERT_EXTENSION = 1,
+ SUPPORTED_CERT_EXTENSION = 2
+} SECSupportExtenTag;
+
+struct SECOidDataStr {
+ SECItem oid;
+ ECCurveName offset;
+ const char * desc;
+ unsigned long mechanism;
+ SECSupportExtenTag supportedExtension;
+ /* only used for x.509 v3 extensions, so
+ that we can print the names of those
+ extensions that we don't even support */
+};
+
+#endif /* _SECOIDT_H_ */