提交 51a55865 编写于 作者: V vinnie

6840752: Provide out-of-the-box support for ECC algorithms

Reviewed-by: alanb, mullan, wetmore
上级 085a8650
# #
# Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. # Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -60,7 +60,7 @@ ifeq ($(PLATFORM), windows) ...@@ -60,7 +60,7 @@ ifeq ($(PLATFORM), windows)
endif endif
endif endif
SUBDIRS = other action util tools jgss krb5 smartcardio $(PKCS11) \ SUBDIRS = ec other action util tools jgss krb5 smartcardio $(PKCS11) \
$(JGSS_WRAPPER) $(MSCAPI) $(JGSS_WRAPPER) $(MSCAPI)
all build clean clobber:: all build clean clobber::
......
#
# Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
# particular file as subject to the "Classpath" exception as provided
# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
# CA 95054 USA or visit www.sun.com if you need additional information or
# have any questions.
#
FILES_c = \
ec.c \
ec2_163.c \
ec2_193.c \
ec2_233.c \
ec2_aff.c \
ec2_mont.c \
ecdecode.c \
ecl.c \
ecl_curve.c \
ecl_gf.c \
ecl_mult.c \
ec_naf.c \
ecp_192.c \
ecp_224.c \
ecp_256.c \
ecp_384.c \
ecp_521.c \
ecp_aff.c \
ecp_jac.c \
ecp_jm.c \
ecp_mont.c \
mp_gf2m.c \
mpi.c \
mplogic.c \
mpmontg.c \
oid.c \
secitem.c
#
# Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
# particular file as subject to the "Classpath" exception as provided
# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
# CA 95054 USA or visit www.sun.com if you need additional information or
# have any questions.
#
#
# Makefile for building sunec.jar and sunecc native library.
#
# This file was derived from make/com/sun/crypto/provider/Makefile.
#
#
# (The terms "OpenJDK" and "JDK" below refer to OpenJDK and Sun JDK builds
# respectively.)
#
# JCE builds are very different between OpenJDK and JDK. The OpenJDK JCE
# jar files do not require signing, but those for JDK do. If an unsigned
# jar file is installed into JDK, things will break when the crypto
# routines are called.
#
# This Makefile does the "real" build of the JCE files. For OpenJDK,
# the jar files built here are installed directly into the OpenJDK.
#
# For JDK, the binaries use pre-built/pre-signed binary files stored in
# the closed workspace that are not shipped in the OpenJDK workspaces.
# We still build the JDK files here to verify the files compile, and in
# preparation for possible signing. Developers working on JCE in JDK
# must sign the JCE files before testing. The JCE signing key is kept
# separate from the JDK workspace to prevent its disclosure.
#
# SPECIAL NOTE TO JCE/JDK developers: The source files must eventually
# be built, signed, and then the resulting jar files MUST BE CHECKED
# INTO THE CLOSED PART OF THE WORKSPACE*. This separate step *MUST NOT
# BE FORGOTTEN*, otherwise a bug fixed in the source code will not be
# reflected in the shipped binaries. The "release" target should be
# used to generate the required files.
#
# There are a number of targets to help both JDK/OpenJDK developers.
#
# Main Targets (JDK/OPENJDK):
#
# all/clobber/clean The usual, plus the native libraries.
# If OpenJDK, installs sunec.jar.
# If JDK, installs prebuilt
# sunec.jar.
#
# jar Builds/installs sunec.jar
# If OpenJDK, does not sign.
# If JDK, tries to sign.
#
# Other lesser-used Targets (JDK/OPENJDK):
#
# build-jar Builds sunec.jar
# (does not sign/install)
#
# install-jar Alias for "jar" above.
#
# Other targets (JDK only):
#
# sign Alias for sign-jar
# sign-jar Builds/signs sunec.jar (no install)
#
# release Builds all targets in preparation
# for workspace integration.
#
# install-prebuilt Installs the pre-built jar files
#
# This makefile was written to support parallel target execution.
#
BUILDDIR = ../../..
PACKAGE = sun.security.ec
PRODUCT = sun
#
# The following is for when we need to do postprocessing
# (signing) against a read-only build. If the OUTPUTDIR
# isn't writable, the build currently crashes out.
#
ifndef OPENJDK
ifdef ALT_JCE_BUILD_DIR
# =====================================================
# Where to place the output, in case we're building from a read-only
# build area. (e.g. a release engineering build.)
JCE_BUILD_DIR=${ALT_JCE_BUILD_DIR}
IGNORE_WRITABLE_OUTPUTDIR_TEST=true
else
JCE_BUILD_DIR=${TEMPDIR}
endif
endif
include $(BUILDDIR)/common/Defs.gmk
#
# Location for the newly built classfiles.
#
CLASSDESTDIR = $(TEMPDIR)/classes
#
# Java files
#
AUTO_FILES_JAVA_DIRS = $(PKGDIR)
include $(BUILDDIR)/common/Classes.gmk
#
# Some licensees do not get the native ECC sources, but we still need to
# be able to build "all" for them. Check here to see if the sources are
# available. If not, then skip them.
#
NATIVE_ECC_AVAILABLE := $(shell \
if [ -d $(SHARE_SRC)/native/$(PKGDIR) ] ; then \
$(ECHO) true; \
else \
$(ECHO) false; \
fi)
ifeq ($(NATIVE_ECC_AVAILABLE), true)
LIBRARY = sunecc
#
# Java files that define native methods
#
FILES_export = \
$(PKGDIR)/ECDHKeyAgreement.java \
$(PKGDIR)/ECDSASignature.java \
$(PKGDIR)/ECKeyPairGenerator.java
JAVAHFLAGS += -classpath $(CLASSDESTDIR)
#
# C and C++ files
#
include FILES_c.gmk
FILES_cpp = ECC_JNI.cpp
CPLUSPLUSLIBRARY=true
FILES_m = mapfile-vers
#
# Find native code
#
vpath %.cpp $(SHARE_SRC)/native/$(PKGDIR)
vpath %.c $(SHARE_SRC)/native/$(PKGDIR)
#
# Find include files
#
OTHER_INCLUDES += -I$(SHARE_SRC)/native/$(PKGDIR)
#
# Compiler flags
#
OTHER_CFLAGS += -DMP_API_COMPATIBLE -DNSS_ECC_MORE_THAN_SUITE_B
#
# Libraries to link
#
ifeq ($(PLATFORM), windows)
OTHER_LDLIBS += $(JVMLIB)
else
OTHER_LDLIBS = -ldl $(JVMLIB) $(LIBCXX)
endif
include $(BUILDDIR)/common/Mapfile-vers.gmk
include $(BUILDDIR)/common/Library.gmk
endif # NATIVE_ECC_AVAILABLE
#
# We use a variety of subdirectories in the $(TEMPDIR) depending on what
# part of the build we're doing. Both OPENJDK/JDK builds are initially
# done in the unsigned area. When files are signed in JDK,
# they will be placed in the appropriate area.
#
UNSIGNED_DIR = $(TEMPDIR)/unsigned
include $(BUILDDIR)/javax/crypto/Defs-jce.gmk
#
# Rules
#
ifdef OPENJDK
all: build-jar install-jar
else
all: build-jar install-prebuilt
$(build-warning)
endif
# =====================================================
# Build the unsigned sunec.jar file.
#
JAR_DESTFILE = $(EXTDIR)/sunec.jar
#
# Since the -C option to jar is used below, each directory entry must be
# preceded with the appropriate directory to "cd" into.
#
JAR_DIRS = $(patsubst %, -C $(CLASSDESTDIR) %, $(AUTO_FILES_JAVA_DIRS))
build-jar: $(UNSIGNED_DIR)/sunec.jar
#
# Build sunec.jar.
#
$(UNSIGNED_DIR)/sunec.jar: build
$(prep-target)
$(BOOT_JAR_CMD) cf $@ $(JAR_DIRS) \
$(BOOT_JAR_JFLAGS)
@$(java-vm-cleanup)
ifndef OPENJDK
# =====================================================
# Sign the provider jar file. Not needed for OpenJDK.
#
SIGNED_DIR = $(JCE_BUILD_DIR)/signed
sign: sign-jar
sign-jar: $(SIGNED_DIR)/sunec.jar
ifndef ALT_JCE_BUILD_DIR
$(SIGNED_DIR)/sunec.jar: $(UNSIGNED_DIR)/sunec.jar
else
#
# We have to remove the build dependency, otherwise, we'll try to rebuild it
# which we can't do on a read-only filesystem.
#
$(SIGNED_DIR)/sunec.jar:
@if [ ! -r $(UNSIGNED_DIR)/sunec.jar ] ; then \
$(ECHO) "Couldn't find $(UNSIGNED_DIR)/sunec.jar"; \
exit 1; \
fi
endif
$(call sign-file, $(UNSIGNED_DIR)/sunec.jar)
# =====================================================
# Create the Release Engineering files. Signed builds, etc.
#
release: $(SIGNED_DIR)/sunec.jar
$(RM) $(JCE_BUILD_DIR)/release/sunec.jar
$(MKDIR) -p $(JCE_BUILD_DIR)/release
$(CP) $(SIGNED_DIR)/sunec.jar $(JCE_BUILD_DIR)/release
$(release-warning)
endif # OPENJDK
# =====================================================
# Install routines.
#
#
# Install sunec.jar, depending on which type is requested.
#
install-jar jar: $(JAR_DESTFILE)
ifndef OPENJDK
$(release-warning)
endif
ifdef OPENJDK
$(JAR_DESTFILE): $(UNSIGNED_DIR)/sunec.jar
else
$(JAR_DESTFILE): $(SIGNED_DIR)/sunec.jar
endif
$(install-file)
ifndef OPENJDK
install-prebuilt:
@$(ECHO) "\n>>>Installing prebuilt SunEC provider..."
$(RM) $(JAR_DESTFILE)
$(CP) $(PREBUILT_DIR)/ec/sunec.jar $(JAR_DESTFILE)
endif
# =====================================================
# Support routines.
#
clobber clean::
$(RM) -r $(JAR_DESTFILE) $(TEMPDIR) $(JCE_BUILD_DIR)
.PHONY: build-jar jar install-jar
ifndef OPENJDK
.PHONY: sign sign-jar release install-prebuilt
endif
#
# Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
# particular file as subject to the "Classpath" exception as provided
# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
# CA 95054 USA or visit www.sun.com if you need additional information or
# have any questions.
#
# Define public interface.
SUNWprivate_1.1 {
global:
Java_sun_security_ec_ECKeyPairGenerator_generateECKeyPair;
Java_sun_security_ec_ECKeyPairGenerator_getEncodedBytes;
Java_sun_security_ec_ECDSASignature_signDigest;
Java_sun_security_ec_ECDSASignature_verifySignedDigest;
Java_sun_security_ec_ECDHKeyAgreement_deriveKey;
local:
*;
};
# #
# Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. # Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -33,7 +33,6 @@ include $(BUILDDIR)/common/Defs.gmk ...@@ -33,7 +33,6 @@ include $(BUILDDIR)/common/Defs.gmk
# #
AUTO_FILES_JAVA_DIRS = \ AUTO_FILES_JAVA_DIRS = \
sun/security/acl \ sun/security/acl \
sun/security/ec \
sun/security/jca \ sun/security/jca \
sun/security/pkcs \ sun/security/pkcs \
sun/security/pkcs12 \ sun/security/pkcs12 \
......
/*
* Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.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.*;
import javax.crypto.*;
import javax.crypto.spec.*;
/**
* KeyAgreement implementation for ECDH.
*
* @since 1.7
*/
public final class ECDHKeyAgreement extends KeyAgreementSpi {
// flag indicating whether the native ECC implementation is present
private static boolean implementationPresent = true;
static {
try {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("sunecc");
return null;
}
});
} catch (UnsatisfiedLinkError e) {
implementationPresent = false;
}
}
// private key, if initialized
private ECPrivateKey privateKey;
// encoded public point, non-null between doPhase() & generateSecret() only
private byte[] publicValue;
// length of the secret to be derived
private int secretLen;
/**
* Constructs a new ECDHKeyAgreement.
*
* @exception ProviderException if the native ECC library is unavailable.
*/
public ECDHKeyAgreement() {
if (!implementationPresent) {
throw new ProviderException("ECDH implementation is not available");
}
}
// see JCE spec
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);
publicValue = null;
}
// see JCE spec
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
protected Key engineDoPhase(Key key, boolean lastPhase)
throws InvalidKeyException, IllegalStateException {
if (privateKey == null) {
throw new IllegalStateException("Not initialized");
}
if (publicValue != 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");
}
ECPublicKey ecKey = (ECPublicKey)key;
ECParameterSpec params = ecKey.getParams();
if (ecKey instanceof ECPublicKeyImpl) {
publicValue = ((ECPublicKeyImpl)ecKey).getEncodedPublicValue();
} else { // instanceof ECPublicKey
publicValue =
ECParameters.encodePoint(ecKey.getW(), params.getCurve());
}
int keyLenBits = params.getCurve().getField().getFieldSize();
secretLen = (keyLenBits + 7) >> 3;
return null;
}
// see JCE spec
protected byte[] engineGenerateSecret() throws IllegalStateException {
if ((privateKey == null) || (publicValue == null)) {
throw new IllegalStateException("Not initialized correctly");
}
byte[] s = privateKey.getS().toByteArray();
byte[] encodedParams =
ECParameters.encodeParameters(privateKey.getParams()); // DER OID
try {
return deriveKey(s, publicValue, encodedParams);
} catch (GeneralSecurityException e) {
throw new ProviderException("Could not derive key", e);
}
}
// see JCE spec
protected int engineGenerateSecret(byte[] sharedSecret, int
offset) throws IllegalStateException, ShortBufferException {
if (offset + secretLen > sharedSecret.length) {
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
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");
}
/**
* 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;
}
/*
* Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.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.util.Arrays;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
import sun.security.jca.JCAUtil;
import sun.security.util.*;
import sun.security.x509.AlgorithmId;
/**
* ECDSA signature implementation. This class currently supports the
* following algorithm names:
*
* . "NONEwithECDSA"
* . "SHA1withECDSA"
* . "SHA256withECDSA"
* . "SHA384withECDSA"
* . "SHA512withECDSA"
*
* @since 1.7
*/
abstract class ECDSASignature extends SignatureSpi {
// flag indicating whether the native ECC implementation is present
private static boolean implementationPresent = true;
static {
try {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("sunecc");
return null;
}
});
} catch (UnsatisfiedLinkError e) {
implementationPresent = false;
}
}
// 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;
/**
* Constructs a new ECDSASignature. Used by Raw subclass.
*
* @exception ProviderException if the native ECC library is unavailable.
*/
ECDSASignature() {
if (!implementationPresent) {
throw new
ProviderException("ECDSA implementation is not available");
}
messageDigest = null;
}
/**
* Constructs a new ECDSASignature. Used by subclasses.
*
* @exception ProviderException if the native ECC library is unavailable.
*/
ECDSASignature(String digestName) {
if (!implementationPresent) {
throw new
ProviderException("ECDSA implementation is not available");
}
try {
messageDigest = MessageDigest.getInstance(digestName);
} catch (NoSuchAlgorithmException e) {
throw new ProviderException(e);
}
needsReset = false;
}
// Nested class for NONEwithECDSA signatures
public static final class Raw 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;
public Raw() {
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 (offset + len >= precomputedDigest.length) {
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 SHA1withECDSA signatures
public static final class SHA1 extends ECDSASignature {
public SHA1() {
super("SHA1");
}
}
// Nested class for SHA256withECDSA signatures
public static final class SHA256 extends ECDSASignature {
public SHA256() {
super("SHA-256");
}
}
// Nested class for SHA384withECDSA signatures
public static final class SHA384 extends ECDSASignature {
public SHA384() {
super("SHA-384");
}
}
// Nested class for SHA512withECDSA signatures
public static final class SHA512 extends ECDSASignature {
public SHA512() {
super("SHA-512");
}
}
// initialize for verification. See JCA doc
@Override
protected void engineInitVerify(PublicKey publicKey)
throws InvalidKeyException {
this.publicKey = (ECPublicKey) ECKeyFactory.toECKey(publicKey);
// Should check that the supplied key is appropriate for signature
// algorithm (e.g. P-256 for SHA256withECDSA)
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 {
this.privateKey = (ECPrivateKey) ECKeyFactory.toECKey(privateKey);
// Should check that the supplied key is appropriate for signature
// algorithm (e.g. P-256 for SHA256withECDSA)
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;
}
// sign the data and return the signature. See JCA doc
@Override
protected byte[] engineSign() throws SignatureException {
byte[] s = privateKey.getS().toByteArray();
ECParameterSpec params = privateKey.getParams();
byte[] encodedParams = ECParameters.encodeParameters(params); // DER OID
int keySize = params.getCurve().getField().getFieldSize();
// seed is twice the key size (in bytes)
byte[] seed = new byte[((keySize + 7) >> 3) * 2];
if (random == null) {
random = JCAUtil.getSecureRandom();
}
random.nextBytes(seed);
try {
return encodeSignature(
signDigest(getDigestValue(), s, encodedParams, seed));
} catch (GeneralSecurityException e) {
throw new SignatureException("Could not sign data", e);
}
}
// verify the data and return the result. See JCA doc
@Override
protected boolean engineVerify(byte[] signature) throws SignatureException {
byte[] w;
ECParameterSpec params = publicKey.getParams();
byte[] encodedParams = ECParameters.encodeParameters(params); // DER OID
if (publicKey instanceof ECPublicKeyImpl) {
w = ((ECPublicKeyImpl)publicKey).getEncodedPublicValue();
} else { // instanceof ECPublicKey
w = ECParameters.encodePoint(publicKey.getW(), params.getCurve());
}
try {
return verifySignedDigest(
decodeSignature(signature), getDigestValue(), w, encodedParams);
} catch (GeneralSecurityException e) {
throw new SignatureException("Could not verify signature", e);
}
}
// set parameter, not supported. See JCA doc
@Override
protected void engineSetParameter(String param, Object value)
throws InvalidParameterException {
throw new UnsupportedOperationException("setParameter() not supported");
}
// get parameter, not supported. See JCA doc
@Override
protected Object engineGetParameter(String param)
throws InvalidParameterException {
throw new UnsupportedOperationException("getParameter() not supported");
}
// 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[] signature) throws SignatureException {
try {
DerInputStream in = new DerInputStream(signature);
DerValue[] values = in.getSequence(2);
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);
return result;
} catch (Exception e) {
throw new SignatureException("Could not decode 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.
*
* @return byte[] the signature.
*/
private static native byte[] signDigest(byte[] digest, byte[] s,
byte[] encodedParams, byte[] seed) throws GeneralSecurityException;
/**
* Verifies the signed digest using the public key.
*
* @param signedDigest 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;
}
/*
* Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package sun.security.ec;
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 sun.security.ec.NamedCurve;
import sun.security.ec.ECParameters;
import sun.security.ec.ECPrivateKeyImpl;
import sun.security.ec.ECPublicKeyImpl;
import sun.security.jca.JCAUtil;
/**
* EC keypair generator.
* Standard algorithm, minimum key length is 112 bits, maximum is 571 bits.
*
* @since 1.7
*/
public final class ECKeyPairGenerator extends KeyPairGeneratorSpi {
// flag indicating whether the native ECC implementation is present
private static boolean implementationPresent = true;
static {
try {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
System.loadLibrary("sunecc");
return null;
}
});
} catch (UnsatisfiedLinkError e) {
implementationPresent = false;
}
}
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)
private static final int KEY_SIZE_DEFAULT = 256;
// 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.
*
* @exception ProviderException if the native ECC library is unavailable.
*/
public ECKeyPairGenerator() {
if (!implementationPresent) {
throw new ProviderException("EC implementation is not available");
}
// initialize to default in case the app does not call initialize()
initialize(KEY_SIZE_DEFAULT, null);
}
// initialize the generator. See JCA doc
@Override
public void initialize(int keySize, SecureRandom random) {
checkKeySize(keySize);
this.params = NamedCurve.getECParameterSpec(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 {
if (params instanceof ECParameterSpec) {
this.params = ECParameters.getNamedCurve((ECParameterSpec)params);
if (this.params == null) {
throw new InvalidAlgorithmParameterException(
"Unsupported curve: " + params);
}
} else if (params instanceof ECGenParameterSpec) {
String name = ((ECGenParameterSpec)params).getName();
this.params = NamedCurve.getECParameterSpec(name);
if (this.params == null) {
throw new InvalidAlgorithmParameterException(
"Unknown curve name: " + name);
}
} else {
throw new InvalidAlgorithmParameterException(
"ECParameterSpec or ECGenParameterSpec required for EC");
}
this.keySize =
((ECParameterSpec)this.params).getCurve().getField().getFieldSize();
this.random = random;
}
// generate the keypair. See JCA doc
@Override
public KeyPair generateKeyPair() {
byte[] encodedParams =
ECParameters.encodeParameters((ECParameterSpec)params);
// seed is twice the key size (in bytes)
byte[] seed = new byte[2 * ((keySize + 7) >> 3)];
if (random == null) {
random = JCAUtil.getSecureRandom();
}
random.nextBytes(seed);
long[] handles = generateECKeyPair(keySize, encodedParams, seed);
// The 'params' object supplied above is equivalent to the native one
// so there is no need to fetch it.
// handles[0] points to the native private key
BigInteger s = new BigInteger(1, getEncodedBytes(handles[0]));
try {
PrivateKey privateKey =
new ECPrivateKeyImpl(s, (ECParameterSpec)params);
// handles[1] points to the native public key
ECPoint w = ECParameters.decodePoint(getEncodedBytes(handles[1]),
((ECParameterSpec)params).getCurve());
PublicKey publicKey =
new ECPublicKeyImpl(w, (ECParameterSpec)params);
return new KeyPair(publicKey, privateKey);
} catch (Exception e) {
throw new ProviderException(e);
}
}
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;
}
/*
* Generates the keypair and returns a 2-element array of handles.
* The first handle points to the private key, the second to the public key.
*/
private static native long[] generateECKeyPair(int keySize,
byte[] encodedParams, byte[] seed);
/*
* Extracts the encoded key data using the supplied handle.
*/
private static native byte[] getEncodedBytes(long handle);
}
/*
* Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package sun.security.ec;
import java.util.*;
import java.security.*;
import sun.security.action.PutAllAction;
/**
* 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 signed sunec.jar in the JRE
* extensions directory and the C++ and C functions are packaged into
* libsunecc.so or sunecc.dll in the JRE native libraries directory.
*
* @since 1.7
*/
public final class SunEC extends Provider {
private static final long serialVersionUID = -2279741672933606418L;
public SunEC() {
super("SunEC", 1.7d, "Sun Elliptic Curve provider (EC, ECDSA, ECDH)");
// if there is no security manager installed, put directly into
// the provider. Otherwise, create a temporary map and use a
// doPrivileged() call at the end to transfer the contents
if (System.getSecurityManager() == null) {
SunECEntries.putEntries(this);
} else {
Map<Object, Object> map = new HashMap<Object, Object>();
SunECEntries.putEntries(map);
AccessController.doPrivileged(new PutAllAction(this, map));
}
}
}
/*
* Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package sun.security.ec;
import java.util.Map;
/**
* Defines the entries of the SunEC provider.
*
* @since 1.7
*/
final class SunECEntries {
private SunECEntries() {
// empty
}
static void putEntries(Map<Object, Object> map) {
/*
* Signature engines
*/
map.put("Signature.NONEwithECDSA",
"sun.security.ec.ECDSASignature$Raw");
map.put("Signature.SHA1withECDSA",
"sun.security.ec.ECDSASignature$SHA1");
map.put("Signature.SHA256withECDSA",
"sun.security.ec.ECDSASignature$SHA256");
map.put("Signature.SHA384withECDSA",
"sun.security.ec.ECDSASignature$SHA384");
map.put("Signature.SHA512withECDSA",
"sun.security.ec.ECDSASignature$SHA512");
String ecKeyClasses = "java.security.interfaces.ECPublicKey" +
"|java.security.interfaces.ECPrivateKey";
map.put("Signature.NONEwithECDSA SupportedKeyClasses", ecKeyClasses);
map.put("Signature.SHA1withECDSA SupportedKeyClasses", ecKeyClasses);
map.put("Signature.SHA256withECDSA SupportedKeyClasses", ecKeyClasses);
map.put("Signature.SHA384withECDSA SupportedKeyClasses", ecKeyClasses);
map.put("Signature.SHA512withECDSA SupportedKeyClasses", ecKeyClasses);
/*
* Key Pair Generator engine
*/
map.put("KeyPairGenerator.EC", "sun.security.ec.ECKeyPairGenerator");
map.put("Alg.Alias.KeyPairGenerator.EllipticCurve", "EC");
/*
* Key Factory engine
*/
map.put("KeyFactory.EC", "sun.security.ec.ECKeyFactory");
map.put("Alg.Alias.KeyFactory.EllipticCurve", "EC");
/*
* Algorithm Parameter engine
*/
map.put("AlgorithmParameters.EC", "sun.security.ec.ECParameters");
map.put("Alg.Alias.AlgorithmParameters.EllipticCurve", "EC");
/*
* Key Agreement engine
*/
map.put("KeyAgreement.ECDH", "sun.security.ec.ECDHKeyAgreement");
map.put("KeyAgreement.ECDH SupportedKeyClasses", ecKeyClasses);
/*
* Key sizes
*/
map.put("Signature.SHA1withECDSA KeySize", "256");
map.put("KeyPairGenerator.EC KeySize", "256");
map.put("AlgorithmParameterGenerator.ECDSA KeySize", "256");
/*
* Implementation type: software or hardware
*/
map.put("Signature.NONEwithECDSA ImplementedIn", "Software");
map.put("Signature.SHA1withECDSA ImplementedIn", "Software");
map.put("Signature.SHA256withECDSA ImplementedIn", "Software");
map.put("Signature.SHA384withECDSA ImplementedIn", "Software");
map.put("Signature.SHA512withECDSA ImplementedIn", "Software");
map.put("KeyPairGenerator.EC ImplementedIn", "Software");
map.put("KeyFactory.EC ImplementedIn", "Software");
map.put("KeyAgreement.ECDH ImplementedIn", "Software");
map.put("AlgorithmParameters.EC ImplementedIn", "Software");
}
}
...@@ -45,12 +45,13 @@ ...@@ -45,12 +45,13 @@
# #
security.provider.1=sun.security.provider.Sun security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=com.sun.net.ssl.internal.ssl.Provider security.provider.3=sun.security.ec.SunEC
security.provider.4=com.sun.crypto.provider.SunJCE security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=sun.security.jgss.SunProvider security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=com.sun.security.sasl.Provider security.provider.6=sun.security.jgss.SunProvider
security.provider.7=org.jcp.xml.dsig.internal.dom.XMLDSigRI security.provider.7=com.sun.security.sasl.Provider
security.provider.8=sun.security.smartcardio.SunPCSC security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC
# #
# Select the source of seed data for SecureRandom. By default an # Select the source of seed data for SecureRandom. By default an
......
...@@ -46,12 +46,13 @@ ...@@ -46,12 +46,13 @@
security.provider.1=sun.security.pkcs11.SunPKCS11 ${java.home}/lib/security/sunpkcs11-solaris.cfg security.provider.1=sun.security.pkcs11.SunPKCS11 ${java.home}/lib/security/sunpkcs11-solaris.cfg
security.provider.2=sun.security.provider.Sun security.provider.2=sun.security.provider.Sun
security.provider.3=sun.security.rsa.SunRsaSign security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=com.sun.net.ssl.internal.ssl.Provider security.provider.4=sun.security.ec.SunEC
security.provider.5=com.sun.crypto.provider.SunJCE security.provider.5=com.sun.net.ssl.internal.ssl.Provider
security.provider.6=sun.security.jgss.SunProvider security.provider.6=com.sun.crypto.provider.SunJCE
security.provider.7=com.sun.security.sasl.Provider security.provider.7=sun.security.jgss.SunProvider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI security.provider.8=com.sun.security.sasl.Provider
security.provider.9=sun.security.smartcardio.SunPCSC security.provider.9=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.10=sun.security.smartcardio.SunPCSC
# #
# Select the source of seed data for SecureRandom. By default an # Select the source of seed data for SecureRandom. By default an
......
...@@ -45,13 +45,14 @@ ...@@ -45,13 +45,14 @@
# #
security.provider.1=sun.security.provider.Sun security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=com.sun.net.ssl.internal.ssl.Provider security.provider.3=sun.security.ec.SunEC
security.provider.4=com.sun.crypto.provider.SunJCE security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=sun.security.jgss.SunProvider security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=com.sun.security.sasl.Provider security.provider.6=sun.security.jgss.SunProvider
security.provider.7=org.jcp.xml.dsig.internal.dom.XMLDSigRI security.provider.7=com.sun.security.sasl.Provider
security.provider.8=sun.security.smartcardio.SunPCSC security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.mscapi.SunMSCAPI security.provider.9=sun.security.smartcardio.SunPCSC
security.provider.10=sun.security.mscapi.SunMSCAPI
# #
# Select the source of seed data for SecureRandom. By default an # Select the source of seed data for SecureRandom. By default an
......
/*
* Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
#include <jni.h>
#include "ecc_impl.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" {
/*
* Throws an arbitrary Java exception.
*/
void ThrowException(JNIEnv *env, char *exceptionName)
{
jclass exceptionClazz = env->FindClass(exceptionName);
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);
}
/*
* Class: sun_security_ec_ECKeyPairGenerator
* Method: generateECKeyPair
* Signature: (I[B[B)[J
*/
JNIEXPORT jlongArray
JNICALL Java_sun_security_ec_ECKeyPairGenerator_generateECKeyPair
(JNIEnv *env, jclass clazz, jint keySize, jbyteArray encodedParams, jbyteArray seed)
{
ECPrivateKey *privKey; /* contains both public and private values */
ECParams *ecparams = NULL;
SECKEYECParams params_item;
jint jSeedLength;
jbyte* pSeedBuffer = NULL;
jlongArray result = NULL;
jlong* resultElements = NULL;
// Initialize the ECParams struct
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(&params_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;
result = env->NewLongArray(2);
resultElements = env->GetLongArrayElements(result, &isCopy);
resultElements[0] = (jlong) &(privKey->privateValue); // private big integer
resultElements[1] = (jlong) &(privKey->publicValue); // encoded ec point
// If the array is a copy then we must write back our changes
if (isCopy == JNI_TRUE) {
env->ReleaseLongArrayElements(result, resultElements, 0);
}
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);
// Don't free privKey->privateValue and privKey->publicValue
}
if (pSeedBuffer)
delete [] pSeedBuffer;
}
return result;
}
/*
* Class: sun_security_ec_ECKeyPairGenerator
* Method: getEncodedBytes
* Signature: (J)[B
*/
JNIEXPORT jbyteArray
JNICALL Java_sun_security_ec_ECKeyPairGenerator_getEncodedBytes
(JNIEnv *env, jclass clazz, jlong hSECItem)
{
SECItem *s = (SECItem *)hSECItem;
jbyteArray jEncodedBytes = env->NewByteArray(s->len);
// Copy bytes from a native SECItem buffer to Java byte array
env->SetByteArrayRegion(jEncodedBytes, 0, s->len, (jbyte *)s->data);
// Use B_FALSE to free only the SECItem->data
SECITEM_FreeItem(s, B_FALSE);
return jEncodedBytes;
}
/*
* 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)
{
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;
// 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(&params_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);
// 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) != SECSuccess) {
ThrowException(env, KEY_EXCEPTION);
goto cleanup;
}
// Create new byte array
temp = env->NewByteArray(signature_item.len);
// 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 (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);
// Fill a new ECParams using the supplied OID
if (EC_DecodeParams(&params_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: 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;
// Extract private key value
SECItem privateValue_item;
privateValue_item.len = env->GetArrayLength(privateKey);
privateValue_item.data =
(unsigned char *) env->GetByteArrayElements(privateKey, 0);
// 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(&params_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);
// 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" */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "mplogic.h"
#include "ec.h"
#include "ecl.h"
#include <sys/types.h>
#ifndef _KERNEL
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#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)
{
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;
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) );
} else {
CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) );
}
/* 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
#ifndef _WIN32
int printf();
#endif /* _WIN32 */
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) );
rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue), kmflag);
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) {
goto cleanup;
}
/* 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;
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;
}
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 */
if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ, kmflag) != 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)
{
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 */
#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)
!= 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 length of n in bits.
* (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
if (digest->len*8 > ecParams->fieldID.size) {
mpl_rsh(&s,&s,digest->len*8 - ecParams->fieldID.size);
}
#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)
{
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);
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 */
#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 length of n in bits.
* (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
if (digest->len*8 > ecParams->fieldID.size) { /* u1 = HASH(M') */
mpl_rsh(&u1,&u1,digest->len*8- ecParams->fieldID.size);
}
#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
*/
if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC, kmflag)
!= 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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef __ec_h_
#define __ec_h_
#pragma ident "%Z%%M% %I% %E% SMI"
#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
#endif /* __ec_h_ */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _EC2_H
#define _EC2_H
#pragma ident "%Z%%M% %I% %E% SMI"
#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);
#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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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.
*/
MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt) );
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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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. */
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)
{
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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _ECC_IMPL_H
#define _ECC_IMPL_H
#pragma ident "%Z%%M% %I% %E% SMI"
#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 _WIN32
typedef unsigned char uint8_t;
typedef unsigned long ulong_t;
typedef enum boolean { B_FALSE, B_TRUE } boolean_t;
#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.
VR
#define RNG_GenerateGlobalRandomBytes(p,l) SECFailure
*/
#define RNG_GenerateGlobalRandomBytes(p,l) SECSuccess
#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);
extern SECStatus EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey, const unsigned char* random, int randomlen, int);
extern SECStatus EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey,
const unsigned char *seed, int seedlen, int kmflag);
extern SECStatus ECDSA_SignDigest(ECPrivateKey *, SECItem *, const SECItem *,
const unsigned char* randon, int randomlen, int);
extern SECStatus ECDSA_SignDigestWithSeed(ECPrivateKey *, SECItem *,
const SECItem *, const unsigned char *seed, int seedlen, int kmflag);
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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#ifndef _WIN32
#ifndef __linux__
#include <sys/systm.h>
#endif /* __linux__ */
#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 = 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 ((name < ECCurve_noName) || (name > ECCurve_pastLastCurve)) goto cleanup;
params->name = name;
curveParams = ecCurve_map[params->name];
CHECK_OK(curveParams);
params->fieldID.size = curveParams->size;
params->fieldID.type = field_type;
if (field_type == ec_field_GFp) {
CHECK_OK(hexString2SECItem(NULL, &params->fieldID.u.prime,
curveParams->irr, kmflag));
} else {
CHECK_OK(hexString2SECItem(NULL, &params->fieldID.u.poly,
curveParams->irr, kmflag));
}
CHECK_OK(hexString2SECItem(NULL, &params->curve.a,
curveParams->curvea, kmflag));
CHECK_OK(hexString2SECItem(NULL, &params->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, &params->base, genenc, kmflag));
CHECK_OK(hexString2SECItem(NULL, &params->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)) {
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;
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;
}
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _ECL_CURVE_H
#define _ECL_CURVE_H
#pragma ident "%Z%%M% %I% %E% SMI"
#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
};
/* 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 */
NULL /* ECCurve_pastLastCurve */
};
#endif /* _ECL_CURVE_H */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _ECL_EXP_H
#define _ECL_EXP_H
#pragma ident "%Z%%M% %I% %E% SMI"
/* 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 */
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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _ECL_PRIV_H
#define _ECL_PRIV_H
#pragma ident "%Z%%M% %I% %E% SMI"
#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); }
#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)); }
#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);
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);
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);
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);
/* 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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _ECL_H
#define _ECL_H
#pragma ident "%Z%%M% %I% %E% SMI"
/* 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);
/* 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);
/* 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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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(a0, r0, r0, 0, 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(a0, r0, r0, 0, 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(a0, r0, r0, 0, 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(a0, r0, r0, 0, 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(b0, r0, r0, 0, 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(b0, r0, r0, 0, 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(b0, r0, r0, 0, 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_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(b0, r0, r0, 0, 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, 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);
}
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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)
{
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 {
MP_CHECKOK(group->
point_mul(&kt, &group->genx, &group->geny, rx, ry,
group));
}
} else {
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));
} else {
MP_CHECKOK(group->point_mul(&kt, px, py, 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:
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)
{
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);
} else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
}
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));
MP_CHECKOK(ECPoint_mul(group, k2, px, py, rx, ry));
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)
{
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);
} else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
}
/* 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)
{
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);
} else {
res = ec_pts_mul_simul_w2(k1p, k2p, px, py, rx, ry, group);
}
CLEANUP:
mp_clear(&k1t);
mp_clear(&k2t);
return res;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _ECP_H
#define _ECP_H
#pragma ident "%Z%%M% %I% %E% SMI"
#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);
/* 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);
#endif /* _ECP_H */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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(r0, a3, r0, 0, carry);
MP_ADD_CARRY(r1, a3, r1, carry, carry);
MP_ADD_CARRY(r2, a4, r2, carry, carry);
r3 = carry;
MP_ADD_CARRY(r0, a5, r0, 0, carry);
MP_ADD_CARRY(r1, a5, r1, carry, carry);
MP_ADD_CARRY(r2, a5, r2, carry, carry);
r3 += carry;
MP_ADD_CARRY(r1, a4, r1, 0, 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(r0, r3, r0, 0, 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(a0, r0, r0, 0, 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(r0, 1, r0, 0, 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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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 (r1, a3b, r1, 0, carry);
MP_ADD_CARRY (r2, a4 , r2, carry, carry);
MP_ADD_CARRY (r3, a5a, r3, carry, carry);
MP_ADD_CARRY (r1, a5b, r1, 0, 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(r1,((mp_digit)r3b) << 32, r1, 0, 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 (r0, 1, r0, 0, 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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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(r1, a5h << 32, r1, 0, carry);
MP_ADD_CARRY(r2, a6, r2, carry, carry);
MP_ADD_CARRY(r3, a7, r3, carry, carry);
r4 = carry;
MP_ADD_CARRY(r1, a5h << 32, r1, 0, carry);
MP_ADD_CARRY(r2, a6, r2, carry, carry);
MP_ADD_CARRY(r3, a7, r3, carry, carry);
r4 += carry;
/* sum 2 */
MP_ADD_CARRY(r1, a6l, r1, 0, carry);
MP_ADD_CARRY(r2, a6h | a7l, r2, carry, carry);
MP_ADD_CARRY(r3, a7h, r3, carry, carry);
r4 += carry;
MP_ADD_CARRY(r1, a6l, r1, 0, 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(r0, a4, r0, 0, 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(r0, a4h | a5l, r0, 0, 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(r0, r4_long, r0, 0, 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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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);
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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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.
*/
MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt) );
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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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));
/* 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)
{
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);
} else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
return ECPoint_mul(group, k1, NULL, NULL, rx, ry);
}
/* 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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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));
/* 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)
{
mp_err res = MP_OKAY;
mp_int precomp[16][2], rz, tpx, tpy;
mp_int raz4;
mp_int scratch[MAX_SCRATCH];
signed char *naf = NULL;
int i, orderBitSize;
MP_DIGITS(&rz) = 0;
MP_DIGITS(&raz4) = 0;
MP_DIGITS(&tpx) = 0;
MP_DIGITS(&tpy) = 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(&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);
/* wNAF method */
for (i = orderBitSize; i >= 0; i--) {
/* 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);
}
}
/* 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(&rz);
mp_clear(&raz4);
#ifdef _KERNEL
kmem_free(naf, (orderBitSize + 1));
#else
free(naf);
#endif
return res;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/* 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;
}
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _LOGTAB_H
#define _LOGTAB_H
#pragma ident "%Z%%M% %I% %E% SMI"
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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _MP_GF2M_PRIV_H_
#define _MP_GF2M_PRIV_H_
#pragma ident "%Z%%M% %I% %E% SMI"
#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_ */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _MP_GF2M_H_
#define _MP_GF2M_H_
#pragma ident "%Z%%M% %I% %E% SMI"
#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_ */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _MPI_CONFIG_H
#define _MPI_CONFIG_H
#pragma ident "%Z%%M% %I% %E% SMI"
/* $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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* 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.
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _MPI_PRIV_H
#define _MPI_PRIV_H
#pragma ident "%Z%%M% %I% %E% SMI"
/* $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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
*
* Arbitrary precision integer arithmetic library
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/* $Id: mpi.c,v 1.45 2006/09/29 20:12:21 alexei.volkov.bugs%sun.com Exp $ */
#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_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;
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;
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_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;
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) {
while (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_int *mp;
++mp_allocs;
#ifdef _KERNEL
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;
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, 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(&quot) = 0;
/* Make room for the quotient */
MP_CHECKOK( mp_init_size(&quot, 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(&quot, 1);
DIGIT(&quot, 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(&quot, 0) = d;
MP_CHECKOK( s_mp_norm(&rem, &quot, &norm) );
if (norm)
d <<= norm;
MP_DIGIT(&quot, 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(&quot, 1) );
DIGIT(&quot, 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(&quot);
mp_exch(&quot, mp);
CLEANUP:
mp_clear(&quot);
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;
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;
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 >= 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;
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;
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;
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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
*
* Arbitrary precision integer arithmetic library
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _MPI_H
#define _MPI_H
#pragma ident "%Z%%M% %I% %E% SMI"
/* $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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
*
* Bitwise logical operations on MPI values
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/* $Id: mplogic.c,v 1.15 2004/04/27 23:04:36 gerv%gerv.net Exp $ */
#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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
*
* Bitwise logical operations on MPI values
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _MPLOGIC_H
#define _MPLOGIC_H
#pragma ident "%Z%%M% %I% %E% SMI"
/* $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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/* $Id: mpmontg.c,v 1.20 2006/08/29 02:41:38 nelson%bolyard.com Exp $ */
/* 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
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
*
* Utilities for finding and working with prime and pseudo-prime
* integers
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _MP_PRIME_H
#define _MP_PRIME_H
#pragma ident "%Z%%M% %I% %E% SMI"
#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 */
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#ifndef _WIN32
#ifndef __linux__
#include <sys/systm.h>
#endif /* __linux__ */
#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 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 };
#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 )
};
SECOidData *
SECOID_FindOID(const SECItem *oid)
{
SECOidData *po;
SECOidData *ret;
int i;
if (oid->len == 8) {
if (oid->data[6] == 0x00) {
/* XXX bounds check */
po = &ANSI_oids[oid->data[7]];
if (memcmp(oid->data, po->oid.data, 8) == 0)
ret = po;
}
if (oid->data[6] == 0x01) {
/* XXX bounds check */
po = &ANSI_prime_oids[oid->data[7]];
if (memcmp(oid->data, po->oid.data, 8) == 0)
ret = po;
}
} else if (oid->len == 5) {
/* XXX bounds check */
po = &SECG_oids[oid->data[4]];
if (memcmp(oid->data, po->oid.data, 5) == 0)
ret = po;
} else {
ret = NULL;
}
return(ret);
}
ECCurveName
SECOID_FindOIDTag(const SECItem *oid)
{
SECOidData *oiddata;
oiddata = SECOID_FindOID (oid);
if (oiddata == NULL)
return ECCurve_noName;
return oiddata->offset;
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* 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
#ifndef __linux__
#include <sys/systm.h>
#endif /* __linux__ */
#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
}
}
}
/* *********************************************************************
*
* Sun elects to have this file available under and governed by the
* Mozilla Public License Version 1.1 ("MPL") (see
* http://www.mozilla.org/MPL/ for full license text). For the avoidance
* of doubt and subject to the following, Sun also elects to allow
* licensees to use this file under the MPL, the GNU General Public
* License version 2 only or the Lesser General Public License version
* 2.1 only. Any references to the "GNU General Public License version 2
* or later" or "GPL" in the following shall be construed to mean the
* GNU General Public License version 2 only. Any references to the "GNU
* Lesser General Public License version 2.1 or later" or "LGPL" in the
* following shall be construed to mean the GNU Lesser General Public
* License version 2.1 only. However, the following notice accompanied
* the original version of this file:
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* 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
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*********************************************************************** */
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SECOIDT_H_
#define _SECOIDT_H_
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* 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_ */
/*
* Copyright 2009 Sun Microsystems, Inc. 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.
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/**
* @test
* @bug 6840752
* @summary Provide out-of-the-box support for ECC algorithms
* @library ../pkcs11
* @library ../pkcs11/ec
* @run main TestEC
*/
import java.security.Provider;
/*
* Leverage the collection of EC tests used by PKCS11
*
* NOTE: the following files were copied here from the PKCS11 EC Test area
* and must be kept in sync with the originals:
*
* ../pkcs11/ec/p12passwords.txt
* ../pkcs11/ec/pkcs12/secp256r1server-secp384r1ca.p12
* ../pkcs11/ec/pkcs12/sect193r1server-rsa1024ca.p12
*/
public class TestEC {
public static void main(String[] args) throws Exception {
Provider p = new sun.security.ec.SunEC();
System.out.println("Running tests with " + p.getName() +
" provider...\n");
long start = System.currentTimeMillis();
new TestECDH().main(p);
new TestECDSA().main(p);
//new TestCurves().main(p);
new TestKeyFactory().main(p);
new TestECGenSpec().main(p);
new ReadPKCS12().main(p);
//new ReadCertificates().main(p);
long stop = System.currentTimeMillis();
System.out.println("\nCompleted tests with " + p.getName() +
" provider (" + (stop - start) + " ms).");
}
}
# MS_ECC_Samples.zip
256-ecc.pfx ecc
256_2-ecc.pfx ecc
384-ecc.pfx ecc
521-ecc.pfx ecc
# MS_Client_certs.zip
eccclicert256.pfx 1
eccclicert384.pfx 1
eccclicert521.pfx 1
# NSS_ECC_PKCS12.zip
ECCp160.p12 ecc
ECCp192.p12 ecc
ECCp224.p12 ecc
ECCp256.p12 ecc
ECCp384.p12 ecc
ECCp521.p12 ecc
# All other files
* password
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册